diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.DS_Store | bin | 0 -> 6148 bytes | |||
-rw-r--r-- | src/client/documents/Documents.ts | 60 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 18 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.scss | 14 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 82 | ||||
-rw-r--r-- | src/client/views/nodes/WebView.tsx | 2 | ||||
-rw-r--r-- | src/fields/WebField.ts | 30 | ||||
-rw-r--r-- | src/server/Message.ts | 2 | ||||
-rw-r--r-- | src/server/ServerUtil.ts | 3 |
13 files changed, 187 insertions, 41 deletions
diff --git a/src/.DS_Store b/src/.DS_Store Binary files differnew file mode 100644 index 000000000..4d6acb95a --- /dev/null +++ b/src/.DS_Store diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9770e5cdc..e5154737e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -7,10 +7,10 @@ import { ListField } from "../../fields/ListField"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { ImageField } from "../../fields/ImageField"; import { ImageBox } from "../views/nodes/ImageBox"; +import { WebField } from "../../fields/WebField"; +import { WebBox } from "../views/nodes/WebBox"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; -import { FieldView } from "../views/nodes/FieldView"; import { HtmlField } from "../../fields/HtmlField"; -import { WebView } from "../views/nodes/WebView"; export interface DocumentOptions { x?: number; @@ -77,29 +77,7 @@ export namespace Documents { export function TextDocument(options: DocumentOptions = {}): Document { let doc = GetTextPrototype().MakeDelegate(); setupOptions(doc, options); - // doc.SetField(KeyStore.Data, new RichTextField()); - return doc; - } - - let htmlProto: Document; - const htmlProtoId = "htmlProto"; - function GetHtmlPrototype(): Document { - if (!htmlProto) { - htmlProto = new Document(htmlProtoId); - htmlProto.Set(KeyStore.X, new NumberField(0)); - htmlProto.Set(KeyStore.Y, new NumberField(0)); - htmlProto.Set(KeyStore.Width, new NumberField(300)); - htmlProto.Set(KeyStore.Height, new NumberField(150)); - htmlProto.Set(KeyStore.Layout, new TextField(WebView.LayoutString())); - htmlProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); - } - return htmlProto; - } - - export function HtmlDocument(html: string, options: DocumentOptions = {}): Document { - let doc = GetHtmlPrototype().MakeDelegate(); - setupOptions(doc, options); - doc.Set(KeyStore.Data, new HtmlField(html)); + // doc.Set(KeyStore.Data, new RichTextField()); return doc; } @@ -116,7 +94,7 @@ export namespace Documents { imageProto.Set(KeyStore.Layout, new TextField(CollectionView.LayoutString("AnnotationsKey"))); imageProto.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) imageProto.Set(KeyStore.BackgroundLayout, new TextField(ImageBox.LayoutString())); - // imageProto.SetField(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />')); + // imageProto.Set(KeyStore.Layout, new TextField('<div style={"background-image: " + {Data}} />')); imageProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations])); return imageProto; } @@ -153,6 +131,36 @@ export namespace Documents { return doc; } + let webProto: Document; + const webProtoId = "webProto"; + function GetWebPrototype(): Document { + if (!webProto) { + webProto = new Document(webProtoId); + webProto.Set(KeyStore.Title, new TextField("WEB PROTO")); + webProto.Set(KeyStore.X, new NumberField(0)); + webProto.Set(KeyStore.Y, new NumberField(0)); + webProto.Set(KeyStore.Width, new NumberField(300)); + webProto.Set(KeyStore.Height, new NumberField(300)); + //webProto.Set(KeyStore.Layout, new TextField(CollectionView.LayoutString("AnnotationsKey"))); + webProto.Set(KeyStore.Layout, new TextField(WebBox.LayoutString())); + webProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations])); + } + return webProto; + } + + export function WebDocument(url: string, options: DocumentOptions = {}): Document { + let doc = GetWebPrototype().MakeDelegate(); + setupOptions(doc, options); + doc.Set(KeyStore.Data, new WebField(new URL(url))); + return doc; + } + export function HtmlDocument(html: string, options: DocumentOptions = {}): Document { + let doc = GetWebPrototype().MakeDelegate(); + setupOptions(doc, options); + doc.Set(KeyStore.Data, new HtmlField(html)); + return doc; + } + let collectionProto: Document; const collectionProtoId = "collectionProto"; function GetCollectionPrototype(): Document { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 7ef4b6132..af4db521c 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -84,6 +84,9 @@ Documents.initProtos(() => { let addImageNode = action(() => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { width: 200, height: 200, title: "an image of a cat" })); + let addWebNode = action(() => Documents.WebDocument("https://cs.brown.edu/courses/cs166/", { + width: 200, height: 200, title: "an image of a cat" + })); let addClick = (creator: any) => action(() => { var img = creator(); @@ -93,6 +96,7 @@ Documents.initProtos(() => { }); let imgRef = React.createRef<HTMLDivElement>(); + let webRef = React.createRef<HTMLDivElement>(); let textRef = React.createRef<HTMLDivElement>(); let schemaRef = React.createRef<HTMLDivElement>(); let colRef = React.createRef<HTMLDivElement>(); @@ -110,15 +114,17 @@ Documents.initProtos(() => { <ContextMenu /> <div style={{ position: 'absolute', bottom: '0px', left: '0px', width: '150px' }} ref={imgRef} > <button onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>Add Image</button></div> - <div style={{ position: 'absolute', bottom: '25px', left: '0px', width: '150px' }} ref={textRef}> + <div style={{ position: 'absolute', bottom: '25px', left: '0px', width: '150px' }} ref={webRef} > + <button onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>Add Web</button></div> + <div style={{ position: 'absolute', bottom: '50px', left: '0px', width: '150px' }} ref={textRef}> <button onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>Add Text</button></div> - <div style={{ position: 'absolute', bottom: '50px', left: '0px', width: '150px' }} ref={colRef}> + <div style={{ position: 'absolute', bottom: '75px', left: '0px', width: '150px' }} ref={colRef}> <button onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>Add Collection</button></div> - <div style={{ position: 'absolute', bottom: '75px', left: '0px', width: '150px' }} ref={schemaRef}> + <div style={{ position: 'absolute', bottom: '100px', left: '0px', width: '150px' }} ref={schemaRef}> <button onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>Add Schema</button></div> - <button style={{ position: 'absolute', bottom: '100px', left: '0px', width: '150px' }} onClick={clearDatabase}>Clear Database</button> - <button style={{ position: 'absolute', bottom: '25', right: '0px', width: '150px' }} onClick={() => UndoManager.Undo()}>Undo</button> - <button style={{ position: 'absolute', bottom: '0', right: '0px', width: '150px' }} onClick={() => UndoManager.Redo()}>Redo</button> + <button style={{ position: 'absolute', bottom: '125px', left: '0px', width: '150px' }} onClick={clearDatabase}>Clear Database</button> + <button style={{ position: 'absolute', bottom: '25px', right: '0px', width: '150px' }} onClick={() => UndoManager.Undo()}>Undo</button> + <button style={{ position: 'absolute', bottom: '0px', right: '0px', width: '150px' }} onClick={() => UndoManager.Redo()}>Redo</button> </div>), document.getElementById('root')); }) diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 12909c151..c454d62b3 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -10,13 +10,13 @@ import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionSchemaView } from "../collections/CollectionSchemaView"; -import { CollectionTreeView } from "../collections/CollectionTreeView"; import { CollectionView } from "../collections/CollectionView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { DocumentView } from "../nodes/DocumentView"; import { WebView } from "../nodes/WebView"; import { FormattedTextBox } from "../nodes/FormattedTextBox"; import { ImageBox } from "../nodes/ImageBox"; +import { WebBox } from "../nodes/WebBox"; import "./CollectionFreeFormView.scss"; import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; @@ -200,7 +200,7 @@ export class CollectionFreeFormView extends CollectionViewBase { get backgroundView() { return !this.backgroundLayout ? (null) : (<JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView, WebBox }} bindings={this.props.bindings} jsx={this.backgroundLayout} showWarnings={true} @@ -211,7 +211,7 @@ export class CollectionFreeFormView extends CollectionViewBase { get overlayView() { return !this.overlayLayout ? (null) : (<JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView, WebBox }} bindings={this.props.bindings} jsx={this.overlayLayout} showWarnings={true} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index feecde921..3517dd0c6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -16,6 +16,7 @@ import { WebView } from "./WebView"; import { ContextMenu } from "../ContextMenu"; import { FormattedTextBox } from "../nodes/FormattedTextBox"; import { ImageBox } from "../nodes/ImageBox"; +import { WebBox } from "../nodes/WebBox"; import "./DocumentView.scss"; import React = require("react"); const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? @@ -195,7 +196,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { @computed get mainContent() { var val = this.props.Document.Id; return <JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView }} + components={{ FormattedTextBox, ImageBox, WebBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView }} bindings={this._documentBindings} jsx={this.layout} showWarnings={true} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index b71309bf5..4e8abd682 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -7,9 +7,11 @@ import { TextField } from "../../../fields/TextField"; import { NumberField } from "../../../fields/NumberField"; import { RichTextField } from "../../../fields/RichTextField"; import { ImageField } from "../../../fields/ImageField"; +import { WebField } from "../../../fields/WebField"; import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; +import { WebBox } from "./WebBox"; import { HtmlField } from "../../../fields/HtmlField"; import { WebView } from "./WebView"; @@ -50,10 +52,13 @@ export class FieldView extends React.Component<FieldViewProps> { else if (field instanceof ImageField) { return <ImageBox {...this.props} /> } + else if (field instanceof WebField) { + return <WebBox {...this.props} /> + } else if (field instanceof NumberField) { return <p>{field.Data}</p> } - else if (field instanceof HtmlField) { + else if (field instanceof WebField) { return <WebView {...this.props} /> } else if (field != FieldWaiting) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4fe73fb8d..e206bf8d5 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -9,7 +9,6 @@ import { FieldWaiting } from '../../../fields/Field'; import { observer } from "mobx-react" import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; -import { element } from 'prop-types'; @observer export class ImageBox extends React.Component<FieldViewProps> { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss new file mode 100644 index 000000000..e72b3c4da --- /dev/null +++ b/src/client/views/nodes/WebBox.scss @@ -0,0 +1,14 @@ + +.webBox-cont { + padding: 0vw; + position: absolute; + width: 100%; + height: 100%; +} + +.webBox-button { + padding : 0vw; + border: none; + width : 100%; + height: 100%; +}
\ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx new file mode 100644 index 000000000..0a198f059 --- /dev/null +++ b/src/client/views/nodes/WebBox.tsx @@ -0,0 +1,82 @@ +import "./WebBox.scss"; +import React = require("react") +import { WebField } from '../../../fields/WebField'; +import { FieldViewProps, FieldView } from './FieldView'; +import { FieldWaiting } from '../../../fields/Field'; +import { observer } from "mobx-react" +import { observable, action, spy, computed } from 'mobx'; +import { KeyStore } from '../../../fields/KeyStore'; +import { HtmlField } from "../../../fields/HtmlField"; + +@observer +export class WebBox extends React.Component<FieldViewProps> { + + public static LayoutString() { return FieldView.LayoutString(WebBox); } + private _ref: React.RefObject<HTMLDivElement>; + private _downX: number = 0; + private _downY: number = 0; + private _lastTap: number = 0; + @observable private _isOpen: boolean = false; + + constructor(props: FieldViewProps) { + super(props); + + this._ref = React.createRef(); + this.state = { + isOpen: false, + }; + } + + componentDidMount() { + } + + componentWillUnmount() { + } + + onPointerDown = (e: React.PointerEvent): void => { + if (Date.now() - this._lastTap < 300) { + if (e.buttons === 1 && this.props.isSelected()) { + e.stopPropagation(); + this._downX = e.clientX; + this._downY = e.clientY; + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); + } + } else { + this._lastTap = Date.now(); + } + } + + @action + onPointerUp = (e: PointerEvent): void => { + document.removeEventListener("pointerup", this.onPointerUp); + if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { + this._isOpen = true; + } + e.stopPropagation(); + } + + @computed + get html(): string { + return this.props.doc.GetData(KeyStore.Data, HtmlField, "" as string); + } + + + render() { + let field = this.props.doc.Get(this.props.fieldKey); + let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu"; + + let content = this.html ? + <span dangerouslySetInnerHTML={{ __html: this.html }}></span> : + <div style={{ width: "100%", height: "100%", position: "absolute" }}> + <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }}></iframe> + {this.props.isSelected() ? (null) : <div style={{ width: "100%", height: "100%", position: "absolute" }} />} + </div>; + + return ( + <div className="webBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} > + {content} + </div>) + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/WebView.tsx b/src/client/views/nodes/WebView.tsx index 717aa8bf5..5cc85eb28 100644 --- a/src/client/views/nodes/WebView.tsx +++ b/src/client/views/nodes/WebView.tsx @@ -3,9 +3,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import React = require('react') -import { TextField } from "../../../fields/TextField"; import { HtmlField } from "../../../fields/HtmlField"; -import { RichTextField } from "../../../fields/RichTextField"; @observer export class WebView extends React.Component<FieldViewProps> { diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts new file mode 100644 index 000000000..8f945d686 --- /dev/null +++ b/src/fields/WebField.ts @@ -0,0 +1,30 @@ +import { BasicField } from "./BasicField"; +import { Field, FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class WebField extends BasicField<URL> { + constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { + super(data == undefined ? new URL("https://crossorigin.me/" + "https://cs.brown.edu/") : data, save, id); + } + + toString(): string { + return this.Data.href; + } + + ToScriptString(): string { + return `new WebField("${this.Data}")`; + } + + Copy(): Field { + return new WebField(this.Data); + } + + ToJson(): { type: Types, data: URL, _id: string } { + return { + type: Types.Web, + data: this.Data, + _id: this.Id + } + } + +}
\ No newline at end of file diff --git a/src/server/Message.ts b/src/server/Message.ts index 80fc9a80d..148e6e723 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -45,7 +45,7 @@ export class GetFieldArgs { } export enum Types { - Number, List, Key, Image, Document, Text, RichText, DocumentReference, Html + Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, Html } export class DocumentTransfer implements Transferable { diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 08e72fdae..a53fb5d2b 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -10,6 +10,7 @@ import { Server } from './../client/Server'; import { Types } from './Message'; import { Utils } from '../Utils'; import { HtmlField } from '../fields/HtmlField'; +import { WebField } from '../fields/WebField'; export class ServerUtils { public static FromJson(json: any): Field { @@ -30,6 +31,8 @@ export class ServerUtils { return new TextField(data, id, false) case Types.Html: return new HtmlField(data, id, false) + case Types.Web: + return new WebField(new URL(data), id, false) case Types.RichText: return new RichTextField(data, id, false) case Types.Key: |