diff options
22 files changed, 209 insertions, 159 deletions
diff --git a/solr-8.3.1/server/solr/dash/core.properties b/solr-8.3.1/server/solr/dash/core.properties index 0912a8303..70081ebc6 100644 --- a/solr-8.3.1/server/solr/dash/core.properties +++ b/solr-8.3.1/server/solr/dash/core.properties @@ -1,5 +1,5 @@ #Written by CorePropertiesLocator -#Wed Jan 08 14:44:34 UTC 2020 +#Wed Jan 29 14:30:24 UTC 2020 name=dash config=solrconfig.xml schema=schema.xml diff --git a/src/client/util/ClientUtils.ts.temp b/src/client/util/ClientUtils.ts.temp deleted file mode 100644 index f9fad5ed9..000000000 --- a/src/client/util/ClientUtils.ts.temp +++ /dev/null @@ -1,3 +0,0 @@ -export namespace ClientUtils { - export const RELEASE = "mode"; -}
\ No newline at end of file diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 8c9e5e263..f14e09a40 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -695,7 +695,7 @@ export class DashDocCommentView { e.stopPropagation(); }; this._collapsed.onpointerenter = (e: any) => { - DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); + DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc, false)); e.preventDefault(); e.stopPropagation(); }; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 4441356dc..6abb7108f 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,27 +1,28 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, runInAction, computed } from "mobx"; +import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Id } from '../../new_fields/FieldSymbols'; import { RichTextField } from '../../new_fields/RichTextField'; -import { NumCast, StrCast, Cast } from "../../new_fields/Types"; +import { NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; -import { DragManager } from "../util/DragManager"; +import RichTextMenu from '../util/RichTextMenu'; import { UndoManager } from "../util/UndoManager"; -import './DocumentButtonBar.scss'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { ParentDocSelector } from './collections/ParentDocumentSelector'; import './collections/ParentDocumentSelector.scss'; +import './DocumentButtonBar.scss'; import { LinkMenu } from "./linking/LinkMenu"; -import { FormattedTextBox, GoogleRef } from "./nodes/FormattedTextBox"; +import { DocumentView } from './nodes/DocumentView'; +import { GoogleRef } from "./nodes/FormattedTextBox"; import { TemplateMenu } from "./TemplateMenu"; import { Template, Templates } from "./Templates"; import React = require("react"); -import { DocumentView } from './nodes/DocumentView'; -import { ParentDocSelector } from './collections/ParentDocumentSelector'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import RichTextMenu from '../util/RichTextMenu'; -import { Id } from '../../new_fields/FieldSymbols'; +import { DragManager } from '../util/DragManager'; +import { MetadataEntryMenu } from './MetadataEntryMenu'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -43,6 +44,7 @@ const fetch: IconProp = "sync-alt"; @observer export class DocumentButtonBar extends React.Component<{ views: (DocumentView | undefined)[], stack?: any }, {}> { private _linkButton = React.createRef<HTMLDivElement>(); + private _dragRef = React.createRef<HTMLDivElement>(); private _downX = 0; private _downY = 0; private _pullAnimating = false; @@ -201,7 +203,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | const view0 = this.view0; const linkCount = view0 && DocListCast(view0.props.Document.links).length; return !view0 ? (null) : <div title="Drag(create link) Tap(view links)" className="documentButtonBar-linkFlyout" ref={this._linkButton}> - <Flyout anchorPoint={anchorPoints.RIGHT_TOP} + <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={<LinkMenu docView={view0} addDocTab={view0.props.addDocTab} changeFlyout={emptyFunction} />}> <div className={"documentButtonBar-linkButton-" + (linkCount ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} > {linkCount ? linkCount : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />} @@ -211,6 +213,19 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | } @computed + get metadataButton() { + const view0 = this.view0; + return !view0 ? (null) : <div title="Show metadata panel" className="documentButtonBar-linkFlyout" ref={this._linkButton}> + <Flyout anchorPoint={anchorPoints.LEFT_TOP} + content={<MetadataEntryMenu docs={() => this.props.views.filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}> + <div className={"documentButtonBar-linkButton-" + "empty"} > + {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />} + </div> + </Flyout> + </div>; + } + + @computed get contextButton() { return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, data, where) => { where === "onRight" ? CollectionDockingView.AddRightSplit(doc, data) : @@ -220,11 +235,61 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | }} />; } - render() { - if (!this.view0) return (null); + private _downx = 0; + private _downy = 0; + onAliasButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + e.stopPropagation(); + } + + onAliasButtonDown = (e: React.PointerEvent): void => { + this._downx = e.clientX; + this._downy = e.clientY; + e.stopPropagation(); + e.preventDefault(); + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.addEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + document.addEventListener("pointerup", this.onAliasButtonUp); + } + onAliasButtonMoved = (e: PointerEvent): void => { + if (this._dragRef.current !== null && (Math.abs(e.clientX - this._downx) > 4 || Math.abs(e.clientY - this._downy) > 4)) { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + + const dragDocView = this.props.views[0]!; + const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); + const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + dragData.embedDoc = true; + dragData.dropAction = "alias"; + DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { + offsetX: dragData.offset[0], + offsetY: dragData.offset[1], + hideSource: false + }); + } + e.stopPropagation(); + } + + @computed + get templateButton() { + const view0 = this.view0; const templates: Map<Template, boolean> = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("show" + template.Name) ? true : false, false as boolean))); + return !view0 ? (null) : <div title="Customize layout" className="documentButtonBar-linkFlyout" ref={this._dragRef}> + <Flyout anchorPoint={anchorPoints.LEFT_TOP} + content={<TemplateMenu docs={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}> + <div className={"documentButtonBar-linkButton-" + "empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} > + {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />} + </div> + </Flyout> + </div>; + } + + render() { + if (!this.view0) return (null); const isText = this.view0.props.Document.data instanceof RichTextField; // bcz: Todo - can't assume layout is using the 'data' field. need to add fieldKey to DocumentView const considerPull = isText && this.considerGoogleDocsPull; @@ -234,7 +299,13 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | {this.linkButton} </div> <div className="documentButtonBar-button"> - <TemplateMenu docs={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} /> + {this.templateButton} + </div> + <div className="documentButtonBar-button"> + {this.metadataButton} + </div> + <div className="documentButtonBar-button"> + {this.contextButton} </div> <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}> {this.considerGoogleDocsPush} @@ -242,7 +313,6 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | <div className="documentButtonBar-button" style={{ display: !considerPull ? "none" : "" }}> {this.considerGoogleDocsPull} </div> - {this.contextButton} </div>; } }
\ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2297c2bb3..87a81504c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { - faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, + faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp, faClipboard } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -131,6 +131,8 @@ export class MainView extends React.Component { library.add(faLongArrowAltRight); library.add(faCheck); library.add(faCaretUp); + library.add(faFilter); + library.add(faBullseye); library.add(faArrowDown); library.add(faArrowUp); library.add(faCloudUploadAlt); diff --git a/src/client/views/MetadataEntryMenu.scss b/src/client/views/MetadataEntryMenu.scss index 7da55fd1c..5f4a52c0c 100644 --- a/src/client/views/MetadataEntryMenu.scss +++ b/src/client/views/MetadataEntryMenu.scss @@ -8,6 +8,10 @@ } } +#metadataEntry-outer { + overflow: auto !important; +} + .metadataEntry-keys { max-height: 80; overflow-y: auto; diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index 22259e509..23b21ae0c 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -196,7 +196,7 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{ _ref = React.createRef<HTMLInputElement>(); render() { return ( - <div className="metadataEntry-outerDiv"> + <div className="metadataEntry-outerDiv" id="metadataEntry-outer"> <div className="metadataEntry-inputArea"> Key: <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange }} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 92987bde0..f2ae93b78 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -51,9 +51,6 @@ export interface TemplateMenuProps { @observer export class TemplateMenu extends React.Component<TemplateMenuProps> { @observable private _hidden: boolean = true; - private _downx = 0; - private _downy = 0; - private _dragRef = React.createRef<HTMLUListElement>(); toggleCustom = (e: React.ChangeEvent<HTMLInputElement>): void => { this.props.docs.map(dv => dv.setCustomView(e.target.checked)); @@ -81,19 +78,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { } } - @undoBatch - @action - clearTemplates = (event: React.MouseEvent) => { - Templates.TemplateList.forEach(template => this.props.docs.forEach(d => d.Document["show" + template.Name] = undefined)); - ["backgroundColor", "borderRounding", "width", "height"].forEach(field => this.props.docs.forEach(d => { - if (d.Document.isTemplateDoc && d.props.DataDoc) { - d.Document[field] = undefined; - } else if (d.Document["default" + field[0].toUpperCase() + field.slice(1)] !== undefined) { - d.Document[field] = Doc.GetProto(d.Document)[field] = undefined; - } - })); - } - @action toggleTemplateActivity = (): void => { this._hidden = !this._hidden; @@ -107,40 +91,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : "enabled"); }); } - onAliasButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - e.stopPropagation(); - } - - onAliasButtonDown = (e: React.PointerEvent): void => { - this._downx = e.clientX; - this._downy = e.clientY; - e.stopPropagation(); - e.preventDefault(); - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.addEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - document.addEventListener("pointerup", this.onAliasButtonUp); - } - onAliasButtonMoved = (e: PointerEvent): void => { - if (this._dragRef.current !== null && (Math.abs(e.clientX - this._downx) > 4 || Math.abs(e.clientY - this._downy) > 4)) { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - - const dragDocView = this.props.docs[0]; - const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); - const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - dragData.embedDoc = true; - dragData.dropAction = "alias"; - DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { - offsetX: dragData.offset[0], - offsetY: dragData.offset[1], - hideSource: false - }); - } - e.stopPropagation(); - } render() { const layout = Doc.Layout(this.props.docs[0].Document); @@ -151,18 +101,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { templateMenu.push(<OtherToggle key={"custom"} name={"Custom"} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") !== "layout"} toggle={this.toggleCustom} />); templateMenu.push(<OtherToggle key={"narrative"} name={"Narrative"} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") === "layout_narrative"} toggle={this.toggleNarrative} />); templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />); - return ( - <div className="templating-button" onPointerDown={this.onAliasButtonDown} title="Drag:(create alias). Tap:(modify layout)." > - <Flyout anchorPoint={anchorPoints.LEFT_TOP} - content={<ul className="template-list" ref={this._dragRef} style={{ display: "block" }}> - {templateMenu} - {<button onClick={this.clearTemplates}>Restore Defaults</button>} - </ul>}> - <span className="parentDocumentSelector-button" > - <FontAwesomeIcon icon={faEdit} size={"sm"} /> - </span> - </Flyout> - </div> - ); + return <ul className="template-list" style={{ display: "block" }}> + {templateMenu} + </ul>; } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 160279efd..82cb3bc88 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -645,7 +645,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { if (curPres) { const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); Doc.GetProto(pinDoc).presentationTargetDoc = doc; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title.toString()'); + Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title?.toString()'); const data = Cast(curPres.data, listSpec(Doc)); if (data) { data.push(pinDoc); diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 6de20593b..440b6856b 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -110,7 +110,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { </div> ); return !facetCollection ? (null) : - <div className="collectionPivotView"> + <div className="collectionPivotView" style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}> <div className={"pivotKeyEntry"}> <EditableView contents={this.props.Document.pivotField} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 65d421c52..8679c8bd1 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -52,9 +52,9 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; private _childLayoutDisposer?: IReactionDisposer; protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view - this.dropDisposer && this.dropDisposer(); - this.gestureDisposer && this.gestureDisposer(); - this.multiTouchDisposer && this.multiTouchDisposer(); + this.dropDisposer?.(); + this.gestureDisposer?.(); + this.multiTouchDisposer?.(); if (ele) { this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 395eed372..a7733ab5f 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -645,10 +645,12 @@ export class CollectionTreeView extends CollectionSubView(Document) { const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif"; const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "short_description" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`; + const textDoc = TextDocument("", { title: "details", _autoHeight: true }); const detailedLayout = Docs.Create.StackingDocument([ CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), - TextDocument("", { title: "details", _autoHeight: true, _textTemplate: new RichTextField(detailedTemplate, "short_description year company") }) + textDoc, ], { _chromeStatus: "disabled", title: "detailed layout stack" }); + textDoc.data = new RichTextField(detailedTemplate, "short_description year company"); detailedLayout.isTemplateDoc = makeTemplate(detailedLayout); const cardLayout = ImageDocument(fallbackImg, { title: "cardLayout", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work? diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 64411b5fe..efe185922 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -20,7 +20,7 @@ .collectionViewBaseChrome-viewPicker { font-size: 75%; - text-transform: uppercase; + //text-transform: uppercase; letter-spacing: 2px; background: rgb(238, 238, 238); color: grey; @@ -34,6 +34,26 @@ outline-color: black; } + .collectionViewBaseChrome-cmdPicker { + margin-left: 3px; + margin-right: 0px; + background: rgb(238, 238, 238); + border: none; + color: grey; + } + .commandEntry-outerDiv { + pointer-events: all; + background-color: gray; + display: flex; + flex-direction: row; + .commandEntry-drop { + color:white; + width:25px; + margin-top: auto; + margin-bottom: auto; + } + } + .collectionViewBaseChrome-collapse { transition: all .5s, opacity 0.3s; position: absolute; @@ -53,6 +73,18 @@ .collectionViewBaseChrome-viewSpecs { margin-left: 10px; display: grid; + + .collectionViewBaseChrome-filterIcon { + position: relative; + display: flex; + margin: auto; + background: gray; + color: white; + width: 40px; + height: 40px; + align-items: center; + justify-content: center; + } .collectionViewBaseChrome-viewSpecsInput { padding: 12px 10px 11px 10px; @@ -240,7 +272,6 @@ .commandEntry-outerDiv { display: flex; flex-direction: column; - width: 165px; height: 40px; } .commandEntry-inputArea { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index e09f90e2c..d1919d588 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -39,25 +39,24 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\) _templateCommand = { - title: "set template", script: "setChildLayout(this.target, this.source?.[0])", params: ["target", "source"], + title: "=> item view", script: "setChildLayout(this.target, this.source?.[0])", params: ["target", "source"], initialize: emptyFunction, immediate: (draggedDocs: Doc[]) => Doc.setChildLayout(this.props.CollectionView.props.Document, draggedDocs.length ? draggedDocs[0] : undefined) }; _narrativeCommand = { - title: "set detailed template", script: "setChildLayout(this.target, this.source?.[0])", params: ["target", "source"], + title: "=> click item view", script: "setChildDetailedLayout(this.target, this.source?.[0])", params: ["target", "source"], initialize: emptyFunction, - immediate: (draggedDocs: Doc[]) => Doc.setChildDetailed(this.props.CollectionView.props.Document, draggedDocs.length ? draggedDocs[0] : undefined) + immediate: (draggedDocs: Doc[]) => Doc.setChildDetailedLayout(this.props.CollectionView.props.Document, draggedDocs.length ? draggedDocs[0] : undefined) }; _contentCommand = { - // title: "set content", script: "getProto(this.target).data = aliasDocs(this.source.map(async p => 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"], + title: "=> content", script: "getProto(this.target).data = aliasDocs(this.source);", params: ["target", "source"], initialize: emptyFunction, immediate: (draggedDocs: Doc[]) => Doc.GetProto(this.props.CollectionView.props.Document).data = new List<Doc>(draggedDocs.map((d: any) => Doc.MakeAlias(d))) }; _viewCommand = { - title: "restore view", script: "this.target._panX = this.restoredPanX; this.target._panY = this.restoredPanY; this.target.scale = this.restoredScale;", params: ["target"], + title: "=> saved view", script: "this.target._panX = this.restoredPanX; this.target._panY = this.restoredPanY; this.target.scale = this.restoredScale;", params: ["target"], + initialize: (button: Doc) => { button.restoredPanX = this.props.CollectionView.props.Document._panX; button.restoredPanY = this.props.CollectionView.props.Document._panY; button.restoredScale = this.props.CollectionView.props.Document.scale; }, immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document._panX = 0; this.props.CollectionView.props.Document._panY = 0; this.props.CollectionView.props.Document.scale = 1; }, - initialize: (button: Doc) => { button.restoredPanX = this.props.CollectionView.props.Document._panX; button.restoredPanY = this.props.CollectionView.props.Document._panY; button.restoredScale = this.props.CollectionView.props.Document.scale; } }; _freeform_commands = [this._contentCommand, this._templateCommand, this._narrativeCommand, this._viewCommand]; _stacking_commands = [this._contentCommand, this._templateCommand]; @@ -153,21 +152,32 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro this.props.CollectionView.props.Document._viewType = parseInt(e.target.selectedOptions[0].value); } + commandChanged = (e: React.ChangeEvent) => { + //@ts-ignore + runInAction(() => this._currentKey = e.target.selectedOptions[0].value); + } + @action openViewSpecs = (e: React.SyntheticEvent) => { - this._viewSpecsOpen = true; + if (this._viewSpecsOpen) this.closeViewSpecs(); + else { + this._viewSpecsOpen = true; - //@ts-ignore - if (!e.target.classList[0].startsWith("qs")) { - this.closeDatePicker(); - } + //@ts-ignore + if (!e.target?.classList[0]?.startsWith("qs")) { + this.closeDatePicker(); + } - e.stopPropagation(); - document.removeEventListener("pointerdown", this.closeViewSpecs); - document.addEventListener("pointerdown", this.closeViewSpecs); + e.stopPropagation(); + document.removeEventListener("pointerdown", this.closeViewSpecs); + document.addEventListener("pointerdown", this.closeViewSpecs); + } } - @action closeViewSpecs = () => { this._viewSpecsOpen = false; document.removeEventListener("pointerdown", this.closeViewSpecs); }; + @action closeViewSpecs = () => { + this._viewSpecsOpen = false; + document.removeEventListener("pointerdown", this.closeViewSpecs); + }; @action openDatePicker = (e: React.PointerEvent) => { @@ -399,23 +409,20 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro onPointerDown={stopPropagation} onChange={this.viewChanged} value={NumCast(this.props.CollectionView.props.Document._viewType)}> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="1">Freeform View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="2">Schema View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="4">Tree View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="5">Stacking View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="7">Multicolumn View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="8">Pivot View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="9">Carousel View</option> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="10">Linear View</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="1">Freeform</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="2">schema</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="4">Tree</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="5">Stacking</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="7">Multicolumn</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="8">Pivot</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="9">Carousel</option> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="10">Linear</option> </select> - <div className="collectionViewBaseChrome-viewSpecs" style={{ display: collapsed ? "none" : "grid" }}> - <input className="collectionViewBaseChrome-viewSpecsInput" - placeholder="FILTER" - value={this.filterValue ? this.filterValue.script.originalScript === "return true" ? "" : this.filterValue.script.originalScript : ""} - onChange={(e) => { }} - onPointerDown={this.openViewSpecs} /> - {this.getPivotInput()} + <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}> + <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.openViewSpecs} > + <FontAwesomeIcon icon="filter" size="2x" /> + </div> <div className="collectionViewBaseChrome-viewSpecsMenu" onPointerDown={this.openViewSpecs} style={{ @@ -456,17 +463,20 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro </div> </div> <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} > - <div className="commandEntry-outerDiv" ref={this._commandRef} onPointerDown={this.dragCommandDown}> - <div className="commandEntry-inputArea" onPointerDown={this.autoSuggestDown} > - <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange }} - getSuggestionValue={this.getSuggestionValue} - suggestions={this.suggestions} - alwaysRenderSuggestions={true} - renderSuggestion={this.renderSuggestion} - onSuggestionsFetchRequested={this.onSuggestionFetch} - onSuggestionsClearRequested={this.onSuggestionClear} - ref={this._autosuggestRef} /> + <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}> + <div className="commandEntry-drop"> + <FontAwesomeIcon icon="bullseye" size="2x"></FontAwesomeIcon> </div> + <select + className="collectionViewBaseChrome-cmdPicker" + onPointerDown={stopPropagation} + onChange={this.commandChanged} + value={this._currentKey}> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""}>{""}</option> + {this._buttonizableCommands.map(cmd => + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option> + )} + </select> </div> </div> </div> diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 18f1baf44..115f8d633 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -64,22 +64,13 @@ export class SelectorContextMenu extends React.Component<SelectorProps> { this.props.addDocTab(col, undefined, "inTab"); // bcz: dataDoc? }; } - get metadataMenu() { - return <div className="parentDocumentSelector-metadata"> - <Flyout anchorPoint={anchorPoints.TOP_LEFT} - content={<MetadataEntryMenu docs={() => this.props.Views.map(dv => dv.props.Document)} suggestWithFunction />}>{/* tfs: @bcz This might need to be the data document? */} - <div className="docDecs-tagButton" title="Add fields"><FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" /></div> - </Flyout> - </div>; - } render() { return <div > - <div key="metadata">Metadata: {this.metadataMenu}</div> <p key="contexts">Contexts:</p> {this._docs.map(doc => <p key={doc.col[Id] + doc.target[Id]}><a onClick={this.getOnClick(doc)}>{doc.col.title?.toString()}</a></p>)} {this._otherDocs.length ? <hr key="hr" /> : null} - {this._otherDocs.map(doc => <p key="p"><a onClick={this.getOnClick(doc)}>{doc.col.title?.toString()}</a></p>)} + {this._otherDocs.map(doc => <p key={"p" + doc.col[Id] + doc.target[Id]}><a onClick={this.getOnClick(doc)}>{doc.col.title?.toString()}</a></p>)} </div>; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index bac968165..20d20f1f6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -653,7 +653,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!init) { state.initializers![this.Document[Id]] = { panX: this.Document._panX, panY: this.Document._panY }; HistoryUtil.pushState(state); - } else if (init.panX !== this.Document.panX || init.panY !== this.Document.panY) { + } else if (init.panX !== this.Document._panX || init.panY !== this.Document._panY) { init.panX = this.Document._panX; init.panY = this.Document._panY; HistoryUtil.pushState(state); @@ -899,7 +899,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 87b2a9729..041eb69da 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -249,7 +249,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu render(): JSX.Element { return ( - <div className={"collectionMulticolumnView_contents"} ref={this.createDashEventsTarget} b > + <div className={"collectionMulticolumnView_contents"} ref={this.createDashEventsTarget}> {this.contents} </div> ); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3244b7d3e..2183129cf 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -60,8 +60,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF componentWillUnmount() { this._disposer?.(); } componentDidMount() { - this._disposer = reaction(() => Array.from(Cast(this.props.Document?.animateToPos, listSpec("number"), null)), - target => this._animPos = !target ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : + this._disposer = reaction(() => Array.from(Cast(this.props.Document?.animateToPos, listSpec("number"), null) || []), + target => this._animPos = !target || !target?.length ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]), { fireImmediately: true }); } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index eda12d6fb..428e9aa7b 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -44,7 +44,7 @@ export class PresBox extends React.Component<FieldViewProps> { if (item instanceof Doc && item.type !== DocumentType.PRESELEMENT) { const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); Doc.GetProto(pinDoc).presentationTargetDoc = item; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title.toString()'); + Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('this.presentationTargetDoc?.title?.toString()'); value.splice(i, 1, pinDoc); } }); @@ -342,7 +342,7 @@ export class PresBox extends React.Component<FieldViewProps> { doc.presBox = this.props.Document; doc.presBoxKey = this.props.fieldKey; doc.collapsedHeight = hgt; - doc.height = ComputedField.MakeFunction("this.collapsedHeight + Number(this.embedOpen ? 100:0)"); + doc._height = ComputedField.MakeFunction("this.collapsedHeight + Number(this.embedOpen ? 100:0)"); const curScale = NumCast(doc.viewScale, null); if (curScale === undefined) { doc.viewScale = 1; diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 0825580b7..f492ea773 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -9,6 +9,7 @@ position: absolute; font-size: 10px; line-height: 1; + overflow: hidden; } .searchBox-bar { height: 32px; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index d129fe33b..5f454e930 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -710,9 +710,9 @@ export namespace Doc { } let dt = 0; - export function linkFollowHighlight(destDoc: Doc) { + export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) { linkFollowUnhighlight(); - Doc.HighlightDoc(destDoc); + Doc.HighlightDoc(destDoc, dataAndDisplayDocs); document.removeEventListener("pointerdown", linkFollowUnhighlight); document.addEventListener("pointerdown", linkFollowUnhighlight); const x = dt = Date.now(); @@ -726,10 +726,10 @@ export namespace Doc { export function IsHighlighted(doc: Doc) { return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc)); } - export function HighlightDoc(doc: Doc) { + export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) { runInAction(() => { highlightManager.HighlightedDoc.set(doc, true); - highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true); + dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true); }); } export function UnHighlightDoc(doc: Doc) { @@ -756,7 +756,7 @@ export namespace Doc { source.dragFactory instanceof Doc && source.dragFactory.isTemplateDoc ? source.dragFactory : source && source.layout instanceof Doc && source.layout.isTemplateDoc ? source.layout : undefined; } - export function setChildDetailed(target: Doc, source?: Doc) { + export function setChildDetailedLayout(target: Doc, source?: Doc) { target.childDetailed = source && source.isTemplateDoc ? source : source && source.dragFactory instanceof Doc && source.dragFactory.isTemplateDoc ? source.dragFactory : source && source.layout instanceof Doc && source.layout.isTemplateDoc ? source.layout : undefined; @@ -776,6 +776,7 @@ export namespace Doc { Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); Scripting.addGlobal(function setChildLayout(target: any, source: any) { Doc.setChildLayout(target, source); }); +Scripting.addGlobal(function setChildDetailedLayout(target: any, source: any) { Doc.setChildDetailedLayout(target, source); }); Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 6f99af8f6..35b266608 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -14,6 +14,7 @@ import { Utils } from "../../../Utils"; import { nullAudio } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; import { InkingControl } from "../../../client/views/InkingControl"; +import { CollectionViewType } from "../../../client/views/collections/CollectionView"; export class CurrentUserUtils { private static curr_id: string; @@ -54,7 +55,7 @@ export class CurrentUserUtils { { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' }, { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", ignoreClick: true, drag: 'Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List<Doc>(), { _width: 200, _height: 500, title: "a presentation trail" })' }, + { title: "presentation", icon: "tv", ignoreClick: true, drag: `Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List<Doc>(), { _width: 200, _height: 500, _viewType: ${CollectionViewType.Stacking}, title: "a presentation trail" })` }, { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, @@ -246,7 +247,7 @@ export class CurrentUserUtils { // the initial presentation Doc to use static setupDefaultPresentation(doc: Doc) { - doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", boxShadow: "0 0" }); + doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, boxShadow: "0 0" }); } static setupMobileUploads(doc: Doc) { |