aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <samuel_wilkins@brown.edu>2019-06-11 13:29:48 -0400
committerSam Wilkins <samuel_wilkins@brown.edu>2019-06-11 13:29:48 -0400
commitc789df5ae7a9e364f0d95b54f4a2f330b536a393 (patch)
treef7e32d53c8d6b87b0ddb860104b288107666e89c /src
parent79b37db46fda36cd779645256b03d9d074141eb6 (diff)
some inline documentation and new template skeletons
Diffstat (limited to 'src')
-rw-r--r--src/client/views/Templates.tsx12
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx13
-rw-r--r--src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx72
-rw-r--r--src/client/views/document_templates/image_card/ImageCard.tsx18
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx1
-rw-r--r--src/documentation/collection_hierarchies.txt50
8 files changed, 161 insertions, 9 deletions
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index 0cd367bcb..df53284ed 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -39,12 +39,18 @@ export class Template {
export namespace Templates {
// export const BasicLayout = new Template("Basic layout", "{layout}");
+ // export const Caption = new Template("Caption", TemplatePosition.OutterBottom,
+ // `<div>
+ // <div style="height:100%; width:100%;position:absolute;">{layout}</div>
+ // <div style="bottom: 0; font-size:14px; width:100%; position:absolute">
+ // <FormattedTextBox {...props} fieldKey={"caption"} hideOnLeave={"true"} />
+ // </div>
+ // </div>` );
+
export const Caption = new Template("Caption", TemplatePosition.OutterBottom,
`<div>
<div style="height:100%; width:100%;position:absolute;">{layout}</div>
- <div style="bottom: 0; font-size:14px; width:100%; position:absolute">
- <FormattedTextBox {...props} fieldKey={"caption"} hideOnLeave={"true"} />
- </div>
+ <DetailedCaptionToggle {...props}/>
</div>` );
export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop,
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 734669893..a3019f23e 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -106,14 +106,19 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
}
if (!this.createsCycle(doc, props.Document)) {
//TODO This won't create the field if it doesn't already exist
- const value = Cast(props.Document[props.fieldKey], listSpec(Doc));
+ const childDocs = DocListCast(props.Document[props.fieldKey]);
let alreadyAdded = true;
- if (value !== undefined) {
- if (allowDuplicates || !value.some(v => v instanceof Doc && v[Id] === doc[Id])) {
+ if (childDocs !== undefined) {
+ // if this is not the first document added to the collection
+ if (allowDuplicates || !childDocs.some(v => v instanceof Doc && v[Id] === doc[Id])) {
alreadyAdded = false;
- value.push(doc);
+ childDocs.push(doc);
}
+ // if we're here, we've tried to add a duplicate
} else {
+ // if we are the first, set up a new list for this and all
+ // future child documents stored in the associated collection document at the fieldKey (likely .data)
+ // passed in via props
alreadyAdded = false;
Doc.SetOnPrototype(this.props.Document, this.props.fieldKey, new List([doc]));
}
diff --git a/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx b/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx
new file mode 100644
index 000000000..2172f2852
--- /dev/null
+++ b/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx
@@ -0,0 +1,72 @@
+import * as React from 'react';
+import { FontWeightProperty, FontStyleProperty, FontSizeProperty, ColorProperty } from 'csstype';
+import { observer } from 'mobx-react';
+import { observable, action, runInAction } from 'mobx';
+import { FormattedTextBox, FormattedTextBoxProps } from '../../nodes/FormattedTextBox';
+import { FieldViewProps } from '../../nodes/FieldView';
+
+interface DetailedCaptionDataProps {
+ captionFieldKey?: string,
+ detailsFieldKey?: string,
+}
+
+interface DetailedCaptionStylingProps {
+ sharedFontColor?: ColorProperty;
+ captionFontStyle?: FontStyleProperty
+ detailsFontStyle?: FontStyleProperty
+ toggleSize?: number
+}
+
+@observer
+export default class DetailedCaptionToggle extends React.Component<DetailedCaptionDataProps & DetailedCaptionStylingProps & FieldViewProps> {
+ @observable loaded: boolean = false;
+ @observable detailsExpanded: boolean = false;
+
+ @action toggleDetails = (e: React.MouseEvent<HTMLDivElement>) => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.detailsExpanded = !this.detailsExpanded;
+ }
+
+ componentDidMount() {
+ runInAction(() => this.loaded = true);
+ }
+
+ render() {
+ let size = this.props.toggleSize || 20;
+ return (
+ <div style={{
+ transition: "0.5s opacity ease",
+ opacity: this.loaded ? 1 : 0,
+ bottom: 0,
+ fontSize: 14,
+ width: "100%",
+ position: "absolute"
+ }}>
+ {/* caption */}
+ <div style={{ opacity: this.detailsExpanded ? 0 : 1, transition: "opacity 0.3s ease" }}>
+ <FormattedTextBox {...this.props} fieldKey={this.props.captionFieldKey || "caption"} />
+ </div>
+ {/* details */}
+ <div style={{ opacity: this.detailsExpanded ? 1 : 0, transition: "opacity 0.3s ease" }}>
+ <FormattedTextBox {...this.props} fieldKey={this.props.detailsFieldKey || "captiondetails"} />
+ </div>
+ {/* toggle */}
+ <div
+ style={{
+ width: size,
+ height: size,
+ borderRadius: "50%",
+ backgroundColor: "red",
+ zIndex: 3,
+ cursor: "pointer"
+ }}
+ onClick={this.toggleDetails}
+ >
+ <span style={{ color: "white" }}></span>
+ </div>
+ </div>
+ );
+ }
+
+}
diff --git a/src/client/views/document_templates/image_card/ImageCard.tsx b/src/client/views/document_templates/image_card/ImageCard.tsx
new file mode 100644
index 000000000..9931515f3
--- /dev/null
+++ b/src/client/views/document_templates/image_card/ImageCard.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { DocComponent } from '../../DocComponent';
+import { FieldViewProps } from '../../nodes/FieldView';
+import { createSchema, makeInterface } from '../../../../new_fields/Schema';
+import { createInterface } from 'readline';
+import { ImageBox } from '../../nodes/ImageBox';
+
+export default class ImageCard extends React.Component<FieldViewProps> {
+
+ render() {
+ return (
+ <div style={{ padding: 30, borderRadius: 15 }}>
+ <ImageBox {...this.props} />
+ </div>
+ );
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 02396c3af..b6c150854 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -23,6 +23,7 @@ import { FieldViewProps } from "./FieldView";
import { Without, OmitKeys } from "../../../Utils";
import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
import { List } from "../../../new_fields/List";
+import DetailedCaptionToggle from "../document_templates/caption_toggle/DetailedCaptionToggle";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -103,7 +104,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
render() {
if (!this.layout && (this.props.layoutKey !== "overlayLayout" || !this.templates.length)) return (null);
return <ObserverJsxParser
- components={{ FormattedTextBox, ImageBox, IconBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
+ components={{ DetailedCaptionToggle, FormattedTextBox, ImageBox, IconBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
bindings={this.CreateBindings()}
jsx={this.finalLayout}
showWarnings={true}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 7b642b299..74453488a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -19,6 +19,7 @@ import { IconField } from "../../../new_fields/IconField";
import { RichTextField } from "../../../new_fields/RichTextField";
import { DateField } from "../../../new_fields/DateField";
import { NumCast } from "../../../new_fields/Types";
+import ImageCard from "../document_templates/image_card/ImageCard";
//
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5c635cc0c..d00a4b928 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -363,7 +363,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
onPointerUp={this.onPointerUp}
onPointerDown={this.onPointerDown}
onMouseDown={this.onMouseDown}
- onContextMenu={this.specificContextMenu}
// tfs: do we need this event handler
onWheel={this.onPointerWheel}
onPointerEnter={this.onPointerEnter}
diff --git a/src/documentation/collection_hierarchies.txt b/src/documentation/collection_hierarchies.txt
new file mode 100644
index 000000000..69e60c136
--- /dev/null
+++ b/src/documentation/collection_hierarchies.txt
@@ -0,0 +1,50 @@
+** When we drag and drop out a node from MainView.tsx's button menu, what actually happens? **
+
+As you have probably already seen, MainView.tsx renders a line of circular buttons, each of wich can be dragged and dropped to
+create new nodes in the collection acting as the drop target.
+
+These buttons are logically stored as an array of tuples, currently called 'btns'. Each tuple contains the React reference to
+the actual HTMLDivElement around which the button is made, later used to set up dragging behavior, but most importantly contains the sort of factory function that creates a
+new document (of the relevant type). This document underlies the view that will be added to the collection (something like addImageNode()).
+
+The SetupDrag() function in DragManager.ts creates new DragManager.DocumentDragData and, in it, embeds the newly created document (which may have, for example, an ImageField
+at its data key, which will soon be used to render an ImageBox...). The DragManager then begins the dragging operation, which handles the display of the element as it's
+dragged out onto the canvas and registers the desired drop operation, namely copying the document or creating an alias.
+
+When the document is dropped onto the target collection, the CollectionSubView superclass's drop() method is invoked. Typically, if dropping a single document from one
+of the MainView.tsx node addition buttons, this iterates through the DragData's droppedDocuments and adds them to the collection via an addDocument() function this CollectionSubView
+received with its props. In actuality, this addDocument() function is defined in and passed down from CollectionBaseView, and conditionally adds the document to the
+underlying collection document's data (list of child documents). To actually be added, the document to add cannot create a cycle (for example, you cannot add a collection to one of
+its own children that is itself a collection).
+
+Here is the sequence of function calls:
+
+MainView."round-button add-button" onPointerDown() => DragManager.SetupDrag()
+DragManager.SetupDrag.onRowMove() => DragManager.StartDocumentDrag()
+DragManager.StartDrag()
+
+... (USER IS DRAGGING DOCUMENT AROUND VIA BUTTON)
+... (USER DROPS THE DOCUMENT IN THE TARGET COLLECTION)
+
+CollectionSubView.drop()
+
+<DocumentView>
+ <DocumentContentsView> {
+ Nodes themselves, both base types and collections, are actually always rendered by using a JSXParser to parse a stringified JSX element layout (see
+ FieldView.LayoutString()). Typically, way back in the initial drag phase, where the buttons maintained document creation
+ functions like Documents.ImageDocument(), the layout string will have always been set, because of the way that new node
+ documents are created. The ImageDocument() function creates a delegate from the imageProto (image document prototype) which is itself created at the time
+ Dash is loaded. Since the delegate inherits the prototype's layout string, the layoutKey field will be set and effectively always, the JSXParser will
+ parse the existing layout string to return the appropriate JSX element to be rendered as a child of the collection sub view. On the off chance that this
+ layout field has not been set, the layout() getter just returns a generic FieldView element to the JSXParser, and internally, this component decides based
+ on the nature of the document it receives, which node view to assign. This is basically a fallback.
+ }
+ <CollectionView>
+ <CollectionBaseView>
+ // all of the below extend <CollectionSubView>
+ <CollectionFreeFormView>
+ <CollectionSchemaView>
+ <CollectionDockingView>
+ <CollectionTreeView>
+ <CollectionStackingView>
+ <FieldView> \ No newline at end of file