aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-04-03 22:05:11 -0400
committerGitHub <noreply@github.com>2020-04-03 22:05:11 -0400
commit5a49ff42f845239de72c4c31c4df0688313b30e7 (patch)
tree082ea03501aecc4f9ea3f68d3954ef9b2c6195a8
parenta0e4ae65f81c62ac08761359e60b996f0e839559 (diff)
parentfac740378a9eeaeb0af4567f6402120aba8bd62e (diff)
Merge pull request #350 from browngraphicslab/search_doc
Search doc
-rw-r--r--package-lock.json133
-rw-r--r--package.json1
-rw-r--r--solr-8.3.1/server/tmp/start_1935456665153398890.properties11
-rw-r--r--solr-8.3.1/server/tmp/start_5098042466590842962.properties11
-rw-r--r--solr-8.3.1/server/tmp/start_5201032335657884982.properties11
-rw-r--r--solr-8.3.1/server/tmp/start_5906520416860122978.properties11
-rw-r--r--solr-8.3.1/server/tmp/start_5982280610074344638.properties11
-rw-r--r--solr-8.3.1/server/tmp/start_8210707001248201939.properties11
-rw-r--r--src/client/documents/DocumentTypes.ts2
-rw-r--r--src/client/documents/Documents.ts10
-rw-r--r--src/client/util/RichTextSchema.tsx1
-rw-r--r--src/client/util/SelectionManager.ts8
-rw-r--r--src/client/views/DocComponent.tsx6
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/GestureOverlay.tsx1
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/OverlayView.tsx1
-rw-r--r--src/client/views/Palette.tsx26
-rw-r--r--src/client/views/RecommendationsBox.tsx1
-rw-r--r--src/client/views/SearchDocBox.tsx432
-rw-r--r--src/client/views/TemplateMenu.tsx12
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx1
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx3
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx1
-rw-r--r--src/client/views/collections/CollectionSubView.tsx5
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx1
-rw-r--r--src/client/views/nodes/AudioBox.tsx12
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx7
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx1
-rw-r--r--src/client/views/nodes/DocumentBox.tsx1
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx5
-rw-r--r--src/client/views/nodes/DocumentView.tsx28
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.tsx1
-rw-r--r--src/client/views/nodes/QueryBox.scss6
-rw-r--r--src/client/views/nodes/QueryBox.tsx33
-rw-r--r--src/client/views/pdf/PDFViewer.tsx3
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx3
-rw-r--r--src/client/views/search/CheckBox.tsx146
-rw-r--r--src/client/views/search/FilterBox.scss9
-rw-r--r--src/client/views/search/FilterBox.tsx2
-rw-r--r--src/client/views/search/IconBar.scss7
-rw-r--r--src/client/views/search/IconBar.tsx20
-rw-r--r--src/client/views/search/IconButton.scss1
-rw-r--r--src/client/views/search/IconButton.tsx16
-rw-r--r--src/client/views/search/SearchBox.scss263
-rw-r--r--src/client/views/search/SearchBox.tsx417
-rw-r--r--src/client/views/search/SearchItem.tsx3
-rw-r--r--src/mobile/MobileInterface.tsx2
-rw-r--r--src/new_fields/documentSchemas.ts2
-rw-r--r--src/server/DashSession/DashSessionAgent.ts2
-rw-r--r--src/server/authentication/models/current_user_utils.ts31
-rw-r--r--src/server/index.ts2
57 files changed, 1321 insertions, 428 deletions
diff --git a/package-lock.json b/package-lock.json
index 51ce57395..2cd3c0b82 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -287,17 +287,6 @@
"resolved": "https://registry.npmjs.org/@tensorflow-models/universal-sentence-encoder/-/universal-sentence-encoder-1.2.2.tgz",
"integrity": "sha512-fGCl/gwB7jmKCRI2FhgIBeIa/LCSUcjlEcckH2Bc2dIjhJ+2nspp+22lubxcseN6jjrmP42kkXt/reAPe+KJkQ=="
},
- "@tensorflow/tfjs": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-1.5.2.tgz",
- "integrity": "sha512-BCvcbnkE/zMdORIGE7TFAiJU3zLLVUaRv/HyWucVVyHU40oU4L5mGyRXK6RwqU38KmeK3HSI5rUHop4cLNUaRQ==",
- "requires": {
- "@tensorflow/tfjs-converter": "1.5.2",
- "@tensorflow/tfjs-core": "1.5.2",
- "@tensorflow/tfjs-data": "1.5.2",
- "@tensorflow/tfjs-layers": "1.5.2"
- }
- },
"@tensorflow/tfjs-converter": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-1.5.2.tgz",
@@ -323,69 +312,6 @@
}
}
},
- "@tensorflow/tfjs-data": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-1.5.2.tgz",
- "integrity": "sha512-ruCsTSyH67CADWthgLQlWKh8u8YGEXD+4vsW8uOGdFNcDFLcL0ffy4jsSzIV/X6NdPIWYsvSHmiz57LtgfCFew==",
- "requires": {
- "@types/node-fetch": "^2.1.2",
- "node-fetch": "~2.1.2"
- },
- "dependencies": {
- "node-fetch": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
- "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
- }
- }
- },
- "@tensorflow/tfjs-layers": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-1.5.2.tgz",
- "integrity": "sha512-fn2hi5D1sOKGEgiBCuoU/hTHO87znODweGivIn6x2HMtF1EC39QWroYQBWzJyrWWMOUZZ4nOFR6coA0Fkhc+nA=="
- },
- "@tensorflow/tfjs-node": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-node/-/tfjs-node-1.5.2.tgz",
- "integrity": "sha512-qihOkKbCLTDcqe3TTDbA9v00PacMzPwhspV8MEHWpohVb7itqQ8cMSE8w38b2oA+FE38c1RI7KOd2qAl5bCNHA==",
- "requires": {
- "@tensorflow/tfjs": "1.5.2",
- "adm-zip": "^0.4.11",
- "google-protobuf": "^3.9.2",
- "https-proxy-agent": "^2.2.1",
- "node-pre-gyp": "0.14.0",
- "progress": "^2.0.0",
- "rimraf": "^2.6.2",
- "tar": "^4.4.6"
- },
- "dependencies": {
- "node-pre-gyp": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
- "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
- "requires": {
- "detect-libc": "^1.0.2",
- "mkdirp": "^0.5.1",
- "needle": "^2.2.1",
- "nopt": "^4.0.1",
- "npm-packlist": "^1.1.6",
- "npmlog": "^4.0.2",
- "rc": "^1.2.7",
- "rimraf": "^2.6.1",
- "semver": "^5.3.0",
- "tar": "^4.4.2"
- }
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
"@trendmicro/react-buttons": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@trendmicro/react-buttons/-/react-buttons-1.3.1.tgz",
@@ -791,14 +717,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz",
"integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg=="
},
- "@types/node-fetch": {
- "version": "2.5.4",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.4.tgz",
- "integrity": "sha512-Oz6id++2qAOFuOlE1j0ouk1dzl3mmI1+qINPNBhi9nt/gVOz0G+13Ao6qjhdF0Ys+eOkhu6JnFmt38bR3H0POQ==",
- "requires": {
- "@types/node": "*"
- }
- },
"@types/nodemailer": {
"version": "4.6.8",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-4.6.8.tgz",
@@ -5697,8 +5615,7 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"aproba": {
"version": "1.2.0",
@@ -5716,13 +5633,11 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5735,18 +5650,15 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5849,8 +5761,7 @@
},
"inherits": {
"version": "2.0.4",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"ini": {
"version": "1.3.5",
@@ -5860,7 +5771,6 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5873,20 +5783,17 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
- "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -5903,7 +5810,6 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
- "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5984,8 +5890,7 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"object-assign": {
"version": "4.1.1",
@@ -5995,7 +5900,6 @@
"once": {
"version": "1.4.0",
"bundled": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
@@ -6071,8 +5975,7 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6102,7 +6005,6 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6120,7 +6022,6 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
- "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6159,13 +6060,11 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true,
- "optional": true
+ "bundled": true
}
}
},
@@ -6460,11 +6359,6 @@
}
}
},
- "google-protobuf": {
- "version": "3.11.3",
- "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.11.3.tgz",
- "integrity": "sha512-Sp8E+0AJLxmiPwAk9VH3MkYAmYYheNUhywIyXOS7wvRkqbIYcHtGzJzIYicNqYsqgKmY35F9hxRkI+ZTqTB4Tg=="
- },
"googleapis": {
"version": "40.0.1",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-40.0.1.tgz",
@@ -13546,11 +13440,6 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
- },
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
diff --git a/package.json b/package.json
index cb5a70f3c..440646c48 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,6 @@
"@tensorflow-models/universal-sentence-encoder": "^1.2.2",
"@tensorflow/tfjs-converter": "^1.3.2",
"@tensorflow/tfjs-core": "^1.5.2",
- "@tensorflow/tfjs-node": "^1.5.2",
"@trendmicro/react-dropdown": "^1.3.0",
"@types/adm-zip": "^0.4.32",
"@types/animejs": "^2.0.2",
diff --git a/solr-8.3.1/server/tmp/start_1935456665153398890.properties b/solr-8.3.1/server/tmp/start_1935456665153398890.properties
deleted file mode 100644
index a694ae90a..000000000
--- a/solr-8.3.1/server/tmp/start_1935456665153398890.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Thu Jan 09 14:51:58 UTC 2020
-java.version.platform=8
-java.version=1.8.0_211
-java.version.micro=0
-jetty.home=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
-jetty.base=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
diff --git a/solr-8.3.1/server/tmp/start_5098042466590842962.properties b/solr-8.3.1/server/tmp/start_5098042466590842962.properties
deleted file mode 100644
index 194d8ff5c..000000000
--- a/solr-8.3.1/server/tmp/start_5098042466590842962.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Thu Jan 09 23:36:29 UTC 2020
-java.version.platform=8
-java.version=1.8.0_131
-java.version.micro=0
-jetty.home=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
-jetty.base=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
diff --git a/solr-8.3.1/server/tmp/start_5201032335657884982.properties b/solr-8.3.1/server/tmp/start_5201032335657884982.properties
deleted file mode 100644
index e3a72dc76..000000000
--- a/solr-8.3.1/server/tmp/start_5201032335657884982.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Wed Jan 08 17:27:07 UTC 2020
-java.version.platform=8
-java.version=1.8.0_131
-java.version.micro=0
-jetty.home=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
-jetty.base=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
diff --git a/solr-8.3.1/server/tmp/start_5906520416860122978.properties b/solr-8.3.1/server/tmp/start_5906520416860122978.properties
deleted file mode 100644
index 4177968f4..000000000
--- a/solr-8.3.1/server/tmp/start_5906520416860122978.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Wed Jan 08 14:30:05 UTC 2020
-java.version.platform=8
-java.version=1.8.0_211
-java.version.micro=0
-jetty.home=c\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///c\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
-jetty.base=c\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///c\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
diff --git a/solr-8.3.1/server/tmp/start_5982280610074344638.properties b/solr-8.3.1/server/tmp/start_5982280610074344638.properties
deleted file mode 100644
index 840417082..000000000
--- a/solr-8.3.1/server/tmp/start_5982280610074344638.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Fri Dec 13 19:19:27 UTC 2019
-java.version.platform=8
-java.version=1.8.0_131
-java.version.micro=0
-jetty.home=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
-jetty.base=C\:\\Users\\avd\\Desktop\\Sam\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///C\:/Users/avd/Desktop/Sam/Dash-Web/solr-8.3.1/server
diff --git a/solr-8.3.1/server/tmp/start_8210707001248201939.properties b/solr-8.3.1/server/tmp/start_8210707001248201939.properties
deleted file mode 100644
index aebc17bdc..000000000
--- a/solr-8.3.1/server/tmp/start_8210707001248201939.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#start.jar properties
-#Thu Jan 16 20:33:22 UTC 2020
-java.version.platform=8
-java.version=1.8.0_211
-java.version.micro=0
-jetty.home=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.minor=8
-jetty.home.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
-jetty.base=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server
-java.version.major=1
-jetty.base.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 5ec1cfdb4..b98e4d581 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -22,7 +22,7 @@ export enum DocumentType {
RECOMMENDATION = "recommendation",
LINKFOLLOW = "linkfollow",
PRESELEMENT = "preselement",
- QUERY = "search",
+ QUERY = "query",
COLOR = "color",
DOCULINK = "doculink",
PDFANNO = "pdfanno",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 96425ba30..1a2969cf5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -41,6 +41,8 @@ import { ComputedField, ScriptField } from "../../new_fields/ScriptField";
import { ProxyField } from "../../new_fields/Proxy";
import { DocumentType } from "./DocumentTypes";
import { RecommendationsBox } from "../views/RecommendationsBox";
+import { SearchBox } from "../views/search/SearchBox";
+
//import { PresBox } from "../views/nodes/PresBox";
//import { PresField } from "../../new_fields/PresField";
import { PresElementBox } from "../views/presentationview/PresElementBox";
@@ -101,6 +103,7 @@ export interface DocumentOptions {
isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents
forceActive?: boolean;
layout?: string | Doc;
+ hideFilterView?: boolean; // whether to hide the filter popout on collections
hideHeadings?: boolean; // whether stacking view column headings should be hidden
isTemplateForField?: string; // the field key for which the containing document is a rendering template
isTemplateDoc?: boolean;
@@ -115,7 +118,7 @@ export interface DocumentOptions {
lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
opacity?: number;
defaultBackgroundColor?: string;
- dontSelect?: boolean; // whether document decorations should be displayed when the document is selected
+ dontDecorateSelection?: boolean; // whether document decorations should be displayed when the document is selected
isBackground?: boolean;
isButton?: boolean;
columnWidth?: number;
@@ -161,6 +164,9 @@ 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,
linearViewIsExpanded?: boolean; // is linear view expanded
}
@@ -430,7 +436,7 @@ export namespace Docs {
Scripting.addGlobal(Buxton);
const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn",
- "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
+ "_chromeStatus", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
"_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop",
"_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"];
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 094cd58f3..4a930177d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -818,6 +818,7 @@ export class DashDocView {
LibraryPath={this._textBox.props.LibraryPath}
fitToBox={BoolCast(dashDoc._fitToBox)}
addDocument={returnFalse}
+ rootSelected={this._textBox.props.isSelected}
removeDocument={removeDoc}
ScreenToLocalTransform={this.getDocTransform}
addDocTab={this._textBox.props.addDocTab}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 0e281e77e..7221fbbf9 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -33,6 +33,7 @@ export namespace SelectionManager {
@action
DeselectDoc(docView: DocumentView): void {
if (manager.SelectedDocuments.get(docView)) {
+ docView.dontDecorateSelection = false;
manager.SelectedDocuments.delete(docView);
docView.props.whenActiveChanged(false);
Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
@@ -40,7 +41,10 @@ export namespace SelectionManager {
}
@action
DeselectAll(): void {
- Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
+ Array.from(manager.SelectedDocuments.keys()).map(dv => {
+ dv.dontDecorateSelection = false;
+ dv.props.whenActiveChanged(false);
+ });
manager.SelectedDocuments.clear();
Doc.UserDoc().SelectedDocs = new List<Doc>([]);
}
@@ -54,7 +58,7 @@ export namespace SelectionManager {
export function SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
manager.SelectDoc(docView, ctrlPressed);
}
-
+
export function IsSelected(doc: DocumentView, outsideReaction?: boolean): boolean {
return outsideReaction ?
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f4e830a48..454c245cc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -29,6 +29,7 @@ interface DocExtendableProps {
fieldKey: string;
isSelected: (outsideReaction?: boolean) => boolean;
renderDepth: number;
+ rootSelected: () => boolean;
}
export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
class Component extends Touchable<P> {
@@ -36,7 +37,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
@computed get Document(): T { return schemaCtor(this.props.Document); }
@computed get layoutDoc() { return Doc.Layout(this.props.Document); }
@computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
- active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools
+ active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools
}
return Component;
}
@@ -50,6 +51,7 @@ export interface DocAnnotatableProps {
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
isSelected: (outsideReaction?: boolean) => boolean;
+ rootSelected: () => boolean;
renderDepth: number;
}
export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
@@ -86,7 +88,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
- (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+ ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
(this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 79600b7c1..c35263237 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -69,7 +69,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
get Bounds(): { x: number, y: number, b: number, r: number } {
return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
if (documentView.props.renderDepth === 0 ||
- //documentView.props.Document.dontSelect ||
+ documentView.dontDecorateSelection ||
Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
return bounds;
}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ea60907f6..26bee9a6f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -705,6 +705,7 @@ export default class GestureOverlay extends Touchable {
LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={returnFalse}
+ rootSelected={returnTrue}
pinToPres={emptyFunction}
onClick={undefined}
removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8d9be5980..fae520e40 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -309,6 +309,7 @@ export class MainView extends React.Component {
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
+ rootSelected={returnTrue}
onClick={undefined}
backgroundColor={this.defaultBackgroundColors}
removeDocument={undefined}
@@ -407,6 +408,7 @@ export class MainView extends React.Component {
DataDoc={undefined}
LibraryPath={emptyPath}
addDocument={undefined}
+ rootSelected={returnTrue}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
removeDocument={undefined}
@@ -435,6 +437,7 @@ export class MainView extends React.Component {
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
+ rootSelected={returnTrue}
removeDocument={returnFalse}
onClick={undefined}
ScreenToLocalTransform={this.mainContainerXf}
@@ -523,6 +526,7 @@ export class MainView extends React.Component {
fieldKey={"data"}
dropAction={"alias"}
annotationsKey={""}
+ rootSelected={returnTrue}
bringToFront={emptyFunction}
select={emptyFunction}
active={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 220efd4a8..7587071db 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -174,6 +174,7 @@ export class OverlayView extends React.Component {
Document={d}
LibraryPath={emptyPath}
ChromeHeight={returnZero}
+ rootSelected={returnTrue}
// isSelected={returnFalse}
// select={emptyFunction}
// layoutKey={"layout"}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index e04f814d1..674b27918 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,23 +1,12 @@
+import { IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
import * as React from "react";
-import "./Palette.scss";
-import { PointData } from "../../new_fields/InkField";
import { Doc } from "../../new_fields/Doc";
-import { Docs } from "../documents/Documents";
-import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
-import { List } from "../../new_fields/List";
-import { DocumentView } from "./nodes/DocumentView";
-import { emptyPath, returnFalse, emptyFunction, returnOne, returnEmptyString, returnTrue } from "../../Utils";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { NumCast } from "../../new_fields/Types";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
import { Transform } from "../util/Transform";
-import { computed, action, IReactionDisposer, reaction, observable } from "mobx";
-import { FieldValue, Cast, NumCast } from "../../new_fields/Types";
-import { observer } from "mobx-react";
-import { DocumentContentsView } from "./nodes/DocumentContentsView";
-import { CollectionStackingView } from "./collections/CollectionStackingView";
-import { CollectionView } from "./collections/CollectionView";
-import { CollectionSubView, SubCollectionViewProps } from "./collections/CollectionSubView";
-import { makeInterface } from "../../new_fields/Schema";
-import { documentSchema } from "../../new_fields/documentSchemas";
+import { DocumentView } from "./nodes/DocumentView";
+import "./Palette.scss";
export interface PaletteProps {
x: number;
@@ -40,7 +29,7 @@ export default class Palette extends React.Component<PaletteProps> {
}
componentWillUnmount = () => {
- this._selectedDisposer && this._selectedDisposer();
+ this._selectedDisposer?.();
}
render() {
@@ -54,6 +43,7 @@ export default class Palette extends React.Component<PaletteProps> {
LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={returnFalse}
+ rootSelected={returnTrue}
pinToPres={emptyFunction}
removeDocument={undefined}
onClick={undefined}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 5ebba0abb..bf8de36b4 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -68,6 +68,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
addDocument={returnFalse}
LibraryPath={emptyPath}
removeDocument={returnFalse}
+ rootSelected={returnFalse}
ScreenToLocalTransform={Transform.Identity}
addDocTab={returnFalse}
pinToPres={returnFalse}
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
new file mode 100644
index 000000000..cd9666af8
--- /dev/null
+++ b/src/client/views/SearchDocBox.tsx
@@ -0,0 +1,432 @@
+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 "../../new_fields/Doc";
+import { Id } from "../../new_fields/FieldSymbols";
+import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { returnFalse } 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(() => {
+ console.log("didit"
+ );
+ 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) {
+ let newdocs = await this.getAllResults(this.query);
+ let things = newdocs.docs
+ console.log(things);
+ console.log(this.content);
+ runInAction(() => {
+ this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query });
+ });
+ console.log(this.content);
+ }
+
+
+ //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) => {
+ console.log(e.key);
+ if (e.key === "Enter") {
+ let newdocs = await this.getAllResults(this.query)
+ let things = newdocs.docs
+ console.log(things);
+ this.content = Docs.Create.TreeDocument(things, { _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);
+ // console.log(this._results)
+ 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(docs, { _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 (
+ <div style={{ pointerEvents: "all" }}>
+ <ContentFittingDocumentView {...this.props}
+ Document={this.content}
+ rootSelected={returnFalse}
+ getTransform={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/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 8eb5c5050..87ffb432d 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -124,7 +124,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
templateMenu.push(<OtherToggle key={"default"} name={"Default"} checked={templateName === "layout"} toggle={this.toggleDefault} />);
if (noteTypesDoc) {
- addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction("templateIsUsed(this, firstDoc)", { firstDoc: "string" }, { firstDoc: StrCast(firstDoc.title) }));
+ addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(this, "${StrCast(firstDoc.title)}")`, { firstDoc: "string" }));
this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push(
<OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
templateMenu.push(
@@ -174,10 +174,12 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc) {
return templateTitle && DocumentView.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template);
});
-Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) {
+Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitle: string) {
const firstDoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0].props.Document : undefined;
- if (!firstDoc) return false;
- const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
- return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
+ if (firstDoc) {
+ const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
+ return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
+ }
+ return false;
// return SelectionManager.SelectedDocuments().some(view => StrCast(view.props.Document.layoutKey) === "layout_" + template) ? 'check' : 'unchecked'
}); \ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4e1e76f39..4209bd574 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -788,6 +788,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
Document={document}
DataDoc={resolvedDataDoc}
bringToFront={emptyFunction}
+ rootSelected={returnTrue}
addDocument={undefined}
removeDocument={undefined}
ContentScaling={this.contentScaling}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 344605412..a6ada75b2 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
import { makeInterface } from '../../../new_fields/Schema';
import { BoolCast, NumCast, StrCast, Cast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
import { Transform } from '../../util/Transform';
import "./CollectionLinearView.scss";
@@ -110,6 +110,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
removeDocument={this.props.removeDocument}
onClick={undefined}
ScreenToLocalTransform={this.getTransform(dref)}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 981438513..a1b541f74 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -124,6 +124,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
LibraryPath={this.props.LibraryPath}
childDocs={this.childDocs}
renderDepth={this.props.renderDepth}
+ rootSelected={this.rootSelected}
PanelWidth={this.previewWidth}
PanelHeight={this.previewHeight}
getTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 076dd3629..d21e17bbc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
LibraryPath={this.props.LibraryPath}
renderDepth={this.props.renderDepth + 1}
fitToBox={this.props.fitToBox}
+ rootSelected={this.rootSelected}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
PanelWidth={width}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 70927cf22..d1d6ae3c1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,6 +34,7 @@ export interface CollectionViewProps extends FieldViewProps {
PanelHeight: () => number;
VisibleHeight?: () => number;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+ rootSelected: () => boolean;
fieldKey: string;
}
@@ -95,6 +96,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
}
+ rootSelected = () => {
+ return this.props.isSelected() || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected() : false);
+ }
+
// The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
// When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
// to its children which may be templates.
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 6ee48f11b..fc612c66d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,6 +373,7 @@ class TreeView extends React.Component<TreeViewProps> {
DataDocument={this.templateDataDoc}
LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
+ rootSelected={returnTrue}
backgroundColor={this.props.backgroundColor}
fitToBox={this.boundsOfCollectionDocument !== undefined}
PanelWidth={this.docWidth}
@@ -454,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
LibraryPath={this.props.libraryPath || []}
addDocument={undefined}
addDocTab={this.props.addDocTab}
+ rootSelected={returnTrue}
pinToPres={emptyFunction}
onClick={this.props.onChildClick || editTitle}
dropAction={this.props.dropAction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index df1770ffe..23d701ffd 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -117,7 +117,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
return viewField;
}
- active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0;
+ active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected() && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
@@ -463,7 +463,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
:
""))}
- {!this.props.isSelected() || this.props.PanelHeight() < 100 ? (null) :
+ {!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) :
<div className="collectionTimeView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this.facetWidth()}px, 0px)` }} >
<span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} />
</div>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2871fe192..a164e1794 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
Document: childLayout,
LibraryPath: this.libraryPath,
layoutKey: undefined,
+ rootSelected: this.rootSelected,
dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
//onClick: undefined, // this.props.onClick, // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
onClick: this.onChildClickHandler,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 276a49570..503df10c2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -5,7 +5,6 @@ import { InkField, InkData } from "../../../../new_fields/InkField";
import { List } from "../../../../new_fields/List";
import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
-import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
import { Utils } from "../../../../Utils";
import { Docs, DocUtils } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 03b2a2297..bd54d64ff 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
import { DocExtendableComponent } from "../DocComponent";
import { makeInterface, createSchema } from "../../../new_fields/Schema";
import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
import { DateField } from "../../../new_fields/DateField";
import { SelectionManager } from "../../util/SelectionManager";
@@ -258,9 +258,15 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
return !linkTime ? (null) :
<div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
<div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
- <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
+ <DocumentView {...this.props}
+ Document={l}
+ rootSelected={returnFalse}
+ layoutKey={Doc.LinkEndpoint(l, la2)}
ContainingCollectionDoc={this.props.Document}
- parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
+ parentActive={returnTrue}
+ bringToFront={emptyFunction}
+ zoomToScale={emptyFunction}
+ getScale={returnOne}
backgroundColor={returnTransparent} />
</div>
<div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index eaab4086c..356192797 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -89,14 +89,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
pointerEvents: this.props.Document.isBackground ? "none" : undefined
}} >
- {!this.props.fitToBox ? <DocumentView {...this.props}
+ {!this.props.fitToBox ?
+ <DocumentView {...this.props}
dragDivName={"collectionFreeFormDocumentView-container"}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
backgroundColor={this.props.backgroundColor}
PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
- /> : <ContentFittingDocumentView {...this.props}
+ PanelHeight={this.panelHeight} />
+ : <ContentFittingDocumentView {...this.props}
CollectionDoc={this.props.ContainingCollectionDoc}
DataDocument={this.props.DataDoc}
getTransform={this.getTransform}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9494a4bc4..fdf2a9551 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -40,6 +40,7 @@ interface ContentFittingDocumentViewProps {
addDocTab: (document: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
dontRegisterView?: boolean;
+ rootSelected: () => boolean;
}
@observer
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index debe104d7..47118e758 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -122,6 +122,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
CollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
fitToBox={this.props.fitToBox}
layoutKey={"layout_" + childTemplateName}
+ rootSelected={this.props.isSelected}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
removeDocument={this.props.removeDocument}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 68501fca2..dc71ba280 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,6 +1,6 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
import { Cast, StrCast } from "../../../new_fields/Types";
import { OmitKeys, Without } from "../../../Utils";
import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
@@ -35,6 +35,7 @@ import { WebBox } from "./WebBox";
import { InkingStroke } from "../InkingStroke";
import React = require("react");
import { RecommendationsBox } from "../RecommendationsBox";
+
import { TraceMobx } from "../../../new_fields/util";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -60,7 +61,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
forceLayout?: string,
forceFieldKey?: string,
hideOnLeave?: boolean,
- makeLink?: () => Opt<Doc>;
+ makeLink?: () => Opt<Doc>, // function to call when a link is made
}> {
@computed get layout(): string {
TraceMobx();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 02a1ac527..42f5fb946 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -60,6 +60,7 @@ export interface DocumentViewProps {
LayoutDoc?: () => Opt<Doc>;
LibraryPath: Doc[];
fitToBox?: boolean;
+ rootSelected: () => boolean; // whether the root of a template has been selected
onClick?: ScriptField;
onPointerDown?: ScriptField;
onPointerUp?: ScriptField;
@@ -272,10 +273,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
+ dontDecorateSelection: any = false;
onClick = (e: React.MouseEvent | React.PointerEvent) => {
+ this.dontDecorateSelection = this.props.Document.dontDecorateSelection && (!e.ctrlKey || e.button < 2);
if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
(Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
- e.stopPropagation();
+ let stopPropagate = true;
let preventDefault = true;
this.props.bringToFront(this.props.Document);
if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
@@ -292,16 +295,21 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this: this.props.Document,
self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document,
containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
- }, console.log) && !this.props.Document.dontSelect && !this.props.Document.isButton && this.select(false), "on click");
+ }, console.log) && !this.props.Document.dontDecorateSelection && !this.props.Document.isButton && this.select(false), "on click");
} else if (this.Document.type === DocumentType.BUTTON) {
UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
} else if (this.Document.isButton) {
SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
UndoManager.RunInBatch(() => this.buttonClick(e.altKey, e.ctrlKey), "on link button follow");
} else {
- SelectionManager.SelectDoc(this, e.ctrlKey);
+ if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
+ stopPropagate = false;
+ } else {
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
preventDefault = false;
}
+ stopPropagate && e.stopPropagation();
preventDefault && e.preventDefault();
}
}
@@ -926,6 +934,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const fallback = Cast(this.props.Document.layoutKey, "string");
return typeof fallback === "string" ? fallback : "layout";
}
+ rootSelected = () => {
+ return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
+ }
childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@computed get contents() {
TraceMobx();
@@ -935,6 +946,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
DataDoc={this.props.DataDoc}
LayoutDoc={this.props.LayoutDoc}
makeLink={this.makeLink}
+ rootSelected={this.rootSelected}
fitToBox={this.props.fitToBox}
LibraryPath={this.props.LibraryPath}
addDocument={this.props.addDocument}
@@ -983,9 +995,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
{StrCast(this.props.Document.title)}
{this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
<div className="documentView-docuLinkWrapper" style={{ position: "absolute", top: 0, left: 0 }} key={`${d[Id]}`}>
- <DocumentView {...this.props} Document={d} ContainingCollectionDoc={this.props.Document}
- PanelWidth={returnOne} PanelHeight={returnOne} layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
- backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
+ <DocumentView {...this.props}
+ Document={d}
+ ContainingCollectionDoc={this.props.Document}
+ PanelWidth={returnOne} PanelHeight={returnOne}
+ layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
+ backgroundColor={returnTransparent}
+ removeDocument={undoBatch(doc => doc.hidden = true)} />
</div>)}
</div>;
}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0305f43d5..13a1becf7 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
dropAction: dropActionType;
isSelected: (outsideReaction?: boolean) => boolean;
select: (isCtrlPressed: boolean) => void;
+ rootSelected: () => boolean;
renderDepth: number;
addDocument?: (document: Doc) => boolean;
addDocTab: (document: Doc, where: string) => boolean;
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 61df188f8..d1a563494 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -181,6 +181,7 @@ export class FormattedTextBoxComment {
LibraryPath={emptyPath}
fitToBox={true}
moveDocument={returnFalse}
+ rootSelected={returnFalse}
getTransform={Transform.Identity}
active={returnFalse}
addDocument={returnFalse}
diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss
index e69de29bb..82f64054c 100644
--- a/src/client/views/nodes/QueryBox.scss
+++ b/src/client/views/nodes/QueryBox.scss
@@ -0,0 +1,6 @@
+.queryBox, .queryBox-dragging {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ pointer-events: all;
+} \ No newline at end of file
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
index 99b5810fc..7016b4f04 100644
--- a/src/client/views/nodes/QueryBox.tsx
+++ b/src/client/views/nodes/QueryBox.tsx
@@ -1,35 +1,34 @@
import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons';
import { IReactionDisposer } from "mobx";
import { observer } from "mobx-react";
-import { FilterBox } from "../search/FilterBox";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { Id } from '../../../new_fields/FieldSymbols';
+import { makeInterface } from "../../../new_fields/Schema";
+import { StrCast } from "../../../new_fields/Types";
+import { SelectionManager } from "../../util/SelectionManager";
+import { DocAnnotatableComponent } from '../DocComponent';
+import { SearchBox } from "../search/SearchBox";
import { FieldView, FieldViewProps } from './FieldView';
-import "./PresBox.scss";
+import "./QueryBox.scss";
-library.add(faArrowLeft);
-library.add(faArrowRight);
-library.add(faPlay);
-library.add(faStop);
-library.add(faPlus);
-library.add(faTimes);
-library.add(faMinus);
-library.add(faEdit);
+type QueryDocument = makeInterface<[typeof documentSchema]>;
+const QueryDocument = makeInterface(documentSchema);
@observer
-export class QueryBox extends React.Component<FieldViewProps> {
+export class QueryBox extends DocAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
_docListChangedReaction: IReactionDisposer | undefined;
componentDidMount() {
}
componentWillUnmount() {
- this._docListChangedReaction && this._docListChangedReaction();
+ this._docListChangedReaction?.();
}
render() {
- return <div style={{ width: "100%", height: "100%", position: "absolute", pointerEvents: "all" }}>
- <FilterBox></FilterBox>
- </div>;
+ const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
+ return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
+ <SearchBox id={this.props.Document[Id]} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQquery={StrCast(this.dataDoc.filterQuery)} />
+ </div >;
}
} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 71495d95f..c032f019d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,8 +31,6 @@ import { InkingControl } from "../InkingControl";
import { InkTool } from "../../../new_fields/InkField";
import { TraceMobx } from "../../../new_fields/util";
import { PdfField } from "../../../new_fields/URLField";
-import { PDFBox } from "../nodes/PDFBox";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
import { DocumentView } from "../nodes/DocumentView";
const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
const pdfjsLib = require("pdfjs-dist");
@@ -61,6 +59,7 @@ interface IViewerProps {
PanelHeight: () => number;
ContentScaling: () => number;
select: (isCtrlPressed: boolean) => void;
+ rootSelected: () => boolean;
startupLive: boolean;
renderDepth: number;
focus: (doc: Doc) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 758795ed5..7ad3474e8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -9,7 +9,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from "../../../new_fields/FieldSymbols";
import { createSchema, makeInterface } from '../../../new_fields/Schema';
import { Cast, NumCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils";
import { Transform } from "../../util/Transform";
import { CollectionViewType } from '../collections/CollectionView';
import { DocExtendableComponent } from '../DocComponent';
@@ -175,6 +175,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
LibraryPath={emptyPath}
fitToBox={true}
+ rootSelected={returnTrue}
addDocument={returnFalse}
removeDocument={returnFalse}
addDocTab={returnFalse}
diff --git a/src/client/views/search/CheckBox.tsx b/src/client/views/search/CheckBox.tsx
index a9d48219a..8c97d5dbc 100644
--- a/src/client/views/search/CheckBox.tsx
+++ b/src/client/views/search/CheckBox.tsx
@@ -17,8 +17,8 @@ interface CheckBoxProps {
export class CheckBox extends React.Component<CheckBoxProps>{
// true = checked, false = unchecked
@observable private _status: boolean;
- @observable private uncheckTimeline: anime.AnimeTimelineInstance;
- @observable private checkTimeline: anime.AnimeTimelineInstance;
+ // @observable private uncheckTimeline: anime.AnimeTimelineInstance;
+ // @observable private checkTimeline: anime.AnimeTimelineInstance;
@observable private checkRef: any;
@observable private _resetReaction?: IReactionDisposer;
@@ -28,87 +28,87 @@ export class CheckBox extends React.Component<CheckBoxProps>{
this._status = this.props.originalStatus;
this.checkRef = React.createRef();
- this.checkTimeline = anime.timeline({
- loop: false,
- autoplay: false,
- direction: "normal",
- }); this.uncheckTimeline = anime.timeline({
- loop: false,
- autoplay: false,
- direction: "normal",
- });
+ // this.checkTimeline = anime.timeline({
+ // loop: false,
+ // autoplay: false,
+ // direction: "normal",
+ // }); this.uncheckTimeline = anime.timeline({
+ // loop: false,
+ // autoplay: false,
+ // direction: "normal",
+ // });
}
- componentDidMount = () => {
- this.uncheckTimeline.add({
- targets: this.checkRef.current,
- easing: "easeInOutQuad",
- duration: 500,
- opacity: 0,
- });
- this.checkTimeline.add({
- targets: this.checkRef.current,
- easing: "easeInOutQuad",
- duration: 500,
- strokeDashoffset: [anime.setDashoffset, 0],
- opacity: 1
- });
+ // componentDidMount = () => {
+ // this.uncheckTimeline.add({
+ // targets: this.checkRef.current,
+ // easing: "easeInOutQuad",
+ // duration: 500,
+ // opacity: 0,
+ // });
+ // this.checkTimeline.add({
+ // targets: this.checkRef.current,
+ // easing: "easeInOutQuad",
+ // duration: 500,
+ // strokeDashoffset: [anime.setDashoffset, 0],
+ // opacity: 1
+ // });
- if (this.props.originalStatus) {
- this.checkTimeline.play();
- this.checkTimeline.restart();
- }
+ // if (this.props.originalStatus) {
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
+ // }
- this._resetReaction = reaction(
- () => this.props.parent._resetBoolean,
- () => {
- if (this.props.parent._resetBoolean) {
- runInAction(() => {
- this.reset();
- this.props.parent._resetCounter++;
- if (this.props.parent._resetCounter === this.props.numCount) {
- this.props.parent._resetCounter = 0;
- this.props.parent._resetBoolean = false;
- }
- });
- }
- },
- );
- }
+ // this._resetReaction = reaction(
+ // () => this.props.parent._resetBoolean,
+ // () => {
+ // if (this.props.parent._resetBoolean) {
+ // runInAction(() => {
+ // this.reset();
+ // this.props.parent._resetCounter++;
+ // if (this.props.parent._resetCounter === this.props.numCount) {
+ // this.props.parent._resetCounter = 0;
+ // this.props.parent._resetBoolean = false;
+ // }
+ // });
+ // }
+ // },
+ // );
+ // }
- @action.bound
- reset() {
- if (this.props.default) {
- if (!this._status) {
- this._status = true;
- this.checkTimeline.play();
- this.checkTimeline.restart();
- }
- }
- else {
- if (this._status) {
- this._status = false;
- this.uncheckTimeline.play();
- this.uncheckTimeline.restart();
- }
- }
+ // @action.bound
+ // reset() {
+ // if (this.props.default) {
+ // if (!this._status) {
+ // this._status = true;
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
+ // }
+ // }
+ // else {
+ // if (this._status) {
+ // this._status = false;
+ // this.uncheckTimeline.play();
+ // this.uncheckTimeline.restart();
+ // }
+ // }
- this.props.updateStatus(this.props.default);
- }
+ // this.props.updateStatus(this.props.default);
+ // }
@action.bound
onClick = () => {
- if (this._status) {
- this.uncheckTimeline.play();
- this.uncheckTimeline.restart();
- }
- else {
- this.checkTimeline.play();
- this.checkTimeline.restart();
+ // if (this._status) {
+ // this.uncheckTimeline.play();
+ // this.uncheckTimeline.restart();
+ // }
+ // else {
+ // this.checkTimeline.play();
+ // this.checkTimeline.restart();
- }
- this._status = !this._status;
- this.props.updateStatus(this._status);
+ // }
+ // this._status = !this._status;
+ // this.props.updateStatus(this._status);
}
diff --git a/src/client/views/search/FilterBox.scss b/src/client/views/search/FilterBox.scss
index ebb39460d..094ea9cc5 100644
--- a/src/client/views/search/FilterBox.scss
+++ b/src/client/views/search/FilterBox.scss
@@ -4,7 +4,6 @@
.filter-form {
padding: 25px;
width: 440px;
- background: whitesmoke;
position: relative;
right: 1px;
color: grey;
@@ -12,9 +11,7 @@
display: inline-block;
transform-origin: top;
overflow: auto;
- border-radius: 15px;
- box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw;
- border: solid #BBBBBBBB 1px;
+ border-bottom: solid black 3px;
.top-filter-header {
@@ -124,7 +121,7 @@
max-width: 40px;
flex: initial;
- &.icon{
+ &.icon {
width: 40px;
text-align: center;
margin-bottom: 5px;
@@ -150,7 +147,7 @@
transition: all 0.2s ease-in-out;
}
- &.icon:hover + .description {
+ &.icon:hover+.description {
opacity: 1;
}
}
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
index d4c9e67fb..1c05ff864 100644
--- a/src/client/views/search/FilterBox.tsx
+++ b/src/client/views/search/FilterBox.tsx
@@ -387,7 +387,7 @@ export class FilterBox extends React.Component {
{/* {this.getActiveFilters()} */}
</div>
{this._filterOpen ? (
- <div className="filter-form" onPointerDown={this.stopProp} id="filter-form" style={this._filterOpen ? { display: "flex" } : { display: "none" }}>
+ <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>
diff --git a/src/client/views/search/IconBar.scss b/src/client/views/search/IconBar.scss
index 2555ad271..013dcd57e 100644
--- a/src/client/views/search/IconBar.scss
+++ b/src/client/views/search/IconBar.scss
@@ -2,10 +2,9 @@
.icon-bar {
display: flex;
+ flex-wrap: wrap;
justify-content: space-evenly;
- align-items: center;
- height: 35px;
+ height: auto;
width: 100%;
- flex-wrap: wrap;
- margin-bottom: 10px;
+ flex-direction: row-reverse;
} \ No newline at end of file
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index cff397407..46c109934 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -9,7 +9,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import * as _ from "lodash";
import { IconButton } from './IconButton';
-import { FilterBox } from './FilterBox';
+import { DocumentType } from "../../documents/DocumentTypes";
+
library.add(faSearch);
library.add(faObjectGroup);
@@ -25,6 +26,9 @@ library.add(faBan);
@observer
export class IconBar extends React.Component {
+ public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+
+ @observable private _icons: string[] = this._allIcons;
static Instance: IconBar;
@@ -33,16 +37,22 @@ export class IconBar extends React.Component {
@observable public _reset: number = 0;
@observable public _select: number = 0;
+ @action.bound
+ updateIcon(newArray: string[]) { this._icons = newArray; }
+
+ @action.bound
+ getIcons(): string[] { return this._icons; }
+
constructor(props: any) {
super(props);
IconBar.Instance = this;
}
@action.bound
- getList(): string[] { return FilterBox.Instance.getIcons(); }
+ getList(): string[] { return this.getIcons(); }
@action.bound
- updateList(newList: string[]) { FilterBox.Instance.updateIcon(newList); }
+ updateList(newList: string[]) { this.updateIcon(newList); }
@action.bound
resetSelf = () => {
@@ -53,13 +63,13 @@ export class IconBar extends React.Component {
@action.bound
selectAll = () => {
this._selectAllClicked = true;
- this.updateList(FilterBox.Instance._allIcons);
+ this.updateList(this._allIcons);
}
render() {
return (
<div className="icon-bar">
- {FilterBox.Instance._allIcons.map((type: string) =>
+ {this._allIcons.map((type: string) =>
<IconButton key={type.toString()} type={type} />
)}
</div>
diff --git a/src/client/views/search/IconButton.scss b/src/client/views/search/IconButton.scss
index 4a3107676..4ec03c7c9 100644
--- a/src/client/views/search/IconButton.scss
+++ b/src/client/views/search/IconButton.scss
@@ -5,7 +5,6 @@
flex-direction: column;
align-items: center;
width: 30px;
- height: 60px;
.type-icon {
height: 30px;
diff --git a/src/client/views/search/IconButton.tsx b/src/client/views/search/IconButton.tsx
index f01508141..4f94139d9 100644
--- a/src/client/views/search/IconButton.tsx
+++ b/src/client/views/search/IconButton.tsx
@@ -11,7 +11,6 @@ import '../globalCssVariables.scss';
import * as _ from "lodash";
import { IconBar } from './IconBar';
import { props } from 'bluebird';
-import { FilterBox } from './FilterBox';
import { Search } from '../../../server/Search';
import { gravity } from 'sharp';
@@ -34,7 +33,7 @@ interface IconButtonProps {
@observer
export class IconButton extends React.Component<IconButtonProps>{
- @observable private _isSelected: boolean = FilterBox.Instance.getIcons().indexOf(this.props.type) !== -1;
+ @observable private _isSelected: boolean = IconBar.Instance.getIcons().indexOf(this.props.type) !== -1;
@observable private _hover = false;
private _resetReaction?: IReactionDisposer;
private _selectAllReaction?: IReactionDisposer;
@@ -108,7 +107,7 @@ export class IconButton extends React.Component<IconButtonProps>{
@action.bound
onClick = () => {
- const newList: string[] = FilterBox.Instance.getIcons();
+ const newList: string[] = IconBar.Instance.getIcons();
if (!this._isSelected) {
this._isSelected = true;
@@ -119,21 +118,24 @@ export class IconButton extends React.Component<IconButtonProps>{
_.pull(newList, this.props.type);
}
- FilterBox.Instance.updateIcon(newList);
+ IconBar.Instance.updateIcon(newList);
}
selected = {
opacity: 1,
- backgroundColor: "rgb(128, 128, 128)"
+ backgroundColor: "#121721",
+ //backgroundColor: "rgb(128, 128, 128)"
};
notSelected = {
opacity: 0.2,
+ backgroundColor: "#121721",
};
hoverStyle = {
opacity: 1,
- backgroundColor: "rgb(178, 206, 248)" //$darker-alt-accent
+ backgroundColor: "rgb(128, 128, 128)"
+ //backgroundColor: "rgb(178, 206, 248)" //$darker-alt-accent
};
@action.bound
@@ -186,7 +188,7 @@ export class IconButton extends React.Component<IconButtonProps>{
>
{this.getFA()}
</div>
- <div className="filter-description">{this.props.type}</div>
+ {/* <div className="filter-description">{this.props.type}</div> */}
</div>
);
}
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index f492ea773..f0223ca76 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -4,20 +4,21 @@
.searchBox-container {
display: flex;
flex-direction: column;
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
position: absolute;
font-size: 10px;
line-height: 1;
- overflow: hidden;
+ overflow: auto;
+ background: lightgrey,
}
+
.searchBox-bar {
height: 32px;
display: flex;
justify-content: flex-end;
align-items: center;
padding-left: 2px;
- padding-right: 2px;
.searchBox-barChild {
@@ -33,8 +34,7 @@
-webkit-transition: width 0.4s;
transition: width 0.4s;
align-self: stretch;
- margin-left: 2px;
- margin-right: 2px
+
}
.searchBox-input:focus {
@@ -44,6 +44,10 @@
&.searchBox-filter {
align-self: stretch;
+ button:hover{
+ transform:scale(1.0);
+ background:"#121721";
+ }
}
&.searchBox-submit {
@@ -65,7 +69,7 @@
}
.searchBox-results {
- display:flex;
+ display: flex;
flex-direction: column;
top: 300px;
display: flex;
@@ -83,6 +87,249 @@
text-transform: uppercase;
text-align: left;
font-weight: bold;
- margin-left: 28px;
+ }
+}
+
+.filter-form {
+ position: relative;
+ background: #121721;
+ flex-direction: column;
+ transform-origin: top;
+ transition: height 0.3s ease, display 0.6s ease;
+ height:0px;
+ overflow:hidden;
+
+
+ .filter-header {
+ display: flex;
+ position: relative;
+ flex-wrap:wrap;
+ right: 1px;
+ color: grey;
+ flex-direction: row-reverse;
+ transform-origin: top;
+ justify-content: space-evenly;
+ margin-bottom: 5px;
+ overflow:hidden;
+ transition:height 0.3s ease-out;
+
+
+
+ .filter-item {
+ position: relative;
+ border:1px solid grey;
+ border-radius: 16px;
+
+ }
+ }
+
+ .filter-body {
+ position: relative;
+ right: 1px;
+ 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-key {
+ position: relative;
+ right: 1px;
+ 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-item {
+ position: relative;
+ border:1px solid grey;
+ border-radius: 16px;
+
+ }
+ }
+
+
+ }
+}
+
+// .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/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 586365f6e..49b6b18ca 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -1,37 +1,51 @@
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 } from 'mobx';
+import { action, computed, observable, runInAction, IReactionDisposer, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as rp from 'request-promise';
import { Doc } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
-import { Cast, NumCast } from '../../../new_fields/Types';
+import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
import { Utils } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { SetupDrag } from '../../util/DragManager';
import { SearchUtil } from '../../util/SearchUtil';
-import { FilterBox } from './FilterBox';
-import "./FilterBox.scss";
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';
library.add(faTimes);
+export interface SearchProps {
+ id: string;
+ searchQuery?: string;
+ filterQquery?: string;
+}
+
+export enum Keys {
+ TITLE = "title",
+ AUTHOR = "author",
+ DATA = "data"
+}
+
@observer
-export class SearchBox extends React.Component {
+export class SearchBox extends React.Component<SearchProps> {
@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>();
+ private _resultsSet = new Map<Doc, number>();
+ private _resultsRef = React.createRef<HTMLDivElement>();
public inputRef = React.createRef<HTMLInputElement>();
private _isSearch: ("search" | "placeholder" | undefined)[] = [];
@@ -42,10 +56,18 @@ export class SearchBox extends React.Component {
private _maxSearchIndex: number = 0;
private _curRequest?: Promise<any> = undefined;
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); }
+
+
+ //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;
+
constructor(props: any) {
super(props);
-
SearchBox.Instance = this;
this.resultsScrolled = this.resultsScrolled.bind(this);
}
@@ -53,20 +75,22 @@ export class SearchBox extends React.Component {
componentDidMount = () => {
if (this.inputRef.current) {
this.inputRef.current.focus();
+ runInAction(() => this._searchbarOpen = true);
+ }
+ if (this.props.searchQuery && this.props.filterQquery) {
+ console.log(this.props.searchQuery);
+ const sq = this.props.searchQuery;
runInAction(() => {
- this._searchbarOpen = true;
+ this._searchString = sq;
+ this.submitSearch();
});
}
}
+
@action
getViews = async (doc: Doc) => {
- const results = await SearchUtil.GetViewsOfDocument(doc);
- let toReturn: Doc[] = [];
- await runInAction(() => {
- toReturn = results;
- });
- return toReturn;
+ return await SearchUtil.GetViewsOfDocument(doc);
}
@action.bound
@@ -106,33 +130,191 @@ export class SearchBox extends React.Component {
}
}
+ public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB, DocumentType.TEMPLATE];
+ //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 _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;
+
+
+ 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;
+ }
+
+ 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;
+ }
+
+ @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;
+ }
+
+ 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.bound
+ updateIcon(newArray: string[]) { this._icons = newArray; }
+
+ @action.bound
+ getIcons(): string[] { return this._icons; }
+
+ //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;
+ }
+
+
+ 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;
+ }
+
+ 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;
+ }
+
+ get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); }
+
+
@action
submitSearch = async () => {
let query = this._searchString;
- query = FilterBox.Instance.getFinalQuery(query);
+ this.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 {
+ if (query !== "") {
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();
- });
+ runInAction(() => {
+ this._resultsOpen = true;
+ this._searchbarOpen = true;
+ this._openNoResults = true;
+ this.resultsScrolled();
+ });
+ }
}
getAllResults = async (query: string) => {
@@ -140,11 +322,13 @@ export class SearchBox extends React.Component {
}
private get filterQuery() {
- const types = FilterBox.Instance.filterTypes;
- const includeDeleted = FilterBox.Instance.getDataStatus();
+ const types = this.filterTypes;
+ const includeDeleted = this.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(" ")})` : "");
}
+ getDataStatus() { return this._deletedDocsStatus; }
+
private NumResults = 25;
private lockPromise?: Promise<void>;
@@ -155,7 +339,6 @@ export class SearchBox extends React.Component {
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;
@@ -168,9 +351,9 @@ export class SearchBox extends React.Component {
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);
+ const filteredDocs = this.filterDocsByType(docs);
runInAction(() => {
- // this._results.push(...filteredDocs);
+ //this._results.push(...filteredDocs);
filteredDocs.forEach(doc => {
const index = this._resultsSet.get(doc);
const highlight = highlights[doc[Id]];
@@ -200,9 +383,8 @@ export class SearchBox extends React.Component {
collectionRef = React.createRef<HTMLSpanElement>();
startDragCollection = async () => {
- const res = await this.getAllResults(FilterBox.Instance.getFinalQuery(this._searchString));
- const filtered = FilterBox.Instance.filterDocsByType(res.docs);
- // console.log(this._results)
+ const res = await this.getAllResults(this.getFinalQuery(this._searchString));
+ const filtered = this.filterDocsByType(res.docs);
const docs = filtered.map(doc => {
const isProto = Doc.GetT(doc, "isPrototype", "boolean", true);
if (isProto) {
@@ -234,22 +416,19 @@ export class SearchBox extends React.Component {
y += 300;
}
}
- return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, title: `Search Docs: "${this._searchString}"` });
+ return Docs.Create.QueryDocument({ _autoHeight: true, title: this._searchString, filterQuery: this.filterQuery, searchQuery: 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;
}
@@ -267,11 +446,11 @@ export class SearchBox extends React.Component {
@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;
+ 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)));
+ const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this._resultsRef.current.getBoundingClientRect().height / itemHght)));
this._endIndex = endIndex === -1 ? 12 : endIndex;
@@ -337,9 +516,132 @@ export class SearchBox extends React.Component {
@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}`);
+
+
+ }
+ }
+
+ @computed
+ get menuHeight() {
+ return document.getElementById("hi")?.clientHeight;
+ }
+
+
+ collapseSection(thing: string) {
+ let id = this.props.id;
+ let element = document.getElementById(thing)!;
+ // get the height of the element's inner content, regardless of its actual size
+ var sectionHeight = element.scrollHeight;
+
+ // temporarily disable all css transitions
+ var 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) {
+ console.log("expand");
+ let element = document.getElementById(thing)!;
+ // get the height of the element's inner content, regardless of its actual size
+ var sectionHeight = element.scrollHeight;
+
+ // have the element transition to the height of its inner content
+ let temp = element.style.height;
+ 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
+ console.log("autoset");
+ 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');
+
+ }
+
+ autoset(thing: string) {
+ let element = document.getElementById(thing)!;
+ console.log("autoset");
+ 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;
+ }
+
+ @action.bound
+ updateTitleStatus() { this._titleFieldStatus = !this._titleFieldStatus; }
+
+ @action.bound
+ updateAuthorStatus() { this._authorFieldStatus = !this._authorFieldStatus; }
+
+ @action.bound
+ updateDataStatus() { this._deletedDocsStatus = !this._deletedDocsStatus; }
+
render() {
+
return (
- <div className="searchBox-container" onPointerDown={e => { e.stopPropagation(); e.preventDefault(); }}>
+ <div 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" />
@@ -347,16 +649,31 @@ export class SearchBox extends React.Component {
<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={() => { }} onPointerDown={FilterBox.Instance.stopProp}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button>
+ <button className="searchBox-barChild searchBox-filter" title="Advanced Filtering Options" onClick={() => this.handleFilterChange()}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button>
</div>
- <div className="searchBox-quickFilter" onPointerDown={this.openSearch}>
- <div className="filter-panel"><IconBar /></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 />
+ </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>
+ </div>
</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}>
+ }} ref={this._resultsRef}>
{this._visibleElements}
</div>
</div>
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 63cef5101..0d77026ad 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
import { Doc } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue } from "../../../Utils";
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, SetupDrag } from "../../util/DragManager";
@@ -158,6 +158,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
<ContentFittingDocumentView
Document={this.props.doc}
LibraryPath={emptyPath}
+ rootSelected={returnFalse}
fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
addDocument={returnFalse}
removeDocument={returnFalse}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 1d2d57b96..98a6d384e 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -124,6 +124,7 @@ export default class MobileInterface extends React.Component {
addDocument={returnFalse}
addDocTab={returnFalse}
pinToPres={emptyFunction}
+ rootSelected={returnFalse}
removeDocument={undefined}
onClick={undefined}
ScreenToLocalTransform={Transform.Identity}
@@ -285,6 +286,7 @@ export default class MobileInterface extends React.Component {
addDocument={returnFalse}
addDocTab={returnFalse}
pinToPres={emptyFunction}
+ rootSelected={returnFalse}
removeDocument={undefined}
onClick={undefined}
ScreenToLocalTransform={Transform.Identity}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 91ea32bee..4bf871d97 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -42,7 +42,7 @@ export const documentSchema = createSchema({
removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee)
- dontSelect: "boolean", // whether document should be selected when clicked (usually set to false for buttons)
+ dontDecorateSelection: "boolean", // whether document should be selected when clicked (usually set to false for buttons)
treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden
treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree
treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts
index 1ed98cdbe..5cbba13de 100644
--- a/src/server/DashSession/DashSessionAgent.ts
+++ b/src/server/DashSession/DashSessionAgent.ts
@@ -226,4 +226,4 @@ export namespace DashSessionAgent {
export const notificationRecipient = "brownptcdash@gmail.com";
-} \ No newline at end of file
+}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 4f82da44d..fc6e36485 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -89,6 +89,9 @@ export class CurrentUserUtils {
{ title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
{ title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
{ title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
+ { title: "query", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
+
+
];
return docProtoData.filter(d => !alreadyCreatedButtons?.includes(d.title)).map(data => Docs.Create.FontIconDocument({
_nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
@@ -97,7 +100,7 @@ export class CurrentUserUtils {
ignoreClick: data.ignoreClick,
dropAction: data.click ? "copy" : undefined,
onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, dontSelect: true,
+ ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, dontDecorateSelection: true,
backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
}));
}
@@ -207,10 +210,10 @@ export class CurrentUserUtils {
});
return Docs.Create.ButtonDocument({
- _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontSelect: true,
+ _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
- _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack"
+ _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
}),
onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
});
@@ -233,7 +236,7 @@ export class CurrentUserUtils {
});
return Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Library", fontSize: 10, dontSelect: true,
+ _width: 50, _height: 25, title: "Library", fontSize: 10, dontDecorateSelection: true,
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
@@ -246,11 +249,9 @@ export class CurrentUserUtils {
// setup the Search button which will display the search panel.
static setupSearchPanel(sidebarContainer: Doc) {
return Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Search", fontSize: 10, dontSelect: true,
+ _width: 50, _height: 25, title: "Search", fontSize: 10, dontDecorateSelection: true,
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: Docs.Create.QueryDocument({
- title: "search stack", ignoreClick: true
- }),
+ sourcePanel: Docs.Create.QueryDocument({ title: "search stack", }),
targetContainer: sidebarContainer,
lockedPosition: true,
onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
@@ -277,6 +278,13 @@ export class CurrentUserUtils {
/// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
static setupExpandingButtons(doc: Doc) {
+ const queryTemplate = Docs.Create.MulticolumnDocument(
+ [
+ Docs.Create.QueryDocument({ title: "query", _height: 200 }),
+ Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
+ ],
+ { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
+ queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
const slideTemplate = Docs.Create.MultirowDocument(
[
Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }),
@@ -288,10 +296,10 @@ export class CurrentUserUtils {
Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
- const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dontSelect: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
+ const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dontDecorateSelection: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
...opts,
- _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontSelect: true, forceActive: true,
+ _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontDecorateSelection: true, forceActive: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
})) as any as Doc;
@@ -300,7 +308,8 @@ export class CurrentUserUtils {
doc.redoBtn = ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
- doc.templateButtons = blist({ title: "template buttons" }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc]);
+ doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "sticky-note" });
+ doc.templateButtons = blist({ title: "template buttons" }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
doc.expandingButtons = blist({ title: "expanding buttons" }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
title: "template layouts", _xPadding: 0,
diff --git a/src/server/index.ts b/src/server/index.ts
index f4446352f..97f70630b 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -146,7 +146,7 @@ export async function launchServer() {
* So, the 'else' clause is exactly what we've always run when executing npm start.
*/
if (process.env.RELEASE) {
- // (sessionAgent = new DashSessionAgent()).launch();
+ (sessionAgent = new DashSessionAgent()).launch();
} else {
launchServer();
}