aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts28
-rw-r--r--src/client/views/FilterPanel.tsx15
-rw-r--r--src/client/views/InkTangentHandles.tsx1
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx6
-rw-r--r--src/fields/Doc.ts25
5 files changed, 37 insertions, 38 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 055950e6f..254be67b9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } fro
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField, YoutubeField } from '../../fields/URLField';
import { inheritParentAcls, SharingPermissions } from '../../fields/util';
import { Upload } from '../../server/SharedMediaTypes';
-import { aggregateBounds, OmitKeys, Utils } from '../../Utils';
+import { OmitKeys, Utils } from '../../Utils';
import { YoutubeBox } from '../apis/youtube/YoutubeBox';
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
@@ -1296,20 +1296,6 @@ export namespace DocUtils {
for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragsDocFilter.split(Doc.FilterSep)[0])) {
const facet = filterFacets[facetKey];
- let links = true;
- const linkedTo = filterFacets['-linkedTo'] && Array.from(Object.keys(filterFacets['-linkedTo']))?.[0];
- const linkedToField = filterFacets['-linkedTo']?.[linkedTo];
- const allLinks = linkedTo && linkedToField ? LinkManager.Instance.getAllRelatedLinks(d) : [];
- // prettier-ignore
- if (linkedTo) {
- if (allLinks.some(d => linkedTo === Field.toScriptString(DocCast(DocCast(d.link_anchor_1)?.[linkedToField]))) || //
- allLinks.some(d => linkedTo === Field.toScriptString(DocCast(DocCast(d.link_anchor_2)?.[linkedToField]))))
- {
- links = true;
- }
- else links = false
- }
-
// facets that match some value in the field of the document (e.g. some text field)
const matches = Object.keys(facet).filter(value => value !== 'cookies' && facet[value] === 'match');
@@ -1319,16 +1305,16 @@ export namespace DocUtils {
// metadata facets that exist
const exists = Object.keys(facet).filter(value => facet[value] === 'exists');
- // metadata facets that exist
+ // facets that unset metadata (a hack for making cookies work)
const unsets = Object.keys(facet).filter(value => facet[value] === 'unset');
- // facets that have an x next to them
+ // facets that specify that a field must not match a specific value
const xs = Object.keys(facet).filter(value => facet[value] === 'x');
- if (!linkedTo && !unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true;
+ if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true;
const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value));
const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
- const satisfiesExistsFacets = !exists.length ? true : exists.some(value => d[facetKey] !== undefined);
+ const satisfiesExistsFacets = !exists.length ? true : exists.some(value => (facetKey !== '-linkedTo' ? d[facetKey] !== undefined : LinkManager.Instance.getAllRelatedLinks(d).length));
const satisfiesUnsetsFacets = !unsets.length ? true : unsets.some(value => d[facetKey] === undefined);
const satisfiesMatchFacets = !matches.length
? true
@@ -1344,11 +1330,11 @@ export namespace DocUtils {
});
// if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
if (parentCollection?.childFilters_boolean === 'OR') {
- if (links && satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
+ if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
}
// if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
else {
- if (!links || !satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
+ if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
}
}
return parentCollection?.childFilters_boolean === 'OR' ? false : true;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 4af29c70e..312dc3a70 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -56,7 +56,7 @@ export class FilterPanel extends React.Component<filterProps> {
@computed get _allFacets() {
// trace();
- const noviceReqFields = ['author', 'tags', 'text', 'type'];
+ const noviceReqFields = ['author', 'tags', 'text', 'type', '-linkedTo'];
const noviceLayoutFields: string[] = []; //["_layout_curPage"];
const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
@@ -118,7 +118,7 @@ export class FilterPanel extends React.Component<filterProps> {
// }
gatherFieldValues(childDocs: Doc[], facetKey: string) {
- const valueSet = new Set<string>();
+ const valueSet = new Set<string>(StrListCast(this.props.rootDoc.childFilters).map(filter => filter.split(Doc.FilterSep)[1]));
let rtFields = 0;
let subDocs = childDocs;
if (subDocs.length > 0) {
@@ -127,7 +127,6 @@ export class FilterPanel extends React.Component<filterProps> {
newarray = [];
subDocs.forEach(t => {
const facetVal = t[facetKey];
- // console.log("facetVal " + facetVal)
if (facetVal instanceof RichTextField || typeof facetVal === 'string') rtFields++;
facetVal !== undefined && valueSet.add(Field.toString(facetVal as Field));
(facetVal === true || facetVal == false) && valueSet.add(Field.toString(!facetVal));
@@ -182,14 +181,14 @@ export class FilterPanel extends React.Component<filterProps> {
});
if (facetHeader === 'text') {
- return { facetHeader: facetHeader, renderType: 'text' };
+ return { facetHeader, renderType: 'text' };
} else if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) {
const extendedMinVal = minVal - Math.min(1, Math.floor(Math.abs(maxVal - minVal) * 0.1));
const extendedMaxVal = Math.max(minVal + 1, maxVal + Math.min(1, Math.ceil(Math.abs(maxVal - minVal) * 0.05)));
const ranged = Doc.readDocRangeFilter(this.targetDoc, facetHeader); // not the filter range, but the zooomed in range on the filter
- return { facetHeader: facetHeader, renderType: 'range', domain: [extendedMinVal, extendedMaxVal], range: ranged ? ranged : [extendedMinVal, extendedMaxVal] };
+ return { facetHeader, renderType: 'range', domain: [extendedMinVal, extendedMaxVal], range: ranged ? ranged : [extendedMinVal, extendedMaxVal] };
} else {
- return { facetHeader: facetHeader, renderType: 'checkbox' };
+ return { facetHeader, renderType: 'checkbox' };
}
})
);
@@ -236,7 +235,7 @@ export class FilterPanel extends React.Component<filterProps> {
facetValues = (facetHeader: string) => {
const allCollectionDocs = new Set<Doc>();
SearchUtil.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
- const set = new Set<string>([String.fromCharCode(127) + '--undefined--', Doc.FilterAny]);
+ const set = new Set<string>([...StrListCast(this.props.rootDoc.childFilters).map(filter => filter.split(Doc.FilterSep)[1]), Doc.FilterNone, Doc.FilterAny]);
if (facetHeader === 'tags')
allCollectionDocs.forEach(child =>
StrListCast(child[facetHeader])
@@ -404,7 +403,7 @@ export class FilterPanel extends React.Component<filterProps> {
?.split(Doc.FilterSep)[2] ?? ''
)}
type={type}
- onChange={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, fval, e.target.checked ? (fval === Doc.FilterAny ? 'exists' : 'check') : 'remove'), 'set filter')}
+ onChange={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, fval, e.target.checked ? 'check' : 'remove'), 'set filter')}
/>
{facetValue}
</div>
diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx
index 71e0ff63c..65f6a6dfa 100644
--- a/src/client/views/InkTangentHandles.tsx
+++ b/src/client/views/InkTangentHandles.tsx
@@ -12,7 +12,6 @@ import { UndoManager } from '../util/UndoManager';
import { Colors } from './global/globalEnums';
import { InkingStroke } from './InkingStroke';
import { InkStrokeProperties } from './InkStrokeProperties';
-import { DocumentView } from './nodes/DocumentView';
export interface InkHandlesProps {
inkDoc: Doc;
inkView: InkingStroke;
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 3e22c0d0e..d7469e530 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -350,7 +350,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// Removes filter
Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
- Doc.setDocFilter(this.rootDoc, '-linkedTo', Field.toString(DocCast(this.selectedPin.mapPin)), 'removeAll');
+ Doc.setDocFilter(this.rootDoc, '-linkedTo', `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
const temp = this.selectedPin;
if (!this._unmounting) {
@@ -382,7 +382,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
// Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
- Doc.setDocFilter(this.rootDoc, '-linkedTo', Field.toScriptString(this.selectedPin), 'mapPin' as any);
+ Doc.setDocFilter(this.rootDoc, '-linkedTo', `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
this.recolorPin(this.selectedPin, 'green');
@@ -516,7 +516,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// Removes filter
Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
- Doc.setDocFilter(this.rootDoc, '-linkedTo', Field.toString(DocCast(this.selectedPin.mapPin)), 'removeAll');
+ Doc.setDocFilter(this.rootDoc, '-linkedTo', `mapPin=${Field.toString(DocCast(this.selectedPin.mapPin))}`, 'remove');
this.removePushpin(this.selectedPin);
}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5af49629d..78a03d782 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1463,18 +1463,32 @@ export namespace Doc {
const isTransparent = (color: string) => color !== '' && DashColor(color).alpha() !== 1;
return isTransparent(StrCast(doc[key]));
}
+ if (key === '-linkedTo') {
+ // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
+ const allLinks = LinkManager.Instance.getAllRelatedLinks(doc);
+ const matchLink = (value: string, anchor: Doc) => {
+ const linkedToExp = value?.split('=');
+ if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value;
+ return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1];
+ };
+ // prettier-ignore
+ return (value === Doc.FilterNone && !allLinks.length) ||
+ (value === Doc.FilterAny && !!allLinks.length) ||
+ (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) ||
+ matchLink(value,DocCast(link.link_anchor_2)) ));
+ }
if (typeof value === 'string') {
value = value.replace(`,${Utils.noRecursionHack}`, '');
}
const fieldVal = doc[key];
if (Cast(fieldVal, listSpec('string'), []).length) {
- const vals = Cast(fieldVal, listSpec('string'), []);
+ const vals = StrListCast(fieldVal);
const docs = vals.some(v => (v as any) instanceof Doc);
if (docs) return value === Field.toString(fieldVal as Field);
return vals.some(v => v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
const fieldStr = Field.toString(fieldVal as Field);
- return fieldStr.includes(value) || (value === String.fromCharCode(127) + '--undefined--' && fieldVal === undefined); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ return fieldStr.includes(value) || (value === Doc.FilterAny && fieldVal !== undefined) || (value === Doc.FilterNone && fieldVal === undefined); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
export function deiconifyView(doc: Doc) {
@@ -1520,18 +1534,19 @@ export namespace Doc {
export const FilterSep = '::';
export const FilterAny = '--any--';
+ export const FilterNone = '--undefined--';
// 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: Opt<Doc>, key: string, value: any, modifiers: 'removeAll' | 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
+ export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
if (!container) return;
const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters';
const childFilters = StrListCast(container[filterField]);
runInAction(() => {
for (let i = 0; i < childFilters.length; i++) {
const fields = childFilters[i].split(FilterSep); // split key:value:modifier
- if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || modifiers === 'removeAll' || (fields[2] === 'match' && modifiers === 'remove'))) {
+ if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) {
if (toggle) modifiers = 'remove';
else return;
@@ -1543,7 +1558,7 @@ export namespace Doc {
}
if (!childFilters.length && modifiers === 'match' && value === undefined) {
container[filterField] = undefined;
- } else if (modifiers !== 'remove' && modifiers !== 'removeAll') {
+ } else if (modifiers !== 'remove') {
!append && (childFilters.length = 0);
childFilters.push(key + FilterSep + value + FilterSep + modifiers);
container[filterField] = new List<string>(childFilters);