From 700dfc5add1ecd9c2b1ecafcdc593ff821b7a6a6 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 20 Aug 2019 17:20:27 -0400 Subject: UI enhancements and other backend fixes for templates. --- src/client/util/DragManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/client/util/DragManager.ts') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0b6d9b5e5..894b366ef 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -9,8 +9,6 @@ import { DocumentManager } from "./DocumentManager"; import { LinkManager } from "./LinkManager"; import { SelectionManager } from "./SelectionManager"; import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; -import { DocumentDecorations } from "../views/DocumentDecorations"; -import { NumberLiteralType } from "typescript"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -211,6 +209,7 @@ export namespace DragManager { dropAction: dropActionType; userDropAction: dropActionType; moveDocument?: MoveFunction; + applyAsTemplate?: boolean; [id: string]: any; } -- cgit v1.2.3-70-g09d2 From 20f7d2dca1c115c84f6ac89981ef1e3c7c9a2757 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 22 Aug 2019 23:18:42 -0400 Subject: added start of collection script building UI --- src/client/util/DragManager.ts | 4 +- .../views/collections/CollectionViewChromes.scss | 73 +++++++++++++++++- .../views/collections/CollectionViewChromes.tsx | 87 ++++++++++++++++++++-- src/client/views/nodes/ButtonBox.tsx | 27 ++++++- src/new_fields/Doc.ts | 3 +- 5 files changed, 184 insertions(+), 10 deletions(-) (limited to 'src/client/util/DragManager.ts') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 894b366ef..24c093213 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -140,6 +140,8 @@ export namespace DragManager { withoutShiftDrag?: boolean; + finishDrag?: (dropData: { [id: string]: any }) => void; + offsetX?: number; offsetY?: number; @@ -234,7 +236,7 @@ export namespace DragManager { export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { runInAction(() => StartDragFunctions.map(func => func())); - StartDrag(eles, dragData, downX, downY, options, + StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : (dropData: { [id: string]: any }) => { (dropData.droppedDocuments = dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? dragData.draggedDocuments.map(d => Doc.MakeAlias(d)) : diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index f39bd877a..64411b5fe 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -64,7 +64,7 @@ font-size: 75%; background: rgb(238, 238, 238); height: 100%; - width: 150px; + width: 75px; } .collectionViewBaseChrome-viewSpecsMenu { @@ -234,4 +234,75 @@ margin-left: 50px; } } +} + + +.commandEntry-outerDiv { + display: flex; + flex-direction: column; + width: 165px; + height: 40px; +} +.commandEntry-inputArea { + display:flex; + flex-direction: row; + width: 150px; + margin: auto 0 auto auto; +} + +.react-autosuggest__container { + position: relative; + width: 100%; + margin-left: 5px; + margin-right: 5px; +} + +.react-autosuggest__input { + border: 1px solid #aaa; + border-radius: 4px; + width: 100%; +} + +.react-autosuggest__input--focused { + outline: none; +} + +.react-autosuggest__input--open { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.react-autosuggest__suggestions-container { + display: none; +} + +.react-autosuggest__suggestions-container--open { + display: block; + position: fixed; + overflow-y: auto; + max-height: 400px; + width: 180px; + border: 1px solid #aaa; + background-color: #fff; + font-family: Helvetica, sans-serif; + font-weight: 300; + font-size: 16px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + z-index: 2; +} + +.react-autosuggest__suggestions-list { + margin: 0; + padding: 0; + list-style-type: none; +} + +.react-autosuggest__suggestion { + cursor: pointer; + padding: 10px 20px; +} + +.react-autosuggest__suggestion--highlighted { + background-color: #ddd; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 74e57611d..352bcd4a6 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -8,7 +8,7 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { Utils } from "../../../Utils"; +import { Utils, emptyFunction } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; import { CompileScript } from "../../util/Scripting"; import { undoBatch } from "../../util/UndoManager"; @@ -18,7 +18,9 @@ import { DocLike } from "../MetadataEntryMenu"; import { CollectionViewType } from "./CollectionBaseView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; +import * as Autosuggest from 'react-autosuggest'; import KeyRestrictionRow from "./KeyRestrictionRow"; +import { Docs } from "../../documents/Documents"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -43,6 +45,8 @@ export class CollectionViewBaseChrome extends React.Component(); @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } private _picker: any; @@ -287,7 +291,12 @@ export class CollectionViewBaseChrome extends React.Component(de.data.draggedDocuments); + } e.stopPropagation(); return true; } @@ -308,6 +317,63 @@ export class CollectionViewBaseChrome extends React.Component(); + + renderSuggestion = (suggestion: string) => { + return

