From 51eea45ec6ee39cb83ee3b0780ad262b8b8b5dd8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Sep 2020 20:10:58 -0400 Subject: made basic progressivized slides using TreeView --- src/client/documents/Documents.ts | 2 + src/client/util/CurrentUserUtils.ts | 4 ++ src/client/views/EditableView.tsx | 23 ++++++---- src/client/views/PropertiesView.tsx | 2 +- .../views/collections/CollectionTreeView.scss | 13 +++++- .../views/collections/CollectionTreeView.tsx | 49 ++++++++++++++++++---- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 4 ++ .../collections/collectionFreeForm/MarqueeView.tsx | 24 +++++++---- src/client/views/nodes/DocumentView.tsx | 3 -- src/client/views/nodes/PresBox.tsx | 16 ++++--- 11 files changed, 105 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2f7b5a449..f67887c09 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -130,6 +130,7 @@ export interface DocumentOptions { opacity?: number; defaultBackgroundColor?: string; _isBackground?: boolean; + "_isBackground-canClick"?: boolean; // a background document that you can still click on to edit its contents isLinkButton?: boolean; _columnWidth?: number; _fontSize?: string; @@ -195,6 +196,7 @@ export interface DocumentOptions { treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked treeViewTruncateTitleWidth?: number; + treeViewOutlineMode?: boolean; // whether slide should function as a text outline treeViewLockExpandedView?: boolean; // whether the expanded view can be changed treeViewDefaultExpandedView?: string; // default expanded view limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2f08aa928..b3567a4e8 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -418,6 +418,9 @@ export class CurrentUserUtils { doc.emptyPane = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _width: 500, _height: 800, title: "Untitled Tab", system: true, cloneFieldFilter: new List(["system"]) }); ((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0; } + if (doc.emptySlide === undefined) { + doc.emptySlide = Docs.Create.TreeDocument([], { title: "slide", treeViewOutlineMode: true, "_isBackground-canClick": true, _backgroundColor: "transparent", _width: 300, _height: 300, system: true, cloneFieldFilter: new List(["system"]) }); + } if (doc.emptyComparison === undefined) { doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300, system: true, cloneFieldFilter: new List(["system"]) }); } @@ -453,6 +456,7 @@ export class CurrentUserUtils { return [ { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, }, { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true }, + { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc, noviceMode: true }, { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc }, { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true }, { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc }, diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 1b4b9a2be..cbbd78a20 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -18,11 +18,12 @@ export interface EditableProps { * @param value - The string entered by the user to set the value to * @returns `true` if setting the value was successful, `false` otherwise * */ - SetValue(value: string, shiftDown?: boolean): boolean; + SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean; OnFillDown?(value: string): void; OnTab?(shift?: boolean): void; + OnEmpty?(): void; /** * The contents to render when not editing @@ -93,13 +94,17 @@ export class EditableView extends React.Component { switch (e.key) { case "Tab": e.stopPropagation(); - this.finalizeEdit(e.currentTarget.value, e.shiftKey, false); - this.props.OnTab && this.props.OnTab(e.shiftKey); + this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false); + this.props.OnTab?.(e.shiftKey); + break; + case "Backspace": + e.stopPropagation(); + if (!e.currentTarget.value) this.props.OnEmpty?.(); break; case "Enter": e.stopPropagation(); if (!e.ctrlKey) { - this.finalizeEdit(e.currentTarget.value, e.shiftKey, false); + this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); } else if (this.props.OnFillDown) { this.props.OnFillDown(e.currentTarget.value); this._editing = false; @@ -130,10 +135,10 @@ export class EditableView extends React.Component { } @action - private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean) { - if (this.props.SetValue(value, shiftDown)) { + private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { + if (this.props.SetValue(value, shiftDown, enterKey)) { this._editing = false; - this.props.isEditingCallback?.(false); + this.props.isEditingCallback?.(false,); } else { this._editing = false; this.props.isEditingCallback?.(false); @@ -164,7 +169,7 @@ export class EditableView extends React.Component { className: "editableView-input", onKeyDown: this.onKeyDown, autoFocus: true, - onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true), + onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true, false), onPointerDown: this.stopPropagation, onClick: this.stopPropagation, onPointerUp: this.stopPropagation, @@ -178,7 +183,7 @@ export class EditableView extends React.Component { onKeyDown={this.onKeyDown} autoFocus={true} onKeyPress={e => e.stopPropagation()} - onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)} + onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} style={{ display: this.props.display, fontSize: this.props.fontSize, minWidth: 20 }} placeholder={this.props.placeholder} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index d70f4b332..5a9402d70 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1040,7 +1040,7 @@ export class PropertiesView extends React.Component { } {!selectedItem ? (null) :
{ this.openPresProgressivize = !this.openPresProgressivize; })} + onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)} style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>     Progressivize
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index e192f1760..3f437b799 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -30,6 +30,14 @@ padding-left: 0; } + .outline-bullet { + position: relative; + width: 15px; + color: $intermediate-color; + margin-top: 3px; + transform: scale(0.5); + } + .bullet { position: relative; width: 15px; @@ -106,11 +114,14 @@ cursor: pointer; } +.treeViewItem-border-outline, .treeViewItem-border { display: flex; - border-left: dashed 1px #00000042; overflow: hidden; } +.treeViewItem-border{ + border-left: dashed 1px #00000042; +} .treeViewItem-header-editing, .treeViewItem-header { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d2b86d3c6..a6975f517 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -181,22 +181,38 @@ class TreeView extends React.Component { fontStyle={style} fontSize={12} GetValue={() => StrCast(this.doc[key])} - SetValue={undoBatch((value: string) => { - Doc.SetInPlace(this.doc, key, value, false) || true; - Doc.SetInPlace(this.doc, "editTitle", undefined, false); + SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => { + if (this.props.treeView.doc.treeViewOutlineMode && enterKey) { + Doc.SetInPlace(this.doc, key, value, false); + const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + Doc.SetInPlace(this.doc, "editTitle", undefined, false); + Doc.SetInPlace(doc, "editTitle", "*", false); + this.props.addDocument(doc); + doc.context = this.props.treeView.Document; + } else { + Doc.SetInPlace(this.doc, key, value, false) || true; + Doc.SetInPlace(this.doc, "editTitle", undefined, false); + } })} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.doc, key, value, false); - const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); Doc.SetInPlace(this.doc, "editTitle", undefined, false); Doc.SetInPlace(doc, "editTitle", "*", false); - return this.props.addDocument(doc); + const added = this.props.addDocument(doc); + doc.context = this.props.treeView.Document; + return added; })} onClick={() => { SelectionManager.DeselectAll(); Doc.UserDoc().activeSelection = new List([this.doc]); return false; }} + OnEmpty={undoBatch(() => { + if (this.props.treeView.doc.treeViewOutlineMode) { + this.props.removeDoc?.(this.doc); + } + })} OnTab={undoBatch((shift?: boolean) => { shift ? this.props.outdentDocument?.() : this.props.indentDocument?.(); setTimeout(() => Doc.SetInPlace(this.doc, "editTitle", `${this.props.treeView._uniqueId}`, false), 0); @@ -398,13 +414,25 @@ class TreeView extends React.Component { e.stopPropagation(); } + @computed get renderOutlineBullet() { + TraceMobx(); + return
+ {} +
; + } @computed get renderBullet() { TraceMobx(); const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined; return
+ style={{ + color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"), + opacity: checked === "unchecked" ? undefined : 0.4 + }}> {}
; } @@ -521,10 +549,10 @@ class TreeView extends React.Component { } }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> - {this.renderBullet} + {this.props.treeView.props.Document.treeViewOutlineMode ? this.renderOutlineBullet : this.renderBullet} {this.renderTitle}
-
+
{!this.treeViewOpen || this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? (null) : this.renderContent}
@@ -617,6 +645,7 @@ class TreeView extends React.Component { Doc.AddDocToList(docs[i - 1], fieldKey, child); docs[i - 1].treeViewOpen = true; remove(child); + child.context = treeView.Document; } } }; @@ -627,6 +656,7 @@ class TreeView extends React.Component { Doc.AddDocToList(parentCollectionDoc, fieldKey, child, parentPrevSibling, false); parentCollectionDoc.treeViewOpen = true; remove(child); + child.context = treeView.Document; } }; const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => { @@ -729,8 +759,11 @@ export class CollectionTreeView extends CollectionSubView doAddDoc(doc)); + } else if (relativeTo === undefined) { + this.props.addDocument(doc); } else { doAddDoc(doc); + (doc instanceof Doc ? [doc] : doc).forEach(d => d.context = this.props.Document); } return true; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 6939399e6..7084aba40 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -391,7 +391,7 @@ export class CollectionView extends Touchable diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 5ace82b3c..aa1852250 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -146,6 +146,10 @@ export class TabDocView extends React.Component { CollectionDockingView.AddSplit(curPres, "right"); } DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null)); + setTimeout(() => { + curPres._itemIndex = DocListCast(curPres.data).length - 1; + doc.treeViewOutlineMode && PresBox.Instance.progressivizeChild(null as any); + }, 100); } } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index deb7e68e8..ebad3bf45 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -116,15 +116,23 @@ export class MarqueeView extends React.Component { + // const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + // if (ns.length === 1 && text.startsWith("http")) { + // this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer + // } else { + // this.pasteTable(ns, x, y); + // } + // }); + // e.stopPropagation(); + e.preventDefault(); - navigator.clipboard.readText().then(text => { - const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); - if (ns.length === 1 && text.startsWith("http")) { - this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer - } else { - this.pasteTable(ns, x, y); - } - }); + const slide = Doc.copyDragFactory(Doc.UserDoc().emptySlide as Doc)!; + slide.x = x; + slide.y = y; + this.props.addDocument(slide); + setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false)); e.stopPropagation(); } else if (!e.ctrlKey && !e.metaKey) { FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : ""; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7ef5eaf54..7b7c3578b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -593,9 +593,6 @@ export class DocumentView extends DocComponent(Docu if (CurrentUserUtils.ActiveDashboard === this.props.Document) { alert("Can't delete the active dashboard"); } else { - const selected = SelectionManager.SelectedDocuments().slice(); - SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); this.props.removeDocument?.(this.props.Document); } } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 99fb5d2ce..79f1b7ddc 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -1258,7 +1258,7 @@ export class PresBox extends ViewBoxBaseComponent
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
{this.stringType} selected -
+
Contents
Edit
@@ -1435,18 +1435,22 @@ export class PresBox extends ViewBoxBaseComponent } @action - progressivizeChild = (e: React.MouseEvent) => { - e.stopPropagation(); + progressivizeChild = (e?: React.MouseEvent) => { + e?.stopPropagation(); const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); if (!activeItem.presProgressivize) { targetDoc.editing = false; activeItem.presProgressivize = true; targetDoc.presProgressivize = true; targetDoc._currentFrame = 0; - docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true)); - targetDoc.lastFrame = docs.length - 1; + let count = 0; + const setupProgressivize = (doc: Doc) => { + CollectionFreeFormDocumentView.setupKeyframes([doc], count++, true); + targetDoc.treeViewOutlineMode && DocListCast(doc[Doc.LayoutFieldKey(doc)]).forEach(d => setupProgressivize(d)); + } + setupProgressivize(targetDoc); + targetDoc.lastFrame = count; } else { targetDoc.editProgressivize = false; activeItem.presProgressivize = false; -- cgit v1.2.3-70-g09d2