diff options
| author | Sam Wilkins <samuel_wilkins@brown.edu> | 2019-06-11 13:29:48 -0400 |
|---|---|---|
| committer | Sam Wilkins <samuel_wilkins@brown.edu> | 2019-06-11 13:29:48 -0400 |
| commit | c789df5ae7a9e364f0d95b54f4a2f330b536a393 (patch) | |
| tree | f7e32d53c8d6b87b0ddb860104b288107666e89c | |
| parent | 79b37db46fda36cd779645256b03d9d074141eb6 (diff) | |
some inline documentation and new template skeletons
| -rw-r--r-- | src/client/views/Templates.tsx | 12 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionBaseView.tsx | 13 | ||||
| -rw-r--r-- | src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx | 72 | ||||
| -rw-r--r-- | src/client/views/document_templates/image_card/ImageCard.tsx | 18 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
| -rw-r--r-- | src/client/views/nodes/FieldView.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 1 | ||||
| -rw-r--r-- | src/documentation/collection_hierarchies.txt | 50 |
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 |
