aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ButtonBox.scss13
-rw-r--r--src/client/views/nodes/ButtonBox.tsx2
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.scss5
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx23
-rw-r--r--src/client/views/nodes/ColorBox.tsx4
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx5
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx6
-rw-r--r--src/client/views/nodes/DocumentView.scss47
-rw-r--r--src/client/views/nodes/DocumentView.tsx152
-rw-r--r--src/client/views/nodes/FieldView.tsx4
-rw-r--r--src/client/views/nodes/FontIconBox.scss6
-rw-r--r--src/client/views/nodes/FontIconBox.tsx7
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss347
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx107
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.scss1
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.tsx102
-rw-r--r--src/client/views/nodes/ImageBox.scss2
-rw-r--r--src/client/views/nodes/ImageBox.tsx12
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/PDFBox.scss54
-rw-r--r--src/client/views/nodes/PDFBox.tsx35
-rw-r--r--src/client/views/nodes/VideoBox.scss1
-rw-r--r--src/client/views/nodes/VideoBox.tsx10
23 files changed, 657 insertions, 290 deletions
diff --git a/src/client/views/nodes/ButtonBox.scss b/src/client/views/nodes/ButtonBox.scss
index e8a3d1479..7c3825978 100644
--- a/src/client/views/nodes/ButtonBox.scss
+++ b/src/client/views/nodes/ButtonBox.scss
@@ -3,7 +3,7 @@
height: 100%;
pointer-events: all;
border-radius: inherit;
- display:flex;
+ display: flex;
flex-direction: column;
}
@@ -15,19 +15,22 @@
display: table;
overflow: hidden;
text-overflow: ellipsis;
+ letter-spacing: 2px;
+ text-transform: uppercase;
}
+
.buttonBox-mainButtonCenter {
height: 100%;
- display:table-cell;
+ display: table-cell;
vertical-align: middle;
}
.buttonBox-params {
- display:flex;
- flex-direction: row;
+ display: flex;
+ flex-direction: row;
}
.buttonBox-missingParam {
- width:100%;
+ width: 100%;
background: lightgray;
} \ No newline at end of file
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index beb2b30fd..659ba154a 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -79,7 +79,7 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
return (
<div className="buttonBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
- <div className="buttonBox-mainButton" style={{ background: this.Document.backgroundColor || "", color: this.Document.color || "black" }} >
+ <div className="buttonBox-mainButton" style={{ background: this.Document.backgroundColor || "", color: this.Document.color || "black", fontSize: this.Document.fontSize }} >
<div className="buttonBox-mainButtonCenter">
{(this.Document.text || this.Document.title)}
</div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
index af9232c2f..da287649e 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
@@ -2,6 +2,7 @@
transform-origin: left top;
position: absolute;
background-color: transparent;
- top:0;
- left:0;
+ touch-action: manipulation;
+ top: 0;
+ left: 0;
} \ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 83638b240..c85b59488 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -10,9 +10,10 @@ import "./CollectionFreeFormDocumentView.scss";
import { DocumentView, DocumentViewProps } from "./DocumentView";
import React = require("react");
import { PositionDocument } from "../../../new_fields/documentSchemas";
+import { TraceMobx } from "../../../new_fields/util";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
- dataProvider?: (doc: Doc, dataDoc?: Doc) => { x: number, y: number, width: number, height: number, z: number, transition?: string } | undefined;
+ dataProvider?: (doc: Doc) => { x: number, y: number, width: number, height: number, z: number, transition?: string } | undefined;
x?: number;
y?: number;
width?: number;
@@ -24,12 +25,16 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
@observer
export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps, PositionDocument>(PositionDocument) {
_disposer: IReactionDisposer | undefined = undefined;
+ get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; }
get X() { return this._animPos !== undefined ? this._animPos[0] : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
get Y() { return this._animPos !== undefined ? this._animPos[1] : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.dataProvider && this.dataProvider ? this.dataProvider.width : this.layoutDoc[WidthSym](); }
- get height() { return this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym](); }
- @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document, this.props.DataDoc) ? this.props.dataProvider(this.props.Document, this.props.DataDoc) : undefined; }
+ get height() {
+ let hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
+ return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
+ }
+ @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
@computed get nativeWidth() { return NumCast(this.layoutDoc.nativeWidth); }
@computed get nativeHeight() { return NumCast(this.layoutDoc.nativeHeight); }
@@ -52,11 +57,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
this._disposer && this._disposer();
}
componentDidMount() {
- this._disposer = reaction(() => [this.props.Document.animateToPos, this.props.Document.isAnimating],
- () => {
- const target = this.props.Document.animateToPos ? Array.from(Cast(this.props.Document.animateToPos, listSpec("number"))!) : undefined;
- this._animPos = !target ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]);
- }, { fireImmediately: true });
+ this._disposer = reaction(() => this.props.Document.animateToPos ? Array.from(Cast(this.props.Document.animateToPos, listSpec("number"))!) : undefined,
+ target => this._animPos = !target ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]),
+ { fireImmediately: true });
}
contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect ? this.width / this.nativeWidth : 1;
@@ -84,7 +87,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight();
render() {
- // trace();
+ TraceMobx();
return <div className="collectionFreeFormDocumentView-container"
style={{
boxShadow:
@@ -95,7 +98,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
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),
+ transition: this.Document.isAnimating ? ".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,
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index fda6d64f4..40674b034 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -38,7 +38,9 @@ export class ColorBox extends DocExtendableComponent<FieldViewProps, ColorDocume
render() {
return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`}
- onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}>
+ onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
+ style={{ transformOrigin: "top left", transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+
<SketchPicker color={this._startupColor} onChange={InkingControl.Instance.switchColor} />
</div>;
}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index f41c4fc91..573a55710 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -20,7 +20,6 @@ interface ContentFittingDocumentViewProps {
childDocs?: Doc[];
renderDepth: number;
fitToBox?: boolean;
- fieldKey: string;
PanelWidth: () => number;
PanelHeight: () => number;
ruleProvider: Doc | undefined;
@@ -33,10 +32,11 @@ interface ContentFittingDocumentViewProps {
addDocument: (document: Doc) => boolean;
moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
removeDocument: (document: Doc) => boolean;
- active: () => boolean;
+ active: (outsideReaction: boolean) => 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;
}
@@ -108,6 +108,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
focus={this.props.focus || emptyFunction}
backgroundColor={returnEmptyString}
bringToFront={emptyFunction}
+ dontRegisterView={this.props.dontRegisterView}
zoomToScale={emptyFunction}
getScale={returnOne}
/>
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 779d25cdd..b9b84d5ce 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -30,6 +30,7 @@ import { DocuLinkBox } from "./DocuLinkBox";
import { PresElementBox } from "../presentationview/PresElementBox";
import { VideoBox } from "./VideoBox";
import { WebBox } from "./WebBox";
+import { InkingStroke } from "../InkingStroke";
import React = require("react");
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -49,7 +50,7 @@ const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any;
@observer
export class DocumentContentsView extends React.Component<DocumentViewProps & {
- isSelected: () => boolean,
+ isSelected: (outsideReaction: boolean) => boolean,
select: (ctrl: boolean) => void,
onClick?: ScriptField,
layoutKey: string,
@@ -97,7 +98,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
components={{
FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, FontIconBox: FontIconBox, ButtonBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
- PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox, ColorBox, DocuLinkBox
+ PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox,
+ ColorBox, DocuLinkBox, InkingStroke
}}
bindings={this.CreateBindings()}
jsx={this.layout}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 65df86d27..dfb84ed5c 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,13 +1,14 @@
@import "../globalCssVariables";
-.documentView-node, .documentView-node-topmost {
+.documentView-node,
+.documentView-node-topmost {
position: inherit;
top: 0;
- left:0;
+ left: 0;
border-radius: inherit;
- transition : outline .3s linear;
+ transition: outline .3s linear;
cursor: grab;
-
+
// background: $light-color; //overflow: hidden;
transform-origin: left top;
@@ -37,44 +38,48 @@
position: absolute;
transform-origin: top left;
width: 100%;
- height: 100%;
+ height: 100%;
}
+
.documentView-styleWrapper {
- position: absolute;
+ position: absolute;
display: inline-block;
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
pointer-events: none;
.documentView-styleContentWrapper {
- width:100%;
+ width: 100%;
display: inline-block;
position: absolute;
}
+
.documentView-titleWrapper {
- overflow:hidden;
- color: white;
- transform-origin: top left;
- top: 0;
+ overflow: hidden;
+ color: white;
+ transform-origin: top left;
+ top: 0;
+ width: 100%;
height: 25;
background: rgba(0, 0, 0, .4);
- padding: 4px;
- text-align: center;
- text-overflow: ellipsis;
+ padding: 4px;
+ text-align: center;
+ text-overflow: ellipsis;
white-space: pre;
}
.documentView-searchHighlight {
- position: absolute;
- background: yellow;
+ position: absolute;
+ background: yellow;
bottom: -20px;
border-radius: 5px;
- transform-origin: bottom left;
+ transform-origin: bottom left;
}
.documentView-captionWrapper {
- position: absolute;
- bottom: 0;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
transform-origin: bottom left;
}
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 304555c30..467fd4b32 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -11,13 +11,12 @@ import { ScriptField } from '../../../new_fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { ImageField } from '../../../new_fields/URLField';
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { emptyFunction, returnTransparent, returnTrue, Utils } from "../../../Utils";
+import { emptyFunction, returnTransparent, returnTrue, Utils, returnOne } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { DocServer } from "../../DocServer";
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
import { ClientUtils } from '../../util/ClientUtils';
-import { DictationManager } from '../../util/DictationManager';
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, dropActionType } from "../../util/DragManager";
import { LinkManager } from '../../util/LinkManager';
@@ -41,6 +40,10 @@ import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import { FormattedTextBox } from './FormattedTextBox';
import React = require("react");
+import { InteractionUtils } from '../../util/InteractionUtils';
+import { InkingControl } from '../InkingControl';
+import { InkTool } from '../../../new_fields/InkField';
+import { TraceMobx } from '../../../new_fields/util';
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,
@@ -64,7 +67,7 @@ export interface DocumentViewProps {
PanelWidth: () => number;
PanelHeight: () => number;
focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => void;
- parentActive: () => boolean;
+ parentActive: (outsideReaction: boolean) => boolean;
whenActiveChanged: (isActive: boolean) => void;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean;
@@ -74,6 +77,7 @@ export interface DocumentViewProps {
getScale: () => number;
animateBetweenIcon?: (maximize: boolean, target: number[]) => void;
ChromeHeight?: () => number;
+ dontRegisterView?: boolean;
layoutKey?: string;
}
@@ -88,8 +92,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
private _mainCont = React.createRef<HTMLDivElement>();
private _dropDisposer?: DragManager.DragDropDisposer;
+ public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
public get ContentDiv() { return this._mainCont.current; }
- @computed get active() { return SelectionManager.IsSelected(this) || this.props.parentActive(); }
+ @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
@computed get topMost() { return this.props.renderDepth === 0; }
@computed get nativeWidth() { return this.layoutDoc.nativeWidth || 0; }
@computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; }
@@ -98,7 +103,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
@@ -111,7 +117,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) {
@@ -136,7 +142,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";
@@ -206,14 +212,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
document.addEventListener("pointerup", this.onPointerUp);
if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); }
}
+
onPointerMove = (e: PointerEvent): void => {
if ((e as any).formattedHandled) { e.stopPropagation(); return; }
if (e.cancelBubble && this.active) {
document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
}
- else if (!e.cancelBubble && (SelectionManager.IsSelected(this) || this.props.parentActive() || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) {
+ else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) {
if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
- if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && e.buttons === 1) {
+ if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCH))) {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag);
@@ -223,6 +230,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
e.preventDefault();
}
}
+
onPointerUp = (e: PointerEvent): void => {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
@@ -350,9 +358,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);
}
}
@@ -370,15 +378,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
}
- listen = async () => {
- Doc.GetProto(this.props.Document).transcript = await DictationManager.Controls.listen({
- continuous: { indefinite: true },
- interimHandler: (results: string) => {
- DictationOverlay.Instance.dictationSuccess = true;
- DictationOverlay.Instance.dictatedPhrase = results;
- DictationOverlay.Instance.isListening = { interim: true };
- }
- });
+ @undoBatch
+ @action
+ toggleLockTransform = (): void => {
+ this.Document.lockedTransform = this.Document.lockedTransform ? undefined : true;
}
@action
@@ -402,14 +405,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
subitems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" });
cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" });
- if (Cast(this.props.Document.data, ImageField)) {
- cm.addItem({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
- }
- if (Cast(Doc.GetProto(this.props.Document).data, listSpec(Doc))) {
- cm.addItem({ description: "Export to Google Photos Album", event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.props.Document }).then(console.log), icon: "caret-square-right" });
- cm.addItem({ description: "Tag Child Images via Google Photos", event: () => GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" });
- cm.addItem({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" });
- }
let existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
let onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
@@ -427,10 +422,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
!existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
let funcs: ContextMenuProps[] = [];
- funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
- funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
- funcs.push({ description: "Drag Document", icon: "edit", event: () => this.Document.onDragStart = undefined });
- ContextMenu.Instance.addItem({ description: "OnDrag...", subitems: funcs, icon: "asterisk" });
+ if (this.Document.onDragStart) {
+ funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
+ funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
+ funcs.push({ description: "Drag Document", icon: "edit", event: () => this.Document.onDragStart = undefined });
+ ContextMenu.Instance.addItem({ description: "OnDrag...", subitems: funcs, icon: "asterisk" });
+ }
let existing = ContextMenu.Instance.findByDescription("Layout...");
let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
@@ -442,6 +439,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) {
@@ -450,18 +448,26 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
layoutItems.push({ description: "Use Native Layout", event: () => DocumentView.makeNativeViewClicked(this.props.Document), icon: "concierge-bell" });
}
!existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
+
+ let more = ContextMenu.Instance.findByDescription("More...");
+ let moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
+
if (!ClientUtils.RELEASE) {
// let copies: ContextMenuProps[] = [];
- cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
+ moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
// cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" });
}
- let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
- let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
- analyzers.push({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
- !existingAnalyze && cm.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" });
- cm.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle!
- cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
- cm.addItem({
+ if (Cast(this.props.Document.data, ImageField)) {
+ moreItems.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
+ }
+ if (Cast(Doc.GetProto(this.props.Document).data, listSpec(Doc))) {
+ moreItems.push({ description: "Export to Google Photos Album", event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.props.Document }).then(console.log), icon: "caret-square-right" });
+ moreItems.push({ description: "Tag Child Images via Google Photos", event: () => GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" });
+ moreItems.push({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" });
+ }
+ moreItems.push({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle!
+ moreItems.push({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
+ moreItems.push({
description: "Download document", icon: "download", event: async () =>
console.log(JSON.parse(await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), {
qs: { q: 'world', fq: 'NOT baseProto_b:true AND NOT deleted:true', start: '0', rows: '100', hl: true, 'hl.fl': '*' }
@@ -473,8 +479,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
// a.click();
});
- cm.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
- cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+ moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
+ moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+ moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
+ !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
runInAction(() => {
if (!ClientUtils.RELEASE) {
let setWriteMode = (mode: DocServer.WriteMode) => {
@@ -497,7 +505,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" });
aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" });
cm.addItem({ description: "Collaboration ACLs...", subitems: aclsMenu, icon: "share" });
- cm.addItem({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
}
});
runInAction(() => {
@@ -512,7 +519,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
e.stopPropagation();
}
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
- if (!SelectionManager.IsSelected(this)) {
+ if (!SelectionManager.IsSelected(this, true)) {
SelectionManager.SelectDoc(this, false);
}
});
@@ -524,7 +531,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
getLayoutPropStr = (prop: string) => StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
- isSelected = () => SelectionManager.IsSelected(this);
+ isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
chromeHeight = () => {
@@ -533,8 +540,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
return (showTitle ? 25 : 0) + 1;
}
+ @computed get finalLayoutKey() { return this.props.layoutKey || "layout"; }
childScaling = () => (this.layoutDoc.fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@computed get contents() {
+ TraceMobx();
return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
Document={this.props.Document}
@@ -563,12 +572,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
isSelected={this.isSelected}
select={this.select}
onClick={this.onClickHandler}
- layoutKey={this.props.layoutKey || "layout"}
+ layoutKey={this.finalLayoutKey}
DataDoc={this.props.DataDoc} />);
}
linkEndpoint = (linkDoc: Doc) => Doc.LinkEndpoint(linkDoc, this.props.Document);
- // used to decide whether a link document should be created or not.
+ // used to decide whether a link document should be created or not.
// if it's a tempoarl link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here.
// would be good to generalize this some way.
isNonTemporalLink = (linkDoc: Doc) => {
@@ -578,16 +587,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@computed get innards() {
+ TraceMobx();
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 searchHighlight = (!this.Document.searchFields ? (null) :
- <div className="documentView-searchHighlight" style={{ width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}>
+ <div className="documentView-searchHighlight">
{this.Document.searchFields}
</div>);
const captionView = (!showCaption ? (null) :
- <div className="documentView-captionWrapper" style={{ width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}>
+ <div className="documentView-captionWrapper">
<FormattedTextBox {...this.props}
onClick={this.onClickHandler} DataDoc={this.props.DataDoc} active={returnTrue}
isSelected={this.isSelected} focus={emptyFunction} select={this.select}
@@ -596,7 +606,6 @@ 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",
}}>
@@ -608,9 +617,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
/>
</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))} />
+ {this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
+ <div className="documentView-docuLinkWrapper" key={`${d[Id]}`}>
+ <DocumentView {...this.props} ContentScaling={returnOne} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
</div>)}
{!showTitle && !showCaption ?
this.Document.searchFields ?
@@ -630,45 +639,52 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
{searchHighlight}
</div>
}
- </>
+ </>;
}
+ @computed get ignorePointerEvents() {
+ return (this.Document.isBackground && !this.isSelected()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None);
+ }
+
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) ?
+ 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);
- 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;
+ const localScale = fullDegree;
- let animheight = animDims ? animDims[1] : nativeHeight;
- let animwidth = animDims ? animDims[0] : nativeWidth;
+ const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
+ let animheight = animDims ? animDims[1] : "100%";
+ let animwidth = animDims ? animDims[0] : "100%";
const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
- const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"];
+ const highlightStyles = ["solid", "dashed", "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}
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)}
+ onPointerEnter={e => {
+ console.log("Brush" + this.props.Document.title);
+ Doc.BrushDoc(this.props.Document);
+ }} onPointerLeave={e => {
+ console.log("UnBrush" + this.props.Document.title);
+ 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",
+ transition: this.Document.isAnimating ? ".5s linear" : StrCast(this.Document.transition),
+ pointerEvents: this.ignorePointerEvents ? "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}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 5108954bb..c93746773 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -31,7 +31,7 @@ export interface FieldViewProps {
Document: Doc;
DataDoc?: Doc;
onClick?: ScriptField;
- isSelected: () => boolean;
+ isSelected: (outsideReaction?: boolean) => boolean;
select: (isCtrlPressed: boolean) => void;
renderDepth: number;
addDocument?: (document: Doc) => boolean;
@@ -40,7 +40,7 @@ export interface FieldViewProps {
removeDocument?: (document: Doc) => boolean;
moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
ScreenToLocalTransform: () => Transform;
- active: () => boolean;
+ active: (outsideReaction?: boolean) => boolean;
whenActiveChanged: (isActive: boolean) => void;
focus: (doc: Doc) => void;
PanelWidth: () => number;
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 75d093fcb..905601ce3 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -5,9 +5,9 @@
border-radius: inherit;
background: black;
border-radius: 100%;
+ transform-origin: top left;
svg {
- margin:18%;
- width:65% !important;
- height:65%;
+ width:95% !important;
+ height:95%;
}
}
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index ae9273639..960b55e3e 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");
@@ -39,7 +39,10 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
let referenceDoc = (this.props.Document.dragFactory instanceof Doc ? this.props.Document.dragFactory : this.props.Document);
let referenceLayout = Doc.Layout(referenceDoc);
return <button className="fontIconBox-outerDiv" title={StrCast(this.props.Document.title)} ref={this._ref}
- style={{ background: StrCast(referenceLayout.backgroundColor), boxShadow: this.props.Document.unchecked ? undefined : `4px 4px 12px black` }}>
+ style={{
+ background: StrCast(referenceLayout.backgroundColor),
+ boxShadow: this.props.Document.ischecked ? `4px 4px 12px black` : undefined
+ }}>
<FontAwesomeIcon className="fontIconBox-icon" icon={this.Document.icon as any} color={this._foregroundColor} size="sm" />
</button>;
}
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index a4acd3b82..77cdd3d42 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -27,6 +27,9 @@
pointer-events: all;
overflow-y: auto;
max-height: 100%;
+ display: flex;
+ flex-direction: row;
+
.formattedTextBox-dictation {
height: 20px;
width: 20px;
@@ -36,6 +39,45 @@
}
}
+.collectionfreeformview-container {
+ position: relative;
+}
+
+.formattedTextBox-outer {
+ position: relative;
+ overflow: auto;
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+}
+.formattedTextBox-sidebar-handle {
+ position: absolute;
+ top: calc(50% - 17.5px);
+ width: 10px;
+ height: 35px;
+ background: lightgray;
+ border-radius: 20px;
+}
+.formattedTextBox-cont > .formattedTextBox-sidebar-handle {
+ right: 0;
+ left: unset;
+}
+.formattedTextBox-sidebar, .formattedTextBox-sidebar-inking {
+ border-left: dashed 1px black;
+ height: 100%;
+ display: inline-block;
+ position: absolute;
+ right: 0;
+ > .formattedTextBox-sidebar-handle {
+ right:unset;
+ left:-5;
+ }
+}
+
+.formattedTextBox-sidebar-inking {
+ pointer-events: all;
+}
+
.formattedTextBox-inner-rounded {
height: 70%;
width: 85%;
@@ -45,23 +87,23 @@
left: 10%;
}
-.formattedTextBox-inner-rounded ,
-.formattedTextBox-inner {
+.formattedTextBox-inner-rounded,
+.formattedTextBox-inner {
padding: 10px 10px;
height: 100%;
}
-.menuicon {
- display: inline-block;
- border-right: 1px solid rgba(0, 0, 0, 0.2);
- color: #888;
- line-height: 1;
- padding: 0 7px;
- margin: 1px;
- cursor: pointer;
- text-align: center;
- min-width: 1.4em;
-}
+// .menuicon {
+// display: inline-block;
+// border-right: 1px solid rgba(0, 0, 0, 0.2);
+// color: #888;
+// line-height: 1;
+// padding: 0 7px;
+// margin: 1px;
+// cursor: pointer;
+// text-align: center;
+// min-width: 1.4em;
+// }
.strong,
.heading {
@@ -73,19 +115,20 @@
}
.userMarkOpen {
- background: rgba(255, 255, 0, 0.267);
+ background: rgba(255, 255, 0, 0.267);
display: inline;
}
+
.userMark {
- background: rgba(255, 255, 0, 0.267);
+ background: rgba(255, 255, 0, 0.267);
font-size: 2px;
display: inline-grid;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- width:10px;
- min-height:10px;
- text-align:center;
+ width: 10px;
+ min-height: 10px;
+ text-align: center;
align-content: center;
}
@@ -93,8 +136,9 @@ footnote {
display: inline-block;
position: relative;
cursor: pointer;
+
div {
- padding : 0 !important;
+ padding: 0 !important;
}
}
@@ -107,7 +151,7 @@ footnote::after {
.ProseMirror {
counter-reset: prosemirror-footnote;
- }
+}
.footnote-tooltip {
cursor: auto;
@@ -126,6 +170,7 @@ footnote::after {
.prosemirror-attribution {
font-size: 8px;
}
+
.footnote-tooltip::before {
border: 5px solid silver;
border-top-width: 0px;
@@ -140,45 +185,247 @@ footnote::after {
}
.formattedTextBox-summarizer {
- opacity :0.5;
+ opacity: 0.5;
position: relative;
- width:40px;
- height:20px;
+ width: 40px;
+ height: 20px;
}
-.formattedTextBox-summarizer::after{
- content: "←" ;
+
+.formattedTextBox-summarizer::after {
+ content: "←";
}
.formattedTextBox-summarizer-collapsed {
- opacity :0.5;
+ opacity: 0.5;
position: relative;
- width:40px;
- height:20px;
+ width: 40px;
+ height: 20px;
}
+
.formattedTextBox-summarizer-collapsed::after {
content: "...";
}
.ProseMirror {
-ol { counter-reset: deci1 0; padding-left: 0px; }
-.decimal1-ol {counter-reset: deci1; p { display: inline }; font-size: 24 ; ul, ol { padding-left:30px; } }
-.decimal2-ol {counter-reset: deci2; p { display: inline }; font-size: 18 ; ul, ol { padding-left:30px; } }
-.decimal3-ol {counter-reset: deci3; p { display: inline }; font-size: 14 ; ul, ol { padding-left:30px; } }
-.decimal4-ol {counter-reset: deci4; p { display: inline }; font-size: 10 ; ul, ol { padding-left:30px; } }
-.decimal5-ol {counter-reset: deci5; p { display: inline }; font-size: 10 ; ul, ol { padding-left:30px; } }
-.decimal6-ol {counter-reset: deci6; p { display: inline }; font-size: 10 ; ul, ol { padding-left:30px; } }
-.decimal7-ol {counter-reset: deci7; p { display: inline }; font-size: 10 ; ul, ol { padding-left:30px; } }
-.upper-alpha-ol {counter-reset: ualph; p { display: inline }; font-size: 18; }
-.lower-roman-ol {counter-reset: lroman; p { display: inline }; font-size: 14; }
-.lower-alpha-ol {counter-reset: lalpha; p { display: inline }; font-size: 10; }
-.decimal1:before { content: counter(deci1) ") "; counter-increment: deci1; display:inline-block; min-width: 30;}
-.decimal2:before { content: counter(deci1) "." counter(deci2) ") "; counter-increment: deci2; display:inline-block; min-width: 35}
-.decimal3:before { content: counter(deci1) "." counter(deci2) "." counter(deci3) ") "; counter-increment: deci3; display:inline-block; min-width: 35}
-.decimal4:before { content: counter(deci1) "." counter(deci2) "." counter(deci3) "." counter(deci4) ") "; counter-increment: deci4; display:inline-block; min-width: 40}
-.decimal5:before { content: counter(deci1) "." counter(deci2) "." counter(deci3) "." counter(deci4) "." counter(deci5) ") "; counter-increment: deci5; display:inline-block; min-width: 40}
-.decimal6:before { content: counter(deci1) "." counter(deci2) "." counter(deci3) "." counter(deci4) "." counter(deci5) "." counter(deci6) ") "; counter-increment: deci6; display:inline-block; min-width: 45}
-.decimal7:before { content: counter(deci1) "." counter(deci2) "." counter(deci3) "." counter(deci4) "." counter(deci5) "." counter(deci6) "." counter(deci7) ") "; counter-increment: deci7; display:inline-block; min-width: 50}
-.upper-alpha:before { content: counter(deci1) "." counter(ualph, upper-alpha) ") "; counter-increment: ualph; display:inline-block; min-width: 35 }
-.lower-roman:before { content: counter(deci1) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) ") "; counter-increment: lroman;display:inline-block; min-width: 50 }
-.lower-alpha:before { content: counter(deci1) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) "." counter(lalpha, lower-alpha) ") "; counter-increment: lalpha; display:inline-block; min-width: 35}
-}
+ touch-action: none;
+
+ ol {
+ counter-reset: deci1 0;
+ padding-left: 0px;
+ }
+
+ .decimal1-ol {
+ counter-reset: deci1;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 24;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal2-ol {
+ counter-reset: deci2;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 18;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal3-ol {
+ counter-reset: deci3;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 14;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal4-ol {
+ counter-reset: deci4;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 10;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal5-ol {
+ counter-reset: deci5;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 10;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal6-ol {
+ counter-reset: deci6;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 10;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .decimal7-ol {
+ counter-reset: deci7;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 10;
+
+ ul,
+ ol {
+ padding-left: 30px;
+ }
+ }
+
+ .upper-alpha-ol {
+ counter-reset: ualph;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 18;
+ }
+
+ .lower-roman-ol {
+ counter-reset: lroman;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 14;
+ }
+
+ .lower-alpha-ol {
+ counter-reset: lalpha;
+
+ p {
+ display: inline
+ }
+
+ ;
+ font-size: 10;
+ }
+
+ .decimal1:before {
+ content: counter(deci1) ") ";
+ counter-increment: deci1;
+ display: inline-block;
+ min-width: 30;
+ }
+
+ .decimal2:before {
+ content: counter(deci1) "."counter(deci2) ") ";
+ counter-increment: deci2;
+ display: inline-block;
+ min-width: 35
+ }
+
+ .decimal3:before {
+ content: counter(deci1) "."counter(deci2) "."counter(deci3) ") ";
+ counter-increment: deci3;
+ display: inline-block;
+ min-width: 35
+ }
+
+ .decimal4:before {
+ content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) ") ";
+ counter-increment: deci4;
+ display: inline-block;
+ min-width: 40
+ }
+
+ .decimal5:before {
+ content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ") ";
+ counter-increment: deci5;
+ display: inline-block;
+ min-width: 40
+ }
+
+ .decimal6:before {
+ content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ") ";
+ counter-increment: deci6;
+ display: inline-block;
+ min-width: 45
+ }
+
+ .decimal7:before {
+ content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ") ";
+ counter-increment: deci7;
+ display: inline-block;
+ min-width: 50
+ }
+
+ .upper-alpha:before {
+ content: counter(deci1) "."counter(ualph, upper-alpha) ") ";
+ counter-increment: ualph;
+ display: inline-block;
+ min-width: 35
+ }
+
+ .lower-roman:before {
+ content: counter(deci1) "."counter(ualph, upper-alpha) "."counter(lroman, lower-roman) ") ";
+ counter-increment: lroman;
+ display: inline-block;
+ min-width: 50
+ }
+
+ .lower-alpha:before {
+ content: counter(deci1) "."counter(ualph, upper-alpha) "."counter(lroman, lower-roman) "."counter(lalpha, lower-alpha) ") ";
+ counter-increment: lalpha;
+ display: inline-block;
+ min-width: 35
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 24d6f2509..9910c9ecd 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -17,14 +17,13 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols';
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 { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+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';
import { DocumentType } from '../../documents/DocumentTypes';
import { DictationManager } from '../../util/DictationManager';
-import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from "../../util/DragManager";
import buildKeymap from "../../util/ProsemirrorExampleTransfer";
import { inpRules } from "../../util/RichTextRules";
@@ -33,7 +32,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 +45,9 @@ 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';
+import { InkTool } from '../../../new_fields/InkField';
+import { TraceMobx } from '../../../new_fields/util';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -70,11 +72,11 @@ 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;
- private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
+ public static ToolTipTextMenu: TooltipTextMenu | undefined = undefined;
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _proseRef?: HTMLDivElement;
private _editorView: Opt<EditorView>;
@@ -85,7 +87,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>;
@@ -120,7 +121,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
public static getToolTip(ev: EditorView) {
- return this._toolTipTextMenu ? this._toolTipTextMenu : this._toolTipTextMenu = new TooltipTextMenu(ev);
+ return this.ToolTipTextMenu ? this.ToolTipTextMenu : this.ToolTipTextMenu = new TooltipTextMenu(ev);
}
@undoBatch
@@ -191,9 +192,8 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
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 - 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();
@@ -250,7 +250,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
@@ -290,6 +290,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) {
@@ -358,8 +359,11 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
}
+ toggleSidebar = () => this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%";
+
specificContextMenu = (e: React.MouseEvent): void => {
let funcs: ContextMenuProps[] = [];
+ funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.toggleSidebar(); }, 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({
@@ -510,17 +514,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);
@@ -787,7 +780,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,
@@ -834,7 +829,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();
@@ -848,7 +842,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
if (this.props.onClick && e.button === 0) {
e.preventDefault();
}
- if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
e.stopPropagation();
}
if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
@@ -857,10 +851,13 @@ 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) {
+ if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) {
e.stopPropagation();
}
}
@@ -873,7 +870,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
onPointerWheel = (e: React.WheelEvent): void => {
// if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time
- if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) {
+ if (this.props.isSelected(true) || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) {
e.stopPropagation();
}
}
@@ -884,7 +881,7 @@ 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) {
+ // if (e.button === 0 && ((!this.props.isSelected(true) && !e.ctrlKey) || (this.props.isSelected(true) && e.ctrlKey)) && !e.metaKey && e.target) {
// let href = (e.target as any).href;
// let location: string;
// if ((e.target as any).attributes.location) {
@@ -924,7 +921,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
hitBulletTargets(x: number, y: number, offsetX: number, select: boolean = false) {
clearStyleSheetRules(FormattedTextBox._bulletStyleSheet);
- if (this.props.isSelected() && offsetX < 40) {
+ if (this.props.isSelected(true) && offsetX < 40) {
let pos = this._editorView!.posAtCoords({ left: x, top: y });
if (pos && pos.pos > 0) {
let node = this._editorView!.state.doc.nodeAt(pos.pos);
@@ -968,7 +965,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
let self = FormattedTextBox;
return new Plugin({
view(newView) {
- return self._toolTipTextMenu = FormattedTextBox.getToolTip(newView);
+ return self.ToolTipTextMenu = FormattedTextBox.getToolTip(newView);
}
});
}
@@ -1003,13 +1000,16 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
if (!this._undoTyping) {
this._undoTyping = UndoManager.StartBatch("undoTyping");
}
- if (this._recording) { this.stopDictation(true); setTimeout(() => this.recordDictation(), 250); }
+ if (this._recording) {
+ this.stopDictation(true);
+ setTimeout(() => this.recordDictation(), 250);
+ }
}
@action
tryUpdateHeight() {
- let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0;
- if (!this.layoutDoc.isAnimating && this.layoutDoc.autoHeight && scrollHeight !== 0 &&
+ const scrollHeight = this._ref.current?.scrollHeight;
+ if (!this.layoutDoc.animateToPos && this.layoutDoc.autoHeight && scrollHeight &&
getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
let nh = this.Document.isTemplateField ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
let dh = NumCast(this.layoutDoc.height, 0);
@@ -1018,12 +1018,15 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
}
+ @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "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();
+ TraceMobx();
let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
let interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground;
if (this.props.isSelected()) {
- FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props);
+ FormattedTextBox.ToolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props);
} else if (FormattedTextBoxComment.textBox === this) {
FormattedTextBoxComment.Hide();
}
@@ -1050,8 +1053,36 @@ 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%" ?
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} /> :
+ <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
+ style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${StrCast(this.extensionDoc?.backgroundColor, "transparent")}` }}>
+ <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.annotationsActive}
+ 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 className="formattedTextBox-sidebar-handle" onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} />
+ </div>}
<div className="formattedTextBox-dictation"
onClick={e => {
this._recording ? this.stopDictation(true) : this.recordDictation();
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 f35ca502f..c076fd34a 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -1,17 +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, Cast, FieldValue } from "../../../new_fields/Types";
-import { FormattedTextBox } from "./FormattedTextBox";
-import { DocUtils } from "../../documents/Documents";
-import { isBuffer } from "util";
import { DocumentManager } from "../../util/DocumentManager";
-import { DocumentType } from "../../documents/DocumentTypes";
+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); }
@@ -50,6 +53,7 @@ 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;
@@ -59,30 +63,40 @@ export class FormattedTextBoxComment {
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.style.maxWidth = "350px";
- FormattedTextBoxComment.tooltip.appendChild(input);
+ 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;
- if (FormattedTextBoxComment.linkDoc && !keep && FormattedTextBoxComment.textBox) {
- DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, FormattedTextBoxComment.textBox.props.Document,
- (doc: Doc, maxLocation: string) => FormattedTextBoxComment.textBox!.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
+ 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() {
@@ -98,7 +112,7 @@ 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) &&
@@ -113,6 +127,12 @@ export class FormattedTextBoxComment {
}
let set = "none";
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);
@@ -127,6 +147,7 @@ export class FormattedTextBoxComment {
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.
@@ -138,15 +159,48 @@ export class FormattedTextBoxComment {
let mark = child && findLinkMark(child.marks);
if (mark && child && nbef && naft) {
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 => {
if (linkDoc instanceof Doc) {
FormattedTextBoxComment.linkDoc = linkDoc;
- let target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc));
- 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)));
+ 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)));
}
});
}
@@ -168,5 +222,5 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = set);
}
- destroy() { FormattedTextBoxComment.tooltip.style.display = "none"; }
+ destroy() { }
}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 57c024bbf..ba4ef8879 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -11,10 +11,12 @@
}
.imageBox-container {
+ pointer-events: all;
border-radius: inherit;
width:100%;
height:100%;
position: absolute;
+ transform-origin: top left;
}
.imageBox-cont-interactive {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 212c99f9d..f21ce3bf2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -27,6 +27,7 @@ import React = require("react");
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
+import { TraceMobx } from '../../../new_fields/util';
var requestImageSize = require('../../util/request-image-size');
var path = require('path');
const { Howl } = require('howler');
@@ -268,6 +269,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
@computed get content() {
+ TraceMobx();
const extensionDoc = this.extensionDoc;
if (!extensionDoc) return (null);
// let transform = this.props.ScreenToLocalTransform().inverse();
@@ -290,7 +292,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
if (field instanceof ImageField) paths = [this.choosePath(field.url)];
paths.push(...altpaths);
// }
- let interactive = InkingControl.Instance.selectedTool || this.Document.isBackground ? "" : "-interactive";
+ let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
let rotation = NumCast(this.Document.rotation, 0);
let aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
@@ -330,8 +332,10 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
</div>);
}
+ contentFunc = () => [this.content];
render() {
- return (<div className={"imageBox-container"} onContextMenu={this.specificContextMenu}>
+ return (<div className={"imageBox-container"} onContextMenu={this.specificContextMenu}
+ style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
@@ -340,7 +344,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}
@@ -352,7 +356,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
chromeCollapsed={true}>
- {() => [this.content]}
+ {this.contentFunc}
</CollectionFreeFormView>
</div >);
}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 35e9e4862..aa6e135fe 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -95,7 +95,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
}
onPointerDown = (e: React.PointerEvent): void => {
- if (e.buttons === 1 && this.props.isSelected()) {
+ if (e.buttons === 1 && this.props.isSelected(true)) {
e.stopPropagation();
}
}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 2d92c9581..46af63a7d 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -1,3 +1,11 @@
+.pdfBox-ui {
+ position: absolute;
+ width: 100%;
+ height:100%;
+ z-index: 1;
+ pointer-events: none;
+}
+
.pdfBox-cont,
.pdfBox-cont-interactive {
display: inline-block;
@@ -8,6 +16,7 @@
position:absolute;
cursor:auto;
transform-origin: top left;
+ z-index: 0;
}
.pdfBox-title-outer {
@@ -26,10 +35,10 @@
color:lightgray;
margin-top: auto;
margin-bottom: auto;
- transform-origin: 42% -18%;
+ transform-origin: 42% 15%;
width: 100%;
transform: rotate(55deg);
- font-size: 144;
+ font-size: 72;
padding: 5%;
overflow: hidden;
display: inline-block;
@@ -48,7 +57,6 @@
}
.pdfViewer-text {
.textLayer {
- will-change: transform;
span {
user-select: none;
}
@@ -60,7 +68,6 @@
pointer-events: all;
.pdfViewer-text {
.textLayer {
- will-change: transform;
span {
user-select: text;
}
@@ -135,14 +142,13 @@
.pdfBox-overlayCont {
position: absolute;
- width: 100%;
- height: 40px;
+ width: calc(100% - 40px);
+ height: 30px;
background: #121721;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
- padding: 20px;
overflow: hidden;
transition: left .5s;
pointer-events: all;
@@ -172,28 +178,24 @@
border-right: 15px solid #121721;
transition: all 0.5s;
}
+}
- .pdfBox-overlayButton-iconCont,
- .pdfBox-nextIcon,
- .pdfBox-prevIcon {
- background: #121721;
- height: 30px;
- width: 70px;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-left: -2px;
- border-radius: 3px;
- }
+.pdfBox-overlayButton-iconCont,
+.pdfBox-nextIcon,
+.pdfBox-prevIcon {
+ padding: 0;
+ background: #121721;
+ height: 30px;
+ width: 25px;
+ display: inline-block;
+ position: relative;
+ justify-content: center;
+ align-items: center;
+ margin-left: -2px;
+ border-radius: 3px;
+ pointer-events: all;
}
.pdfBox-overlayButton:hover {
background: none;
}
-
-.pdfBox-nextIcon {
- left: 20; top: 5; height: 30px; position: absolute;
-}
-.pdfBox-prevIcon {
- left: 50; top: 5; height: 30px; position: absolute;
-}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 8e0515f8a..23512543a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -62,7 +62,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
this._selectReactionDisposer = reaction(() => this.props.isSelected(),
() => {
document.removeEventListener("keydown", this.onKeyDown);
- this.props.isSelected() && document.addEventListener("keydown", this.onKeyDown);
+ this.props.isSelected(true) && document.addEventListener("keydown", this.onKeyDown);
}, { fireImmediately: true });
}
@@ -111,26 +111,24 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
private newValueChange = (e: React.ChangeEvent<HTMLInputElement>) => this._valueValue = e.currentTarget.value;
private newScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => this._scriptValue = e.currentTarget.value;
- whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
+ whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
setPdfViewer = (pdfViewer: PDFViewer) => { this._pdfViewer = pdfViewer; };
searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => this._searchString = e.currentTarget.value;
settingsPanel() {
let pageBtns = <>
<button className="pdfBox-overlayButton-iconCont" key="back" title="Page Back"
- onPointerDown={e => e.stopPropagation()} onClick={this.backPage}
- style={{ left: 50, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
+ onPointerDown={e => e.stopPropagation()} onClick={e => this.backPage()} style={{ left: 45, top: 5 }}>
<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}
- style={{ left: 80, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
+ onPointerDown={e => e.stopPropagation()} onClick={e => this.forwardPage()} style={{ left: 45, top: 5 }}>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-right"} size="sm" />
</button>
</>;
return !this.active() ? (null) :
(<div className="pdfBox-ui" onKeyDown={e => e.keyCode === KeyCodes.BACKSPACE || e.keyCode === KeyCodes.DELETE ? e.stopPropagation() : true}
- onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none", position: "absolute", width: "100%", height: "100%", zIndex: 1, pointerEvents: "none" }}>
+ onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "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)} />
@@ -143,14 +141,14 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="sm" />
</button>
</div>
- <button className="pdfBox-overlayButton" key="search" onClick={action(() => this._searching = !this._searching)} title="Open Search Bar" style={{ bottom: 8, right: 0 }}>
+ <button className="pdfBox-overlayButton" key="search" onClick={action(() => this._searching = !this._searching)} title="Open Search Bar" style={{ bottom: 0, right: 0 }}>
<div className="pdfBox-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()}></div>
<div className="pdfBox-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
<FontAwesomeIcon style={{ color: "white", padding: 5 }} icon={this._searching ? "times" : "search"} size="3x" /></div>
</button>
<input value={`${(this.Document.curPage || 1)}`}
onChange={e => this.gotoPage(Number(e.currentTarget.value))}
- style={{ left: 20, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }}
+ style={{ left: 5, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }}
onClick={action(() => this._pageControls = !this._pageControls)} />
{this._pageControls ? pageBtns : (null)}
<div className="pdfBox-settingsCont" key="settings" onPointerDown={(e) => e.stopPropagation()}>
@@ -199,33 +197,24 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
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>
+ <strong className="pdfBox-title" >{this.props.Document.title}</strong>
</div>
</div>;
}
+ isChildActive = (outsideReaction?: boolean) => this._isChildActive;
@computed get renderPdfView() {
- trace();
const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
- let classname = "pdfBox-cont" + (this.active() ? "-interactive" : "");
- 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();
- }
- }}>
+ return <div className={"pdfBox-cont"} onContextMenu={this.specificContextMenu}>
<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}
+ Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged}
+ isChildActive={this.isChildActive}
fieldKey={this.props.fieldKey} startupLive={this._initialScale < 2.5 ? true : false} />
{this.settingsPanel()}
</div>;
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 5829c1bd9..0a4c650a8 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,5 +1,6 @@
.videoBox-container {
pointer-events: all;
+ transform-origin: top left;
.inkingCanvas-paths-markers {
opacity : 0.4; // we shouldn't have to do this, but since chrome crawls to a halt with z-index unset in videoBox-content, this is a workaround
}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 53baea4ae..bd5bd918f 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -249,7 +249,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
this._youtubeReactionDisposer && this._youtubeReactionDisposer();
this._reactionDisposer = reaction(() => this.Document.currentTimecode, () => !this._playing && this.Seek(this.Document.currentTimecode || 0));
this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
- let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting;
+ let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected(true) && !DocumentDecorations.Instance.Interacting;
iframe.style.pointerEvents = interactive ? "all" : "none";
}, { fireImmediately: true });
};
@@ -333,8 +333,10 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
return this.addDocument(doc);
}
+ contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
render() {
- return (<div className={"videoBox-container"} onContextMenu={this.specificContextMenu}>
+ return (<div className={"videoBox-container"} onContextMenu={this.specificContextMenu}
+ style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
@@ -343,7 +345,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}
@@ -355,7 +357,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
chromeCollapsed={true}>
- {() => [this.youtubeVideoId ? this.youtubeContent : this.content]}
+ {this.contentFunc}
</CollectionFreeFormView>
{this.uIButtons}
</div >);