diff options
Diffstat (limited to 'src')
24 files changed, 751 insertions, 311 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 956a5645c..5e83645ec 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1212,5 +1212,4 @@ export namespace DocUtils { } Scripting.addGlobal("Docs", Docs); -Scripting.addGlobal(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: "child of " + proto.title }); return d; }); - +Scripting.addGlobal(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: "child of " + proto.title }); return d; });
\ No newline at end of file diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 4fbc27cd3..11c2395ff 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -391,7 +391,7 @@ export class CurrentUserUtils { }[] { if (doc.emptyPresentation === undefined) { doc.emptyPresentation = Docs.Create.PresDocument(new List<Doc>(), - { title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0", system: true }); + { title: "Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0", system: true }); } if (doc.emptyCollection === undefined) { doc.emptyCollection = Docs.Create.FreeformDocument([], @@ -834,10 +834,7 @@ export class CurrentUserUtils { })); } if (doc.activePresentation === undefined) { - doc.activePresentation = Docs.Create.PresDocument(new List<Doc>(), { - title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", - _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0", system: true - }); + doc.activePresentation = Doc.MakeCopy(doc.emptyPresentation as Doc, true); } } @@ -926,12 +923,13 @@ export class CurrentUserUtils { this.setupSearchPanel(doc); this.setupOverlays(doc); // documents in overlay layer this.setupDockedButtons(doc); // the bottom bar of font icons - this.setupDefaultPresentation(doc); // presentation that's initially triggered await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument(); doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument(); doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument(); + setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered + // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); @@ -969,4 +967,4 @@ Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.cre Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); }, - "returns all the links directly to the document", "(doc: any)"); + "returns all the links directly to the document", "(doc: any)");
\ No newline at end of file diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index bd57e7f48..962294933 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -231,6 +231,7 @@ export class DocumentManager { containerDoc.currentTimecode = targetTimecode; const targetContext = await target?.context as Doc; const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined; + console.log(targetNavContext); DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished); } else { finished?.(); diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 05ba00331..113278593 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -84,11 +84,4 @@ export namespace SelectionManager { export function SelectedDocuments(): Array<DocumentView> { return Array.from(manager.SelectedDocuments.keys()); } -} - - -Scripting.addGlobal(function selectDoc(doc: any) { - const view = DocumentManager.Instance.getDocumentView(doc); - view && SelectionManager.SelectDoc(view, false); - //Doc.UserDoc().activeSelection = new List([doc]); -});
\ No newline at end of file +}
\ No newline at end of file diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index a05bfc302..4a92ed262 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -176,6 +176,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T added.map(doc => doc.context = this.props.Document); (targetDataDoc[this.annotationKey] as List<Doc>).push(...added); targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + const lastModified = "lastModified"; + targetDataDoc[lastModified] = new DateField(new Date(Date.now())); } } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c97882f06..1fc0ed034 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -324,6 +324,8 @@ export default class KeyManager { undoBatch(() => { targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]); targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + const lastModified = "lastModified"; + targetDataDoc[lastModified] = new DateField(new Date(Date.now())); })(); } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index dbce1502f..5ee10f7a6 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -199,7 +199,7 @@ export class MainView extends React.Component { let check = false; const icon = "icon"; targets.forEach((thing) => { - if (thing.className.toString() === "collectionSchemaView-table" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "beta" || thing.className.toString() === "collectionSchemaView-menuOptions-wrapper") { + if (thing.className.toString() === "collectionSchemaView-searchContainer" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "collectionSchema-header-menuOptions" || thing.className.toString() === "altcollectionTimeView-treeView") { check = true; } }); @@ -904,4 +904,4 @@ Scripting.addGlobal(function copyWorkspace() { Doc.AddDocToList(workspaces, "data", copiedWorkspace); // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => MainView.Instance.openWorkspace(copiedWorkspace), 0); -}); +});
\ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 7db846f72..22bb6e59a 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -758,7 +758,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged); this.props.glContainer.on("tab", this.onActiveContentItemChanged); this.onActiveContentItemChanged(); - this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance.props.backgroundColor?.(this._document, 0) || "white") }), + this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white") }), (data) => { const selected = data.views.some(v => Doc.AreProtosEqual(v.props.Document, this._document)); this._tab && (this._tab.style.backgroundColor = selected ? data.color : ""); @@ -821,7 +821,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { if (this._mainCont && this._mainCont.children) { const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement); const scale = Utils.GetScreenTransform(this._mainCont).scale; - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); + return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); } return Transform.Identity(); } diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 8a1dd8472..20ae74b44 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -33,6 +33,8 @@ import DatePicker from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; import { DateField } from "../../../fields/DateField"; import { RichTextField } from "../../../fields/RichTextField"; +import { DocumentManager } from "../../util/DocumentManager"; +import { SearchUtil } from "../../util/SearchUtil"; const path = require('path'); library.add(faExpand); @@ -159,6 +161,29 @@ export class CollectionSchemaCell extends React.Component<CellProps> { // e.stopPropagation(); // } + returnHighlights(bing: (() => string), positions?: number[]) { + const results = []; + const contents = bing(); + + if (positions !== undefined) { + StrCast(this.props.Document._searchString) + const length = StrCast(this.props.Document._searchString).length; + + results.push(<span style={{ color: contents ? "black" : "grey" }}>{contents ? contents.slice(0, positions[0]) : "undefined"}</span>); + positions.forEach((num, cur) => { + results.push(<span style={{ backgroundColor: "#FFFF00", color: contents ? "black" : "grey" }}>{contents ? contents.slice(num, num + length) : "undefined"}</span>); + let end = 0; + cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1]; + results.push(<span style={{ color: contents ? "black" : "grey" }}>{contents ? contents.slice(num + length, end) : "undefined"}</span>); + } + ); + return results; + } + else { + return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>; + } + } + renderCellWithType(type: string | undefined) { const dragRef: React.RefObject<HTMLDivElement> = React.createRef(); @@ -200,12 +225,24 @@ export class CollectionSchemaCell extends React.Component<CellProps> { const doc = FieldValue(Cast(field, Doc)); const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc); - const onItemDown = (e: React.PointerEvent) => { - //fieldIsDoc && - SetupDrag(this._focusRef, - () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document, - this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument, - this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); + const onItemDown = async (e: React.PointerEvent) => { + if (this.props.Document._searchDoc !== undefined) { + let doc = Doc.GetProto(this.props.rowProps.original); + const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc); + let targetContext = undefined; + if (aliasdoc.length > 0) { + targetContext = Cast(aliasdoc[0].context, Doc) as Doc; + } + console.log(targetContext); + DocumentManager.Instance.jumpToDocument(this.props.rowProps.original, false, undefined, targetContext); + } + else { + fieldIsDoc && + SetupDrag(this._focusRef, + () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document, + this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument, + this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); + } }; const onPointerEnter = (e: React.PointerEvent): void => { if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { @@ -281,27 +318,98 @@ export class CollectionSchemaCell extends React.Component<CellProps> { positions.pop(); } } + let search = false; + if (this.props.Document._searchDoc !== undefined) { + search = true; + } + + return ( <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }} ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> <div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}> - <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}> - <EditableView - positions={positions.length > 0 ? positions : undefined} - search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined} - editing={this._isEditing} - isEditingCallback={this.isEditingCallback} - display={"inline"} - contents={contents ? contents : type === "number" ? "0" : "undefined"} - highlight={positions.length > 0 ? true : undefined} - //contents={StrCast(contents)} - height={"auto"} - maxHeight={Number(MAX_ROW_HEIGHT)} - placeholder={"enter value"} - bing={() => { + <div className="collectionSchemaView-cellContents" + ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}> + {!search ? + <EditableView + positions={positions.length > 0 ? positions : undefined} + search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined} + editing={this._isEditing} + isEditingCallback={this.isEditingCallback} + display={"inline"} + contents={contents ? contents : type === "number" ? "0" : "undefined"} + highlight={positions.length > 0 ? true : undefined} + //contents={StrCast(contents)} + height={"auto"} + maxHeight={Number(MAX_ROW_HEIGHT)} + placeholder={"undefined"} + bing={() => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); + if (cfield !== undefined) { + // if (typeof(cfield)===RichTextField) + const a = cfield as RichTextField; + if (a.Text !== undefined) { + return (a.Text); + } + else if (StrCast(cfield)) { + return StrCast(cfield); + } + else { + return String(NumCast(cfield)); + } + } + }} + GetValue={() => { + if (type === "number" && (contents === 0 || contents === "0")) { + return "0"; + } else { + const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); + if (type === "number") { + return StrCast(cfield); + } + const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; + const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; + const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : + Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; + return val; + + } + + }} + SetValue={action((value: string) => { + let retVal = false; + + if (value.startsWith(":=")) { + retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col); + } else { + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + if (script.compiled) { + retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); + } + + } + if (retVal) { + this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing' + this.props.setIsEditing(false); + } + return retVal; + + //return true; + })} + OnFillDown={async (value: string) => { + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + if (script.compiled) { + DocListCast(this.props.Document[this.props.fieldKey]). + forEach((doc, i) => value.startsWith(":=") ? + this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) : + this.applyToDoc(doc, i, this.props.col, script.run)); + } + }} + /> + : + this.returnHighlights(() => { const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); if (cfield !== undefined) { - console.log(typeof (cfield)); // if (typeof(cfield)===RichTextField) const a = cfield as RichTextField; if (a.Text !== undefined) { @@ -314,56 +422,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> { return String(NumCast(cfield)); } } - }} - GetValue={() => { - if (type === "number" && (contents === 0 || contents === "0")) { - return "0"; - } else { - const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); - if (type === "number") { - return StrCast(cfield); - } - const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; - const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; - const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : - Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; - return val; - + else { + return ""; } - - }} - SetValue={action((value: string) => { - let retVal = false; - - if (value.startsWith(":=")) { - retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col); - } else { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - if (script.compiled) { - retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); - } - - } - if (retVal) { - this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing' - this.props.setIsEditing(false); - } - return retVal; - - //return true; - })} - OnFillDown={async (value: string) => { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - if (script.compiled) { - DocListCast(this.props.Document[this.props.fieldKey]). - forEach((doc, i) => value.startsWith(":=") ? - this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) : - this.applyToDoc(doc, i, this.props.col, script.run)); - } - }} - /> - - + }, positions) + } </div > {/* {fieldIsDoc ? docExpander : null} */} </div> @@ -903,7 +966,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell { }}><button onClick={() => { doc.searchMatch = false; setTimeout(() => doc.searchMatch = true, 0); - doc.searchIndex = NumCast(doc.searchIndex); }} style={{ padding: 2, left: 77 }}> <FontAwesomeIcon icon="arrow-up" size="sm" /> </button> @@ -911,7 +973,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell { { doc.searchMatchAlt = false; setTimeout(() => doc.searchMatchAlt = true, 0); - doc.searchIndex = NumCast(doc.searchIndex); } }} style={{ padding: 2 }}> <FontAwesomeIcon icon="arrow-down" size="sm" /> @@ -929,7 +990,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell { onClick={() => { doc.searchMatch = false; setTimeout(() => doc.searchMatch = true, 0); - doc.searchIndex = NumCast(doc.searchIndex); }}> <FontAwesomeIcon icon="arrow-down" size="sm" /> </button></div >; diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index e65adcf76..8cc91b3da 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -1,5 +1,5 @@ import React = require("react"); -import { action, observable } from "mobx"; +import { action, observable, computed } from "mobx"; import { observer } from "mobx-react"; import "./CollectionSchemaView.scss"; import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl, faCalendar } from '@fortawesome/free-solid-svg-icons'; @@ -9,8 +9,23 @@ import { ColumnType } from "./CollectionSchemaView"; import { faFile } from "@fortawesome/free-regular-svg-icons"; import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; -import { Doc } from "../../../fields/Doc"; -import { StrCast } from "../../../fields/Types"; +import { Transform } from '../../util/Transform'; +import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc"; +import { StrCast, Cast } from "../../../fields/Types"; +import { optionFocusAriaMessage } from "react-select/src/accessibility"; +import { TraceMobx } from "../../../fields/util"; +import { CollectionTreeView } from "./CollectionTreeView"; +import { returnEmptyFilter, returnFalse, emptyPath, returnZero, emptyFunction, returnOne } from "../../../Utils"; +import { RichTextField } from "../../../fields/RichTextField"; +import { Docs } from "../../documents/Documents"; +import { List } from "../../../fields/List"; +import { listSpec } from "../../../fields/Schema"; +import { ScriptField, ComputedField } from "../../../fields/ScriptField"; +import { DocumentType } from "../../documents/DocumentTypes"; +import { CollectionView } from "./CollectionView"; +import { SearchBox } from "../search/SearchBox"; +import { createParameter } from "typescript"; + const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -286,6 +301,12 @@ export interface KeysDropdownProps { setIsEditing: (isEditing: boolean) => void; width?: string; docs?: Doc[]; + Document?: Doc; + dataDoc?: Doc; + fieldKey?: string; + ContainingCollectionDoc?: Doc; + ContainingCollectionView?: CollectionView; + active?: (outsideReaction?: boolean) => boolean; } @observer export class KeysDropdown extends React.Component<KeysDropdownProps> { @@ -301,8 +322,10 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { @action onSelect = (key: string): void => { - if (key.slice(0, this._key.length) === this._key && this._key !== key) { - const filter = key.slice(this._key.length - key.length); + if (this._searchTerm.includes(":")) { + const colpos = this._searchTerm.indexOf(":"); + const filter = this._searchTerm.slice(colpos + 1, this._searchTerm.length); + //const filter = key.slice(this._key.length - key.length); this.props.onSelect(this._key, this._key, this.props.addNew, filter); } else { @@ -314,16 +337,21 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { } @action - onSelect2 = (key: string): void => { - this._searchTerm = this._searchTerm.slice(0, this._key.length) + key; + onSelectValue = (key: string): void => { + const colpos = this._searchTerm.indexOf(":"); + this.onSelect(key); + this._searchTerm = this._searchTerm.slice(0, colpos + 1) + key; this._isOpen = false; + this.props.onSelect(this._key, this._key, this.props.addNew, key); } @undoBatch onKeyDown = (e: React.KeyboardEvent): void => { if (e.key === "Enter") { - const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); + let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); + let blockedkeys = ["_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"]; + keyOptions = keyOptions.filter(n => !blockedkeys.includes(n)); if (keyOptions.length) { this.onSelect(keyOptions[0]); } else if (this._searchTerm !== "" && this.props.canAddNew) { @@ -360,20 +388,25 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { onPointerOut = (e: React.PointerEvent): void => { this._canClose = true; } - + @action renderOptions = (): JSX.Element[] | JSX.Element => { - if (!this._isOpen) return <></>; - + if (!this._isOpen) { + this.defaultMenuHeight = 0; + return <></>; + } const searchTerm = this._searchTerm.trim() === "New field" ? "" : this._searchTerm; - const keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); + let keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); const exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 || this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1; + let blockedkeys = ["proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"]; + keyOptions = keyOptions.filter(n => !blockedkeys.includes(n)); + const options = keyOptions.map(key => { return <div key={key} className="key-option" style={{ border: "1px solid lightgray", - width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" + width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", }} onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect(key); this.setSearchTerm(""); }}>{key}</div>; }); @@ -382,49 +415,252 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { if (this._key !== this._searchTerm.slice(0, this._key.length)) { if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) { options.push(<div key={""} className="key-option" style={{ - border: "1px solid lightgray", - width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" + border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", }} onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}> Create "{this._searchTerm}" key</div>); } } + if (options.length === 0) { + this.defaultMenuHeight = 0; + } + else { + if (this.props.docs) { + let panesize = this.props.docs.length * 30; + options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8; + } + else { + options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8; + } + } return options; } - + @action renderFilterOptions = (): JSX.Element[] | JSX.Element => { - if (!this._isOpen) return <></>; - const keyOptions: string[] = []; - const temp = this._searchTerm.slice(this._key.length); - this.props.docs?.forEach((doc) => { + if (!this._isOpen) { + this.defaultMenuHeight = 0; + return <></>; + } + let keyOptions: string[] = []; + const colpos = this._searchTerm.indexOf(":"); + const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length); + let docs = DocListCast(this.props.dataDoc![this.props.fieldKey!]); + docs.forEach((doc) => { const key = StrCast(doc[this._key]); if (keyOptions.includes(key) === false && key.includes(temp)) { keyOptions.push(key); } }); - const options = keyOptions.map(key => { + //Doc.setDocFilter(this.props.Document!, this._key, key, undefined); + let bool = false; + let filters = Cast(this.props.Document!._docFilters, listSpec("string")); + console.log(filters); + if (filters !== undefined) { + bool = filters.includes(key) && filters[filters.indexOf(key) + 1] === "check"; + console.log(filters.includes(key)); + } return <div key={key} className="key-option" style={{ - border: "1px solid lightgray", - width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" + border: "1px solid lightgray", paddingLeft: 5, textAlign: "left", + width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white", }} - onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect2(key); }}>{key}</div>; + > + <input type="checkbox" onChange={(e) => { e.target.checked === true ? Doc.setDocFilter(this.props.Document!, this._key, key, "check") : Doc.setDocFilter(this.props.Document!, this._key, key, undefined); e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs![0], this._key, key, "check") : Doc.setDocFilter(docs![0], this._key, key, undefined); }} + checked={bool} ></input> + <span style={{ paddingLeft: 4 }}> + {key} + </span> + + </div>; }); + if (options.length === 0) { + this.defaultMenuHeight = 0; + } + else { + if (this.props.docs) { + let panesize = this.props.docs.length * 30; + options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8; + } + else { + options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8; + } + + } return options; } + // @action + // renderFilterOptions = (): JSX.Element[] | JSX.Element => { + // this.facetClick(this._key); + // return <div> + // {this.filterView} + // </div> + // } + @observable defaultMenuHeight = 0; + + + facetClick = (facetHeader: string) => { + facetHeader = this._key; + let newFacet: Opt<Doc>; + if (this.props.Document !== undefined) { + const facetCollection = this.props.Document; + // const found = DocListCast(facetCollection[this.props.fieldKey + "-filter"]).findIndex(doc => doc.title === facetHeader); + // if (found !== -1) { + // console.log("found not n-1"); + // (facetCollection[this.props.fieldKey + "-filter"] as List<Doc>).splice(found, 1); + // const docFilter = Cast(this.props.Document._docFilters, listSpec("string")); + // if (docFilter) { + // let index: number; + // while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) { + // docFilter.splice(index, 3); + // } + // } + // const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string")); + // if (docRangeFilters) { + // let index: number; + // while ((index = docRangeFilters.findIndex(item => item === facetHeader)) !== -1) { + // docRangeFilters.splice(index, 3); + // } + // } + // } + + + + console.log("found is n-1"); + const allCollectionDocs = DocListCast(this.props.dataDoc![this.props.fieldKey!]); + var rtfields = 0; + const facetValues = Array.from(allCollectionDocs.reduce((set, child) => { + const field = child[facetHeader] as Field; + const fieldStr = Field.toString(field); + if (field instanceof RichTextField || (typeof (field) === "string" && fieldStr.split(" ").length > 2)) rtfields++; + return set.add(fieldStr); + }, new Set<string>())); + + let nonNumbers = 0; + let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE; + facetValues.map(val => { + const num = Number(val); + if (Number.isNaN(num)) { + nonNumbers++; + } else { + minVal = Math.min(num, minVal); + maxVal = Math.max(num, maxVal); + } + }); + if (facetHeader === "text" || rtfields / allCollectionDocs.length > 0.1) { + console.log("Case1"); + newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true }); + Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox + newFacet.target = this.props.Document; + newFacet._textBoxPadding = 4; + const scriptText = `setDocFilter(this.target, "${facetHeader}", text, "match")`; + newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" }); + } else if (nonNumbers / facetValues.length < .1) { + console.log("Case2"); + newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true }); + const newFacetField = Doc.LayoutFieldKey(newFacet); + const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader); + Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox + const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05); + const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05); + newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0]; + newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1]; + Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal; + Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal; + newFacet.target = this.props.Document; + const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`; + newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); + Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); + } else { + console.log("Case3"); + newFacet = new Doc(); + newFacet.title = facetHeader; + newFacet.treeViewOpen = true; + newFacet.type = DocumentType.COL; + const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.props.dataDoc! }; + this.props.Document.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables); + // this.props.Document.data + } + //newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); + } + } + + + get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } + + @computed get scriptField() { + console.log("we kinda made it"); + const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)"; + const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name }); + return script ? () => script : undefined; + } + filterBackground = () => "rgba(105, 105, 105, 0.432)"; + + + // @computed get filterView() { + // TraceMobx(); + // if (this.props.Document !== undefined) { + // //const facetCollection = this.props.Document; + // // const flyout = ( + // // <div className="collectionTimeView-flyout" style={{ width: `${this.facetWidth()}`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}> + // // {this._allFacets.map(facet => <label className="collectionTimeView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}> + // // <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey + "-filter"]).some(d => d.title === facet)} /> + // // <span className="checkmark" /> + // // {facet} + // // </label>)} + // // </div> + // // ); + // return <div className="altcollectionTimeView-treeView"> + // <div className="altcollectionTimeView-tree" key="tree"> + // <CollectionTreeView + // PanelPosition={""} + // Document={this.props.Document} + // DataDoc={this.props.Document} + // fieldKey={this.props.fieldKey!} + // CollectionView={undefined} + // docFilters={returnEmptyFilter} + // ContainingCollectionDoc={this.props.ContainingCollectionDoc!} + // ContainingCollectionView={this.props.ContainingCollectionView!} + // PanelWidth={() => 200} + // PanelHeight={() => 200} + // NativeHeight={returnZero} + // NativeWidth={returnZero} + // LibraryPath={emptyPath} + // rootSelected={returnFalse} + // renderDepth={1} + // dropAction={undefined} + // ScreenToLocalTransform={Transform.Identity} + // addDocTab={returnFalse} + // pinToPres={returnFalse} + // isSelected={returnFalse} + // select={returnFalse} + // bringToFront={emptyFunction} + // active={this.props.active!} + // whenActiveChanged={returnFalse} + // treeViewHideTitle={true} + // ContentScaling={returnOne} + // focus={returnFalse} + // treeViewHideHeaderFields={true} + // onCheckedClick={this.scriptField} + // ignoreFields={this.ignoreFields} + // annotationsKey={""} + // dontRegisterView={true} + // backgroundColor={this.filterBackground} + // moveDocument={returnFalse} + // removeDocument={returnFalse} + // addDocument={returnFalse} /> + // </div> + // </div>; + // } + // } + render() { return ( <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}> - {this._key === this._searchTerm.slice(0, this._key.length) ? - <div style={{ position: "absolute", marginLeft: "4px", marginTop: "3", color: "grey", pointerEvents: "none", lineHeight: 1.15 }}> - {this._key} - </div> - : undefined} <input className="keys-search" style={{ width: "100%" }} ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown} onChange={e => this.onChange(e.target.value)} @@ -433,11 +669,10 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { e.stopPropagation(); }} onFocus={this.onFocus} onBlur={this.onBlur}></input> <div className="keys-options-wrapper" style={{ - backgroundColor: "white", - width: this.props.width, maxWidth: this.props.width, + width: this.props.width, maxWidth: this.props.width, height: "auto", }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}> - {this._key === this._searchTerm.slice(0, this._key.length) ? + {this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()} </div> </div > diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index ba0a259c5..5c2931a8b 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -43,6 +43,49 @@ // } } +.collectionSchemaView-searchContainer { + border-width: $COLLECTION_BORDER_WIDTH; + border-color: $intermediate-color; + border-style: solid; + border-radius: $border-radius; + box-sizing: border-box; + position: relative; + top: 0; + width: 100%; + height: 100%; + margin-top: 0; + transition: top 0.5s; + display: flex; + justify-content: space-between; + flex-wrap: nowrap; + touch-action: none; + + div { + touch-action: none; + } + + + .collectionSchemaView-tableContainer { + width: 100%; + height: 100%; + } + + .collectionSchemaView-dividerDragger { + position: relative; + height: 100%; + width: 20px; + z-index: 20; + right: 0; + top: 0; + background: gray; + cursor: col-resize; + } + + // .documentView-node:first-child { + // background: $light-color; + // } +} + .ReactTable { width: 100%; background: white; @@ -165,7 +208,7 @@ .collectionSchema-header-menu { - height: 100%; + height: auto; z-index: 100; position: absolute; background:white; @@ -280,11 +323,9 @@ button.add-column { background-color: white; .key-option { - //background-color: $light-color; background-color: white; border: 1px solid lightgray; padding: 2px 3px; - &:not(:first-child) { border-top: 0; } @@ -315,12 +356,53 @@ button.add-column { } } +.altcollectionTimeView-treeView { + display: flex; + flex-direction: column; + width: 175px; + height: auto; + position: fixed; + border-left: solid 1px; + z-index: 1; + + .collectionTimeView-addfacet { + display: inline-block; + width: 200px; + height: 30px; + background: darkGray; + text-align: left; + + .collectionTimeView-button { + align-items: center; + display: flex; + width: 100%; + height: 100%; + + .collectionTimeView-span { + margin: auto; + } + } + + >div, + >div>div { + width: 100%; + height: 100%; + } + } + + .altcollectionTimeView-tree { + display: inline-block; + width: 100%; + height: calc(100% - 30px); + } +} + .collectionSchema-row { height: 100%; background-color: white; &.row-focused .rt-td { - background-color: rgb(255, 246, 246); //$light-color-secondary; + background-color: #bfffc0; //$light-color-secondary; } &.row-wrapped { @@ -383,6 +465,9 @@ button.add-column { .collectionSchemaView-cellWrapper { height: 100%; padding: 4px; + text-align:left; + padding-left:19px; + position: relative; &:focus { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index a003de0d3..3f879b489 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -11,7 +11,7 @@ import { Doc } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; -import { Cast, NumCast } from "../../../fields/Types"; +import { Cast, NumCast, BoolCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils"; import { SnappingManager } from "../../util/SnappingManager"; @@ -71,8 +71,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @observable _pointerY = 0; @observable _openTypes: boolean = false; @computed get menuCoordinates() { - const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)); - const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)); + let searchx = 0; + let searchy = 0; + if (this.props.Document._searchDoc !== undefined) { + let el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0]; + if (el !== undefined) { + let rect = el.getBoundingClientRect(); + searchx = rect.x; + searchy = rect.y + } + } + const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx; + const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy; return this.props.ScreenToLocalTransform().transformPoint(x, y); } @@ -611,14 +621,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { } render() { + let name = "collectionSchemaView-container"; + if (this.props.Document._searchDoc !== undefined) { + name = "collectionSchemaView-searchContainer"; + } TraceMobx(); const menuContent = this.renderMenuContent; const menu = <div className="collectionSchema-header-menu" ref={this.setNode} onWheel={e => this.onZoomMenu(e)} onPointerDown={e => this.onHeaderClick(e)} style={{ - position: "fixed", background: "white", - transform: `translate(${this.menuCoordinates[0] / this.scale}px, ${this.menuCoordinates[1] / this.scale}px)` + position: "fixed", background: "white", border: "black 1px solid", + transform: `translate(${(this.menuCoordinates[0] / this.scale)}px, ${(this.menuCoordinates[1] / this.scale)}px)` }}> <Measure offset onResize={action((r: any) => { const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height); @@ -627,9 +641,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>} </Measure> </div>; - return <div className="collectionSchemaView-container" + return <div className={name} style={{ - overflow: this.props.overflow === true ? "auto" : undefined, + overflow: this.props.overflow === true ? "scroll" : undefined, pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined, width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", }} > diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c88eabdcc..7957ded1c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -112,10 +112,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; } @computed get childDocs() { - let rawdocs: (Doc | Promise<Doc>)[] = DocListCast(this.props.Document._searchDocs); - - if (rawdocs.length !== 0) { - } else if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list; + let rawdocs: (Doc | Promise<Doc>)[] = []; + if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list; rawdocs = [this.dataField]; } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it. rawdocs = Cast(this.dataField, listSpec(Doc), null); @@ -130,28 +128,23 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; - const searchDocs = DocListCast(this.props.Document._searchDocs); - // if (searchDocs !== undefined && searchDocs.length > 0) { - // let newdocs: Doc[] = []; - // childDocs.forEach((el) => { - // searchDocs.includes(el) ? newdocs.push(el) : undefined; - // }); - // childDocs = newdocs; - // } + let searchDocs = DocListCast(this.props.Document._searchDocs); + let docsforFilter: Doc[] = childDocs; + if (searchDocs !== undefined && searchDocs.length > 0) { docsforFilter = []; - // let newdocs: Doc[] = []; - // let newarray: Doc[] = []; - //while (childDocs.length > 0) { - //newarray = []; + const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []); + console.log(searchDocs); + searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript) + console.log(this.docFilters()); + console.log(searchDocs); childDocs.forEach((d) => { if (d.data !== undefined) { - console.log(d); let newdocs = DocListCast(d.data); if (newdocs.length > 0) { - let vibecheck: boolean | undefined = undefined; + let displaycheck: boolean | undefined = undefined; let newarray: Doc[] = []; while (newdocs.length > 0) { newarray = []; @@ -163,12 +156,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: }); } if (searchDocs.includes(t)) { - vibecheck = true; + displaycheck = true; } }); newdocs = newarray; } - if (vibecheck === true) { + if (displaycheck === true) { docsforFilter.push(d); } } @@ -177,14 +170,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: docsforFilter.push(d); } }); - //childDocs = newarray; - //} + return docsforFilter; } - childDocs = docsforFilter; - + console.log("you fool"); + console.log(childDocs); const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []); - - return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript); + return this.props.Document.dontRegisterView ? childDocs : DocUtils.FilterDocs(childDocs, this.docFilters(), docRangeFilters, viewSpecScript); } @action @@ -481,7 +472,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: completed?.(); } else { if (text && !text.includes("https://")) { - this.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 })); + UndoManager.RunInBatch(() => this.addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop"); } } disposer(); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index dc88917cc..6768c6df9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -53,7 +53,7 @@ export interface TreeViewProps { indentDocument?: () => void; outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; - backgroundColor?: (doc: Doc) => string | undefined; + backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined; outerXf: () => { translateX: number, translateY: number }; treeViewDoc: Doc; parentKey: string; @@ -88,7 +88,7 @@ class TreeView extends React.Component<TreeViewProps> { get doc() { return this.props.document; } get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode, false); } get displayName() { return "TreeView(" + this.doc.title + ")"; } // this makes mobx trace() statements more descriptive - get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); } + get defaultExpandedView() { return this.childDocs.length ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; @@ -108,6 +108,7 @@ class TreeView extends React.Component<TreeViewProps> { } @computed get childDocs() { return this.childDocList(this.fieldKey); } @computed get childLinks() { return this.childDocList("links"); } + @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); } @computed get boundsOfCollectionDocument() { return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined : Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey])); @@ -127,7 +128,7 @@ class TreeView extends React.Component<TreeViewProps> { constructor(props: any) { super(props); - const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `); + const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); documentView.select();} `, { documentView: "any" }); this._editTitleScript = script && (() => script); if (Doc.GetT(this.doc, "editTitle", "string", true) === "*") Doc.SetInPlace(this.doc, "editTitle", this._uniqueId, false); } @@ -313,11 +314,11 @@ class TreeView extends React.Component<TreeViewProps> { @computed get renderContent() { TraceMobx(); const expandKey = this.treeViewExpandedView; - if (["links", this.fieldKey].includes(expandKey)) { + if (["links", "annotations", this.fieldKey].includes(expandKey)) { const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey); const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true); - const docs = expandKey === "links" ? this.childLinks : this.childDocs; + const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; const sortKey = `${this.fieldKey}-sortAscending`; return <ul key={expandKey + "more"} onClick={(e) => { this.doc[sortKey] = (this.doc[sortKey] ? false : (this.doc[sortKey] === false ? undefined : true)); @@ -397,7 +398,7 @@ class TreeView extends React.Component<TreeViewProps> { title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"} onClick={this.bulletClick} style={{ color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}> - {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />} + {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs?.length ? "caret-square-right" : "caret-right") : (this.childDocs?.length ? "caret-square-down" : "caret-down"))} />} </div>; } @@ -424,7 +425,8 @@ class TreeView extends React.Component<TreeViewProps> { this.doc.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode ? "layout" : "fields") : this.treeViewExpandedView === "fields" && this.layoutDoc ? "layout" : this.treeViewExpandedView === "layout" && DocListCast(this.doc.links).length ? "links" : - this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields"); + (this.treeViewExpandedView === "links" || this.treeViewExpandedView === "layout") && DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" : + this.childDocs.length ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields"); } this.treeViewOpen = true; })}> @@ -453,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> { NativeHeight={returnZero} NativeWidth={returnZero} contextMenuItems={this.contextMenuItems} + opacity={returnOne} renderDepth={1} focus={returnTrue} parentActive={returnTrue} @@ -533,7 +536,7 @@ class TreeView extends React.Component<TreeViewProps> { dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => boolean, pinToPres: (document: Doc) => void, - backgroundColor: undefined | ((document: Doc) => string | undefined), + backgroundColor: undefined | ((document: Doc, renderDepth: number) => string | undefined), screenToLocalXf: () => Transform, outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 555db7e1a..a048d4ebd 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -46,6 +46,7 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import { ContextMenuProps } from '../ContextMenuItem'; +import { table } from 'console'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -182,6 +183,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus // targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]); (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added); targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + const lastModified = "lastModified"; + targetDataDoc[lastModified] = new DateField(new Date(Date.now())); } } } @@ -515,56 +518,56 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus </label>)} </div> ); - return !this._facetWidth || this.props.dontRegisterView ? (null) : - <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}> - <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}> - <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}> - <div className="collectionTimeView-button"> - <FontAwesomeIcon icon={faEdit} size={"lg"} /> - <span className="collectionTimeView-span">Facet Filters</span> - </div> - </Flyout> - </div> - <div className="collectionTimeView-tree" key="tree"> - <CollectionTreeView - PanelPosition={""} - Document={facetCollection} - DataDoc={facetCollection} - fieldKey={`${this.props.fieldKey}-filter`} - CollectionView={this} - docFilters={returnEmptyFilter} - ContainingCollectionDoc={this.props.ContainingCollectionDoc} - ContainingCollectionView={this.props.ContainingCollectionView} - PanelWidth={this.facetWidth} - PanelHeight={this.props.PanelHeight} - NativeHeight={returnZero} - NativeWidth={returnZero} - LibraryPath={emptyPath} - rootSelected={this.props.rootSelected} - renderDepth={1} - dropAction={this.props.dropAction} - ScreenToLocalTransform={this.props.ScreenToLocalTransform} - addDocTab={returnFalse} - pinToPres={returnFalse} - isSelected={returnFalse} - select={returnFalse} - bringToFront={emptyFunction} - active={this.props.active} - whenActiveChanged={returnFalse} - treeViewHideTitle={true} - ContentScaling={returnOne} - focus={returnFalse} - treeViewHideHeaderFields={true} - onCheckedClick={this.scriptField} - ignoreFields={this.ignoreFields} - annotationsKey={""} - dontRegisterView={true} - backgroundColor={this.filterBackground} - moveDocument={returnFalse} - removeDocument={returnFalse} - addDocument={returnFalse} /> - </div> - </div>; + + return !this._facetWidth || this.props.dontRegisterView ? (null) : <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}> + <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}> + <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}> + <div className="collectionTimeView-button"> + <FontAwesomeIcon icon={faEdit} size={"lg"} /> + <span className="collectionTimeView-span">Facet Filters</span> + </div> + </Flyout> + </div> + <div className="collectionTimeView-tree" key="tree"> + <CollectionTreeView + PanelPosition={""} + Document={facetCollection} + DataDoc={facetCollection} + fieldKey={`${this.props.fieldKey}-filter`} + CollectionView={this} + docFilters={returnEmptyFilter} + ContainingCollectionDoc={this.props.ContainingCollectionDoc} + ContainingCollectionView={this.props.ContainingCollectionView} + PanelWidth={this.facetWidth} + PanelHeight={this.props.PanelHeight} + NativeHeight={returnZero} + NativeWidth={returnZero} + LibraryPath={emptyPath} + rootSelected={this.props.rootSelected} + renderDepth={1} + dropAction={this.props.dropAction} + ScreenToLocalTransform={this.props.ScreenToLocalTransform} + addDocTab={returnFalse} + pinToPres={returnFalse} + isSelected={returnFalse} + select={returnFalse} + bringToFront={emptyFunction} + active={this.props.active} + whenActiveChanged={returnFalse} + treeViewHideTitle={true} + ContentScaling={returnOne} + focus={returnFalse} + treeViewHideHeaderFields={true} + onCheckedClick={this.scriptField} + ignoreFields={this.ignoreFields} + annotationsKey={""} + dontRegisterView={true} + backgroundColor={this.filterBackground} + moveDocument={returnFalse} + removeDocument={returnFalse} + addDocument={returnFalse} /> + </div> + </div>; } childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx index a974c5496..d8756aae3 100644 --- a/src/client/views/collections/SchemaTable.tsx +++ b/src/client/views/collections/SchemaTable.tsx @@ -177,9 +177,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> { } ); } + this.props.active const cols = this.props.columns.map(col => { - const keysDropdown = <KeysDropdown keyValue={col.heading} possibleKeys={possibleKeys} @@ -189,6 +189,14 @@ export class SchemaTable extends React.Component<SchemaTableProps> { onSelect={this.props.changeColumns} setIsEditing={this.props.setHeaderIsEditing} docs={this.props.childDocs} + Document={this.props.Document} + dataDoc={this.props.dataDoc} + fieldKey={this.props.fieldKey} + ContainingCollectionDoc={this.props.ContainingCollectionDoc} + ContainingCollectionView={this.props.ContainingCollectionView} + active={this.props.active} + + // try commenting this out width={"100%"} />; @@ -218,19 +226,15 @@ export class SchemaTable extends React.Component<SchemaTableProps> { background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}> - <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px" }} /> + <FontAwesomeIcon onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} /> {/* <div className="keys-dropdown" style={{ display: "inline", zIndex: 1000 }}> */} {keysDropdown} {/* </div> */} <div onClick={e => this.changeSorting(col)} - style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit" }}> + style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}> <FontAwesomeIcon icon={sortIcon} size="lg" /> </div> - {/* <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} - style={{ float: "right", paddingRight: "6px", zIndex: 1, background: "inherit" }}> - <FontAwesomeIcon icon={"compass"} size="sm" /> - </div> */} </div>; return { @@ -318,27 +322,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> { } - - @action - nextHighlight = (e: React.MouseEvent, doc: Doc) => { - e.preventDefault(); - e.stopPropagation(); - doc.searchMatch = false; - console.log(doc.searchMatch); - setTimeout(() => doc.searchMatch = true, 0); - console.log(doc.searchMatch); - - doc.searchIndex = NumCast(doc.searchIndex); - } - - @action - nextHighlight2 = (doc: Doc) => { - - doc.searchMatchAlt = false; - setTimeout(() => doc.searchMatchAlt = true, 0); - doc.searchIndex = NumCast(doc.searchIndex); - } - constructor(props: SchemaTableProps) { super(props); // convert old schema columns (list of strings) into new schema columns (list of schema header fields) diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 7de14c7d6..a396dc6c8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -105,11 +105,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque if (br) break; } } + let ypos = y; ns.map(line => { const indent = line.search(/\S|$/); - const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line }); + const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line }); this.props.addDocument(newBox); - y += 40 * this.props.getTransform().Scale; + ypos += 40 * this.props.getTransform().Scale; }); })(); e.stopPropagation(); diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx index e0f3eca44..c7edd67b3 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx @@ -970,15 +970,15 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { <div className="propertiesView-name"> {this.editableTitle} <div className="propertiesView-presSelected"> - {PresBox.Instance._selectedArray.length} selected + {PresBox.Instance?._selectedArray.length} selected <div className="propertiesView-selectedList"> - {PresBox.Instance.listOfSelected} + {PresBox.Instance?.listOfSelected} </div> </div> </div> {!selectedItem ? (null) : <div className="propertiesView-presTrails"> <div className="propertiesView-presTrails-title" - onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })} + onPointerDown={action(() => { this.openPresTransitions = !this.openPresTransitions; })} style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}> <FontAwesomeIcon icon={"rocket"} /> Transitions <div className="propertiesView-presTrails-title-icon"> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7d2c34b2b..58f8bdaac 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -324,6 +324,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu self: this.rootDoc, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, + documentView: this, shiftKey: e.shiftKey }, console.log); if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) && !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc)) { @@ -924,7 +925,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu const showTitle = StrCast(this.layoutDoc._showTitle); const showTitleHover = StrCast(this.layoutDoc._showTitleHover); const showCaption = StrCast(this.layoutDoc._showCaption); - const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined; + const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined; const captionView = (!showCaption ? (null) : <div className="documentView-captionWrapper" style={{ backgroundColor: StrCast(this.layoutDoc["caption-backgroundColor"]), color: StrCast(this.layoutDoc["caption-color"]) }}> <DocumentContentsView {...OmitKeys(this.props, ['children']).omit} diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index a87b0e466..8ee7f1e0e 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -19,7 +19,7 @@ $light-background: #ececec; .presBox-listCont { position: relative; - height: calc(100% - 25px); + height: calc(100% - 67px); width: 100%; margin-top: 3px; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 7d4bd5dd3..f1eb5ef09 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -23,7 +23,7 @@ import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from "../../../../fields/RichTextField"; import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { createSchema, makeInterface } from "../../../../fields/Schema"; -import { Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../fields/Types"; +import { Cast, DateCast, NumCast, StrCast, ScriptCast, BoolCast } from "../../../../fields/Types"; import { TraceMobx, OVERRIDE_ACL, GetEffectiveAcl } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; @@ -376,6 +376,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp public highlightSearchTerms = (terms: string[], alt: boolean) => { if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) { + const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight); const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true }); const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term)); @@ -383,30 +384,31 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp let tr = this._editorView.state.tr; const flattened: TextSelection[] = []; res.map(r => r.map(h => flattened.push(h))); - - - const lastSel = Math.min(flattened.length - 1, this._searchIndex); - flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark)); - this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; - this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView()); - if (alt === true) { - if (this._searchIndex > 1) { - this._searchIndex += -2; - } - else if (this._searchIndex === 1) { - this._searchIndex = length - 1; - } - else if (this._searchIndex === 0 && length !== 1) { - this._searchIndex = length - 2; - } - + if (BoolCast(Doc.GetProto(this.dataDoc).resetSearch) === true) { + this._searchIndex = 0; + Doc.GetProto(this.dataDoc).resetSearch = undefined; } else { + this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; + if (alt === true) { + if (this._searchIndex > 1) { + this._searchIndex += -2; + } + else if (this._searchIndex === 1) { + this._searchIndex = length - 1; + } + else if (this._searchIndex === 0 && length !== 1) { + this._searchIndex = length - 2; + } + } } - const index = this._searchIndex; - Doc.GetProto(this.dataDoc).searchIndex = index; + const lastSel = Math.min(flattened.length - 1, this._searchIndex); + flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark)); + flattened[lastSel] && this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView()); + + console.log(this._searchIndex); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index cfa9a1844..7c1b2f621 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -337,7 +337,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu nextAnnotation = () => { this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1); this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]); - this.Document.searchIndex = this.Index; } @@ -411,7 +410,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu phraseSearch: true, query: searchString }); - this.Document.searchIndex = this.Index; } else if (this._mainCont.current) { const executeFind = () => { @@ -425,7 +423,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu }; this._mainCont.current.addEventListener("pagesloaded", executeFind); this._mainCont.current.addEventListener("pagerendered", executeFind); - this.Document.searchIndex = this.Index; } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index f7b817aa1..4a14b222c 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -126,6 +126,29 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc if (e.target.value === "") { + if (this.currentSelectedCollection !== undefined) { + let newarray: Doc[] = []; + let docs: Doc[] = []; + docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); + while (docs.length > 0) { + newarray = []; + docs.forEach((d) => { + if (d.data !== undefined) { + d._searchDocs = new List<Doc>(); + d._docFilters = new List(); + const newdocs = DocListCast(d.data); + newdocs.forEach((newdoc) => { + newarray.push(newdoc); + }); + } + }); + docs = newarray; + } + + this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]); + this.currentSelectedCollection.props.Document._docFilters = new List(); + this.props.Document.selectedDoc = undefined; + } this._results.forEach(result => { Doc.UnBrushDoc(result[0]); result[0].searchMatch = undefined; @@ -235,7 +258,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc @action filterDocsByType(docs: Doc[]) { const finalDocs: Doc[] = []; - const blockedTypes: string[] = ["preselement", "docholder", "collection", "search", "searchitem", "script", "fonticonbox", "button", "label"]; + const blockedTypes: string[] = ["preselement", "docholder", "search", "searchitem", "script", "fonticonbox", "button", "label"]; docs.forEach(doc => { const layoutresult = Cast(doc.type, "string"); if (layoutresult && !blockedTypes.includes(layoutresult)) { @@ -299,6 +322,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc searchCollection(query: string) { const selectedCollection: DocumentView = SelectionManager.SelectedDocuments()[0]; query = query.toLowerCase(); + if (selectedCollection !== undefined) { this.currentSelectedCollection = selectedCollection; if (this.filter === true) { @@ -312,6 +336,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc while (docs.length > 0) { newarray = []; docs.forEach((d) => { + d ? console.log(Cast(d.context, Doc)) : null; if (d.data !== undefined) { newarray.push(...DocListCast(d.data)); } @@ -412,10 +437,33 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc @action submitSearch = async (reset?: boolean) => { + if (this.currentSelectedCollection !== undefined) { + let newarray: Doc[] = []; + let docs: Doc[] = []; + docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); + while (docs.length > 0) { + newarray = []; + docs.forEach((d) => { + if (d.data !== undefined) { + d._searchDocs = new List<Doc>(); + d._docFilters = new List(); + const newdocs = DocListCast(d.data); + newdocs.forEach((newdoc) => { + newarray.push(newdoc); + }); + } + }); + docs = newarray; + } + + this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]); + this.currentSelectedCollection.props.Document._docFilters = new List(); + this.props.Document.selectedDoc = undefined; + } if (reset) { this.layoutDoc._searchString = ""; } - this.props.Document._docFilters = undefined; + this.props.Document._docFilters = new List(); this.noresults = ""; this.dataDoc[this.fieldKey] = new List<Doc>([]); @@ -586,7 +634,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc y += 300; } } - return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString), searchQuery: StrCast(this.layoutDoc._searchString) }); + return Docs.Create.SchemaDocument(Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []), DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) }); } @action.bound @@ -628,7 +676,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc const endIndex = 30; //this._endIndex = endIndex === -1 ? 12 : endIndex; this._endIndex = 30; - const headers = new Set<string>(["title", "author", "*lastModified", "text"]); + const headers = new Set<string>(["title", "author", "*lastModified"]); if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) { if (this.noresults === "") { this.noresults = "No search results :("; @@ -733,6 +781,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); } + @computed get viewspec() { return Cast(this.props.Document._docFilters, listSpec("string"), []) } + getTransform = () => { return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight } @@ -749,7 +799,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc @observable filter = false; - //Make id layour document render() { this.props.Document._chromeStatus === "disabled"; this.props.Document._searchDoc = true; @@ -758,47 +807,67 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc cols > 5 ? length = 1076 : length = cols * 205 + 51; let height = 0; const rows = this.children; - rows > 8 ? height = 31 + 31 * 8 : height = 31 * rows + 31; + rows > 6 ? height = 31 + 31 * 6 : height = 31 * rows + 31; return ( <div style={{ pointerEvents: "all" }} className="searchBox-container"> <div className="searchBox-bar"> <div style={{ position: "absolute", left: 15 }}>{Doc.CurrentUserEmail}</div> <div style={{ display: "flex", alignItems: "center" }}> - <FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg" - style={{ color: "black", padding: 1, left: 35, position: "relative" }} /> - + <Tooltip title={<div className="dash-tooltip" >drag search results as collection</div>} ><div> + <FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg" + style={{ cursor: "hand", color: "black", padding: 1, left: 35, position: "relative" }} /> + </div></Tooltip> <div style={{ cursor: "default", left: 250, position: "relative", }}> <Tooltip title={<div className="dash-tooltip" >only display documents matching search</div>} ><div> <FontAwesomeIcon icon={"filter"} size="lg" - style={{ padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }} + style={{ cursor: "hand", padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }} onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined); }} onClick={action(() => { - const dofilter = (currentSelectedCollection: DocumentView) => { - let docs = DocListCast(currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(currentSelectedCollection.dataDoc)]); + ///DONT Change without emailing andy r first. + this.filter = !this.filter && !this.searchFullDB; + if (this.filter === true && this.currentSelectedCollection !== undefined) { + this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>(this.docsforfilter); + let newarray: Doc[] = []; + let docs: Doc[] = []; + docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); while (docs.length > 0) { - const newarray: Doc[] = []; - docs.filter(d => d.data !== undefined).forEach((d) => { - d._searchDocs = new List<Doc>(this.docsforfilter); - newarray.push(...DocListCast(d.data)); + newarray = []; + docs.forEach((d) => { + if (d.data !== undefined) { + d._searchDocs = new List<Doc>(this.docsforfilter); + const newdocs = DocListCast(d.data); + newdocs.forEach((newdoc) => { + newarray.push(newdoc); + }); + } }); docs = newarray; } - }; - this.filter = !this.filter && !this.searchFullDB; - if (this.filter === true && this.currentSelectedCollection !== undefined) { - this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>(this.docsforfilter); - dofilter(this.currentSelectedCollection); - - this.currentSelectedCollection.props.Document._docFilters = new List<string>(Cast(this.props.Document._docFilters, listSpec("string"), [])); + this.currentSelectedCollection.props.Document._docFilters = new List<string>(this.viewspec); this.props.Document.selectedDoc = this.currentSelectedCollection.props.Document; } else if (this.filter === false && this.currentSelectedCollection !== undefined) { - - dofilter(this.currentSelectedCollection); + let newarray: Doc[] = []; + let docs: Doc[] = []; + docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); + while (docs.length > 0) { + newarray = []; + docs.forEach((d) => { + if (d.data !== undefined) { + d._searchDocs = new List<Doc>(); + d._docFilters = new List(); + const newdocs = DocListCast(d.data); + newdocs.forEach((newdoc) => { + newarray.push(newdoc); + }); + } + }); + docs = newarray; + } this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]); - this.currentSelectedCollection.props.Document._docFilters = undefined; + this.currentSelectedCollection.props.Document._docFilters = new List(); this.props.Document.selectedDoc = undefined; } } @@ -832,6 +901,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc docs.forEach((d) => { if (d.data !== undefined) { d._searchDocs = new List<Doc>(); + d._docFilters = new List(); const newdocs = DocListCast(d.data); newdocs.forEach((newdoc) => { newarray.push(newdoc); @@ -840,7 +910,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc }); docs = newarray; } - this.currentSelectedCollection.props.Document._docFilters = undefined; + this.currentSelectedCollection.props.Document._docFilters = new List(); this.currentSelectedCollection.props.Document._searchDocs = undefined; this.currentSelectedCollection = undefined; } @@ -866,6 +936,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc docs.forEach((d) => { if (d.data !== undefined) { d._searchDocs = new List<Doc>(); + d._docFilters = new List() const newdocs = DocListCast(d.data); newdocs.forEach((newdoc) => { newarray.push(newdoc); @@ -874,7 +945,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc }); docs = newarray; } - this.currentSelectedCollection.props.Document._docFilters = undefined; + this.currentSelectedCollection.props.Document._docFilters = new List(); this.currentSelectedCollection.props.Document._searchDocs = undefined; this.currentSelectedCollection = undefined; } @@ -900,7 +971,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc removeDocument={returnFalse} PanelHeight={this.open === true ? () => height : () => 0} PanelWidth={this.open === true ? () => length : () => 0} - overflow={cols > 5 || rows > 8 ? true : false} + overflow={cols > 5 || rows > 6 ? true : false} focus={this.selectElement} ScreenToLocalTransform={Transform.Identity} /> @@ -920,4 +991,4 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc </div > ); } -} +}
\ No newline at end of file diff --git a/src/server/websocket.ts b/src/server/websocket.ts index f9351ba05..18c5ece98 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -230,7 +230,6 @@ export namespace WebSocket { "RichTextField": ["_t", value => value.Text], "date": ["_d", value => new Date(value.date).toISOString()], "proxy": ["_i", "fieldId"], - // "proxy": ["", "fieldId"], "list": ["_l", list => { const results = []; for (const value of list.fields) { |