aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-06-30 01:08:45 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-06-30 01:08:45 -0400
commit6a75dac53b9fab5b96f2cce4937b59f1e29928f9 (patch)
treed3da9eca5549bd4d40590fbc6e9f143996c14463 /src
parent6219da84de5c5a1d1efccdfc2d54da95612b1d35 (diff)
added a docFilter for a substring match. fixed formattedTextBox to not keep adding user_mark storedMarks on every load
Diffstat (limited to 'src')
-rw-r--r--src/client/util/SearchUtil.ts2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx13
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx4
-rw-r--r--src/client/views/collections/CollectionView.tsx26
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx9
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts1
-rw-r--r--src/fields/Doc.ts33
7 files changed, 57 insertions, 31 deletions
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 5679c0a14..1ac68480e 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -74,7 +74,7 @@ export namespace SearchUtil {
const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc);
for (let i = 0; i < ids.length; i++) {
const testDoc = docs[i];
- if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowAliases || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
+ if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowAliases || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
theDocs.push(testDoc);
theLines.push([]);
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 29144abaf..b76859d90 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -7,7 +7,7 @@ import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
import { WebField } from "../../../fields/URLField";
-import { Cast, ScriptCast, NumCast } from "../../../fields/Types";
+import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
import { Upload } from "../../../server/SharedMediaTypes";
import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
@@ -136,8 +136,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const filteredDocs = docFilters.length && !this.props.dontRegisterView ? childDocs.filter(d => {
for (const facetKey of Object.keys(filterFacets)) {
const facet = filterFacets[facetKey];
- const satisfiesFacet = Object.keys(facet).some(value =>
- (facet[value] === "x") !== Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesFacet = Object.keys(facet).some(value => {
+ if (facet[value] === "match") {
+ return d[facetKey] === undefined || Cast(d[facetKey], RichTextField)?.Text.includes(value);
+ }
+ return (facet[value] === "x") !== Doc.matchFieldValue(d, facetKey, value);
+ });
if (!satisfiesFacet) {
return false;
}
@@ -471,4 +475,5 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { DocumentType } from "../../documents/DocumentTypes";
import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox";
import { CollectionView } from "./CollectionView";
-import { SelectionManager } from "../../util/SelectionManager";
+import { SelectionManager } from "../../util/SelectionManager"; import { RichTextField } from "../../../fields/RichTextField";
+
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f6f6fb7cc..c1569a172 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -386,8 +386,8 @@ class TreeView extends React.Component<TreeViewProps> {
e.stopPropagation();
}
- @computed
- get renderBullet() {
+ @computed get renderBullet() {
+ TraceMobx();
const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
return <div className="bullet"
title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f2ffe7835..c7b1afbd6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -47,6 +47,7 @@ import { CollectionGridView } from './collectionGrid/CollectionGridView';
import './CollectionView.scss';
import { CollectionViewBaseChrome } from './CollectionViewChromes';
import { UndoManager } from '../../util/UndoManager';
+import { RichTextField } from '../../../fields/RichTextField';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -357,8 +358,9 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
}
@computed get _allFacets() {
+ TraceMobx();
const facets = new Set<string>();
- this.childDocs.filter(child => child).forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
+ 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(f => !f.startsWith("_") && !["proto", "zIndex", "isPrototype", "context", "text-noTemplate"].includes(f)).sort();
}
@@ -387,8 +389,12 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
}
} else {
const allCollectionDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
- const facetValues = Array.from(allCollectionDocs.reduce((set, child) =>
- set.add(Field.toString(child[facetHeader] as Field)), new Set<string>()));
+ var rtfields = 0;
+ const facetValues = Array.from(allCollectionDocs.reduce((set, child) => {
+ const field = child[facetHeader] as Field;
+ if (field instanceof RichTextField) rtfields++;
+ return set.add(Field.toString(field));
+ }, new Set<string>()));
let nonNumbers = 0;
let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
@@ -402,13 +408,17 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
}
});
let newFacet: Opt<Doc>;
- if (nonNumbers / allCollectionDocs.length < .1) {
- newFacet = Docs.Create.SliderDocument({ title: facetHeader });
+ if (rtfields / allCollectionDocs.length > 0.1) {
+ newFacet = Docs.Create.TextDocument("", { _width: 200, _height: 30, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
+ Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
+ newFacet.target = this.props.Document;
+ const scriptText = `setDocFilter(this.target, "${facetHeader}", text, "match")`;
+ newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
+ } else if (nonNumbers / allCollectionDocs.length < .1) {
+ newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true });
const newFacetField = Doc.LayoutFieldKey(newFacet);
const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader);
Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
- newFacet.treeViewExpandedView = "layout";
- newFacet.treeViewOpen = true;
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];
@@ -418,7 +428,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
newFacet.target = this.props.Document;
const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`;
newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" });
-
Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
} else {
newFacet = new Doc();
@@ -445,6 +454,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
}
@computed get filterView() {
+ TraceMobx();
const facetCollection = this.props.Document;
const flyout = (
<div className="collectionTimeView-flyout" style={{ width: `${this.facetWidth()}`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 90f379525..222a359d1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -22,7 +22,7 @@ import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from "../../../../fields/RichTextField";
import { RichTextUtils } from '../../../../fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../../fields/Schema";
-import { Cast, DateCast, NumCast, StrCast } from "../../../../fields/Types";
+import { Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../fields/Types";
import { TraceMobx, OVERRIDE_ACL } from '../../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
@@ -203,13 +203,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (!this.dataDoc[AclSym]) {
if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
this._applyingChange = true;
- this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
if (json !== curLayout?.Data) {
!curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
!curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily));
this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
+ ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
}
} else { // if we've deleted all the text in a note driven by a template, then restore the template data
this.dataDoc[this.props.fieldKey] = undefined;
@@ -970,7 +971,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
(selectOnLoad /* || !rtfField?.Text*/) && this._editorView!.focus();
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
- this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
+ if (!this._editorView!.state.storedMarks || !this._editorView!.state.storedMarks.some(mark => mark.type === schema.marks.user_mark)) {
+ this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
+ }
}
getFont(font: string) {
switch (font) {
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index b09ac0678..54b61aa20 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -270,6 +270,7 @@ export const marks: { [index: string]: MarkSpec } = {
userid: { default: "" },
modified: { default: "when?" }, // 1 second intervals since 1970
},
+ excludes: "user_mark",
group: "inline",
toDOM(node: any) {
const uid = node.attrs.userid.replace(".", "").replace("@", "");
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index bef8acb06..e4d11dd4d 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -945,20 +945,27 @@ export namespace Doc {
// 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?: "check" | "x" | undefined) {
+ export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "match" | "check" | "x" | undefined) {
const docFilters = Cast(container._docFilters, listSpec("string"), []);
- for (let i = 0; i < docFilters.length; i += 3) {
- if (docFilters[i] === key && docFilters[i + 1] === value) {
- docFilters.splice(i, 3);
- break;
+ runInAction(() => {
+ for (let i = 0; i < docFilters.length; i += 3) {
+ if (docFilters[i] === key && (docFilters[i + 1] === value || modifiers === "match")) {
+ if (docFilters[i + 2] === modifiers && modifiers && docFilters[i + 1] === value) return;
+ docFilters.splice(i, 3);
+ break;
+ }
}
- }
- if (typeof modifiers === "string") {
- docFilters.push(key);
- docFilters.push(value);
- docFilters.push(modifiers);
- container._docFilters = new List<string>(docFilters);
- }
+ if (typeof modifiers === "string") {
+ if (!docFilters.length && modifiers === "match" && value === undefined) {
+ container._docFilters = undefined;
+ } else {
+ docFilters.push(key);
+ docFilters.push(value);
+ docFilters.push(modifiers);
+ container._docFilters = new List<string>(docFilters);
+ }
+ }
+ })
}
export function readDocRangeFilter(doc: Doc, key: string) {
const docRangeFilters = Cast(doc._docRangeFilters, listSpec("string"), []);
@@ -1168,5 +1175,5 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo
(!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null)));
return docs.length ? new List(docs) : prevValue;
});
-Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); });
+Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "match" | "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); });
Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file