aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json9
-rw-r--r--package.json1
-rw-r--r--solr-8.3.1/CHANGES.txt2
-rwxr-xr-x[-rw-r--r--]solr-8.3.1/bin/solr0
-rw-r--r--solr-8.3.1/bin/solr-8983.pid2
-rw-r--r--solr-8.3.1/server/solr/dash/conf/schema.xml3
-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.ts37
-rw-r--r--src/client/util/Scripting.ts2
-rw-r--r--src/client/util/SearchUtil.ts2
-rw-r--r--src/client/util/SettingsManager.scss249
-rw-r--r--src/client/util/SettingsManager.tsx191
-rw-r--r--src/client/views/ContextMenu.scss5
-rw-r--r--src/client/views/DocumentButtonBar.scss8
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/EditableView.tsx41
-rw-r--r--src/client/views/Main.scss6
-rw-r--r--src/client/views/MainView.scss14
-rw-r--r--src/client/views/MainView.tsx79
-rw-r--r--src/client/views/MainViewModal.tsx4
-rw-r--r--src/client/views/PropertiesButtons.scss30
-rw-r--r--src/client/views/PropertiesButtons.tsx366
-rw-r--r--src/client/views/SearchDocBox.tsx428
-rw-r--r--src/client/views/collections/CollectionLinearView.scss2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx101
-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/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx67
-rw-r--r--src/client/views/collections/CollectionTreeView.scss15
-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/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.scss16
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx385
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/linking/LinkEditor.scss3
-rw-r--r--src/client/views/linking/LinkEditor.tsx6
-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.scss8
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx8
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/FieldView.tsx7
-rw-r--r--src/client/views/nodes/FontIconBox.scss5
-rw-r--r--src/client/views/nodes/FontIconBox.tsx18
-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.tsx2
-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
70 files changed, 2116 insertions, 2577 deletions
diff --git a/package-lock.json b/package-lock.json
index da700cee2..19f10bb63 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1102,15 +1102,6 @@
"@types/prosemirror-transform": "*"
}
},
- "@types/puppeteer": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-2.1.1.tgz",
- "integrity": "sha512-FqPZvUtnpTGrqbHvPUn76pvVcBPEVEqZftrdOjr6YRkaaxkjKQ8dQLNaQBjER7Lvd1Q6+0R0XR+N3tYGWBSzNw==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
"@types/qs": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz",
diff --git a/package.json b/package.json
index 7ae7cdc95..47aea960f 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,6 @@
"@types/prosemirror-state": "^1.2.4",
"@types/prosemirror-transform": "^1.1.1",
"@types/prosemirror-view": "^1.11.2",
- "@types/puppeteer": "^2.1.1",
"@types/rc-switch": "^1.9.0",
"@types/react": "^16.9.41",
"@types/react-autosuggest": "^9.3.14",
diff --git a/solr-8.3.1/CHANGES.txt b/solr-8.3.1/CHANGES.txt
index 219888b49..78ee2efc1 100644
--- a/solr-8.3.1/CHANGES.txt
+++ b/solr-8.3.1/CHANGES.txt
@@ -66,7 +66,7 @@ Upgrade Notes
----------------------
* Users who have written test cases that extend SolrTestCaseJ4 may see NullPointerExceptions if
- their tests directly reference both SolrTestCaseJ4.initCoreDataDir and SolrTestCaseJ4.deleteCore().
+ their tests directly reference both SolrTestCaseJ4.initCoreDataDir and TestCaseJ4.deleteCore().
This change in behavior is due to a bug fix in deleteCore() to ensure the dataDir is properly reset
in tests that call initCore()/deleteCore() multiple times in a given test (class). initCoreDataDir
is now deprecated, and users are encouraged to use SolrTestCaseJ4.initAndGetDataDir() in it's place.
diff --git a/solr-8.3.1/bin/solr b/solr-8.3.1/bin/solr
index 596242fac..596242fac 100644..100755
--- a/solr-8.3.1/bin/solr
+++ b/solr-8.3.1/bin/solr
diff --git a/solr-8.3.1/bin/solr-8983.pid b/solr-8.3.1/bin/solr-8983.pid
index 779eb1af5..1f77d281d 100644
--- a/solr-8.3.1/bin/solr-8983.pid
+++ b/solr-8.3.1/bin/solr-8983.pid
@@ -1 +1 @@
-17656
+1731
diff --git a/solr-8.3.1/server/solr/dash/conf/schema.xml b/solr-8.3.1/server/solr/dash/conf/schema.xml
index c0a4bab07..36e803d83 100644
--- a/solr-8.3.1/server/solr/dash/conf/schema.xml
+++ b/solr-8.3.1/server/solr/dash/conf/schema.xml
@@ -44,6 +44,9 @@
<field name="text" type="text" indexed="true" stored="false" uninvertible="false" multiValued="true"/>
<field name="id" type="string" indexed="true" stored="true" uninvertible="false" required="true"/>
<field name="_version_" type="plong" indexed="true" stored="true"/>
+ <field name="proto" type="string" indexed="true" stored="true" uninvertible="false" />
+ <field name="_height" type="pdouble" indexed="true" stored="true" uninvertible="false" docValues="true"/>
+
<dynamicField name="*_t" type="text" indexed="true" stored="true" uninvertible="false" docValues="false"/>
<dynamicField name="*_n" type="pdouble" indexed="true" stored="true" uninvertible="false" docValues="false"/>
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 959aeac41..7719b3eef 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";
@@ -39,7 +41,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";
@@ -47,7 +48,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');
@@ -197,10 +197,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 {
@@ -230,8 +230,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, {
@@ -638,8 +638,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 4e59434b5..1f140e145 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -8,7 +8,7 @@ import { Doc, DocListCast, DocListCastAsync, DataSym } from "../../fields/Doc";
import { List } from "../../fields/List";
import { listSpec } from "../../fields/Schema";
import { ScriptField, ComputedField } from "../../fields/ScriptField";
-import { Cast, PromiseValue, StrCast, NumCast } from "../../fields/Types";
+import { Cast, PromiseValue, StrCast, NumCast, BoolCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
import { DragManager } from "./DragManager";
import { Scripting } from "./Scripting";
@@ -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 }) =>
@@ -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;
@@ -774,8 +781,8 @@ export class CurrentUserUtils {
// 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);
+ CurrentUserUtils.setupSidebarContainer(doc);
+ await CurrentUserUtils.setupToolsBtnPanel(doc);
CurrentUserUtils.setupWorkspaces(doc);
CurrentUserUtils.setupCatalog(doc);
CurrentUserUtils.setupRecentlyClosed(doc);
@@ -813,6 +820,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 +834,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" }));
}
}
@@ -890,14 +902,17 @@ export class CurrentUserUtils {
doc.fontFamily = StrCast(doc.fontFamily, "Arial");
doc.fontColor = StrCast(doc.fontColor, "black");
doc.fontHighlight = StrCast(doc.fontHighlight, "");
+ doc.defaultColor = StrCast(doc.defaultColor, "white");
+ doc.noviceMode = BoolCast(doc.noviceMode, true);
doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); //
doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); //
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/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index 6923fe879..41bce8a1b 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -1,7 +1,7 @@
@import "../views/globalCssVariables";
.settings-interface {
- background-color: whitesmoke !important;
+ //background-color: whitesmoke !important;
color: grey;
width: 450px;
height: 300px;
@@ -22,85 +22,232 @@
}
}
-.settings-interface {
+.settings-title {
+ font-size: 25px;
+ font-weight: bold;
+ padding-right: 10px;
+ color: black;
+}
+
+.settings-username {
+ font-size: 14px;
+ padding-right: 15px;
+ color: black;
+ margin-top: 10px;
+}
+
+.settings-section {
display: flex;
- flex-direction: column;
+ border-bottom: 1px solid grey;
+ padding-bottom: 8px;
+ padding-top: 6px;
- button {
- width: 100%;
- align-self: center;
- background: #252b33;
- margin-top: 4px;
+ .settings-section-title {
+ font-size: 16;
+ font-weight: bold;
+ text-align: left;
+ color: black;
+ width: 80;
+ margin-right: 50px;
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+
+.password-content {
+ display: flex;
+
+ .password-content-inputs {
+ width: 100;
+
+ .password-inputs {
+ border: none;
+ margin-bottom: 8px;
+ width: 180;
+ color: black;
+ border-radius: 5px;
+ }
+ }
+
+ .password-content-buttons {
+ margin-left: 84px;
+ width: 100;
+
+ .password-submit {
+ margin-left: 85px;
+ }
+
+ .password-forgot {
+ margin-left: 65px;
+ margin-top: -20px;
+ white-space: nowrap;
+ }
+ }
+}
+
+.accounts-content {
+ display: flex;
+}
+
+.modes-content {
+ display: flex;
+
+ .modes-select {
+ width: 170px;
+ margin-right: 65px;
+ color: black;
+ border-radius: 5px;
&:hover {
- background: $main-accent;
+ cursor: pointer;
}
}
- .delete-button {
- background: rgb(227, 86, 86);
+ .modes-playground {
+ display: flex;
+
+ .playground-check {
+ margin-right: 5px;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+
+ .playground-text {
+ color: black;
+ }
}
+}
- .close-button {
- position: absolute;
- right: 1em;
- top: 1em;
+.colorFlyout {
+ margin-top: 2px;
+ margin-right: 25px;
+
+ &:hover {
cursor: pointer;
}
- .settings-heading {
- letter-spacing: .5em;
+ .colorFlyout-button {
+ width: 20px;
+ height: 20px;
+ border: 0.5px solid black;
+ border-radius: 5px;
}
+}
+.preferences-content {
+ display: flex;
+ margin-top: 4px;
- .settings-body {
+ .preferences-color {
display: flex;
- justify-content: space-between;
- margin-top: -10;
- .settings-type {
- display: flex;
- flex-direction: column;
- flex-basis: 45%;
+ .preferences-color-text {
+ color: black;
+ font-size: 11;
+ margin-top: 4;
+ margin-right: 4;
+ }
+ }
+ .preferences-font {
+ display: flex;
+
+ .preferences-font-text {
+ color: black;
+ font-size: 11;
+ margin-top: 4;
+ margin-right: 4;
}
- .settings-content {
- padding-left: 1em;
- padding-right: 1em;
- display: flex;
- flex-direction: column;
- flex-basis: 70%;
- justify-content: space-around;
- text-align: left;
-
- ::placeholder {
- color: $intermediate-color;
- }
+ .font-select {
+ width: 100px;
+ color: black;
+ font-size: 9;
+ margin-right: 6;
+ border-radius: 5px;
- input {
- border-radius: 5px;
- border: none;
- padding: 4px;
- min-width: 100%;
- margin: 2px 0;
+ &:hover {
+ cursor: pointer;
}
+ }
- .error-text {
- color: #C40233;
- }
+ .size-select {
+ width: 60px;
+ color: black;
+ font-size: 9;
+ border-radius: 5px;
- .success-text {
- color: #009F6B;
+ &:hover {
+ cursor: pointer;
}
+ }
+ }
+}
- p {
- padding: 0 0 .1em .2em;
- }
+.settings-interface {
+ display: flex;
+ flex-direction: column;
+
+ button {
+ width: auto;
+ align-self: center;
+ background: #252b33;
+ margin-right: 15px;
+ //margin-top: 4px;
+
+ &:hover {
+ background: $main-accent;
}
}
+ // .delete-button {
+ // background: rgb(227, 86, 86);
+ // }
+
+ .close-button {
+ position: absolute;
+ right: 1em;
+ top: 1em;
+ cursor: pointer;
+ }
+
+ .settings-content {
+ background: #e4e4e4;
+ border-radius: 6px;
+ padding: 10px;
+ width: 560px;
+ }
+
+ .settings-top {
+ display: flex;
+ margin-bottom: 10px;
+ }
+
+
+ .error-text {
+ color: #C40233;
+ width: 300;
+ margin-left: -20;
+ font-size: 10;
+ margin-bottom: 4;
+ margin-top: -3;
+ }
+
+ .success-text {
+ width: 300;
+ margin-left: -20;
+ font-size: 10;
+ margin-bottom: 4;
+ margin-top: -3;
+ color: #009F6B;
+ }
+
.focus-span {
text-decoration: underline;
}
@@ -138,8 +285,6 @@
color: black;
}
-
-
}
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 6276fae96..68ed32c0f 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,4 +1,4 @@
-import { observable, runInAction, action } from "mobx";
+import { observable, runInAction, action, computed } from "mobx";
import * as React from "react";
import MainViewModal from "../views/MainViewModal";
import { observer } from "mobx-react";
@@ -15,6 +15,12 @@ import GroupManager from "./GroupManager";
import HypothesisAuthenticationManager from "../apis/HypothesisAuthenticationManager";
import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
import { DocServer } from "../DocServer";
+import { BoolCast, StrCast, NumCast } from "../../fields/Types";
+import { undoBatch } from "./UndoManager";
+import { ColorState, SketchPicker } from "react-color";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
library.add(fa.faTimes);
@@ -33,6 +39,9 @@ export default class SettingsManager extends React.Component<{}> {
private new_password_ref = React.createRef<HTMLInputElement>();
private new_confirm_ref = React.createRef<HTMLInputElement>();
+
+ @computed get backgroundColor() { return Doc.UserDoc().defaultColor; }
+
public open = action(() => {
SelectionManager.DeselectAll();
this.isOpen = true;
@@ -107,50 +116,151 @@ export default class SettingsManager extends React.Component<{}> {
addStyleSheetRule(SettingsManager._settingsStyle, "lm_header", { background: "pink !important" });
}
+ @action
+ changeMode = (e: any) => {
+ if (e.currentTarget.value === "Novice") {
+ Doc.UserDoc().noviceMode = true;
+ } else {
+ Doc.UserDoc().noviceMode = false;
+ }
+ }
+
+ @action
+ changeFontFamily = (e: any) => {
+ Doc.UserDoc().fontFamily = e.currentTarget.value;
+ }
+
+ @action
+ changeFontSize = (e: any) => {
+ Doc.UserDoc().fontSize = e.currentTarget.value;
+ }
+
+ @action @undoBatch
+ switchColor = (color: ColorState) => {
+ const val = String(color.hex);
+ Doc.UserDoc().defaultColor = val;
+ return true;
+ }
+
private get settingsInterface() {
- return (
- <div className={"settings-interface"}>
- <div className="settings-heading">
- <h1>settings</h1>
- <div className={"close-button"} onClick={this.close}>
- <FontAwesomeIcon icon={fa.faTimes} color="black" size={"lg"} />
- </div>
- </div>
- <div className="settings-body">
- <div className="settings-type">
- <button onClick={this.onClick} value="password">reset password</button>
- <button onClick={this.noviceToggle} value="data">{`Set ${Doc.UserDoc().noviceMode ? "developer" : "novice"} mode`}</button>
- <button onClick={this.togglePlaygroundMode}>{`${this.playgroundMode ? "Disable" : "Enable"} playground mode`}</button>
- <button onClick={this.googleAuthorize} value="data">{`Link to Google`}</button>
- <button onClick={this.hypothesisAuthorize} value="data">{`Link to Hypothes.is`}</button>
- <button onClick={() => GroupManager.Instance.open()}>Manage groups</button>
- <button onClick={() => window.location.assign(Utils.prepend("/logout"))}>
- {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
- </button>
+
+
+ const passwordContent = <div className="password-content">
+ <div className="password-content-inputs">
+ <input className="password-inputs" type="password" placeholder="current password" ref={this.curr_password_ref} />
+ <input className="password-inputs" type="password" placeholder="new password" ref={this.new_password_ref} />
+ <input className="password-inputs" type="password" placeholder="confirm new password" ref={this.new_confirm_ref} />
+ </div>
+ <div className="password-content-buttons">
+ {this.errorText ? <div className="error-text">{this.errorText}</div> : undefined}
+ {this.successText ? <div className="success-text">{this.successText}</div> : undefined}
+ <button className="password-submit" onClick={this.dispatchRequest}>submit</button>
+ <a className="password-forgot" style={{ marginLeft: 65, marginTop: -20 }}
+ href="/forgotPassword">forgot password?</a>
+ </div>
+ </div>;
+
+ const modesContent = <div className="modes-content">
+ <select className="modes-select"
+ onChange={e => this.changeMode(e)}>
+ <option key={"Novice"} value={"Novice"} selected={BoolCast(Doc.UserDoc().noviceMode)}>
+ Novice
+ </option>
+ <option key={"Developer"} value={"Developer"} selected={!BoolCast(Doc.UserDoc().noviceMode)}>
+ Developer
+ </option>
+ </select>
+ <div className="modes-playground">
+ <input className="playground-check" type="checkbox"
+ checked={this.playgroundMode}
+ onChange={undoBatch(action(() => this.togglePlaygroundMode()))}
+ /><div className="playground-text">Playground Mode</div>
+ </div>
+ </div>;
+
+ const accountsContent = <div className="accounts-content">
+ <button onClick={this.googleAuthorize} value="data">{`Link to Google`}</button>
+ <button onClick={this.hypothesisAuthorize} value="data">{`Link to Hypothes.is`}</button>
+ <button onClick={() => GroupManager.Instance.open()}>Manage groups</button>
+ </div>;
+
+ const colorBox = <SketchPicker onChange={this.switchColor}
+ presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+ '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+ '#FFFFFF', '#f1efeb', 'transparent']}
+ color={StrCast(this.backgroundColor)} />;
+
+ const colorFlyout = <div className="colorFlyout">
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+ content={colorBox}>
+ <div>
+ <div className="colorFlyout-button" style={{ backgroundColor: StrCast(this.backgroundColor) }}
+ onPointerDown={e => e.stopPropagation()} >
+ <FontAwesomeIcon icon="palette" size="sm" color={StrCast(this.backgroundColor)} />
</div>
- {this.settingsContent === "password" ?
- <div className="settings-content">
- <input placeholder="current password" ref={this.curr_password_ref} />
- <input placeholder="new password" ref={this.new_password_ref} />
- <input placeholder="confirm new password" ref={this.new_confirm_ref} />
- {this.errorText ? <div className="error-text">{this.errorText}</div> : undefined}
- {this.successText ? <div className="success-text">{this.successText}</div> : undefined}
- <button onClick={this.dispatchRequest}>submit</button>
- <a style={{ marginLeft: 65, marginTop: -20 }} href="/forgotPassword">forgot password?</a>
-
- </div>
- : undefined}
- {this.settingsContent === "data" ?
- <div className="settings-content">
- <p>WARNING: <br />
- THIS WILL ERASE ALL YOUR CURRENT DOCUMENTS STORED ON DASH. IF YOU WISH TO PROCEED, CLICK THE BUTTON BELOW.</p>
- <button className="delete-button">DELETE</button>
- </div>
- : undefined}
</div>
+ </Flyout>
+ </div>;
+ const fontFamilies: string[] = ["Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"];
+ const fontSizes: string[] = ["7pt", "8pt", "9pt", "10pt", "12pt", "14pt", "16pt", "18pt", "20pt", "24pt", "32pt", "48pt", "72pt"];
+
+ const preferencesContent = <div className="preferences-content">
+ <div className="preferences-color">
+ <div className="preferences-color-text">Background Color</div> {colorFlyout}
</div>
- );
+ <div className="preferences-font">
+ <div className="preferences-font-text">Default Font</div>
+ <select className="font-select"
+ onChange={e => this.changeFontFamily(e)}>
+ {fontFamilies.map((font) => {
+ return <option key={font} value={font} selected={StrCast(Doc.UserDoc().fontFamily) === font}>
+ {font}
+ </option>;
+ })}
+ </select>
+ <select className="size-select"
+ onChange={e => this.changeFontSize(e)}>
+ {fontSizes.map((size) => {
+ return <option key={size} value={size} selected={StrCast(Doc.UserDoc().fontSize) === size}>
+ {size}
+ </option>;
+ })}
+ </select>
+ </div>
+ </div>;
+
+ return (<div className="settings-interface">
+ <div className="settings-top">
+ <div className="settings-title">Settings</div>
+ <div className="settings-username">{Doc.CurrentUserEmail}</div>
+ <button onClick={() => window.location.assign(Utils.prepend("/logout"))}
+ style={{ right: 35, position: "absolute" }} >
+ {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
+ </button>
+ <div className="close-button" onClick={this.close}>
+ <FontAwesomeIcon icon={fa.faTimes} color="black" size={"lg"} />
+ </div>
+ </div>
+ <div className="settings-content">
+ <div className="settings-section">
+ <div className="settings-section-title">Password</div>
+ <div className="settings-section-context">{passwordContent}</div>
+ </div>
+ <div className="settings-section">
+ <div className="settings-section-title">Modes</div>
+ <div className="settings-section-context">{modesContent}</div>
+ </div>
+ <div className="settings-section">
+ <div className="settings-section-title">Accounts</div>
+ <div className="settings-section-context">{accountsContent}</div>
+ </div>
+ <div className="settings-section" style={{ paddingBottom: 4 }}>
+ <div className="settings-section-title">Preferences</div>
+ <div className="settings-section-context">{preferencesContent}</div>
+ </div>
+ </div>
+ </div>);
}
render() {
@@ -160,6 +270,7 @@ export default class SettingsManager extends React.Component<{}> {
isDisplayed={this.isOpen}
interactive={true}
closeOnExternalClick={this.close}
+ dialogueBoxStyle={{ width: "600px", height: "340px" }}
/>
);
}
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 86e0a568a..7467bc043 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -7,7 +7,7 @@
box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw;
flex-direction: column;
background: whitesmoke;
- padding-top: 10px;
+ padding-top: 10px;
padding-bottom: 10px;
border-radius: 15px;
border: solid #BBBBBBBB 1px;
@@ -72,6 +72,7 @@
margin-left: 5px;
}
}
+
.contextMenu-description {
// width: 11vw; //10vw
background: whitesmoke;
@@ -100,6 +101,8 @@
border-color: $intermediate-color; // rgb(187, 186, 186);
border-bottom-style: solid;
border-top-style: solid;
+
+ cursor: pointer;
}
.contextMenu-itemSelected {
diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss
index c2ca93900..09ae14016 100644
--- a/src/client/views/DocumentButtonBar.scss
+++ b/src/client/views/DocumentButtonBar.scss
@@ -64,9 +64,13 @@ $linkGap : 3px;
text-align: center;
border-radius: 50%;
pointer-events: auto;
- color: $dark-color;
- border: $dark-color 1px solid;
+ background-color: $dark-color;
+ border: none;
transition: 0.2s ease all;
+
+ &:hover {
+ background-color: $main-accent;
+ }
}
.documentButtonBar-linker:hover {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index d45531b76..8748b1880 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -198,7 +198,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
<div className="documentButtonBar-linker"
- style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }}
+ style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white", border: isPinned ? "black 1px solid " : "" }}
onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
<FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
/>
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/Main.scss b/src/client/views/Main.scss
index a2a9ceca5..97ed0a901 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -26,7 +26,7 @@ body {
height: 100%;
border-radius: inherit;
position: inherit;
- // background: inherit;
+ // background: inherit;
}
p {
@@ -37,7 +37,7 @@ p {
::-webkit-scrollbar {
-webkit-appearance: none;
height: 8px;
- width: 8px;
+ width: 8px;
}
::-webkit-scrollbar-thumb {
@@ -47,7 +47,7 @@ p {
// button stuff
button {
- background: $dark-color;
+ background: black;
outline: none;
border: 0px;
color: $light-color;
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index a57d22afd..f3fba82bc 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -21,7 +21,7 @@
// add nodes menu. Note that the + button is actually an input label, not an actual button.
.mainView-docButtons {
position: absolute;
- bottom: 20px;
+ bottom: 35px;
left: calc(100% + 5px);
z-index: 1;
}
@@ -103,7 +103,8 @@
}
.mainView-propertiesDragger {
- background-color: rgb(140, 139, 139);
+ //background-color: rgb(140, 139, 139);
+ background-color: lightgrey;
height: 55px;
width: 17px;
position: absolute;
@@ -155,8 +156,8 @@
.mainView-menuPanel {
width: 60px;
- background-color: black;
- height: 100%;
+ background-color: #121721;
+ height: calc(100% - 32px);
//overflow-y: scroll;
//overflow-x: hidden;
@@ -165,6 +166,7 @@
padding: 7px;
padding-left: 7px;
width: 100%;
+ background: black;
.mainView-menuPanel-button-wrap {
width: 45px;
@@ -213,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 {
@@ -297,6 +298,7 @@
position: absolute;
z-index: 2;
touch-action: none;
+ background-color: lightgrey;
cursor: grab;
.mainView-libraryHandle-icon {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7f50dda72..845e93ecb 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,6 +80,7 @@ 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;
@observable public panelContent: string = "none";
@@ -191,6 +193,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;
@@ -316,6 +332,16 @@ export class MainView extends React.Component {
defaultBackgroundColors = (doc: Opt<Doc>) => {
if (this.panelContent === doc?.title) return "lightgrey";
+
+ if (doc?.type === DocumentType.COL) {
+ if (doc.title === "Basic Item Creators" || doc.title === "sidebar-tools"
+ || doc.title === "sidebar-recentlyClosed" || doc.title === "sidebar-catalog"
+ || doc.title === "Mobile Uploads" || doc.title === "COLLECTION_PROTO"
+ || doc.title === "Advanced Item Prototypes" || doc.title === "all Creators") {
+ return "lightgrey";
+ }
+ return StrCast(Doc.UserDoc().defaultColor);
+ }
if (this.darkScheme) {
switch (doc?.type) {
case DocumentType.FONTICON: return "white";
@@ -340,6 +366,7 @@ export class MainView extends React.Component {
}
}
}
+
@computed get mainDocView() {
return <DocumentView
Document={this.mainContainer!}
@@ -368,11 +395,12 @@ export class MainView extends React.Component {
renderDepth={-1}
/>;
}
+
@computed get dockingContent() {
TraceMobx();
const mainContainer = this.mainContainer;
const width = this.flyoutWidth + this.propertiesWidth();
- return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}>
+ return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)`, height: `calc(100% - 32px)` }}>
{!mainContainer ? (null) : this.mainDocView}
</div>;
}
@@ -417,11 +445,11 @@ export class MainView extends React.Component {
@computed get flyout() {
if (!this.sidebarContent) return null;
return <div className="mainView-libraryFlyout">
- <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}>
- {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
+ <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - 32px)`, width: "100%", overflow: "visible" }}>
+ {/* {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
onPointerDown={this.closeFlyout}>
<FontAwesomeIcon icon="times" color="black" size="lg" />
- </div> : null}
+ </div> : null} */}
<DocumentView
Document={this.sidebarContent}
@@ -449,6 +477,7 @@ export class MainView extends React.Component {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
relative={true}
+ forcedBackgroundColor={() => "lightgrey"}
/>
</div>
{this.docButtons}</div>;
@@ -488,7 +517,7 @@ export class MainView extends React.Component {
}
- @action @undoBatch
+ @action
closeFlyout = () => {
this._lastButton && (this._lastButton.color = "white");
this._lastButton && (this._lastButton._backgroundColor = "");
@@ -499,7 +528,7 @@ export class MainView extends React.Component {
get groupManager() { return GroupManager.Instance; }
_lastButton: Doc | undefined;
- @action @undoBatch
+ @action
selectMenu = (button: Doc, str: string) => {
this._lastButton && (this._lastButton.color = "white");
this._lastButton && (this._lastButton._backgroundColor = "");
@@ -528,7 +557,7 @@ export class MainView extends React.Component {
return true;
}
- @action @undoBatch
+ @action
closeProperties = () => {
CurrentUserUtils.propertiesWidth = 0;
}
@@ -556,7 +585,8 @@ export class MainView extends React.Component {
<div className="mainView-flyoutContainer" style={{ width: this.flyoutWidth }}>
{this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle"
onPointerDown={this.onFlyoutPointerDown}
- style={{ backgroundColor: 'lightgrey' }}>
+ //style={{ backgroundColor: '#8c8b8b' }}
+ >
<span title="library View Dragger" style={{
width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw",
//height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh",
@@ -583,7 +613,7 @@ export class MainView extends React.Component {
<div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown}
style={{ right: rightFlyout, top: "50%" }}>
<div className="mainView-propertiesDragger-icon">
- <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
+ <FontAwesomeIcon icon={this.propertiesIcon} color="black" size="sm" /> </div>
</div>
}
{this.propertiesWidth() < 10 ? (null) :
@@ -593,7 +623,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;
@@ -716,8 +745,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>;
}
@@ -732,7 +785,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/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index 66ea2dbf8..19387f619 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -21,7 +21,9 @@ export default class MainViewModal extends React.Component<MainViewOverlayProps>
const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1;
const overlayOpacity = p.overlayDisplayedOpacity || 0.4;
return !p.isDisplayed ? (null) : (
- <div style={{ pointerEvents: p.isDisplayed && p.interactive ? "all" : "none" }}>
+ <div style={{
+ pointerEvents: p.isDisplayed && p.interactive ? "all" : "none"
+ }}>
<div
className={"dialogue-box"}
style={{
diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
index 1cba252de..6199d34d0 100644
--- a/src/client/views/PropertiesButtons.scss
+++ b/src/client/views/PropertiesButtons.scss
@@ -21,9 +21,8 @@ $linkGap : 3px;
.propertiesButtons-linkButton-empty,
.propertiesButtons-linkButton-nonempty {
height: 30px;
- width: 30px;
- border-radius: 5px;
- opacity: 0.9;
+ width: 32px;
+ border-radius: 6px;
pointer-events: auto;
background-color: #121721;
color: #fcfbf7;
@@ -36,6 +35,7 @@ $linkGap : 3px;
justify-content: center;
align-items: center;
margin-right: 10px;
+ margin-left: 3.5px;
&:hover {
background: $main-accent;
@@ -68,23 +68,35 @@ $linkGap : 3px;
padding-right: 5px;
width: 25px;
border-radius: 5px;
- margin-right: 18px;
+ margin-right: 22px;
margin-bottom: 8px;
}
+.propertiesButtons-title {
+ background: #121721;
+ color: white;
+ font-size: 6px;
+ width: 40px;
+ padding: 3px;
+ height: 13px;
+ border-radius: 7px;
+ text-transform: uppercase;
+ text-align: center;
+ margin-top: -4px;
+}
+
.propertiesButtons-linker {
height: 30px;
- width: 30px;
+ width: 32px;
text-align: center;
- border-radius: 5px;
+ border-radius: 6px;
pointer-events: auto;
- // color: $dark-color;
- // border: $dark-color 1px solid;
- background-color: #252b33;
+ background-color: #121721;
color: #fcfbf7;
transition: 0.2s ease all;
margin-right: 5px;
padding-top: 5px;
+ margin-left: 3.5px;
&:hover {
background: $main-accent;
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 7d8a75dda..29afd447f 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';
import { PresBox } from './nodes/PresBox';
const higflyout = require("@hig/flyout");
@@ -129,18 +128,22 @@ 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></>}>
- <div
- className="propertiesButtons-linker"
- style={{ animation }}
- onClick={async () => {
- await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
- !published && runInAction(() => this.isAnimatingPulse = true);
- PropertiesButtons.hasPushedHack = false;
- targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
- }}>
- <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? "sm" : "xs"} />
- </div></Tooltip>;
+ return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div>} placement="top">
+ <div>
+ <div
+ className="propertiesButtons-linker"
+ style={{ animation }}
+ onClick={async () => {
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
+ !published && runInAction(() => this.isAnimatingPulse = true);
+ PropertiesButtons.hasPushedHack = false;
+ targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
+ }}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? "lg" : "sm"} />
+ </div>
+ <div className="propertiesButtons-title">Google</div>
+ </div>
+ </Tooltip>;
}
@computed
@@ -159,62 +162,76 @@ export class PropertiesButtons extends React.Component<{}, {}> {
})();
return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{title}</div></>}>
- <div className="propertiesButtons-linker"
- style={{ backgroundColor: this.pullColor }}
- onPointerEnter={action(e => {
- if (e.altKey) {
- this.openHover = UtilityButtonState.OpenExternally;
- } else if (e.shiftKey) {
- this.openHover = UtilityButtonState.OpenRight;
- }
- })}
- onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)}
- onClick={async e => {
- const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
- if (e.shiftKey) {
- e.preventDefault();
- let googleDoc = await Cast(dataDoc.googleDoc, Doc);
- if (!googleDoc) {
- const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
- googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
- dataDoc.googleDoc = googleDoc;
+ title={<><div className="dash-tooltip">{title}</div></>} placement="top">
+ <div>
+ <div className="propertiesButtons-linker"
+ style={{ backgroundColor: this.pullColor }}
+ onPointerEnter={action(e => {
+ if (e.altKey) {
+ this.openHover = UtilityButtonState.OpenExternally;
+ } else if (e.shiftKey) {
+ this.openHover = UtilityButtonState.OpenRight;
}
- CollectionDockingView.AddRightSplit(googleDoc);
- } else if (e.altKey) {
- e.preventDefault();
- window.open(googleDocUrl);
- } else {
- this.clearPullColor();
- PropertiesButtons.hasPulledHack = false;
- targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
- dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
- }
- }}>
- <FontAwesomeIcon className="documentdecorations-icon" size="sm"
- style={{ WebkitAnimation: animation, MozAnimation: animation }}
- icon={(() => {
- switch (this.openHover) {
- default:
- case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
- case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
- case UtilityButtonState.OpenExternally: return "share";
+ })}
+ onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)}
+ onClick={async e => {
+ const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
+ if (e.shiftKey) {
+ e.preventDefault();
+ let googleDoc = await Cast(dataDoc.googleDoc, Doc);
+ if (!googleDoc) {
+ const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
+ googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
+ dataDoc.googleDoc = googleDoc;
+ }
+ CollectionDockingView.AddRightSplit(googleDoc);
+ } else if (e.altKey) {
+ e.preventDefault();
+ window.open(googleDocUrl);
+ } else {
+ this.clearPullColor();
+ PropertiesButtons.hasPulledHack = false;
+ targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
+ dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
}
- })()}
- />
- </div></Tooltip>;
+ }}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="lg"
+ color="black"
+ style={{ WebkitAnimation: animation, MozAnimation: animation }}
+ icon={(() => {
+ switch (this.openHover) {
+ default:
+ case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+ case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
+ case UtilityButtonState.OpenExternally: return "share";
+ }
+ })()}
+ />
+ </div>
+ <div className="propertiesButtons-title" style={{ backgroundColor: "white", color: "black" }}>Fetch</div>
+ </div>
+ </Tooltip>;
}
@computed
get pinButton() {
const targetDoc = this.selectedDoc;
const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
- return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
- <div className="propertiesButtons-linker"
- style={{ backgroundColor: isPinned ? "" : "white", color: isPinned ? "white" : "black" }}
- onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
- <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
- />
- </div></Tooltip>;
+ return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div>} placement="top">
+ <div>
+ <div className="propertiesButtons-linker"
+ style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white" }}
+ onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin"
+ />
+ </div>
+
+ <div className="propertiesButtons-title" style={{
+ backgroundColor: Doc.isDocPinned(targetDoc) ? "white" : "black",
+ color: Doc.isDocPinned(targetDoc) ? "black" : "white"
+ }}
+ >{Doc.isDocPinned(targetDoc) ? "Unpin" : "Pin"}</div>
+ </div>
+ </Tooltip>;
}
@computed
@@ -252,12 +269,15 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get metadataButton() {
//const view0 = this.view0;
if (this.selectedDoc) {
- return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
+ return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>} placement="top">
<div className="propertiesButtons-linkFlyout">
<Flyout anchorPoint={anchorPoints.LEFT_TOP}
content={<MetadataEntryMenu docs={[this.selectedDoc]} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
- <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
- {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
+ <div>
+ <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+ {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title">Metadata</div>
</div>
</Flyout>
</div></Tooltip>;
@@ -296,12 +316,15 @@ export class PropertiesButtons extends React.Component<{}, {}> {
Array.from(Object.values(Templates.TemplateList)).map(template =>
templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
return !docView ? (null) :
- <Tooltip title={<><div className="dash-tooltip">Customize layout</div></>}>
+ <Tooltip title={<><div className="dash-tooltip">Customize layout</div></>} placement="top">
<div className="propertiesButtons-linkFlyout">
<Flyout anchorPoint={anchorPoints.LEFT_TOP} //onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
content={<TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
- <div className={"propertiesButtons-linkButton-empty"} >
- {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"} >
+ {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title">Layout</div>
</div>
</Flyout>
</div></Tooltip>;
@@ -324,12 +347,15 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed
get copyButton() {
const targetDoc = this.selectedDoc;
- return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Tap or Drag to create an alias"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- ref={this._dragRef}
- onPointerDown={this.onAliasButtonDown}
- onClick={this.onCopy}>
- {<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="sm" />}
+ return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Tap or Drag to create an alias"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ ref={this._dragRef}
+ onPointerDown={this.onAliasButtonDown}
+ onClick={this.onCopy}>
+ {<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title">Alias</div>
</div>
</Tooltip>;
}
@@ -344,11 +370,19 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
title={<><div className="dash-tooltip">{this.selectedDoc?.lockedPosition ?
- "Unlock Position" : "Lock Position"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={this.onLock} >
- {<FontAwesomeIcon className="documentdecorations-icon"
- icon={BoolCast(this.selectedDoc?.lockedPosition) ? "unlock" : "lock"} size="sm" />}
+ "Unlock Position" : "Lock Position"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ style={{ backgroundColor: BoolCast(this.selectedDoc?.lockedPosition) ? "white" : "" }}
+ onPointerDown={this.onLock} >
+ {<FontAwesomeIcon className="documentdecorations-icon"
+ color={BoolCast(this.selectedDoc?.lockedPosition) ? "black" : "white"}
+ icon={BoolCast(this.selectedDoc?.lockedPosition) ? "unlock" : "lock"} size="lg" />}
+ </div>
+ <div className="propertiesButtons-title" style={{
+ backgroundColor: BoolCast(this.selectedDoc?.lockedPosition) ? "white" : "black",
+ color: BoolCast(this.selectedDoc?.lockedPosition) ? "black" : "white"
+ }}>Position </div>
</div>
</Tooltip>;
}
@@ -357,15 +391,18 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get downloadButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{"Download Document"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={async () => {
- if (this.selectedDocumentView?.props.Document) {
- Doc.Zip(this.selectedDocumentView?.props.Document);
- }
- }}>
- {<FontAwesomeIcon className="propertiesButtons-icon"
- icon="download" size="sm" />}
+ title={<><div className="dash-tooltip">{"Download Document"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ onPointerDown={async () => {
+ if (this.selectedDocumentView?.props.Document) {
+ Doc.Zip(this.selectedDocumentView?.props.Document);
+ }
+ }}>
+ {<FontAwesomeIcon className="propertiesButtons-icon"
+ icon="download" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title"> downld </div>
</div>
</Tooltip>;
}
@@ -374,11 +411,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get deleteButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{"Delete Document"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={this.deleteDocument}>
- {<FontAwesomeIcon className="propertiesButtons-icon"
- icon="trash-alt" size="sm" />}
+ title={<><div className="dash-tooltip">{"Delete Document"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ onPointerDown={this.deleteDocument}>
+ {<FontAwesomeIcon className="propertiesButtons-icon"
+ icon="trash-alt" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title"> delete </div>
</div>
</Tooltip>;
}
@@ -393,15 +433,18 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get sharingButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{"Share Document"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={() => {
- if (this.selectedDocumentView) {
- SharingManager.Instance.open(this.selectedDocumentView);
- }
- }}>
- {<FontAwesomeIcon className="propertiesButtons-icon"
- icon="users" size="sm" />}
+ title={<><div className="dash-tooltip">{"Share Document"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ onPointerDown={() => {
+ if (this.selectedDocumentView) {
+ SharingManager.Instance.open(this.selectedDocumentView);
+ }
+ }}>
+ {<FontAwesomeIcon className="propertiesButtons-icon"
+ icon="users" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title"> share </div>
</div>
</Tooltip>;
}
@@ -409,15 +452,19 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed
get onClickButton() {
if (this.selectedDoc) {
- return <Tooltip title={<><div className="dash-tooltip">Choose onClick behavior</div></>}>
- <div className="propertiesButtons-linkFlyout">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP}
- content={this.onClickFlyout}>
- <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
- {<FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="sm" />}
- </div>
- </Flyout>
- </div></Tooltip>;
+ return <Tooltip title={<><div className="dash-tooltip">Choose onClick behavior</div></>} placement="top">
+ <div>
+ <div className="propertiesButtons-linkFlyout">
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+ content={this.onClickFlyout}>
+ <div className={"propertiesButtons-linkButton-empty"} onPointerDown={e => e.stopPropagation()} >
+ {<FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />}
+ </div>
+ </Flyout>
+ </div>
+ <div className="propertiesButtons-title"> onclick </div>
+ </div>
+ </Tooltip>;
} else {
return null;
}
@@ -504,15 +551,18 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get googlePhotosButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{"Export to Google Photos"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={() => {
- if (this.selectedDocumentView) {
- GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDocumentView.Document }).then(console.log);
- }
- }}>
- {<FontAwesomeIcon className="documentdecorations-icon"
- icon="cloud-upload-alt" size="sm" />}
+ title={<><div className="dash-tooltip">{"Export to Google Photos"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ onPointerDown={() => {
+ if (this.selectedDocumentView) {
+ GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDocumentView.Document }).then(console.log);
+ }
+ }}>
+ {<FontAwesomeIcon className="documentdecorations-icon"
+ icon="cloud-upload-alt" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title"> google </div>
</div>
</Tooltip>;
}
@@ -521,13 +571,19 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get clustersButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{this.selectedDoc?.useClusters ? "Stop Showing Clusters" : "Show Clusters"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- style={{ backgroundColor: this.selectedDoc?.useClusters ? "#a0a0a0" : "" }}
- onPointerDown={this.changeClusters}>
- {<FontAwesomeIcon className="documentdecorations-icon"
- color={this.selectedDoc?.useClusters ? "black" : "white"}
- icon="braille" size="sm" />}
+ title={<><div className="dash-tooltip">{this.selectedDoc?.useClusters ? "Stop Showing Clusters" : "Show Clusters"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ style={{ backgroundColor: this.selectedDoc?.useClusters ? "white" : "" }}
+ onPointerDown={this.changeClusters}>
+ {<FontAwesomeIcon className="documentdecorations-icon"
+ color={this.selectedDoc?.useClusters ? "black" : "white"}
+ icon="braille" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title" style={{
+ backgroundColor: this.selectedDoc?.useClusters ? "white" : "black",
+ color: this.selectedDoc?.useClusters ? "black" : "white"
+ }}> clusters </div>
</div>
</Tooltip>;
}
@@ -546,13 +602,19 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get fitContentButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{this.selectedDoc?._fitToBox ? "Stop Fitting Content" : "Fit Content"}</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- style={{ backgroundColor: this.selectedDoc?._fitToBox ? "#a0a0a0" : "" }}
- onPointerDown={this.changeFitToBox}>
- {<FontAwesomeIcon className="documentdecorations-icon"
- color={this.selectedDoc?._fitToBox ? "black" : "white"}
- icon="expand" size="sm" />}
+ title={<><div className="dash-tooltip">{this.selectedDoc?._fitToBox ? "Stop Fitting Content" : "Fit Content"}</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ style={{ backgroundColor: this.selectedDoc?._fitToBox ? "white" : "" }}
+ onPointerDown={this.changeFitToBox}>
+ {<FontAwesomeIcon className="documentdecorations-icon"
+ color={this.selectedDoc?._fitToBox ? "black" : "white"}
+ icon="expand" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title" style={{
+ backgroundColor: this.selectedDoc?._fitToBox ? "white" : "black",
+ color: this.selectedDoc?._fitToBox ? "black" : "white"
+ }}> {this.selectedDoc?._fitToBox ? "unfit" : "fit"} </div>
</div>
</Tooltip>;
}
@@ -573,11 +635,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get maskButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">Make Mask</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}
- onPointerDown={this.makeMask}>
- {<FontAwesomeIcon className="documentdecorations-icon"
- color="white" icon="paint-brush" size="sm" />}
+ title={<><div className="dash-tooltip">Make Mask</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}
+ onPointerDown={this.makeMask}>
+ {<FontAwesomeIcon className="documentdecorations-icon"
+ color="white" icon="paint-brush" size="lg" />}
+ </div>
+ <div className="propertiesButtons-title"> mask </div>
</div>
</Tooltip>;
}
@@ -585,13 +650,16 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed
get contextButton() {
if (this.selectedDoc) {
- return <Tooltip title={<><div className="dash-tooltip">Show Context</div></>}>
- <div className={"propertiesButtons-linkButton-empty"}>
- <ParentDocSelector Document={this.selectedDoc} addDocTab={(doc, where) => {
- where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
- this.selectedDocumentView?.props.addDocTab(doc, "onRight");
- return true;
- }} />
+ return <Tooltip title={<><div className="dash-tooltip">Show Context</div></>} placement="top">
+ <div>
+ <div className={"propertiesButtons-linkButton-empty"}>
+ <ParentDocSelector Document={this.selectedDoc} addDocTab={(doc, where) => {
+ where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
+ this.selectedDocumentView?.props.addDocTab(doc, "onRight");
+ return true;
+ }} />
+ </div>
+ <div className="propertiesButtons-title"> context </div>
</div>
</Tooltip>;
} else {
@@ -657,9 +725,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button">
{this.onClickButton}
</div>
- {/* <div className="propertiesButtons-button">
- {this.contextButton}
- </div> */}
<div className="propertiesButtons-button">
{this.sharingButton}
</div>
@@ -687,6 +752,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button" style={{ display: !isInk ? "none" : "" }}>
{this.maskButton}
</div>
+ <div className="propertiesButtons-button">
+ {this.contextButton}
+ </div>
</div>
</div>;
}
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/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index b8b72e756..f5c4299a9 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -2,7 +2,7 @@
@import "../_nodeModuleOverrides";
.collectionLinearView-outer {
- overflow: hidden;
+ overflow: visible;
height: 100%;
.collectionLinearView {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a1f5ff657..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 {
@@ -185,7 +183,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
};
- @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+ @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
@computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
@computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
@computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
@@ -236,7 +234,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get subChrome() {
switch (this.props.type) {
- default:
+ default: return this.otherSubChrome;
case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />);
case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
@@ -247,6 +245,21 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />);
}
}
+
+ @computed get otherSubChrome() {
+ const docType = this.props.docView.Document.type;
+ switch (docType) {
+ default: return (null);
+ case DocumentType.IMG: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.PDF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.INK: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.WEB: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.VID: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.RTF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} isDoc={true} />);
+ }
+ }
+
+
private dropDisposer?: DragManager.DragDropDisposer;
protected createDropTarget = (ele: HTMLDivElement) => {
this.dropDisposer?.();
@@ -392,7 +405,7 @@ export class CollectionDockingChrome extends React.Component<CollectionMenuProps
}
@observer
-export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean }> {
+export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean, isDoc?: boolean }> {
public static Instance: CollectionFreeFormViewChrome;
constructor(props: any) {
super(props);
@@ -590,34 +603,36 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</div>;
}
+ @observable viewType = this.selectedDoc?._viewType;
+
render() {
return !this.props.docView.layoutDoc ? (null) :
<div className="collectionFreeFormMenu-cont">
- {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) :
+ {this.props.docView.props.renderDepth !== 0 || this.isText || this.props.isDoc ? (null) :
<Tooltip key="map" title={<div className="dash-tooltip">Toggle Mini Map</div>} placement="bottom">
- <div className="backKeyframe" onClick={this.miniMap}>
+ <div className="backKeyframe" onClick={this.miniMap} style={{ marginRight: "5px" }}>
<FontAwesomeIcon icon={"map"} size={"lg"} />
</div>
</Tooltip>
}
- {!this.isText ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
<div className="backKeyframe" onClick={this.prevKeyframe}>
<FontAwesomeIcon icon={"caret-left"} size={"lg"} />
</div>
</Tooltip> : null}
- {!this.isText ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
<div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
onClick={action(() => this.document.editing = !this.document.editing)} >
{NumCast(this.document.currentFrame)}
</div>
</Tooltip> : null}
- {!this.isText ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom">
<div className="fwdKeyframe" onClick={this.nextKeyframe}>
<FontAwesomeIcon icon={"caret-right"} size={"lg"} />
</div>
</Tooltip> : null}
- {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) :
+ {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) :
<Tooltip key="hypothesis" title={<div className="dash-tooltip">Use Hypothesis</div>} placement="bottom">
<button className={"antimodeMenu-button"} key="hypothesis"
style={{
@@ -655,6 +670,24 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
getKeySuggestions = async (value: string): Promise<string[]> => {
value = value.toLowerCase();
const docs = DocListCast(this.document[this.props.fieldKey]);
+
+ if (Doc.UserDoc().noviceMode) {
+ if (docs instanceof Doc) {
+ const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
+ key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
+ (key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
+ return keys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ } else {
+ const keys = new Set<string>();
+ docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+ const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 ||
+ key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 ||
+ key.indexOf("lastModified") >= 0 || (key[0].toUpperCase() === key[0] &&
+ key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
+ return noviceKeys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ }
+ }
+
if (docs instanceof Doc) {
return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
} else {
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/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index fbc4e1552..f193a9787 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -369,7 +369,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
</div>
{(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== DocumentType.PRES) ?
<div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
- style={{ width: style.columnWidth / style.numGroupColumns }}>
+ style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 70 }}>
<EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
</div> : null}
</div>
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/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 50f0534bd..c9bf82406 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -22,7 +22,7 @@
ul {
list-style: none;
padding-left: 20px;
- margin-bottom: 1px;// otherwise vertical scrollbars may pop up for no apparent reason....
+ margin-bottom: 1px; // otherwise vertical scrollbars may pop up for no apparent reason....
}
@@ -35,7 +35,7 @@
width: 15px;
color: $intermediate-color;
margin-top: 3px;
- transform: scale(1.3, 1.3);
+ transform: scale(1.3, 1.3);
border: #80808030 1px solid;
border-radius: 4px;
}
@@ -67,8 +67,10 @@
margin-left: 3px;
display: none;
}
+
.collectionTreeView-keyHeader:hover {
background: #797777;
+ cursor: pointer;
}
.collectionTreeView-subtitle {
@@ -89,8 +91,10 @@
height: 17px;
width: 15px;
}
+
.treeViewItem-openRight:hover {
background: #797777;
+ cursor: pointer;
}
.treeViewItem-border {
@@ -106,10 +110,12 @@
.editableView-container-editing-oneLine {
min-width: 15px;
}
+
.documentView-node-topmost {
width: unset;
}
- > svg {
+
+ >svg {
display: none;
}
@@ -119,7 +125,8 @@
.collectionTreeView-keyHeader {
display: inherit;
}
- > svg {
+
+ >svg {
display: inherit;
}
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/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 65cd28742..f2ad0ba58 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1258,7 +1258,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.ContainingCollectionView &&
optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
- appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
+ optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
if (!Doc.UserDoc().noviceMode) {
optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
optionItems.push({ description: `${this.Document._freeformLOD ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" });
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index 89124129b..5b41db90e 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -41,7 +41,7 @@
font-size: 12.5px;
&:hover {
- cursor: pointer;
+ cursor: text;
}
}
@@ -617,6 +617,7 @@
display: flex;
margin-bottom: 3px;
+ margin-left: 4px;
.arrows-head {
@@ -650,7 +651,7 @@
.dashed {
display: flex;
- margin-left: 74px;
+ margin-left: 64px;
margin-bottom: 6px;
.dashed-title {
@@ -662,4 +663,15 @@
margin-top: 2px;
}
}
+}
+
+.editable-title {
+ border: none;
+ padding: 6px;
+ padding-bottom: 2px;
+
+
+ &:hover {
+ border: 0.75px solid rgb(122, 28, 28);
+ }
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index dcbf8e989..89f48fc65 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -29,6 +29,9 @@ import "./FormatShapePane.scss";
import { discovery_v1 } from "googleapis";
import { PresBox } from "../../nodes/PresBox";
import { DocumentManager } from "../../../util/DocumentManager";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
interface PropertiesViewProps {
@@ -74,6 +77,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@observable openPresProgressivize: boolean = true;
@observable openSlideOptions: boolean = true;
+ @observable inActions: boolean = false;
@observable _controlBtn: boolean = false;
@observable _lock: boolean = false;
@@ -174,7 +178,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
const rows: JSX.Element[] = [];
for (const key of Object.keys(ids).slice().sort()) {
- if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL")
+ if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL" && key !== "UseCors")
|| key[0] === "#" || key === "author" ||
key === "creationDate" || key.indexOf("lastModified") !== -1) {
@@ -254,7 +258,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
rootSelected={returnFalse}
treeViewDoc={undefined}
backgroundColor={() => "lightgrey"}
- fitToBox={false}
+ fitToBox={true}
FreezeDimensions={true}
NativeWidth={layoutDoc.type ===
StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
@@ -277,6 +281,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
bringToFront={returnFalse}
ContentScaling={returnOne}
dontRegisterView={true}
+ dropAction={undefined}
/>
</div>;
} else {
@@ -367,20 +372,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
/>;
}
- @undoBatch
@action
toggleCheckbox = () => {
this.layoutFields = !this.layoutFields;
}
@computed get editableTitle() {
- return <EditableView
+ return <div className="editable-title"><EditableView
key="editableView"
contents={StrCast(this.selectedDoc?.title)}
height={25}
fontSize={14}
GetValue={() => StrCast(this.selectedDoc?.title)}
- SetValue={this.setTitle} />;
+ SetValue={this.setTitle} /> </div>;
}
@undoBatch
@@ -417,15 +421,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
var index = 0;
if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
doc.rotation = Number(doc.rotation) + Number(angle);
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
-
+ const inks = Cast(doc.data, InkField)?.inkData;
+ if (inks) {
const newPoints: { X: number, Y: number }[] = [];
- for (var i = 0; i < ink.length; i++) {
- const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
- const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+ inks.forEach(ink => {
+ const newX = Math.cos(angle) * (ink.X - _centerPoints[index].X) - Math.sin(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].X;
+ const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
newPoints.push({ X: newX, Y: newY });
- }
+ });
doc.data = new InkField(newPoints);
const xs = newPoints.map(p => p.X);
const ys = newPoints.map(p => p.Y);
@@ -552,7 +555,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
getField(key: string) {
//if (this.selectedDoc) {
- return Field.toString(this?.[key] as Field);
+ return Field.toString(this.selectedDoc?.[key] as Field);
// } else {
// return undefined as Opt<string>;
// }
@@ -594,14 +597,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); }
set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); }
- colorButton(value: string, setter: () => {}) {
- return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
- <div className="color-button-preview" style={{
- backgroundColor: value ?? "121212", width: 15, height: 15,
- display: value === "" || value === "transparent" ? "none" : ""
- }} />
- {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
- </div>;
+ colorButton(value: string, type: string, setter: () => {}) {
+ return <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+ content={type === "fill" ? this.fillPicker : this.linePicker}>
+ <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
+ <div className="color-button-preview" style={{
+ backgroundColor: value ?? "121212", width: 15, height: 15,
+ display: value === "" || value === "transparent" ? "none" : ""
+ }} />
+ {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
+ </div>
+ </Flyout>;
+
}
@undoBatch
@@ -627,8 +634,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
color={type === "stk" ? this.colorStk : this.colorFil} />;
}
- @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
- @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
+ @computed get fillButton() { return this.colorButton(this.colorFil, "fill", () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
+ @computed get lineButton() { return this.colorButton(this.colorStk, "line", () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
@computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
@computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
@@ -645,8 +652,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<div className="stroke-button">{this.lineButton}</div>
</div>
</div>
- {this._fillBtn ? this.fillPicker : ""}
- {this._lineBtn ? this.linePicker : ""}
+ {/* {this._fillBtn ? this.fillPicker : ""}
+ {this._lineBtn ? this.linePicker : ""} */}
</div>;
}
@@ -753,201 +760,203 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return <div className="propertiesView" style={{ width: this.props.width }}>
<div className="propertiesView-title" style={{ width: this.props.width }}>
No Document Selected
- <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
- <FontAwesomeIcon icon="times" color="black" size="xs" />
- </div>
</div>
</div>;
- }
- const novice = Doc.UserDoc().noviceMode;
-
- if (this.selectedDoc && !this.isPres) {
- return <div className="propertiesView" style={{ width: this.props.width }} >
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- Properties
- <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+ } else {
+ const novice = Doc.UserDoc().noviceMode;
+
+ if (this.selectedDoc && !this.isPres) {
+ return <div className="propertiesView" style={{
+ width: this.props.width,
+ // overflowY: this.inActions ? "visible" : "scroll"
+ }} >
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
+ Properties
+ {/* <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
<FontAwesomeIcon icon="times" color="black" size="sm" />
+ </div> */}
</div>
- </div>
- <div className="propertiesView-name">
- {this.editableTitle}
- </div>
- <div className="propertiesView-settings">
- <div className="propertiesView-settings-title"
- onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
- style={{ backgroundColor: this.openActions ? "black" : "" }}>
- Actions
- <div className="propertiesView-settings-title-icon">
- <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-name">
+ {this.editableTitle}
+ </div>
+ <div className="propertiesView-settings" onPointerEnter={() => runInAction(() => { this.inActions = true; })}
+ onPointerLeave={action(() => this.inActions = false)}>
+ <div className="propertiesView-settings-title"
+ onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
+ style={{ backgroundColor: this.openActions ? "black" : "" }}>
+ Actions
+ <div className="propertiesView-settings-title-icon">
+ <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {!this.openActions ? (null) :
+ <div className="propertiesView-settings-content">
+ <PropertiesButtons />
+ </div>}
</div>
- {!this.openActions ? (null) :
- <div className="propertiesView-settings-content">
- <PropertiesButtons />
- </div>}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
- style={{ backgroundColor: this.openSharing ? "black" : "" }}>
- Sharing {"&"} Permissions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
+ style={{ backgroundColor: this.openSharing ? "black" : "" }}>
+ Sharing {"&"} Permissions
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {!this.openSharing ? (null) :
+ <div className="propertiesView-sharing-content">
+ {this.sharingTable}
+ </div>}
</div>
- {!this.openSharing ? (null) :
- <div className="propertiesView-sharing-content">
- {this.sharingTable}
+
+ {!this.isInk ? (null) :
+ <div className="propertiesView-appearance">
+ <div className="propertiesView-appearance-title"
+ onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
+ style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
+ Appearance
+ <div className="propertiesView-appearance-title-icon">
+ <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {!this.openAppearance ? (null) :
+ <div className="propertiesView-appearance-content">
+ {this.appearanceEditor}
+ </div>}
</div>}
- </div>
- {!this.isInk ? (null) :
- <div className="propertiesView-appearance">
- <div className="propertiesView-appearance-title"
- onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
- style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
- Appearance
- <div className="propertiesView-appearance-title-icon">
- <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
+ {this.isInk ? <div className="propertiesView-transform">
+ <div className="propertiesView-transform-title"
+ onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
+ style={{ backgroundColor: this.openTransform ? "black" : "" }}>
+ Transform
+ <div className="propertiesView-transform-title-icon">
+ <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
</div>
</div>
- {!this.openAppearance ? (null) :
- <div className="propertiesView-appearance-content">
- {this.appearanceEditor}
- </div>}
- </div>}
-
- {this.isInk ? <div className="propertiesView-transform">
- <div className="propertiesView-transform-title"
- onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
- style={{ backgroundColor: this.openTransform ? "black" : "" }}>
- Transform
- <div className="propertiesView-transform-title-icon">
- <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openTransform ? <div className="propertiesView-transform-content">
- {this.transformEditor}
+ {this.openTransform ? <div className="propertiesView-transform-content">
+ {this.transformEditor}
+ </div> : null}
</div> : null}
- </div> : null}
-
- <div className="propertiesView-fields">
- <div className="propertiesView-fields-title"
- onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
- style={{ backgroundColor: this.openFields ? "black" : "" }}>
- <div className="propertiesView-fields-title-name">
- Fields {"&"} Tags
- <div className="propertiesView-fields-title-icon">
- <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+
+ <div className="propertiesView-fields">
+ <div className="propertiesView-fields-title"
+ onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
+ style={{ backgroundColor: this.openFields ? "black" : "" }}>
+ <div className="propertiesView-fields-title-name">
+ Fields {"&"} Tags
+ <div className="propertiesView-fields-title-icon">
+ <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
</div>
+ {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
+ {this.fieldsCheckbox}
+ <div className="propertiesView-fields-checkbox-text">Layout</div>
+ </div> : null}
+ {!this.openFields ? (null) :
+ <div className="propertiesView-fields-content">
+ {novice ? this.noviceFields : this.expandedField}
+ </div>}
</div>
- {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
- {this.fieldsCheckbox}
- <div className="propertiesView-fields-checkbox-text">Layout</div>
- </div> : null}
- {!this.openFields ? (null) :
- <div className="propertiesView-fields-content">
- {novice ? this.noviceFields : this.expandedField}
- </div>}
- </div>
- <div className="propertiesView-layout">
- <div className="propertiesView-layout-title"
- onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
- style={{ backgroundColor: this.openLayout ? "black" : "" }}>
- Layout
- <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
- <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-layout">
+ <div className="propertiesView-layout-title"
+ onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
+ style={{ backgroundColor: this.openLayout ? "black" : "" }}>
+ Layout
+ <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
+ <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null}
</div>
- {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null}
- </div>
- </div>;
- }
- if (this.isPres) {
- return <div className="propertiesView" style={{ width: this.props.width }} >
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- Presentation
- <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
- <FontAwesomeIcon icon="times" color="black" size="sm" />
+ </div>;
+ }
+ if (this.isPres) {
+ return <div className="propertiesView" style={{ width: this.props.width }} >
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
+ Presentation
+ <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+ <FontAwesomeIcon icon="times" color="black" size="sm" />
+ </div>
</div>
- </div>
- <div className="propertiesView-name">
- {this.editableTitle}
- <div className="propertiesView-presSelected">
- {PresBox.Instance._selectedArray.length} selected
- <div className="propertiesView-selectedList">
- {PresBox.Instance.listOfSelected}
+ <div className="propertiesView-name">
+ {this.editableTitle}
+ <div className="propertiesView-presSelected">
+ {PresBox.Instance._selectedArray.length} selected
+ <div className="propertiesView-selectedList">
+ {PresBox.Instance.listOfSelected}
+ </div>
</div>
</div>
- </div>
- <div className="propertiesView-settings">
- <div className="propertiesView-settings-title"
- onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
- style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
- <div className="propertiesView-settings-title-icon">
- <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-settings">
+ <div className="propertiesView-settings-title"
+ onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
+ style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
+ <div className="propertiesView-settings-title-icon">
+ <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openAddSlide ? <div className="propertiesView-settings-content">
+ {PresBox.Instance.newDocumentDropdown}
+ </div> : null}
</div>
- {this.openAddSlide ? <div className="propertiesView-settings-content">
- {PresBox.Instance.newDocumentDropdown}
- </div> : null}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
- style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
+ style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openPresTransitions ? <div className="propertiesView-sharing-content">
+ {PresBox.Instance.transitionDropdown}
+ </div> : null}
</div>
- {this.openPresTransitions ? <div className="propertiesView-sharing-content">
- {PresBox.Instance.transitionDropdown}
- </div> : null}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
- style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
+ style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openPresProgressivize ? <div className="propertiesView-sharing-content">
+ {PresBox.Instance.progressivizeDropdown}
+ </div> : null}
</div>
- {this.openPresProgressivize ? <div className="propertiesView-sharing-content">
- {PresBox.Instance.progressivizeDropdown}
- </div> : null}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
- style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
+ style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openSlideOptions ? <div className="propertiesView-sharing-content">
+ {PresBox.Instance.optionsDropdown}
+ </div> : null}
</div>
- {this.openSlideOptions ? <div className="propertiesView-sharing-content">
- {PresBox.Instance.optionsDropdown}
- </div> : null}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
- style={{ backgroundColor: this.openSharing ? "black" : "" }}>
- Sharing {"&"} Permissions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
+ style={{ backgroundColor: this.openSharing ? "black" : "" }}>
+ Sharing {"&"} Permissions
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openSharing ? <div className="propertiesView-sharing-content">
+ {this.sharingTable}
+ </div> : null}
</div>
- {this.openSharing ? <div className="propertiesView-sharing-content">
- {this.sharingTable}
- </div> : null}
- </div>
- </div>;
+ </div>;
+ }
}
}
} \ No newline at end of file
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/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss
index d26b7920a..7e6999cdc 100644
--- a/src/client/views/linking/LinkEditor.scss
+++ b/src/client/views/linking/LinkEditor.scss
@@ -89,7 +89,7 @@
/* float: right; */
border-radius: 7px;
font-size: 9px;
- background-color: black;
+ background: black;
/* padding: 3px; */
padding-top: 4px;
padding-left: 7px;
@@ -100,6 +100,7 @@
&:hover {
cursor: pointer;
+ background: grey;
}
}
}
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 660afd4b9..75fc8bf85 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -287,7 +287,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
@observable openDropdown: boolean = false;
@observable showInfo: boolean = false;
@computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; }
- @observable private buttonColor: string = "black";
+ @observable private buttonColor: string = "";
//@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
@@ -303,7 +303,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
if (LinkManager.currentLink) {
LinkManager.currentLink.description = value;
this.buttonColor = "rgb(62, 133, 55)";
- setTimeout(action(() => this.buttonColor = "black"), 750);
+ setTimeout(action(() => this.buttonColor = ""), 750);
return true;
}
}
@@ -345,7 +345,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
></input>
</div>
<div className="linkEditor-description-add-button"
- style={{ backgroundColor: this.buttonColor }}
+ style={{ background: this.buttonColor }}
onPointerDown={this.onDown}>Set</div>
</div></div>;
}
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 e3f258b8d..2408b3906 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -25,7 +25,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";
@@ -192,7 +192,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
components={{
FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, MenuIconBox, 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.scss b/src/client/views/nodes/DocumentLinksButton.scss
index 97e714cd5..9328fb96b 100644
--- a/src/client/views/nodes/DocumentLinksButton.scss
+++ b/src/client/views/nodes/DocumentLinksButton.scss
@@ -28,7 +28,13 @@
}
.documentLinksButton {
- background-color: $link-color;
+ background-color: black;
+
+ &:hover {
+ background: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
+ }
}
.documentLinksButton-endLink {
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 025669b41..cb79e1522 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -181,7 +181,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
const linkButton = <div ref={this._linkButton} style={{ minWidth: 20, minHeight: 20, position: "absolute", left: this.props.Offset?.[0] }}>
<div className={"documentLinksButton"} style={{
- backgroundColor: this.props.InMenu ? "black" : "",
+ backgroundColor: this.props.InMenu ? "" : "#add8e6",
color: this.props.InMenu ? "white" : "black",
width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px", fontWeight: "bold"
}}
@@ -202,8 +202,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
link : links.length}
</div>
- {DocumentLinksButton.StartLink && this.props.InMenu && !this.props.StartLink &&
- DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"}
+ {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View ?
+ <div className={"documentLinksButton-endLink"}
style={{
width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px",
backgroundColor: DocumentLinksButton.StartLink ? "" : "grey",
@@ -218,7 +218,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
</div>;
return (!links.length) && !this.props.AlwaysOn ? (null) :
- this.props.InMenu ?
+ this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink) ?
<Tooltip title={<><div className="dash-tooltip">{title}</div></>}>
{linkButton}
</Tooltip> : !!!DocumentLinksButton.EditLink && !this.props.InMenu ?
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e6e709621..b9e685b44 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -749,7 +749,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "users" });
//moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
- moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
+ //moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
if (!Doc.UserDoc().noviceMode) {
moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 1b4151bd8..e631ad5fe 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -49,11 +49,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/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 5bdafd857..9709e1dbd 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -15,12 +15,17 @@
.menuButton-round {
border-radius: 100%;
+ background-color: black;
.fontIconBox-label {
margin-left: -10px; // button padding is 10px;
bottom: 0;
position: absolute;
}
+
+ &:hover {
+ background-color: #aaaaa3;
+ }
}
.menuButton-square {
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index eff5a4160..c0eb78d98 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -63,16 +63,14 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
const color = StrCast(this.layoutDoc.color, this._foregroundColor);
const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc)));
const shape = StrCast(this.layoutDoc.iconShape, "round");
- const button = <>
- <button className={`menuButton-${shape}`} ref={this._ref} onContextMenu={this.specificContextMenu}
- style={{ boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined, backgroundColor }}>
- <div className="menuButton-wrap">
- {<FontAwesomeIcon className={`menuButton-icon-${shape}`} icon={StrCast(this.dataDoc.icon, "user") as any} color={color}
- size={this.layoutDoc.iconShape === "square" ? "sm" : "lg"} />}
- {!label ? (null) : <div className="fontIconBox-label" style={{ color, backgroundColor }}> {label} </div>}
- </div>
- </button>
- </>;
+ const button = <button className={`menuButton-${shape}`} ref={this._ref} onContextMenu={this.specificContextMenu}
+ style={{ boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined, backgroundColor: this.layoutDoc.iconShape === "square" ? backgroundColor : "" }}>
+ <div className="menuButton-wrap">
+ {<FontAwesomeIcon className={`menuButton-icon-${shape}`} icon={StrCast(this.dataDoc.icon, "user") as any} color={color}
+ size={this.layoutDoc.iconShape === "square" ? "sm" : "lg"} />}
+ {!label ? (null) : <div className="fontIconBox-label" style={{ color, backgroundColor }}> {label} </div>}
+ </div>
+ </button>;
return !this.layoutDoc.toolTip ? button :
<Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>
{button}
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 ab1de5529..af4bd77c7 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");
@@ -799,8 +823,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 5af07c15d..459632ec8 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -274,7 +274,7 @@ export default class RichTextMenu extends AntimodeMenu {
}
!activeFamilies.length && (activeFamilies.push(StrCast(this.TextView.layoutDoc._fontFamily, StrCast(Doc.UserDoc().fontFamily))));
!activeSizes.length && (activeSizes.push(StrCast(this.TextView.layoutDoc._fontSize, StrCast(Doc.UserDoc().fontSize))));
- !activeColors.length && (activeSizes.push(StrCast(this.TextView.layoutDoc.color, StrCast(Doc.UserDoc().fontColor))));
+ !activeColors.length && (activeColors.push(StrCast(this.TextView.layoutDoc.color, StrCast(Doc.UserDoc().fontColor))));
}
!activeFamilies.length && (activeFamilies.push(StrCast(Doc.UserDoc().fontFamily)));
!activeSizes.length && (activeSizes.push(StrCast(Doc.UserDoc().fontSize)));
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 192a6300a..cfa9a1844 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
@@ -408,6 +411,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
phraseSearch: true,
query: searchString
});
+ this.Document.searchIndex = this.Index;
}
else if (this._mainCont.current) {
const executeFind = () => {
@@ -421,7 +425,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 9cd7eaa69..6163fedbb 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;