From ef94ad7df2a087141ddb8d347d3e3c484ff7609b Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 3 Dec 2019 01:46:36 -0500 Subject: const linter rule and restored google docs push, fixed routing --- src/client/views/ContextMenu.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 5d452e72e..937aff0d6 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -49,8 +49,8 @@ export class ContextMenu extends React.Component { @action onPointerUp = (e: PointerEvent) => { this._mouseDown = false; - let curX = e.clientX; - let curY = e.clientY; + const curX = e.clientX; + const curY = e.clientY; if (this._mouseX !== curX || this._mouseY !== curY) { this._shouldDisplay = false; } @@ -208,7 +208,7 @@ export class ContextMenu extends React.Component { if (!this._display) { return null; } - let style = this._yRelativeToTop ? { left: this.pageX, top: this.pageY } : + const style = this._yRelativeToTop ? { left: this.pageX, top: this.pageY } : { left: this.pageX, bottom: this.pageY }; const contents = ( -- cgit v1.2.3-70-g09d2 From 7c27e6502037caf1aee3eb9e30b4e0572ce095a1 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 29 Jan 2020 17:06:59 -0500 Subject: added custom narrative types. fixed scrolling ambiguity with stackviews. can create metdata from stackingview --- .../apis/google_docs/GooglePhotosClientUtils.ts | 2 +- src/client/util/ClientUtils.ts.temp | 3 + src/client/views/ContextMenu.tsx | 16 ++++- src/client/views/TemplateMenu.tsx | 33 ++++++--- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 3 +- .../CollectionStackingViewFieldColumn.tsx | 24 ++++++- src/client/views/nodes/DocumentView.tsx | 84 +++++++++------------- src/new_fields/RichTextUtils.ts | 4 +- 9 files changed, 104 insertions(+), 67 deletions(-) create mode 100644 src/client/util/ClientUtils.ts.temp (limited to 'src/client/views/ContextMenu.tsx') diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 21cd20e14..7e5d5fe1b 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -340,7 +340,7 @@ export namespace GooglePhotos { const url = data.url.href; const target = Doc.MakeAlias(source); const description = parseDescription(target, descriptionKey); - await DocumentView.makeCustomViewClicked(target, undefined); + await DocumentView.makeCustomViewClicked(target, undefined, Docs.Create.FreeformDocument); media.push({ url, description }); } if (media.length) { diff --git a/src/client/util/ClientUtils.ts.temp b/src/client/util/ClientUtils.ts.temp new file mode 100644 index 000000000..f9fad5ed9 --- /dev/null +++ b/src/client/util/ClientUtils.ts.temp @@ -0,0 +1,3 @@ +export namespace ClientUtils { + export const RELEASE = "mode"; +} \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 937aff0d6..ac803d977 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -77,8 +77,13 @@ export class ContextMenu extends React.Component { @action clearItems() { this._items = []; + this._defaultPrefix = ""; + this._defaultItem = undefined; } + _defaultPrefix: string = ""; + _defaultItem: ((name: string) => void) | undefined; + findByDescription = (target: string, toLowerCase = false) => { return this._items.find(menuItem => { let reference = menuItem.description; @@ -93,6 +98,11 @@ export class ContextMenu extends React.Component { this._items.push(item); } } + @action + setDefaultItem(prefix: string, item: (name: string) => void) { + this._defaultPrefix = prefix; + this._defaultItem = item; + } getItems() { return this._items; @@ -248,7 +258,11 @@ export class ContextMenu extends React.Component { e.preventDefault(); } else if (e.key === "Enter" || e.key === "Tab") { const item = this.flatItems[this.selectedIndex]; - item && item.event({ x: this.pageX, y: this.pageY }); + if (item) { + item.event({ x: this.pageX, y: this.pageY }); + } else if (this._searchString.startsWith(this._defaultPrefix)) { + this._defaultItem?.(this._searchString.substring(this._defaultPrefix.length)); + } this.closeMenu(); e.preventDefault(); } diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index f2ae93b78..b01ca7a41 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -1,6 +1,5 @@ -import { action, observable } from "mobx"; +import { action, observable, runInAction, ObservableSet } from "mobx"; import { observer } from "mobx-react"; -import { DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './TemplateMenu.scss'; @@ -9,8 +8,6 @@ import { Template, Templates } from "./Templates"; import React = require("react"); import { Doc } from "../../new_fields/Doc"; import { StrCast } from "../../new_fields/Types"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faEdit, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -52,11 +49,8 @@ export interface TemplateMenuProps { export class TemplateMenu extends React.Component { @observable private _hidden: boolean = true; - toggleCustom = (e: React.ChangeEvent): void => { - this.props.docs.map(dv => dv.setCustomView(e.target.checked)); - } - toggleNarrative = (e: React.ChangeEvent): void => { - this.props.docs.map(dv => dv.setNarrativeView(e.target.checked)); + toggleLayout = (e: React.ChangeEvent, layout: string): void => { + this.props.docs.map(dv => dv.setCustomView(e.target.checked, layout)); } toggleFloat = (e: React.ChangeEvent): void => { @@ -92,17 +86,34 @@ export class TemplateMenu extends React.Component { }); } + // todo: add brushes to brushMap to save with a style name + onCustomKeypress = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + runInAction(() => TemplateMenu._addedKeys.add(this._customRef.current!.value)); + } + } + componentDidMount() { + !TemplateMenu._addedKeys && (TemplateMenu._addedKeys = new ObservableSet(["narrative"])); + Array.from(Object.keys(Doc.GetProto(this.props.docs[0].props.Document))). + filter(key => key.startsWith("layout_")). + map(key => runInAction(() => TemplateMenu._addedKeys.add(key.replace("layout_", "")))); + } + + static _addedKeys = new ObservableSet(["narrative"]); + _customRef = React.createRef(); render() { const layout = Doc.Layout(this.props.docs[0].Document); const templateMenu: Array = []; this.props.templates.forEach((checked, template) => templateMenu.push()); templateMenu.push(); - templateMenu.push(); - templateMenu.push(); templateMenu.push(); + TemplateMenu._addedKeys && Array.from(TemplateMenu._addedKeys).map(layout => + templateMenu.push( this.toggleLayout(e, layout)} />) + ); return
    {templateMenu} +
; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index e1577cfee..843c743db 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -385,4 +385,4 @@ .rc-switch-checked .rc-switch-inner { left: 8px; } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 41247c1b3..91c7ca76e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -389,6 +389,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
doc) { onScroll={action((e: React.UIEvent) => this._scroll = e.currentTarget.scrollTop)} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} - onWheel={e => e.stopPropagation()} > + onWheel={e => this.props.active() && e.stopPropagation()} > {this.renderedSections} {!this.showAddAGroup ? (null) :
DocListCast(dataDoc[fieldKey]).length).map(fieldKey => + docItems.push({ + description: ":" + fieldKey, event: () => { + const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); + if (created) { + if (this.props.parent.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document); + } + return this.props.parent.props.addDocument(created); + } + }, icon: "compress-arrows-alt" + })); layoutItems.push({ description: ":freeform", event: () => this.props.parent.props.addDocument(Docs.Create.FreeformDocument([], { _width: 200, _height: 200, _LODdisable: true })), icon: "compress-arrows-alt" }); layoutItems.push({ description: ":carousel", event: () => this.props.parent.props.addDocument(Docs.Create.CarouselDocument([], { _width: 400, _height: 200, _LODdisable: true })), icon: "compress-arrows-alt" }); layoutItems.push({ description: ":columns", event: () => this.props.parent.props.addDocument(Docs.Create.MulticolumnDocument([], { _width: 200, _height: 200 })), icon: "compress-arrows-alt" }); @@ -289,6 +301,16 @@ export class CollectionStackingViewFieldColumn extends React.Component { + Doc.GetProto(this.props.parent.props.Document)[name] = ""; + const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true }); + if (created) { + if (this.props.parent.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document); + } + this.props.parent.props.addDocument(created); + } + }); const pt = this.props.screenToLocalTransform().inverse().transformPoint(x, y); ContextMenu.Instance.displayMenu(pt[0], pt[1]); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9e07b51d1..f75184b42 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -9,12 +9,12 @@ import { Id } from '../../../new_fields/FieldSymbols'; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { ImageField } from '../../../new_fields/URLField'; +import { ImageField, PdfField, VideoField, AudioField } from '../../../new_fields/URLField'; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { emptyFunction, returnTransparent, returnTrue, Utils, returnOne } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from "../../DocServer"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { Docs, DocUtils, DocumentOptions } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; import { ClientUtils } from '../../util/ClientUtils'; import { DocumentManager } from "../../util/DocumentManager"; @@ -49,6 +49,7 @@ import { RadialMenu } from './RadialMenu'; import { RadialMenuProps } from './RadialMenuItem'; import { CollectionStackingView } from '../collections/CollectionStackingView'; +import { RichTextField } from '../../../new_fields/RichTextField'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -515,43 +516,45 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } - static makeNativeViewClicked = (doc: Doc) => { - undoBatch(() => doc.layoutKey = "layout")(); + static makeNativeViewClicked = (doc: Doc, prevLayout: string) => { + undoBatch(() => { + if (StrCast(doc.title).endsWith("_" + prevLayout)) doc.title = StrCast(doc.title).replace("_" + prevLayout, ""); + doc.layoutKey = "layout"; + })(); } - static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, name: string = "custom") => { + static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, name: string = "custom") => { const batch = UndoManager.StartBatch("CustomViewClicked"); - const customName = "layout-" + name; + const customName = "layout_" + name; + if (!StrCast(doc.title).endsWith(name)) doc.title = doc.title + "_" + name; if (doc[customName] === undefined) { const _width = NumCast(doc._width); const _height = NumCast(doc._height); const options = { title: "data", _width, x: -_width / 2, y: - _height / 2, }; - let fieldTemplate: Doc; - switch (doc.type) { - case DocumentType.TEXT: - fieldTemplate = Docs.Create.TextDocument("", options); - break; - case DocumentType.PDF: - fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); - break; - case DocumentType.VID: - fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); - break; - case DocumentType.AUDIO: - fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); - break; - default: - fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); + const field = doc.data; + let fieldTemplate: Opt; + if (field instanceof RichTextField || typeof (field) === "string") { + fieldTemplate = Docs.Create.TextDocument("", options); + } else if (field instanceof PdfField) { + fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); + } else if (field instanceof VideoField) { + fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); + } else if (field instanceof AudioField) { + fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); + } else if (field instanceof ImageField) { + fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); } - fieldTemplate.backgroundColor = doc.backgroundColor; - fieldTemplate.heading = 1; - fieldTemplate._autoHeight = true; + if (fieldTemplate) { + fieldTemplate.backgroundColor = doc.backgroundColor; + fieldTemplate.heading = 1; + fieldTemplate._autoHeight = true; + } - const docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); + const docTemplate = creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); - Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); + fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); Doc.ApplyTemplateTo(docTemplate, dataDoc || doc, customName, undefined); } else { doc.layoutKey = customName; @@ -642,29 +645,17 @@ export class DocumentView extends DocComponent(Docu } } - @undoBatch - @action - setNarrativeView = (custom: boolean): void => { - if (custom) { - custom ? DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc, "narrative") : DocumentView.makeNativeViewClicked(this.props.Document); - // this.props.Document.layout_narrative = CollectionView.LayoutString("narrative"); - // this.props.Document.layoutKey = "layout_narrative"; - // this.props.Document._nativeWidth = this.props.Document._nativeHeight = undefined; - // !this.props.Document.narrative && (Doc.GetProto(this.props.Document).narrative = new List([])); - // this.props.Document._viewType = CollectionViewType.Stacking; - // } else { - // DocumentView.makeNativeViewClicked(this.props.Document); - } - } - @undoBatch @action setCustomView = - (custom: boolean): void => { + (custom: boolean, layout: string): void => { if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document); + } else if (custom) { + DocumentView.makeNativeViewClicked(this.props.Document, StrCast(this.props.Document.layoutKey).split("_")[1]); + DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout); } else { - custom ? DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc) : DocumentView.makeNativeViewClicked(this.props.Document); + DocumentView.makeNativeViewClicked(this.props.Document, StrCast(this.props.Document.layoutKey).split("_")[1]); } } @@ -744,11 +735,6 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - if (this.Document.type !== DocumentType.COL && this.Document.type !== DocumentType.TEMPLATE) { - layoutItems.push({ description: "Use Custom Layout", event: () => DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); - } else { - layoutItems.push({ description: "Use Native Layout", event: () => DocumentView.makeNativeViewClicked(this.props.Document), icon: "concierge-bell" }); - } !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); const more = ContextMenu.Instance.findByDescription("More..."); diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 6f34c82db..c50f8cc48 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -274,7 +274,7 @@ export namespace RichTextUtils { const backingDocId = StrCast(textNote[guid]); if (!backingDocId) { const backingDoc = Docs.Create.ImageDocument(src, { _width: 300, _height: 300 }); - DocumentView.makeCustomViewClicked(backingDoc, undefined); + DocumentView.makeCustomViewClicked(backingDoc, undefined, Docs.Create.FreeformDocument); docid = backingDoc[Id]; textNote[guid] = docid; } else { @@ -403,7 +403,7 @@ export namespace RichTextUtils { let exported = (await Cast(linkDoc.anchor2, Doc))!; if (!exported.customLayout) { exported = Doc.MakeAlias(exported); - DocumentView.makeCustomViewClicked(exported, undefined); + DocumentView.makeCustomViewClicked(exported, undefined, Docs.Create.FreeformDocument); linkDoc.anchor2 = exported; } url = Utils.shareUrl(exported[Id]); -- cgit v1.2.3-70-g09d2