{suggestion}

; + } + getSuggestionValue = (suggestion: string) => suggestion; + + @action + onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { + this._currentKey = newValue; + } + onSuggestionFetch = async ({ value }: { value: string }) => { + const sugg = await this.getKeySuggestions(value); + runInAction(() => this.suggestions = sugg); + } + @action + onSuggestionClear = () => { + this.suggestions = []; + } + getKeySuggestions = async (value: string): Promise => { + return this._allCommands.filter(c => c.indexOf(value) !== -1); + } + + autoSuggestDown = (e: React.PointerEvent) => { + e.stopPropagation(); + } + dragCommandDown = (e: React.PointerEvent) => { + let de = new DragManager.DocumentDragData([this.props.CollectionView.props.Document], [undefined]); + DragManager.StartDocumentDrag([this._commandRef.current!], de, e.clientX, e.clientY, { + finishDrag: (dropData: { [id: string]: any }) => { + let bd = Docs.Create.ButtonDocument({ width: 150, height: 50, title: this._currentKey }); + let script = `getProto(target).data = copyField(this.source);`; + let compiled = CompileScript(script, { + params: { doc: Doc.name }, + capturedVariables: { target: this.props.CollectionView.props.Document }, + typecheck: false, + editable: true + }); + if (compiled.compiled) { + let scriptField = new ScriptField(compiled); + bd.onClick = scriptField; + } + dropData.droppedDocuments = [bd]; + }, + handlers: { + dragComplete: action(() => { + }), + }, + hideSource: false + }); + e.preventDefault(); + e.stopPropagation(); + } + render() { let collapsed = this.props.CollectionView.props.Document.chromeStatus !== "enabled"; return ( @@ -337,7 +403,7 @@ export class CollectionViewBaseChrome extends React.Component
{ }} onPointerDown={this.openViewSpecs} @@ -388,8 +454,19 @@ export class CollectionViewBaseChrome extends React.Component
-
- TEMPLATE +
+
+
+ +
+
{this.subChrome()} diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index 8b6f11aac..ca5f0acc2 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -15,7 +15,11 @@ import { Doc } from '../../../new_fields/Doc'; import './ButtonBox.scss'; import { observer } from 'mobx-react'; import { DocumentIconContainer } from './DocumentIcon'; -import { StrCast } from '../../../new_fields/Types'; +import { StrCast, BoolCast } from '../../../new_fields/Types'; +import { DragManager } from '../../util/DragManager'; +import { undoBatch } from '../../util/UndoManager'; +import { action, computed } from 'mobx'; +import { List } from '../../../new_fields/List'; library.add(faEdit as any); @@ -30,10 +34,29 @@ const ButtonDocument = makeInterface(ButtonSchema); @observer export class ButtonBox extends DocComponent(ButtonDocument) { public static LayoutString() { return FieldView.LayoutString(ButtonBox); } + private dropDisposer?: DragManager.DragDropDisposer; + @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } + + + protected createDropTarget = (ele: HTMLDivElement) => { + if (this.dropDisposer) { + this.dropDisposer(); + } + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); + } + } + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + if (de.data instanceof DragManager.DocumentDragData) { + Doc.GetProto(this.dataDoc).source = new List(de.data.droppedDocuments); + } + } render() { return ( -
+
{this.Document.text || this.Document.title}
); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e5b609966..f6114d476 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -626,4 +626,5 @@ export namespace Doc { } } Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`; }); -Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); \ No newline at end of file +Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); +Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f4afa471e03618169137a6533db8623aae93d6c5 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 23 Aug 2019 12:42:38 -0400 Subject: got drag drop buttons working better. --- src/client/util/DragManager.ts | 30 ++++++++- .../views/collections/CollectionViewChromes.tsx | 71 +++++++--------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++- src/client/views/nodes/ButtonBox.scss | 19 +++++- src/client/views/nodes/ButtonBox.tsx | 42 +++++++------ src/new_fields/Doc.ts | 14 ++++- 6 files changed, 111 insertions(+), 76 deletions(-) (limited to 'src/client/util/DragManager.ts') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 24c093213..748fb9d13 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,5 +1,5 @@ import { action, runInAction } from "mobx"; -import { Doc } from "../../new_fields/Doc"; +import { Doc, Field } from "../../new_fields/Doc"; import { Cast, StrCast } from "../../new_fields/Types"; import { URLField } from "../../new_fields/URLField"; import { emptyFunction } from "../../Utils"; @@ -9,6 +9,11 @@ import { DocumentManager } from "./DocumentManager"; import { LinkManager } from "./LinkManager"; import { SelectionManager } from "./SelectionManager"; import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; +import { Docs } from "../documents/Documents"; +import { CompileScript } from "./Scripting"; +import { ScriptField } from "../../new_fields/ScriptField"; +import { List } from "../../new_fields/List"; +import { PrefetchProxy } from "../../new_fields/Proxy"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -247,6 +252,27 @@ export namespace DragManager { }); } + export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], downX: number, downY: number, options?: DragOptions) { + let dragData = new DragManager.DocumentDragData([], [undefined]); + runInAction(() => StartDragFunctions.map(func => func())); + StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : + (dropData: { [id: string]: any }) => { + let bd = Docs.Create.ButtonDocument({ width: 150, height: 50, title: title }); + let compiled = CompileScript(script, { + params: { doc: Doc.name }, + typecheck: false, + editable: true + }); + if (compiled.compiled) { + let scriptField = new ScriptField(compiled); + bd.onClick = scriptField; + } + params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); + bd.buttonParams = new List(params); + dropData.droppedDocuments = [bd]; + }); + } + export function StartLinkedDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { dragData.moveDocument = moveLinkedDocument; @@ -482,7 +508,7 @@ export namespace DragManager { // if (parent && dragEle) parent.appendChild(dragEle); }); if (target) { - if (finishDrag) finishDrag(dragData); + finishDrag && finishDrag(dragData); target.dispatchEvent( new CustomEvent("dashOnDrop", { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 352bcd4a6..15bef39b3 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -286,20 +286,22 @@ export class CollectionViewBaseChrome extends React.Component await p));", params: ["target", "source"], // bcz: doesn't look like we can do async stuff in scripting... + title: "set content", script: "getProto(this.target).data = aliasDocs(this.source);", params: ["target", "source"], + immediate: (draggedDocs: Doc[]) => Doc.GetProto(this.props.CollectionView.props.Document).data = new List(draggedDocs) + }, + { + title: "set template", script: "this.target.childLayout = this.source ? this.source[0] : undefined", params: ["target", "source"], + immediate: (draggedDocs: Doc[]) => this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined + }]; @undoBatch @action protected drop(e: Event, de: DragManager.DropEvent): boolean { - if (de.data instanceof DragManager.DocumentDragData) { - if (de.data.draggedDocuments.length) { - if (this._currentKey === "Set Template") { - this.props.CollectionView.props.Document.childLayout = de.data.draggedDocuments[0]; - } - if (this._currentKey === "Set Content") { - Doc.GetProto(this.props.CollectionView.props.Document).data = new List(de.data.draggedDocuments); - } - e.stopPropagation(); - return true; - } + if (de.data instanceof DragManager.DocumentDragData && de.data.draggedDocuments.length) { + this.commands.filter(c => c.title === this._currentKey).map(c => c.immediate(de.data.draggedDocuments)); + e.stopPropagation(); } return true; } @@ -317,9 +319,7 @@ export class CollectionViewBaseChrome extends React.Component(); renderSuggestion = (suggestion: string) => { @@ -340,38 +340,19 @@ export class CollectionViewBaseChrome extends React.Component => { - return this._allCommands.filter(c => c.indexOf(value) !== -1); + return this.commands.filter(c => c.title.indexOf(value) !== -1).map(c => c.title); } autoSuggestDown = (e: React.PointerEvent) => { e.stopPropagation(); } + dragCommandDown = (e: React.PointerEvent) => { - let de = new DragManager.DocumentDragData([this.props.CollectionView.props.Document], [undefined]); - DragManager.StartDocumentDrag([this._commandRef.current!], de, e.clientX, e.clientY, { - finishDrag: (dropData: { [id: string]: any }) => { - let bd = Docs.Create.ButtonDocument({ width: 150, height: 50, title: this._currentKey }); - let script = `getProto(target).data = copyField(this.source);`; - let compiled = CompileScript(script, { - params: { doc: Doc.name }, - capturedVariables: { target: this.props.CollectionView.props.Document }, - typecheck: false, - editable: true - }); - if (compiled.compiled) { - let scriptField = new ScriptField(compiled); - bd.onClick = scriptField; - } - dropData.droppedDocuments = [bd]; - }, - handlers: { - dragComplete: action(() => { - }), - }, - hideSource: false - }); - e.preventDefault(); + this.commands.filter(c => c.title === this._currentKey).map(c => + DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title, + { target: this.props.CollectionView.props.Document }, c.params, e.clientX, e.clientY)); e.stopPropagation(); + e.preventDefault(); } render() { @@ -419,7 +400,7 @@ export class CollectionViewBaseChrome extends React.Component
CREATED WITHIN: -
+