aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-03-18 06:40:43 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-03-18 06:40:43 -0400
commit7859d3c9902d6d15666cce6a93a24cfba6ffdf32 (patch)
tree0ef35c3231cdcf3208ea7111fad55cb472b1f624 /src
parent5a2551c83e451823c7d3176a5dbac9adca34dea1 (diff)
parent6df4833c13921dd6d69d05fa979398356d438c71 (diff)
Merged, added delete all route, and added history to workspaces
Diffstat (limited to 'src')
-rw-r--r--src/client/Server.ts2
-rw-r--r--src/client/documents/Documents.ts85
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/jsx-decl.d.ts1
-rw-r--r--src/client/views/InkingCanvas.tsx2
-rw-r--r--src/client/views/InkingControl.tsx8
-rw-r--r--src/client/views/Main.tsx49
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx73
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx10
-rw-r--r--src/client/views/collections/CollectionView.tsx2
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx34
-rw-r--r--src/client/views/collections/MarqueeView.tsx2
-rw-r--r--src/client/views/collections/PreviewCursor.tsx10
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx60
-rw-r--r--src/client/views/nodes/DocumentView.tsx56
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx8
-rw-r--r--src/client/views/nodes/ImageBox.tsx15
-rw-r--r--src/debug/Test.tsx43
-rw-r--r--src/debug/Viewer.tsx4
-rw-r--r--src/fields/AudioField.ts8
-rw-r--r--src/fields/Document.ts56
-rw-r--r--src/fields/HtmlField.ts2
-rw-r--r--src/fields/ImageField.ts4
-rw-r--r--src/fields/KVPField.ts30
-rw-r--r--src/fields/KeyStore.ts3
-rw-r--r--src/fields/ListField.ts44
-rw-r--r--src/fields/PDFField.ts4
-rw-r--r--src/fields/VideoField.ts4
-rw-r--r--src/fields/WebField.ts4
-rw-r--r--src/mobile/ImageUpload.scss13
-rw-r--r--src/mobile/ImageUpload.tsx79
-rw-r--r--src/mobile/InkControls.tsx (renamed from src/fields/KVPField)0
-rw-r--r--src/server/RouteStore.ts1
-rw-r--r--src/server/database.ts4
-rw-r--r--src/server/index.ts34
-rw-r--r--src/typings/index.d.ts604
36 files changed, 759 insertions, 601 deletions
diff --git a/src/client/Server.ts b/src/client/Server.ts
index f2d7de75c..5e42c8285 100644
--- a/src/client/Server.ts
+++ b/src/client/Server.ts
@@ -145,4 +145,4 @@ export class Server {
}
Server.Socket.on(MessageStore.Foo.Message, Server.connected);
-Server.Socket.on(MessageStore.SetField.Message, Server.updateField); \ No newline at end of file
+Server.Socket.on(MessageStore.SetField.Message, Server.updateField);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 477adecd1..fabdaad17 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,30 +1,27 @@
+import { AudioField } from "../../fields/AudioField";
import { Document } from "../../fields/Document";
-import { Server } from "../Server";
+import { Field } from "../../fields/Field";
+import { HtmlField } from "../../fields/HtmlField";
+import { ImageField } from "../../fields/ImageField";
+import { InkField, StrokeData } from "../../fields/InkField";
+import { Key } from "../../fields/Key";
import { KeyStore } from "../../fields/KeyStore";
-import { TextField } from "../../fields/TextField";
-import { NumberField } from "../../fields/NumberField";
import { ListField } from "../../fields/ListField";
-import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
-import { ImageField } from "../../fields/ImageField";
-import { ImageBox } from "../views/nodes/ImageBox";
+import { PDFField } from "../../fields/PDFField";
+import { TextField } from "../../fields/TextField";
+import { VideoField } from "../../fields/VideoField";
import { WebField } from "../../fields/WebField";
-import { WebBox } from "../views/nodes/WebBox";
+import { Server } from "../Server";
+import { CollectionPDFView } from "../views/collections/CollectionPDFView";
+import { CollectionVideoView } from "../views/collections/CollectionVideoView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
-import { HtmlField } from "../../fields/HtmlField";
-import { Key } from "../../fields/Key"
-import { Field } from "../../fields/Field";
-import { KeyValueBox } from "../views/nodes/KeyValueBox"
-import { KVPField } from "../../fields/KVPField";
-import { VideoField } from "../../fields/VideoField"
-import { VideoBox } from "../views/nodes/VideoBox";
-import { AudioField } from "../../fields/AudioField";
import { AudioBox } from "../views/nodes/AudioBox";
-import { PDFField } from "../../fields/PDFField";
+import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
+import { ImageBox } from "../views/nodes/ImageBox";
+import { KeyValueBox } from "../views/nodes/KeyValueBox";
import { PDFBox } from "../views/nodes/PDFBox";
-import { CollectionPDFView } from "../views/collections/CollectionPDFView";
-import { RichTextField } from "../../fields/RichTextField";
-import { CollectionVideoView } from "../views/collections/CollectionVideoView";
-import { StrokeData, InkField } from "../../fields/InkField";
+import { VideoBox } from "../views/nodes/VideoBox";
+import { WebBox } from "../views/nodes/WebBox";
export interface DocumentOptions {
x?: number;
@@ -74,24 +71,29 @@ export namespace Documents {
});
}
function assignOptions(doc: Document, options: DocumentOptions): Document {
- if (options.x !== undefined) { doc.SetNumber(KeyStore.X, options.x); }
- if (options.y !== undefined) { doc.SetNumber(KeyStore.Y, options.y); }
- if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); }
- if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); }
if (options.nativeWidth !== undefined) { doc.SetNumber(KeyStore.NativeWidth, options.nativeWidth); }
if (options.nativeHeight !== undefined) { doc.SetNumber(KeyStore.NativeHeight, options.nativeHeight); }
if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); }
- if (options.panx !== undefined) { doc.SetNumber(KeyStore.PanX, options.panx); }
- if (options.pany !== undefined) { doc.SetNumber(KeyStore.PanY, options.pany); }
if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); }
if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); }
if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); }
if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); }
+ if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); }
if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); }
if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); }
- if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); }
return doc;
}
+
+ function assignToDelegate(doc: Document, options: DocumentOptions): Document {
+ if (options.x !== undefined) { doc.SetNumber(KeyStore.X, options.x); }
+ if (options.y !== undefined) { doc.SetNumber(KeyStore.Y, options.y); }
+ if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); }
+ if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); }
+ if (options.panx !== undefined) { doc.SetNumber(KeyStore.PanX, options.panx); }
+ if (options.pany !== undefined) { doc.SetNumber(KeyStore.PanY, options.pany); }
+ return doc
+ }
+
function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document {
return assignOptions(new Document(protoId), { ...options, title: title, layout: layout });
}
@@ -159,8 +161,7 @@ export namespace Documents {
export function ImageDocument(url: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetImagePrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] },
- [new URL(url), ImageField]);
+ return assignToDelegate(SetInstanceOptions(GetImagePrototype(), options, [new URL(url), ImageField]).MakeDelegate(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
// let doc = SetInstanceOptions(GetImagePrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] },
// [new URL(url), ImageField]);
// doc.SetText(KeyStore.Caption, "my caption...");
@@ -169,34 +170,38 @@ export namespace Documents {
// return doc;
}
export function VideoDocument(url: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetVideoPrototype(), options, [new URL(url), VideoField]);
+ return assignToDelegate(SetInstanceOptions(GetVideoPrototype(), options, [new URL(url), VideoField]), options);
}
export function AudioDocument(url: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetAudioPrototype(), options, [new URL(url), AudioField]);
+ return assignToDelegate(SetInstanceOptions(GetAudioPrototype(), options, [new URL(url), AudioField]), options);
}
+
export function TextDocument(options: DocumentOptions = {}) {
- return SetInstanceOptions(GetTextPrototype(), options, ["", TextField]);
+ return assignToDelegate(SetInstanceOptions(GetTextPrototype(), options, ["", TextField]).MakeDelegate(), options);
}
export function PdfDocument(url: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetPdfPrototype(), options, [new URL(url), PDFField]);
+ return assignToDelegate(SetInstanceOptions(GetPdfPrototype(), options, [new URL(url), PDFField]).MakeDelegate(), options);
}
export function WebDocument(url: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetWebPrototype(), options, [new URL(url), WebField]);
+ return assignToDelegate(SetInstanceOptions(GetWebPrototype(), options, [new URL(url), WebField]).MakeDelegate(), options);
}
export function HtmlDocument(html: string, options: DocumentOptions = {}) {
- return SetInstanceOptions(GetWebPrototype(), options, [html, HtmlField]);
+ return assignToDelegate(SetInstanceOptions(GetWebPrototype(), options, [html, HtmlField]).MakeDelegate(), options);
}
export function KVPDocument(document: Document, options: DocumentOptions = {}, id?: string) {
- return SetInstanceOptions(GetKVPPrototype(), options, document, id)
+ return assignToDelegate(SetInstanceOptions(GetKVPPrototype(), options, document, id), options)
}
- export function FreeformDocument(documents: Array<Document>, options: DocumentOptions, id?: string) {
- return SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id)
+ export function FreeformDocument(documents: Array<Document>, options: DocumentOptions, id?: string, makePrototype: boolean = true) {
+ if (!makePrototype) {
+ return SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id)
+ }
+ return assignToDelegate(SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options)
}
export function SchemaDocument(documents: Array<Document>, options: DocumentOptions, id?: string) {
- return SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id)
+ return assignToDelegate(SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options)
}
export function DockDocument(config: string, options: DocumentOptions, id?: string) {
- return SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id)
+ return assignToDelegate(SetInstanceOptions(GetCollectionPrototype(), { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options)
}
// example of custom display string for an image that shows a caption.
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 4a61220a5..c0abec407 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -123,7 +123,7 @@ export namespace DragManager {
// however, PDF's have a thumbnail field that contains an image of their canvas.
// So we replace the pdf's canvas with the image thumbnail
const docView: DocumentView = dragData["documentView"];
- const doc: Document = docView ? docView.props.Document : dragData["document"];
+ const doc: Document = dragData["document"];
if (doc) {
var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement;
diff --git a/src/client/util/jsx-decl.d.ts b/src/client/util/jsx-decl.d.ts
new file mode 100644
index 000000000..532f06178
--- /dev/null
+++ b/src/client/util/jsx-decl.d.ts
@@ -0,0 +1 @@
+declare module 'react-jsx-parser';
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 84c47f616..d7b8bf3c3 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -46,7 +46,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
}
set inkData(value: StrokeMap) {
- this.props.Document.SetData(KeyStore.Ink, value, InkField);
+ this.props.Document.SetOnPrototype(KeyStore.Ink, new InkField(value));
}
componentDidMount() {
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index fb75ef2a5..6616f68d8 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -9,6 +9,8 @@ import "./InkingCanvas.scss"
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
+import { SelectionManager } from "../util/SelectionManager";
+import { KeyStore } from "../../fields/KeyStore";
library.add(faPen, faHighlighter, faEraser, faBan);
@@ -34,6 +36,12 @@ export class InkingControl extends React.Component {
@action
switchColor = (color: ColorResult): void => {
this._selectedColor = color.hex;
+ if (SelectionManager.SelectedDocuments().length == 1) {
+ var sdoc = SelectionManager.SelectedDocuments()[0];
+ if (sdoc.props.ContainingCollectionView && sdoc.props.ContainingCollectionView) {
+ sdoc.props.Document.SetText(KeyStore.BackgroundColor, color.hex);
+ }
+ }
}
@action
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 7942367f5..d0f84f779 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -20,7 +20,6 @@ import { DocumentDecorations } from './DocumentDecorations';
import { DocumentView } from './nodes/DocumentView';
import "./Main.scss";
import { observer } from 'mobx-react';
-import { Field, Opt } from '../../fields/Field';
import { InkingControl } from './InkingControl';
import { RouteStore } from '../../server/RouteStore';
import { json } from 'body-parser';
@@ -41,6 +40,8 @@ import Measure from 'react-measure';
import { DashUserModel } from '../../server/authentication/models/user_model';
import { ServerUtils } from '../../server/ServerUtil';
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
+import { Field, Opt } from '../../fields/Field';
+import { ListField } from '../../fields/ListField';
@observer
export class Main extends React.Component {
@@ -83,6 +84,26 @@ export class Main extends React.Component {
});
}
+ onHistory = () => {
+ if (window.location.pathname !== RouteStore.home) {
+ let pathname = window.location.pathname.split("/");
+ this.mainDocId = pathname[pathname.length - 1];
+ Server.GetField(this.mainDocId, action((field: Opt<Field>) => {
+ if (field instanceof Document) {
+ this.openWorkspace(field, true);
+ }
+ }));
+ }
+ }
+
+ componentDidMount() {
+ window.onpopstate = this.onHistory;
+ }
+
+ componentWillUnmount() {
+ window.onpopstate = null;
+ }
+
initEventListeners = () => {
// window.addEventListener("pointermove", (e) => this.reportLocation(e))
window.addEventListener("drop", (e) => e.preventDefault(), false) // drop event handler
@@ -104,19 +125,18 @@ export class Main extends React.Component {
this.openWorkspace(field);
this.populateWorkspaces();
} else {
- this.createNewWorkspace(true);
+ this.createNewWorkspace(true, this.mainDocId);
}
});
} else {
- this.createNewWorkspace(true);
+ this.createNewWorkspace(true, this.mainDocId);
}
});
-
}
@action
- createNewWorkspace = (init: boolean): void => {
- let mainDoc = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: `Main Container ${this.userWorkspaces.length + 1}` });
+ createNewWorkspace = (init: boolean, id?: string): void => {
+ let mainDoc = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: `Main Container ${this.userWorkspaces.length + 1}` }, id);
let newId = mainDoc.Id;
request.post(ServerUtils.prepend(RouteStore.addWorkspace), {
body: { target: newId },
@@ -130,6 +150,8 @@ export class Main extends React.Component {
mainDoc.SetText(KeyStore.Data, JSON.stringify(dockingLayout));
mainDoc.Set(KeyStore.ActiveFrame, freeformDoc);
this.openWorkspace(mainDoc);
+ let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" })
+ mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument);
}, 0);
this.userWorkspaces.push(mainDoc);
}
@@ -144,13 +166,24 @@ export class Main extends React.Component {
}
@action
- openWorkspace = (doc: Document): void => {
+ openWorkspace = (doc: Document, fromHistory = false): void => {
request.post(ServerUtils.prepend(RouteStore.setActiveWorkspace), {
body: { target: doc.Id },
json: true
});
this.mainContainer = doc;
- this.mainContainer.GetAsync(KeyStore.ActiveFrame, field => this.mainfreeform = field as Document);
+ fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id);
+ this.mainContainer.GetTAsync(KeyStore.ActiveFrame, Document, field => this.mainfreeform = field);
+ this.mainContainer.GetTAsync(KeyStore.OptionalRightCollection, Document, col => {
+ // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized)
+ if (col) {
+ col.GetTAsync<ListField<Document>>(KeyStore.Data, ListField, (f: Opt<ListField<Document>>) => {
+ if (f && f.Data.length > 0) {
+ CollectionDockingView.Instance.AddRightSplit(col);
+ }
+ })
+ }
+ });
}
toggleWorkspaces = () => {
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index e095f0252..f0096109a 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -8,31 +8,17 @@ import { TextField } from "../../../fields/TextField";
import { DragManager } from "../../util/DragManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionPDFView } from "../collections/CollectionPDFView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
-import { CollectionVideoView } from "../collections/CollectionVideoView";
-import { CollectionView } from "../collections/CollectionView";
import { InkingCanvas } from "../InkingCanvas";
-import { AudioBox } from "../nodes/AudioBox";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { DocumentView } from "../nodes/DocumentView";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
-import { ImageBox } from "../nodes/ImageBox";
-import { KeyValueBox } from "../nodes/KeyValueBox";
-import { PDFBox } from "../nodes/PDFBox";
-import { VideoBox } from "../nodes/VideoBox";
-import { WebBox } from "../nodes/WebBox";
+import { DocumentContentsView } from "../nodes/DocumentContentsView";
+import { DocumentViewProps } from "../nodes/DocumentView";
import "./CollectionFreeFormView.scss";
import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
import { CollectionViewBase } from "./CollectionViewBase";
import { MarqueeView } from "./MarqueeView";
import { PreviewCursor } from "./PreviewCursor";
import React = require("react");
-import { Utils } from "../../../Utils";
-const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
import v5 = require("uuid/v5");
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
@observer
export class CollectionFreeFormView extends CollectionViewBase {
@@ -91,12 +77,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
super.drop(e, de);
- const docView: DocumentView = de.data["documentView"];
- let doc: Document = docView ? docView.props.Document : de.data["document"];
+ let screenX = de.x - (de.data["xOffset"] as number || 0);
+ let screenY = de.y - (de.data["yOffset"] as number || 0);
+ const [x, y] = this.getTransform().transformPoint(screenX, screenY);
+ let doc: Document = de.data["document"];
if (doc) {
- let screenX = de.x - (de.data["xOffset"] as number || 0);
- let screenY = de.y - (de.data["yOffset"] as number || 0);
- const [x, y] = this.getTransform().transformPoint(screenX, screenY);
doc.SetNumber(KeyStore.X, x);
doc.SetNumber(KeyStore.Y, y);
this.bringToFront(doc);
@@ -253,6 +238,21 @@ export class CollectionFreeFormView extends CollectionViewBase {
this.props.focus(this.props.Document);
}
+ getDocumentViewProps(document: Document): DocumentViewProps {
+ return {
+ Document: document,
+ AddDocument: this.props.addDocument,
+ RemoveDocument: this.props.removeDocument,
+ ScreenToLocalTransform: this.getTransform,
+ isTopMost: false,
+ SelectOnLoad: document.Id == this._selectOnLoaded,
+ PanelWidth: document.Width,
+ PanelHeight: document.Height,
+ ContentScaling: this.noScaling,
+ ContainingCollectionView: this.props.CollectionView,
+ focus: this.focusDocument
+ }
+ }
@computed
get views() {
@@ -262,18 +262,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
return lvalue.Data.map(doc => {
var page = doc.GetNumber(KeyStore.Page, 0);
return (page != curPage && page != 0) ? (null) :
- (<CollectionFreeFormDocumentView key={doc.Id} Document={doc}
- AddDocument={this.props.addDocument}
- RemoveDocument={this.props.removeDocument}
- ScreenToLocalTransform={this.getTransform}
- isTopMost={false}
- SelectOnLoad={doc.Id === this._selectOnLoaded}
- ContentScaling={this.noScaling}
- PanelWidth={doc.Width}
- PanelHeight={doc.Height}
- ContainingCollectionView={this.props.CollectionView}
- focus={this.focusDocument}
- />);
+ (<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
})
}
return null;
@@ -282,24 +271,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
@computed
get backgroundView() {
return !this.backgroundLayout ? (null) :
- (<JsxParser
- components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
- bindings={this.props.bindings}
- jsx={this.backgroundLayout}
- showWarnings={true}
- onError={(test: any) => console.log(test)}
- />);
+ (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
+ layoutKey={KeyStore.BackgroundLayout} isSelected={() => false} select={() => { }} />);
}
@computed
get overlayView() {
return !this.overlayLayout ? (null) :
- (<JsxParser
- components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
- bindings={this.props.bindings}
- jsx={this.overlayLayout}
- showWarnings={true}
- onError={(test: any) => console.log(test)}
- />);
+ (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
+ layoutKey={KeyStore.OverlayLayout} isSelected={() => false} select={() => { }} />);
}
getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform())
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 957fd0fca..0e8ad44c9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -155,11 +155,11 @@ export class CollectionSchemaView extends CollectionViewBase {
// e.preventDefault();
// } else
{
- if (e.buttons === 1) {
- if (this.props.isSelected()) {
- e.stopPropagation();
- }
- }
+ // if (e.buttons === 1) {
+ // if (this.props.isSelected()) {
+ // e.stopPropagation();
+ // }
+ // }
}
}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index d9b2722a6..40acf466e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -55,7 +55,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
value.push(doc);
} else {
- props.Document.SetData(props.fieldKey, [doc], ListField);
+ props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
}
}
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index c3f7e4951..f3a75dad5 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -1,20 +1,19 @@
-import { action, runInAction, observable, computed } from "mobx";
+import { action, runInAction } from "mobx";
import { Document } from "../../../fields/Document";
import { ListField } from "../../../fields/ListField";
import React = require("react");
import { KeyStore } from "../../../fields/KeyStore";
-import { FieldWaiting } from "../../../fields/Field";
+import { FieldWaiting, Opt } from "../../../fields/Field";
import { undoBatch } from "../../util/UndoManager";
import { DragManager } from "../../util/DragManager";
-import { DocumentView } from "../nodes/DocumentView";
import { Documents, DocumentOptions } from "../../documents/Documents";
import { Key } from "../../../fields/Key";
import { Transform } from "../../util/Transform";
import { CollectionView } from "./CollectionView";
import { RouteStore } from "../../../server/RouteStore";
import { TupleField } from "../../../fields/TupleField";
-import { DashUserModel } from "../../../server/authentication/models/user_model";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { NumberField } from "../../../fields/NumberField";
export interface CollectionViewProps {
fieldKey: Key;
@@ -82,16 +81,26 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
@undoBatch
@action
protected drop(e: Event, de: DragManager.DropEvent) {
- const docView: DocumentView = de.data["documentView"];
- const doc: Document = de.data["document"];
-
- if (docView && (!docView.props.ContainingCollectionView || docView.props.ContainingCollectionView !== this.props.CollectionView)) {
- if (docView.props.RemoveDocument) {
- docView.props.RemoveDocument(docView.props.Document);
+ let docToAlias = de.data["documentToAlias"];
+ let docView = de.data["documentView"];
+ let doc = docToAlias ? docToAlias.CreateAlias() : de.data["document"];
+ if (docToAlias) {
+ [KeyStore.Width, KeyStore.Height].map(key =>
+ docToAlias.GetTAsync(key, NumberField, (f: Opt<NumberField>) => {
+ if (f) {
+ doc.SetNumber(key, f.Data)
+ }
+ })
+ );
+ this.props.addDocument(doc);
+ } else if (docView) {
+ if (doc && docView.props.RemoveDocument && docView.props.ContainingCollectionView !== this.props.CollectionView) {
+ docView.props.RemoveDocument(doc);
+ this.props.removeDocument(doc); // bcz: not good -- want to check if it's there and then add if it isn't
+ this.props.addDocument(doc);
}
- this.props.addDocument(docView.props.Document);
} else if (doc) {
- this.props.removeDocument(doc);
+ this.props.removeDocument(doc); // bcz: not good -- want to check if it's there and then add if it isn't
this.props.addDocument(doc);
}
e.stopPropagation();
@@ -129,7 +138,6 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
let type = item.type
console.log(type)
if (item.kind == "file") {
- let fReader = new FileReader()
let file = item.getAsFile();
let formData = new FormData()
diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx
index 65aaa837f..f5c83a934 100644
--- a/src/client/views/collections/MarqueeView.tsx
+++ b/src/client/views/collections/MarqueeView.tsx
@@ -121,7 +121,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
let centerShiftY = 0 - (selRect.top + selRect.height / 2);
let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- if (ink && ink != FieldWaiting) {
+ if (ink && ink != FieldWaiting && ink.Data) {
let idata = new Map();
ink.Data.forEach((value: StrokeData, key: string, map: any) => {
let inside = InkingCanvas.IntersectStrokeRect(value, selRect);
diff --git a/src/client/views/collections/PreviewCursor.tsx b/src/client/views/collections/PreviewCursor.tsx
index a1411250a..cbcfa568d 100644
--- a/src/client/views/collections/PreviewCursor.tsx
+++ b/src/client/views/collections/PreviewCursor.tsx
@@ -1,16 +1,12 @@
-import { trace } from "mobx";
-import "./PreviewCursor.scss";
-import React = require("react");
import { action, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
-import { FieldWaiting, Opt } from "../../../fields/Field";
-import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
+import { Opt } from "../../../fields/Field";
import { Documents } from "../../documents/Documents";
-import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
+import "./PreviewCursor.scss";
+import React = require("react");
export interface PreviewCursorProps {
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 55b4938a0..ce72ab64b 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,33 +1,55 @@
-import { Document } from "../../../fields/Document";
-import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
+import { computed } from "mobx";
+import { observer } from "mobx-react";
+import { FieldWaiting } from "../../../fields/Field";
+import { Key } from "../../../fields/Key";
+import { KeyStore } from "../../../fields/KeyStore";
+import { ListField } from "../../../fields/ListField";
import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
-import { CollectionView, CollectionViewType } from "../collections/CollectionView";
+import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
import { CollectionPDFView } from "../collections/CollectionPDFView";
+import { CollectionSchemaView } from "../collections/CollectionSchemaView";
import { CollectionVideoView } from "../collections/CollectionVideoView";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
-import { ImageBox } from "../nodes/ImageBox";
-import { VideoBox } from "../nodes/VideoBox";
-import { AudioBox } from "../nodes/AudioBox";
-import { KeyValueBox } from "./KeyValueBox"
-import { WebBox } from "../nodes/WebBox";
-import { PDFBox } from "../nodes/PDFBox";
+import { CollectionView } from "../collections/CollectionView";
+import { AudioBox } from "./AudioBox";
+import { DocumentViewProps, JsxBindings } from "./DocumentView";
import "./DocumentView.scss";
+import { FormattedTextBox } from "./FormattedTextBox";
+import { ImageBox } from "./ImageBox";
+import { KeyValueBox } from "./KeyValueBox";
+import { PDFBox } from "./PDFBox";
+import { VideoBox } from "./VideoBox";
+import { WebBox } from "./WebBox";
import React = require("react");
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
-interface JsxBindings {
- Document: Document;
- layout: string;
- [prop: string]: any;
-}
-export class DocumentContentsView extends React.PureComponent<JsxBindings> {
+@observer
+export class DocumentContentsView extends React.Component<DocumentViewProps & {
+ isSelected: () => boolean,
+ select: (ctrl: boolean) => void,
+ layoutKey: Key
+}> {
+ @computed get layout(): string { return this.props.Document.GetText(this.props.layoutKey, "<p>Error loading layout data</p>"); }
+ @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
+ @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
+
+ CreateBindings(): JsxBindings {
+ let bindings: JsxBindings = { ...this.props, };
+ for (const key of this.layoutKeys) {
+ bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
+ }
+ for (const key of this.layoutFields) {
+ let field = this.props.Document.Get(key);
+ bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
+ }
+ return bindings;
+ }
+
render() {
return <JsxParser
components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
- bindings={this.props}
- jsx={this.props.layout}
+ bindings={this.CreateBindings()}
+ jsx={this.layout}
showWarnings={true}
onError={(test: any) => { console.log(test) }}
/>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7a43c34d0..6a3967b3b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,11 +1,12 @@
import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
-import { Field, FieldWaiting, Opt } from "../../../fields/Field";
+import { Field, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
import { TextField } from "../../../fields/TextField";
+import { Utils } from "../../../Utils";
import { Documents } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager } from "../../util/DragManager";
@@ -14,11 +15,9 @@ import { Transform } from "../../util/Transform";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../collections/CollectionView";
import { ContextMenu } from "../ContextMenu";
+import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
-import { DocumentContentsView } from "./DocumentContentsView";
-import { Utils } from "../../../Utils";
-const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
export interface DocumentViewProps {
@@ -76,6 +75,17 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
return args;
}
+export interface JsxBindings {
+ Document: Document;
+ isSelected: () => boolean;
+ select: (isCtrlPressed: boolean) => void;
+ isTopMost: boolean;
+ SelectOnLoad: boolean;
+ [prop: string]: any;
+}
+
+
+
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
@@ -93,7 +103,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
this._downY = e.clientY;
if (e.shiftKey && e.buttons === 2) {
if (this.props.isTopMost) {
- this.startDragging(e.pageX, e.pageY);
+ this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey);
}
else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e);
e.stopPropagation();
@@ -150,18 +160,19 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
- startDragging(x: number, y: number) {
+ startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
if (this._mainCont.current) {
const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
let dragData: { [id: string]: any } = {};
dragData["documentView"] = this;
+ dragData[dropAliasOfDraggedDoc ? "documentToAlias" : "document"] = this.props.Document;
dragData["xOffset"] = x - left;
dragData["yOffset"] = y - top;
DragManager.StartDrag(this._mainCont.current, dragData, {
handlers: {
dragComplete: action(() => { }),
},
- hideSource: true
+ hideSource: !dropAliasOfDraggedDoc
})
}
}
@@ -174,7 +185,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
document.removeEventListener("pointermove", this.onPointerMove)
document.removeEventListener("pointerup", this.onPointerUp);
if (!this.topMost || e.buttons == 2 || e.altKey) {
- this.startDragging(e.x, e.y);
+ this.startDragging(e.x, e.y, e.ctrlKey || e.altKey);
}
}
e.stopPropagation();
@@ -200,7 +211,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
fieldsClicked = (e: React.MouseEvent): void => {
if (this.props.AddDocument) {
- this.props.AddDocument(Documents.KVPDocument(this.props.Document));
+ this.props.AddDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }));
}
}
fullScreenClicked = (e: React.MouseEvent): void => {
@@ -298,26 +309,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
SelectionManager.SelectDoc(this, ctrlPressed)
}
- @computed
- get getProps() {
- let bindings: any = {
- ...this.props,
- isSelected: this.isSelected,
- select: this.select,
- layout: this.layout
- };
- for (const key of this.layoutKeys) {
- bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
- }
- for (const key of this.layoutFields) {
- let field = this.props.Document.Get(key);
- bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
- }
- bindings.bindings = bindings;
-
- return bindings
- }
-
render() {
if (!this.props.Document) {
return (null);
@@ -341,10 +332,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}}
onDrop={this.onDrop}
onContextMenu={this.onContextMenu}
- onPointerDown={this.onPointerDown}
- onPointerUp={this.stopPropogation} >
- <DocumentContentsView {...this.getProps} />
- </div>
+ onPointerDown={this.onPointerDown} >
+ <DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />
+ </div >
)
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d7026ed67..4bd5726f4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -55,7 +55,9 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
if (this._editorView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- this.props.doc.SetData(this.props.fieldKey, JSON.stringify(state.toJSON()), RichTextField);
+ const { doc, fieldKey } = this.props;
+ doc.SetOnPrototype(fieldKey, new RichTextField(JSON.stringify(state.toJSON())))
+ // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField);
}
}
@@ -114,7 +116,9 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
@action
onChange(e: React.ChangeEvent<HTMLInputElement>) {
- this.props.doc.SetData(this.props.fieldKey, e.target.value, RichTextField);
+ const { fieldKey, doc } = this.props;
+ doc.SetOnPrototype(fieldKey, new RichTextField(e.target.value))
+ // doc.SetData(fieldKey, e.target.value, RichTextField);
}
onPointerDown = (e: React.PointerEvent): void => {
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index cad8904d0..2db0cc4e2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -10,6 +10,7 @@ import { ContextMenu } from "../../views/ContextMenu";
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react")
+import { Utils } from '../../../Utils';
@observer
export class ImageBox extends React.Component<FieldViewProps> {
@@ -89,12 +90,16 @@ export class ImageBox extends React.Component<FieldViewProps> {
}
}
- //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE
- imageCapability = (e: React.MouseEvent): void => {
- }
-
specificContextMenu = (e: React.MouseEvent): void => {
- ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability });
+ let field = this.props.doc.GetT(this.props.fieldKey, ImageField);
+ if (field && field !== FieldWaiting) {
+ let url = field.Data.href;
+ ContextMenu.Instance.addItem({
+ description: "Copy path", event: () => {
+ Utils.CopyText(url)
+ }
+ });
+ }
}
render() {
diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx
index 7bc70615f..c8de33f41 100644
--- a/src/debug/Test.tsx
+++ b/src/debug/Test.tsx
@@ -1,46 +1,29 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
+import JsxParser from 'react-jsx-parser'
-class TestInternal extends React.Component {
- onContextMenu = (e: React.MouseEvent) => {
- console.log("Internal");
- e.stopPropagation();
- }
-
- onPointerDown = (e: React.MouseEvent) => {
- console.log("pointer down")
- e.preventDefault();
- }
-
- render() {
- return <div onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}
- onPointerUp={this.onPointerDown}>Hello world</div>
- }
-}
-
-class TestChild extends React.Component {
- onContextMenu = () => {
- console.log("Child");
- }
-
+class Hello extends React.Component<{ firstName: string, lastName: string }> {
render() {
- return <div onContextMenu={this.onContextMenu}><TestInternal /></div>
+ return <div>Hello {this.props.firstName} {this.props.lastName}</div>
}
}
-class TestParent extends React.Component {
- onContextMenu = () => {
- console.log("Parent");
- }
-
+class Test extends React.Component {
render() {
- return <div onContextMenu={this.onContextMenu}><TestChild /></div>
+ let jsx = "<Hello {...props}/>";
+ let bindings = {
+ props: {
+ firstName: "First",
+ lastName: "Last"
+ }
+ }
+ return <JsxParser jsx={jsx} bindings={bindings} components={{ Hello }}></JsxParser>
}
}
ReactDOM.render((
<div style={{ position: "absolute", width: "100%", height: "100%" }}>
- <TestParent />
+ <Test />
</div>),
document.getElementById('root')
); \ No newline at end of file
diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx
index 780e9f8f2..7fdd77bf3 100644
--- a/src/debug/Viewer.tsx
+++ b/src/debug/Viewer.tsx
@@ -137,11 +137,13 @@ class DebugViewer extends React.Component<{ fieldId: string }> {
content = (<FieldViewer field={this.field} />)
} else if (this.field instanceof Key) {
content = (<KeyViewer field={this.field} />)
+ } else {
+ content = (<span>Unrecognized field type</span>)
}
} else if (this.error) {
content = <span>Field <b>{this.props.fieldId}</b> not found <button onClick={() => this.update()}>Refresh</button></span>
} else {
- content = <>Field loading</>
+ content = <span>Field loading: {this.props.fieldId}</span>
}
return content;
}
diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts
index aefcc15c1..8864471ae 100644
--- a/src/fields/AudioField.ts
+++ b/src/fields/AudioField.ts
@@ -10,8 +10,8 @@ export class AudioField extends BasicField<URL> {
toString(): string {
return this.Data.href;
}
-
-
+
+
ToScriptString(): string {
return `new AudioField("${this.Data}")`;
}
@@ -20,10 +20,10 @@ export class AudioField extends BasicField<URL> {
return new AudioField(this.Data);
}
- ToJson(): { type: Types, data: URL, _id: string } {
+ ToJson(): { type: Types, data: string, _id: string } {
return {
type: Types.Audio,
- data: this.Data,
+ data: this.Data.href,
_id: this.Id
}
}
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 25e239417..763b79de2 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -2,7 +2,7 @@ import { Key } from "./Key"
import { KeyStore } from "./KeyStore";
import { Field, Cast, FieldWaiting, FieldValue, FieldId, Opt } from "./Field"
import { NumberField } from "./NumberField";
-import { ObservableMap, computed, action } from "mobx";
+import { ObservableMap, computed, action, runInAction } from "mobx";
import { TextField } from "./TextField";
import { ListField } from "./ListField";
import { Server } from "../client/Server";
@@ -11,6 +11,7 @@ import { UndoManager } from "../client/util/UndoManager";
import { HtmlField } from "./HtmlField";
export class Document extends Field {
+ //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field
public fields: ObservableMap<string, { key: Key, field: Field }> = new ObservableMap();
public _proxies: ObservableMap<string, FieldId> = new ObservableMap();
@@ -119,9 +120,11 @@ export class Document extends Field {
* @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise
*/
GetAsync(key: Key, callback: (field: Field) => void): boolean {
- //TODO: This should probably check if this.fields contains the key before calling Server.GetDocumentField
- //This currently doesn't deal with prototypes
- if (this._proxies.has(key.Id)) {
+ //TODO: This currently doesn't deal with prototypes
+ let field = this.fields.get(key.Id);
+ if (field && field.field) {
+ callback(field.field);
+ } else if (this._proxies.has(key.Id)) {
Server.GetDocumentField(this, key, callback);
return true;
}
@@ -207,25 +210,37 @@ export class Document extends Field {
}
@action
- Set(key: Key, field: Field | undefined): void {
+ SetOnPrototype(key: Key, field: Field | undefined): void {
+ this.GetAsync(KeyStore.Prototype, (f: Field) => {
+ (f as Document).Set(key, field)
+ })
+ }
+
+ @action
+ Set(key: Key, field: Field | undefined, setOnPrototype = false): void {
let old = this.fields.get(key.Id);
let oldField = old ? old.field : undefined;
- if (field) {
- this.fields.set(key.Id, { key, field });
- this._proxies.set(key.Id, field.Id)
- // Server.AddDocumentField(this, key, field);
- } else {
- this.fields.delete(key.Id);
- this._proxies.delete(key.Id)
- // Server.DeleteDocumentField(this, key);
+ if (setOnPrototype) {
+ this.SetOnPrototype(key, field)
+ }
+ else {
+ if (field) {
+ this.fields.set(key.Id, { key, field });
+ this._proxies.set(key.Id, field.Id)
+ // Server.AddDocumentField(this, key, field);
+ } else {
+ this.fields.delete(key.Id);
+ this._proxies.delete(key.Id)
+ // Server.DeleteDocumentField(this, key);
+ }
+ Server.UpdateField(this);
}
if (oldField || field) {
UndoManager.AddEvent({
- undo: () => this.Set(key, oldField),
- redo: () => this.Set(key, field)
+ undo: () => this.Set(key, oldField, setOnPrototype),
+ redo: () => this.Set(key, field, setOnPrototype)
})
}
- Server.UpdateField(this);
}
@action
@@ -265,6 +280,15 @@ export class Document extends Field {
return protos;
}
+ CreateAlias(id?: string): Document {
+ let alias = new Document(id)
+ this.GetAsync(KeyStore.Prototype, (f: Field) => {
+ alias.Set(KeyStore.Prototype, f)
+ })
+
+ return alias
+ }
+
MakeDelegate(id?: string): Document {
let delegate = new Document(id);
diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts
index a07326095..7cbdf7e58 100644
--- a/src/fields/HtmlField.ts
+++ b/src/fields/HtmlField.ts
@@ -15,7 +15,7 @@ export class HtmlField extends BasicField<string> {
return new HtmlField(this.Data);
}
- ToJson(): { _id: string; type: Types; data: any; } {
+ ToJson(): { _id: string; type: Types; data: string; } {
return {
type: Types.Html,
data: this.Data,
diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts
index be8d73e68..a9ece7d7b 100644
--- a/src/fields/ImageField.ts
+++ b/src/fields/ImageField.ts
@@ -19,10 +19,10 @@ export class ImageField extends BasicField<URL> {
return new ImageField(this.Data);
}
- ToJson(): { type: Types, data: URL, _id: string } {
+ ToJson(): { type: Types, data: string, _id: string } {
return {
type: Types.Image,
- data: this.Data,
+ data: this.Data.href,
_id: this.Id
}
}
diff --git a/src/fields/KVPField.ts b/src/fields/KVPField.ts
deleted file mode 100644
index a7ecc0768..000000000
--- a/src/fields/KVPField.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { BasicField } from "./BasicField"
-import { FieldId } from "./Field";
-import { Types } from "../server/Message";
-import { Document } from "./Document"
-
-export class KVPField extends BasicField<Document> {
- constructor(data: Document | undefined = undefined, id?: FieldId, save: boolean = true) {
- super(data == undefined ? new Document() : data, save, id);
- }
-
- toString(): string {
- return this.Data.Title;
- }
-
- ToScriptString(): string {
- return `new KVPField("${this.Data}")`;
- }
-
- Copy() {
- return new KVPField(this.Data);
- }
-
- ToJson(): { type: Types, data: Document, _id: string } {
- return {
- type: Types.Text,
- data: this.Data,
- _id: this.Id
- }
- }
-} \ No newline at end of file
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index c6e58ee35..68883d6f1 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -38,4 +38,7 @@ export namespace KeyStore {
export const NumPages = new Key("NumPages");
export const Ink = new Key("Ink");
export const Cursors = new Key("Cursors");
+ export const OptionalRightCollection = new Key("OptionalRightCollection");
+ export const Archives = new Key("Archives");
+ export const Updated = new Key("Updated");
}
diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts
index ce32da0a6..77c1d6e14 100644
--- a/src/fields/ListField.ts
+++ b/src/fields/ListField.ts
@@ -16,6 +16,8 @@ export class ListField<T extends Field> extends BasicField<T[]> {
this.observeList();
}
+ private _processingServerUpdate: boolean = false;
+
private observeDisposer: Lambda | undefined;
private observeList(): void {
this.observeDisposer = observe(this.Data as IObservableArray<T>, (change: IArrayChange<T> | IArraySplice<T>) => {
@@ -31,7 +33,8 @@ export class ListField<T extends Field> extends BasicField<T[]> {
redo: () => this.Data[change.index] = change.newValue
})
}
- Server.UpdateField(this);
+ if (!this._processingServerUpdate)
+ Server.UpdateField(this);
});
}
@@ -69,30 +72,29 @@ export class ListField<T extends Field> extends BasicField<T[]> {
init(callback: (field: Field) => any) {
Server.GetFields(this._proxies, action((fields: { [index: string]: Field }) => {
- if (!this.arraysEqual(this._proxies, this.Data.map(field => field.Id))) {
+ if (!this.arraysEqual(this._proxies, this.data.map(field => field.Id))) {
var dataids = this.data.map(d => d.Id);
- var added = this.data.length == this._proxies.length - 1;
+ var proxies = this._proxies.map(p => p);
+ var added = this.data.length < this._proxies.length;
var deleted = this.data.length > this._proxies.length;
for (let i = 0; i < dataids.length && added; i++)
- added = this._proxies.indexOf(dataids[i]) != -1;
+ added = proxies.indexOf(dataids[i]) != -1;
for (let i = 0; i < this._proxies.length && deleted; i++)
- deleted = dataids.indexOf(this._proxies[i]) != -1;
- if (added) { // if only 1 items was added
- for (let i = 0; i < this._proxies.length; i++)
- if (dataids.indexOf(this._proxies[i]) === -1)
- this.Data.splice(i, 0, fields[this._proxies[i]] as T);
- } else if (deleted) { // if only items were deleted
- for (let i = this.data.length - 1; i >= 0; i--) {
- if (this._proxies.indexOf(this.data[i].Id) === -1) {
- this.Data.splice(i, 1);
- }
- }
- } else // otherwise, just rebuild the whole list
- this.data = this._proxies.map(id => fields[id] as T)
- observe(this.Data, () => {
- this.updateProxies()
- Server.UpdateField(this);
- })
+ deleted = dataids.indexOf(proxies[i]) != -1;
+
+ this._processingServerUpdate = true;
+ for (let i = 0; i < proxies.length && added; i++) {
+ if (dataids.indexOf(proxies[i]) === -1)
+ this.Data.splice(i, 0, fields[proxies[i]] as T);
+ }
+ for (let i = dataids.length - 1; i >= 0 && deleted; i--) {
+ if (proxies.indexOf(dataids[i]) === -1)
+ this.Data.splice(i, 1);
+ }
+ if (!added && !deleted) {// otherwise, just rebuild the whole list
+ this.setData(proxies.map(id => fields[id] as T));
+ }
+ this._processingServerUpdate = false;
}
callback(this);
}))
diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts
index f3a009001..b6625387e 100644
--- a/src/fields/PDFField.ts
+++ b/src/fields/PDFField.ts
@@ -22,10 +22,10 @@ export class PDFField extends BasicField<URL> {
return `new PDFField("${this.Data}")`;
}
- ToJson(): { type: Types, data: URL, _id: string } {
+ ToJson(): { type: Types, data: string, _id: string } {
return {
type: Types.PDF,
- data: this.Data,
+ data: this.Data.href,
_id: this.Id
}
}
diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts
index 5f4ae19bf..626e4ec83 100644
--- a/src/fields/VideoField.ts
+++ b/src/fields/VideoField.ts
@@ -19,10 +19,10 @@ export class VideoField extends BasicField<URL> {
return new VideoField(this.Data);
}
- ToJson(): { type: Types, data: URL, _id: string } {
+ ToJson(): { type: Types, data: string, _id: string } {
return {
type: Types.Video,
- data: this.Data,
+ data: this.Data.href,
_id: this.Id
}
}
diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts
index 8f945d686..6c4de5000 100644
--- a/src/fields/WebField.ts
+++ b/src/fields/WebField.ts
@@ -19,10 +19,10 @@ export class WebField extends BasicField<URL> {
return new WebField(this.Data);
}
- ToJson(): { type: Types, data: URL, _id: string } {
+ ToJson(): { type: Types, data: string, _id: string } {
return {
type: Types.Web,
- data: this.Data,
+ data: this.Data.href,
_id: this.Id
}
}
diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss
new file mode 100644
index 000000000..d0b7d4e41
--- /dev/null
+++ b/src/mobile/ImageUpload.scss
@@ -0,0 +1,13 @@
+.imgupload_cont {
+ height: 100vh;
+ width: 100vw;
+ align-content: center;
+ .button_file {
+ text-align: center;
+ height: 50%;
+ width: 50%;
+ background-color: paleturquoise;
+ color: grey;
+ font-size: 3em;
+ }
+} \ No newline at end of file
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
new file mode 100644
index 000000000..292a3a035
--- /dev/null
+++ b/src/mobile/ImageUpload.tsx
@@ -0,0 +1,79 @@
+import * as ReactDOM from 'react-dom';
+import React = require('react');
+import "./ImageUpload.scss"
+import { action, runInAction } from "mobx";
+import { type } from 'os';
+import { Documents } from '../client/documents/Documents';
+import { Document } from '../fields/Document';
+import { Server } from '../client/Server';
+import { Opt, Field } from '../fields/Field';
+import { ListField } from '../fields/ListField';
+import { KeyStore } from '../fields/KeyStore';
+import { ImageField } from '../fields/ImageField';
+
+
+
+
+// const onPointerDown = (e: React.TouchEvent) => {
+// let imgInput = document.getElementById("input_image_file");
+// if (imgInput) {
+// imgInput.click();
+// }
+// }
+const pendingDocId = "pending-doc"
+
+const onFileLoad = (file: any) => {
+ let imgPrev = document.getElementById("img_preview")
+ if (imgPrev) {
+ let files: File[] = file.target.files;
+ if (files.length != 0) {
+ console.log(files[0]);
+ let formData = new FormData();
+ formData.append("file", files[0]);
+
+ const upload = window.location.origin + "/upload"
+ fetch(upload, {
+ method: 'POST',
+ body: formData
+ }).then((res: Response) => {
+ return res.json()
+ }).then(json => {
+ json.map((file: any) => {
+ let path = window.location.origin + file
+ runInAction(() => {
+ var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 })
+ doc.GetTAsync(KeyStore.Data, ImageField, (i) => {
+ if (i) {
+ document.getElementById("message")!.innerText = i.Data.href;
+ }
+ })
+ Server.GetField(pendingDocId, (res: Opt<Field>) => {
+ if (res) {
+ if (res instanceof Document) {
+ res.GetOrCreateAsync(KeyStore.Data, ListField, (f: ListField<Document>) => {
+ f.Data.push(doc)
+ })
+ }
+ }
+ })
+ })
+ })
+ })
+ // console.log(window.location.origin + file[0])
+
+ //imgPrev.setAttribute("src", window.location.origin + files[0].name)
+ }
+ }
+
+
+}
+
+ReactDOM.render((
+ <div className="imgupload_cont">
+ {/* <button className = "button_file" = {onPointerDown}> Open Image </button> */}
+ <input type="file" accept="image/*" onChange={onFileLoad} className="input_file" id="input_image_file"></input>
+ <img id="img_preview" src=""></img>
+ <div id="message" />
+ </div>),
+ document.getElementById('root')
+); \ No newline at end of file
diff --git a/src/fields/KVPField b/src/mobile/InkControls.tsx
index e69de29bb..e69de29bb 100644
--- a/src/fields/KVPField
+++ b/src/mobile/InkControls.tsx
diff --git a/src/server/RouteStore.ts b/src/server/RouteStore.ts
index 683fd6d7e..fb06b878b 100644
--- a/src/server/RouteStore.ts
+++ b/src/server/RouteStore.ts
@@ -6,6 +6,7 @@ export enum RouteStore {
home = "/home",
corsProxy = "/corsProxy",
delete = "/delete",
+ deleteAll = "/deleteAll",
// UPLOAD AND STATIC FILE SERVING
public = "/public",
diff --git a/src/server/database.ts b/src/server/database.ts
index 164bdd68a..99b13805e 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -32,9 +32,9 @@ export class Database {
}
}
- public deleteAll() {
+ public deleteAll(collectionName: string = 'documents') {
if (this.db) {
- let collection = this.db.collection('documents');
+ let collection = this.db.collection(collectionName);
collection.deleteMany({});
}
}
diff --git a/src/server/index.ts b/src/server/index.ts
index 6d8dd2d6c..5773514ea 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -25,6 +25,7 @@ import flash = require('connect-flash');
import * as bodyParser from 'body-parser';
import * as session from 'express-session';
import * as cookieParser from 'cookie-parser';
+import * as mobileDetect from 'mobile-detect';
import c = require("crypto");
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
@@ -32,6 +33,7 @@ import { DashUserModel } from './authentication/models/user_model';
import * as fs from 'fs';
import * as request from 'request'
import { RouteStore } from './RouteStore';
+import { exec } from 'child_process'
const download = (url: string, dest: fs.PathLike) => {
request.get(url).pipe(fs.createWriteStream(dest));
@@ -116,6 +118,16 @@ let FieldStore: ObservableMap<FieldId, Field> = new ObservableMap();
app.use(express.static(__dirname + RouteStore.public));
app.use(RouteStore.images, express.static(__dirname + RouteStore.public))
+app.get("/pull", (req, res) => {
+ exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => {
+ if (err) {
+ res.send(err.message);
+ return;
+ }
+ res.redirect("/");
+ })
+});
+
// GETTERS
// anyone attempting to navigate to localhost at this port will
@@ -129,7 +141,14 @@ addSecureRoute(
addSecureRoute(
Method.GET,
- (user, res) => res.sendFile(path.join(__dirname, '../../deploy/index.html')),
+ (user, res, req) => {
+ let detector = new mobileDetect(req.headers['user-agent'] || "");
+ if (detector.mobile() != null) {
+ res.sendFile(path.join(__dirname, '../../deploy/mobile/image.html'));
+ } else {
+ res.sendFile(path.join(__dirname, '../../deploy/index.html'));
+ }
+ },
undefined,
RouteStore.home,
RouteStore.openDocumentWithId
@@ -233,6 +252,11 @@ app.use(RouteStore.corsProxy, (req, res) => {
});
app.get(RouteStore.delete, (req, res) => {
+ deleteFields();
+ res.redirect(RouteStore.home);
+});
+
+app.get(RouteStore.deleteAll, (req, res) => {
deleteAll();
res.redirect(RouteStore.home);
});
@@ -263,11 +287,17 @@ server.on("connection", function (socket: Socket) {
Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args))
Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField)
Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields)
- Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteAll)
+ Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields)
})
+function deleteFields() {
+ Database.Instance.deleteAll();
+}
+
function deleteAll() {
Database.Instance.deleteAll();
+ Database.Instance.deleteAll('sessions');
+ Database.Instance.deleteAll('users');
}
function barReceived(guid: String) {
diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts
index e4a66f7f2..7939ae8be 100644
--- a/src/typings/index.d.ts
+++ b/src/typings/index.d.ts
@@ -1,322 +1,322 @@
/// <reference types="node" />
declare module '@react-pdf/renderer' {
- import * as React from 'react';
-
- namespace ReactPDF {
- interface Style {
- [property: string]: any;
- }
- interface Styles {
- [key: string]: Style;
- }
- type Orientation = 'portrait' | 'landscape';
-
- interface DocumentProps {
- title?: string;
- author?: string;
- subject?: string;
- keywords?: string;
- creator?: string;
- producer?: string;
- onRender?: () => any;
- }
-
- /**
- * This component represent the PDF document itself. It must be the root
- * of your tree element structure, and under no circumstances should it be
- * used as children of another react-pdf component. In addition, it should
- * only have childs of type <Page />.
- */
- class Document extends React.Component<DocumentProps> {}
-
- interface NodeProps {
- style?: Style | Style[];
- /**
- * Render component in all wrapped pages.
- * @see https://react-pdf.org/advanced#fixed-components
- */
- fixed?: boolean;
- /**
- * Force the wrapping algorithm to start a new page when rendering the
- * element.
- * @see https://react-pdf.org/advanced#page-breaks
- */
- break?: boolean;
- }
-
- interface PageProps extends NodeProps {
- /**
- * Enable page wrapping for this page.
- * @see https://react-pdf.org/components#page-wrapping
- */
- wrap?: boolean;
- debug?: boolean;
- size?: string | [number, number] | {width: number; height: number};
- orientation?: Orientation;
- ruler?: boolean;
- rulerSteps?: number;
- verticalRuler?: boolean;
- verticalRulerSteps?: number;
- horizontalRuler?: boolean;
- horizontalRulerSteps?: number;
- ref?: Page;
- }
-
- /**
- * Represents single page inside the PDF document, or a subset of them if
- * using the wrapping feature. A <Document /> can contain as many pages as
- * you want, but ensure not rendering a page inside any component besides
- * Document.
- */
- class Page extends React.Component<PageProps> {}
-
- interface ViewProps extends NodeProps {
- /**
- * Enable/disable page wrapping for element.
- * @see https://react-pdf.org/components#page-wrapping
- */
- wrap?: boolean;
- debug?: boolean;
- render?: (props: {pageNumber: number}) => React.ReactNode;
- children?: React.ReactNode;
- }
-
+ import * as React from 'react';
+
+ namespace ReactPDF {
+ interface Style {
+ [property: string]: any;
+ }
+ interface Styles {
+ [key: string]: Style;
+ }
+ type Orientation = 'portrait' | 'landscape';
+
+ interface DocumentProps {
+ title?: string;
+ author?: string;
+ subject?: string;
+ keywords?: string;
+ creator?: string;
+ producer?: string;
+ onRender?: () => any;
+ }
+
+ /**
+ * This component represent the PDF document itself. It must be the root
+ * of your tree element structure, and under no circumstances should it be
+ * used as children of another react-pdf component. In addition, it should
+ * only have childs of type <Page />.
+ */
+ class Document extends React.Component<DocumentProps> { }
+
+ interface NodeProps {
+ style?: Style | Style[];
/**
- * The most fundamental component for building a UI and is designed to be
- * nested inside other views and can have 0 to many children.
+ * Render component in all wrapped pages.
+ * @see https://react-pdf.org/advanced#fixed-components
*/
- class View extends React.Component<ViewProps> {}
-
- interface ImageProps extends NodeProps {
- debug?: boolean;
- src: string | {data: Buffer; format: 'png' | 'jpg'};
- cache?: boolean;
- }
-
+ fixed?: boolean;
/**
- * A React component for displaying network or local (Node only) JPG or
- * PNG images, as well as base64 encoded image strings.
+ * Force the wrapping algorithm to start a new page when rendering the
+ * element.
+ * @see https://react-pdf.org/advanced#page-breaks
*/
- class Image extends React.Component<ImageProps> {}
-
- interface TextProps extends NodeProps {
- /**
- * Enable/disable page wrapping for element.
- * @see https://react-pdf.org/components#page-wrapping
- */
- wrap?: boolean;
- debug?: boolean;
- render?: (
- props: {pageNumber: number; totalPages: number},
- ) => React.ReactNode;
- children?: React.ReactNode;
- /**
- * How much hyphenated breaks should be avoided.
- */
- hyphenationCallback?: number;
- }
-
+ break?: boolean;
+ }
+
+ interface PageProps extends NodeProps {
/**
- * A React component for displaying text. Text supports nesting of other
- * Text or Link components to create inline styling.
+ * Enable page wrapping for this page.
+ * @see https://react-pdf.org/components#page-wrapping
*/
- class Text extends React.Component<TextProps> {}
-
- interface LinkProps extends NodeProps {
- /**
- * Enable/disable page wrapping for element.
- * @see https://react-pdf.org/components#page-wrapping
- */
- wrap?: boolean;
- debug?: boolean;
- src: string;
- children?: React.ReactNode;
- }
-
+ wrap?: boolean;
+ debug?: boolean;
+ size?: string | [number, number] | { width: number; height: number };
+ orientation?: Orientation;
+ ruler?: boolean;
+ rulerSteps?: number;
+ verticalRuler?: boolean;
+ verticalRulerSteps?: number;
+ horizontalRuler?: boolean;
+ horizontalRulerSteps?: number;
+ ref?: Page;
+ }
+
+ /**
+ * Represents single page inside the PDF document, or a subset of them if
+ * using the wrapping feature. A <Document /> can contain as many pages as
+ * you want, but ensure not rendering a page inside any component besides
+ * Document.
+ */
+ class Page extends React.Component<PageProps> { }
+
+ interface ViewProps extends NodeProps {
/**
- * A React component for displaying an hyperlink. Link’s can be nested
- * inside a Text component, or being inside any other valid primitive.
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
*/
- class Link extends React.Component<LinkProps> {}
-
- interface NoteProps extends NodeProps {
- children: string;
- }
-
- class Note extends React.Component<NoteProps> {}
-
- interface BlobProviderParams {
- blob: Blob | null;
- url: string | null;
- loading: boolean;
- error: Error | null;
- }
- interface BlobProviderProps {
- document: React.ReactElement<DocumentProps>;
- children: (params: BlobProviderParams) => React.ReactNode;
- }
-
+ wrap?: boolean;
+ debug?: boolean;
+ render?: (props: { pageNumber: number }) => React.ReactNode;
+ children?: React.ReactNode;
+ }
+
+ /**
+ * The most fundamental component for building a UI and is designed to be
+ * nested inside other views and can have 0 to many children.
+ */
+ class View extends React.Component<ViewProps> { }
+
+ interface ImageProps extends NodeProps {
+ debug?: boolean;
+ src: string | { data: Buffer; format: 'png' | 'jpg' };
+ cache?: boolean;
+ }
+
+ /**
+ * A React component for displaying network or local (Node only) JPG or
+ * PNG images, as well as base64 encoded image strings.
+ */
+ class Image extends React.Component<ImageProps> { }
+
+ interface TextProps extends NodeProps {
/**
- * Easy and declarative way of getting document's blob data without
- * showing it on screen.
- * @see https://react-pdf.org/advanced#on-the-fly-rendering
- * @platform web
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
*/
- class BlobProvider extends React.Component<BlobProviderProps> {}
-
- interface PDFViewerProps {
- width?: number;
- height?: number;
- style?: Style | Style[];
- className?: string;
- children?: React.ReactElement<DocumentProps>;
- }
-
+ wrap?: boolean;
+ debug?: boolean;
+ render?: (
+ props: { pageNumber: number; totalPages: number },
+ ) => React.ReactNode;
+ children?: React.ReactNode;
/**
- * Iframe PDF viewer for client-side generated documents.
- * @platform web
+ * How much hyphenated breaks should be avoided.
*/
- class PDFViewer extends React.Component<PDFViewerProps> {}
-
- interface PDFDownloadLinkProps {
- document: React.ReactElement<DocumentProps>;
- fileName?: string;
- style?: Style | Style[];
- className?: string;
- children?:
- | React.ReactNode
- | ((params: BlobProviderParams) => React.ReactNode);
- }
-
+ hyphenationCallback?: number;
+ }
+
+ /**
+ * A React component for displaying text. Text supports nesting of other
+ * Text or Link components to create inline styling.
+ */
+ class Text extends React.Component<TextProps> { }
+
+ interface LinkProps extends NodeProps {
/**
- * Anchor tag to enable generate and download PDF documents on the fly.
- * @see https://react-pdf.org/advanced#on-the-fly-rendering
- * @platform web
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
*/
- class PDFDownloadLink extends React.Component<PDFDownloadLinkProps> {}
-
- interface EmojiSource {
- url: string;
- format: string;
- }
- interface RegisteredFont {
- src: string;
- loaded: boolean;
- loading: boolean;
- data: any;
- [key: string]: any;
- }
- type HyphenationCallback = (
- words: string[],
- glyphString: {[key: string]: any},
- ) => string[];
-
- const Font: {
- register: (
- src: string,
- options: {family: string; [key: string]: any},
- ) => void;
- getEmojiSource: () => EmojiSource;
- getRegisteredFonts: () => string[];
- registerEmojiSource: (emojiSource: EmojiSource) => void;
- registerHyphenationCallback: (
- hyphenationCallback: HyphenationCallback,
- ) => void;
- getHyphenationCallback: () => HyphenationCallback;
- getFont: (fontFamily: string) => RegisteredFont | undefined;
- load: (
- fontFamily: string,
- document: React.ReactElement<DocumentProps>,
- ) => Promise<void>;
- clear: () => void;
- reset: () => void;
- };
-
- const StyleSheet: {
- hairlineWidth: number;
- create: <TStyles>(styles: TStyles) => TStyles;
- resolve: (
- style: Style,
- container: {
- width: number;
- height: number;
- orientation: Orientation;
- },
- ) => Style;
- flatten: (...styles: Style[]) => Style;
- absoluteFillObject: {
- position: 'absolute';
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- };
- };
-
- const version: any;
-
- const PDFRenderer: any;
-
- const createInstance: (
- element: {
- type: string;
- props: {[key: string]: any};
- },
- root?: any,
- ) => any;
-
- const pdf: (
+ wrap?: boolean;
+ debug?: boolean;
+ src: string;
+ children?: React.ReactNode;
+ }
+
+ /**
+ * A React component for displaying an hyperlink. Link’s can be nested
+ * inside a Text component, or being inside any other valid primitive.
+ */
+ class Link extends React.Component<LinkProps> { }
+
+ interface NoteProps extends NodeProps {
+ children: string;
+ }
+
+ class Note extends React.Component<NoteProps> { }
+
+ interface BlobProviderParams {
+ blob: Blob | null;
+ url: string | null;
+ loading: boolean;
+ error: Error | null;
+ }
+ interface BlobProviderProps {
+ document: React.ReactElement<DocumentProps>;
+ children: (params: BlobProviderParams) => React.ReactNode;
+ }
+
+ /**
+ * Easy and declarative way of getting document's blob data without
+ * showing it on screen.
+ * @see https://react-pdf.org/advanced#on-the-fly-rendering
+ * @platform web
+ */
+ class BlobProvider extends React.Component<BlobProviderProps> { }
+
+ interface PDFViewerProps {
+ width?: number;
+ height?: number;
+ style?: Style | Style[];
+ className?: string;
+ children?: React.ReactElement<DocumentProps>;
+ }
+
+ /**
+ * Iframe PDF viewer for client-side generated documents.
+ * @platform web
+ */
+ class PDFViewer extends React.Component<PDFViewerProps> { }
+
+ interface PDFDownloadLinkProps {
+ document: React.ReactElement<DocumentProps>;
+ fileName?: string;
+ style?: Style | Style[];
+ className?: string;
+ children?:
+ | React.ReactNode
+ | ((params: BlobProviderParams) => React.ReactNode);
+ }
+
+ /**
+ * Anchor tag to enable generate and download PDF documents on the fly.
+ * @see https://react-pdf.org/advanced#on-the-fly-rendering
+ * @platform web
+ */
+ class PDFDownloadLink extends React.Component<PDFDownloadLinkProps> { }
+
+ interface EmojiSource {
+ url: string;
+ format: string;
+ }
+ interface RegisteredFont {
+ src: string;
+ loaded: boolean;
+ loading: boolean;
+ data: any;
+ [key: string]: any;
+ }
+ type HyphenationCallback = (
+ words: string[],
+ glyphString: { [key: string]: any },
+ ) => string[];
+
+ const Font: {
+ register: (
+ src: string,
+ options: { family: string;[key: string]: any },
+ ) => void;
+ getEmojiSource: () => EmojiSource;
+ getRegisteredFonts: () => string[];
+ registerEmojiSource: (emojiSource: EmojiSource) => void;
+ registerHyphenationCallback: (
+ hyphenationCallback: HyphenationCallback,
+ ) => void;
+ getHyphenationCallback: () => HyphenationCallback;
+ getFont: (fontFamily: string) => RegisteredFont | undefined;
+ load: (
+ fontFamily: string,
document: React.ReactElement<DocumentProps>,
- ) => {
- isDirty: () => boolean;
- updateContainer: (document: React.ReactElement<any>) => void;
- toBuffer: () => NodeJS.ReadableStream;
- toBlob: () => Blob;
- toString: () => string;
+ ) => Promise<void>;
+ clear: () => void;
+ reset: () => void;
+ };
+
+ const StyleSheet: {
+ hairlineWidth: number;
+ create: <TStyles>(styles: TStyles) => TStyles;
+ resolve: (
+ style: Style,
+ container: {
+ width: number;
+ height: number;
+ orientation: Orientation;
+ },
+ ) => Style;
+ flatten: (...styles: Style[]) => Style;
+ absoluteFillObject: {
+ position: 'absolute';
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
};
-
- const renderToStream: (
- document: React.ReactElement<DocumentProps>,
- ) => NodeJS.ReadableStream;
-
- const renderToFile: (
- document: React.ReactElement<DocumentProps>,
- filePath: string,
- callback?: (output: NodeJS.ReadableStream, filePath: string) => any,
- ) => Promise<NodeJS.ReadableStream>;
-
- const render: typeof renderToFile;
- }
-
- const Document: typeof ReactPDF.Document;
- const Page: typeof ReactPDF.Page;
- const View: typeof ReactPDF.View;
- const Image: typeof ReactPDF.Image;
- const Text: typeof ReactPDF.Text;
- const Link: typeof ReactPDF.Link;
- const Note: typeof ReactPDF.Note;
- const Font: typeof ReactPDF.Font;
- const StyleSheet: typeof ReactPDF.StyleSheet;
- const createInstance: typeof ReactPDF.createInstance;
- const PDFRenderer: typeof ReactPDF.PDFRenderer;
- const version: typeof ReactPDF.version;
- const pdf: typeof ReactPDF.pdf;
-
- export default ReactPDF;
- export {
- Document,
- Page,
- View,
- Image,
- Text,
- Link,
- Note,
- Font,
- StyleSheet,
- createInstance,
- PDFRenderer,
- version,
- pdf,
};
- } \ No newline at end of file
+
+ const version: any;
+
+ const PDFRenderer: any;
+
+ const createInstance: (
+ element: {
+ type: string;
+ props: { [key: string]: any };
+ },
+ root?: any,
+ ) => any;
+
+ const pdf: (
+ document: React.ReactElement<DocumentProps>,
+ ) => {
+ isDirty: () => boolean;
+ updateContainer: (document: React.ReactElement<any>) => void;
+ toBuffer: () => NodeJS.ReadableStream;
+ toBlob: () => Blob;
+ toString: () => string;
+ };
+
+ const renderToStream: (
+ document: React.ReactElement<DocumentProps>,
+ ) => NodeJS.ReadableStream;
+
+ const renderToFile: (
+ document: React.ReactElement<DocumentProps>,
+ filePath: string,
+ callback?: (output: NodeJS.ReadableStream, filePath: string) => any,
+ ) => Promise<NodeJS.ReadableStream>;
+
+ const render: typeof renderToFile;
+ }
+
+ const Document: typeof ReactPDF.Document;
+ const Page: typeof ReactPDF.Page;
+ const View: typeof ReactPDF.View;
+ const Image: typeof ReactPDF.Image;
+ const Text: typeof ReactPDF.Text;
+ const Link: typeof ReactPDF.Link;
+ const Note: typeof ReactPDF.Note;
+ const Font: typeof ReactPDF.Font;
+ const StyleSheet: typeof ReactPDF.StyleSheet;
+ const createInstance: typeof ReactPDF.createInstance;
+ const PDFRenderer: typeof ReactPDF.PDFRenderer;
+ const version: typeof ReactPDF.version;
+ const pdf: typeof ReactPDF.pdf;
+
+ export default ReactPDF;
+ export {
+ Document,
+ Page,
+ View,
+ Image,
+ Text,
+ Link,
+ Note,
+ Font,
+ StyleSheet,
+ createInstance,
+ PDFRenderer,
+ version,
+ pdf,
+ };
+} \ No newline at end of file