aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/DocumentTypes.ts7
-rw-r--r--src/client/documents/Documents.ts8
-rw-r--r--src/client/util/CurrentUserUtils.ts17
-rw-r--r--src/client/views/DocumentDecorations.tsx32
-rw-r--r--src/client/views/MainView.tsx9
-rw-r--r--src/client/views/PropertiesView.tsx6
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/FilterBox.scss44
-rw-r--r--src/client/views/nodes/FilterBox.tsx197
-rw-r--r--src/client/views/nodes/WebBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts8
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
-rw-r--r--src/client/views/search/SearchBox.tsx9
-rw-r--r--src/fields/Doc.ts9
16 files changed, 321 insertions, 38 deletions
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 1bef6fa08..37a148e55 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -13,7 +13,8 @@ export enum DocumentType {
INK = "inks", // ink stroke
SCREENSHOT = "screenshot", // view of a desktop application
FONTICON = "fonticonbox", // font icon
- SEARCH = "search", // search query
+ FILTER = "filter",
+ SEARCH = "search", // search query
LABEL = "label", // simple text label
BUTTON = "button", // onClick button
WEBCAM = "webcam", // webcam
@@ -32,10 +33,10 @@ export enum DocumentType {
YOUTUBE = "youtube", // youtube directory (view of you tube search results)
DOCHOLDER = "docholder", // nested document (view of a document)
SEARCHITEM = "searchitem",
- COMPARISON = "comparison", // before/after view with slider (view of 2 images)
+ COMPARISON = "comparison", // before/after view with slider (view of 2 images)
GROUP = "group", // group of users
LINKDB = "linkdb", // database of links ??? why do we have this
- SCRIPTDB = "scriptdb", // database of scripts
+ SCRIPTDB = "scriptdb", // database of scripts
GROUPDB = "groupdb" // database of groups
} \ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index feb84843d..fbcecbec6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -50,6 +50,7 @@ import { PresElementBox } from "../views/presentationview/PresElementBox";
import { SearchBox } from "../views/search/SearchBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { DocumentType } from "./DocumentTypes";
+import { FilterBox } from "../views/nodes/FilterBox";
const path = require('path');
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
@@ -246,6 +247,10 @@ export namespace Docs {
layout: { view: SearchBox, dataField: defaultDataKey },
options: { _width: 400 }
}],
+ [DocumentType.FILTER, {
+ layout: { view: FilterBox, dataField: defaultDataKey },
+ options: { _width: 400 }
+ }],
[DocumentType.COLOR, {
layout: { view: ColorBox, dataField: defaultDataKey },
options: { _nativeWidth: 220, _nativeHeight: 300 }
@@ -821,6 +826,9 @@ export namespace Docs {
export function FontIconDocument(options?: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) });
}
+ export function FilterDocument(options?: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.FILTER), undefined, { ...(options || {}) });
+ }
export function PresElementBoxDocument(options?: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 734050b05..164c3ab67 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -516,6 +516,7 @@ export class CurrentUserUtils {
{ title: "Import", target: Cast(doc.myImportPanel, Doc, null), icon: "upload", click: 'selectMainMenu(self)' },
{ title: "Sharing", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc.mySharedDocs as Doc },
{ title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)' },
+ { title: "Filter", target: Cast(doc.myFilter, Doc, null), icon: "filter", click: 'selectMainMenu(self)' },
{ title: "Pres. Trails", target: Cast(doc.myPresentations, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' },
{ title: "Catalog", target: undefined as any, icon: "file", click: 'selectMainMenu(self)' },
{ title: "Help", target: undefined as any, icon: "question-circle", click: 'selectMainMenu(self)' },
@@ -775,6 +776,21 @@ export class CurrentUserUtils {
(doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List<string>(["Clear All"]);
}
}
+ static setupFilterDocs(doc: Doc) {
+ // setup Recently Closed library item
+ doc.myFilter === undefined;
+ if (doc.myFilter === undefined) {
+ doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({
+ title: "FilterDoc", _height: 500,
+ treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+ treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
+ }));
+ const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
+ (doc.myFilter as any as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
+ (doc.myFilter as any as Doc).contextMenuLabels = new List<string>(["Clear All"]);
+ }
+ }
static setupUserDoc(doc: Doc) {
@@ -806,6 +822,7 @@ export class CurrentUserUtils {
CurrentUserUtils.setupDashboards(doc);
CurrentUserUtils.setupPresentations(doc);
CurrentUserUtils.setupRecentlyClosedDocs(doc);
+ CurrentUserUtils.setupFilterDocs(doc);
CurrentUserUtils.setupUserDoc(doc);
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6951cb592..7781d6069 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from '@material-ui/core';
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, DataSym, Doc, Field } from "../../fields/Doc";
+import { AclAdmin, AclEdit, DataSym, Doc, Field, WidthSym, HeightSym } from "../../fields/Doc";
import { Document } from '../../fields/documentSchemas';
import { HtmlField } from '../../fields/HtmlField';
import { InkField } from "../../fields/InkField";
@@ -11,7 +11,7 @@ import { ScriptField } from '../../fields/ScriptField';
import { Cast, NumCast } from "../../fields/Types";
import { GetEffectiveAcl } from '../../fields/util';
import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from "../../Utils";
-import { DocUtils } from "../documents/Documents";
+import { DocUtils, Docs } from "../documents/Documents";
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from "../util/DragManager";
import { SelectionManager } from "../util/SelectionManager";
@@ -178,17 +178,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
@action
onMaximizeDown = (e: React.PointerEvent): void => {
- if (e.ctrlKey) {
- const selectedDocs = SelectionManager.SelectedDocuments();
- const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
- alias.context = undefined;
- //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]);
- CollectionDockingView.AddSplit(alias, "right");
- e.stopPropagation();
- e.preventDefault();
- } else {
- setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMaximizeClick);
- }
+ setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMaximizeClick);
}
@undoBatch
@action
@@ -196,7 +186,21 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (e.button === 0) {
const selectedDocs = SelectionManager.SelectedDocuments();
if (selectedDocs.length) {
- CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, "right");
+ if (e.ctrlKey) {
+ const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
+ alias.context = undefined;
+ //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]);
+ CollectionDockingView.AddSplit(alias, "right");
+ } else if (e.shiftKey) {
+ const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
+ alias.context = undefined;
+ alias.x = -alias[WidthSym]() / 2;
+ alias.y = -alias[HeightSym]() / 2;
+ //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]);
+ CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([alias], { title: "Tab for " + alias.title }), "right");
+ } else {
+ CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, "right");
+ }
}
}
SelectionManager.DeselectAll();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7c7c5b72b..e6e80d9fb 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -372,9 +372,9 @@ export class MainView extends React.Component {
@action
selectMenu = (button: Doc) => {
const title = StrCast(Doc.GetProto(button).title);
- const closed = !this._flyoutWidth;
+ const willOpen = !this._flyoutWidth || this._panelContent !== title;
this.closeFlyout();
- if (this._panelContent !== title || !this._flyoutWidth) {
+ if (willOpen) {
switch (this._panelContent = title) {
case "Settings":
SettingsManager.Instance.open();
@@ -384,7 +384,7 @@ export class MainView extends React.Component {
SearchBox.Instance.enter(undefined);
break;
default:
- closed && this.expandFlyout(button);
+ this.expandFlyout(button);
}
}
return true;
@@ -434,6 +434,7 @@ export class MainView extends React.Component {
this._lastButton && (this._lastButton.color = "white");
this._lastButton && (this._lastButton._backgroundColor = "");
this._panelContent = "none";
+ this._sidebarContent.proto = undefined;
this._flyoutWidth = 0;
});
@@ -520,7 +521,7 @@ export class MainView extends React.Component {
</defs>
</svg>;
}
- select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
+ select = (ctrlPressed: boolean) => { };
@computed get search() {
TraceMobx();
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 67c26c392..bb4657a2b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -243,10 +243,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return true;
} else if (value[0] === "#") {
const newVal = value + `:'${value}'`;
- KeyValueBox.SetField(doc, value, `'${value}'`, true);
+ doc[DataSym][value] = value;
const tags = StrCast(doc.tags, ":");
- if (!tags.includes(`#${value}:`)) {
- KeyValueBox.SetField(doc, "tags", `"${tags + value + ':'}"`, true);
+ if (!tags.includes(`${value}:`)) {
+ doc[DataSym].tags = `${tags + value + ':'}`;
}
return true;
}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 3c230537c..fb4f5c366 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -191,7 +191,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) {
this._isActive = this.props.glContainer.tab.isActive;
this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0);
- (CollectionDockingView.Instance as any)._goldenLayout.isInitialised && CollectionDockingView.Instance.stateChanged();
+ (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged();
!this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
}
}
@@ -334,7 +334,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
setView = action((view: DocumentView) => this._view = view);
@computed get docView() {
TraceMobx();
- return !this._document ? (null) :
+ return !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
<><DocumentView key={this._document[Id]}
LibraryPath={emptyPath}
Document={this._document}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 5d5a1f7f3..1b2070c0f 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -25,6 +25,7 @@ import { KeyValueBox } from "./KeyValueBox";
import { PDFBox } from "./PDFBox";
import { PresBox } from "./PresBox";
import { SearchBox } from "../search/SearchBox";
+import { FilterBox } from "./FilterBox";
import { ColorBox } from "./ColorBox";
import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
import { LinkAnchorBox } from "./LinkAnchorBox";
@@ -191,7 +192,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
components={{
FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
- PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox,
+ PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
ScreenshotBox, HTMLtag, ComparisonBox
}}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0182e652f..41e6d9603 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -300,7 +300,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
let stopPropagate = true;
let preventDefault = true;
!this.props.Document._isBackground && this.props.bringToFront(this.props.Document);
- if (this._doubleTap && this.props.renderDepth && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !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
+ if (this._doubleTap && ((this.props.renderDepth && this.props.Document.type !== DocumentType.FONTICON) || this.onDoubleClickHandler)) {// && !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
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = undefined;
diff --git a/src/client/views/nodes/FilterBox.scss b/src/client/views/nodes/FilterBox.scss
new file mode 100644
index 000000000..c5d6e2505
--- /dev/null
+++ b/src/client/views/nodes/FilterBox.scss
@@ -0,0 +1,44 @@
+
+
+ .collectionTimeView-treeView {
+ display: flex;
+ flex-direction: column;
+ width: 200px;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ border-left: solid 1px;
+ z-index: 1;
+
+ .collectionTimeView-addfacet {
+ display: inline-block;
+ width: 200px;
+ height: 30px;
+ background: darkGray;
+ text-align: left;
+
+ .collectionTimeView-button {
+ align-items: center;
+ display: flex;
+ width: 100%;
+ height: 100%;
+
+ .collectionTimeView-span {
+ margin: auto;
+ }
+ }
+
+ >div,
+ >div>div {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .collectionTimeView-tree {
+ display: inline-block;
+ width: 100%;
+ height: calc(100% - 30px);
+ }
+ } \ No newline at end of file
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
new file mode 100644
index 000000000..7bffc9184
--- /dev/null
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -0,0 +1,197 @@
+import React = require("react");
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import { ColorState, SketchPicker } from 'react-color';
+import { Doc, Opt, DocListCast, Field, DataSym } from "../../../fields/Doc";
+import { Utils, returnEmptyFilter, returnEmptyDoclist, returnZero, emptyPath, returnFalse, emptyFunction, returnOne } from "../../../Utils";
+import { documentSchema } from "../../../fields/documentSchemas";
+import { InkTool } from "../../../fields/InkField";
+import { makeInterface, listSpec } from "../../../fields/Schema";
+import { StrCast, Cast } from "../../../fields/Types";
+import { SelectionManager } from "../../util/SelectionManager";
+import { undoBatch } from "../../util/UndoManager";
+import { ViewBoxBaseComponent } from "../DocComponent";
+import "./ColorBox.scss";
+import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentType } from "../../documents/DocumentTypes";
+import { CollectionTreeView } from "../collections/CollectionTreeView";
+import { ScriptField, ComputedField } from "../../../fields/ScriptField";
+import { Docs } from "../../documents/Documents";
+import { RichTextField } from "../../../fields/RichTextField";
+import { List } from "../../../fields/List";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import './FilterBox.scss';
+import { CollectionDockingView } from "../collections/CollectionDockingView";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+type FilterBoxDocument = makeInterface<[typeof documentSchema]>;
+const FilterBoxDocument = makeInterface(documentSchema);
+
+@observer
+export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDocument>(FilterBoxDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterBox, fieldKey); }
+
+ @computed get _allFacets() {
+ return ["author", "creationDate", "type", "text", "context"];
+ // const noviceReqFields = ["author", "creationDate", "type", "text", "context"];
+ // const noviceLayoutFields: string[] = [];//["_curPage"];
+ // const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
+
+ // const facets = new Set<string>([...noviceReqFields, ...noviceLayoutFields]);
+ // this.childDocs.filter(child => child).forEach(child => child && Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
+ // Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.filter(child => child).forEach(child => Object.keys(child).forEach(key => facets.add(key)));
+
+ // return Array.from(facets).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_") && !key.startsWith("ACL")) || noviceFields.includes(key)).sort();
+ }
+ /**
+ * Responds to clicking the check box in the flyout menu
+ */
+ facetClick = (facetHeader: string) => {
+ const targetDoc = CollectionDockingView.Instance.props.Document;
+ const found = DocListCast(this.dataDoc[this.props.fieldKey]).findIndex(doc => doc.title === facetHeader);
+ if (found !== -1) {
+ (this.dataDoc[this.props.fieldKey] as List<Doc>).splice(found, 1);
+ const docFilter = Cast(targetDoc._docFilters, listSpec("string"));
+ if (docFilter) {
+ let index: number;
+ while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) {
+ docFilter.splice(index, 3);
+ }
+ }
+ const docRangeFilters = Cast(targetDoc._docRangeFilters, listSpec("string"));
+ if (docRangeFilters) {
+ let index: number;
+ while ((index = docRangeFilters.findIndex(item => item === facetHeader)) !== -1) {
+ docRangeFilters.splice(index, 3);
+ }
+ }
+ } else {
+ const allCollectionDocs = DocListCast((targetDoc.data as any)[0].data);
+ var rtfields = 0;
+ const facetValues = Array.from(allCollectionDocs.reduce((set, child) => {
+ const field = child[facetHeader] as Field;
+ const fieldStr = Field.toString(field);
+ if (field instanceof RichTextField || (typeof (field) === "string" && fieldStr.split(" ").length > 2)) rtfields++;
+ return set.add(fieldStr);
+ }, new Set<string>()));
+
+ let nonNumbers = 0;
+ let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
+ facetValues.map(val => {
+ const num = Number(val);
+ if (Number.isNaN(num)) {
+ nonNumbers++;
+ } else {
+ minVal = Math.min(num, minVal);
+ maxVal = Math.max(num, maxVal);
+ }
+ });
+ let newFacet: Opt<Doc>;
+ if (facetHeader === "text" || rtfields / allCollectionDocs.length > 0.1) {
+ newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
+ Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
+ newFacet._textBoxPadding = 4;
+ const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`;
+ newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
+ } else if (nonNumbers / facetValues.length < .1) {
+ newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true });
+ const newFacetField = Doc.LayoutFieldKey(newFacet);
+ const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader);
+ Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
+ const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05);
+ const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05);
+ newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0];
+ newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1];
+ Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal;
+ Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal;
+ const scriptText = `setDocFilterRange(this?.target, "${facetHeader}", range)`;
+ newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" });
+ } else {
+ newFacet = new Doc();
+ newFacet.sytem = true;
+ newFacet.title = facetHeader;
+ newFacet.treeViewOpen = true;
+ newFacet.type = DocumentType.COL;
+ const capturedVariables = { layoutDoc: targetDoc, dataDoc: (targetDoc.data as any)[0][DataSym] };
+ newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables);
+ }
+ newFacet && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, newFacet);
+ }
+ }
+ filterBackground = () => "rgba(105, 105, 105, 0.432)";
+ get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
+ @computed get scriptField() {
+ const scriptText = "setDocFilter(this?.target, heading, this.title, checked)";
+ const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+ return script ? () => script : undefined;
+ }
+
+ @computed get filterView() {
+ const facetCollection = this.props.Document.proto as Doc;
+ const flyout = (
+ <div className="collectionTimeView-flyout" style={{ width: `100%`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
+ {this._allFacets.map(facet => <label className="collectionTimeView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}>
+ <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey]).some(d => d.title === facet)} />
+ <span className="checkmark" />
+ {facet}
+ </label>)}
+ </div>
+ );
+
+ return this.props.dontRegisterView ? (null) : <div className="collectionTimeView-treeView" style={{ width: "100%" }}>
+ <div className="collectionTimeView-addFacet" style={{ width: "100%" }} onPointerDown={e => e.stopPropagation()}>
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
+ <div className="collectionTimeView-button">
+ <FontAwesomeIcon icon={"edit"} size={"lg"} />
+ <span className="collectionTimeView-span">Facet Filters</span>
+ </div>
+ </Flyout>
+ </div>
+ <div className="collectionTimeView-tree" key="tree">
+ <CollectionTreeView
+ PanelPosition={""}
+ Document={facetCollection}
+ DataDoc={Doc.GetProto(facetCollection)}
+ fieldKey={`${this.props.fieldKey}`}
+ CollectionView={undefined}
+ docFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ PanelWidth={this.props.PanelWidth}
+ PanelHeight={this.props.PanelHeight}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ LibraryPath={emptyPath}
+ rootSelected={this.props.rootSelected}
+ renderDepth={1}
+ dropAction={this.props.dropAction}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ isSelected={returnFalse}
+ select={returnFalse}
+ bringToFront={emptyFunction}
+ active={this.props.active}
+ whenActiveChanged={returnFalse}
+ treeViewHideTitle={true}
+ ContentScaling={returnOne}
+ focus={returnFalse}
+ treeViewHideHeaderFields={true}
+ onCheckedClick={this.scriptField}
+ ignoreFields={this.ignoreFields}
+ annotationsKey={""}
+ dontRegisterView={true}
+ backgroundColor={this.filterBackground}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ addDocument={returnFalse} />
+ </div>
+ </div>;
+ }
+ render() {
+ return this.filterView;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 4dded50b0..f9e6227d7 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -495,7 +495,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
Doc.GetProto(targetDoc).data = new List<Doc>([clipDoc]);
clipDoc.rootDocument = targetDoc;
targetDoc.layoutKey = "layout";
- const annotationDoc = this.highlight("rgba(173, 216, 230, 0.3)"); // hyperlink color
+ const annotationDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 3fadfe842..5c0505909 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -3,7 +3,7 @@ import { NodeSelection, TextSelection } from "prosemirror-state";
import { DataSym, Doc } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { ComputedField } from "../../../../fields/ScriptField";
-import { Cast, NumCast } from "../../../../fields/Types";
+import { Cast, NumCast, StrCast } from "../../../../fields/Types";
import { returnFalse, Utils } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -321,7 +321,11 @@ export class RichTextRules {
(state, match, start, end) => {
const tag = match[1];
if (!tag) return state.tr;
- this.Document[DataSym]["#" + tag] = ".";
+ this.Document[DataSym]["#" + tag] = "#" + tag;
+ const tags = StrCast(this.Document.tags, ":");
+ if (!tags.includes(`#${tag}:`)) {
+ this.Document[DataSym].tags = `"${tags + "#" + tag + ':'}"`;
+ }
const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" + tag });
return state.tr.deleteRange(start, end).insert(start, fieldView);
}),
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index bd9723fc2..0a52f6ad5 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -601,7 +601,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
// Doc.GetProto(targetDoc).snipped = this.dataDoc[this.props.fieldKey][Copy]();
// const snipLayout = Docs.Create.PdfDocument("http://www.msn.com", { title: "snippetView", isTemplateDoc: true, isTemplateForField: "snipped", _fitWidth: true, _width: this.marqueeWidth(), _height: this.marqueeHeight(), _scrollTop: this.marqueeY() });
// Doc.GetProto(snipLayout).layout = PDFBox.LayoutString("snipped");
- const annotationDoc = this.highlight("rgba(173, 216, 230, 0.3)"); // hyperlink color
+ const annotationDoc = this.highlight("rgba(173, 216, 230, 0.75)"); // hyperlink color
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 3d564f073..3907d2d5c 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -45,7 +45,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
private _maxSearchIndex: number = 0;
private _curRequest?: Promise<any> = undefined;
private _disposers: { [name: string]: IReactionDisposer } = {};
- private _blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.DOCHOLDER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+ private _blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.DOCHOLDER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
private docsforfilter: Doc[] | undefined = [];
private realTotalResults: number = 0;
@@ -192,8 +192,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
while (docs.length > 0) {
newarray = [];
- docs.forEach((d) => {
- d.data && newarray.push(...DocListCast(d.data));
+ docs.forEach(d => {
+ const fieldKey = Doc.LayoutFieldKey(d);
+ const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
+ const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+ data && newarray.push(...DocListCast(data));
const hlights = new Set<string>();
this.documentKeys(d).forEach(key =>
Field.toString(d[key] as Field).toLowerCase().includes(query) && hlights.add(key));
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index bc31c1a21..08d949b5e 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -23,6 +23,7 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u
import { LinkManager } from "../client/util/LinkManager";
import JSZip = require("jszip");
import { saveAs } from "file-saver";
+import { CollectionDockingView } from "../client/views/collections/CollectionDockingView";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -1048,7 +1049,8 @@ export namespace Doc {
doc.layoutKey = deiconify || "layout";
}
export function setDocFilterRange(target: Doc, key: string, range?: number[]) {
- const docRangeFilters = Cast(target._docRangeFilters, listSpec("string"), []);
+ const container = target ?? CollectionDockingView.Instance.props.Document;
+ const docRangeFilters = Cast(container._docRangeFilters, listSpec("string"), []);
for (let i = 0; i < docRangeFilters.length; i += 3) {
if (docRangeFilters[i] === key) {
docRangeFilters.splice(i, 3);
@@ -1059,14 +1061,15 @@ export namespace Doc {
docRangeFilters.push(key);
docRangeFilters.push(range[0].toString());
docRangeFilters.push(range[1].toString());
- target._docRangeFilters = new List<string>(docRangeFilters);
+ container._docRangeFilters = new List<string>(docRangeFilters);
}
}
// filters document in a container collection:
// all documents with the specified value for the specified key are included/excluded
// based on the modifiers :"check", "x", undefined
- export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "remove" | "match" | "check" | "x" | undefined) {
+ export function setDocFilter(target: Opt<Doc>, key: string, value: any, modifiers?: "remove" | "match" | "check" | "x" | undefined) {
+ const container = target ?? CollectionDockingView.Instance.props.Document;
const docFilters = Cast(container._docFilters, listSpec("string"), []);
runInAction(() => {
for (let i = 0; i < docFilters.length; i += 3) {