aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx173
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx23
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx6
4 files changed, 196 insertions, 10 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 002bfe6a2..1f93ac391 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -21,7 +21,7 @@ import { YoutubeBox } from "../apis/youtube/YoutubeBox";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { LinkManager } from "../util/LinkManager";
import { DocumentManager } from "../util/DocumentManager";
-import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox";
+import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
import { Scripting } from "../util/Scripting";
import { LabelBox } from "../views/nodes/LabelBox";
import { SliderBox } from "../views/nodes/SliderBox";
@@ -385,7 +385,7 @@ export namespace Docs {
// synthesize the default options, the type and title from computed values and
// whatever options pertain to this specific prototype
const options = { title, type, baseProto: true, ...defaultOptions, ...(template.options || {}) };
- options.layout = layout.view.LayoutString(layout.dataField);
+ options.layout = layout.view?.LayoutString(layout.dataField);
const doc = Doc.assign(new Doc(prototypeId, true), { layoutKey: "layout", ...options });
doc.layout_keyValue = KeyValueBox.LayoutString("");
return doc;
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index baf9d4156..e34a9e450 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -3,7 +3,7 @@ import { action, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, returnOne, Utils } from "../../../Utils";
import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { KeyCodes } from "../../util/KeyCodes";
@@ -24,6 +24,9 @@ import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
import { undoBatch } from "../../util/UndoManager";
import { SnappingManager } from "../../util/SnappingManager";
import { ComputedField } from "../../../fields/ScriptField";
+import { ImageField } from "../../../fields/URLField";
+import { KeysDropdown } from "./CollectionSchemaHeaders";
+const path = require('path');
library.add(faExpand);
@@ -205,6 +208,18 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const doc = FieldValue(Cast(field, Doc));
contents = typeof field === "object" ? doc ? StrCast(doc.title) === "" ? "--" : StrCast(doc.title) : `--${typeof field}--` : `--${typeof field}--`;
}
+ if (type === "image") {
+ // fix this
+
+ const image = FieldValue(Cast(field, ImageField));
+ const doc = FieldValue(Cast(field, Doc));
+ contents = typeof field === "object" ? doc ? StrCast(doc.title) === "" ? "--" : StrCast(doc.title) : `--${typeof field}--` : `--${typeof field}--`;
+ }
+ if (type === "list") {
+ // fix this
+ contents = typeof field === "object" ? doc ? StrCast(field) === "" ? "--" : StrCast(field) : `--${typeof field}--` : `--${typeof field}--`;
+ }
+
let className = "collectionSchemaView-cellWrapper";
if (this._isEditing) className += " editing";
@@ -305,6 +320,162 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell {
}
@observer
+export class CollectionSchemaImageCell extends CollectionSchemaCell {
+ // render() {
+ // return this.renderCellWithType("image");
+ // }
+
+ choosePath(url: URL, dataDoc: any) {
+ const lower = url.href.toLowerCase();
+ if (url.protocol === "data") {
+ return url.href;
+ } else if (url.href.indexOf(window.location.origin) === -1) {
+ return Utils.CorsProxy(url.href);
+ } else if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) {
+ return url.href;//Why is this here
+ }
+ const ext = path.extname(url.href);
+ const _curSuffix = "_o";
+ return url.href.replace(ext, _curSuffix + ext);
+ }
+
+ render() {
+ const props: FieldViewProps = {
+ Document: this.props.rowProps.original,
+ DataDoc: this.props.rowProps.original,
+ LibraryPath: [],
+ dropAction: "alias",
+ bringToFront: emptyFunction,
+ rootSelected: returnFalse,
+ fieldKey: this.props.rowProps.column.id as string,
+ ContainingCollectionView: this.props.CollectionView,
+ ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
+ isSelected: returnFalse,
+ select: emptyFunction,
+ renderDepth: this.props.renderDepth + 1,
+ ScreenToLocalTransform: Transform.Identity,
+ focus: emptyFunction,
+ active: returnFalse,
+ whenActiveChanged: emptyFunction,
+ PanelHeight: returnZero,
+ PanelWidth: returnZero,
+ NativeHeight: returnZero,
+ NativeWidth: returnZero,
+ addDocTab: this.props.addDocTab,
+ pinToPres: this.props.pinToPres,
+ ContentScaling: returnOne
+ };
+
+ let image = true;
+ let url = [];
+ if (props.DataDoc) {
+ const field = Cast(props.DataDoc[props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+ const alts = DocListCast(props.DataDoc[props.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
+ const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url, props.DataDoc)); // access the primary layout data of the alternate documents
+ const paths = field ? [this.choosePath(field.url, props.DataDoc), ...altpaths] : altpaths;
+ if (paths.length) {
+ url = paths;
+ } else {
+ url = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
+ image = false;
+ }
+ //url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
+ } else {
+ url = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
+ image = false;
+ }
+
+ const heightToWidth = NumCast(props.DataDoc?._nativeHeight) / NumCast(props.DataDoc?._nativeWidth);
+ const height = this.props.rowProps.width * heightToWidth;
+
+ if (props.fieldKey === "data") {
+ if (url !== []) {
+ const reference = React.createRef<HTMLDivElement>();
+ return (
+ <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+ <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
+ <img src={url[0]} width={image ? this.props.rowProps.width : "30px"}
+ height={image ? height : "30px"} />
+ </div >
+ </div>
+ );
+
+ } else {
+ return this.renderCellWithType("image");
+ }
+ } else {
+ return this.renderCellWithType("image");
+ }
+ }
+}
+
+@observer
+export class CollectionSchemaListCell extends CollectionSchemaCell {
+
+ // render() {
+ // return this.renderCellWithType("list");
+ // }
+
+ emptyFunc() {
+
+ }
+ render() {
+ const props: FieldViewProps = {
+ Document: this.props.rowProps.original,
+ DataDoc: this.props.rowProps.original,
+ LibraryPath: [],
+ dropAction: "alias",
+ bringToFront: emptyFunction,
+ rootSelected: returnFalse,
+ fieldKey: this.props.rowProps.column.id as string,
+ ContainingCollectionView: this.props.CollectionView,
+ ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
+ isSelected: returnFalse,
+ select: emptyFunction,
+ renderDepth: this.props.renderDepth + 1,
+ ScreenToLocalTransform: Transform.Identity,
+ focus: emptyFunction,
+ active: returnFalse,
+ whenActiveChanged: emptyFunction,
+ PanelHeight: returnZero,
+ PanelWidth: returnZero,
+ NativeHeight: returnZero,
+ NativeWidth: returnZero,
+ addDocTab: this.props.addDocTab,
+ pinToPres: this.props.pinToPres,
+ ContentScaling: returnOne
+ };
+
+ let value = "";
+ const reference = React.createRef<HTMLDivElement>();
+ const data = props.DataDoc?.fieldKey;
+
+ if (Array.isArray(data)) {
+
+
+
+ return (
+ <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+ <div className="collectionSchemaView-cellContents" key={this._document[Id]} ref={reference}>
+ <KeysDropdown
+ keyValue={value}
+ possibleKeys={data}
+ existingKeys={data}
+ canAddNew={true}
+ addNew={false}
+ onSelect={this.emptyFunc}
+ setIsEditing={this.props.setIsEditing}
+ />
+ </div >
+ </div>
+ );
+ } else {
+ return this.renderCellWithType("list");
+ }
+ }
+}
+
+@observer
export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
@observable private _isChecked: boolean = typeof this.props.rowProps.original[this.props.rowProps.column.id as string] === "boolean" ? BoolCast(this.props.rowProps.original[this.props.rowProps.column.id as string]) : false;
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index dae0600b1..0d6cf4474 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -2,7 +2,7 @@ import React = require("react");
import { action, observable } from "mobx";
import { observer } from "mobx-react";
import "./CollectionSchemaView.scss";
-import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl } from '@fortawesome/free-solid-svg-icons';
import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ColumnType } from "./CollectionSchemaView";
@@ -13,7 +13,7 @@ const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes);
+library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl);
export interface HeaderProps {
keyValue: SchemaHeaderField;
@@ -33,7 +33,8 @@ export interface HeaderProps {
export class CollectionSchemaHeader extends React.Component<HeaderProps> {
render() {
const icon: IconProp = this.props.keyType === ColumnType.Number ? "hashtag" : this.props.keyType === ColumnType.String ? "font" :
- this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" : "align-justify";
+ this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" :
+ this.props.keyType === ColumnType.Image ? "image" : this.props.keyType === ColumnType.List ? "list-ul" : "align-justify";
return (
<div className="collectionSchemaView-header" style={{ background: this.props.keyValue.color }}>
<CollectionSchemaColumnMenu
@@ -160,10 +161,18 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
<FontAwesomeIcon icon={"check-square"} size="sm" />
Checkbox
</div>
+ <div className={"columnMenu-option" + (type === ColumnType.List ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.List)}>
+ <FontAwesomeIcon icon={"list-ul"} size="sm" />
+ List
+ </div>
<div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Doc)}>
<FontAwesomeIcon icon={"file"} size="sm" />
Document
</div>
+ <div className={"columnMenu-option" + (type === ColumnType.Image ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Image)}>
+ <FontAwesomeIcon icon={"image"} size="sm" />
+ Image
+ </div>
</div>
</div >
);
@@ -258,7 +267,7 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
}
-interface KeysDropdownProps {
+export interface KeysDropdownProps {
keyValue: string;
possibleKeys: string[];
existingKeys: string[];
@@ -268,7 +277,7 @@ interface KeysDropdownProps {
setIsEditing: (isEditing: boolean) => void;
}
@observer
-class KeysDropdown extends React.Component<KeysDropdownProps> {
+export class KeysDropdown extends React.Component<KeysDropdownProps> {
@observable private _key: string = this.props.keyValue;
@observable private _searchTerm: string = this.props.keyValue;
@observable private _isOpen: boolean = false;
@@ -331,7 +340,9 @@ class KeysDropdown extends React.Component<KeysDropdownProps> {
renderOptions = (): JSX.Element[] | JSX.Element => {
if (!this._isOpen) return <></>;
- const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ const searchTerm = this._searchTerm.trim() === "New field" ? "" : this._searchTerm;
+
+ const keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
const exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 ||
this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 6dbee217a..610e2336e 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -20,7 +20,7 @@ import { undoBatch } from "../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
import { ContextMenu } from "../ContextMenu";
import '../DocumentDecorations.scss';
-import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaImageCell, CollectionSchemaListCell } from "./CollectionSchemaCells";
import { CollectionSchemaAddColumnHeader, CollectionSchemaHeader } from "./CollectionSchemaHeaders";
import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
import "./CollectionSchemaView.scss";
@@ -40,6 +40,8 @@ export enum ColumnType {
String,
Boolean,
Doc,
+ Image,
+ List
}
// this map should be used for keys that should have a const type of value
const columnTypes: Map<string, ColumnType> = new Map([
@@ -353,6 +355,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
if (colType === ColumnType.String) return <CollectionSchemaStringCell {...props} />;
if (colType === ColumnType.Boolean) return <CollectionSchemaCheckboxCell {...props} />;
if (colType === ColumnType.Doc) return <CollectionSchemaDocCell {...props} />;
+ if (colType === ColumnType.Image) return <CollectionSchemaImageCell {...props} />;
+ if (colType === ColumnType.List) return <CollectionSchemaListCell {...props} />;
return <CollectionSchemaCell {...props} />;
},
minWidth: 200,