a5f7cb33b5647f203f3c8eec390d09bbebc46521
[ccsdk/features.git] /
1 /**
2  * Copyright 2010-2013 Ben Birch
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this software except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 (function( $, app, i18n ) {
17
18         var ui = app.ns("ui");
19         var data = app.ns("data");
20         var ut = app.ns("ut");
21
22         ui.FilterBrowser = ui.AbstractWidget.extend({
23                 defaults: {
24                         cluster: null,  // (required) instanceof app.services.Cluster
25                         index: "" // (required) name of the index to query
26                 },
27
28                 init: function(parent) {
29                         this._super();
30                         this._cluster = this.config.cluster;
31                         this.el = $(this._main_template());
32                         this.filtersEl = this.el.find(".uiFilterBrowser-filters");
33                         this.attach( parent );
34                         new data.MetaDataFactory({ cluster: this._cluster, onReady: function(metadata, eventData) {
35                                 this.metadata = metadata;
36                                 this._createFilters_handler(eventData.originalData.metadata.indices);
37                         }.bind(this) });
38                 },
39
40                 _createFilters_handler: function(data) {
41                         var filters = [];
42                         function scan_properties(path, obj) {
43                                 if (obj.properties) {
44                                         for (var prop in obj.properties) {
45                                                 scan_properties(path.concat(prop), obj.properties[prop]);
46                                         }
47                                 } else {
48                                         // handle multi_field 
49                                         if (obj.fields) {
50                                                 for (var subField in obj.fields) {
51                                                         filters.push({ path: (path[path.length - 1] !== subField) ? path.concat(subField) : path, type: obj.fields[subField].type, meta: obj.fields[subField] });
52                                                 }
53                                         } else {
54                                                 filters.push({ path: path, type: obj.type, meta: obj });
55                                         }
56                                 }
57                         }
58                         for(var type in data[this.config.index].mappings) {
59                                 scan_properties([type], data[this.config.index].mappings[type]);
60                         }
61
62                         filters.sort( function(a, b) {
63                                 var x = a.path.join(".");
64                                 var y = b.path.join(".");
65                                 return (x < y) ? -1 : (x > y) ? 1 : 0;
66                         });
67
68                         this.filters = [
69                                 { path: ["match_all"], type: "match_all", meta: {} },
70                                 { path: ["_all"], type: "_all", meta: {}}
71                         ].concat(filters);
72
73                         this._addFilterRow_handler();
74                 },
75                 
76                 _addFilterRow_handler: function() {
77                         this.filtersEl.append(this._filter_template());
78                 },
79                 
80                 _removeFilterRow_handler: function(jEv) {
81                         $(jEv.target).closest("DIV.uiFilterBrowser-row").remove();
82                         if(this.filtersEl.children().length === 0) {
83                                 this._addFilterRow_handler();
84                         }
85                 },
86                 
87                 _search_handler: function() {
88                         var search = new data.BoolQuery();
89                         search.setSize( this.el.find(".uiFilterBrowser-outputSize").val() )
90                         this.fire("startingSearch");
91                         this.filtersEl.find(".uiFilterBrowser-row").each(function(i, row) {
92                                 row = $(row);
93                                 var bool = row.find(".bool").val();
94                                 var field = row.find(".field").val();
95                                 var op = row.find(".op").val();
96                                 var value = {};
97                                 if(field === "match_all") {
98                                         op = "match_all";
99                                 } else if(op === "range") {
100                                         var lowqual = row.find(".lowqual").val(),
101                                                 highqual = row.find(".highqual").val();
102                                         if(lowqual.length) {
103                                                 value[row.find(".lowop").val()] = lowqual;
104                                         }
105                                         if(highqual.length) {
106                                                 value[row.find(".highop").val()] = highqual;
107                                         }
108                                 } else if(op === "fuzzy") {
109                                         var qual = row.find(".qual").val(),
110                                                 fuzzyqual = row.find(".fuzzyqual").val();
111                                         if(qual.length) {
112                                                 value["value"] = qual;
113                                         }
114                                         if(fuzzyqual.length) {
115                                                 value[row.find(".fuzzyop").val()] = fuzzyqual;
116                                         }
117                                 } else {
118                                         value = row.find(".qual").val();
119                                 }
120                                 search.addClause(value, field, op, bool);
121                         });
122                         if(this.el.find(".uiFilterBrowser-showSrc").attr("checked")) {
123                                 this.fire("searchSource", search.search);
124                         }
125                         this._cluster.post( this.config.index + "/_search", search.getData(), this._results_handler );
126                 },
127                 
128                 _results_handler: function( data ) {
129                         var type = this.el.find(".uiFilterBrowser-outputFormat").val();
130                         this.fire("results", this, { type: type, data: data, metadata: this.metadata });
131                 },
132                 
133                 _changeQueryField_handler: function(jEv) {
134                         var select = $(jEv.target);
135                         var spec = select.children(":selected").data("spec");
136                         select.siblings().remove(".op,.qual,.range,.fuzzy");
137                         var ops = [];
138                         if(spec.type === 'match_all') {
139                         } else if(spec.type === '_all') {
140                                 ops = ["query_string"];
141                         } else if(spec.type === 'string' || spec.type === 'text' || spec.type === 'keyword') {
142                                 ops = ["term", "wildcard", "prefix", "fuzzy", "range", "query_string", "text", "missing"];
143                         } else if(spec.type === 'long' || spec.type === 'integer' || spec.type === 'float' ||
144                                         spec.type === 'byte' || spec.type === 'short' || spec.type === 'double') {
145                                 ops = ["term", "range", "fuzzy", "query_string", "missing"];
146                         } else if(spec.type === 'date') {
147                                 ops = ["term", "range", "fuzzy", "query_string", "missing"];
148                         } else if(spec.type === 'geo_point') {
149                                 ops = ["missing"];
150                         } else if(spec.type === 'ip') {
151                                 ops = ["term", "range", "fuzzy", "query_string", "missing"];
152                         } else if(spec.type === 'boolean') {
153                                 ops = ["term"]
154                         }
155                         select.after({ tag: "SELECT", cls: "op", onchange: this._changeQueryOp_handler, children: ops.map(ut.option_template) });
156                         select.next().change();
157                 },
158                 
159                 _changeQueryOp_handler: function(jEv) {
160                         var op = $(jEv.target), opv = op.val();
161                         op.siblings().remove(".qual,.range,.fuzzy");
162                         if(opv === 'term' || opv === 'wildcard' || opv === 'prefix' || opv === "query_string" || opv === 'text') {
163                                 op.after({ tag: "INPUT", cls: "qual", type: "text" });
164                         } else if(opv === 'range') {
165                                 op.after(this._range_template());
166                         } else if(opv === 'fuzzy') {
167                                 op.after(this._fuzzy_template());
168                         }
169                 },
170                 
171                 _main_template: function() {
172                         return { tag: "DIV", children: [
173                                 { tag: "DIV", cls: "uiFilterBrowser-filters" },
174                                 { tag: "BUTTON", type: "button", text: i18n.text("General.Search"), onclick: this._search_handler },
175                                 { tag: "LABEL", children:
176                                         i18n.complex("FilterBrowser.OutputType", { tag: "SELECT", cls: "uiFilterBrowser-outputFormat", children: [
177                                                 { text: i18n.text("Output.Table"), value: "table" },
178                                                 { text: i18n.text("Output.JSON"), value: "json" },
179                                                 { text: i18n.text("Output.CSV"), value: "csv" }
180                                         ].map(function( o ) { return $.extend({ tag: "OPTION" }, o ); } ) } )
181                                 },
182                                 { tag: "LABEL", children:
183                                         i18n.complex("FilterBrowser.OutputSize", { tag: "SELECT", cls: "uiFilterBrowser-outputSize",
184                                                 children: [ "10", "50", "250", "1000", "5000", "25000" ].map( ut.option_template )
185                                         } )
186                                 },
187                                 { tag: "LABEL", children: [ { tag: "INPUT", type: "checkbox", cls: "uiFilterBrowser-showSrc" }, i18n.text("Output.ShowSource") ] }
188                         ]};
189                 },
190                 
191                 _filter_template: function() {
192                         return { tag: "DIV", cls: "uiFilterBrowser-row", children: [
193                                 { tag: "SELECT", cls: "bool", children: ["must", "must_not", "should"].map(ut.option_template) },
194                                 { tag: "SELECT", cls: "field", onchange: this._changeQueryField_handler, children: this.filters.map(function(f) {
195                                         return { tag: "OPTION", data: { spec: f }, value: f.path.join("."), text: f.path.join(".") };
196                                 })},
197                                 { tag: "BUTTON", type: "button", text: "+", onclick: this._addFilterRow_handler },
198                                 { tag: "BUTTON", type: "button", text: "-", onclick: this._removeFilterRow_handler }
199                         ]};
200                 },
201                 
202                 _range_template: function() {
203                         return { tag: "SPAN", cls: "range", children: [
204                                 { tag: "SELECT", cls: "lowop", children: ["gt", "gte"].map(ut.option_template) },
205                                 { tag: "INPUT", type: "text", cls: "lowqual" },
206                                 { tag: "SELECT", cls: "highop", children: ["lt", "lte"].map(ut.option_template) },
207                                 { tag: "INPUT", type: "text", cls: "highqual" }
208                         ]};
209                 },
210
211                 _fuzzy_template: function() {
212                         return { tag: "SPAN", cls: "fuzzy", children: [
213                                 { tag: "INPUT", cls: "qual", type: "text" },
214                                 { tag: "SELECT", cls: "fuzzyop", children: ["max_expansions", "min_similarity"].map(ut.option_template) },
215                                 { tag: "INPUT", cls: "fuzzyqual", type: "text" }
216                         ]};
217                 }
218         });
219         
220 })( this.jQuery, this.app, this.i18n );