From f6b542b9ab015483393c605db60683c3883c3a39 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 11:26:01 -0400 Subject: prevent users from deleting the activeWorspace with 'delete' menu item --- src/client/views/nodes/DocumentView.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 345ca479f..9c8c05176 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -576,7 +576,14 @@ export class DocumentView extends DocComponent(Docu } @undoBatch - deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); } + deleteClicked = (): void => { + if (Doc.UserDoc().activeWorkspace === this.props.Document) { + alert("Can't delete the active workspace"); + } else { + SelectionManager.DeselectAll(); + this.props.removeDocument?.(this.props.Document); + } + } @undoBatch -- cgit v1.2.3-70-g09d2 From b4b1a14f442bdfd41f79c67a6545335e43f85f2f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 11:37:47 -0400 Subject: fixed onClick events for text. --- src/client/views/nodes/DocumentView.tsx | 8 -------- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 5 +---- 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9c8c05176..71cb18e08 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -323,20 +323,12 @@ export class DocumentView extends DocComponent(Docu const alias = Doc.MakeAlias(this.props.Document); DocUtils.makeCustomViewClicked(alias, undefined, "onClick"); this.props.addDocTab(alias, "onRight"); - // UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); - //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { - // if (this.props.Document.type === DocumentType.RTF) { - // DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; - // DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; - - // this.props.focus(this.props.Document, false); - // } SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey); } preventDefault = false; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f45a86b56..86757296e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1066,12 +1066,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; } (e.nativeEvent as any).formattedHandled = true; - if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientX - this._downX) < 4) { - this.props.select(e.ctrlKey); - this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); - } if (this.props.isSelected(true)) { // if text box is selected, then it consumes all click events e.stopPropagation(); + this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); } } -- cgit v1.2.3-70-g09d2 From d7dbc15ecc211ab9533c0cffa40227523b6a5831 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 22 Jun 2020 21:07:45 -0400 Subject: made chrome commands fire by clicking bullseye. added commands for freeformview. made backgroundHalo() work diffrently for ink strokes --- src/client/views/InkingStroke.tsx | 4 +- .../views/collections/CollectionViewChromes.tsx | 32 ++++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 76 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 1 - .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/FieldView.tsx | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 8 files changed, 68 insertions(+), 51 deletions(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 7e3bd1c17..cdabd213b 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import { documentSchema } from "../../fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../fields/InkField"; import { makeInterface } from "../../fields/Schema"; -import { Cast, StrCast } from "../../fields/Types"; +import { Cast, StrCast, BoolCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { InteractionUtils } from "../util/InteractionUtils"; @@ -54,7 +54,7 @@ export class InkingStroke extends ViewBoxBaseComponent 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15), StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 52fb63386..ac7136d4d 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -40,28 +40,41 @@ export class CollectionViewBaseChrome extends React.Component item view", script: "this.target.childLayout = getDocTemplate(this.source?.[0])", - immediate: (source: Doc[]) => this.target.childLayout = Doc.getDocTemplate(source?.[0]), + immediate: undoBatch((source: Doc[]) => source.length && (this.target.childLayout = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _narrativeCommand = { params: ["target", "source"], title: "=> child click view", script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])", - immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]), + immediate: undoBatch((source: Doc[]) => source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _contentCommand = { - params: ["target", "source"], title: "=> content", + params: ["target", "source"], title: "=> clear content", script: "getProto(this.target).data = copyField(this.source);", - immediate: (source: Doc[]) => Doc.GetProto(this.target).data = new List(source), // Doc.aliasDocs(source), + immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List(source)), // Doc.aliasDocs(source), initialize: emptyFunction, }; _viewCommand = { - params: ["target"], title: "=> saved view", + params: ["target"], title: "=> reset view", script: "this.target._panX = this.restoredPanX; this.target._panY = this.restoredPanY; this.target.scale = this.restoredScale;", - immediate: (source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target.scale = 1; }, + immediate: undoBatch((source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target.scale = 1; }), initialize: (button: Doc) => { button.restoredPanX = this.target._panX; button.restoredPanY = this.target._panY; button.restoredScale = this.target.scale; }, }; - _freeform_commands = [this._contentCommand, this._templateCommand, this._narrativeCommand, this._viewCommand]; + _clusterCommand = { + params: ["target"], title: "=> fit content", + script: "this.target._fitToBox = !this.target._fitToBox;", + immediate: undoBatch((source: Doc[]) => this.target._fitToBox = !this.target._fitToBox), + initialize: emptyFunction + }; + _fitContentCommand = { + params: ["target"], title: "=> toggle clusters", + script: "this.target.useClusters = !this.target.useClusters;", + immediate: undoBatch((source: Doc[]) => this.target.useClusters = !this.target.useClusters), + initialize: emptyFunction + }; + + _freeform_commands = [this._viewCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; _stacking_commands = [this._contentCommand, this._templateCommand]; _masonry_commands = [this._contentCommand, this._templateCommand]; _schema_commands = [this._templateCommand, this._narrativeCommand]; @@ -84,6 +97,7 @@ export class CollectionViewBaseChrome extends React.Component { + this._currentKey = this._currentKey || (this._buttonizableCommands.length ? this._buttonizableCommands[0]?.title : ""); // chrome status is one of disabled, collapsed, or visible. this determines initial state from document switch (this.props.CollectionView.props.Document._chromeStatus) { case "disabled": @@ -248,7 +262,9 @@ export class CollectionViewBaseChrome extends React.Component { + this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate([])); + }); } @computed get templateChrome() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 960b6efef..ac1456970 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1128,6 +1128,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.annotationsKey) return; - !this.props.isAnnotationOverlay && ContextMenu.Instance.addItem({ - description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; - }), icon: this._timelineVisible ? faEyeSlash : faEye - }); - const appearance = ContextMenu.Instance.findByDescription("Appearance..."); const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : []; appearanceItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); appearanceItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); appearanceItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); - appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)!._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); + appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" }); const options = ContextMenu.Instance.findByDescription("Options..."); const optionItems = options && "subitems" in options ? options.subitems : []; - optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }); - !Doc.UserDoc().noviceMode && optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); - this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); + !this.props.isAnnotationOverlay && + optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: faEye }); + this.props.ContainingCollectionView && + optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); + optionItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " snap lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }); optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); - !Doc.UserDoc().noviceMode && optionItems.push({ - description: "Import document", icon: "upload", event: ({ x, y }) => { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".zip"; - input.onchange = async _e => { - const upload = Utils.prepend("/uploadDoc"); - const formData = new FormData(); - const file = input.files && input.files[0]; - if (file) { - formData.append('file', file); - formData.append('remap', "true"); - const response = await fetch(upload, { method: "POST", body: formData }); - const json = await response.json(); - if (json !== "error") { - const doc = await DocServer.GetRefField(json); - if (doc instanceof Doc) { - const [xx, yy] = this.props.ScreenToLocalTransform().transformPoint(x, y); - doc.x = xx, doc.y = yy; - this.props.addDocument?.(doc); + if (!Doc.UserDoc().noviceMode) { + optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); + optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + optionItems.push({ + description: "Import document", icon: "upload", event: ({ x, y }) => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".zip"; + input.onchange = async _e => { + const upload = Utils.prepend("/uploadDoc"); + const formData = new FormData(); + const file = input.files && input.files[0]; + if (file) { + formData.append('file', file); + formData.append('remap', "true"); + const response = await fetch(upload, { method: "POST", body: formData }); + const json = await response.json(); + if (json !== "error") { + const doc = await DocServer.GetRefField(json); + if (doc instanceof Doc) { + const [xx, yy] = this.props.ScreenToLocalTransform().transformPoint(x, y); + doc.x = xx, doc.y = yy; + this.props.addDocument?.(doc); + } } } - } - }; - input.click(); - } - }); - !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + }; + input.click(); + } + }); + } !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); } - @observable _timelineVisible = false; + @observable showTimeline = false; intersectRect(r1: { left: number, top: number, width: number, height: number }, r2: { left: number, top: number, width: number, height: number }) { @@ -1350,7 +1350,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.children} - {this._timelineVisible ? : (null)} + {this.showTimeline ? : (null)} ; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 23efeec8d..1bc7c6fb5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -741,7 +741,6 @@ export class MarqueeView extends React.Component e.preventDefault()} - onPaste={this.paste} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f934945a6..404d69730 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -144,7 +144,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu LayoutTemplate={this.props.LayoutTemplate} makeLink={this.makeLink} rootSelected={this.rootSelected} + backgroundHalo={this.props.backgroundHalo} dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} LibraryPath={this.props.LibraryPath} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 305c04a90..c57738361 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -27,6 +27,7 @@ export interface FieldViewProps { LibraryPath: Doc[]; onClick?: ScriptField; dropAction: dropActionType; + backgroundHalo?: () => boolean; docFilters: () => string[]; isSelected: (outsideReaction?: boolean) => boolean; select: (isCtrlPressed: boolean) => void; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 5e0585169..2a019ada7 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -452,7 +452,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp appearanceItems.push({ description: "Convert to be a template style", event: () => { if (!this.layoutDoc.isTemplateDoc) { - const title = StrCast(this.rootDoc.title) + const title = StrCast(this.rootDoc.title); this.rootDoc.title = "text"; this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc, true, title); } else { -- cgit v1.2.3-70-g09d2