aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Utils.ts2
-rw-r--r--src/client/documents/Documents.ts16
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.scss6
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.tsx2
-rw-r--r--src/client/views/DocumentDecorations.tsx42
-rw-r--r--src/client/views/Main.tsx8
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss9
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx13
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx9
-rw-r--r--src/client/views/globalCssVariables.scss2
-rw-r--r--src/client/views/globalCssVariables.scss.d.ts1
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx26
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/DocumentView.scss16
-rw-r--r--src/client/views/nodes/DocumentView.tsx71
-rw-r--r--src/client/views/nodes/FieldView.tsx5
-rw-r--r--src/client/views/nodes/IconBox.scss12
-rw-r--r--src/client/views/nodes/IconBox.tsx90
-rw-r--r--src/fields/IconFIeld.ts25
-rw-r--r--src/fields/KeyStore.ts10
-rw-r--r--src/server/Message.ts2
-rw-r--r--src/server/ServerUtil.ts2
24 files changed, 264 insertions, 121 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index dec6245ef..98f75d3b9 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -1,7 +1,7 @@
import v4 = require('uuid/v4');
import v5 = require("uuid/v5");
import { Socket } from 'socket.io';
-import { Message, Types, Transferable } from './server/Message';
+import { Message } from './server/Message';
import { Document } from './fields/Document';
export class Utils {
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4febfa7eb..b0bb74d89 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -32,6 +32,9 @@ import { action } from "mobx";
import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel";
import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel";
import { AggregateFunction } from "../northstar/model/idea/idea";
+import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss";
+import { IconBox } from "../views/nodes/IconBox";
+import { IconField } from "../../fields/IconFIeld";
export interface DocumentOptions {
x?: number;
@@ -63,6 +66,7 @@ export namespace Documents {
let videoProto: Document;
let audioProto: Document;
let pdfProto: Document;
+ let iconProto: Document;
const textProtoId = "textProto";
const histoProtoId = "histoProto";
const pdfProtoId = "pdfProto";
@@ -72,6 +76,7 @@ export namespace Documents {
const kvpProtoId = "kvpProto";
const videoProtoId = "videoProto";
const audioProtoId = "audioProto";
+ const iconProtoId = "iconProto";
export function initProtos(): Promise<void> {
return Server.GetFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => {
@@ -84,6 +89,7 @@ export namespace Documents {
videoProto = fields[videoProtoId] as Document || CreateVideoPrototype();
audioProto = fields[audioProtoId] as Document || CreateAudioPrototype();
pdfProto = fields[pdfProtoId] as Document || CreatePdfPrototype();
+ iconProto = fields[iconProtoId] as Document || CreateIconPrototype();
});
}
function assignOptions(doc: Document, options: DocumentOptions): Document {
@@ -92,6 +98,8 @@ export namespace Documents {
if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); }
if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); }
if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); }
+ if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); }
+ if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); }
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)); }
@@ -139,6 +147,11 @@ export namespace Documents {
histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString());
return histoProto;
}
+ function CreateIconPrototype(): Document {
+ let iconProto = setupPrototypeOptions(iconProtoId, "ICON_PROTO", IconBox.LayoutString(),
+ { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data] });
+ return iconProto;
+ }
function CreateTextPrototype(): Document {
let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(),
{ x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] });
@@ -203,6 +216,9 @@ export namespace Documents {
export function TextDocument(options: DocumentOptions = {}) {
return assignToDelegate(SetInstanceOptions(textProto, options, ["", TextField]).MakeDelegate(), options);
}
+ export function IconDocument(icon: string, options: DocumentOptions = {}) {
+ return assignToDelegate(SetInstanceOptions(iconProto, { width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data], layout: IconBox.LayoutString(), ...options }, [icon, IconField]), options);
+ }
export function PdfDocument(url: string, options: DocumentOptions = {}) {
return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options);
}
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss
index e899cf15e..06d781263 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.scss
+++ b/src/client/northstar/dash-nodes/HistogramBox.scss
@@ -1,12 +1,12 @@
.histogrambox-container {
padding: 0vw;
position: absolute;
- top: 0;
- left:0;
+ top: -50%;
+ left:-50%;
text-align: center;
width: 100%;
height: 100%;
- background: black;
+ background: black;
}
.histogrambox-xaxislabel {
position:absolute;
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 0e84ace50..e2ecc8c83 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -146,7 +146,7 @@ export class HistogramBox extends React.Component<FieldViewProps> {
return (
<Measure onResize={(r: any) => runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}>
{({ measureRef }) =>
- <div className="histogrambox-container" ref={measureRef} style={{ transform: `translate(-50%, -50%)` }}>
+ <div className="histogrambox-container" ref={measureRef}>
<div className="histogrambox-yaxislabel" onPointerDown={this.yLabelPointerDown} ref={this._dropYRef} >
<span className="histogrambox-yaxislabel-text">
{labelY}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index cfb9befd5..da2c7a3be 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -5,17 +5,18 @@ import { KeyStore } from "../../fields/KeyStore";
import { ListField } from "../../fields/ListField";
import { NumberField } from "../../fields/NumberField";
import { TextField } from "../../fields/TextField";
+import { Document } from "../../fields/Document";
import { emptyFunction } from "../../Utils";
import { DragLinksAsDocuments, DragManager } from "../util/DragManager";
import { SelectionManager } from "../util/SelectionManager";
import { undoBatch } from "../util/UndoManager";
import './DocumentDecorations.scss';
import { MainOverlayTextBox } from "./MainOverlayTextBox";
-import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss";
import { DocumentView } from "./nodes/DocumentView";
import { LinkMenu } from "./nodes/LinkMenu";
import React = require("react");
import { CompileScript } from "../util/Scripting";
+import { IconBox } from "./nodes/IconBox";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -191,6 +192,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
document.addEventListener("pointerup", this.onMinimizeUp);
}
}
+
+ @observable _minimizedX = 0;
+ @observable _minimizedY = 0;
@action
onMinimizeMove = (e: PointerEvent): void => {
e.stopPropagation();
@@ -201,12 +205,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let xf = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
let dx = e.pageX - xf[0];
let dy = e.pageY - xf[1];
- if (Math.abs(dx) < 20 && Math.abs(dy) < 20)
- dx = dy = 0;
+ this._minimizedX = e.clientX;
+ this._minimizedY = e.clientY;
+ if (Math.abs(dx) < 20 && Math.abs(dy) < 20) {
+ this._minimizedX = xf[0];
+ this._minimizedY = xf[1];
+ }
SelectionManager.SelectedDocuments().map(dv => {
- let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformDirection(dx, dy);
- dv.props.Document.SetNumber(KeyStore.MinimizedX, where[0]);
- dv.props.Document.SetNumber(KeyStore.MinimizedY, where[1]);
+ let minDoc = dv.props.Document.Get(KeyStore.MinimizedDoc);
+ if (minDoc instanceof Document) {
+ let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformPoint(this._minimizedX, this._minimizedY);
+ let minDocument = minDoc as Document;
+ minDocument.SetNumber(KeyStore.X, where[0] + dv.props.Document.GetNumber(KeyStore.X, 0));
+ minDocument.SetNumber(KeyStore.Y, where[1] + dv.props.Document.GetNumber(KeyStore.Y, 0));
+ }
});
}
}
@@ -219,6 +231,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (Math.abs(dx) < 4 && Math.abs(dy) < 4 && !this._iconifying) {
SelectionManager.SelectedDocuments().map(dv => dv.minimize());
SelectionManager.DeselectAll();
+ } else {
+ this._minimizedX = this._minimizedY = 0;
}
document.removeEventListener("pointermove", this.onMinimizeMove);
document.removeEventListener("pointerup", this.onMinimizeUp);
@@ -404,24 +418,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (bounds.x === Number.MAX_VALUE || !seldoc) {
return (null);
}
- let minvec = [seldoc.props.Document.GetNumber(KeyStore.MinimizedX, 0), seldoc.props.Document.GetNumber(KeyStore.MinimizedY, 0)];
- minvec = seldoc.props.ScreenToLocalTransform().scale(seldoc.props.ContentScaling()).inverse().transformDirection(minvec[0], minvec[1]);
- let selpos = minvec[0] !== 0 || minvec[1] !== 0 ?
- [minvec[0] - 12 + (!this._iconifying ? 8 : 0), minvec[1] - 12 + (!this._iconifying ? 28 : 0)] :
+ let selpos = this._minimizedX !== 0 || this._minimizedY !== 0 ?
+ [this._minimizedX - 12 + (!this._iconifying ? 8 : 0), this._minimizedY - 12 + (!this._iconifying ? 28 : 0)] :
[0, this._iconifying ? -18 : 0];
let minimizeIcon = (
<div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}
style={{ transform: `translate(${selpos[0]}px,${selpos[1]}px)`, }}>
- {SelectionManager.SelectedDocuments().length == 1 ? SelectionManager.SelectedDocuments()[0].minimizedIcon : "..."}
+ {SelectionManager.SelectedDocuments().length == 1 ? IconBox.DocumentIcon(SelectionManager.SelectedDocuments()[0].props.Document.GetText(KeyStore.Layout, "...")) : "..."}
</div>);
if (this._iconifying) {
- let xfpt = seldoc.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- return (<div className="documentDecorations-container" style={{ transform: `translate(${xfpt[0]}px,${xfpt[1]}px` }}>
- {minimizeIcon}
- </div>);
+ return (<div className="documentDecorations-container" > {minimizeIcon} </div>);
}
- // console.log(this._documents.length)
- // let test = this._documents[0].props.Document.Title;
+
if (this.Hidden) {
return (null);
}
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 503a11b35..09ef30f6b 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -85,11 +85,11 @@ export class Main extends React.Component {
this.initEventListeners();
this.initAuthenticationRouters();
- // try {
- // this.initializeNorthstar();
- // } catch (e) {
+ try {
+ this.initializeNorthstar();
+ } catch (e) {
- // }
+ }
}
componentDidMount() { window.onpopstate = this.onHistory; }
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 6eabbe17c..cfdb3ab22 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -1,6 +1,7 @@
@import "../globalCssVariables";
+
.collectionSchemaView-container {
border-width: $COLLECTION_BORDER_WIDTH;
border-color : $intermediate-color;
@@ -10,6 +11,10 @@
position: absolute;
width: 100%;
height: 100%;
+
+ .collectionSchemaView-cellContents {
+ height: $MAX_ROW_HEIGHT;
+ }
.collectionSchemaView-previewRegion {
position: relative;
@@ -104,7 +109,7 @@
}
.rt-tr-group {
direction: ltr;
- max-height: 44px;
+ max-height: $MAX_ROW_HEIGHT;
}
.rt-td {
border-width: 1px;
@@ -136,7 +141,7 @@
}
.ReactTable .rt-th,
.ReactTable .rt-td {
- max-height: 44;
+ max-height: $MAX_ROW_HEIGHT;
padding: 3px 7px;
font-size: 13px;
text-align: center;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b61eb342d..90077b053 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, untracked } from "mobx";
import { observer } from "mobx-react";
import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
+import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'
import "react-table/react-table.css";
import { Document } from "../../../fields/Document";
import { Field, Opt } from "../../../fields/Field";
@@ -99,11 +100,11 @@ export class CollectionSchemaView extends CollectionSubView {
return false;
};
return (
- <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.Document.Id} ref={reference}>
+ <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} key={props.Document.Id} ref={reference}>
<EditableView
display={"inline"}
contents={contents}
- height={56}
+ height={Number(MAX_ROW_HEIGHT)}
GetValue={() => {
let field = props.Document.Get(props.fieldKey);
if (field && field instanceof Field) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 8868f7df0..20c5a84bf 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
let l = this.props.LinkDocs;
let a = this.props.A;
let b = this.props.B;
- let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Width() / 2);
- let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Height() / 2);
- let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Width() / 2);
- let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Height() / 2);
+ let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Width() / 2);
+ let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Height() / 2);
+ let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Width() / 2);
+ let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Height() / 2);
return (
<line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c50597655..945c01059 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -21,6 +21,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import v5 = require("uuid/v5");
+import { BooleanField } from "../../../../fields/BooleanField";
@observer
export class CollectionFreeFormView extends CollectionSubView {
@@ -71,17 +72,15 @@ export class CollectionFreeFormView extends CollectionSubView {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) {
- console.log("DROP Aat " + de.x + " off " + de.data.xOffset);
const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset);
if (de.data.droppedDocuments.length) {
let dragDoc = de.data.droppedDocuments[0];
let dropX = dragDoc.GetNumber(KeyStore.X, 0);
let dropY = dragDoc.GetNumber(KeyStore.Y, 0);
de.data.droppedDocuments.map(d => {
- let minimized = d.GetBoolean(KeyStore.Minimized, false);
- d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedX, 0) : 0)) - dropX);
- d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedY, 0) : 0)) - dropY);
- if (!minimized) {
+ d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX);
+ d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY);
+ if (!d.GetBoolean(KeyStore.IsMinimized, false)) {
if (!d.GetNumber(KeyStore.Width, 0)) {
d.SetNumber(KeyStore.Width, 300);
}
@@ -264,7 +263,9 @@ export class CollectionFreeFormView extends CollectionSubView {
let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
var page = doc.GetNumber(KeyStore.Page, -1);
if (page === curPage || page === -1) {
- prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
+ let minim = doc.GetT(KeyStore.IsMinimized, BooleanField);
+ if (minim === undefined || (minim && !minim.Data))
+ prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
}
return prev;
}, [] as JSX.Element[]);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 8b94374fa..bf918beba 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -208,12 +208,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let selRect = this.Bounds;
let selection: Document[] = [];
this.props.activeDocuments().map(doc => {
- let minimized = doc.GetBoolean(KeyStore.Minimized, false);
var z = doc.GetNumber(KeyStore.Zoom, 1);
- var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0);
- var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0);
- var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z;
- var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z;
+ var x = doc.GetNumber(KeyStore.X, 0);
+ var y = doc.GetNumber(KeyStore.Y, 0);
+ var w = doc.Width() / z;
+ var h = doc.Height() / z;
if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
selection.push(doc);
}
diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss
index f154f8158..4f68b71b0 100644
--- a/src/client/views/globalCssVariables.scss
+++ b/src/client/views/globalCssVariables.scss
@@ -24,8 +24,10 @@ $docDecorations-zindex: 998; // then doc decorations appear over everything else
$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right?
$COLLECTION_BORDER_WIDTH: 1;
$MINIMIZED_ICON_SIZE:25;
+$MAX_ROW_HEIGHT: 44px;
:export {
contextMenuZindex: $contextMenu-zindex;
COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH;
MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE;
+ MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT;
} \ No newline at end of file
diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts
index cc77d987a..9788d31f7 100644
--- a/src/client/views/globalCssVariables.scss.d.ts
+++ b/src/client/views/globalCssVariables.scss.d.ts
@@ -3,6 +3,7 @@ interface IGlobalScss {
contextMenuZindex: string; // context menu shows up over everything
COLLECTION_BORDER_WIDTH: string;
MINIMIZED_ICON_SIZE: string;
+ MAX_ROW_HEIGHT: string;
}
declare const globalCssVariables: IGlobalScss;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index a3689414d..1d42b3899 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -46,10 +46,10 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
}
get X() {
- return this.props.Document.GetNumber(KeyStore.X, 0) + (this.isMinimized ? this.props.Document.GetNumber(KeyStore.MinimizedX, 0) : 0);
+ return this.props.Document.GetNumber(KeyStore.X, 0);
}
get Y() {
- return this.props.Document.GetNumber(KeyStore.Y, 0) + (this.isMinimized ? this.props.Document.GetNumber(KeyStore.MinimizedY, 0) : 0);
+ return this.props.Document.GetNumber(KeyStore.Y, 0);
}
getTransform = (): Transform =>
this.props.ScreenToLocalTransform()
@@ -57,8 +57,8 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
.scale(1 / this.contentScaling()).scale(1 / this.zoom)
contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
- panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth();
- panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight();
+ panelWidth = () => this.props.PanelWidth();
+ panelHeight = () => this.props.PanelHeight();
@computed
get docView() {
@@ -70,19 +70,17 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
/>;
}
- get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); }
-
render() {
let zoomFade = 1;
//var zoom = doc.GetNumber(KeyStore.Zoom, 1);
- let transform = this.getTransform().scale(this.contentScaling()).inverse();
- var [sptX, sptY] = transform.transformPoint(0, 0);
- let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
- let w = bptX - sptX;
- //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
- let fadeUp = .75 * 1800;
- let fadeDown = .075 * 1800;
- zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+ // let transform = this.getTransform().scale(this.contentScaling()).inverse();
+ // var [sptX, sptY] = transform.transformPoint(0, 0);
+ // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
+ // let w = bptX - sptX;
+ // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
+ // let fadeUp = .75 * 1800;
+ // let fadeDown = .075 * 1800;
+ // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
return (
<div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 76f852601..07599c345 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -15,6 +15,7 @@ import { DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import { FormattedTextBox } from "./FormattedTextBox";
import { ImageBox } from "./ImageBox";
+import { IconBox } from "./IconBox";
import { KeyValueBox } from "./KeyValueBox";
import { PDFBox } from "./PDFBox";
import { VideoBox } from "./VideoBox";
@@ -62,7 +63,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
return <p>Error loading layout keys</p>;
}
return <JsxParser
- components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
+ components={{ FormattedTextBox, ImageBox, IconBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
bindings={this.CreateBindings()}
jsx={this.layout}
showWarnings={true}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a0e829d26..7c72fb6e6 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -4,7 +4,7 @@
position: inherit;
top: 0;
left:0;
- background: $light-color; //overflow: hidden;
+ // background: $light-color; //overflow: hidden;
transform-origin: left top;
&.minimized {
@@ -30,18 +30,4 @@
}
.documentView-node-topmost {
background: white;
-}
-.minimized-box {
- position: absolute;
- left:0;
- top:0;
- width:$MINIMIZED_ICON_SIZE;
- height:$MINIMIZED_ICON_SIZE;
- transform:translate(-50%, -50%);
-}
-
-.minimized-box:hover {
- background: $main-accent;
- transform:translate(-50%, -50%) scale(1.15);;
- cursor: pointer;
} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3ada3252c..558cbf017 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,6 +1,3 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faObjectGroup, faStickyNote, faFilePdf, faFilm, faImage } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
@@ -20,18 +17,11 @@ import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionPDFView } from "../collections/CollectionPDFView";
import { CollectionVideoView } from "../collections/CollectionVideoView";
import { CollectionView } from "../collections/CollectionView";
-import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss";
import { ContextMenu } from "../ContextMenu";
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
-
-
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm);
+import { TextField } from "../../../fields/TextField";
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
@@ -189,10 +179,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
e.stopPropagation();
- if (!SelectionManager.IsSelected(this) && e.button !== 2 &&
- Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
- SelectionManager.SelectDoc(this, e.ctrlKey);
- }
+ if (!SelectionManager.IsSelected(this) && e.button !== 2)
+ if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
}
stopPropagation = (e: React.SyntheticEvent) => {
e.stopPropagation();
@@ -221,13 +211,33 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
}
+ @action createIcon = (layoutString: string): void => {
+ let iconDoc = Documents.IconDocument(layoutString);
+ iconDoc.SetBoolean(KeyStore.IsMinimized, false);
+ iconDoc.SetNumber(KeyStore.NativeWidth, 0);
+ iconDoc.SetNumber(KeyStore.NativeHeight, 0);
+ iconDoc.Set(KeyStore.Prototype, this.props.Document);
+ iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document);
+ this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc);
+ this.props.addDocument && this.props.addDocument(iconDoc, false);
+ }
+
@action
- public minimize = (where: number[]): void => {
- this.props.Document.SetBoolean(KeyStore.Minimized, true);
- if (where[0] !== 0 || where[1] !== 0)
- this.props.Document.SetNumber(KeyStore.MinimizedX, where[0]);
- if (where[1] !== 0 || where[0] !== 0)
- this.props.Document.SetNumber(KeyStore.MinimizedY, where[1]);
+ public minimize = (): void => {
+ this.props.Document.SetBoolean(KeyStore.IsMinimized, true);
+ this.props.Document.GetAsync(KeyStore.MinimizedDoc, mindoc => {
+ if (mindoc === undefined) {
+ this.props.Document.GetAsync(KeyStore.BackgroundLayout, field => {
+ if (field instanceof TextField) this.createIcon(field.Data);
+ else this.props.Document.GetAsync(KeyStore.Layout, field => {
+ if (field instanceof TextField) this.createIcon(field.Data);
+ });
+ });
+ }
+ else if (mindoc instanceof Document) {
+ this.props.addDocument && this.props.addDocument(mindoc, false);
+ }
+ });
}
@undoBatch
@@ -295,7 +305,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
e.preventDefault();
- !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: () => this.minimize([0, 0]) });
ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked });
ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) });
@@ -309,9 +318,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
SelectionManager.SelectDoc(this, false);
}
- @action
- expand = (e: React.MouseEvent) => { this.props.Document.SetBoolean(KeyStore.Minimized, false); SelectionManager.SelectDoc(this, e.ctrlKey); }
- isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false);
isSelected = () => SelectionManager.IsSelected(this);
select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
@@ -319,27 +325,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
@computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
@computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />); }
- @computed get minimizedIcon() {
- let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf :
- this.layout.indexOf("ImageBox") !== -1 ? faImage :
- this.layout.indexOf("Formatted") !== -1 ? faStickyNote :
- this.layout.indexOf("Video") !== -1 ? faFilm :
- this.layout.indexOf("Collection") !== -1 ? faObjectGroup :
- faCaretUp;
- return <FontAwesomeIcon icon={button} style={{ width: MINIMIZED_ICON_SIZE, height: MINIMIZED_ICON_SIZE }} className="documentView-minimizedIcon" />
- }
render() {
var scaling = this.props.ContentScaling();
var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%";
var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%";
- if (this.isMinimized()) {
- return (
- <div className="minimized-box" ref={this._mainCont} onClick={this.expand} onDrop={this.onDrop} onPointerDown={this.onPointerDown} >
- {this.minimizedIcon}
- </div>);
- }
return (
<div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
ref={this._mainCont}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index e9f6950ff..93e385821 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -23,6 +23,8 @@ import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../.
import { CollectionView } from "../collections/CollectionView";
import { CollectionPDFView } from "../collections/CollectionPDFView";
import { CollectionVideoView } from "../collections/CollectionVideoView";
+import { IconField } from "../../../fields/IconFIeld";
+import { IconBox } from "./IconBox";
//
@@ -72,6 +74,9 @@ export class FieldView extends React.Component<FieldViewProps> {
else if (field instanceof ImageField) {
return <ImageBox {...this.props} />;
}
+ else if (field instanceof IconField) {
+ return <IconBox {...this.props} />;
+ }
else if (field instanceof VideoField) {
return <VideoBox {...this.props} />;
}
diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss
new file mode 100644
index 000000000..ce0ee2e09
--- /dev/null
+++ b/src/client/views/nodes/IconBox.scss
@@ -0,0 +1,12 @@
+
+@import "../globalCssVariables";
+.iconBox-container {
+ position: absolute;
+ left:0;
+ top:0;
+ svg {
+ width: 100% !important;
+ height: 100%;
+ background: white;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx
new file mode 100644
index 000000000..5ada2186d
--- /dev/null
+++ b/src/client/views/nodes/IconBox.tsx
@@ -0,0 +1,90 @@
+import React = require("react");
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import { Document } from '../../../fields/Document';
+import { IconField } from "../../../fields/IconFIeld";
+import { KeyStore } from "../../../fields/KeyStore";
+import { SelectionManager } from "../../util/SelectionManager";
+import { FieldView, FieldViewProps } from './FieldView';
+import "./IconBox.scss";
+
+
+library.add(faCaretUp);
+library.add(faObjectGroup);
+library.add(faStickyNote);
+library.add(faFilePdf);
+library.add(faFilm);
+
+@observer
+export class IconBox extends React.Component<FieldViewProps> {
+ public static LayoutString() { return FieldView.LayoutString(IconBox); }
+
+ @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); }
+ @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "<p>Error loading layout data</p>" as string); }
+ @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); }
+
+ public static DocumentIcon(layout: string) {
+ let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
+ layout.indexOf("ImageBox") !== -1 ? faImage :
+ layout.indexOf("Formatted") !== -1 ? faStickyNote :
+ layout.indexOf("Video") !== -1 ? faFilm :
+ layout.indexOf("Collection") !== -1 ? faObjectGroup :
+ faCaretUp;
+ return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />
+ }
+
+ animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) {
+ setTimeout(() => {
+ let now = Date.now();
+ let progress = Math.min(1, (now - stime) / 200);
+ let pval = maximizing ?
+ [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] :
+ [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress];
+ target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress);
+ target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress);
+ target.SetNumber(KeyStore.X, pval[0]);
+ target.SetNumber(KeyStore.Y, pval[1]);
+ if (now < stime + 200) {
+ this.animateTransition(icon, targ, width, height, stime, target, maximizing);
+ }
+ else {
+ if (!maximizing) {
+ target.SetBoolean(KeyStore.IsMinimized, true);
+ target.SetNumber(KeyStore.X, targ[0]);
+ target.SetNumber(KeyStore.Y, targ[1]);
+ target.SetNumber(KeyStore.Width, width);
+ target.SetNumber(KeyStore.Height, height);
+ }
+ this._completed = true;
+ }
+ },
+ 2);
+ }
+
+ _completed = true;
+
+ @action
+ public toggleMinimize = (): void => {
+ SelectionManager.DeselectAll();
+ if (this.maximized instanceof Document && this._completed) {
+ this._completed = false;
+ let minimized = this.maximized.GetBoolean(KeyStore.IsMinimized, false);
+ this.maximized.SetBoolean(KeyStore.IsMinimized, false);
+ this.animateTransition(
+ [this.props.Document.GetNumber(KeyStore.X, 0), this.props.Document.GetNumber(KeyStore.Y, 0)],
+ [this.maximized.GetNumber(KeyStore.X, 0), this.maximized.GetNumber(KeyStore.Y, 0)],
+ this.maximized.GetNumber(KeyStore.Width, 0), this.maximized.GetNumber(KeyStore.Width, 0),
+ Date.now(), this.maximized, minimized);
+ }
+ }
+
+ render() {
+ return (
+ <div className="iconBox-container" onClick={this.toggleMinimize} >
+ {this.minimizedIcon}
+ </div>);
+ }
+} \ No newline at end of file
diff --git a/src/fields/IconFIeld.ts b/src/fields/IconFIeld.ts
new file mode 100644
index 000000000..a6694cc49
--- /dev/null
+++ b/src/fields/IconFIeld.ts
@@ -0,0 +1,25 @@
+import { BasicField } from "./BasicField";
+import { FieldId } from "./Field";
+import { Types } from "../server/Message";
+
+export class IconField extends BasicField<string> {
+ constructor(data: string = "", id?: FieldId, save: boolean = true) {
+ super(data, save, id);
+ }
+
+ ToScriptString(): string {
+ return `new IconField("${this.Data}")`;
+ }
+
+ Copy() {
+ return new IconField(this.Data);
+ }
+
+ ToJson() {
+ return {
+ type: Types.Icon,
+ 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 ff2f31003..a347f8bcf 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -4,8 +4,6 @@ export namespace KeyStore {
export const Prototype = new Key("Prototype");
export const X = new Key("X");
export const Y = new Key("Y");
- export const MinimizedX = new Key("MinimizedX");
- export const MinimizedY = new Key("MinimizedY");
export const Page = new Key("Page");
export const Title = new Key("Title");
export const Author = new Key("Author");
@@ -47,14 +45,16 @@ export namespace KeyStore {
export const OptionalRightCollection = new Key("OptionalRightCollection");
export const Archives = new Key("Archives");
export const Workspaces = new Key("Workspaces");
- export const Minimized = new Key("Minimized");
+ export const IsMinimized = new Key("IsMinimized");
+ export const MinimizedDoc = new Key("MinimizedDoc");
+ export const MaximizedDoc = new Key("MaximizedDoc");
export const CopyDraggedItems = new Key("CopyDraggedItems");
- export const KeyList: Key[] = [Prototype, X, Y, MinimizedX, MinimizedY, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight,
+ export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight,
Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys,
LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs,
LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection,
- Archives, Workspaces, Minimized, CopyDraggedItems
+ Archives, Workspaces, IsMinimized, MinimizedDoc, MaximizedDoc, CopyDraggedItems
];
export function KeyLookup(keyid: string) {
for (const key of KeyList) {
diff --git a/src/server/Message.ts b/src/server/Message.ts
index bbe4ffcad..15916ef12 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -14,7 +14,7 @@ export class Message<T> {
}
export enum Types {
- Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference,
+ Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference,
Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script,
}
diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts
index 818230c1a..79ca5e55d 100644
--- a/src/server/ServerUtil.ts
+++ b/src/server/ServerUtil.ts
@@ -18,6 +18,7 @@ import { NumberField } from "./../fields/NumberField";
import { RichTextField } from "./../fields/RichTextField";
import { TextField } from "./../fields/TextField";
import { Transferable, Types } from "./Message";
+import { IconField } from "../fields/IconFIeld";
export class ServerUtils {
public static prepend(extension: string): string {
@@ -37,6 +38,7 @@ export class ServerUtils {
case Types.Boolean: return new BooleanField(json.data, json.id, false);
case Types.Number: return new NumberField(json.data, json.id, false);
case Types.Text: return new TextField(json.data, json.id, false);
+ case Types.Icon: return new IconField(json.data, json.id, false);
case Types.Html: return new HtmlField(json.data, json.id, false);
case Types.Web: return new WebField(new URL(json.data), json.id, false);
case Types.RichText: return new RichTextField(json.data, json.id, false);