Much progress on refactoring/extending PCrudFilterDialog.js
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Fri, 6 Jan 2012 20:11:32 +0000 (15:11 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Fri, 6 Jan 2012 20:11:32 +0000 (15:11 -0500)
Todo:
    - better display for no filter rows empty case
    - dupe fields: prevent or "or" them together?
    - operators
    - preserve rows of filters across dialog show/hide

Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/web/css/skin/default.css
Open-ILS/web/js/dojo/openils/widget/PCrudFilterDialog.js

index 4fa7215..1973b49 100644 (file)
@@ -87,6 +87,13 @@ table { border-collapse: collapse; }
     vertical-align:middle;
 }
 .oils-fm-edit-dialog td { border:1px solid #999;}
+.oils-pcrudfilterdialog-table tr td { padding: 0.75ex 0.5em; }
+.oils-pcrudfilterdialog-remover {
+    background-color: #ccc; color: #f00;
+    padding: 0.25em; border: 1px outset #000;
+    text-decoration: none;
+}
+.oils-pcrudfilterdialog-buttonholder > * { padding: 0 2em; }
 .oils-header-panel {
     width: 100%;
     margin-top:20px;
index 5d9fb0c..90d7449 100644 (file)
@@ -1,4 +1,3 @@
-
 if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
     dojo.provide('openils.widget.PCrudFilterDialog');
     dojo.require('openils.widget.AutoFieldWidget');
@@ -8,6 +7,163 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
     dojo.require('dijit.Dialog');
     dojo.require('openils.Util');
 
+    /* This is not the dijit per se. Search further in this file for
+     * "dojo.declare" for the dijit. */
+    function PCrudFilterRowTable() {
+        var self = this;
+
+        this._init = function(container, field_store, fm_class) {
+            this.container = container;
+            this.field_store = field_store;
+            this.fm_class = fm_class;
+
+            this.rows = {};
+            this.row_index = 0;
+
+            this._build_table();
+        };
+
+        this._build_table = function() {
+            this.table = dojo.create(
+                "table", {
+                    "className": "oils-pcrudfilterdialog-table"
+                }, this.container
+            );
+
+            this.add_row();
+        };
+
+        this.add_row = function() {
+            var row_id = this.row_index++;
+            this.rows[row_id] = new PCrudFilterRow(this, row_id);
+        };
+
+        this.remove_row = function(row_id) {
+            this.rows[row_id].destroy();
+            delete this.rows[row_id];
+        };
+
+        this.compile = function() {
+            var filter = {};
+            for (var row_id in this.rows) {
+                var row = this.rows[row_id];
+                var value = row.compile();
+                var field = row.get_selected_field();
+
+                if (typeof(value) != "undefined" &&
+                    typeof(field) != "undefined") {
+                    filter[field] = value;
+                }
+            }
+
+            /* Don't return an empty filter: pcrud can't use that. */
+            if (openils.Util.objectProperties(filter).length < 1)
+                filter[fieldmapper[this.fm_class].Identifier] = {"!=": null};
+
+            dump(js2JSON(filter) + "\n"); // LFW XXX
+            return filter;
+        };
+
+        this._init.apply(this, arguments);
+    }
+
+    function PCrudFilterRow() {
+        var self = this;
+
+        this._init = function(filter_row_table, row_id) {
+            this.filter_row_table = filter_row_table;
+            this.row_id = row_id;
+
+            this._build();
+        };
+
+        this._build = function() {
+            this.tr = dojo.create("tr", {}, this.filter_row_table.table);
+
+            this._create_field_selector();
+            this._create_operator_selector();
+            this._create_value_slot();
+            this._create_remover();
+        };
+
+        this._create_field_selector = function() {
+            var td = dojo.create("td", {}, this.tr);
+            this.field_selector = new dijit.form.FilteringSelect(
+                {
+                    "labelAttr": "label",
+                    "onChange": function(value) {
+                        self.update_selected_field(value);
+                    },
+                    "store": this.filter_row_table.field_store
+                }, dojo.create("span", {}, td)
+            );
+        };
+
+        this._create_operator_selector = function() {
+        };
+
+        this._create_value_slot = function() {
+            this.value_slot = dojo.create("td", {"innerHTML": "-"}, this.tr);
+        };
+
+        this._create_remover = function() {
+            var td = dojo.create("td", {}, this.tr);
+            var anchor = dojo.create(
+                "a", {
+                    "className": "oils-pcrudfilterdialog-remover",
+                    "innerHTML": "X",
+                    "href": "#",
+                    "onclick": function() {
+                        self.filter_row_table.remove_row(self.row_id);
+                    }
+                }, td
+            );
+        };
+
+        this._clear_value_slot = function() {
+            if (this.value_widget)
+                this.value_widget.destroy();
+
+            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._clear_value_slot();
+
+            this.value_widget = new openils.widget.AutoFieldWidget({
+                "fmClass": this.filter_row_table.fm_class,
+                "fmField": value,
+                "parentNode": dojo.create("div", {}, this.value_slot)
+            });
+
+            this.value_widget.build();
+        };
+
+        this.get_selected_field = function() {
+            return this.field_selector.attr("value");
+        };
+
+        this.compile = function() {
+            if (this.value_widget)
+                return this.value_widget.getFormattedValue();
+            return undefined;
+        };
+
+        this.destroy = function() {
+            this._clear_value_slot();
+            this.field_selector.destroy();
+
+            dojo.destroy(this.tr);
+        };
+
+        this._init.apply(this, arguments);
+    }
+
+
     /**
      * Given a fieldmapper object, this builds a pop-up dialog used for editing the object
      */
@@ -20,6 +176,7 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
             constructor : function(args) {
                 for(var k in args)
                     this[k] = args[k];
+                this.title = this.title || "Filter Rows"; /* XXX i18n */
                 this.widgetIndex = 0;
                 this.widgetCache = {};
             },
@@ -45,84 +202,49 @@ if(!dojo._hasResource['openils.widget.PCrudFilterDialog']) {
                         )
                     }
                 });
