From 7350e420087f89364e71b4431e3a3130d4d00c69 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Tue, 12 Oct 2021 06:39:37 +0100 Subject: [PATCH 1/7] add options in the refining AND selector to deal with the possibility that aggregations and filters use different values for the same thing, and enable translation between them. Use case: boolean fields are listed in aggregations with the keys and , but in filters booleans must be represented as and --- src/components/selectors.js | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/selectors.js b/src/components/selectors.js index 0608461..2111a4f 100644 --- a/src/components/selectors.js +++ b/src/components/selectors.js @@ -31,6 +31,15 @@ $.extend(edges, { this.valueMap = params.valueMap || false; this.valueFunction = params.valueFunction || false; + // function to parse the value selected (which will be a string) into whatever + // datatype the filter requires + this.parseSelectedValueString = edges.getParam(params.parseSelectedValueString, false); + + // function to convert the filter value to the same type as the aggregation value, if they + // differ (e.g. if the filter is `true` but the agg value is `1` this function can convert + // between them. + this.filterToAggValue = edges.getParam(params.filterToAggValue, false); + // due to a limitation in elasticsearch's clustered node facet counts, we need to inflate // the number of facet results we need to ensure that the results we actually want are // accurate. This option tells us by how much. @@ -99,8 +108,12 @@ $.extend(edges, { var filters = this.edge.currentQuery.listMust(es.newTermFilter({field: this.field})); for (var i = 0; i < filters.length; i++) { var val = filters[i].value; + if (this.filterToAggValue) { + val = this.filterToAggValue(val); + } + let term = val; val = this._translate(val); - this.filters.push({display: val, term: filters[i].value}); + this.filters.push({display: val, term: term}); } }; @@ -138,7 +151,11 @@ $.extend(edges, { var exclude = false; for (var j = 0; j < predefined.length; j++) { var f = predefined[j]; - if (bucket.key === f.value) { + let filterValue = f.value; + if (this.filterToAggValue) { + filterValue = this.filterToAggValue(f.value) + } + if (bucket.key === filterValue) { exclude = true; break; } @@ -217,6 +234,10 @@ $.extend(edges, { // functions that can be called on this component to change its state this.selectTerm = function(term) { + if (this.parseSelectedValueString) { + term = this.parseSelectedValueString(term); + } + var nq = this.edge.cloneQuery(); // first make sure we're not double-selecting a term @@ -246,6 +267,10 @@ $.extend(edges, { }; this.removeFilter = function(term) { + if (this.parseSelectedValueString) { + term = this.parseSelectedValueString(term); + } + var nq = this.edge.cloneQuery(); nq.removeMust(es.newTermFilter({ From 42ebaf6f3cc59ba0dfb6f288bdab786d2025fe5d Mon Sep 17 00:00:00 2001 From: Aga Date: Fri, 16 Jun 2023 12:04:53 +0100 Subject: [PATCH 2/7] make sure selected filter renderer removes the filter correctly even after the conversion to string --- src/renderers/bs3.SelectedFiltersRenderer.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/renderers/bs3.SelectedFiltersRenderer.js b/src/renderers/bs3.SelectedFiltersRenderer.js index 662a6c7..0ee927a 100644 --- a/src/renderers/bs3.SelectedFiltersRenderer.js +++ b/src/renderers/bs3.SelectedFiltersRenderer.js @@ -107,6 +107,7 @@ $.extend(true, edges, { // event handlers this.removeFilter = function (element) { + var sf = this.component; var el = this.component.jq(element); var field = el.attr("data-field"); var ft = el.attr("data-filter"); @@ -114,7 +115,12 @@ $.extend(true, edges, { var value = false; if (ft === "terms" || ft === "term") { - value = el.attr("data-value"); + // value = el.attr("data-value"); + values = sf.mustFilters[field].values; + // sanity check, values length needs to be 1 due to the nature of the terms filter + if(values.length == 1){ + value = values[0].val; + } } else if (ft === "range") { value = {}; From 990f4220163a3e18880f0bdc3ad5c80d234d22dd Mon Sep 17 00:00:00 2001 From: Aga Date: Wed, 28 Jun 2023 12:57:23 +0100 Subject: [PATCH 3/7] selected filters rendeder value fix --- src/renderers/bs3.SelectedFiltersRenderer.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/renderers/bs3.SelectedFiltersRenderer.js b/src/renderers/bs3.SelectedFiltersRenderer.js index 0ee927a..7fe39cd 100644 --- a/src/renderers/bs3.SelectedFiltersRenderer.js +++ b/src/renderers/bs3.SelectedFiltersRenderer.js @@ -65,7 +65,7 @@ $.extend(true, edges, { if (this.allowRemove) { var removeClass = edges.css_classes(ns, "remove", this); if (def.filter == "term" || def.filter === "terms") { - filters += ''; + filters += ''; filters += ''; filters += ""; } else if (def.filter === "range") { @@ -117,10 +117,8 @@ $.extend(true, edges, { if (ft === "terms" || ft === "term") { // value = el.attr("data-value"); values = sf.mustFilters[field].values; - // sanity check, values length needs to be 1 due to the nature of the terms filter - if(values.length == 1){ - value = values[0].val; - } + idx = el.attr("data-value-idx") + value = values[idx].val } else if (ft === "range") { value = {}; From 5b74a457128d66588b32c58848891dee38f64765 Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 12 Sep 2024 11:07:11 +0100 Subject: [PATCH 4/7] changes to edges --- src/components/selectors.js | 678 ++++++++++++++++++++++++++++-------- src/edges.js | 351 +++++++++++-------- 2 files changed, 727 insertions(+), 302 deletions(-) diff --git a/src/components/selectors.js b/src/components/selectors.js index 2111a4f..76d9784 100644 --- a/src/components/selectors.js +++ b/src/components/selectors.js @@ -3,10 +3,10 @@ $.extend(edges, { // Selector implementations - newRefiningANDTermSelector : function(params) { + newRefiningANDTermSelector: function (params) { return edges.instantiate(edges.RefiningANDTermSelector, params, edges.newSelector); }, - RefiningANDTermSelector : function(params) { + RefiningANDTermSelector: function (params) { //////////////////////////////////////////// // configurations to be passed in @@ -69,7 +69,7 @@ $.extend(edges, { ////////////////////////////////////////// // overrides on the parent object's standard functions - this.init = function(edge) { + this.init = function (edge) { // first kick the request up to the superclass edges.up(this, "init", [edge]); @@ -78,7 +78,7 @@ $.extend(edges, { } }; - this.contrib = function(query) { + this.contrib = function (query) { var params = { name: this.id, field: this.field, @@ -93,7 +93,7 @@ $.extend(edges, { ); }; - this.synchronise = function() { + this.synchronise = function () { // reset the state of the internal variables if (this.lifecycle === "update") { // if we are in the "update" lifecycle, then reset and read all the values @@ -117,7 +117,7 @@ $.extend(edges, { } }; - this._readValues = function(params) { + this._readValues = function (params) { var result = params.result; // assign the terms and counts from the aggregation @@ -187,7 +187,7 @@ $.extend(edges, { ///////////////////////////////////////////////// // query handlers for getting the full list of terms to display - this.listAll = function() { + this.listAll = function () { // to list all possible terms, build off the base query var bq = this.edge.cloneBaseQuery(); bq.clearAggregations(); @@ -214,7 +214,7 @@ $.extend(edges, { }); }; - this.listAllQuerySuccess = function(params) { + this.listAllQuerySuccess = function (params) { var result = params.result; // set the values according to what comes back @@ -225,7 +225,7 @@ $.extend(edges, { this.draw(); }; - this.listAllQueryFail = function() { + this.listAllQueryFail = function () { this.values = []; console.log("RefiningANDTermSelector asynchronous query failed"); }; @@ -233,7 +233,7 @@ $.extend(edges, { ////////////////////////////////////////// // functions that can be called on this component to change its state - this.selectTerm = function(term) { + this.selectTerm = function (term) { if (this.parseSelectedValueString) { term = this.parseSelectedValueString(term); } @@ -266,7 +266,7 @@ $.extend(edges, { return true; }; - this.removeFilter = function(term) { + this.removeFilter = function (term) { if (this.parseSelectedValueString) { term = this.parseSelectedValueString(term); } @@ -284,7 +284,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.clearFilters = function(params) { + this.clearFilters = function (params) { var triggerQuery = edges.getParam(params.triggerQuery, true); if (this.filters.length > 0) { @@ -303,7 +303,7 @@ $.extend(edges, { } }; - this.changeSize = function(newSize) { + this.changeSize = function (newSize) { this.size = newSize; var nq = this.edge.cloneQuery(); @@ -315,7 +315,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.changeSort = function(orderBy, orderDir) { + this.changeSort = function (orderBy, orderDir) { this.orderBy = orderBy; this.orderDir = orderDir; @@ -331,7 +331,7 @@ $.extend(edges, { ////////////////////////////////////////// // "private" functions for internal use - this._translate = function(term) { + this._translate = function (term) { if (this.valueMap) { if (term in this.valueMap) { return this.valueMap[term]; @@ -343,12 +343,14 @@ $.extend(edges, { }; }, - newORTermSelector : function(params) { - if (!params) { params = {} } + newORTermSelector: function (params) { + if (!params) { + params = {} + } edges.ORTermSelector.prototype = edges.newSelector(params); return new edges.ORTermSelector(params); }, - ORTermSelector : function(params) { + ORTermSelector: function (params) { // whether this component updates itself on every request, or whether it is static // throughout its lifecycle. One of "update" or "static" this.lifecycle = edges.getParam(params.lifecycle, "static"); @@ -398,7 +400,7 @@ $.extend(edges, { this.reQueryAfterListAll = false; - this.init = function(edge) { + this.init = function (edge) { // first kick the request up to the superclass edges.newSelector().init.call(this, edge); @@ -411,7 +413,7 @@ $.extend(edges, { } }; - this.synchronise = function() { + this.synchronise = function () { // reset the internal properties this.selected = []; @@ -431,7 +433,7 @@ $.extend(edges, { } }; - this._synchroniseTermsMergeInitial = function(params) { + this._synchroniseTermsMergeInitial = function (params) { var result = params.result; // mesh the terms in the aggregation with the terms in the terms list @@ -454,7 +456,7 @@ $.extend(edges, { } }; - this._synchroniseTerms = function(params) { + this._synchroniseTerms = function (params) { if (this.updateType === "mergeInitial") { this._synchroniseTermsMergeInitial(params); } else { @@ -462,7 +464,7 @@ $.extend(edges, { } }; - this._synchroniseTermsFresh = function(params) { + this._synchroniseTermsFresh = function (params) { var result = params.result; this.terms = []; @@ -476,7 +478,7 @@ $.extend(edges, { ///////////////////////////////////////////////// // query handlers for getting the full list of terms to display - this.listAll = function() { + this.listAll = function () { // to list all possible terms, build off the base query var bq = this.edge.cloneBaseQuery(); bq.clearAggregations(); @@ -503,7 +505,7 @@ $.extend(edges, { }); }; - this.listAllQuerySuccess = function(params) { + this.listAllQuerySuccess = function (params) { var result = params.result; // get the terms out of the aggregation @@ -528,11 +530,11 @@ $.extend(edges, { } }; - this.listAllQueryFail = function() { + this.listAllQueryFail = function () { this.terms = []; }; - this.setupEvent = function() { + this.setupEvent = function () { if (this.lifecycle === "update") { this.edge.context.on("edges:pre-query", edges.eventClosure(this, "doUpdate")); // we used to do this, but no need, as when the query cycles, the event handler set above will run it anyway @@ -540,7 +542,7 @@ $.extend(edges, { } }; - this.doUpdate = function() { + this.doUpdate = function () { // is an update already happening? if (this.updating) { return @@ -576,7 +578,7 @@ $.extend(edges, { }); }; - this.doUpdateQuerySuccess = function(params) { + this.doUpdateQuerySuccess = function (params) { var result = params.result; this._synchroniseTerms({result: result}); @@ -588,7 +590,7 @@ $.extend(edges, { this.draw(); }; - this.doUpdateQueryFail = function() { + this.doUpdateQueryFail = function () { // just do nothing, hopefully the next request will be successful this.updating = false; }; @@ -596,7 +598,7 @@ $.extend(edges, { /////////////////////////////////////////// // state change functions - this.selectTerms = function(params) { + this.selectTerms = function (params) { var terms = params.terms; var clearOthers = edges.getParam(params.clearOthers, false); @@ -644,11 +646,11 @@ $.extend(edges, { return true; }; - this.selectTerm = function(term) { - return this.selectTerms({terms : [term]}); + this.selectTerm = function (term) { + return this.selectTerms({terms: [term]}); }; - this.removeFilter = function(term) { + this.removeFilter = function (term) { var nq = this.edge.cloneQuery(); // first find out if there was a terms filter already in place @@ -670,7 +672,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.clearFilters = function(params) { + this.clearFilters = function (params) { var triggerQuery = edges.getParam(params.triggerQuery, true); if (this.selected.length > 0) { @@ -688,7 +690,7 @@ $.extend(edges, { ////////////////////////////////////////// // "private" functions for internal use - this._translate = function(term) { + this._translate = function (term) { if (this.valueMap) { if (term in this.valueMap) { return this.valueMap[term]; @@ -700,12 +702,14 @@ $.extend(edges, { }; }, - newBasicRangeSelector : function(params) { - if (!params) { params = {} } + newBasicRangeSelector: function (params) { + if (!params) { + params = {} + } edges.BasicRangeSelector.prototype = edges.newSelector(params); return new edges.BasicRangeSelector(params); }, - BasicRangeSelector : function(params) { + BasicRangeSelector: function (params) { ////////////////////////////////////////////// // values that can be passed in @@ -733,7 +737,7 @@ $.extend(edges, { // {display: , from: , to: } this.filters = []; - this.contrib = function(query) { + this.contrib = function (query) { var ranges = []; for (var i = 0; i < this.ranges.length; i++) { var r = this.ranges[i]; @@ -755,7 +759,7 @@ $.extend(edges, { ); }; - this.synchronise = function() { + this.synchronise = function () { // reset the state of the internal variables this.values = []; this.filters = []; @@ -791,7 +795,7 @@ $.extend(edges, { } }; - this.selectRange = function(from, to) { + this.selectRange = function (from, to) { var nq = this.edge.cloneQuery(); // just add a new range filter (the query builder will ensure there are no duplicates) @@ -810,7 +814,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.removeFilter = function(from, to) { + this.removeFilter = function (from, to) { var nq = this.edge.cloneQuery(); // just add a new range filter (the query builder will ensure there are no duplicates) @@ -829,7 +833,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this._getRangeDef = function(from, to) { + this._getRangeDef = function (from, to) { for (var i = 0; i < this.ranges.length; i++) { var r = this.ranges[i]; var frMatch = true; @@ -858,7 +862,7 @@ $.extend(edges, { return false; }; - this._getRangeBucket = function(buckets, from, to) { + this._getRangeBucket = function (buckets, from, to) { for (var i = 0; i < buckets.length; i++) { var r = buckets[i]; var frMatch = true; @@ -885,7 +889,7 @@ $.extend(edges, { return false; }; - this._formatUnknown = function(from, to) { + this._formatUnknown = function (from, to) { if (this.formatUnknown) { return this.formatUnknown(from, to) } else { @@ -913,12 +917,14 @@ $.extend(edges, { }; }, - newBasicGeoDistanceRangeSelector : function(params) { - if (!params) { params = {} } + newBasicGeoDistanceRangeSelector: function (params) { + if (!params) { + params = {} + } edges.BasicGeoDistanceRangeSelector.prototype = edges.newSelector(params); return new edges.BasicGeoDistanceRangeSelector(params); }, - BasicGeoDistanceRangeSelector : function(params) { + BasicGeoDistanceRangeSelector: function (params) { // list of distances (in order) which define the filters // {"from" : , "to" : , "display" : ""} this.distances = params.distances || []; @@ -938,18 +944,20 @@ $.extend(edges, { this.values = []; - this.synchronise = function() { + this.synchronise = function () { // reset the state of the internal variables this.values = []; }; }, - newDateHistogramSelector : function(params) { - if (!params) { params = {} } + newDateHistogramSelector: function (params) { + if (!params) { + params = {} + } edges.DateHistogramSelector.prototype = edges.newSelector(params); return new edges.DateHistogramSelector(params); }, - DateHistogramSelector : function(params) { + DateHistogramSelector: function (params) { // "year, quarter, month, week, day, hour, minute ,second" // period to use for date histogram this.interval = params.interval || "year"; @@ -966,7 +974,7 @@ $.extend(edges, { this.values = []; this.filters = []; - this.contrib = function(query) { + this.contrib = function (query) { query.addAggregation( es.newDateHistogramAggregation({ name: this.id, @@ -976,7 +984,7 @@ $.extend(edges, { ); }; - this.synchronise = function() { + this.synchronise = function () { // reset the state of the internal variables this.values = []; this.filters = []; @@ -989,9 +997,9 @@ $.extend(edges, { if (this.displayFormatter) { key = this.displayFormatter(key); } - var obj = {"display" : key, "gte": bucket.key, "count" : bucket.doc_count}; + var obj = {"display": key, "gte": bucket.key, "count": bucket.doc_count}; if (i < buckets.length - 1) { - obj["lt"] = buckets[i+1].key; + obj["lt"] = buckets[i + 1].key; } this.values.push(obj); } @@ -1023,7 +1031,7 @@ $.extend(edges, { } }; - this.selectRange = function(params) { + this.selectRange = function (params) { var from = params.gte; var to = params.lt; @@ -1046,7 +1054,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.removeFilter = function(params) { + this.removeFilter = function (params) { var from = params.gte; var to = params.lt; @@ -1068,7 +1076,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this.clearFilters = function(params) { + this.clearFilters = function (params) { var triggerQuery = edges.getParam(params.triggerQuery, true); var nq = this.edge.cloneQuery(); @@ -1082,19 +1090,21 @@ $.extend(edges, { }; }, - newAutocompleteTermSelector : function(params) { - if (!params) { params = {} } + newAutocompleteTermSelector: function (params) { + if (!params) { + params = {} + } edges.AutocompleteTermSelector.prototype = edges.newComponent(params); return new edges.AutocompleteTermSelector(params); }, - AutocompleteTermSelector : function(params) { + AutocompleteTermSelector: function (params) { this.defaultRenderer = params.defaultRenderer || "newAutocompleteTermSelectorRenderer"; }, - newNavigationTermList : function(params) { + newNavigationTermList: function (params) { return edges.instantiate(edges.NavigationTermList, params, edges.newComponent); }, - NavigationTermList : function(params) { + NavigationTermList: function (params) { this.urlTemplate = params.urlTemplate; this.placeholder = edges.getParam(params.placeholder, "{term}"); this.sourceResults = edges.getParam(params.sourceResults, false); @@ -1102,7 +1112,7 @@ $.extend(edges, { this.terms = []; - this.synchronise = function() { + this.synchronise = function () { this.terms = []; var results = this.edge.result; @@ -1117,53 +1127,111 @@ $.extend(edges, { } var agg = results.aggregation(this.sourceAggregation); - this.terms = agg.buckets.map(function(x) { return x.key}); + this.terms = agg.buckets.map(function (x) { + return x.key + }); }; - this.navigate = function(params) { + this.navigate = function (params) { var term = params.term; var url = this.urlTemplate.replace(this.placeholder, term); window.location.href = url; } }, - newTreeBrowser : function(params) { - return edges.instantiate(edges.TreeBrowser, params, edges.newComponent); + newTreeBrowserCore: function (params) { + return edges.instantiate(edges.TreeBrowserCore, params, edges.newComponent); }, - TreeBrowser : function(params) { - this.field = edges.getParam(params.field, false); - this.size = edges.getParam(params.size, 10); + newTreeBrowser: function (params) { + return edges.instantiate(edges.TreeBrowserSearch, params, edges.newTreeBrowserCore); + }, + TreeBrowserCore: function (params) { this.tree = edges.getParam(params.tree, {}); - this.nodeMatch = edges.getParam(params.nodeMatch, false); - this.filterMatch = edges.getParam(params.filterMatch, false); - this.nodeIndex = edges.getParam(params.nodeIndex, false); - this.pruneTree = edges.getParam(params.pruneTree, false); - this.syncTree = []; - this.parentIndex = {}; - - this.pruned = false; - this.nodeCount = 0; - this.init = function(edge) { + this.init = function (edge) { + console.log("edges.TreeBrowserCore"); // first kick the request up to the superclass - edges.newSelector().init.call(this, edge); + edges.newComponent().init.call(this, edge); + }; + + // Common recurse function + this.baseRecurse = function (tree, path, processNode) { + console.log("edges.TreeBrowserCore.baseRecurse"); + var anySelected = false; + var childCount = 0; + + for (var i = 0; i < tree.length; i++) { + var node = tree[i]; + this.nodeCount++; + + this.parentIndex[node.value] = $.extend(true, [], path); + + // Process the node with the provided function + processNode(node); + + if (node.children) { + path.push(node.value); + var childReport = this.baseRecurse(node.children, path, processNode); + path.pop(); + if (childReport.anySelected) { + node.selected = true; + anySelected = true; + } + childCount += childReport.childCount; + node.childCount = childReport.childCount; + } else { + node.childCount = 0; + } + } + return {anySelected: anySelected, childCount: childCount}; + }; + + this.addFilter = function (params) { + console.log('addFilter method must be implemented.'); + // throw new edges.error.NotImplementedError('addFilter method must be implemented.'); + } + + this.removeFilter = function (params) { + console.log('removeFilter method must be implemented.'); + // throw new edges.error.NotImplementedError('removeFilter method must be implemented.'); + } + + this.synchronise = function (params) { + console.log('synchronise method must be implemented.'); + // throw new edges.error.NotImplementedError('synchronise method must be implemented.'); + } + + }, + TreeBrowserSearch: function (params) { + // edges.TreeBrowserCore.call(this, params); + + this.field = edges.getParam(params.field, false); + this.size = edges.getParam(params.size, 10); + this.pruneTree = edges.getParam(params.pruneTree, false); + this.pruned = false; + + this.init = function (edge) { + // first kick the request up to the core component + console.log("edges.TreeBrowserSearch"); + edges.newTreeBrowserCore().init.call(this, edge); // now trigger a request for the terms to present, if not explicitly provided if (this.pruneTree) { this._pruneTree(); } }; - this.contrib = function(query) { + this.contrib = function (query) { + console.log("edges.TreeBrowserSearch.contrib"); var params = { name: this.id, field: this.field @@ -1176,19 +1244,9 @@ $.extend(edges, { ); }; - this.synchronise = function() { - // synchronise if: - // * we are not pruning the tree - // * we are pruning the tree, and it has now been pruned - this.nodeCount = 0; - if (!(!this.pruneTree || (this.pruneTree && this.pruned))) { - this.syncTree = []; - this.parentIndex = {}; - return; - } - + this.synchronise = function () { + console.log("edges.TreeBrowserSearch.synchronise"); this.syncTree = $.extend(true, [], this.tree); - var results = this.edge.result; if (!results) { return; @@ -1205,57 +1263,26 @@ $.extend(edges, { var buckets = $.extend(true, [], agg.buckets); var that = this; - function recurse(tree, path) { - var anySelected = false; - var childCount = 0; - - for (var i = 0; i < tree.length; i++) { - var node = tree[i]; - that.nodeCount++; - - that.parentIndex[node.value] = $.extend(true, [], path); - - var idx = that.nodeMatch(node, buckets); - if (idx === -1) { - node.count = 0; - } else { - node.count = buckets[idx].doc_count; - } - childCount += node.count; - - if (that.filterMatch(node, selected)) { - node.selected = true; - anySelected = true; - } - - if (that.nodeIndex) { - node.index = that.nodeIndex(node); - } else { - node.index = node.display; - } - - if (node.children) { - path.push(node.value); - var childReport = recurse(node.children, path); - path.pop(); - if (childReport.anySelected) { - node.selected = true; - anySelected = true; - } - childCount += childReport.childCount; - node.childCount = childReport.childCount; - } else { - node.childCount = 0; - } - + var processNode = function (node) { + var idx = that.nodeMatch(node, buckets); + if (idx === -1) { + node.count = 0; + } else { + node.count = buckets[idx].doc_count; } - return {anySelected: anySelected, childCount: childCount} - } + if (that.filterMatch(node, selected)) { + node.selected = true; + anySelected = true; + } + node.index = that.nodeIndex ? that.nodeIndex(node) : node.display; + }; + var path = []; - recurse(this.syncTree, path); + this.baseRecurse(this.syncTree, path, processNode); }; - this.addFilter = function(params) { + this.addFilter = function (params) { + console.log("edges.TreeBrowserSearch.addFilter"); var value = params.value; var parents = this.parentIndex[value]; var terms = [params.value]; @@ -1318,7 +1345,8 @@ $.extend(edges, { return true; }; - this.removeFilter = function(params) { + this.removeFilter = function (params) { + console.log("edges.TreeBrowserSearch.removeFilter"); var term = params.value; var nq = this.edge.cloneQuery(); @@ -1382,7 +1410,7 @@ $.extend(edges, { this.edge.doQuery(); }; - this._pruneTree = function() { + this._pruneTree = function () { // to list all possible terms, build off the base query var bq = this.edge.cloneBaseQuery(); bq.clearAggregations(); @@ -1409,7 +1437,7 @@ $.extend(edges, { }); }; - this._querySuccess = function(params) { + this._querySuccess = function (params) { var result = params.result; var agg = result.aggregation(this.id); @@ -1448,6 +1476,7 @@ $.extend(edges, { } return {newTree: newTree, treeCount: treeCount} } + var treeUpdate = recurse(this.tree); this.tree = treeUpdate.newTree; @@ -1460,7 +1489,7 @@ $.extend(edges, { this.draw(); }; - this._queryFail = function() { + this._queryFail = function () { console.log("pruneTree query failed"); this.tree = []; this.pruned = true; @@ -1472,4 +1501,357 @@ $.extend(edges, { this.draw(); }; } + + // TreeBrowser : function(params) { + // // search + // this.field = edges.getParam(params.field, false); + // // search + // this.size = edges.getParam(params.size, 10); + // // UI + // this.tree = edges.getParam(params.tree, {}); + // // UI + // this.nodeMatch = edges.getParam(params.nodeMatch, false); + // // UI + // this.filterMatch = edges.getParam(params.filterMatch, false); + // // UI + // this.nodeIndex = edges.getParam(params.nodeIndex, false); + // + // // search? + // this.pruneTree = edges.getParam(params.pruneTree, false); + // // UI + // this.syncTree = []; + // //UI + // this.parentIndex = {}; + // // search + // this.pruned = false; + // //UI + // this.nodeCount = 0; + // + // this.init = function(edge) { + // // first kick the request up to the superclass + // edges.newSelector().init.call(this, edge); + // + // // now trigger a request for the terms to present, if not explicitly provided + // if (this.pruneTree) { + // this._pruneTree(); + // } + // }; + // + // // search + // this.contrib = function(query) { + // var params = { + // name: this.id, + // field: this.field + // }; + // if (this.size) { + // params["size"] = this.size + // } + // query.addAggregation( + // es.newTermsAggregation(params) + // ); + // }; + // + // this.synchronise = function() { + // // synchronise if: + // // * we are not pruning the tree + // // * we are pruning the tree, and it has now been pruned + // this.nodeCount = 0; + // if (!(!this.pruneTree || (this.pruneTree && this.pruned))) { + // this.syncTree = []; + // this.parentIndex = {}; + // return; + // } + // + // this.syncTree = $.extend(true, [], this.tree); + // + // var results = this.edge.result; + // if (!results) { + // return; + // } + // + // var selected = []; + // var filters = this.edge.currentQuery.listMust(es.newTermsFilter({field: this.field})); + // for (var i = 0; i < filters.length; i++) { + // var vals = filters[i].values; + // selected = selected.concat(vals); + // } + // + // var agg = results.aggregation(this.id); + // var buckets = $.extend(true, [], agg.buckets); + // var that = this; + // + // function recurse(tree, path) { + // var anySelected = false; + // var childCount = 0; + // + // for (var i = 0; i < tree.length; i++) { + // var node = tree[i]; + // that.nodeCount++; + // + // that.parentIndex[node.value] = $.extend(true, [], path); + // + // // this is irrelevant to form, only to search UI - should be optional & parameterised? + // var idx = that.nodeMatch(node, buckets); + // if (idx === -1) { + // node.count = 0; + // } else { + // node.count = buckets[idx].doc_count; + // } + // childCount += node.count; + // + // if (that.filterMatch(node, selected)) { + // node.selected = true; + // anySelected = true; + // } + // + // if (that.nodeIndex) { + // node.index = that.nodeIndex(node); + // } else { + // node.index = node.display; + // } + // + // if (node.children) { + // path.push(node.value); + // var childReport = recurse(node.children, path); + // path.pop(); + // if (childReport.anySelected) { + // node.selected = true; + // anySelected = true; + // } + // childCount += childReport.childCount; + // node.childCount = childReport.childCount; + // } else { + // node.childCount = 0; + // } + // + // } + // return {anySelected: anySelected, childCount: childCount} + // } + // var path = []; + // recurse(this.syncTree, path); + // }; + // + // // this function adds filters to search - not needed for UI only component + // this.addFilter = function(params) { + // var value = params.value; + // var parents = this.parentIndex[value]; + // var terms = [params.value]; + // var clearOthers = edges.getParam(params.clearOthers, false); + // + // var nq = this.edge.cloneQuery(); + // + // // first find out if there was a terms filter already in place + // var filters = nq.listMust(es.newTermsFilter({field: this.field})); + // + // // if there is, just add the term to it (removing and parent terms along the way) + // if (filters.length > 0) { + // var filter = filters[0]; + // var originalValues = $.extend(true, [], filter.values); + // originalValues.sort(); + // + // // if this is an exclusive filter that clears all others, just do that + // if (clearOthers) { + // filter.clear_terms(); + // } + // + // // next, if there are any terms left, remove all the parent terms + // for (var i = 0; i < parents.length; i++) { + // var parent = parents[i]; + // if (filter.has_term(parent)) { + // filter.remove_term(parent); + // } + // } + // + // // now add all the provided terms + // var hadTermAlready = 0; + // for (var i = 0; i < terms.length; i++) { + // var term = terms[i]; + // if (filter.has_term(term)) { + // hadTermAlready++; + // } else { + // filter.add_term(term); + // } + // } + // + // // if, as a result of the all the operations, the values didn't change, then don't search + // if (originalValues === filter.values.sort()) { + // return false; + // } else if (!filter.has_terms()) { + // nq.removeMust(es.newTermsFilter({field: this.field})); + // } + // } else { + // // otherwise, set the Terms Filter + // nq.addMust(es.newTermsFilter({ + // field: this.field, + // values: terms + // })); + // } + // + // // reset the search page to the start and then trigger the next query + // nq.from = 0; + // this.edge.pushQuery(nq); + // this.edge.doQuery(); + // + // return true; + // }; + // + // // the same as with this.addFilter + // this.removeFilter = function(params) { + // var term = params.value; + // var nq = this.edge.cloneQuery(); + // + // // first find out if there was a terms filter already in place + // var filters = nq.listMust(es.newTermsFilter({field: this.field})); + // + // if (filters.length > 0) { + // var filter = filters[0]; + // + // if (filter.has_term(term)) { + // // the filter we are being asked to remove is the actual selected one + // filter.remove_term(term); + // } else { + // // the filter we are being asked to remove may be a parent of the actual selected one + // // first get all the parent sets of the values that are currently in force + // var removes = []; + // for (var i = 0; i < filter.values.length; i++) { + // var val = filter.values[i]; + // var parentSet = this.parentIndex[val]; + // if ($.inArray(term, parentSet) > -1) { + // removes.push(val); + // } + // } + // for (var i = 0; i < removes.length; i++) { + // filter.remove_term(removes[i]); + // } + // } + // + // // look to see if the term has a parent chain + // var grandparents = this.parentIndex[term]; + // if (grandparents.length > 0) { + // // if it does, get a candidate value to add to the filter + // var immediate = grandparents[grandparents.length - 1]; + // + // // we only want to add the candidate value to the filter if it is not a grandparent of any + // // of the existing filters + // var other_terms = filter.values; + // var tripwire = false; + // for (var i = 0; i < other_terms.length; i++) { + // var ot = other_terms[i]; + // var other_parents = this.parentIndex[ot]; + // if ($.inArray(immediate, other_parents) > -1) { + // tripwire = true; + // break; + // } + // } + // + // if (!tripwire) { + // filter.add_term(immediate); + // } + // } + // + // if (!filter.has_terms()) { + // nq.removeMust(es.newTermsFilter({field: this.field})); + // } + // } + // + // // reset the search page to the start and then trigger the next query + // nq.from = 0; + // this.edge.pushQuery(nq); + // this.edge.doQuery(); + // }; + // + // // search specific + // this._pruneTree = function() { + // // to list all possible terms, build off the base query + // var bq = this.edge.cloneBaseQuery(); + // bq.clearAggregations(); + // bq.size = 0; + // + // // now add the aggregation that we want + // var params = { + // name: this.id, + // field: this.field + // }; + // if (this.size) { + // params["size"] = this.size + // } + // bq.addAggregation( + // es.newTermsAggregation(params) + // ); + // + // // issue the query to elasticsearch + // this.edge.queryAdapter.doQuery({ + // edge: this.edge, + // query: bq, + // success: edges.objClosure(this, "_querySuccess", ["result"]), + // error: edges.objClosure(this, "_queryFail") + // }); + // }; + // + // // seaarch specific + // this._querySuccess = function(params) { + // var result = params.result; + // + // var agg = result.aggregation(this.id); + // var buckets = $.extend(true, [], agg.buckets); + // var that = this; + // + // function recurse(tree) { + // var treeCount = 0; + // var newTree = []; + // for (var i = 0; i < tree.length; i++) { + // var node = $.extend({}, tree[i]); + // var nodeCount = 0; + // + // var idx = that.nodeMatch(node, buckets); + // if (idx === -1) { + // nodeCount = 0; + // } else { + // nodeCount = buckets[idx].doc_count; + // } + // treeCount += nodeCount; + // + // if (node.children) { + // var childUpdate = recurse(node.children); + // treeCount += childUpdate.treeCount; + // nodeCount += childUpdate.treeCount; + // if (childUpdate.newTree.length > 0) { + // node.children = childUpdate.newTree; + // } else { + // delete node.children; + // } + // } + // + // if (nodeCount > 0) { + // newTree.push(node); + // } + // } + // return {newTree: newTree, treeCount: treeCount} + // } + // var treeUpdate = recurse(this.tree); + // this.tree = treeUpdate.newTree; + // + // this.pruned = true; + // + // // in case there's a race between this and another update operation, subsequently synchronise + // this.synchronise(); + // + // // since this happens asynchronously, we may want to draw + // this.draw(); + // }; + // + // // search specific + // this._queryFail = function() { + // console.log("pruneTree query failed"); + // this.tree = []; + // this.pruned = true; + // + // // in case there's a race between this and another update operation, subsequently synchronise + // this.synchronise(); + // + // // since this happens asynchronously, we may want to draw + // this.draw(); + // }; + // } + }); diff --git a/src/edges.js b/src/edges.js index ec908a2..61ab30a 100644 --- a/src/edges.js +++ b/src/edges.js @@ -28,12 +28,14 @@ var edges = { * @param components {Array} List of all the components that are involved in this edge * @param renderPacks=[edges.bs3, edges.nvd3, edges.highcharts, edges.google, edges.d3] {Array} Render packs to use to source automatically assigned rendering objects. Defaults to [edges.bs3, edges.nvd3, edges.highcharts, edges.google, edges.d3] */ - newEdge : function(params) { - if (!params) { params = {} } + newEdge: function (params) { + if (!params) { + params = {} + } return new edges.Edge(params); }, /** @class */ - Edge : function(params) { + Edge: function (params) { ///////////////////////////////////////////// // parameters that can be set via params arg @@ -158,7 +160,7 @@ var edges = { // startup functions // at the bottom of this constructor, we'll call this function - this.startup = function() { + this.startup = function () { // obtain the jquery context for all our operations this.context = $(this.selector); @@ -169,7 +171,7 @@ var edges = { if (this.manageUrl) { var urlParams = this.getUrlParams(); if (this.urlQuerySource in urlParams) { - this.urlQuery = es.newQuery({raw : urlParams[this.urlQuerySource]}); + this.urlQuery = es.newQuery({raw: urlParams[this.urlQuerySource]}); delete urlParams[this.urlQuerySource]; } this.urlParams = urlParams; @@ -195,13 +197,13 @@ var edges = { this.loadStaticsAsync(onward); }; - this.startupPart2 = function() { + this.startupPart2 = function () { // FIXME: at this point we should check whether the statics all loaded correctly var onward = edges.objClosure(this, "startupPart3"); this.runPreflightQueries(onward); }; - this.startupPart3 = function() { + this.startupPart3 = function () { // determine whether to initialise with either the openingQuery or the urlQuery var requestedQuery = this.openingQuery; @@ -230,12 +232,12 @@ var edges = { ///////////////////////////////////////////////////////// // Edges lifecycle functions - this.doQuery = function() { + this.doQuery = function () { // the original doQuery has become doPrimaryQuery, so this has been aliased for this.cycle this.cycle(); }; - this.cycle = function() { + this.cycle = function () { // if a search is currently executing, don't do anything, else turn it on // FIXME: should we queue them up? - see the d3 map for an example of how to do this if (this.searching) { @@ -263,12 +265,12 @@ var edges = { } }; - this.cyclePart2 = function() { + this.cyclePart2 = function () { var onward = edges.objClosure(this, "cyclePart3"); this.runSecondaryQueries(onward); }; - this.cyclePart3 = function() { + this.cyclePart3 = function () { this.synchronise(); // pre-render trigger @@ -282,7 +284,7 @@ var edges = { this.searching = false; }; - this.synchronise = function() { + this.synchronise = function () { // ask the components to synchronise themselves with the latest state for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; @@ -290,7 +292,7 @@ var edges = { } }; - this.draw = function() { + this.draw = function () { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.draw(this); @@ -298,7 +300,7 @@ var edges = { }; // reset the query to the start and re-issue the query - this.reset = function() { + this.reset = function () { // tell the world we're about to reset this.trigger("edges:pre-reset"); @@ -322,14 +324,14 @@ var edges = { this.cycle(); }; - this.sleep = function() { + this.sleep = function () { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.sleep(); } }; - this.wake = function() { + this.wake = function () { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.wake(); @@ -339,28 +341,28 @@ var edges = { //////////////////////////////////////////////////// // functions for working with the queries - this.cloneQuery = function() { + this.cloneQuery = function () { if (this.currentQuery) { return $.extend(true, {}, this.currentQuery); } return false; }; - this.pushQuery = function(query) { + this.pushQuery = function (query) { if (this.baseQuery) { query.merge(this.baseQuery); } this.currentQuery = query; }; - this.cloneBaseQuery = function() { + this.cloneBaseQuery = function () { if (this.baseQuery) { return $.extend(true, {}, this.baseQuery); } return es.newQuery(); }; - this.cloneOpeningQuery = function() { + this.cloneOpeningQuery = function () { if (this.openingQuery) { return $.extend(true, {}, this.openingQuery); } @@ -372,8 +374,8 @@ var edges = { // execute the query and all the associated workflow // FIXME: could replace this with an async group for neatness - this.doPrimaryQuery = function(callback) { - var context = {"callback" : callback}; + this.doPrimaryQuery = function (callback) { + var context = {"callback": callback}; this.queryAdapter.doQuery({ edge: this, @@ -382,7 +384,7 @@ var edges = { }); }; - this.queryFail = function(params) { + this.queryFail = function (params) { var callback = params.callback; var response = params.response; this.trigger("edges:query-fail"); @@ -395,7 +397,7 @@ var edges = { callback(); }; - this.querySuccess = function(params) { + this.querySuccess = function (params) { this.result = params.result; var callback = params.callback; @@ -404,7 +406,7 @@ var edges = { callback(); }; - this.runPreflightQueries = function(callback) { + this.runPreflightQueries = function (callback) { if (!this.preflightQueries || Object.keys(this.preflightQueries).length == 0) { callback(); return; @@ -422,7 +424,7 @@ var edges = { var that = this; var pg = edges.newAsyncGroup({ list: entries, - action: function(params) { + action: function (params) { var entry = params.entry; var success = params.success_callback; var error = params.error_callback; @@ -436,16 +438,16 @@ var edges = { }); }, successCallbackArgs: ["result"], - success: function(params) { + success: function (params) { var result = params.result; var entry = params.entry; that.preflightResults[entry.id] = result; }, - errorCallbackArgs : ["result"], - error: function(params) { + errorCallbackArgs: ["result"], + error: function (params) { that.trigger("edges:error-preflight"); }, - carryOn: function() { + carryOn: function () { that.trigger("edges:post-preflight"); callback(); } @@ -454,7 +456,7 @@ var edges = { pg.process(); }; - this.runSecondaryQueries = function(callback) { + this.runSecondaryQueries = function (callback) { this.realisedSecondaryQueries = {}; if (!this.secondaryQueries || Object.keys(this.secondaryQueries).length == 0) { callback(); @@ -478,7 +480,7 @@ var edges = { var that = this; var pg = edges.newAsyncGroup({ list: entries, - action: function(params) { + action: function (params) { var entry = params.entry; var success = params.success_callback; var error = params.error_callback; @@ -492,16 +494,16 @@ var edges = { }); }, successCallbackArgs: ["result"], - success: function(params) { + success: function (params) { var result = params.result; var entry = params.entry; that.secondaryResults[entry.id] = result; }, - errorCallbackArgs : ["result"], - error: function(params) { + errorCallbackArgs: ["result"], + error: function (params) { // FIXME: not really sure what to do about this }, - carryOn: function() { + carryOn: function () { callback(); } }); @@ -512,7 +514,7 @@ var edges = { //////////////////////////////////////////////// // various utility functions - this.getComponent = function(params) { + this.getComponent = function (params) { var id = params.id; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; @@ -524,7 +526,7 @@ var edges = { }; // return components in the requested category - this.category = function(cat) { + this.category = function (cat) { var comps = []; for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; @@ -535,7 +537,7 @@ var edges = { return comps; }; - this.getRenderPackObject = function(oname, params) { + this.getRenderPackObject = function (oname, params) { for (var i = 0; i < this.renderPacks.length; i++) { var rp = this.renderPacks[i]; if (rp && rp.hasOwnProperty(oname)) { @@ -547,11 +549,11 @@ var edges = { // get the jquery object for the desired element, in the correct context // you should ALWAYS use this, rather than the standard jquery $ object - this.jq = function(selector) { + this.jq = function (selector) { return $(selector, this.context); }; - this.trigger = function(event_name) { + this.trigger = function (event_name) { if (event_name in this.callbacks) { this.callbacks[event_name](this); } @@ -561,22 +563,22 @@ var edges = { ///////////////////////////////////////////////////// // URL management functions - this.getUrlParams = function() { + this.getUrlParams = function () { return edges.getUrlParams(); }; - this.urlQueryArg = function(objectify_options) { + this.urlQueryArg = function (objectify_options) { if (!objectify_options) { if (this.urlQueryOptions) { objectify_options = this.urlQueryOptions } else { objectify_options = { - include_query_string : true, - include_filters : true, - include_paging : true, - include_sort : true, - include_fields : false, - include_aggregations : false + include_query_string: true, + include_filters: true, + include_paging: true, + include_sort: true, + include_fields: false, + include_aggregations: false } } } @@ -586,17 +588,17 @@ var edges = { return obj; }; - this.fullQueryArgs = function() { + this.fullQueryArgs = function () { var args = $.extend(true, {}, this.urlParams); $.extend(args, this.urlQueryArg()); return args; }; - this.fullUrlQueryString = function() { + this.fullUrlQueryString = function () { return this._makeUrlQuery(this.fullQueryArgs()) }; - this._makeUrlQuery = function(args) { + this._makeUrlQuery = function (args) { var keys = Object.keys(args); var entries = []; for (var i = 0; i < keys.length; i++) { @@ -607,7 +609,7 @@ var edges = { return entries.join("&"); }; - this.fullUrl = function() { + this.fullUrl = function () { var args = this.fullQueryArgs(); var fragment = ""; if (args["#"]) { @@ -620,7 +622,7 @@ var edges = { return url; }; - this.updateUrl = function() { + this.updateUrl = function () { var currentQs = window.location.search; var qs = "?" + this.fullUrlQueryString(); @@ -641,7 +643,7 @@ var edges = { ///////////////////////////////////////////// // static file management - this.loadStaticsAsync = function(callback) { + this.loadStaticsAsync = function (callback) { if (!this.staticFiles || this.staticFiles.length == 0) { this.trigger("edges:post-load-static"); callback(); @@ -651,7 +653,7 @@ var edges = { var that = this; var pg = edges.newAsyncGroup({ list: this.staticFiles, - action: function(params) { + action: function (params) { var entry = params.entry; var success = params.success_callback; var error = params.error_callback; @@ -669,24 +671,24 @@ var edges = { }) }, successCallbackArgs: ["data"], - success: function(params) { + success: function (params) { var data = params.data; var entry = params.entry; if (entry.processor) { - var processed = entry.processor({data : data}); + var processed = entry.processor({data: data}); that.resources[entry.id] = processed; if (entry.opening) { - entry.opening({resource : processed, edge: that}); + entry.opening({resource: processed, edge: that}); } } that.static[entry.id] = data; }, - errorCallbackArgs : ["data"], - error: function(params) { + errorCallbackArgs: ["data"], + error: function (params) { that.errorLoadingStatic.push(params.entry.id); that.trigger("edges:error-load-static"); }, - carryOn: function() { + carryOn: function () { that.trigger("edges:post-load-static"); callback(); } @@ -703,11 +705,13 @@ var edges = { ////////////////////////////////////////////////// // Asynchronous resource loading feature - newAsyncGroup : function(params) { - if (!params) { params = {} } + newAsyncGroup: function (params) { + if (!params) { + params = {} + } return new edges.AsyncGroup(params); }, - AsyncGroup : function(params) { + AsyncGroup: function (params) { this.list = params.list; this.successCallbackArgs = params.successCallbackArgs; this.errorCallbackArgs = params.errorCallbackArgs; @@ -728,13 +732,13 @@ var edges = { this.finished = false; - this.construct = function(params) { + this.construct = function (params) { for (var i = 0; i < this.list.length; i++) { this.checkList.push(0); } }; - this.process = function(params) { + this.process = function (params) { if (this.list.length == 0) { this.functions.carryOn(); } @@ -746,7 +750,8 @@ var edges = { var error_callback = edges.objClosure(this, "_actionError", this.successCallbackArgs, context); var complete_callback = false; - this.functions.action({entry: this.list[i], + this.functions.action({ + entry: this.list[i], success_callback: success_callback, error_callback: error_callback, complete_callback: complete_callback @@ -754,7 +759,7 @@ var edges = { } }; - this._actionSuccess = function(params) { + this._actionSuccess = function (params) { var index = params.index; delete params.index; @@ -767,7 +772,7 @@ var edges = { } }; - this._actionError = function(params) { + this._actionError = function (params) { var index = params.index; delete params.index; @@ -780,15 +785,15 @@ var edges = { } }; - this._actionComplete = function(params) { + this._actionComplete = function (params) { }; - this._isComplete = function() { + this._isComplete = function () { return $.inArray(0, this.checkList) === -1; }; - this._finalise = function() { + this._finalise = function () { if (this.finished) { return; } @@ -803,20 +808,25 @@ var edges = { ///////////////////////////////////////////// // Query adapter base class and core ES implementation - newQueryAdapter : function(params) { - if (!params) { params = {} } + newQueryAdapter: function (params) { + if (!params) { + params = {} + } return edges.instantiate(edges.QueryAdapter, params); }, - QueryAdapter : function(params) { - this.doQuery = function(params) {}; + QueryAdapter: function (params) { + this.doQuery = function (params) { + }; }, - newESQueryAdapter : function(params) { - if (!params) { params = {} } + newESQueryAdapter: function (params) { + if (!params) { + params = {} + } return edges.instantiate(edges.ESQueryAdapter, params); }, - ESQueryAdapter : function(params) { - this.doQuery = function(params) { + ESQueryAdapter: function (params) { + this.doQuery = function (params) { var edge = params.edge; var query = params.query; var success = params.success; @@ -839,31 +849,38 @@ var edges = { ///////////////////////////////////////////// // Base classes for the various kinds of components - newRenderer : function(params) { - if (!params) { params = {} } + newRenderer: function (params) { + if (!params) { + params = {} + } return new edges.Renderer(params); }, - Renderer : function(params) { + Renderer: function (params) { this.component = params.component || false; - this.init = function(component) { + this.init = function (component) { this.component = component }; - this.draw = function(component) {}; - this.sleep = function() {}; - this.wake = function() {} + this.draw = function (component) { + }; + this.sleep = function () { + }; + this.wake = function () { + } }, - newComponent : function(params) { - if (!params) { params = {} } + newComponent: function (params) { + if (!params) { + params = {} + } return new edges.Component(params); }, - Component : function(params) { + Component: function (params) { this.id = params.id; this.renderer = params.renderer; this.category = params.category || "none"; this.defaultRenderer = params.defaultRenderer || "newRenderer"; - this.init = function(edge) { + this.init = function (edge) { // record a reference to the parent object this.edge = edge; this.context = this.edge.jq("#" + this.id); @@ -877,39 +894,43 @@ var edges = { } }; - this.draw = function() { + this.draw = function () { if (this.renderer) { this.renderer.draw(); } }; - this.contrib = function(query) {}; - this.synchronise = function() {}; + this.contrib = function (query) { + }; + this.synchronise = function () { + }; - this.sleep = function() { + this.sleep = function () { if (this.renderer) { this.renderer.sleep(); } }; - this.wake = function() { + this.wake = function () { if (this.renderer) { this.renderer.wake(); } }; // convenience method for any renderer rendering a component - this.jq = function(selector) { + this.jq = function (selector) { return this.edge.jq(selector); } }, - newSelector : function(params) { - if (!params) { params = {} } + newSelector: function (params) { + if (!params) { + params = {} + } edges.Selector.prototype = edges.newComponent(params); return new edges.Selector(params); }, - Selector : function(params) { + Selector: function (params) { // field upon which to build the selector this.field = params.field; @@ -925,56 +946,62 @@ var edges = { this.category = params.category || "selector"; }, - newTemplate : function(params) { - if (!params) { params = {} } + newTemplate: function (params) { + if (!params) { + params = {} + } return new edges.Template(params); }, - Template : function(params) { - this.draw = function(edge) {} + Template: function (params) { + this.draw = function (edge) { + } }, - newNestedEdge : function(params) { - if (!params) { params = {}} + newNestedEdge: function (params) { + if (!params) { + params = {} + } params.category = params.category || "edge"; params.renderer = false; params.defaultRenderer = false; return edges.instantiate(edges.NestedEdge, params, edges.newComponent) }, - NestedEdge : function(params) { + NestedEdge: function (params) { this.constructOnInit = edges.getParam(params.constructOnInit, false); this.constructArgs = edges.getParam(params.constructArgs, {}); this.inner = false; - this.init = function(edge) { + this.init = function (edge) { this.edge = edge; if (this.constructOnInit) { this.construct_and_bind(); } }; - this.setConstructArg = function(key, value) { + this.setConstructArg = function (key, value) { this.constructArgs[key] = value; }; - this.getConstructArg = function(key, def) { + this.getConstructArg = function (key, def) { if (this.constructArgs.hasOwnProperty(key)) { return this.constructArgs[key]; } return def; }; - this.construct_and_bind = function() { + this.construct_and_bind = function () { this.construct(); if (this.inner) { this.inner.outer = this; } }; - this.construct = function() {}; + this.construct = function () { + }; - this.destroy = function() { + this.destroy = function () { if (this.inner) { this.inner.context.empty(); this.inner.context.hide(); @@ -982,12 +1009,12 @@ var edges = { this.inner = false; }; - this.sleep = function() { + this.sleep = function () { this.inner.sleep(); this.inner.context.hide(); }; - this.wake = function() { + this.wake = function () { if (this.inner) { this.inner.context.show(); this.inner.wake(); @@ -1002,8 +1029,10 @@ var edges = { // instantiate an object with the parameters and the (optional) // prototype - instantiate : function(clazz, params, protoConstructor) { - if (!params) { params = {} } + instantiate: function (clazz, params, protoConstructor) { + if (!params) { + params = {} + } if (protoConstructor) { clazz.prototype = protoConstructor(params); } @@ -1015,7 +1044,7 @@ var edges = { }, // call a method on the parent class - up : function(inst, fn, args) { + up: function (inst, fn, args) { var parent = new inst.__proto_constructor__(); parent[fn].apply(inst, args); }, @@ -1043,8 +1072,8 @@ var edges = { // results in a call to // this.function({one: arg1, two: arg2}) // - objClosure : function(obj, fn, args, context_params) { - return function() { + objClosure: function (obj, fn, args, context_params) { + return function () { if (args) { var params = {}; for (var i = 0; i < args.length; i++) { @@ -1086,11 +1115,11 @@ var edges = { // results in a call (only in the case that the event is a click), to // this.handler(element) // - eventClosure : function(obj, fn, conditional, preventDefault) { + eventClosure: function (obj, fn, conditional, preventDefault) { if (preventDefault === undefined) { preventDefault = true; } - return function(event) { + return function (event) { if (conditional) { if (!conditional(event)) { return; @@ -1106,7 +1135,7 @@ var edges = { ////////////////////////////////////////////////////////////////// // CSS normalising/canonicalisation tools - css_classes : function(namespace, field, renderer) { + css_classes: function (namespace, field, renderer) { var cl = namespace + "-" + field; if (renderer) { cl += " " + cl + "-" + renderer.component.id; @@ -1114,7 +1143,7 @@ var edges = { return cl; }, - css_class_selector : function(namespace, field, renderer) { + css_class_selector: function (namespace, field, renderer) { var sel = "." + namespace + "-" + field; if (renderer) { sel += sel + "-" + renderer.component.id; @@ -1122,7 +1151,7 @@ var edges = { return sel; }, - css_id : function(namespace, field, renderer) { + css_id: function (namespace, field, renderer) { var id = namespace + "-" + field; if (renderer) { id += "-" + renderer.component.id; @@ -1130,14 +1159,14 @@ var edges = { return id; }, - css_id_selector : function(namespace, field, renderer) { + css_id_selector: function (namespace, field, renderer) { return "#" + edges.css_id(namespace, field, renderer); }, ////////////////////////////////////////////////////////////////// // Event binding utilities - on : function(selector, event, caller, targetFunction, delay, conditional, preventDefault) { + on: function (selector, event, caller, targetFunction, delay, conditional, preventDefault) { if (preventDefault === undefined) { preventDefault = true; } @@ -1180,7 +1209,7 @@ var edges = { } }, - off : function(selector, event, caller) { + off: function (selector, event, caller) { // if the caller has an inner component (i.e. it is a Renderer), use the component's id // otherwise, if it has a namespace (which is true of Renderers or Templates) use that if (caller.component && caller.component.id) { @@ -1204,7 +1233,7 @@ var edges = { ////////////////////////////////////////////////////////////////// // Shared utilities - getUrlParams : function() { + getUrlParams: function () { var params = {}; var url = window.location.href; var fragment = false; @@ -1229,7 +1258,7 @@ var edges = { // if it looks like a JSON object in string form... // remove " (double quotes) at beginning and end of string to make it a valid // representation of a JSON object, or the parser will complain - val = val.replace(/^"/,"").replace(/"$/,""); + val = val.replace(/^"/, "").replace(/"$/, ""); val = JSON.parse(val); } params[key] = val; @@ -1244,7 +1273,7 @@ var edges = { return params; }, - escapeHtml : function(unsafe, def) { + escapeHtml: function (unsafe, def) { if (def === undefined) { def = ""; } @@ -1261,7 +1290,7 @@ var edges = { .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); - } catch(err) { + } catch (err) { return def; } }, @@ -1273,7 +1302,7 @@ var edges = { * @param path * @returns {boolean} */ - hasProp : function(obj, path) { + hasProp: function (obj, path) { var bits = path.split("."); var ctx = obj; for (var i = 0; i < bits.length; i++) { @@ -1293,7 +1322,7 @@ var edges = { * @param def * @returns {*} */ - objVal : function(path, rec, def) { + objVal: function (path, rec, def) { if (def === undefined) { def = false; } @@ -1320,8 +1349,10 @@ var edges = { * @param def * @returns {*} */ - objVals : function(path, rec, def) { - if (def === undefined) { def = false; } + objVals: function (path, rec, def) { + if (def === undefined) { + def = false; + } var bits = path.split("."); var contexts = [rec]; @@ -1357,22 +1388,22 @@ var edges = { return contexts; }, - getParam : function(value, def) { + getParam: function (value, def) { return value !== undefined ? value : def; }, - safeId : function(unsafe) { + safeId: function (unsafe) { return unsafe.replace(/&/g, "_") - .replace(//g, "_") - .replace(/"/g, "_") - .replace(/'/g, "_") - .replace(/\./gi,'_') - .replace(/\:/gi,'_') - .replace(/\s/gi,"_"); + .replace(//g, "_") + .replace(/"/g, "_") + .replace(/'/g, "_") + .replace(/\./gi, '_') + .replace(/\:/gi, '_') + .replace(/\s/gi, "_"); }, - numFormat : function(params) { + numFormat: function (params) { var reflectNonNumbers = edges.getParam(params.reflectNonNumbers, false); var prefix = edges.getParam(params.prefix, ""); var zeroPadding = edges.getParam(params.zeroPadding, false); @@ -1381,7 +1412,7 @@ var edges = { var decimalSeparator = edges.getParam(params.decimalSeparator, "."); var suffix = edges.getParam(params.suffix, ""); - return function(number) { + return function (number) { // ensure this is really a number var num = parseFloat(number); if (isNaN(num)) { @@ -1397,7 +1428,7 @@ var edges = { if (decimalPlaces !== false) { num = num.toFixed(decimalPlaces); } else { - num = num.toString(); + num = num.toString(); } // now "num" is a string containing the formatted number that we can work on @@ -1425,10 +1456,10 @@ var edges = { } }, - numParse : function(params) { + numParse: function (params) { var commaRx = new RegExp(",", "g"); - return function(num) { + return function (num) { num = num.trim(); num = num.replace(commaRx, ""); if (num === "") { @@ -1438,11 +1469,23 @@ var edges = { } }, - isEmptyObject: function(obj) { - for(var key in obj) { - if(obj.hasOwnProperty(key)) + isEmptyObject: function (obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) return false; } return true; + }, + + error: { + NotImplementedError: function (params) { + edges.error.NotImplementedErrorInst.prototype = Object.create(Error.prototype); + edges.error.NotImplementedErrorInst.prototype.constructor = edges.error.NotImplementedErrorInst; + return edges.error.NotImplementedErrorInst.call(params); + }, + NotImplementedErrorInst: function (message) { + this.name = 'NotImplementedError'; + this.message = message || 'This method should be implemented by the derived class'; + }, } }; From 6c8f1e8f464de1e9840ad75d87afbe50cdc07551 Mon Sep 17 00:00:00 2001 From: Aga Date: Mon, 16 Sep 2024 11:47:18 +0100 Subject: [PATCH 5/7] update refactoring --- src/components/selectors.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/selectors.js b/src/components/selectors.js index 76d9784..135b0b0 100644 --- a/src/components/selectors.js +++ b/src/components/selectors.js @@ -1143,7 +1143,7 @@ $.extend(edges, { return edges.instantiate(edges.TreeBrowserCore, params, edges.newComponent); }, - newTreeBrowser: function (params) { + newTreeBrowser: function (params) {`` return edges.instantiate(edges.TreeBrowserSearch, params, edges.newTreeBrowserCore); }, @@ -1165,7 +1165,6 @@ $.extend(edges, { // Common recurse function this.baseRecurse = function (tree, path, processNode) { - console.log("edges.TreeBrowserCore.baseRecurse"); var anySelected = false; var childCount = 0; @@ -1175,8 +1174,11 @@ $.extend(edges, { this.parentIndex[node.value] = $.extend(true, [], path); - // Process the node with the provided function - processNode(node); + // Process the node and check if it was selected + var nodeSelected = processNode(node); + if (nodeSelected) { + anySelected = true; + } if (node.children) { path.push(node.value); @@ -1246,6 +1248,14 @@ $.extend(edges, { this.synchronise = function () { console.log("edges.TreeBrowserSearch.synchronise"); + + this.nodeCount = 0; + if (!(!this.pruneTree || (this.pruneTree && this.pruned))) { + this.syncTree = []; + this.parentIndex = {}; + return; + } + this.syncTree = $.extend(true, [], this.tree); var results = this.edge.result; if (!results) { @@ -1272,11 +1282,13 @@ $.extend(edges, { } if (that.filterMatch(node, selected)) { node.selected = true; - anySelected = true; + return true; // Node is selected } node.index = that.nodeIndex ? that.nodeIndex(node) : node.display; + return false; // Node not selected }; + var path = []; this.baseRecurse(this.syncTree, path, processNode); }; From 4df98985894b004b5711597d32d4c4fb26cc6fad Mon Sep 17 00:00:00 2001 From: Aga Date: Mon, 23 Sep 2024 12:39:01 +0100 Subject: [PATCH 6/7] search tree selector works --- src/components/selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/selectors.js b/src/components/selectors.js index 135b0b0..341af9b 100644 --- a/src/components/selectors.js +++ b/src/components/selectors.js @@ -1280,11 +1280,11 @@ $.extend(edges, { } else { node.count = buckets[idx].doc_count; } + node.index = that.nodeIndex ? that.nodeIndex(node) : node.display; if (that.filterMatch(node, selected)) { node.selected = true; return true; // Node is selected } - node.index = that.nodeIndex ? that.nodeIndex(node) : node.display; return false; // Node not selected }; From bbd3567e7158b3db0b627339d75852c42042e3b6 Mon Sep 17 00:00:00 2001 From: Aga Date: Mon, 23 Sep 2024 13:46:20 +0100 Subject: [PATCH 7/7] remove comments and console logs --- src/components/selectors.js | 389 +----------------------------------- 1 file changed, 1 insertion(+), 388 deletions(-) diff --git a/src/components/selectors.js b/src/components/selectors.js index 341af9b..7824f22 100644 --- a/src/components/selectors.js +++ b/src/components/selectors.js @@ -1158,8 +1158,6 @@ $.extend(edges, { this.nodeCount = 0; this.init = function (edge) { - console.log("edges.TreeBrowserCore"); - // first kick the request up to the superclass edges.newComponent().init.call(this, edge); }; @@ -1208,15 +1206,13 @@ $.extend(edges, { } this.synchronise = function (params) { - console.log('synchronise method must be implemented.'); + console.log('synchronise method must be implemented.');`` // throw new edges.error.NotImplementedError('synchronise method must be implemented.'); } }, TreeBrowserSearch: function (params) { - // edges.TreeBrowserCore.call(this, params); - this.field = edges.getParam(params.field, false); this.size = edges.getParam(params.size, 10); this.pruneTree = edges.getParam(params.pruneTree, false); @@ -1224,16 +1220,13 @@ $.extend(edges, { this.init = function (edge) { // first kick the request up to the core component - console.log("edges.TreeBrowserSearch"); edges.newTreeBrowserCore().init.call(this, edge); - // now trigger a request for the terms to present, if not explicitly provided if (this.pruneTree) { this._pruneTree(); } }; this.contrib = function (query) { - console.log("edges.TreeBrowserSearch.contrib"); var params = { name: this.id, field: this.field @@ -1247,7 +1240,6 @@ $.extend(edges, { }; this.synchronise = function () { - console.log("edges.TreeBrowserSearch.synchronise"); this.nodeCount = 0; if (!(!this.pruneTree || (this.pruneTree && this.pruned))) { @@ -1294,7 +1286,6 @@ $.extend(edges, { }; this.addFilter = function (params) { - console.log("edges.TreeBrowserSearch.addFilter"); var value = params.value; var parents = this.parentIndex[value]; var terms = [params.value]; @@ -1302,21 +1293,17 @@ $.extend(edges, { var nq = this.edge.cloneQuery(); - // first find out if there was a terms filter already in place var filters = nq.listMust(es.newTermsFilter({field: this.field})); - // if there is, just add the term to it (removing and parent terms along the way) if (filters.length > 0) { var filter = filters[0]; var originalValues = $.extend(true, [], filter.values); originalValues.sort(); - // if this is an exclusive filter that clears all others, just do that if (clearOthers) { filter.clear_terms(); } - // next, if there are any terms left, remove all the parent terms for (var i = 0; i < parents.length; i++) { var parent = parents[i]; if (filter.has_term(parent)) { @@ -1324,7 +1311,6 @@ $.extend(edges, { } } - // now add all the provided terms var hadTermAlready = 0; for (var i = 0; i < terms.length; i++) { var term = terms[i]; @@ -1335,21 +1321,18 @@ $.extend(edges, { } } - // if, as a result of the all the operations, the values didn't change, then don't search if (originalValues === filter.values.sort()) { return false; } else if (!filter.has_terms()) { nq.removeMust(es.newTermsFilter({field: this.field})); } } else { - // otherwise, set the Terms Filter nq.addMust(es.newTermsFilter({ field: this.field, values: terms })); } - // reset the search page to the start and then trigger the next query nq.from = 0; this.edge.pushQuery(nq); this.edge.doQuery(); @@ -1358,22 +1341,17 @@ $.extend(edges, { }; this.removeFilter = function (params) { - console.log("edges.TreeBrowserSearch.removeFilter"); var term = params.value; var nq = this.edge.cloneQuery(); - // first find out if there was a terms filter already in place var filters = nq.listMust(es.newTermsFilter({field: this.field})); if (filters.length > 0) { var filter = filters[0]; if (filter.has_term(term)) { - // the filter we are being asked to remove is the actual selected one filter.remove_term(term); } else { - // the filter we are being asked to remove may be a parent of the actual selected one - // first get all the parent sets of the values that are currently in force var removes = []; for (var i = 0; i < filter.values.length; i++) { var val = filter.values[i]; @@ -1387,14 +1365,10 @@ $.extend(edges, { } } - // look to see if the term has a parent chain var grandparents = this.parentIndex[term]; if (grandparents.length > 0) { - // if it does, get a candidate value to add to the filter var immediate = grandparents[grandparents.length - 1]; - // we only want to add the candidate value to the filter if it is not a grandparent of any - // of the existing filters var other_terms = filter.values; var tripwire = false; for (var i = 0; i < other_terms.length; i++) { @@ -1416,19 +1390,16 @@ $.extend(edges, { } } - // reset the search page to the start and then trigger the next query nq.from = 0; this.edge.pushQuery(nq); this.edge.doQuery(); }; this._pruneTree = function () { - // to list all possible terms, build off the base query var bq = this.edge.cloneBaseQuery(); bq.clearAggregations(); bq.size = 0; - // now add the aggregation that we want var params = { name: this.id, field: this.field @@ -1440,7 +1411,6 @@ $.extend(edges, { es.newTermsAggregation(params) ); - // issue the query to elasticsearch this.edge.queryAdapter.doQuery({ edge: this.edge, query: bq, @@ -1494,376 +1464,19 @@ $.extend(edges, { this.pruned = true; - // in case there's a race between this and another update operation, subsequently synchronise this.synchronise(); - // since this happens asynchronously, we may want to draw this.draw(); }; this._queryFail = function () { - console.log("pruneTree query failed"); this.tree = []; this.pruned = true; - // in case there's a race between this and another update operation, subsequently synchronise this.synchronise(); - // since this happens asynchronously, we may want to draw this.draw(); }; } - // TreeBrowser : function(params) { - // // search - // this.field = edges.getParam(params.field, false); - // // search - // this.size = edges.getParam(params.size, 10); - // // UI - // this.tree = edges.getParam(params.tree, {}); - // // UI - // this.nodeMatch = edges.getParam(params.nodeMatch, false); - // // UI - // this.filterMatch = edges.getParam(params.filterMatch, false); - // // UI - // this.nodeIndex = edges.getParam(params.nodeIndex, false); - // - // // search? - // this.pruneTree = edges.getParam(params.pruneTree, false); - // // UI - // this.syncTree = []; - // //UI - // this.parentIndex = {}; - // // search - // this.pruned = false; - // //UI - // this.nodeCount = 0; - // - // this.init = function(edge) { - // // first kick the request up to the superclass - // edges.newSelector().init.call(this, edge); - // - // // now trigger a request for the terms to present, if not explicitly provided - // if (this.pruneTree) { - // this._pruneTree(); - // } - // }; - // - // // search - // this.contrib = function(query) { - // var params = { - // name: this.id, - // field: this.field - // }; - // if (this.size) { - // params["size"] = this.size - // } - // query.addAggregation( - // es.newTermsAggregation(params) - // ); - // }; - // - // this.synchronise = function() { - // // synchronise if: - // // * we are not pruning the tree - // // * we are pruning the tree, and it has now been pruned - // this.nodeCount = 0; - // if (!(!this.pruneTree || (this.pruneTree && this.pruned))) { - // this.syncTree = []; - // this.parentIndex = {}; - // return; - // } - // - // this.syncTree = $.extend(true, [], this.tree); - // - // var results = this.edge.result; - // if (!results) { - // return; - // } - // - // var selected = []; - // var filters = this.edge.currentQuery.listMust(es.newTermsFilter({field: this.field})); - // for (var i = 0; i < filters.length; i++) { - // var vals = filters[i].values; - // selected = selected.concat(vals); - // } - // - // var agg = results.aggregation(this.id); - // var buckets = $.extend(true, [], agg.buckets); - // var that = this; - // - // function recurse(tree, path) { - // var anySelected = false; - // var childCount = 0; - // - // for (var i = 0; i < tree.length; i++) { - // var node = tree[i]; - // that.nodeCount++; - // - // that.parentIndex[node.value] = $.extend(true, [], path); - // - // // this is irrelevant to form, only to search UI - should be optional & parameterised? - // var idx = that.nodeMatch(node, buckets); - // if (idx === -1) { - // node.count = 0; - // } else { - // node.count = buckets[idx].doc_count; - // } - // childCount += node.count; - // - // if (that.filterMatch(node, selected)) { - // node.selected = true; - // anySelected = true; - // } - // - // if (that.nodeIndex) { - // node.index = that.nodeIndex(node); - // } else { - // node.index = node.display; - // } - // - // if (node.children) { - // path.push(node.value); - // var childReport = recurse(node.children, path); - // path.pop(); - // if (childReport.anySelected) { - // node.selected = true; - // anySelected = true; - // } - // childCount += childReport.childCount; - // node.childCount = childReport.childCount; - // } else { - // node.childCount = 0; - // } - // - // } - // return {anySelected: anySelected, childCount: childCount} - // } - // var path = []; - // recurse(this.syncTree, path); - // }; - // - // // this function adds filters to search - not needed for UI only component - // this.addFilter = function(params) { - // var value = params.value; - // var parents = this.parentIndex[value]; - // var terms = [params.value]; - // var clearOthers = edges.getParam(params.clearOthers, false); - // - // var nq = this.edge.cloneQuery(); - // - // // first find out if there was a terms filter already in place - // var filters = nq.listMust(es.newTermsFilter({field: this.field})); - // - // // if there is, just add the term to it (removing and parent terms along the way) - // if (filters.length > 0) { - // var filter = filters[0]; - // var originalValues = $.extend(true, [], filter.values); - // originalValues.sort(); - // - // // if this is an exclusive filter that clears all others, just do that - // if (clearOthers) { - // filter.clear_terms(); - // } - // - // // next, if there are any terms left, remove all the parent terms - // for (var i = 0; i < parents.length; i++) { - // var parent = parents[i]; - // if (filter.has_term(parent)) { - // filter.remove_term(parent); - // } - // } - // - // // now add all the provided terms - // var hadTermAlready = 0; - // for (var i = 0; i < terms.length; i++) { - // var term = terms[i]; - // if (filter.has_term(term)) { - // hadTermAlready++; - // } else { - // filter.add_term(term); - // } - // } - // - // // if, as a result of the all the operations, the values didn't change, then don't search - // if (originalValues === filter.values.sort()) { - // return false; - // } else if (!filter.has_terms()) { - // nq.removeMust(es.newTermsFilter({field: this.field})); - // } - // } else { - // // otherwise, set the Terms Filter - // nq.addMust(es.newTermsFilter({ - // field: this.field, - // values: terms - // })); - // } - // - // // reset the search page to the start and then trigger the next query - // nq.from = 0; - // this.edge.pushQuery(nq); - // this.edge.doQuery(); - // - // return true; - // }; - // - // // the same as with this.addFilter - // this.removeFilter = function(params) { - // var term = params.value; - // var nq = this.edge.cloneQuery(); - // - // // first find out if there was a terms filter already in place - // var filters = nq.listMust(es.newTermsFilter({field: this.field})); - // - // if (filters.length > 0) { - // var filter = filters[0]; - // - // if (filter.has_term(term)) { - // // the filter we are being asked to remove is the actual selected one - // filter.remove_term(term); - // } else { - // // the filter we are being asked to remove may be a parent of the actual selected one - // // first get all the parent sets of the values that are currently in force - // var removes = []; - // for (var i = 0; i < filter.values.length; i++) { - // var val = filter.values[i]; - // var parentSet = this.parentIndex[val]; - // if ($.inArray(term, parentSet) > -1) { - // removes.push(val); - // } - // } - // for (var i = 0; i < removes.length; i++) { - // filter.remove_term(removes[i]); - // } - // } - // - // // look to see if the term has a parent chain - // var grandparents = this.parentIndex[term]; - // if (grandparents.length > 0) { - // // if it does, get a candidate value to add to the filter - // var immediate = grandparents[grandparents.length - 1]; - // - // // we only want to add the candidate value to the filter if it is not a grandparent of any - // // of the existing filters - // var other_terms = filter.values; - // var tripwire = false; - // for (var i = 0; i < other_terms.length; i++) { - // var ot = other_terms[i]; - // var other_parents = this.parentIndex[ot]; - // if ($.inArray(immediate, other_parents) > -1) { - // tripwire = true; - // break; - // } - // } - // - // if (!tripwire) { - // filter.add_term(immediate); - // } - // } - // - // if (!filter.has_terms()) { - // nq.removeMust(es.newTermsFilter({field: this.field})); - // } - // } - // - // // reset the search page to the start and then trigger the next query - // nq.from = 0; - // this.edge.pushQuery(nq); - // this.edge.doQuery(); - // }; - // - // // search specific - // this._pruneTree = function() { - // // to list all possible terms, build off the base query - // var bq = this.edge.cloneBaseQuery(); - // bq.clearAggregations(); - // bq.size = 0; - // - // // now add the aggregation that we want - // var params = { - // name: this.id, - // field: this.field - // }; - // if (this.size) { - // params["size"] = this.size - // } - // bq.addAggregation( - // es.newTermsAggregation(params) - // ); - // - // // issue the query to elasticsearch - // this.edge.queryAdapter.doQuery({ - // edge: this.edge, - // query: bq, - // success: edges.objClosure(this, "_querySuccess", ["result"]), - // error: edges.objClosure(this, "_queryFail") - // }); - // }; - // - // // seaarch specific - // this._querySuccess = function(params) { - // var result = params.result; - // - // var agg = result.aggregation(this.id); - // var buckets = $.extend(true, [], agg.buckets); - // var that = this; - // - // function recurse(tree) { - // var treeCount = 0; - // var newTree = []; - // for (var i = 0; i < tree.length; i++) { - // var node = $.extend({}, tree[i]); - // var nodeCount = 0; - // - // var idx = that.nodeMatch(node, buckets); - // if (idx === -1) { - // nodeCount = 0; - // } else { - // nodeCount = buckets[idx].doc_count; - // } - // treeCount += nodeCount; - // - // if (node.children) { - // var childUpdate = recurse(node.children); - // treeCount += childUpdate.treeCount; - // nodeCount += childUpdate.treeCount; - // if (childUpdate.newTree.length > 0) { - // node.children = childUpdate.newTree; - // } else { - // delete node.children; - // } - // } - // - // if (nodeCount > 0) { - // newTree.push(node); - // } - // } - // return {newTree: newTree, treeCount: treeCount} - // } - // var treeUpdate = recurse(this.tree); - // this.tree = treeUpdate.newTree; - // - // this.pruned = true; - // - // // in case there's a race between this and another update operation, subsequently synchronise - // this.synchronise(); - // - // // since this happens asynchronously, we may want to draw - // this.draw(); - // }; - // - // // search specific - // this._queryFail = function() { - // console.log("pruneTree query failed"); - // this.tree = []; - // this.pruned = true; - // - // // in case there's a race between this and another update operation, subsequently synchronise - // this.synchronise(); - // - // // since this happens asynchronously, we may want to draw - // this.draw(); - // }; - // } - });