pcrudfilterdialog: selectable operators, including [not] between!
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Sat, 7 Jan 2012 20:28:59 +0000 (15:28 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Sat, 7 Jan 2012 20:28:59 +0000 (15:28 -0500)
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/web/js/dojo/openils/widget/PCrudFilterDialog.js

index bb6b7ea..04f3e98 100644 (file)
@@ -7,6 +7,110 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
     dojo.require('dijit.Dialog');
     dojo.require('openils.Util');
 
+    var _minimal_operators = [
+        {
+            "name": "=",
+            "label": "is",
+            "param_count": 1
+        }, {
+            "name": "!=",
+            "label": "is not",
+            "param_count": 1
+        }, {
+            "name": "null",
+            "label": "is null",
+            "param_count": 0
+        }, {
+            "name": "not null",
+            "label": "is not null",
+            "param_count": 0
+        }
+    ];
+
+    var _strict_operators = [
+        {
+            "name": ">",
+            "label": "is greater than",
+            "param_count": 1
+        }, {
+            "name": "<",
+            "label": "is less than",
+            "param_count": 1
+        }, {
+            "name": ">=",
+            "label": "is greater than or equal to",
+            "param_count": 1
+        }, {
+            "name": "<=",
+            "label": "is less than or equal to",
+            "param_count": 1
+        }, {
+            "name": "between",
+            "label": "is between",
+            "param_count": 2
+        }, {
+            "name": "not between",
+            "label": "is not between",
+            "param_count": 2
+        }
+    ];
+
+    var _fuzzy_operators = [
+        {
+            "name": "like",
+            "label": "is like",
+            "param_count": 1
+        }, {
+            "name": "not like",
+            "label": "is not like",
+            "param_count": 1
+        }
+    ];
+
+    var _minimal_operator_store = new dojo.data.ItemFileReadStore(
+        {
+            "data": {
+                "identifier": "name",
+                "items": _minimal_operators
+            }
+        }
+    );
+
+    var _most_operator_store = new dojo.data.ItemFileReadStore(
+        {
+            "data": {
+                "identifier": "name",
+                "items": _minimal_operators.concat(_strict_operators)
+            }
+        }
+    );
+
+    var _all_operator_store = new dojo.data.ItemFileReadStore(
+        {
+            "data": {
+                "identifier": "name",
+                "items": _minimal_operators.
+                    concat(_strict_operators).
+                    concat(_fuzzy_operators)
+            }
+        }
+    );
+
+    var _operator_stores = {};
+    ["bool", "link", "org_unit"].forEach(
+        function(type) {
+            _operator_stores[type] = _minimal_operator_store;
+        }
+    );
+
+    ["float", "id", "int", "interval", "money", "number", "timestamp"].forEach(
+        function(type) {
+            _operator_stores[type] = _most_operator_store;
+        }
+    );
+
+    _operator_stores.text = _all_operator_store;
+
     /* This is not the dijit per se. Search further in this file for
      * "dojo.declare" for the beginning of the dijit. */
     function PCrudFilterRowManager() {
@@ -118,7 +222,7 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
             for (var row_id in this.rows) {
                 var row = this.rows[row_id];
                 var value = row.compile();
-                var field = row.get_selected_field();
+                var field = row.selected_field;
 
                 if (typeof(value) != "undefined" &&
                     typeof(field) != "undefined") {
@@ -156,7 +260,9 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
             this.tr = dojo.create("tr", {}, this.filter_row_manager.table);
 
             this._create_field_selector();
-            this._create_operator_selector();
+
+            this.operator_slot = dojo.create("td", {}, this.tr);
+
             this._create_value_slot();
             this._create_remover();
         };
@@ -166,6 +272,7 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
             this.field_selector = new dijit.form.FilteringSelect(
                 {
                     "labelAttr": "label",
+                    "searchAttr": "label",
                     "scrollOnFocus": false,
                     "onChange": function(value) {
                         self.update_selected_field(value);
@@ -175,7 +282,46 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
             );
         };
 
-        this._create_operator_selector = function() {
+        this._remove_operator_selector = function() {
+            if (this.operator_selector) {
+                var old_value = this.operator_selector.attr("value");
+                this.operator_selector.destroy();
+                dojo.empty(this.operator_slot);
+                return old_value;
+            }
+
+            return undefined;
+        };
+
+        this._replace_operator_selector = function() {
+            var old_operator = this._remove_operator_selector();
+
+            var _operator_store = _operator_stores[this.selected_field_type];
+            var operator_selector_args = {
+                "labelAttr": "label",
+                "searchAttr": "label",
+                "scrollOnFocus": false,
+                "onChange": function(value) {
+                    self.update_selected_operator(value);
+                },
+                "store": _operator_store
+            };
+
+            this.operator_selector = new dijit.form.FilteringSelect(
+                operator_selector_args,
+                dojo.create("span", {}, this.operator_slot)
+            );
+
+            if (old_operator) {
+                _operator_store.fetchItemByIdentity(
+                    {
+                        "identity": old_operator,
+                        "onItem": function(item) {
+                            self.operator_selector.attr("value", old_operator);
+                        }
+                    }
+                );
+            }
         };
 
         this._create_value_slot = function() {
@@ -197,42 +343,110 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
         };
 
         this._clear_value_slot = function() {
-            if (this.value_widget)
-                this.value_widget.widget.destroy();
+            if (this.value_widgets) {
+                this.value_widgets.forEach(
+                    function(autowidg) { autowidg.widget.destroy(); }
+                );
+                delete this.value_widgets;
+            }
 
             dojo.empty(this.value_slot);
         };
 
-        this.update_selected_field = function(value) {
-            /* This is called when the field selector is changed,
-             * and is responsible for changing the widget(s) in the value slot.
-             */
+        this._rebuild_value_widgets = function() {
+            if (!this.selected_operator || !this.selected_field)
+                return;
 
             this._clear_value_slot();
 
-            this.value_widget = new openils.widget.AutoFieldWidget({
-                "fmClass": this.filter_row_manager.fm_class,
-                "fmField": value,
-                "parentNode": dojo.create("div", {}, this.value_slot),
-                "dijitArgs": {"scrollOnFocus": false}
-            });
+            var _operator_store = _operator_stores[this.selected_field_type];
+
+            _operator_store.fetchItemByIdentity(
+                {
+                    "identity": this.selected_operator,
+                    "onItem": function(item) {
+                        self._rebuild_value_widgets_impl(item.param_count);
+                    }
+                }
+            );
+        };
+
+        this._rebuild_value_widgets_impl = function(param_count) {
+            this.value_widgets = [];
+
+            for (var i = 0; i < param_count; i++) {
+                var widg = new openils.widget.AutoFieldWidget({
+                    "fmClass": this.filter_row_manager.fm_class,
+                    "fmField": this.selected_field,
+                    "parentNode": dojo.create("span", {}, this.value_slot),
+                    "dijitArgs": {"scrollOnFocus": false}
+                });
+
+                widg.build();
+                this.value_widgets.push(widg);
+            }
+        };
+
+        this._null_clause = function() {
+            /* ugly special cases */
+            if (this.selected_operator == "not null")
+                return {"!=": null};
+            else if (this.selected_operator == "null")
+                return null;
+            else
+                return undefined;
+        };
 
-            this.value_widget.build();
+        this.update_selected_operator = function(value) {
+            this.selected_operator = value;
+            this._rebuild_value_widgets();
         };
 
-        this.get_selected_field = function() {
-            return this.field_selector.attr("value");
+        this.update_selected_field = function(value) {
+            this.filter_row_manager.field_store.fetchItemByIdentity(
+                {
+                    "identity": value,
+                    "onItem": function(item) {
+                        self._update_selected_field_impl(value, item.type);
+                    }
+                }
+            );
+        };
+
+        this._update_selected_field_impl = function(value, type) {
+            this.selected_field = value;
+            this.selected_field_type = type;
+            this._replace_operator_selector();
+            this._rebuild_value_widgets();
         };
 
         this.compile = function() {
-            if (this.value_widget)
-                return this.value_widget.getFormattedValue();
-            return undefined;
+            if (this.value_widgets) {
+                var values = this.value_widgets.map(
+                    function(widg) { return widg.getFormattedValue(); }
+                );
+
+                if (!values.length) {
+                    return this._null_clause(); /* null/not null */
+                } else if (values.length == 1) {
+                    var clause = {};
+                    clause[self.selected_operator] = values.pop();
+                    return clause;
+                } else {
+                    var clause = {};
+                    clause[self.selected_operator] = values;
+                    return clause;
+                }
+            } else {
+                return undefined;
+            }
         };
 
         this.destroy = function() {
             this._clear_value_slot();
             this.field_selector.destroy();
+            if (this.operator_selector)
+                this.operator_selector.destroy();
 
             dojo.destroy(this.tr);
         };
@@ -269,12 +483,16 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
                 var realFieldList = this.sortedFieldList.filter(
                     function(item) { return !(item.virtual || item.nonIdl); });
                 this.fieldStore = new dojo.data.ItemFileReadStore({
-                    data : {
-                        identifier : 'name',
-                        name : 'label',
-                        items : realFieldList.map(
+                    "data": {
+                        "identifier": "name",
+                        "name": "label",
+                        "items": realFieldList.map(
                             function(item) {
-                                return {label:item.label, name:item.name};
+                                return {
+                                    "label": item.label,
+                                    "name": item.name,
+                                    "type": item.datatype
+                                };
                             }
                         )
                     }