aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-08-05 17:28:15 -0400
committerbobzel <zzzman@gmail.com>2020-08-05 17:28:15 -0400
commit50ddaaab31351ad277fbd2ebb4405a99a721a536 (patch)
tree9a41e3f3d15365807b95413ba1603f00c2433123 /src
parentf9e34ffc8b21780d966a149e5ba4459c602a6eed (diff)
parentd254d35d8d1fc10e9ca7ef5b9db06cd138b2d102 (diff)
Merge branch 'master' into menu_restructure
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts3
-rw-r--r--src/client/apis/HypothesisAuthenticationManager.tsx2
-rw-r--r--src/client/documents/DocumentTypes.ts3
-rw-r--r--src/client/documents/Documents.ts18
-rw-r--r--src/client/util/CurrentUserUtils.ts44
-rw-r--r--src/client/util/Scripting.ts2
-rw-r--r--src/client/util/SearchUtil.ts2
-rw-r--r--src/client/views/EditableView.tsx41
-rw-r--r--src/client/views/MainView.scss3
-rw-r--r--src/client/views/MainView.tsx52
-rw-r--r--src/client/views/PropertiesButtons.tsx5
-rw-r--r--src/client/views/SearchDocBox.tsx428
-rw-r--r--src/client/views/collections/CollectionMenu.tsx48
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx132
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx82
-rw-r--r--src/client/views/collections/CollectionSchemaMovableTableHOC.tsx18
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss34
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx44
-rw-r--r--src/client/views/collections/CollectionSubView.tsx67
-rw-r--r--src/client/views/collections/CollectionView.tsx7
-rw-r--r--src/client/views/collections/SchemaTable.tsx96
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx2
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx1
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx2
-rw-r--r--src/client/views/nodes/FieldView.tsx7
-rw-r--r--src/client/views/nodes/LabelBox.tsx14
-rw-r--r--src/client/views/nodes/QueryBox.tsx71
-rw-r--r--src/client/views/nodes/WebBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx35
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx3
-rw-r--r--src/client/views/pdf/PDFViewer.tsx6
-rw-r--r--src/client/views/search/FieldFilters.scss12
-rw-r--r--src/client/views/search/FieldFilters.tsx41
-rw-r--r--src/client/views/search/FilterBox.scss178
-rw-r--r--src/client/views/search/FilterBox.tsx431
-rw-r--r--src/client/views/search/SearchBox.scss69
-rw-r--r--src/client/views/search/SearchBox.tsx731
-rw-r--r--src/client/views/search/SearchItem.scss163
-rw-r--r--src/client/views/search/SearchItem.tsx310
-rw-r--r--src/fields/Doc.ts2
-rw-r--r--src/server/ApiManagers/SearchManager.ts2
-rw-r--r--src/server/ApiManagers/UploadManager.ts36
-rw-r--r--src/server/websocket.ts14
45 files changed, 1185 insertions, 2084 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 6fa8cf909..2fe3e9778 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -372,6 +372,9 @@ export namespace DocServer {
} else if (cached instanceof Promise) {
proms.push(cached as any);
}
+ } else if (field) {
+ proms.push(_cache[field.id] as any);
+ fieldMap[field.id] = field;
}
}
});
diff --git a/src/client/apis/HypothesisAuthenticationManager.tsx b/src/client/apis/HypothesisAuthenticationManager.tsx
index c3e8d2fff..bc95b5f9a 100644
--- a/src/client/apis/HypothesisAuthenticationManager.tsx
+++ b/src/client/apis/HypothesisAuthenticationManager.tsx
@@ -18,7 +18,7 @@ export default class HypothesisAuthenticationManager extends React.Component<{}>
@observable private showPasteTargetState = false;
@observable private success: Opt<boolean> = undefined;
@observable private displayLauncher = true;
- @observable private credentials: string;
+ @observable private credentials: string = "";
private disposer: Opt<IReactionDisposer>;
private set isOpen(value: boolean) {
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 985fcce11..71d6c2ccc 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -13,7 +13,7 @@ export enum DocumentType {
INK = "ink", // ink stroke
SCREENSHOT = "screenshot", // view of a desktop application
FONTICON = "fonticonbox", // font icon
- QUERY = "query", // search query
+ SEARCH = "search", // search query
LABEL = "label", // simple text label
BUTTON = "button", // onClick button
WEBCAM = "webcam", // webcam
@@ -31,6 +31,7 @@ export enum DocumentType {
COLOR = "color", // color picker (view of a color picker for a color string)
YOUTUBE = "youtube", // youtube directory (view of you tube search results)
DOCHOLDER = "docholder", // nested document (view of a document)
+ SEARCHITEM= "searchitem",
COMPARISON = "comparison", // before/after view with slider (view of 2 images)
GROUP = "group", // group of users
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dbff6a46c..b809a73b7 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -21,6 +21,8 @@ import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
import { LinkManager } from "../util/LinkManager";
import { Scripting } from "../util/Scripting";
import { UndoManager } from "../util/UndoManager";
+import { DocumentType } from "./DocumentTypes";
+import { SearchBox } from "../views/search/SearchBox";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
import { ContextMenu } from "../views/ContextMenu";
@@ -38,7 +40,6 @@ import { LabelBox } from "../views/nodes/LabelBox";
import { LinkBox } from "../views/nodes/LinkBox";
import { PDFBox } from "../views/nodes/PDFBox";
import { PresBox } from "../views/nodes/PresBox";
-import { QueryBox } from "../views/nodes/QueryBox";
import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
import { ScriptingBox } from "../views/nodes/ScriptingBox";
import { SliderBox } from "../views/nodes/SliderBox";
@@ -46,7 +47,6 @@ import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
import { PresElementBox } from "../views/presentationview/PresElementBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
-import { DocumentType } from "./DocumentTypes";
import { Networking } from "../Network";
import { Upload } from "../../server/SharedMediaTypes";
const path = require('path');
@@ -189,10 +189,10 @@ export interface DocumentOptions {
flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
selectedIndex?: number;
syntaxColor?: string; // can be applied to text for syntax highlighting all matches in the text
- searchText?: string; //for searchbox
- searchQuery?: string; // for queryBox
- filterQuery?: string;
+ searchQuery?: string; // for quersyBox
linearViewIsExpanded?: boolean; // is linear view expanded
+ border?: string; //for searchbox
+ hovercolor?: string;
}
class EmptyBox {
@@ -222,8 +222,8 @@ export namespace Docs {
layout: { view: FormattedTextBox, dataField: "text" },
options: { _height: 150, _xMargin: 10, _yMargin: 10 }
}],
- [DocumentType.QUERY, {
- layout: { view: QueryBox, dataField: defaultDataKey },
+ [DocumentType.SEARCH, {
+ layout: { view: SearchBox, dataField: defaultDataKey },
options: { _width: 400 }
}],
[DocumentType.COLOR, {
@@ -630,8 +630,8 @@ export namespace Docs {
return instance;
}
- export function QueryDocument(options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.QUERY), "", options);
+ export function SearchDocument(options: DocumentOptions = {}) {
+ return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List<Doc>([]), options);
}
export function ColorDocument(options: DocumentOptions = {}) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 630952ccf..70a4ceb68 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -45,7 +45,7 @@ export class CurrentUserUtils {
if (doc["template-button-query"] === undefined) {
const queryTemplate = Docs.Create.MulticolumnDocument(
[
- Docs.Create.QueryDocument({ title: "query", _height: 200 }),
+ Docs.Create.SearchDocument({ _viewType: CollectionViewType.Schema, ignoreClick: true, forceActive: true, lockedPosition: true, title: "query", _height: 200 }),
Docs.Create.FreeformDocument([], { title: "data", _height: 100 })
],
{ _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
@@ -415,9 +415,6 @@ export class CurrentUserUtils {
if (doc.emptyButton === undefined) {
doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button" });
}
- if (doc.emptySearch === undefined) {
- doc.emptySearch = Docs.Create.QueryDocument({ _width: 200, title: "empty search" });
- }
if (doc.emptyDocHolder === undefined) {
doc.emptyDocHolder = Docs.Create.DocumentDocument(
ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any,
@@ -512,6 +509,14 @@ export class CurrentUserUtils {
];
}
+ static setupSearchPanel(doc: Doc) {
+ if (doc["search-panel"] === undefined) {
+ doc["search-panel"] = new PrefetchProxy(Docs.Create.SearchDocument({
+ _width: 500, _height: 400, backgroundColor: "dimGray", ignoreClick: true,
+ childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, _chromeStatus: "disabled", title: "sidebar search stack",
+ })) as any as Doc;
+ }
+ }
static setupMenuPanel(doc: Doc) {
if (doc.menuStack === undefined) {
const menuBtns = CurrentUserUtils.menuBtnDescriptions().map(({ title, icon, click }) =>
@@ -546,7 +551,7 @@ export class CurrentUserUtils {
btn.color = "white";
btn._backgroundColor = "";
}));
- })
+ });
});
return doc.menuStack as Doc;
}
@@ -652,7 +657,7 @@ export class CurrentUserUtils {
// setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
// when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
- static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) {
+ static async setupToolsBtnPanel(doc: Doc) {
// setup a masonry view of all he creators
const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
@@ -750,6 +755,8 @@ export class CurrentUserUtils {
})) as any as Doc;
}
}
+
+
static setupUserDoc(doc: Doc) {
if (doc["sidebar-userDoc"] === undefined) {
doc.treeViewOpen = true;
@@ -762,20 +769,9 @@ export class CurrentUserUtils {
}
}
- static setupSidebarContainer(doc: Doc) {
- if (doc["sidebar"] === undefined) {
- const sidebarContainer = new Doc();
- sidebarContainer._chromeStatus = "disabled";
- sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
- doc["sidebar"] = new PrefetchProxy(sidebarContainer);
- }
- return doc["sidebar"] as Doc;
- }
-
// setup the list of sidebar mode buttons which determine what is displayed in the sidebar
static async setupSidebarButtons(doc: Doc) {
- const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc);
- await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
+ await CurrentUserUtils.setupToolsBtnPanel(doc);
CurrentUserUtils.setupWorkspaces(doc);
CurrentUserUtils.setupCatalog(doc);
CurrentUserUtils.setupRecentlyClosed(doc);
@@ -813,6 +809,11 @@ export class CurrentUserUtils {
// the initial presentation Doc to use
static setupDefaultPresentation(doc: Doc) {
+ if (doc["template-presentation"] === undefined) {
+ doc["template-presentation"] = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
+ title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data"
+ }));
+ }
if (doc.activePresentation === undefined) {
doc.activePresentation = Docs.Create.PresDocument(new List<Doc>(), {
title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias",
@@ -822,9 +823,9 @@ export class CurrentUserUtils {
}
// Right sidebar is where mobile uploads are contained
- static setupRightSidebar(doc: Doc) {
+ static setupSharingSidebar(doc: Doc) {
if (doc["sidebar-sharing"] === undefined) {
- doc["sidebar-sharing"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Mobile Uploads" }));
+ doc["sidebar-sharing"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Sharing Sidebar" }));
}
}
@@ -897,9 +898,10 @@ export class CurrentUserUtils {
Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]);
this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
this.setupDocTemplates(doc); // sets up the template menu of templates
- this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
+ this.setupSharingSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile
this.setupMenuPanel(doc);
+ 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
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index f1e6155d2..cb0a4bea0 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -134,7 +134,7 @@ export function scriptingGlobal(constructor: { new(...args: any[]): any }) {
Scripting.addGlobal(constructor);
}
-const _scriptingGlobals: { [name: string]: any } = {};
+export const _scriptingGlobals: { [name: string]: any } = {};
let scriptingGlobals: { [name: string]: any } = _scriptingGlobals;
const _scriptingDescriptions: { [name: string]: any } = {};
const _scriptingParams: { [name: string]: any } = {};
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 0a01d8ac7..7b2c601fe 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -29,6 +29,8 @@ export namespace SearchUtil {
rows?: number;
fq?: string;
allowAliases?: boolean;
+ "facet"?: string;
+ "facet.field"?: string;
}
export function Search(query: string, returnDocs: true, options?: SearchParams): Promise<DocSearchResult>;
export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index f9d060681..ec3e754fb 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -6,6 +6,8 @@ import { ObjectField } from '../../fields/ObjectField';
import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
import "./EditableView.scss";
import { DragManager } from '../util/DragManager';
+import { ComputedField } from '../../fields/ScriptField';
+import { FieldValue } from '../../fields/Types';
export interface EditableProps {
/**
@@ -52,6 +54,10 @@ export interface EditableProps {
color?: string | undefined;
onDrop?: any;
placeholder?: string;
+ highlight?: boolean;
+ positions?: number[];
+ search?: string;
+ bing?: () => string | undefined;
}
/**
@@ -179,6 +185,34 @@ export class EditableView extends React.Component<EditableProps> {
placeholder={this.props.placeholder}
/>;
}
+
+ returnHighlights() {
+ const results = [];
+ const contents = this.props.bing!();
+
+ if (contents !== undefined) {
+ if (this.props.positions !== undefined) {
+ const positions = this.props.positions;
+ const length = this.props.search!.length;
+
+ // contents = String(this.props.contents.valueOf());
+
+ results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(0, this.props.positions[0]) : this.props.placeholder?.valueOf()}</span>);
+ positions.forEach((num, cur) => {
+ results.push(<span style={{ backgroundColor: "#FFFF00", fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num, num + length) : this.props.placeholder?.valueOf()}</span>);
+ let end = 0;
+ cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
+ results.push(<span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{contents ? contents.slice(num + length, end) : this.props.placeholder?.valueOf()}</span>);
+ }
+ );
+ }
+ return results;
+ }
+ else {
+ return <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>;
+ }
+ }
+
render() {
if (this._editing && this.props.GetValue() !== undefined) {
return this.props.sizeToContent ?
@@ -193,11 +227,8 @@ export class EditableView extends React.Component<EditableProps> {
ref={this._ref}
style={{ display: this.props.display, minHeight: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
onClick={this.onClick} placeholder={this.props.placeholder}>
- <span style={{
- fontStyle: this.props.fontStyle, fontSize: this.props.fontSize,
- color: this.props.contents ? this.props.color ? this.props.color : "black" : "grey"
- }}>
- {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>
+ {this.props.highlight === undefined || this.props.positions === undefined || this.props.bing === undefined ? <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize, color: this.props.contents ? "black" : "grey" }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>
+ : this.returnHighlights()}
</div>
);
}
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 388d4b369..35c135633 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -215,12 +215,11 @@
.mainView-searchPanel {
width: 100%;
- height: 33px;
+ height: 32px;
background-color: black;
color: white;
text-align: center;
vertical-align: middle;
- padding-top: 6px;
}
.mainView-mainDiv {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a6a33d9f7..7a4cb5759 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -60,6 +60,7 @@ import { OverlayView } from './OverlayView';
import PDFMenu from './pdf/PDFMenu';
import { PreviewCursor } from './PreviewCursor';
import { undoBatch } from '../util/UndoManager';
+import { SearchBox } from './search/SearchBox';
@observer
export class MainView extends React.Component {
@@ -79,8 +80,10 @@ export class MainView extends React.Component {
@computed private get userDoc() { return Doc.UserDoc(); }
@computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
@computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
+ @computed public get searchDoc() { return Cast(this.userDoc["search-panel"], Doc) as Doc; }
- @observable public sidebarContent: any = this.userDoc?.["sidebar"];
+ sidebar: string = "sidebar";
+ @observable public sidebarContent: any = this.userDoc?.[this.sidebar];
@observable public panelContent: string = "none";
@observable public showProperties: boolean = false;
public isPointerDown = false;
@@ -188,6 +191,20 @@ export class MainView extends React.Component {
if (targets && (targets.length && targets[0].className.toString() !== "timeline-menu-desc" && targets[0].className.toString() !== "timeline-menu-item" && targets[0].className.toString() !== "timeline-menu-input")) {
TimelineMenu.Instance.closeMenu();
}
+ if (targets && targets.length && SearchBox.Instance._searchbarOpen) {
+ 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") {
+ check = true;
+ }
+ });
+ if (check === false) {
+ SearchBox.Instance.closeSearch();
+ }
+ }
+
+
});
globalPointerUp = () => this.isPointerDown = false;
@@ -347,6 +364,7 @@ export class MainView extends React.Component {
}
}
}
+
@computed get mainDocView() {
return <DocumentView
Document={this.mainContainer!}
@@ -375,6 +393,7 @@ export class MainView extends React.Component {
renderDepth={-1}
/>;
}
+
@computed get dockingContent() {
TraceMobx();
const mainContainer = this.mainContainer;
@@ -602,7 +621,6 @@ export class MainView extends React.Component {
}
@computed get mainContent() {
- //const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
const n = (CollectionMenu.Instance?.Pinned ? 1 : 0);
const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`;
const pinned = FormatShapePane.Instance?.Pinned;
@@ -725,8 +743,32 @@ export class MainView extends React.Component {
@computed get search() {
return <div className="mainView-searchPanel">
- <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div>
- <div>SEARCH GOES HERE</div>
+ {/* <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div> */}
+ <div><DocumentView Document={this.searchDoc}
+ DataDoc={undefined}
+ LibraryPath={emptyPath}
+ addDocument={undefined}
+ addDocTab={this.addDocTabFunc}
+ pinToPres={emptyFunction}
+ rootSelected={returnTrue}
+ onClick={undefined}
+ backgroundColor={this.defaultBackgroundColors}
+ removeDocument={undefined}
+ ScreenToLocalTransform={Transform.Identity}
+ ContentScaling={returnOne}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ PanelWidth={this.getPWidth}
+ PanelHeight={this.getPHeight}
+ renderDepth={0}
+ focus={emptyFunction}
+ parentActive={returnTrue}
+ whenActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ /></div>
</div>;
}
@@ -741,7 +783,7 @@ export class MainView extends React.Component {
<GoogleAuthenticationManager />
<HypothesisAuthenticationManager />
<DocumentDecorations />
- {/* {this.search} */}
+ {this.search}
<CollectionMenu />
<FormatShapePane />
<div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 14ea36dde..738dbc75b 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -28,7 +28,6 @@ import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
import { ImageField } from '../../fields/URLField';
import { undoBatch, UndoManager } from '../util/UndoManager';
import { DocumentType } from '../documents/DocumentTypes';
-import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView';
import { InkField } from '../../fields/InkField';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
@@ -128,7 +127,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const targetDoc = this.selectedDoc;
const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none";
- return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div></>} placement="top">
+ return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div>} placement="top">
<div>
<div
className="propertiesButtons-linker"
@@ -428,7 +427,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-linkFlyout">
<Flyout anchorPoint={anchorPoints.LEFT_TOP}
content={this.onClickFlyout}>
- <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+ <div className={"propertiesButtons-linkButton-empty"} onPointerDown={e => e.stopPropagation()} >
{<FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />}
</div>
</Flyout>
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
deleted file mode 100644
index 084f952a3..000000000
--- a/src/client/views/SearchDocBox.tsx
+++ /dev/null
@@ -1,428 +0,0 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-//import "./SearchBoxDoc.scss";
-import { Doc, DocListCast } from "../../fields/Doc";
-import { Id } from "../../fields/FieldSymbols";
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
-import { returnFalse, returnZero } from "../../Utils";
-import { Docs } from "../documents/Documents";
-import { SearchUtil } from "../util/SearchUtil";
-import { EditableView } from "./EditableView";
-import { ContentFittingDocumentView } from "./nodes/ContentFittingDocumentView";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { FilterBox } from "./search/FilterBox";
-import { SearchItem } from "./search/SearchItem";
-import React = require("react");
-
-export interface RecProps {
- documents: { preview: Doc, similarity: number }[];
- node: Doc;
-
-}
-
-library.add(faBullseye, faLink);
-export const keyPlaceholder = "Query";
-
-@observer
-export class SearchDocBox extends React.Component<FieldViewProps> {
-
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchDocBox, fieldKey); }
-
- // @observable private _display: boolean = false;
- @observable private _pageX: number = 0;
- @observable private _pageY: number = 0;
- @observable private _width: number = 0;
- @observable private _height: number = 0;
- @observable.shallow private _docViews: JSX.Element[] = [];
- // @observable private _documents: { preview: Doc, score: number }[] = [];
- private previewDocs: Doc[] = [];
-
- constructor(props: FieldViewProps) {
- super(props);
- this.editingMetadata = this.editingMetadata || false;
- //SearchBox.Instance = this;
- this.resultsScrolled = this.resultsScrolled.bind(this);
- }
-
-
- @computed
- private get editingMetadata() {
- return BoolCast(this.props.Document.editingMetadata);
- }
-
- private set editingMetadata(value: boolean) {
- this.props.Document.editingMetadata = value;
- }
-
- static readonly buffer = 20;
-
- componentDidMount() {
- runInAction(() => {
- this.query = StrCast(this.props.Document.searchText);
- this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query }));
-
- });
- if (this.inputRef.current) {
- this.inputRef.current.focus();
- runInAction(() => {
- this._searchbarOpen = true;
- });
- }
- }
-
- @observable
- private content: Doc | undefined;
-
- @action
- updateKey = async (newKey: string) => {
- this.query = newKey;
- if (newKey.length > 1) {
- const newdocs = await this.getAllResults(this.query);
- const things = newdocs.docs;
- runInAction(() => {
- this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
- });
- }
-
-
- //this.keyRef.current && this.keyRef.current.setIsFocused(false);
- //this.query.length === 0 && (this.query = keyPlaceholder);
- return true;
- }
-
- @computed
- public get query() {
- return StrCast(this.props.Document.query);
- }
-
- public set query(value: string) {
- this.props.Document.query = value;
- }
-
- @observable private _searchString: string = "";
- @observable private _resultsOpen: boolean = false;
- @observable private _searchbarOpen: boolean = false;
- @observable private _results: [Doc, string[], string[]][] = [];
- private _resultsSet = new Map<Doc, number>();
- @observable private _openNoResults: boolean = false;
- @observable private _visibleElements: JSX.Element[] = [];
-
- private resultsRef = React.createRef<HTMLDivElement>();
- public inputRef = React.createRef<HTMLInputElement>();
-
- private _isSearch: ("search" | "placeholder" | undefined)[] = [];
- private _numTotalResults = -1;
- private _endIndex = -1;
-
-
- private _maxSearchIndex: number = 0;
- private _curRequest?: Promise<any> = undefined;
-
- @action
- getViews = async (doc: Doc) => {
- const results = await SearchUtil.GetViewsOfDocument(doc);
- let toReturn: Doc[] = [];
- await runInAction(() => {
- toReturn = results;
- });
- return toReturn;
- }
-
- @action.bound
- onChange(e: React.ChangeEvent<HTMLInputElement>) {
- this._searchString = e.target.value;
-
- this._openNoResults = false;
- this._results = [];
- this._resultsSet.clear();
- this._visibleElements = [];
- this._numTotalResults = -1;
- this._endIndex = -1;
- this._curRequest = undefined;
- this._maxSearchIndex = 0;
- }
-
- enter = async (e: React.KeyboardEvent) => {
- if (e.key === "Enter") {
- const newdocs = await this.getAllResults(this.query);
- this.content = Docs.Create.TreeDocument(newdocs.docs, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
- }
- }
-
-
- @action
- submitSearch = async () => {
- let query = this._searchString;
- query = FilterBox.Instance.getFinalQuery(query);
- this._results = [];
- this._resultsSet.clear();
- this._isSearch = [];
- this._visibleElements = [];
- FilterBox.Instance.closeFilter();
-
- //if there is no query there should be no result
- if (query === "") {
- return;
- }
- else {
- this._endIndex = 12;
- this._maxSearchIndex = 0;
- this._numTotalResults = -1;
- await this.getResults(query);
- }
-
- runInAction(() => {
- this._resultsOpen = true;
- this._searchbarOpen = true;
- this._openNoResults = true;
- this.resultsScrolled();
- });
- }
-
- getAllResults = async (query: string) => {
- return SearchUtil.Search(query, true, { fq: this.filterQuery, start: 0, rows: 10000000 });
- }
-
- private get filterQuery() {
- const types = FilterBox.Instance.filterTypes;
- const includeDeleted = FilterBox.Instance.getDataStatus();
- return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted_b:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}" OR type_t:"extension"`).join(" ")})` : "");
- }
-
-
- private NumResults = 25;
- private lockPromise?: Promise<void>;
- getResults = async (query: string) => {
- if (this.lockPromise) {
- await this.lockPromise;
- }
- this.lockPromise = new Promise(async res => {
- while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
- this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*" }).then(action(async (res: SearchUtil.DocSearchResult) => {
-
- // happens at the beginning
- if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
- this._numTotalResults = res.numFound;
- }
-
- const highlighting = res.highlighting || {};
- const highlightList = res.docs.map(doc => highlighting[doc[Id]]);
- const lines = new Map<string, string[]>();
- res.docs.map((doc, i) => lines.set(doc[Id], res.lines[i]));
- const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc));
- const highlights: typeof res.highlighting = {};
- docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]);
- const filteredDocs = FilterBox.Instance.filterDocsByType(docs);
- runInAction(() => {
- // this._results.push(...filteredDocs);
- filteredDocs.forEach(doc => {
- const index = this._resultsSet.get(doc);
- const highlight = highlights[doc[Id]];
- const line = lines.get(doc[Id]) || [];
- const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
- if (index === undefined) {
- this._resultsSet.set(doc, this._results.length);
- this._results.push([doc, hlights, line]);
- } else {
- this._results[index][1].push(...hlights);
- this._results[index][2].push(...line);
- }
- });
- });
-
- this._curRequest = undefined;
- }));
- this._maxSearchIndex += this.NumResults;
-
- await this._curRequest;
- }
- this.resultsScrolled();
- res();
- });
- return this.lockPromise;
- }
-
- collectionRef = React.createRef<HTMLSpanElement>();
- startDragCollection = async () => {
- const res = await this.getAllResults(FilterBox.Instance.getFinalQuery(this._searchString));
- const filtered = FilterBox.Instance.filterDocsByType(res.docs);
- const docs = filtered.map(doc => {
- const isProto = Doc.GetT(doc, "isPrototype", "boolean", true);
- if (isProto) {
- return Doc.MakeDelegate(doc);
- } else {
- return Doc.MakeAlias(doc);
- }
- });
- let x = 0;
- let y = 0;
- for (const doc of docs.map(d => Doc.Layout(d))) {
- doc.x = x;
- doc.y = y;
- const size = 200;
- const aspect = NumCast(doc._nativeHeight) / NumCast(doc._nativeWidth, 1);
- if (aspect > 1) {
- doc._height = size;
- doc._width = size / aspect;
- } else if (aspect > 0) {
- doc._width = size;
- doc._height = size * aspect;
- } else {
- doc._width = size;
- doc._height = size;
- }
- x += 250;
- if (x > 1000) {
- x = 0;
- y += 300;
- }
- }
- //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
- return Docs.Create.QueryDocument({ _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
- }
-
- @action.bound
- openSearch(e: React.SyntheticEvent) {
- e.stopPropagation();
- this._openNoResults = false;
- FilterBox.Instance.closeFilter();
- this._resultsOpen = true;
- this._searchbarOpen = true;
- FilterBox.Instance._pointerTime = e.timeStamp;
- }
-
- @action.bound
- closeSearch = () => {
- FilterBox.Instance.closeFilter();
- this.closeResults();
- this._searchbarOpen = false;
- }
-
- @action.bound
- closeResults() {
- this._resultsOpen = false;
- this._results = [];
- this._resultsSet.clear();
- this._visibleElements = [];
- this._numTotalResults = -1;
- this._endIndex = -1;
- this._curRequest = undefined;
- }
-
- @action
- resultsScrolled = (e?: React.UIEvent<HTMLDivElement>) => {
- if (!this.resultsRef.current) return;
- const scrollY = e ? e.currentTarget.scrollTop : this.resultsRef.current ? this.resultsRef.current.scrollTop : 0;
- const itemHght = 53;
- const startIndex = Math.floor(Math.max(0, scrollY / itemHght));
- const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this.resultsRef.current.getBoundingClientRect().height / itemHght)));
-
- this._endIndex = endIndex === -1 ? 12 : endIndex;
-
- if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
- this._visibleElements = [<div className="no-result">No Search Results</div>];
- return;
- }
-
- if (this._numTotalResults <= this._maxSearchIndex) {
- this._numTotalResults = this._results.length;
- }
-
- // only hit right at the beginning
- // visibleElements is all of the elements (even the ones you can't see)
- else if (this._visibleElements.length !== this._numTotalResults) {
- // undefined until a searchitem is put in there
- this._visibleElements = Array<JSX.Element>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
- // indicates if things are placeholders
- this._isSearch = Array<undefined>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
- }
-
- for (let i = 0; i < this._numTotalResults; i++) {
- //if the index is out of the window then put a placeholder in
- //should ones that have already been found get set to placeholders?
- if (i < startIndex || i > endIndex) {
- if (this._isSearch[i] !== "placeholder") {
- this._isSearch[i] = "placeholder";
- this._visibleElements[i] = <div className="searchBox-placeholder" key={`searchBox-placeholder-${i}`}>Loading...</div>;
- }
- }
- else {
- if (this._isSearch[i] !== "search") {
- let result: [Doc, string[], string[]] | undefined = undefined;
- if (i >= this._results.length) {
- this.getResults(this._searchString);
- if (i < this._results.length) result = this._results[i];
- if (result) {
- const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
- this._isSearch[i] = "search";
- }
- }
- else {
- result = this._results[i];
- if (result) {
- const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
- this._isSearch[i] = "search";
- }
- }
- }
- }
- }
- if (this._maxSearchIndex >= this._numTotalResults) {
- this._visibleElements.length = this._results.length;
- this._isSearch.length = this._results.length;
- }
- }
-
- @computed
- get resFull() { return this._numTotalResults <= 8; }
-
- @computed
- get resultHeight() { return this._numTotalResults * 70; }
-
- render() {
- const isEditing = this.editingMetadata;
- return !this.content ? (null) : (
- <div style={{ pointerEvents: "all" }}>
- <ContentFittingDocumentView {...this.props}
- Document={this.content}
- rootSelected={returnFalse}
- bringToFront={returnFalse}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- parentActive={this.props.active}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}>
- </ContentFittingDocumentView>
- <div
- style={{
- position: "absolute",
- right: 0,
- width: 20,
- height: 20,
- background: "black",
- pointerEvents: "all",
- opacity: 1,
- transition: "0.4s opacity ease",
- zIndex: 99,
- top: 0,
- }}
- title={"Add Metadata"}
- onClick={action(() => this.editingMetadata = !this.editingMetadata)}
- />
- <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", position: "absolute", top: 0, left: 0, height: 20, width: "-webkit-fill-available" }}>
- <EditableView
- contents={this.query}
- SetValue={this.updateKey}
- GetValue={() => ""}
- />
- </div>
- </div >
- );
- }
-
-} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 18c456cb9..9ae72ba53 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1,37 +1,35 @@
import React = require("react");
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction, runInAction, Lambda } from "mobx";
+import { Tooltip } from "@material-ui/core";
+import { action, computed, Lambda, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, Opt, Field } from "../../../fields/Doc";
-import { BoolCast, Cast, StrCast, NumCast } from "../../../fields/Types";
-import AntimodeMenu from "../AntimodeMenu";
-import "./CollectionMenu.scss";
-import { undoBatch } from "../../util/UndoManager";
-import { CollectionViewType, CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView";
-import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
-import { DragManager } from "../../util/DragManager";
-import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { List } from "../../../fields/List";
-import { EditableView } from "../EditableView";
+import { ColorState } from "react-color";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { Document } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
-import { listSpec } from "../../../fields/Schema";
-import FormatShapePane from "./collectionFreeForm/FormatShapePane";
-import { ActiveFillColor, SetActiveInkWidth, ActiveInkColor, SetActiveBezierApprox, SetActiveArrowEnd, SetActiveArrowStart, SetActiveFillColor, SetActiveInkColor } from "../InkingStroke";
-import GestureOverlay from "../GestureOverlay";
import { InkTool } from "../../../fields/InkField";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Document } from "../../../fields/documentSchemas";
-import { SelectionManager } from "../../util/SelectionManager";
-import { DocumentView } from "../nodes/DocumentView";
-import { ColorState } from "react-color";
+import { List } from "../../../fields/List";
import { ObjectField } from "../../../fields/ObjectField";
-import RichTextMenu from "../nodes/formattedText/RichTextMenu";
import { RichTextField } from "../../../fields/RichTextField";
+import { listSpec } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { DocUtils } from "../../documents/Documents";
-import { Tooltip } from "@material-ui/core";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
+import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
+import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { DragManager } from "../../util/DragManager";
+import { SelectionManager } from "../../util/SelectionManager";
+import { undoBatch } from "../../util/UndoManager";
+import AntimodeMenu from "../AntimodeMenu";
+import { EditableView } from "../EditableView";
+import GestureOverlay from "../GestureOverlay";
+import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
+import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
+import { DocumentView } from "../nodes/DocumentView";
+import RichTextMenu from "../nodes/formattedText/RichTextMenu";
+import "./CollectionMenu.scss";
+import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
@observer
export default class CollectionMenu extends AntimodeMenu {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index eecaf7672..d11d6a5ba 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -32,6 +32,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { DateField } from "../../../fields/DateField";
+import { RichTextField } from "../../../fields/RichTextField";
const path = require('path');
library.add(faExpand);
@@ -193,7 +194,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc);
const onItemDown = (e: React.PointerEvent) => {
- fieldIsDoc && SetupDrag(this._focusRef,
+ //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);
@@ -240,25 +242,72 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
// <FontAwesomeIcon icon="expand" size="sm" />
// </div>
// );
- trace();
-
-
-
+ const positions = [];
+ if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+ let term = "";
+ if (cfield !== undefined) {
+ if (cfield.Text !== undefined) {
+ term = cfield.Text;
+ }
+ else if (StrCast(cfield)) {
+ term = StrCast(cfield);
+ }
+ else {
+ term = String(NumCast(cfield));
+ }
+ }
+ term = term.toLowerCase();
+ const search = StrCast(this.props.Document._searchString).toLowerCase();
+ let start = term.indexOf(search);
+ let tally = 0;
+ if (start !== -1) {
+ positions.push(start);
+ }
+ while (start < contents.length && start !== -1) {
+ term = term.slice(start + search.length + 1);
+ tally += start + search.length + 1;
+ start = term.indexOf(search);
+ positions.push(tally + start);
+ }
+ if (positions.length > 1) {
+ positions.pop();
+ }
+ }
return (
- <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }} ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
+ <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={() => {
+ 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) {
+ 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";
@@ -272,6 +321,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
return val;
+
}
}}
@@ -827,3 +877,69 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
);
}
}
+
+
+@observer
+export class CollectionSchemaButtons extends CollectionSchemaCell {
+
+ render() {
+ // const reference = React.createRef<HTMLDivElement>();
+ // const onItemDown = (e: React.PointerEvent) => {
+ // (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined :
+ // SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
+ // };
+ const doc = this.props.rowProps.original;
+ let buttons: JSX.Element | undefined = undefined;
+ buttons = <div style={{
+ paddingTop: 8,
+ paddingLeft: 3,
+ }}><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>
+ <button onClick={() => {
+ {
+ doc.searchMatchAlt = false;
+ setTimeout(() => doc.searchMatchAlt = true, 0);
+ doc.searchIndex = NumCast(doc.searchIndex);
+ }
+ }} style={{ padding: 2 }}>
+ <FontAwesomeIcon icon="arrow-down" size="sm" />
+ </button></div>;
+ const type = StrCast(doc.type);
+ if (type === "pdf") {
+ buttons = <div><button
+ style={{
+ position: "relative",
+ height: 30,
+ width: 28,
+ left: 1,
+ }}
+
+ onClick={() => {
+ doc.searchMatch = false;
+ setTimeout(() => doc.searchMatch = true, 0);
+ doc.searchIndex = NumCast(doc.searchIndex);
+ }}>
+ <FontAwesomeIcon icon="arrow-down" size="sm" />
+ </button></div >;
+ }
+ else if (type !== "rtf") {
+ buttons = undefined;
+ }
+
+ if (BoolCast(this.props.Document._searchDoc) === true) {
+
+ }
+ else {
+ buttons = undefined;
+ }
+ return (
+ <div> {buttons}</div>
+ );
+ }
+}
+
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index efff4db98..e65adcf76 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -9,6 +9,8 @@ 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";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -76,14 +78,6 @@ export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHe
-
-
-
-
-
-
-
-
export interface ColumnMenuProps {
columnField: SchemaHeaderField;
// keyValue: string;
@@ -288,9 +282,10 @@ export interface KeysDropdownProps {
existingKeys: string[];
canAddNew: boolean;
addNew: boolean;
- onSelect: (oldKey: string, newKey: string, addnew: boolean) => void;
+ onSelect: (oldKey: string, newKey: string, addnew: boolean, filter?: string) => void;
setIsEditing: (isEditing: boolean) => void;
width?: string;
+ docs?: Doc[];
}
@observer
export class KeysDropdown extends React.Component<KeysDropdownProps> {
@@ -306,10 +301,23 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@action
onSelect = (key: string): void => {
- this.props.onSelect(this._key, key, this.props.addNew);
- this.setKey(key);
+ if (key.slice(0, this._key.length) === this._key && this._key !== key) {
+ const filter = key.slice(this._key.length - key.length);
+ this.props.onSelect(this._key, this._key, this.props.addNew, filter);
+ }
+ else {
+ this.props.onSelect(this._key, key, this.props.addNew);
+ this.setKey(key);
+ this._isOpen = false;
+ this.props.setIsEditing(false);
+ }
+ }
+
+ @action
+ onSelect2 = (key: string): void => {
+ this._searchTerm = this._searchTerm.slice(0, this._key.length) + key;
this._isOpen = false;
- this.props.setIsEditing(false);
+
}
@undoBatch
@@ -371,22 +379,53 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
});
// if search term does not already exist as a group type, give option to create new group type
- if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) {
- options.push(<div key={""} className="key-option" style={{
+ 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"
+ }}
+ onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
+ Create "{this._searchTerm}" key</div>);
+ }
+ }
+
+ return options;
+ }
+
+ 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) => {
+ const key = StrCast(doc[this._key]);
+ if (keyOptions.includes(key) === false && key.includes(temp)) {
+ keyOptions.push(key);
+ }
+ });
+
+
+ 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"
}}
- onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
- Create "{this._searchTerm}" key</div>);
- }
+ onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect2(key); }}>{key}</div>;
+ });
return options;
}
+
render() {
return (
- <div className="keys-dropdown" style={{ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" }}>
- <input className="keys-search" //style={{ width: this.props.width, maxWidth: "1000" }}
+ <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)}
onClick={(e) => {
@@ -395,10 +434,11 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
}} onFocus={this.onFocus} onBlur={this.onBlur}></input>
<div className="keys-options-wrapper" style={{
backgroundColor: "white",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ width: this.props.width, maxWidth: this.props.width,
}}
onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
- {this.renderOptions()}
+ {this._key === this._searchTerm.slice(0, this._key.length) ?
+ this.renderFilterOptions() : this.renderOptions()}
</div>
</div >
);
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index b77173b25..dade4f2f2 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -209,6 +209,14 @@ export class MovableRow extends React.Component<MovableRowProps> {
return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
}
+ @action
+ onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ console.log("yes");
+ if (e.key === "Backspace" || e.key === "Delete") {
+ undoBatch(() => this.props.removeDoc(this.props.rowInfo.original));
+ }
+ }
+
render() {
const { children = null, rowInfo } = this.props;
if (!rowInfo) {
@@ -227,14 +235,14 @@ export class MovableRow extends React.Component<MovableRowProps> {
if (this.props.rowWrapped) className += " row-wrapped";
return (
- <div className={className} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
- <div className="collectionSchema-row-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
- <ReactTableDefaults.TrComponent>
- <div className="row-dragger">
+ <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
+ <div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+ <ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown} >
+ {/* <div className="row-dragger">
<div className="row-option" onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
<div className="row-option" style={{ cursor: "grab" }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
<div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, "onRight")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
- </div>
+ </div> */}
{children}
</ReactTableDefaults.TrComponent>
</div>
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 5226a60f1..ba0a259c5 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -6,7 +6,7 @@
border-style: solid;
border-radius: $border-radius;
box-sizing: border-box;
- position: absolute;
+ position: relative;
top: 0;
width: 100%;
height: 100%;
@@ -25,7 +25,6 @@
.collectionSchemaView-tableContainer {
width: 100%;
height: 100%;
- overflow: scroll;
}
.collectionSchemaView-dividerDragger {
@@ -59,9 +58,7 @@
}
.rt-thead {
- width: calc(100% - 52px);
- margin-left: 50px;
-
+ width: 100%;
z-index: 100;
overflow-y: visible;
@@ -96,7 +93,7 @@
}
.rt-tbody {
- width: calc(100% - 2px);
+ width: 100%;
direction: rtl;
overflow: visible;
}
@@ -164,16 +161,6 @@
.collectionSchema-col {
height: 100%;
-
- .collectionSchema-col-wrapper {
- &.col-before {
- border-left: 2px solid red;
- }
-
- &.col-after {
- border-right: 2px solid red;
- }
- }
}
@@ -297,7 +284,6 @@ button.add-column {
background-color: white;
border: 1px solid lightgray;
padding: 2px 3px;
- overflow-x: hidden;
&:not(:first-child) {
border-top: 0;
@@ -525,14 +511,21 @@ button.add-column {
.collectionSchemaView-table {
width: 100%;
height: 100%;
- overflow: visible;
}
.reactTable-sub {
padding: 10px 30px;
background-color: rgb(252, 252, 252);
- width: calc(100% - 50px);
- margin-left: 50px;
+ width: 100%;
+
+ .rt-thead {
+ display:none;
+ }
+ .collectionSchemaView-table{
+ border: solid 1px;
+ overflow: hidden;
+ }
+
.row-dragger {
background-color: rgb(252, 252, 252);
@@ -567,7 +560,6 @@ button.add-column {
text-transform: uppercase;
cursor: pointer;
font-size: 10.5px;
- padding: 10px;
margin-left: 50px;
margin-top: 10px;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index f67e049fd..a003de0d3 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -4,27 +4,26 @@ import { faCog, faPlus, faSortDown, faSortUp, faTable } from '@fortawesome/free-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, untracked } from "mobx";
import { observer } from "mobx-react";
+import Measure from "react-measure";
import { Resize } from "react-table";
import "react-table/react-table.css";
import { Doc } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
-import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { Docs, DocumentOptions } from "../../documents/Documents";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { Cast, NumCast } from "../../../fields/Types";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils";
+import { SnappingManager } from "../../util/SnappingManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
import '../DocumentDecorations.scss';
+import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
import { KeysDropdown } from "./CollectionSchemaHeaders";
import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils";
-import { SnappingManager } from "../../util/SnappingManager";
-import Measure from "react-measure";
import { SchemaTable } from "./SchemaTable";
-import { TraceMobx } from "../../../fields/util";
library.add(faCog, faPlus, faSortUp, faSortDown);
library.add(faTable);
@@ -170,6 +169,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action
setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => {
const columns = this.columns;
+ columns.forEach(col => col.setDesc(undefined));
+
const index = columns.findIndex(c => c.heading === columnField.heading);
const column = columns[index];
column.setDesc(descending);
@@ -310,7 +311,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@undoBatch
@action
- changeColumns = (oldKey: string, newKey: string, addNew: boolean) => {
+ changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => {
const columns = this.columns;
if (columns === undefined) {
this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, "f1efeb")]);
@@ -325,6 +326,20 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
column.setHeading(newKey);
columns[index] = column;
this.columns = columns;
+ if (filter) {
+ Doc.setDocFilter(this.props.Document, newKey, filter, "match");
+ if (this.props.Document.selectedDoc !== undefined) {
+ const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
+ Doc.setDocFilter(doc, newKey, filter, "match");
+ }
+ }
+ else {
+ this.props.Document._docFilters = undefined;
+ if (this.props.Document.selectedDoc !== undefined) {
+ const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc;
+ doc._docFilters = undefined;
+ }
+ }
}
}
}
@@ -591,6 +606,10 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
}
}
+
+
+ onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ }
render() {
TraceMobx();
const menuContent = this.renderMenuContent;
@@ -608,14 +627,15 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
</Measure>
</div>;
-
return <div className="collectionSchemaView-container"
style={{
+ overflow: this.props.overflow === true ? "auto" : undefined,
pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
- width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%"
+ width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
- style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
+ style={{ backgroundColor: "white", width: `calc(100% - ${this.previewWidth()}px)` }}
+ onKeyPress={this.onKeyPress}
onPointerDown={this.onPointerDown}
onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.onExternalDrop(e, {})}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 3ebc6baca..4025e25f9 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,7 +1,7 @@
import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
import { basename } from 'path';
import CursorField from "../../../fields/CursorField";
-import { Doc, Opt, Field } from "../../../fields/Doc";
+import { Doc, Opt, Field, DocListCast } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
@@ -112,9 +112,10 @@ 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);
- let rawdocs: (Doc | Promise<Doc>)[] = [];
- if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+ if (rawdocs.length !== 0) {
+ } else 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);
@@ -126,11 +127,66 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}
const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
+ 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 docsforFilter: Doc[] = childDocs;
+ if (searchDocs !== undefined && searchDocs.length > 0) {
+ docsforFilter = [];
+ // let newdocs: Doc[] = [];
+ // let newarray: Doc[] = [];
+ //while (childDocs.length > 0) {
+ //newarray = [];
+ 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 newarray: Doc[] = [];
+ while (newdocs.length > 0) {
+ newarray = [];
+ newdocs.forEach((t) => {
+ if (d.data !== undefined) {
+ const newdocs = DocListCast(t.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ if (searchDocs.includes(t)) {
+ vibecheck = true;
+ }
+ });
+ newdocs = newarray;
+ }
+ if (vibecheck === true) {
+ docsforFilter.push(d);
+ }
+ }
+ }
+ if (searchDocs.includes(d)) {
+ docsforFilter.push(d);
+ }
+ });
+ //childDocs = newarray;
+ //}
+ }
+ childDocs = docsforFilter;
+
+
const docFilters = this.docFilters();
- const viewSpecScript = ScriptCast(this.props.Document.viewSpecScript);
const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
- return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, docFilters, docRangeFilters, viewSpecScript);
+ return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript);
}
@action
@@ -436,4 +492,3 @@ import { CollectionView, CollectionViewType } from "./CollectionView";
import { SelectionManager } from "../../util/SelectionManager";
import { OverlayView } from "../OverlayView";
import { setTimeout } from "timers";
-
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 89034a0c0..6e15cb887 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -74,7 +74,7 @@ export enum CollectionViewType {
Pile = "pileup"
}
export interface CollectionViewCustomProps {
- filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ filterAddDocument?: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
childLayoutTemplate?: () => Opt<Doc>; // specify a layout Doc template to use for children of the collection
childLayoutString?: string; // specify a layout string to use for children of the collection
childOpacity?: () => number;
@@ -88,6 +88,7 @@ export interface CollectionRenderProps {
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
PanelWidth: () => number;
+ PanelHeight: () => number;
ChildLayoutTemplate?: () => Doc;
ChildLayoutString?: string;
}
@@ -523,6 +524,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
</div>
<div className="collectionTimeView-tree" key="tree">
<CollectionTreeView
+ PanelPosition={""}
Document={facetCollection}
DataDoc={facetCollection}
fieldKey={`${this.props.fieldKey}-filter`}
@@ -574,6 +576,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
active: this.active,
whenActiveChanged: this.whenActiveChanged,
PanelWidth: this.bodyPanelWidth,
+ PanelHeight: this.props.PanelHeight,
ChildLayoutTemplate: this.childLayoutTemplate,
ChildLayoutString: this.childLayoutString,
};
@@ -582,7 +585,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}>
{this.showIsTagged()}
- <div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
+ <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition === "absolute" ? "flex" : "", justifyContent: this.props.PanelPosition === "absolute" ? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
</div>
{this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 7e2840c2c..75d484cbe 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -11,22 +11,22 @@ import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
import { ComputedField } from "../../../fields/ScriptField";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../fields/Types";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
+import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils";
import { Docs, DocumentOptions } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
import { CompileScript, Transformer, ts } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
import { ContextMenu } from "../ContextMenu";
import '../DocumentDecorations.scss';
-import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaDateCell } from "./CollectionSchemaCells";
+import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
+import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
import "./CollectionSchemaView.scss";
import { CollectionView } from "./CollectionView";
-import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { emptyFunction, returnZero, returnOne, returnFalse, returnEmptyFilter, emptyPath } from "../../../Utils";
-import { TouchScrollableMenuItem } from "../TouchScrollableMenu";
enum ColumnType {
@@ -128,7 +128,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
@computed get sorted(): SortingRule[] {
return this.props.columns.reduce((sorted, shf) => {
- shf.desc && sorted.push({ id: shf.heading, desc: shf.desc });
+ shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc });
return sorted;
}, [] as SortingRule[]);
}
@@ -160,7 +160,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const focusedCol = this._focusedCell.col;
const isEditable = !this.props.headerIsEditing;
- if (this.childDocs.reduce((found, doc) => found || doc.type === "collection", false)) {
+ if (this.childDocs.reduce((found, doc) => found || doc.type === DocumentType.COL, false)) {
columns.push(
{
expander: true,
@@ -177,6 +177,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
);
}
+ console.log(columns);
const cols = this.props.columns.map(col => {
@@ -188,7 +189,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
addNew={false}
onSelect={this.props.changeColumns}
setIsEditing={this.props.setHeaderIsEditing}
-
+ docs={this.props.childDocs}
// try commenting this out
width={"100%"}
/>;
@@ -216,21 +217,21 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
className="collectionSchemaView-menuOptions-wrapper"
style={{
background: col.color, padding: "2px",
- display: "flex"
+ display: "flex", cursor: "default", height: "100%",
}}>
- <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingLeft: "7px" }} />
- <div className="keys-dropdown"
- style={{ display: "inline", zIndex: 1000 }}>
- {keysDropdown}
- </div>
+ <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px" }} />
+ {/* <div className="keys-dropdown"
+ style={{ display: "inline", zIndex: 1000 }}> */}
+ {keysDropdown}
+ {/* </div> */}
<div onClick={e => this.changeSorting(col)}
- style={{ paddingRight: "6px", marginLeft: "4px", display: "inline" }}>
- <FontAwesomeIcon icon={sortIcon} size="sm" />
- </div>
- <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
- style={{ float: "right", paddingRight: "6px" }}>
- <FontAwesomeIcon icon={"cog"} size="sm" />
+ style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit" }}>
+ <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 {
@@ -283,13 +284,63 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
accessor: (doc: Doc) => 0,
id: "add",
- Cell: (rowProps: CellInfo) => <></>,
+ Cell: (rowProps: CellInfo) => {
+ const rowIndex = rowProps.index;
+ const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+ const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+ const props: CellProps = {
+ row: rowIndex,
+ col: columnIndex,
+ rowProps: rowProps,
+ isFocused: isFocused,
+ changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+ CollectionView: this.props.CollectionView,
+ ContainingCollection: this.props.ContainingCollectionView,
+ Document: this.props.Document,
+ fieldKey: this.props.fieldKey,
+ renderDepth: this.props.renderDepth,
+ addDocTab: this.props.addDocTab,
+ pinToPres: this.props.pinToPres,
+ moveDocument: this.props.moveDocument,
+ setIsEditing: this.setCellIsEditing,
+ isEditable: isEditable,
+ setPreviewDoc: this.props.setPreviewDoc,
+ setComputed: this.setComputed,
+ getField: this.getField,
+ showDoc: this.showDoc,
+ };
+
+ return <CollectionSchemaButtons {...props} />;
+ },
width: 28,
resizable: false
});
+ console.log(columns);
return columns;
}
+
+
+ @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)
@@ -574,7 +625,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
return <div className="collectionSchemaView-table" onPointerDown={this.props.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
{this.reactTable}
- <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
+ {StrCast(this.props.Document.type) !== "search" ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
+ : undefined}
{!this._showDoc ? (null) :
<div className="collectionSchemaView-documentPreview" //onClick={() => { this.onOpenClick(); }}
style={{
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index a67f53cea..0c7111a1d 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -542,7 +542,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
getField(key: string) {
//if (this.selectedDoc) {
- return Field.toString(this.selectedDoc[key] as Field);
+ return Field.toString(this.selectedDoc![key] as Field);
// } else {
// return undefined as Opt<string>;
// }
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 21f77e47b..e6ac7021a 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -240,7 +240,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
w: Math.min(w, this.numCols), // reduces width if greater than numCols
static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout.lockedPosition, false) // checks if the lock position item has been selected in the context menu
})) :
- this.savedLayoutList.map((layout, index) => Object.assign(layout, this.unflexedPosition(index)));
+ this.savedLayoutList.map((layout, index) => { Object.assign(layout, this.unflexedPosition(index)); return layout; });
}
/**
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 6feb0a398..f4aed94e7 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -191,7 +191,6 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
case DocumentType.AUDIO: destinationIcon = "microphone"; break;
case DocumentType.BUTTON: destinationIcon = "bolt"; break;
case DocumentType.PRES: destinationIcon = "tv"; break;
- case DocumentType.QUERY: destinationIcon = "search"; break;
case DocumentType.SCRIPTING: destinationIcon = "terminal"; break;
case DocumentType.IMPORT: destinationIcon = "cloud-upload-alt"; break;
case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index e8173d103..1282bbee5 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -24,7 +24,7 @@ import { ImageBox } from "./ImageBox";
import { KeyValueBox } from "./KeyValueBox";
import { PDFBox } from "./PDFBox";
import { PresBox } from "./PresBox";
-import { QueryBox } from "./QueryBox";
+import { SearchBox } from "../search/SearchBox";
import { ColorBox } from "./ColorBox";
import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
import { LinkAnchorBox } from "./LinkAnchorBox";
@@ -191,7 +191,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
components={{
FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
- PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
+ PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
ScreenshotBox, HTMLtag, ComparisonBox
}}
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 7899ff0f0..cb79e1522 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -125,7 +125,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
} else if (this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) {
const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag");
// this notifies any of the subviews that a document is made so that they can make finer-grained hyperlinks (). see note above in onLInkButtonMoved
- DocumentLinksButton.StartLink!._link = this.props.View._link = linkDoc;
+ DocumentLinksButton.StartLink._link = this.props.View._link = linkDoc;
setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0);
LinkManager.currentLink = linkDoc;
if (linkDoc) {
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 23ae48108..34b07f351 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -48,11 +48,18 @@ export interface FieldViewProps {
ignoreAutoHeight?: boolean;
PanelWidth: () => number;
PanelHeight: () => number;
+ PanelPosition?: string;
+ overflow?: boolean;
NativeHeight: () => number;
NativeWidth: () => number;
setVideoBox?: (player: VideoBox) => void;
ContentScaling: () => number;
+
ChromeHeight?: () => number;
+ childLayoutTemplate?: () => Opt<Doc>;
+ highlighting?: string[];
+ lines?: string[];
+ doc?: Doc;
// properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
height?: number;
width?: number;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 05ba6628c..826ccd340 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,4 +1,4 @@
-import { action } from 'mobx';
+import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
@@ -56,16 +56,26 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
e.stopPropagation();
}
}
+
+ @observable _mouseOver = false;
+ @computed get backColor() { return this.clicked || this._mouseOver ? StrCast(this.layoutDoc.hovercolor) : "unset"; }
+
+ @observable clicked = false;
// (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
render() {
const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
const missingParams = params?.filter(p => !this.paramsDoc[p]);
params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
return (
- <div className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
+ <div className="labelBox-outerDiv"
+ onClick={action(() => this.clicked = !this.clicked)}
+ onMouseLeave={action(() => this._mouseOver = false)}
+ onMouseOver={action(() => this._mouseOver = true)}
+ ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}>
<div className="labelBox-mainButton" style={{
background: StrCast(this.layoutDoc.backgroundColor),
+ backgroundColor: this.backColor,
color: StrCast(this.layoutDoc.color, "inherit"),
fontSize: StrCast(this.layoutDoc._fontSize) || "inherit",
fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
index 0fff0b57f..1b6056be6 100644
--- a/src/client/views/nodes/QueryBox.tsx
+++ b/src/client/views/nodes/QueryBox.tsx
@@ -1,41 +1,38 @@
-import React = require("react");
-import { IReactionDisposer } from "mobx";
-import { observer } from "mobx-react";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { Id } from '../../../fields/FieldSymbols';
-import { makeInterface, listSpec } from "../../../fields/Schema";
-import { StrCast, Cast } from "../../../fields/Types";
-import { ViewBoxAnnotatableComponent } from '../DocComponent';
-import { SearchBox } from "../search/SearchBox";
-import { FieldView, FieldViewProps } from './FieldView';
-import "./QueryBox.scss";
-import { List } from "../../../fields/List";
-import { SnappingManager } from "../../util/SnappingManager";
+// import React = require("react");
+// import { IReactionDisposer } from "mobx";
+// import { observer } from "mobx-react";
+// import { documentSchema } from "../../../new_fields/documentSchemas";
+// import { Id } from '../../../new_fields/FieldSymbols';
+// import { makeInterface, listSpec } from "../../../new_fields/Schema";
+// import { StrCast, Cast } from "../../../new_fields/Types";
+// import { ViewBoxAnnotatableComponent } from '../DocComponent';
+// import { SearchBox } from "../search/SearchBox";
+// import { FieldView, FieldViewProps } from './FieldView';
+// import "./QueryBox.scss";
+// import { List } from "../../../new_fields/List";
+// import { SnappingManager } from "../../util/SnappingManager";
-type QueryDocument = makeInterface<[typeof documentSchema]>;
-const QueryDocument = makeInterface(documentSchema);
+// type QueryDocument = makeInterface<[typeof documentSchema]>;
+// const QueryDocument = makeInterface(documentSchema);
-@observer
-export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
- _docListChangedReaction: IReactionDisposer | undefined;
- componentDidMount() {
- }
+// @observer
+// export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
+// public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
+// _docListChangedReaction: IReactionDisposer | undefined;
+// componentDidMount() {
+// }
- componentWillUnmount() {
- this._docListChangedReaction?.();
- }
+// componentWillUnmount() {
+// this._docListChangedReaction?.();
+// }
- render() {
- const dragging = !SnappingManager.GetIsDragging() ? "" : "-dragging";
- return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
- <SearchBox
- id={this.props.Document[Id]}
- setSearchQuery={q => this.dataDoc.searchQuery = q}
- searchQuery={StrCast(this.dataDoc.searchQuery)}
- setSearchFileTypes={q => this.dataDoc.searchFileTypes = new List<string>(q)}
- searchFileTypes={Cast(this.dataDoc.searchFileTypes, listSpec("string"), [])}
- filterQquery={StrCast(this.dataDoc.filterQuery)} />
- </div >;
- }
-} \ No newline at end of file
+// render() {
+// const dragging = !SnappingManager.GetIsDragging() ? "" : "-dragging";
+// return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
+
+// <SearchBox Document={this.props.Document} />
+// </div >;
+// }
+// }
+
+// //<SearchBox id={this.props.Document[Id]} sideBar={side} Document={this.props.Document} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQuery={this.dataDoc.filterQuery} />
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 646a94aa7..3283f568a 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -536,7 +536,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
highlight = (color: string) => {
// creates annotation documents for current highlights
const effectiveAcl = GetEffectiveAcl(this.props.Document);
- const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color);
+ const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) ? this.makeAnnotationDocument(color) : undefined;
annotationDoc && this.addDocument?.(annotationDoc);
return annotationDoc ?? undefined;
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fc65f34eb..5f0f33351 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -236,7 +236,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
this._applyingChange = true;
- (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
+ const lastmodified = "lastmodified";
+ (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))) && (this.dataDoc[lastmodified] = new DateField(new Date(Date.now())));
if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
if (json.replace(/"selection":.*/, "") !== curLayout?.Data.replace(/"selection":.*/, "")) {
!curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
@@ -270,7 +271,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) {
let node = this._editorView.state.doc;
- while (node.firstChild) node = node.firstChild;
+ while (node.firstChild && node.firstChild.type.name !== "text") node = node.firstChild;
const str = node.textContent;
const titlestr = str.substr(0, Math.min(40, str.length));
this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
@@ -292,18 +293,40 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
}
}
- public highlightSearchTerms = (terms: string[]) => {
+ 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));
+ const length = res[0].length;
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;
+ }
+
+ }
+ else {
+
+ }
+ const index = this._searchIndex;
+
+ Doc.GetProto(this.dataDoc).searchIndex = index;
}
}
@@ -314,6 +337,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
const end = this._editorView.state.doc.nodeSize - 2;
this._editorView.dispatch(this._editorView.state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
+
}
if (FormattedTextBox.PasteOnLoad) {
const pdfDocId = FormattedTextBox.PasteOnLoad.clipboardData?.getData("dash/pdfOrigin");
@@ -738,8 +762,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.setupEditor(this.config, this.props.fieldKey);
+ this._disposers.searchAlt = reaction(() => this.rootDoc.searchMatchAlt,
+ search => search ? this.highlightSearchTerms([Doc.SearchQuery()], false) : this.unhighlightSearchTerms(),
+ { fireImmediately: true });
this._disposers.search = reaction(() => this.rootDoc.searchMatch,
- search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
+ search => search ? this.highlightSearchTerms([Doc.SearchQuery()], true) : this.unhighlightSearchTerms(),
{ fireImmediately: this.rootDoc.searchMatch ? true : false });
this._disposers.record = reaction(() => this._recording,
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index f040cd26d..459632ec8 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -903,8 +903,9 @@ export default class RichTextMenu extends AntimodeMenu {
ref_node = pos.nodeBefore;
}
if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
- if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos)
+ if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos) {
ref_node = pos.nodeAfter;
+ }
}
if (!ref_node && pos.pos > 0) {
let skip = false;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 5a43a076b..264d3e6c6 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -106,6 +106,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
private _scrollTopReactionDisposer?: IReactionDisposer;
private _filterReactionDisposer?: IReactionDisposer;
private _searchReactionDisposer?: IReactionDisposer;
+ private _searchReactionDisposer2?: IReactionDisposer;
private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _selectionText: string = "";
@@ -336,6 +337,8 @@ 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;
+
}
@action
@@ -403,6 +406,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
phraseSearch: true,
query: searchString
});
+ this.Document.searchIndex = this.Index;
}
else if (this._mainCont.current) {
const executeFind = () => {
@@ -416,7 +420,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
};
this._mainCont.current.addEventListener("pagesloaded", executeFind);
this._mainCont.current.addEventListener("pagerendered", executeFind);
+ this.Document.searchIndex = this.Index;
}
+
}
@action
diff --git a/src/client/views/search/FieldFilters.scss b/src/client/views/search/FieldFilters.scss
deleted file mode 100644
index e1d0d8df5..000000000
--- a/src/client/views/search/FieldFilters.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.field-filters {
- width: 100%;
- display: grid;
- // grid-template-columns: 18% 20% 60%;
- grid-template-columns: 20% 25% 60%;
-}
-
-.field-filters-required {
- width: 100%;
- display: grid;
- grid-template-columns: 50% 50%;
-} \ No newline at end of file
diff --git a/src/client/views/search/FieldFilters.tsx b/src/client/views/search/FieldFilters.tsx
deleted file mode 100644
index 7a33282d2..000000000
--- a/src/client/views/search/FieldFilters.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as React from 'react';
-import { observable } from 'mobx';
-import { CheckBox } from './CheckBox';
-import { Keys } from './FilterBox';
-import "./FieldFilters.scss";
-
-export interface FieldFilterProps {
- titleFieldStatus: boolean;
- dataFieldStatus: boolean;
- authorFieldStatus: boolean;
- updateTitleStatus(stat: boolean): void;
- updateAuthorStatus(stat: boolean): void;
- updateDataStatus(stat: boolean): void;
-}
-
-export class FieldFilters extends React.Component<FieldFilterProps> {
-
- static Instance: FieldFilters;
-
- @observable public _resetBoolean = false;
- @observable public _resetCounter: number = 0;
-
- constructor(props: FieldFilterProps) {
- super(props);
- FieldFilters.Instance = this;
- }
-
- resetFieldFilters() {
- this._resetBoolean = true;
- }
-
- render() {
- return (
- <div className="field-filters">
- <CheckBox default={true} numCount={3} parent={this} originalStatus={this.props.titleFieldStatus} updateStatus={this.props.updateTitleStatus} title={Keys.TITLE} />
- <CheckBox default={true} numCount={3} parent={this} originalStatus={this.props.authorFieldStatus} updateStatus={this.props.updateAuthorStatus} title={Keys.AUTHOR} />
- <CheckBox default={false} numCount={3} parent={this} originalStatus={this.props.dataFieldStatus} updateStatus={this.props.updateDataStatus} title={"Deleted Docs"} />
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/src/client/views/search/FilterBox.scss b/src/client/views/search/FilterBox.scss
deleted file mode 100644
index 094ea9cc5..000000000
--- a/src/client/views/search/FilterBox.scss
+++ /dev/null
@@ -1,178 +0,0 @@
-@import "../globalCssVariables";
-@import "./NaviconButton.scss";
-
-.filter-form {
- padding: 25px;
- width: 440px;
- position: relative;
- right: 1px;
- color: grey;
- flex-direction: column;
- display: inline-block;
- transform-origin: top;
- overflow: auto;
- border-bottom: solid black 3px;
-
- .top-filter-header {
-
- #header {
- text-transform: uppercase;
- letter-spacing: 2px;
- font-size: 13;
- width: 80%;
- }
-
- .close-icon {
- width: 20%;
- opacity: .6;
- position: relative;
- display: block;
-
- .line {
- display: block;
- background: $alt-accent;
- width: 20;
- height: 3;
- position: absolute;
- right: 0;
- border-radius: ($height-line / 2);
-
- &.line-1 {
- transform: rotate(45deg);
- top: 45%;
- }
-
- &.line-2 {
- transform: rotate(-45deg);
- top: 45%;
- }
- }
- }
-
- .close-icon:hover {
- opacity: 1;
- }
-
- }
-
- .filter-options {
-
- .filter-div {
- margin-top: 10px;
- margin-bottom: 10px;
- display: inline-block;
- width: 100%;
- border-color: rgba(178, 206, 248, .2); // $darker-alt-accent
- border-top-style: solid;
-
- .filter-header {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- letter-spacing: 2px;
-
- .filter-title {
- font-size: 13;
- text-transform: uppercase;
- margin-top: 10px;
- margin-bottom: 10px;
- -webkit-transition: all 0.2s ease-in-out;
- -moz-transition: all 0.2s ease-in-out;
- -o-transition: all 0.2s ease-in-out;
- transition: all 0.2s ease-in-out;
- }
- }
-
- .filter-header:hover .filter-title {
- transform: scale(1.05);
- }
-
- .filter-panel {
- max-height: 0px;
- width: 100%;
- overflow: hidden;
- opacity: 0;
- transform-origin: top;
- -webkit-transition: all 0.2s ease-in-out;
- -moz-transition: all 0.2s ease-in-out;
- -o-transition: all 0.2s ease-in-out;
- transition: all 0.2s ease-in-out;
- text-align: center;
- }
- }
- }
-
- .filter-buttons {
- border-color: rgba(178, 206, 248, .2); // $darker-alt-accent
- border-top-style: solid;
- padding-top: 10px;
- }
-}
-
-.active-filters {
- display: flex;
- flex-direction: row-reverse;
- justify-content: flex-end;
- width: 100%;
- margin-right: 30px;
- position: relative;
-
- .active-icon {
- max-width: 40px;
- flex: initial;
-
- &.icon {
- width: 40px;
- text-align: center;
- margin-bottom: 5px;
- position: absolute;
- }
-
- &.container {
- display: flex;
- flex-direction: column;
- width: 40px;
- }
-
- &.description {
- text-align: center;
- top: 40px;
- position: absolute;
- width: 40px;
- font-size: 9px;
- opacity: 0;
- -webkit-transition: all 0.2s ease-in-out;
- -moz-transition: all 0.2s ease-in-out;
- -o-transition: all 0.2s ease-in-out;
- transition: all 0.2s ease-in-out;
- }
-
- &.icon:hover+.description {
- opacity: 1;
- }
- }
-
- .col-icon {
- height: 35px;
- margin-left: 5px;
- width: 35px;
- background-color: black;
- color: white;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
-
- .save-filter,
- .reset-filter,
- .all-filter {
- background-color: gray;
- }
-
- .save-filter:hover,
- .reset-filter:hover,
- .all-filter:hover {
- background-color: $darker-alt-accent;
- }
- }
-} \ No newline at end of file
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
deleted file mode 100644
index eb61f9a14..000000000
--- a/src/client/views/search/FilterBox.tsx
+++ /dev/null
@@ -1,431 +0,0 @@
-import * as React from 'react';
-import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
-import "./SearchBox.scss";
-import { faTimes, faCheckCircle, faObjectGroup } from '@fortawesome/free-solid-svg-icons';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { Doc } from '../../../fields/Doc';
-import { Id } from '../../../fields/FieldSymbols';
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Cast, StrCast } from '../../../fields/Types';
-import * as _ from "lodash";
-import { IconBar } from './IconBar';
-import { FieldFilters } from './FieldFilters';
-import { SelectionManager } from '../../util/SelectionManager';
-import { DocumentView } from '../nodes/DocumentView';
-import { CollectionFilters } from './CollectionFilters';
-import * as $ from 'jquery';
-import "./FilterBox.scss";
-import { SearchBox } from './SearchBox';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-library.add(faTimes);
-library.add(faCheckCircle);
-library.add(faObjectGroup);
-
-export enum Keys {
- TITLE = "title",
- AUTHOR = "author",
- DATA = "data"
-}
-
-@observer
-export class FilterBox extends React.Component {
-
- static Instance: FilterBox;
- public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
-
- //if true, any keywords can be used. if false, all keywords are required.
- //this also serves as an indicator if the word status filter is applied
- @observable private _basicWordStatus: boolean = true;
- @observable private _filterOpen: boolean = false;
- //if icons = all icons, then no icon filter is applied
- @observable private _icons: string[] = this._allIcons;
- //if all of these are true, no key filter is applied
- @observable private _anyKeywordStatus: boolean = true;
- @observable private _allKeywordStatus: boolean = true;
- @observable private _titleFieldStatus: boolean = true;
- @observable private _authorFieldStatus: boolean = true;
- @observable private _dataFieldStatus: boolean = true;
- //this also serves as an indicator if the collection status filter is applied
- @observable public _deletedDocsStatus: boolean = false;
- @observable private _collectionStatus = false;
- @observable private _collectionSelfStatus = true;
- @observable private _collectionParentStatus = true;
- @observable private _wordStatusOpen: boolean = false;
- @observable private _typeOpen: boolean = false;
- @observable private _colOpen: boolean = false;
- @observable private _fieldOpen: boolean = false;
- public _pointerTime: number = -1;
-
- constructor(props: Readonly<{}>) {
- super(props);
- FilterBox.Instance = this;
- }
- setupAccordion() {
- $('document').ready(function () {
- const acc = document.getElementsByClassName('filter-header');
- // tslint:disable-next-line: prefer-for-of
- for (let i = 0; i < acc.length; i++) {
- acc[i].addEventListener("click", function (this: HTMLElement) {
- this.classList.toggle("active");
-
- const panel = this.nextElementSibling as HTMLElement;
- if (panel.style.maxHeight) {
- panel.style.overflow = "hidden";
- panel.style.maxHeight = "";
- panel.style.opacity = "0";
- } else {
- setTimeout(() => {
- panel.style.overflow = "visible";
- }, 200);
- setTimeout(() => {
- panel.style.opacity = "1";
- }, 50);
- panel.style.maxHeight = panel.scrollHeight + "px";
-
- }
- });
-
- const el = acc[i] as HTMLElement;
- el.click();
- }
- });
- }
-
- @action.bound
- minimizeAll() {
- $('document').ready(function () {
- const acc = document.getElementsByClassName('filter-header');
-
- // tslint:disable-next-line: prefer-for-of
- for (var i = 0; i < acc.length; i++) {
- const classList = acc[i].classList;
- if (classList.contains("active")) {
- acc[i].classList.toggle("active");
- const panel = acc[i].nextElementSibling as HTMLElement;
- panel.style.overflow = "hidden";
- panel.style.maxHeight = "";
- }
- }
- });
- }
-
- @action.bound
- resetFilters = () => {
- this._basicWordStatus = true;
- IconBar.Instance.selectAll();
- FieldFilters.Instance.resetFieldFilters();
- }
-
- basicRequireWords(query: string): string {
- const oldWords = query.split(" ");
- const newWords: string[] = [];
- oldWords.forEach(word => {
- const newWrd = "+" + word;
- newWords.push(newWrd);
- });
- query = newWords.join(" ");
-
- return query;
- }
-
- basicFieldFilters(query: string, type: string): string {
- const oldWords = query.split(" ");
- let mod = "";
-
- if (type === Keys.AUTHOR) {
- mod = " author_t:";
- } if (type === Keys.DATA) {
- //TODO
- } if (type === Keys.TITLE) {
- mod = " title_t:";
- }
-
- const newWords: string[] = [];
- oldWords.forEach(word => {
- const newWrd = mod + word;
- newWords.push(newWrd);
- });
-
- query = newWords.join(" ");
-
- return query;
- }
-
- applyBasicFieldFilters(query: string) {
- let finalQuery = "";
-
- if (this._titleFieldStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TITLE);
- }
- if (this._authorFieldStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.AUTHOR);
- }
- if (this._deletedDocsStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.DATA);
- }
- return finalQuery;
- }
-
- get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); }
-
- //TODO: basically all of this
- //gets all of the collections of all the docviews that are selected
- //if a collection is the only thing selected, search only in that collection (not its container)
- getCurCollections(): Doc[] {
- const selectedDocs: DocumentView[] = SelectionManager.SelectedDocuments();
- const collections: Doc[] = [];
-
- selectedDocs.forEach(async element => {
- const layout: string = StrCast(element.props.Document.layout);
- //checks if selected view (element) is a collection. if it is, adds to list to search through
- if (layout.indexOf("Collection") > -1) {
- //makes sure collections aren't added more than once
- if (!collections.includes(element.props.Document)) {
- collections.push(element.props.Document);
- }
- }
- //makes sure collections aren't added more than once
- if (element.props.ContainingCollectionDoc && !collections.includes(element.props.ContainingCollectionDoc)) {
- collections.push(element.props.ContainingCollectionDoc);
- }
- });
-
- return collections;
- }
-
- getFinalQuery(query: string): string {
- //alters the query so it looks in the correct fields
- //if this is true, then not all of the field boxes are checked
- //TODO: data
- if (this.fieldFiltersApplied) {
- query = this.applyBasicFieldFilters(query);
- query = query.replace(/\s+/g, ' ').trim();
- }
-
- //alters the query based on if all words or any words are required
- //if this._wordstatus is false, all words are required and a + is added before each
- if (!this._basicWordStatus) {
- query = this.basicRequireWords(query);
- query = query.replace(/\s+/g, ' ').trim();
- }
-
- //if should be searched in a specific collection
- if (this._collectionStatus) {
- query = this.addCollectionFilter(query);
- query = query.replace(/\s+/g, ' ').trim();
- }
- return query;
- }
-
- addCollectionFilter(query: string): string {
- const collections: Doc[] = this.getCurCollections();
- const oldWords = query.split(" ");
-
- const collectionString: string[] = [];
- collections.forEach(doc => {
- const proto = doc.proto;
- const protoId = (proto || doc)[Id];
- const colString: string = "{!join from=data_l to=id}id:" + protoId + " ";
- collectionString.push(colString);
- });
-
- let finalColString = collectionString.join(" ");
- finalColString = finalColString.trim();
- return "+(" + finalColString + ")" + query;
- }
-
- get filterTypes() {
- return this._icons.length === 9 ? undefined : this._icons;
- }
-
- @action
- filterDocsByType(docs: Doc[]) {
- if (this._icons.length === 9) {
- return docs;
- }
- const finalDocs: Doc[] = [];
- docs.forEach(doc => {
- const layoutresult = Cast(doc.type, "string");
- if (layoutresult && this._icons.includes(layoutresult)) {
- finalDocs.push(doc);
- }
- });
- return finalDocs;
- }
-
- getABCicon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
- <path d="M25.4 47.9c-1.3 1.3-1.9 2.8-1.9 4.8 0 3.8 2.3 6.1 6.1 6.1 5.1 0 8-3.3 9-6.2 0.2-0.7 0.4-1.4 0.4-2.1v-6.1c-0.1 0-0.1 0-0.2 0C32.2 44.5 27.7 45.6 25.4 47.9z" />
- <path d="M64.5 28.6c-2.2 0-4.1 1.5-4.7 3.8l0 0.2c-0.1 0.3-0.1 0.7-0.1 1.1v3.3c0 0.4 0.1 0.8 0.2 1.1 0.6 2.2 2.4 3.6 4.6 3.6 3.2 0 5.2-2.6 5.2-6.7C69.5 31.8 68 28.6 64.5 28.6z" />
- <path d="M43.9 0C19.7 0 0 19.7 0 43.9s19.7 43.9 43.9 43.9 43.9-19.6 43.9-43.9S68.1 0 43.9 0zM40.1 65.5l-0.5-4c-3 3.1-7.4 4.9-12.1 4.9 -6.8 0-13.6-4.4-13.6-12.8 0-4 1.3-7.4 4-10 4.1-4.1 11.1-6.2 20.8-6.3 0-5.5-2.9-8.4-8.3-8.4 -3.6 0-7.4 1.1-10.2 2.9l-1.1 0.7 -2.4-6.9 0.7-0.4c3.7-2.4 8.9-3.8 14.1-3.8 10.9 0 16.7 6.2 16.7 17.9V54.6c0 4.1 0.2 7.2 0.7 9.7L49 65.5H40.1zM65.5 67.5c1.8 0 3-0.5 4-0.9l0.5-0.2 0.8 3.4 -0.3 0.2c-1 0.5-3 1.1-5.5 1.1 -5.8 0-9.7-4-9.7-9.9 0-6.1 4.3-10.3 10.4-10.3 2.1 0 4 0.5 4.9 1l0.3 0.2 -1 3.5 -0.5-0.3c-0.7-0.4-1.8-0.8-3.7-0.8 -3.7 0-6.1 2.6-6.1 6.6C59.5 64.8 61.9 67.5 65.5 67.5zM65 45.3c-2.5 0-4.5-0.9-5.9-2.7l-0.1 2.3h-3.8l0-0.5c0.1-1.2 0.2-3.1 0.2-4.8V16.7h4.3v10.8c1.4-1.6 3.5-2.5 6-2.5 2.2 0 4.1 0.8 5.5 2.3 1.8 1.8 2.8 4.5 2.8 7.7C73.8 42.1 69.3 45.3 65 45.3z" />
- </svg>
- );
- }
-
- getTypeIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
- <path d="M43.9 0C19.7 0 0 19.7 0 43.9s19.7 43.9 43.9 43.9 43.9-19.6 43.9-43.9S68.1 0 43.9 0zM43.9 12.2c4.1 0 7.5 3.4 7.5 7.5 0 4.1-3.4 7.5-7.5 7.5 -4.1 0-7.5-3.4-7.5-7.5C36.4 15.5 39.7 12.2 43.9 12.2zM11.9 50.4l7.5-13 7.5 13H11.9zM47.6 75.7h-7.5l-3.7-6.5 3.8-6.5h7.5l3.8 6.5L47.6 75.7zM70.7 70.7c-0.2 0.2-0.4 0.3-0.7 0.3s-0.5-0.1-0.7-0.3l-25.4-25.4 -25.4 25.4c-0.2 0.2-0.4 0.3-0.7 0.3s-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1 0-1.4l25.4-25.4 -25.4-25.4c-0.4-0.4-0.4-1 0-1.4s1-0.4 1.4 0l25.4 25.4 25.4-25.4c0.4-0.4 1-0.4 1.4 0s0.4 1 0 1.4l-25.4 25.4 25.4 25.4C71.1 69.7 71.1 70.3 70.7 70.7zM61.4 51.4v-15h15v15H61.4z" />
- </svg>
- );
- }
-
- getKeyIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.8 87.8" height="35">
- <path d="M38.5 32.4c0 3.4-2.7 6.1-6.1 6.1 -3.4 0-6.1-2.7-6.1-6.1 0-3.4 2.8-6.1 6.1-6.1C35.8 26.3 38.5 29 38.5 32.4zM87.8 43.9c0 24.2-19.6 43.9-43.9 43.9S0 68.1 0 43.9C0 19.7 19.7 0 43.9 0S87.8 19.7 87.8 43.9zM66.8 60.3L50.2 43.7c-0.5-0.5-0.6-1.2-0.4-1.8 2.4-5.6 1.1-12.1-3.2-16.5 -5.9-5.8-15.4-5.8-21.2 0l0 0c-4.3 4.3-5.6 10.8-3.2 16.5 3.2 7.6 12 11.2 19.7 8 0.6-0.3 1.4-0.1 1.8 0.4l3.1 3.1h3.9c1.2 0 2.2 1 2.2 2.2v3.6h3.6c1.2 0 2.2 1 2.2 2.2v4l1.6 1.6h6.5V60.3z" />
- </svg>
- );
- }
-
- getColIcon() {
- return (
- <div className="col-icon">
- <FontAwesomeIcon icon={faObjectGroup} size="lg" />
- </div>
- );
- }
-
- @action.bound
- openFilter = () => {
- this._filterOpen = !this._filterOpen;
- SearchBox.Instance.closeResults();
- this.setupAccordion();
- }
-
- //if true, any keywords can be used. if false, all keywords are required.
- @action.bound
- handleWordQueryChange = () => {
- this._basicWordStatus = !this._basicWordStatus;
- }
-
- @action.bound
- updateIcon(newArray: string[]) { this._icons = newArray; }
-
- @action.bound
- getIcons(): string[] { return this._icons; }
-
- stopProp = (e: React.PointerEvent) => {
- e.stopPropagation();
- this._pointerTime = e.timeStamp;
- }
-
- @action.bound
- public closeFilter() {
- this._filterOpen = false;
- }
-
- @action.bound
- updateAnyKeywordStatus(newStat: boolean) { this._anyKeywordStatus = newStat; }
-
- @action.bound
- updateAllKeywordStatus(newStat: boolean) { this._allKeywordStatus = newStat; }
-
- @action.bound
- updateTitleStatus(newStat: boolean) { this._titleFieldStatus = newStat; }
-
- @action.bound
- updateAuthorStatus(newStat: boolean) { this._authorFieldStatus = newStat; }
-
- @action.bound
- updateDataStatus(newStat: boolean) { this._deletedDocsStatus = newStat; }
-
- @action.bound
- updateCollectionStatus(newStat: boolean) { this._collectionStatus = newStat; }
-
- @action.bound
- updateSelfCollectionStatus(newStat: boolean) { this._collectionSelfStatus = newStat; }
-
- @action.bound
- updateParentCollectionStatus(newStat: boolean) { this._collectionParentStatus = newStat; }
-
- getAnyKeywordStatus() { return this._anyKeywordStatus; }
- getAllKeywordStatus() { return this._allKeywordStatus; }
- getCollectionStatus() { return this._collectionStatus; }
- getSelfCollectionStatus() { return this._collectionSelfStatus; }
- getParentCollectionStatus() { return this._collectionParentStatus; }
- getTitleStatus() { return this._titleFieldStatus; }
- getAuthorStatus() { return this._authorFieldStatus; }
- getDataStatus() { return this._deletedDocsStatus; }
-
- getActiveFilters() {
- return (
- <div className="active-filters">
- {!this._basicWordStatus ? <div className="active-icon container">
- <div className="active-icon icon">{this.getABCicon()}</div>
- <div className="active-icon description">Required Words Applied</div>
- </div> : undefined}
- {!(this._icons.length === 9) ? <div className="active-icon container">
- <div className="active-icon icon">{this.getTypeIcon()}</div>
- <div className="active-icon description">Type Filters Applied</div>
- </div> : undefined}
- {!(this._authorFieldStatus && this._dataFieldStatus && this._titleFieldStatus) ?
- <div className="active-icon container">
- <div className="active-icon icon">{this.getKeyIcon()}</div>
- <div className="active-icon description">Field Filters Applied</div>
- </div> : undefined}
- {this._collectionStatus ? <div className="active-icon container">
- <div className="active-icon icon">{this.getColIcon()}</div>
- <div className="active-icon description">Collection Filters Active</div>
- </div> : undefined}
- </div>
- );
- }
-
- // Useful queries:
- // Delegates of a document: {!join from=id to=proto_i}id:{protoId}
- // Documents in a collection: {!join from=data_l to=id}id:{collectionProtoId} //id of collections prototype
- render() {
- return (
- <div>
- <div style={{ display: "flex", flexDirection: "row-reverse" }}>
- <SearchBox />
- {/* {this.getActiveFilters()} */}
- </div>
- {this._filterOpen ? (
- <div className="filter-form" onPointerDown={this.stopProp} id="filter-form" style={this._filterOpen ? { display: "flex", background: "black" } : { display: "none" }}>
- <div className="top-filter-header" style={{ display: "flex", width: "100%" }}>
- <div id="header">Filter Search Results</div>
- <div style={{ marginLeft: "auto" }}></div>
- <div className="close-icon" onClick={this.closeFilter}>
- <span className="line line-1"></span>
- <span className="line line-2"></span></div>
- </div>
- <div className="filter-options">
- <div className="filter-div">
- <div className="filter-header">
- <div className='filter-title words'>Required words</div>
- </div>
- <div className="filter-panel" >
- <button className="all-filter" onClick={this.handleWordQueryChange}>Include All Keywords</button>
- </div>
- </div>
- <div className="filter-div">
- <div className="filter-header">
- <div className="filter-title icon">Filter by type of node</div>
- </div>
- <div className="filter-panel"><IconBar /></div>
- </div>
- <div className="filter-div">
- <div className="filter-header">
- <div className="filter-title field">Filter by Basic Keys</div>
- </div>
- <div className="filter-panel"><FieldFilters
- titleFieldStatus={this._titleFieldStatus} dataFieldStatus={this._deletedDocsStatus} authorFieldStatus={this._authorFieldStatus}
- updateAuthorStatus={this.updateAuthorStatus} updateDataStatus={this.updateDataStatus} updateTitleStatus={this.updateTitleStatus} /> </div>
- </div>
- </div>
- <div className="filter-buttons" style={{ display: "flex", justifyContent: "space-around" }}>
- <button className="save-filter" >Save Filters</button>
- <button className="reset-filter" onClick={this.resetFilters}>Reset Filters</button>
- </div>
- </div>
- ) :
- undefined}
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index bb62113a1..3f06ba7d3 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -17,10 +17,9 @@
.searchBox-bar {
height: 32px;
display: flex;
- justify-content: flex-end;
+ justify-content: center;
align-items: center;
- padding-left: 2px;
-
+ background-color: black;
.searchBox-barChild {
&.searchBox-collection {
@@ -30,24 +29,29 @@
}
&.searchBox-input {
+ margin:5px;
+ border-radius:20px;
+ border:black;
display: block;
width: 130px;
-webkit-transition: width 0.4s;
transition: width 0.4s;
align-self: stretch;
-
+ outline:none;
}
.searchBox-input:focus {
width: 500px;
- outline: 3px solid lightblue;
+ outline:none;
}
&.searchBox-filter {
align-self: stretch;
+ button{
+ transform:none;
+ }
button:hover{
- transform:scale(1.0);
- background:"#121721";
+ transform:none;
}
}
@@ -81,8 +85,6 @@
.no-result {
width: 500px;
background: $light-color-secondary;
- border-color: $intermediate-color;
- border-bottom-style: solid;
padding: 10px;
height: 50px;
text-transform: uppercase;
@@ -96,20 +98,20 @@
background: #121721;
flex-direction: column;
transform-origin: top;
- transition: height 0.3s ease, display 0.6s ease;
+ transition: height 0.3s ease, display 0.6s ease, overflow 0.6s ease;
height:0px;
overflow:hidden;
.filter-header {
- display: flex;
+ //display: flex;
position: relative;
- flex-wrap:wrap;
+ //flex-wrap:wrap;
right: 1px;
color: grey;
- flex-direction: row-reverse;
+ //flex-direction: row-reverse;
transform-origin: top;
- justify-content: space-evenly;
+ //justify-content: space-evenly;
margin-bottom: 5px;
overflow:hidden;
transition:height 0.3s ease-out;
@@ -130,9 +132,7 @@
color: grey;
transform-origin: top;
border-top: 0px;
- //padding-top: 5px;
- margin-left: 10px;
- margin-right: 10px;
+
overflow:hidden;
transition:height 0.3s ease-out;
height:0px;
@@ -144,30 +144,25 @@
color: grey;
transform-origin: top;
border-top: 0px;
- //padding-top: 5px;
- margin-left: 10px;
- margin-right: 10px;
overflow:hidden;
transition:height 0.3s ease-out;
height:0px;
- .filter-keybar {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-evenly;
- height: auto;
- width: 100%;
- flex-direction: row-reverse;
- margin-top:5px;
+
+ // .filter-keybar {
+ // display: flex;
+ // flex-wrap: wrap;
+ // justify-content: space-evenly;
+ // height: auto;
+ // width: 100%;
+ // flex-direction: row-reverse;
+ // margin-top:5px;
- .filter-item {
- position: relative;
- border:1px solid grey;
- border-radius: 16px;
-
- }
- }
-
-
+ // .filter-item {
+ // position: relative;
+ // border:1px solid grey;
+ // border-radius: 16px;
+ // }
+ // }
}
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 99fa6da21..1e44a379b 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -1,59 +1,66 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faTimes } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction, IReactionDisposer, reaction } from 'mobx';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from '@material-ui/core';
+import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as rp from 'request-promise';
-import { Doc } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
+import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
-import { Utils } from '../../../Utils';
+import { returnFalse, Utils } from '../../../Utils';
import { Docs } from '../../documents/Documents';
+import { DocumentType } from "../../documents/DocumentTypes";
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { SetupDrag } from '../../util/DragManager';
import { SearchUtil } from '../../util/SearchUtil';
-import "./SearchBox.scss";
-import { SearchItem } from './SearchItem';
-import { IconBar } from './IconBar';
-import { FieldView } from '../nodes/FieldView';
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentView } from '../nodes/DocumentView';
import { SelectionManager } from '../../util/SelectionManager';
-import { listSpec } from '../../../fields/Schema';
-
-library.add(faTimes);
+import { Transform } from '../../util/Transform';
+import { CollectionView, CollectionViewType } from '../collections/CollectionView';
+import { ViewBoxBaseComponent } from "../DocComponent";
+import { DocumentView } from '../nodes/DocumentView';
+import { FieldView, FieldViewProps } from '../nodes/FieldView';
+import "./SearchBox.scss";
-export interface SearchProps {
- id: string;
- searchQuery: string;
- filterQquery?: string;
- setSearchQuery: (q: string) => {};
- searchFileTypes: string[];
- setSearchFileTypes: (types: string[]) => {};
-}
+export const searchSchema = createSchema({
+ id: "string",
+ Document: Doc,
+ searchQuery: "string",
+});
export enum Keys {
TITLE = "title",
AUTHOR = "author",
- DATA = "data"
+ DATA = "data",
+ TEXT = "text"
}
+type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>;
+const SearchBoxDocument = makeInterface(documentSchema, searchSchema);
+
+//React.Component<SearchProps>
@observer
-export class SearchBox extends React.Component<SearchProps> {
+export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDocument>(SearchBoxDocument) {
- private get _searchString() { return this.props.searchQuery; }
- private set _searchString(value) { this.props.setSearchQuery(value); }
+ get _searchString() { return this.layoutDoc.searchQuery; }
+ @computed set _searchString(value) { this.layoutDoc.searchQuery = (value); }
@observable private _resultsOpen: boolean = false;
- @observable private _searchbarOpen: boolean = false;
+ @observable _searchbarOpen: boolean = false;
@observable private _results: [Doc, string[], string[]][] = [];
@observable private _openNoResults: boolean = false;
@observable private _visibleElements: JSX.Element[] = [];
+ @observable private _visibleDocuments: Doc[] = [];
private _resultsSet = new Map<Doc, number>();
private _resultsRef = React.createRef<HTMLDivElement>();
public inputRef = React.createRef<HTMLInputElement>();
private _isSearch: ("search" | "placeholder" | undefined)[] = [];
+ private _isSorted: ("sorted" | "placeholder" | undefined)[] = [];
+
private _numTotalResults = -1;
private _endIndex = -1;
@@ -63,55 +70,104 @@ export class SearchBox extends React.Component<SearchProps> {
private _curRequest?: Promise<any> = undefined;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); }
-
+ private new_buckets: { [characterName: string]: number } = {};
//if true, any keywords can be used. if false, all keywords are required.
//this also serves as an indicator if the word status filter is applied
@observable private _basicWordStatus: boolean = false;
@observable private _nodeStatus: boolean = false;
@observable private _keyStatus: boolean = false;
+ @observable private newAssign: boolean = true;
constructor(props: any) {
super(props);
SearchBox.Instance = this;
this.resultsScrolled = this.resultsScrolled.bind(this);
+
}
+ @observable setupButtons = false;
+ componentDidMount = () => {
+ if (this.setupButtons === false) {
- componentDidMount = action(() => {
+ runInAction(() => this.setupButtons = true);
+ }
if (this.inputRef.current) {
this.inputRef.current.focus();
- this._searchbarOpen = true;
+ runInAction(() => { this._searchbarOpen = true; });
}
- if (this.props.searchQuery) { // bcz: why was this here? } && this.props.filterQquery) {
- this._searchString = this.props.searchQuery;
- this.submitSearch();
+ if (this.rootDoc.searchQuery && this.newAssign) {
+ const sq = this.rootDoc.searchQuery;
+ runInAction(() => {
+
+ // this._deletedDocsStatus=this.props.filterQuery!.deletedDocsStatus;
+ // this._authorFieldStatus=this.props.filterQuery!.authorFieldStatus
+ // this._titleFieldStatus=this.props.filterQuery!.titleFieldStatus;
+ // this._basicWordStatus=this.props.filterQuery!.basicWordStatus;
+ // this._icons=this.props.filterQuery!.icons;
+ this.newAssign = false;
+ });
+ runInAction(() => {
+ this.layoutDoc._searchString = StrCast(sq);
+ this.submitSearch();
+ });
}
- });
+ }
@action
getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc)
+
+ @observable newsearchstring: string = "";
@action.bound
onChange(e: React.ChangeEvent<HTMLInputElement>) {
- this._searchString = e.target.value;
+ this.layoutDoc._searchString = e.target.value;
+ this.newsearchstring = e.target.value;
- this._openNoResults = false;
- this._results = [];
- this._resultsSet.clear();
- this._visibleElements = [];
- this._numTotalResults = -1;
- this._endIndex = -1;
- this._curRequest = undefined;
- this._maxSearchIndex = 0;
+
+ if (e.target.value === "") {
+ this._results.forEach(result => {
+ Doc.UnBrushDoc(result[0]);
+ result[0].searchMatch = undefined;
+ });
+
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([]);
+ if (this.currentSelectedCollection !== undefined) {
+ this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
+ this.currentSelectedCollection = undefined;
+ this.props.Document.selectedDoc = undefined;
+
+ }
+ runInAction(() => { this.open = false; });
+ this._openNoResults = false;
+ this._results = [];
+ this._resultsSet.clear();
+ this._visibleElements = [];
+ this._numTotalResults = -1;
+ this._endIndex = -1;
+ this._curRequest = undefined;
+ this._maxSearchIndex = 0;
+ }
}
enter = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
+ this.layoutDoc._searchString = this.newsearchstring;
+
+ if (StrCast(this.layoutDoc._searchString) !== "" || !this.searchFullDB) {
+ runInAction(() => this.open = true);
+ }
+ else {
+ runInAction(() => this.open = false);
+
+ }
this.submitSearch();
}
}
+ @observable open: boolean = false;
+
+
public static async convertDataUri(imageUri: string, returnedFilename: string) {
try {
const posting = Utils.prepend("/uploadURI");
@@ -134,10 +190,11 @@ export class SearchBox extends React.Component<SearchProps> {
//this also serves as an indicator if the word status filter is applied
@observable private _filterOpen: boolean = false;
//if icons = all icons, then no icon filter is applied
- get _icons() { return this.props.searchFileTypes; }
- set _icons(value) {
- this.props.setSearchFileTypes(value);
- }
+ // get _icons() { return this.props.searchFileTypes; }
+ // set _icons(value) {
+ // this.props.setSearchFileTypes(value);
+ // }
+ @observable _icons: string[] = this._allIcons;
//if all of these are true, no key filter is applied
@observable private _titleFieldStatus: boolean = true;
@observable private _authorFieldStatus: boolean = true;
@@ -162,10 +219,11 @@ export class SearchBox extends React.Component<SearchProps> {
query = query.replace(/\s+/g, ' ').trim();
}
- //if should be searched in a specific collection
+ // if should be searched in a specific collection
if (this._collectionStatus) {
query = this.addCollectionFilter(query);
query = query.replace(/\s+/g, ' ').trim();
+
}
return query;
}
@@ -176,14 +234,14 @@ export class SearchBox extends React.Component<SearchProps> {
@action
filterDocsByType(docs: Doc[]) {
- if (this._icons.length === this._allIcons.length) {
- return docs;
- }
const finalDocs: Doc[] = [];
+ const blockedTypes: string[] = ["preselement", "docholder", "collection", "search", "searchitem", "script", "fonticonbox", "button", "label"];
docs.forEach(doc => {
const layoutresult = Cast(doc.type, "string");
- if (layoutresult && this._icons.includes(layoutresult)) {
- finalDocs.push(doc);
+ if (layoutresult && !blockedTypes.includes(layoutresult)) {
+ if (layoutresult && this._icons.includes(layoutresult)) {
+ finalDocs.push(doc);
+ }
}
});
return finalDocs;
@@ -216,7 +274,6 @@ export class SearchBox extends React.Component<SearchProps> {
getCurCollections(): Doc[] {
const selectedDocs: DocumentView[] = SelectionManager.SelectedDocuments();
const collections: Doc[] = [];
-
selectedDocs.forEach(async element => {
const layout: string = StrCast(element.props.Document.layout);
//checks if selected view (element) is a collection. if it is, adds to list to search through
@@ -236,6 +293,85 @@ export class SearchBox extends React.Component<SearchProps> {
}
+ currentSelectedCollection: DocumentView | undefined = undefined;
+ docsforfilter: Doc[] = [];
+
+ searchCollection(query: string) {
+ const selectedCollection: DocumentView = SelectionManager.SelectedDocuments()[0];
+ query = query.toLowerCase();
+ if (selectedCollection !== undefined) {
+ this.currentSelectedCollection = selectedCollection;
+ if (this.filter === true) {
+ this.props.Document.selectedDoc = selectedCollection.props.Document;
+ }
+ let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
+ const found: [Doc, string[], string[]][] = [];
+ const docsforFilter: Doc[] = [];
+ let newarray: Doc[] = [];
+
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ newarray.push(...DocListCast(d.data));
+ }
+ const hlights: string[] = [];
+ const protos = Doc.GetAllPrototypes(d);
+ protos.forEach(proto => {
+ Object.keys(proto).forEach(key => {
+ if (StrCast(d[key]).toLowerCase().includes(query) && !hlights.includes(key)) {
+ hlights.push(key);
+ }
+ });
+ });
+ if (hlights.length > 0) {
+ found.push([d, hlights, []]);
+ docsforFilter.push(d);
+ }
+ });
+ docs = newarray;
+ }
+ this._results = found;
+ this.docsforfilter = docsforFilter;
+ if (this.filter === true) {
+ selectedCollection.props.Document._searchDocs = new List<Doc>(docsforFilter);
+ docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ d._searchDocs = new List<Doc>(docsforFilter);
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
+ }
+ this._numTotalResults = found.length;
+ }
+ else {
+ this.noresults = "No collection selected :(";
+ }
+
+ }
+
+
+ documentKeys(doc: Doc) {
+ const keys: { [key: string]: boolean } = {};
+ // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+ // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be
+ // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked.
+ // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu
+ // is displayed (unlikely) it won't show up until something else changes.
+ //TODO Types
+ Doc.GetAllPrototypes(doc).map
+ (proto => Object.keys(proto).forEach(key => keys[key] = false));
+ return Array.from(Object.keys(keys));
+ }
+
applyBasicFieldFilters(query: string) {
let finalQuery = "";
@@ -248,26 +384,24 @@ export class SearchBox extends React.Component<SearchProps> {
if (this._deletedDocsStatus) {
finalQuery = finalQuery + this.basicFieldFilters(query, Keys.DATA);
}
+ if (this._deletedDocsStatus) {
+ finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TEXT);
+ }
return finalQuery;
}
basicFieldFilters(query: string, type: string): string {
- const oldWords = query.split(" ");
let mod = "";
-
- if (type === Keys.AUTHOR) {
- mod = " author_t:";
- } if (type === Keys.DATA) {
- //TODO
- } if (type === Keys.TITLE) {
- mod = " title_t:";
+ switch (type) {
+ case Keys.AUTHOR: mod = " author_t:"; break;
+ case Keys.DATA: break; // TODO
+ case Keys.TITLE: mod = " _title_t:"; break;
+ case Keys.TEXT: mod = " text_t:"; break;
}
const newWords: string[] = [];
- oldWords.forEach(word => {
- const newWrd = mod + word;
- newWords.push(newWrd);
- });
+ const oldWords = query.split(" ");
+ oldWords.forEach(word => newWords.push(mod + word));
query = newWords.join(" ");
@@ -276,30 +410,64 @@ export class SearchBox extends React.Component<SearchProps> {
get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); }
-
@action
- submitSearch = async () => {
- const query = this._searchString;
+ submitSearch = async (reset?: boolean) => {
+ if (reset) {
+ this.layoutDoc._searchString = "";
+ }
+ this.props.Document._docFilters = undefined;
+ this.noresults = "";
+
+ this.dataDoc[this.fieldKey] = new List<Doc>([]);
+ this.headercount = 0;
+ this.children = 0;
+ this.buckets = [];
+ this.new_buckets = {};
+ const query = StrCast(this.layoutDoc._searchString);
+ Doc.SetSearchQuery(query);
this.getFinalQuery(query);
+ this._results.forEach(result => {
+ Doc.UnBrushDoc(result[0]);
+ result[0].searchMatch = undefined;
+ });
this._results = [];
this._resultsSet.clear();
this._isSearch = [];
+ this._isSorted = [];
this._visibleElements = [];
+ this._visibleDocuments = [];
+ if (StrCast(this.props.Document.searchQuery)) {
+ if (this._timeout) { clearTimeout(this._timeout); this._timeout = undefined; }
+ this._timeout = setTimeout(() => {
+ console.log("Resubmitting search");
+ }, 60000);
+ }
+
if (query !== "") {
this._endIndex = 12;
this._maxSearchIndex = 0;
this._numTotalResults = -1;
- await this.getResults(query);
-
+ this.searchFullDB ? await this.getResults(query) : this.searchCollection(query);
runInAction(() => {
this._resultsOpen = true;
this._searchbarOpen = true;
this._openNoResults = true;
this.resultsScrolled();
+
});
}
}
+ @observable searchFullDB = true;
+
+ @observable _timeout: any = undefined;
+
+ @observable firststring: string = "";
+ @observable secondstring: string = "";
+
+ @observable bucketcount: number[] = [];
+ @observable buckets: Doc[] | undefined;
+
getAllResults = async (query: string) => {
return SearchUtil.Search(query, true, { fq: this.filterQuery, start: 0, rows: 10000000 });
}
@@ -309,7 +477,7 @@ export class SearchBox extends React.Component<SearchProps> {
const baseExpr = "NOT baseProto_b:true";
const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true";
const includeIcons = this.getDataStatus() ? "" : " NOT type_t:fonticonbox";
- // const typeExpr = !types ? "" : ` (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})`; // this line was causing issues for me, check solr logging -syip2
+ // const typeExpr = !types ? "" : ` (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})`;
// fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello
const query = [baseExpr, includeDeleted, includeIcons].join(" AND ").replace(/AND $/, "");
return query;
@@ -317,21 +485,20 @@ export class SearchBox extends React.Component<SearchProps> {
getDataStatus() { return this._deletedDocsStatus; }
-
private NumResults = 25;
private lockPromise?: Promise<void>;
getResults = async (query: string) => {
+ console.log("Get");
if (this.lockPromise) {
await this.lockPromise;
}
this.lockPromise = new Promise(async res => {
while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
- this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*" }).then(action(async (res: SearchUtil.DocSearchResult) => {
+ this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
// happens at the beginning
if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
this._numTotalResults = res.numFound;
}
-
const highlighting = res.highlighting || {};
const highlightList = res.docs.map(doc => highlighting[doc[Id]]);
const lines = new Map<string, string[]>();
@@ -340,19 +507,33 @@ export class SearchBox extends React.Component<SearchProps> {
const highlights: typeof res.highlighting = {};
docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]);
const filteredDocs = this.filterDocsByType(docs);
+
runInAction(() => {
- //this._results.push(...filteredDocs);
- filteredDocs.forEach(doc => {
+ filteredDocs.forEach((doc, i) => {
const index = this._resultsSet.get(doc);
const highlight = highlights[doc[Id]];
const line = lines.get(doc[Id]) || [];
const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
- if (index === undefined) {
- this._resultsSet.set(doc, this._results.length);
- this._results.push([doc, hlights, line]);
- } else {
- this._results[index][1].push(...hlights);
- this._results[index][2].push(...line);
+ doc ? console.log(Cast(doc.context, Doc)) : null;
+ if (this.findCommonElements(hlights)) {
+ }
+ else {
+ const layoutresult = Cast(doc.type, "string");
+ if (layoutresult) {
+ if (this.new_buckets[layoutresult] === undefined) {
+ this.new_buckets[layoutresult] = 1;
+ }
+ else {
+ this.new_buckets[layoutresult] = this.new_buckets[layoutresult] + 1;
+ }
+ }
+ if (index === undefined) {
+ this._resultsSet.set(doc, this._results.length);
+ this._results.push([doc, hlights, line]);
+ } else {
+ this._results[index][1].push(...hlights);
+ this._results[index][2].push(...line);
+ }
}
});
});
@@ -363,15 +544,16 @@ export class SearchBox extends React.Component<SearchProps> {
await this._curRequest;
}
+
this.resultsScrolled();
res();
});
return this.lockPromise;
}
-
+ @observable noresults = "";
collectionRef = React.createRef<HTMLSpanElement>();
startDragCollection = async () => {
- const res = await this.getAllResults(this.getFinalQuery(this._searchString));
+ const res = await this.getAllResults(this.getFinalQuery(StrCast(this.layoutDoc._searchString)));
const filtered = this.filterDocsByType(res.docs);
const docs = filtered.map(doc => {
const isProto = Doc.GetT(doc, "isPrototype", "boolean", true);
@@ -404,7 +586,7 @@ export class SearchBox extends React.Component<SearchProps> {
y += 300;
}
}
- return Docs.Create.QueryDocument({ _autoHeight: true, title: this._searchString, filterQuery: this.filterQuery, searchQuery: this._searchString });
+ return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString), searchQuery: StrCast(this.layoutDoc._searchString) });
}
@action.bound
@@ -417,7 +599,7 @@ export class SearchBox extends React.Component<SearchProps> {
@action.bound
closeSearch = () => {
- this.closeResults();
+ //this.closeResults();
this._searchbarOpen = false;
}
@@ -427,23 +609,30 @@ export class SearchBox extends React.Component<SearchProps> {
this._results = [];
this._resultsSet.clear();
this._visibleElements = [];
+ this._visibleDocuments = [];
this._numTotalResults = -1;
this._endIndex = -1;
this._curRequest = undefined;
}
+ @observable children: number = 0;
@action
resultsScrolled = (e?: React.UIEvent<HTMLDivElement>) => {
if (!this._resultsRef.current) return;
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([]);
+
const scrollY = e ? e.currentTarget.scrollTop : this._resultsRef.current ? this._resultsRef.current.scrollTop : 0;
const itemHght = 53;
const startIndex = Math.floor(Math.max(0, scrollY / itemHght));
- const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this._resultsRef.current.getBoundingClientRect().height / itemHght)));
-
- this._endIndex = endIndex === -1 ? 12 : endIndex;
-
+ //const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this._resultsRef.current.getBoundingClientRect().height / itemHght)));
+ const endIndex = 30;
+ //this._endIndex = endIndex === -1 ? 12 : endIndex;
+ this._endIndex = 30;
+ const headers = new Set<string>(["title", "author", "lastModified", "text"]);
if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
- this._visibleElements = [<div className="no-result">No Search Results</div>];
+ if (this.noresults === "") {
+ this.noresults = "No search results :(";
+ }
return;
}
@@ -456,16 +645,19 @@ export class SearchBox extends React.Component<SearchProps> {
else if (this._visibleElements.length !== this._numTotalResults) {
// undefined until a searchitem is put in there
this._visibleElements = Array<JSX.Element>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
- // indicates if things are placeholders
+ this._visibleDocuments = Array<Doc>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
+ // indicates if things are placeholders
this._isSearch = Array<undefined>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
- }
+ this._isSorted = Array<undefined>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
+ }
for (let i = 0; i < this._numTotalResults; i++) {
//if the index is out of the window then put a placeholder in
//should ones that have already been found get set to placeholders?
if (i < startIndex || i > endIndex) {
if (this._isSearch[i] !== "placeholder") {
this._isSearch[i] = "placeholder";
+ this._isSorted[i] = "placeholder";
this._visibleElements[i] = <div className="searchBox-placeholder" key={`searchBox-placeholder-${i}`}>Loading...</div>;
}
}
@@ -473,30 +665,61 @@ export class SearchBox extends React.Component<SearchProps> {
if (this._isSearch[i] !== "search") {
let result: [Doc, string[], string[]] | undefined = undefined;
if (i >= this._results.length) {
- this.getResults(this._searchString);
+ this.getResults(StrCast(this.layoutDoc._searchString));
if (i < this._results.length) result = this._results[i];
if (result) {
const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
+ const lines = new List<string>(result[2]);
+ result[0].lines = lines;
+ result[0].highlighting = highlights.join(", ");
+ highlights.forEach((item) => headers.add(item));
+ this._visibleDocuments[i] = result[0];
this._isSearch[i] = "search";
+ Doc.BrushDoc(result[0]);
+ result[0].searchMatch = true;
+ Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
+ this.children++;
}
}
else {
result = this._results[i];
if (result) {
const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
- this._isSearch[i] = "search";
+ const lines = new List<string>(result[2]);
+ highlights.forEach((item) => headers.add(item));
+ result[0].lines = lines;
+ result[0].highlighting = highlights.join(", ");
+ result[0].searchMatch = true;
+ if (i < this._visibleDocuments.length) {
+ this._visibleDocuments[i] = result[0];
+ this._isSearch[i] = "search";
+ Doc.BrushDoc(result[0]);
+ Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
+ this.children++;
+ }
}
}
}
}
}
+ const schemaheaders: SchemaHeaderField[] = [];
+ this.headerscale = headers.size;
+ headers.forEach((item) => schemaheaders.push(new SchemaHeaderField(item, "#f1efeb")));
+ this.headercount = schemaheaders.length;
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>(schemaheaders);
if (this._maxSearchIndex >= this._numTotalResults) {
this._visibleElements.length = this._results.length;
+ this._visibleDocuments.length = this._results.length;
this._isSearch.length = this._results.length;
}
}
+ @observable headercount: number = 0;
+ @observable headerscale: number = 0;
+
+ findCommonElements(arr2: string[]) {
+ const arr1 = ["layout", "data"];
+ return arr1.some(item => arr2.includes(item));
+ }
@computed
get resFull() { return this._numTotalResults <= 8; }
@@ -504,165 +727,197 @@ export class SearchBox extends React.Component<SearchProps> {
@computed
get resultHeight() { return this._numTotalResults * 70; }
- //if true, any keywords can be used. if false, all keywords are required.
- @action.bound
- handleWordQueryChange = () => {
- this._basicWordStatus = !this._basicWordStatus;
- }
-
- @action.bound
- handleNodeChange = () => {
- this._nodeStatus = !this._nodeStatus;
- if (this._nodeStatus) {
- this.expandSection(`node${this.props.id}`);
- }
- else {
- this.collapseSection(`node${this.props.id}`);
- }
- }
-
- @action.bound
- handleKeyChange = () => {
- this._keyStatus = !this._keyStatus;
- if (this._keyStatus) {
- this.expandSection(`key${this.props.id}`);
- }
- else {
- this.collapseSection(`key${this.props.id}`);
- }
- }
-
- @action.bound
- handleFilterChange = () => {
- this._filterOpen = !this._filterOpen;
- if (this._filterOpen) {
- this.expandSection(`filterhead${this.props.id}`);
- document.getElementById(`filterhead${this.props.id}`)!.style.padding = "5";
- }
- else {
- this.collapseSection(`filterhead${this.props.id}`);
+ addButtonDoc = (doc: Doc) => Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
+ remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
+ moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
+ @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); }
- }
+ getTransform = () => {
+ return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
}
-
- @computed
- get menuHeight() {
- return document.getElementById("hi")?.clientHeight;
+ panelHeight = () => {
+ return this.props.PanelHeight();
}
-
-
- collapseSection(thing: string) {
- const id = this.props.id;
- const element = document.getElementById(thing)!;
- // get the height of the element's inner content, regardless of its actual size
- const sectionHeight = element.scrollHeight;
-
- // temporarily disable all css transitions
- const elementTransition = element.style.transition;
- element.style.transition = '';
-
- // on the next frame (as soon as the previous style change has taken effect),
- // explicitly set the element's height to its current pixel height, so we
- // aren't transitioning out of 'auto'
- requestAnimationFrame(function () {
- element.style.height = sectionHeight + 'px';
- element.style.transition = elementTransition;
-
- // on the next frame (as soon as the previous style change has taken effect),
- // have the element transition to height: 0
- requestAnimationFrame(function () {
- element.style.height = 0 + 'px';
- thing === `filterhead${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
- });
- });
-
- // mark the section as "currently collapsed"
- element.setAttribute('data-collapsed', 'true');
- }
-
- expandSection(thing: string) {
- const element = document.getElementById(thing)!;
- // get the height of the element's inner content, regardless of its actual size
- const sectionHeight = element.scrollHeight;
-
- // have the element transition to the height of its inner content
- element.style.height = sectionHeight + 'px';
-
- // when the next css transition finishes (which should be the one we just triggered)
- element.addEventListener('transitionend', function handler(e) {
- // remove this event listener so it only gets triggered once
- element.removeEventListener('transitionend', handler);
-
- // remove "height" from the element's inline styles, so it can return to its initial value
- element.style.height = "auto";
- //element.style.height = undefined;
- });
-
- // mark the section as "currently not collapsed"
- element.setAttribute('data-collapsed', 'false');
-
+ selectElement = (doc: Doc) => {
+ //this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex));
}
- autoset(thing: string) {
- const element = document.getElementById(thing)!;
- element.removeEventListener('transitionend', function (e) { });
-
- // remove "height" from the element's inline styles, so it can return to its initial value
- element.style.height = "auto";
- //element.style.height = undefined;
+ addDocument = (doc: Doc) => {
+ return null;
}
- @action.bound
- updateTitleStatus() { this._titleFieldStatus = !this._titleFieldStatus; }
-
- @action.bound
- updateAuthorStatus() { this._authorFieldStatus = !this._authorFieldStatus; }
-
- @action.bound
- updateDataStatus() { this._deletedDocsStatus = !this._deletedDocsStatus; }
+ @observable filter = false;
+ //Make id layour document
render() {
-
+ this.props.Document._chromeStatus === "disabled";
+ this.props.Document._searchDoc = true;
+ const cols = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length;
+ let length = 0;
+ 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;
return (
- <div className="searchBox-container">
+ <div style={{ pointerEvents: "all" }} className="searchBox-container">
<div className="searchBox-bar">
- <span className="searchBox-barChild searchBox-collection" onPointerDown={SetupDrag(this.collectionRef, () => this._searchString ? this.startDragCollection() : undefined)} ref={this.collectionRef} title="Drag Results as Collection">
- <FontAwesomeIcon icon="object-group" size="lg" />
- </span>
- <input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
- className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch}
- style={{ width: this._searchbarOpen ? "500px" : "100px" }} />
- <button className="searchBox-barChild searchBox-filter" title="Advanced Filtering Options" onClick={() => this.handleFilterChange()}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button>
- </div>
-
- <div id={`filterhead${this.props.id}`} className="filter-form" >
- <div id={`filterhead2${this.props.id}`} className="filter-header" style={this._filterOpen ? {} : {}}>
- <button className="filter-item" style={this._basicWordStatus ? { background: "#aaaaa3", } : {}} onClick={this.handleWordQueryChange}>Keywords</button>
- <button className="filter-item" style={this._keyStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleKeyChange}>Keys</button>
- <button className="filter-item" style={this._nodeStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleNodeChange}>Nodes</button>
- </div>
- <div id={`node${this.props.id}`} className="filter-body" style={this._nodeStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
- <IconBar setIcons={(icons: string[]) => {
- this._icons = icons;
- }} />
- </div>
- <div className="filter-key" id={`key${this.props.id}`} style={this._keyStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
- <div className="filter-keybar">
- <button className="filter-item" style={this._titleFieldStatus ? { background: "#aaaaa3", } : {}} onClick={this.updateTitleStatus}>Title</button>
- <button className="filter-item" style={this._deletedDocsStatus ? { background: "#aaaaa3", } : {}} onClick={this.updateDataStatus}>Deleted Docs</button>
- <button className="filter-item" style={this._authorFieldStatus ? { background: "#aaaaa3", } : {}} onClick={this.updateAuthorStatus}>Author</button>
+ <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" }} />
+
+ <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" }}
+ 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)]);
+ 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));
+ });
+ 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.props.Document.selectedDoc = this.currentSelectedCollection.props.Document;
+ }
+ else if (this.filter === false && this.currentSelectedCollection !== undefined) {
+
+ dofilter(this.currentSelectedCollection);
+
+ this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
+ this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.props.Document.selectedDoc = undefined;
+ }
+ }
+ )} />
+ </div></Tooltip></div>
+ <input value={this.newsearchstring} autoComplete="off" onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
+ className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch}
+ style={{ padding: 1, paddingLeft: 20, paddingRight: 20, color: "black", height: 20, width: 250 }} />
+ <div style={{
+ height: 25,
+ paddingLeft: "4px",
+ paddingRight: "4px",
+ border: "1px solid gray",
+ borderRadius: "0.3em",
+ borderBottom: this.open === false ? "1px solid" : "none",
+ }}>
+ <form className="beta" style={{ justifyContent: "space-evenly", display: "flex" }}>
+ <div style={{ display: "contents" }}>
+ <div className="radio" style={{ margin: 0 }}>
+ <label style={{ fontSize: 12, marginTop: 6 }} >
+ <input type="radio" style={{ marginLeft: -16, marginTop: -1 }} checked={!this.searchFullDB} onChange={() => {
+ runInAction(() => {
+ this.searchFullDB = !this.searchFullDB;
+ this.dataDoc[this.fieldKey] = new List<Doc>([]);
+ 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>();
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
+ this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.currentSelectedCollection.props.Document._searchDocs = undefined;
+ this.currentSelectedCollection = undefined;
+ }
+ this.submitSearch();
+ });
+ }} />
+ Collection
+ </label>
+ </div>
+ <div className="radio" style={{ margin: 0 }}>
+ <label style={{ fontSize: 12, marginTop: 6 }} >
+ <input style={{ marginLeft: -16, marginTop: -1 }} type="radio" checked={this.searchFullDB} onChange={() => {
+ runInAction(() => {
+ this.searchFullDB = !this.searchFullDB;
+ this.dataDoc[this.fieldKey] = new List<Doc>([]);
+ this.filter = false;
+ 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>();
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
+ this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.currentSelectedCollection.props.Document._searchDocs = undefined;
+ this.currentSelectedCollection = undefined;
+ }
+ this.submitSearch();
+ });
+ }} />
+ DB
+ </label>
+ </div>
+ </div>
+ </form>
</div>
</div>
+
+ </div>
+ <div style={{ zIndex: 20000, color: "black" }}>
+ {this._searchbarOpen === true ?
+ <div style={{ display: "flex", justifyContent: "center", }}>
+ {this.noresults === "" ? <div style={{ display: this.open === true ? "flex" : "none", overflow: "auto", }}>
+ <CollectionView {...this.props}
+ Document={this.props.Document}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ PanelHeight={this.open === true ? () => height : () => 0}
+ PanelWidth={this.open === true ? () => length : () => 0}
+ overflow={cols > 5 || rows > 8 ? true : false}
+ focus={this.selectElement}
+ ScreenToLocalTransform={Transform.Identity}
+ />
+ </div> :
+ <div style={{ display: "flex", justifyContent: "center" }}><div style={{ height: 200, top: 54, minWidth: 400, position: "absolute", backgroundColor: "rgb(241, 239, 235)", display: "flex", justifyContent: "center", alignItems: "center", border: "black 1px solid", }}>
+ <div>{this.noresults}</div>
+ </div></div>}
+ </div> : undefined}
</div>
+
<div className="searchBox-results" onScroll={this.resultsScrolled} style={{
display: this._resultsOpen ? "flex" : "none",
height: this.resFull ? "auto" : this.resultHeight,
overflow: "visibile" // this.resFull ? "auto" : "visible"
}} ref={this._resultsRef}>
- {this._visibleElements}
</div>
- </div>
+ </div >
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss
deleted file mode 100644
index 469f062b2..000000000
--- a/src/client/views/search/SearchItem.scss
+++ /dev/null
@@ -1,163 +0,0 @@
-@import "../globalCssVariables";
-
-.searchItem-overview {
- display: flex;
- flex-direction: reverse;
- justify-content: flex-end;
- z-index: 0;
-}
-
-.searchBox-placeholder,
-.searchItem-overview .searchItem {
- width: 100%;
- background: $light-color-secondary;
- border-color: $intermediate-color;
- border-bottom-style: solid;
- padding: 10px;
- min-height: 50px;
- max-height: 150px;
- height: auto;
- z-index: 0;
- display: flex;
- overflow: visible;
-
- .searchItem-body {
- display: flex;
- flex-direction: row;
- width: 100%;
-
- .searchItem-title-container {
- width: 100%;
- overflow: hidden;
-
- .searchItem-title {
- text-transform: uppercase;
- text-align: left;
- width: 100%;
- font-weight: bold;
- }
- }
-
- .searchItem-info {
- display: flex;
- justify-content: flex-end;
-
- .icon-icons {
- width: 50px
- }
-
- .icon-live {
- width: 175px;
- height: 0px;
- }
-
- .icon-icons {
- height:auto;
- }
- .icon-icons,
- .icon-live {
- margin: auto;
- overflow: visible;
-
- .searchItem-type {
- display: inline-block;
- width: 100%;
- position: absolute;
- justify-content: center;
- align-items: center;
- position: relative;
- margin-right: 5px;
- }
-
- .pdfBox-cont {
- overflow: hidden;
-
- img {
- width: 100% !important;
- height: auto !important;
- }
- }
-
- .searchItem-type:hover+.searchItem-label {
- opacity: 1;
- }
-
- .searchItem-label {
- font-size: 10;
- position: relative;
- right: 0px;
- text-transform: capitalize;
- opacity: 0;
- -webkit-transition: opacity 0.2s ease-in-out;
- -moz-transition: opacity 0.2s ease-in-out;
- -o-transition: opacity 0.2s ease-in-out;
- transition: opacity 0.2s ease-in-out;
- }
- }
-
- .icon-live:hover {
- .pdfBox-cont {
- img {
- width: 100% !important;
- }
- }
- }
- }
-
- .searchItem-info:hover {
- width: 60%;
- }
- }
-}
-
-.searchItem:hover~.searchBox-instances,
-.searchBox-instances:hover,
-.searchBox-instances:active {
- opacity: 1;
- background: $lighter-alt-accent;
-}
-
-.searchItem:hover {
- transition: all 0.2s;
- background: $lighter-alt-accent;
-}
-
-.searchItem-highlighting {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: pre;
-}
-
-.searchBox-instances {
- opacity: 1;
- width:40px;
- height:40px;
- background: gray;
- transition: all 0.2s ease;
- color: black;
- overflow: hidden;
- right:-100;
- display:inline-block;
-}
-
-
-.searchItem-overview:hover {
- z-index: 1;
-}
-
-.searchBox-placeholder {
- min-height: 50px;
- margin-left: 150px;
- width: calc(100% - 150px);
- text-transform: uppercase;
- text-align: left;
- font-weight: bold;
-}
-
-.collection {
- display: flex;
-}
-
-.collection-item {
- width: 35px;
-} \ No newline at end of file
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
deleted file mode 100644
index 2436bf418..000000000
--- a/src/client/views/search/SearchItem.tsx
+++ /dev/null
@@ -1,310 +0,0 @@
-import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero, returnEmptyString, returnEmptyFilter } from "../../../Utils";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DragManager, SetupDrag } from "../../util/DragManager";
-import { SearchUtil } from "../../util/SearchUtil";
-import { Transform } from "../../util/Transform";
-import { SEARCH_THUMBNAIL_SIZE } from "../../views/globalCssVariables.scss";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionViewType } from "../collections/CollectionView";
-import { ParentDocSelector } from "../collections/ParentDocumentSelector";
-import { ContextMenu } from "../ContextMenu";
-import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { SearchBox } from "./SearchBox";
-import "./SearchItem.scss";
-import "./SelectorContextMenu.scss";
-
-export interface SearchItemProps {
- doc: Doc;
- query: string;
- highlighting: string[];
- lines: string[];
-}
-
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFile);
-library.add(faFilePdf);
-library.add(faFilm);
-library.add(faMusic);
-library.add(faLink);
-library.add(faChartBar);
-library.add(faGlobeAsia, faFingerprint);
-
-@observer
-export class SelectorContextMenu extends React.Component<SearchItemProps> {
- @observable private _docs: { col: Doc, target: Doc }[] = [];
- @observable private _otherDocs: { col: Doc, target: Doc }[] = [];
-
- constructor(props: SearchItemProps) {
- super(props);
- this.fetchDocuments();
- }
-
- async fetchDocuments() {
- const aliases = (await SearchUtil.GetViewsOfDocument(this.props.doc)).filter(doc => doc !== this.props.doc);
- const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.doc[Id]}"` });
- const map: Map<Doc, Doc> = new Map;
- const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs)));
- allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
- docs.forEach(doc => map.delete(doc));
- runInAction(() => {
- this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: this.props.doc }));
- this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target }));
-
- });
- }
-
- getOnClick({ col, target }: { col: Doc, target: Doc }) {
- return () => {
- col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
- if (col._viewType === CollectionViewType.Freeform) {
- const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
- const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
- col._panX = newPanX;
- col._panY = newPanY;
- }
- CollectionDockingView.AddRightSplit(col);
- };
- }
- render() {
- return (
- <div className="parents">
- <p className="contexts">Contexts:</p>
- {[...this._docs, ...this._otherDocs].map(doc => {
- const item = React.createRef<HTMLDivElement>();
- return <div className="collection" key={doc.col[Id] + doc.target[Id]} ref={item}>
- <div className="collection-item" onPointerDown={
- SetupDrag(item, () => doc.col, undefined, undefined, () => SearchBox.Instance.closeSearch())}>
- <FontAwesomeIcon icon={faStickyNote} />
- </div>
- <a onClick={this.getOnClick(doc)}>{doc.col.title}</a>
- </div>;
- })}
- </div>
- );
- }
-}
-
-export interface LinkMenuProps {
- doc1: Doc;
- doc2: Doc;
-}
-
-@observer
-export class LinkContextMenu extends React.Component<LinkMenuProps> {
-
- highlightDoc = (doc: Doc) => () => Doc.BrushDoc(doc);
-
- unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
-
- getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col);
-
- render() {
- return (
- <div className="parents">
- <p className="contexts">Anchors:</p>
- <div className="collection"><a onMouseEnter={this.highlightDoc(this.props.doc1)} onMouseLeave={this.unHighlightDoc(this.props.doc1)} onClick={this.getOnClick(this.props.doc1)}>Doc 1: {this.props.doc2.title}</a></div>
- <div><a onMouseEnter={this.highlightDoc(this.props.doc2)} onMouseLeave={this.unHighlightDoc(this.props.doc2)} onClick={this.getOnClick(this.props.doc2)}>Doc 2: {this.props.doc1.title}</a></div>
- </div>
- );
- }
-
-}
-
-@observer
-export class SearchItem extends React.Component<SearchItemProps> {
-
- @observable _selected: boolean = false;
-
- onClick = () => {
- // I dont think this is the best functionality because clicking the name of the collection does that. Change it back if you'd like
- DocumentManager.Instance.jumpToDocument(this.props.doc, false);
- }
- @observable _useIcons = true;
- @observable _displayDim = 50;
-
- componentDidMount() {
- Doc.SetSearchQuery(this.props.query);
- this.props.doc.searchMatch = true;
- }
- componentWillUnmount() {
- this.props.doc.searchMatch = undefined;
- }
-
- //@computed
- @action
- public DocumentIcon() {
- const layoutresult = StrCast(this.props.doc.type);
- if (!this._useIcons) {
- const returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
- const returnYDimension = () => this._displayDim;
- const docview = <div
- onPointerDown={action(() => {
- this._useIcons = !this._useIcons;
- this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
- })}
- onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))} >
- <ContentFittingDocumentView
- Document={this.props.doc}
- LibraryPath={emptyPath}
- rootSelected={returnFalse}
- fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- docFilters={returnEmptyFilter}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
- ScreenToLocalTransform={Transform.Identity}
- renderDepth={1}
- PanelWidth={returnXDimension}
- PanelHeight={returnYDimension}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- focus={emptyFunction}
- moveDocument={returnFalse}
- parentActive={returnFalse}
- whenActiveChanged={returnFalse}
- bringToFront={returnFalse}
- ContentScaling={returnOne}
- />
- </div>;
- return docview;
- }
- const button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf :
- layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage :
- layoutresult.indexOf(DocumentType.RTF) !== -1 ? faStickyNote :
- layoutresult.indexOf(DocumentType.VID) !== -1 ? faFilm :
- layoutresult.indexOf(DocumentType.COL) !== -1 ? faObjectGroup :
- layoutresult.indexOf(DocumentType.AUDIO) !== -1 ? faMusic :
- layoutresult.indexOf(DocumentType.LINK) !== -1 ? faLink :
- layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
- faCaretUp;
- return <div onClick={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
- <FontAwesomeIcon icon={button} size="2x" />
- </div>;
- }
-
- collectionRef = React.createRef<HTMLDivElement>();
-
- @action
- pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); }
-
- nextHighlight = (e: React.PointerEvent) => {
- e.preventDefault();
- e.button === 0 && SearchBox.Instance.openSearch(e);
- this.props.doc.searchMatch = false;
- setTimeout(() => this.props.doc.searchMatch = true, 0);
- }
- highlightDoc = (e: React.PointerEvent) => {
- if (this.props.doc.type === DocumentType.LINK) {
- if (this.props.doc.anchor1 && this.props.doc.anchor2) {
-
- const doc1 = Cast(this.props.doc.anchor1, Doc, null);
- const doc2 = Cast(this.props.doc.anchor2, Doc, null);
- Doc.BrushDoc(doc1);
- Doc.BrushDoc(doc2);
- }
- } else {
- Doc.BrushDoc(this.props.doc);
- }
- e.stopPropagation();
- }
-
- unHighlightDoc = (e: React.PointerEvent) => {
- if (this.props.doc.type === DocumentType.LINK) {
- if (this.props.doc.anchor1 && this.props.doc.anchor2) {
-
- const doc1 = Cast(this.props.doc.anchor1, Doc, null);
- const doc2 = Cast(this.props.doc.anchor2, Doc, null);
- Doc.UnBrushDoc(doc1);
- Doc.UnBrushDoc(doc2);
- }
- } else {
- Doc.UnBrushDoc(this.props.doc);
- }
- }
-
- onContextMenu = (e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({
- description: "Copy ID", event: () => {
- Utils.CopyText(this.props.doc[Id]);
- },
- icon: "fingerprint"
- });
- ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
- }
-
- _downX = 0;
- _downY = 0;
- _target: any;
- onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- e.stopPropagation();
- this._target = e.currentTarget;
- document.removeEventListener("pointermove", this.onPointerMoved);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointermove", this.onPointerMoved);
- document.addEventListener("pointerup", this.onPointerUp);
- }
- onPointerMoved = (e: PointerEvent) => {
- if (Math.abs(e.clientX - this._downX) > Utils.DRAG_THRESHOLD ||
- Math.abs(e.clientY - this._downY) > Utils.DRAG_THRESHOLD) {
- document.removeEventListener("pointermove", this.onPointerMoved);
- document.removeEventListener("pointerup", this.onPointerUp);
- const doc = Doc.IsPrototype(this.props.doc) ? Doc.MakeDelegate(this.props.doc) : this.props.doc;
- DragManager.StartDocumentDrag([this._target], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY);
- }
- }
- onPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onPointerMoved);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- @computed
- get contextButton() {
- return <ParentDocSelector Document={this.props.doc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
- }
-
- render() {
- const doc1 = Cast(this.props.doc.anchor1, Doc);
- const doc2 = Cast(this.props.doc.anchor2, Doc);
- return <div className="searchItem-overview" onPointerDown={this.pointerDown} onContextMenu={this.onContextMenu}>
- <div className="searchItem" onPointerDown={this.nextHighlight} onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc}>
- <div className="searchItem-body" onClick={this.onClick}>
- <div className="searchItem-title-container">
- <div className="searchItem-title">{StrCast(this.props.doc.title)}</div>
- <div className="searchItem-highlighting">{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? this.props.lines[0] : ""}</div>
- {this.props.lines.filter((m, i) => i).map((l, i) => <div id={i.toString()} className="searchItem-highlighting">`${l}`</div>)}
- </div>
- </div>
- <div className="searchItem-info" style={{ width: this._useIcons ? "30px" : "100%" }}>
- <div className={`icon-${this._useIcons ? "icons" : "live"}`}>
- <div className="searchItem-type" title="Click to Preview" onPointerDown={this.onPointerDown}>{this.DocumentIcon()}</div>
- <div className="searchItem-label">{this.props.doc.type ? this.props.doc.type : "Other"}</div>
- </div>
- </div>
- <div className="searchItem-context" title="Drag as document">
- {(doc1 instanceof Doc && doc2 instanceof Doc) && this.props.doc.type === DocumentType.LINK ? <LinkContextMenu doc1={doc1} doc2={doc2} /> :
- this.contextButton}
- </div>
- </div>
- </div>;
- }
-} \ No newline at end of file
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index f4505d475..ad6a9ac1d 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1266,4 +1266,4 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo
return docs.length ? new List(docs) : prevValue;
});
Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "match" | "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); });
-Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file
+Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); });
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
index 753c31fcf..7251e07a1 100644
--- a/src/server/ApiManagers/SearchManager.ts
+++ b/src/server/ApiManagers/SearchManager.ts
@@ -176,7 +176,7 @@ export namespace SolrManager {
"audio": ["_t", "url"],
"web": ["_t", "url"],
"date": ["_d", value => new Date(value.date).toISOString()],
- "proxy": ["_i", "fieldId"],
+ // "proxy": ["_i", "fieldId"],
"list": ["_l", list => {
const results = [];
for (const value of list.fields) {
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 4455d11eb..515fbe4ff 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -14,7 +14,6 @@ import { normalize } from "path";
import RouteSubscriber from "../RouteSubscriber";
const imageDataUri = require('image-data-uri');
import { isWebUri } from "valid-url";
-import { launch } from "puppeteer";
import { Opt } from "../../fields/Doc";
import { SolrManager } from "./SearchManager";
@@ -281,25 +280,26 @@ function delay(ms: number) {
*
* On failure, returns undefined.
*/
-async function captureYoutubeScreenshot(targetUrl: string): Promise<Opt<Buffer>> {
- const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
- const page = await browser.newPage();
- await page.setViewport({ width: 1920, height: 1080 });
+async function captureYoutubeScreenshot(targetUrl: string){
+ // const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
+ // const page = await browser.newPage();
+ // // await page.setViewport({ width: 1920, height: 1080 });
- await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any });
+ // // await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any });
- const videoPlayer = await page.$('.html5-video-player');
- videoPlayer && await page.focus("video");
- await delay(7000);
- const ad = await page.$('.ytp-ad-skip-button-text');
- await ad?.click();
- await videoPlayer?.click();
- await delay(1000);
- // hide youtube player controls.
- await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
+ // const videoPlayer = await page.$('.html5-video-player');
+ // videoPlayer && await page.focus("video");
+ // await delay(7000);
+ // const ad = await page.$('.ytp-ad-skip-button-text');
+ // await ad?.click();
+ // await videoPlayer?.click();
+ // await delay(1000);
+ // // hide youtube player controls.
+ // await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
- const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
- await browser.close();
+ // const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
+ // await browser.close();
- return buffer;
+ // return buffer;
+ return null;
} \ No newline at end of file
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index d81450b32..63cfa41f0 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -16,6 +16,7 @@ import { DocumentsCollection } from "./IDatabase";
import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from "./Message";
import { Search } from "./Search";
import { resolvedPorts } from './server_Initialization';
+import { Opt } from "../fields/Doc";
export namespace WebSocket {
@@ -31,7 +32,7 @@ export namespace WebSocket {
if (socketPort) {
resolvedPorts.socket = Number(socketPort);
}
- let socketEndpoint: Server;
+ let socketEndpoint: Opt<Server>;
await new Promise<void>(resolve => socketEndpoint = createServer(SSL.Credentials, app).listen(resolvedPorts.socket, resolve));
io = sio(socketEndpoint!, SSL.Credentials as any);
} else {
@@ -229,7 +230,8 @@ export namespace WebSocket {
"script": ["_t", value => value.script.originalScript],
"RichTextField": ["_t", value => value.Text],
"date": ["_d", value => new Date(value.date).toISOString()],
- "proxy": ["_i", "fieldId"],
+ // "proxy": ["_i", "fieldId"],
+ // "proxy": ["", "fieldId"],
"list": ["_l", list => {
const results = [];
for (const value of list.fields) {
@@ -243,25 +245,27 @@ export namespace WebSocket {
};
function ToSearchTerm(val: any): { suffix: string, value: any } | undefined {
+
if (val === null || val === undefined) {
return;
}
const type = val.__type || typeof val;
+
let suffix = suffixMap[type];
if (!suffix) {
return;
}
-
if (Array.isArray(suffix)) {
const accessor = suffix[1];
if (typeof accessor === "function") {
val = accessor(val);
} else {
val = val[accessor];
+
}
suffix = suffix[0];
- }
+ }
return { suffix, value: val };
}
@@ -283,7 +287,7 @@ export namespace WebSocket {
dynfield = true;
const val = docfield[key];
key = key.substring(7);
- Object.values(suffixMap).forEach(suf => update[key + getSuffix(suf)] = { set: null });
+ Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
const term = ToSearchTerm(val);
if (term !== undefined) {
const { suffix, value } = term;