-                
-                // TODO i18n/CSS
-                dojo.place(
-                    dojo.create(
-                        'div', 
-                        {innerHTML:'Filter Selector', style:'text-align:center;width:100%;padding:10px;'}
-                    ), this.domNode);
-
-                dojo.place(
-                    new dijit.form.Button({
-                        label:"Apply",
-                        onClick : function() {
-                            if(self.onApply)
-                                self.onApply(self.compileFilter());
-                            self.hide();
-                        }
-                    }).domNode, this.domNode);
-
-                dojo.place(
-                    new dijit.form.Button({
-                        label:"Cancel",
-                        onClick : function() {
-                            if(self.onCancel)
-                                self.onCancel();
-                            self.hide();
-                        }
-                    }).domNode, this.domNode);
-
-                this.table = dojo.place(dojo.create('table'), this.domNode);
-                openils.Util.addCSSClass(this.table, 'oils-fm-edit-dialog');
-                this.insertFieldSelector();
-            },
 
-            insertFieldSelector : function() {
-                var selector = new dijit.form.FilteringSelect({labelAttr:'label', store:this.fieldStore});
-                var row = dojo.place(dojo.create('tr'), this.table);
-                var selectorTd = dojo.place(dojo.create('td'), row);
-                var valueTd = dojo.place(dojo.create('td'), row);
-                dojo.place(selector.domNode, selectorTd);
+                this.filter_row_table = new PCrudFilterRowTable(
+                    dojo.create("div", {}, this.domNode),
+                    this.fieldStore, this.fmClass
+                );
 
-                // dummy text box
-                dojo.place(new dijit.form.TextBox().domNode, valueTd);
+                var button_holder = dojo.create(
+                    "div", {
+                        "className": "oils-pcrudfilterdialog-buttonholder"
+                    }, this.domNode
+                );
 
-                // when a field is selected, update the value widget
-                var self = this;
-                dojo.connect(selector, 'onChange',
-                    function(value) {
-
-                        if(valueTd.childNodes[0]) 
-                            valueTd.removeChild(valueTd.childNodes[0]);
-
-                        var widget = new openils.widget.AutoFieldWidget({
-                            fmClass : self.fmClass, 
-                            fmField : value,
-                            parentNode : dojo.place(dojo.create('div'), valueTd)
-                        });
-                        widget.build();
-
-                        if(self.widgetCache[selector.widgetIndex]) {
-                            self.widgetCache[selector.widgetIndex].widget.destroy();
-                            delete self.widgetCache[selector.widgetIndex];
+                new dijit.form.Button(
+                    {
+                        "label": "Add Row", /* XXX i18n */
+                        "onClick": function() {
+                            self.filter_row_table.add_row();
                         }
+                    }, dojo.create("span", {}, button_holder)
+                );
 
-                        selector.widgetIndex = this.widgetIndex;
-                        self.widgetCache[self.widgetIndex++] = widget;
-                    }
+                new dijit.form.Button(
+                    {
+                        "label": "Apply", /* XXX i18n */
+                        "onClick": function() {
+                            if (self.onApply)
+                                self.onApply(self.filter_row_table.compile());
+                            self.hide();
+                        }
+                    }, dojo.create("span", {}, button_holder)
                 );
-            },
 
-            compileFilter : function() {
-                var filter = {};
-                for(var i in this.widgetCache) {
-                    var widget = this.widgetCache[i];
-                    filter[widget.fmField] = widget.getFormattedValue();
-                }
-                return filter;
+                new dijit.form.Button(
+                    {
+                        "label": "Cancel", /* XXX i18n */
+                        "onClick": function() {
+                            if (self.onCancel)
+                            self.onCancel();
+                            self.hide();
+                        }
+                    }, dojo.create("span", {}, button_holder)
+                );
             }
         }
     );
 }
-