Hi,

Please review the attached patch. Thanks!

https://fedorahosted.org/reviewboard/r/102/

IPA commands now can be defined in these classes:
 - ipa_command: a single IPA command
 - ipa_batch_command: a batch command for executing multiple commands
   on the server side using the new batch plugin

The dialog boxes for adding and removing entries have been refactored:
 - ipa_dialog: base class for dialog boxes
 - ipa_adder_dialog: generic adder dialog box
 - ipa_deleter_dialog: generic deleter dialog box
 - ipa_association_adder_dialog: adding entity association
 - ipa_association_deleter_dialog: removing entity association

Dialog boxes for adding/deleting HBAC users, hosts, services, and
sourcehosts are implemented using the association dialog boxes.

The dialog box for adding access time is implemented using ipa_dialog
and currently contains only a text field. This will be replaced with a
custom dialog box in a separate patch.

The dialog box for removing access time is implemented using the
generic deleter class because it's not an association. Removing multiple
access times is implemented using batch operations.

New test data files for access times have been added.

--
Endi S. Dewata
From d697455097db118a77e706ba79ddf2d858a96a35 Mon Sep 17 00:00:00 2001
From: Endi S. Dewata <edew...@redhat.com>
Date: Thu, 4 Nov 2010 21:42:37 -0500
Subject: [PATCH] HBAC Access Time

IPA commands now can be defined in these classes:
 - ipa_command: a single IPA command
 - ipa_batch_command: a batch command for executing multiple commands
   on the server side using the new batch plugin

The dialog boxes for adding and removing entries have been refactored:
 - ipa_dialog: base class for dialog boxes
 - ipa_adder_dialog: generic adder dialog box
 - ipa_deleter_dialog: generic deleter dialog box
 - ipa_association_adder_dialog: adding entity association
 - ipa_association_deleter_dialog: removing entity association

Dialog boxes for adding/deleting HBAC users, hosts, services, and
sourcehosts are implemented using the association dialog boxes.

The dialog box for adding access time is implemented using ipa_dialog
and currently contains only a text field. This will be replaced with a
custom dialog box in a separate patch.

The dialog box for removing access time is implemented using the
generic deleter class because it's not an association. Removing multiple
access times is implemented using batch operations.

New test data files for access times have been added.
---
 install/static/associate.js                        |  254 +++--------------
 install/static/hbac.js                             |  159 ++++++++--
 install/static/ipa.js                              |   75 +++++
 install/static/policy.js                           |    3 +-
 install/static/search.js                           |    3 +-
 install/static/test/data/hbac_add_accesstime.json  |    7 +
 .../static/test/data/hbac_remove_accesstime.json   |    7 +
 install/static/widget.js                           |  308 +++++++++++++++++++-
 8 files changed, 552 insertions(+), 264 deletions(-)
 create mode 100644 install/static/test/data/hbac_add_accesstime.json
 create mode 100644 install/static/test/data/hbac_remove_accesstime.json

diff --git a/install/static/associate.js b/install/static/associate.js
index 088d4079a1a504d54da3b674878ea8264d0be323..a25144ef90ac75075e182302f9f27065dbb0cd6e 100644
--- a/install/static/associate.js
+++ b/install/static/associate.js
@@ -129,188 +129,81 @@ function bulk_associator(spec) {
 }
 
 /**
- *  Create a form for a one to many association.
- *
+ * This dialog is used for adding associations between two entities.
  */
-function ipa_adder_dialog(spec) {
+function ipa_association_adder_dialog(spec) {
 
     spec = spec || {};
 
-    var that = {};
+    var that = ipa_adder_dialog(spec);
 
-    that.name = spec.name;
-    that.title = spec.title;
     that.entity_name = spec.entity_name;
-
     that.pkey = spec.pkey;
     that.other_entity = spec.other_entity;
 
-    that.setup = spec.setup || ipa_adder_dialog_setup;
-    that.execute = spec.execute || execute;
-    that.on_success = spec.on_success;
-    that.on_error = spec.on_error;
-
     that.associator = spec.associator;
     that.method = spec.method || 'add_member';
 
-    that.dialog = $('<div/>', {
-        'title': that.title
-    });
-
-    that.open = function() {
-
-        that.setup();
-
-        var availableList = $('#availableList', that.dialog);
-        availableList.html('');
-
-        var enrollments = $('#enrollments', that.dialog);
-        enrollments.html('');
-
-        $('#addToList', that.dialog).click(function(){
-            $('#availableList :selected', that.dialog).each(function(i, selected){
-                enrollments.append(selected);
-            });
-            $('#availableList :selected', that.dialog).remove();
-        });
-        $('#removeFromList', that.dialog).click(function(){
-            $('#enrollments :selected', that.dialog).each(function(i, selected){
-                availableList.append(selected);
-            });
-            $('#enrollments :selected', that.dialog).remove();
-        });
-
-        $('#find', that.dialog).click(function(){
-            that.search();
-        });
-
-        that.dialog.dialog({
-            modal: true,
-            width: 600,
-            buttons: {
-                'Enroll': function() {
-                    var values = [];
-                    $('#enrollments', that.dialog).children().each(function (i, selected) {
-                        values.push(selected.value);
-                    });
-                    that.execute(values);
-                },
-                'Cancel': that.close
-            }
-        });
-    };
-
-    that.close = function() {
-        that.dialog.dialog('close');
-    };
+    that.on_success = spec.on_success;
+    that.on_error = spec.on_error;
 
     that.search = function() {
 
-        function search_on_win(data, text_status, xhr) {
+        function on_success(data, text_status, xhr) {
             var results = data.result;
-            var list = $('#availableList', that.dialog);
-            list.html('');
+            that.clear_available_values();
 
-            var searchColumn = IPA.metadata[that.other_entity].primary_key;
+            var pkey = IPA.metadata[that.other_entity].primary_key;
 
-            for (var i =0; i != results.count; i++){
+            for (var i=0; i<results.count; i++){
                 var result = results.result[i];
-                $('<option></option>',{
-                    value: result[searchColumn][0],
-                    html: result[searchColumn][0]
-                }).appendTo(list);
+                that.add_available_value(result[pkey][0]);
             }
         }
 
-        function search_on_fail(xhr, text_status, errow_thrown) {
-            alert('associationSearchFailure');
-        }
-
-        var queryFilter = $('#associateFilter', that.dialog).val();
-        ipa_cmd('find', [queryFilter], {}, search_on_win, null, that.other_entity);
-    };
-
-    that.get_values = function() {
-        var values = [];
-        $('#enrollments', that.dialog).children().each(function (i, selected) {
-            values.push(selected.value);
-        });
-        return values;
+        var filter = that.get_filter();
+        ipa_cmd('find', [filter], {}, on_success, null, that.other_entity);
     };
 
-    function execute(values) {
+    that.add = function() {
 
         var associator = that.associator({
             'entity_name': that.entity_name,
             'pkey': that.pkey,
             'other_entity': that.other_entity,
-            'values': that.get_values(),
+            'values': that.get_selected_values(),
             'method': that.method,
             'on_success': that.on_success,
             'on_error': that.on_error
         });
 
         associator.execute();
-    }
+    };
 
     return that;
 }
 
-function ipa_deleter_dialog(spec) {
+/**
+ * This dialog is used for removing associations between two entities.
+ */
+function ipa_association_deleter_dialog(spec) {
 
     spec = spec || {};
 
-    var that = {};
+    var that = ipa_deleter_dialog(spec);
 
-    that.name = spec.name;
-    that.title = spec.title || IPA.messages.button.deletes;
     that.entity_name = spec.entity_name;
-
     that.pkey = spec.pkey;
     that.other_entity = spec.other_entity;
-
-    that.setup = spec.setup || ipa_deleter_dialog_setup;
-    that.execute = spec.execute || execute;
-    that.on_success = spec.on_success;
-    that.on_error = spec.on_error;
+    that.values = spec.values;
 
     that.associator = spec.associator;
     that.method = spec.method || 'remove_member';
 
-    that.values = spec.values || [];
+    that.on_success = spec.on_success;
+    that.on_error = spec.on_error;
 
-    that.dialog = $('<div/>', {
-        'title': that.title,
-        'class': 'search-dialog-delete'
-    });
-
-    that.add_value = function(value) {
-        that.values.push(value);
-    };
-
-    that.set_values = function(values) {
-        that.values = that.values.concat(values);
-    };
-
-    that.get_values = function() {
-        return that.values;
-    };
-
-    that.open = function() {
-
-        that.setup();
-
-        that.dialog.dialog({
-            modal: true,
-            width: 400,
-            buttons: {
-                'Delete': that.execute,
-                'Cancel': that.close
-            }
-        });
-    };
-
-    function execute() {
+    that.remove = function() {
 
         var associator = that.associator({
             'entity_name': that.entity_name,
@@ -323,16 +216,13 @@ function ipa_deleter_dialog(spec) {
         });
 
         associator.execute();
-    }
-
-    that.close = function() {
-        that.dialog.dialog('close');
     };
 
     return that;
 }
 
 function ipa_association_config(spec) {
+
     spec = spec || {};
 
     var that = {};
@@ -349,9 +239,6 @@ function ipa_association_widget(spec) {
 
     spec = spec || {};
 
-    spec.add = spec.add || add;
-    spec.remove = spec.remove || remove;
-
     var that = ipa_table_widget(spec);
 
     that.other_entity = spec.other_entity;
@@ -402,17 +289,20 @@ function ipa_association_widget(spec) {
 
         that.add_method = association ? association.add_method : null;
         that.delete_method = association ? association.delete_method : null;
+
+        that.add_method = that.add_method || "add_member";
+        that.delete_method = that.delete_method || "remove_member";
     };
 
-    function add(container) {
+    that.add = function(container) {
 
         var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || '';
         var label = IPA.metadata[that.other_entity].label;
         var title = 'Enroll '+that.entity_name+' '+pkey+' in '+label;
 
-        var dialog = ipa_adder_dialog({
-            'name': 'adder_dialog',
+        var dialog = ipa_association_adder_dialog({
             'title': title,
+            'parent': container,
             'entity_name': that.entity_name,
             'pkey': pkey,
             'other_entity': that.other_entity,
@@ -429,9 +319,9 @@ function ipa_association_widget(spec) {
         });
 
         dialog.open();
-    }
+    };
 
-    function remove(container) {
+    that.remove = function(container) {
 
         var values = that.get_selected_values();
 
@@ -444,9 +334,9 @@ function ipa_association_widget(spec) {
         var label = IPA.metadata[that.other_entity].label;
         var title = 'Remove '+label+' from '+that.entity_name+' '+pkey;
 
-        var dialog = ipa_deleter_dialog({
-            'name': 'deleter_dialog',
+        var dialog = ipa_association_deleter_dialog({
             'title': title,
+            'parent': container,
             'entity_name': that.entity_name,
             'pkey': pkey,
             'other_entity': that.other_entity,
@@ -464,7 +354,7 @@ function ipa_association_widget(spec) {
         });
 
         dialog.open();
-    }
+    };
 
     return that;
 }
@@ -514,78 +404,6 @@ function ipa_association_facet(spec) {
 }
 
 
-function ipa_adder_dialog_setup() {
-
-    var that = this;
-
-    var div = $('<div id="associations"></div>');
-
-    var form = $('<form></form>');
-    var form_div = $('<div></div>');
-    form_div.css('border-width', '1px');
-    var sub_div = $('<div></div>');
-    sub_div.append($('<input />', {
-        id: 'associateFilter',
-        type: 'text'
-    }));
-    sub_div.append($('<input />', {
-        id: 'find',
-        type: 'button',
-        value: 'Find'
-    }));
-
-    form_div.append(sub_div);
-    form.append(form_div);
-    var form_div = $('<div id="results"></div>');
-    form_div.css('border', '2px solid rgb(0, 0, 0)');
-    form_div.css('position', 'relative');
-    form_div.css('height', '200px');
-    var sub_div = $('<div></div>');
-    sub_div.css('float', 'left');
-    sub_div.append($('<div></div>', {
-        text: 'Available'
-    }));
-    sub_div.append($('<select></select>', {
-        id: 'availableList',
-        width: '150px',
-        size: '10',
-        multiple: 'true'
-    }));
-    form_div.append(sub_div);
-    var sub_div = $('<div></div>');
-    sub_div.css('float', 'left');
-    var p = $('<p></p>');
-    p.append($('<input />', {
-        id: 'removeFromList',
-        type: 'button',
-        value: '<<'
-    }));
-    sub_div.append(p);
-    var p = $('<p></p>');
-    p.append($('<input />', {
-        id: 'addToList',
-        type: 'button',
-        value: '>>'
-    }));
-    sub_div.append(p);
-    form_div.append(sub_div);
-    var sub_div = $('<div></div>');
-    sub_div.css('float', 'left');
-    sub_div.append($('<div></div>', {
-        text: 'Prospective'
-    }));
-    sub_div.append($('<select></select>', {
-        id: 'enrollments',
-        width: '150px',
-        size: '10',
-        multiple: 'true'
-    }));
-    form_div.append(sub_div);
-    form.append(form_div);
-    div.append(form);
-    that.dialog.append(div);
-}
-
 function association_list_create(obj_name, jobj)
 {
     search_create(obj_name, [], jobj);
diff --git a/install/static/hbac.js b/install/static/hbac.js
index 528fdec9243c5524dec97e0a28b5d97beecf5b5a..7b58bf40d70df18da810f43957bf6cfe582d3d64 100755
--- a/install/static/hbac.js
+++ b/install/static/hbac.js
@@ -351,7 +351,7 @@ function ipa_hbac_details_init() {
             'name': 'accesstime',
             'label': 'When',
             'text': 'Rule applies when access is being requested at:',
-            'field_name': 'sourcehostcategory',
+            'field_name': 'accesstime',
             'options': [
                 { 'value': 'all', 'label': 'Any Time' },
                 { 'value': '', 'label': 'Specified Times' }
@@ -517,18 +517,10 @@ function ipa_hbac_details_tables_section(spec){
     return that;
 }
 
-/**
- * This widget adds & deletes the rows of the table in the UI, but does not
- * execute IPA command to apply the changes on the server.
- */
 function ipa_hbac_association_widget(spec) {
 
     spec = spec || {};
 
-    spec.add = spec.add || add;
-    spec.remove = spec.remove || remove;
-    spec.save = spec.save || save;
-
     var that = ipa_table_widget(spec);
 
     that.other_entity = spec.other_entity;
@@ -588,15 +580,15 @@ function ipa_hbac_association_widget(spec) {
         }
     };
 
-    function add(container) {
+    that.add = function(container) {
 
         var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || '';
         var label = IPA.metadata[that.other_entity].label;
         var title = 'Add '+label+' to '+that.entity_name+' '+pkey;
 
-        var dialog = ipa_adder_dialog({
-            'name': 'adder_dialog',
+        var dialog = ipa_association_adder_dialog({
             'title': title,
+            'parent': container,
             'entity_name': that.entity_name,
             'pkey': pkey,
             'other_entity': that.other_entity,
@@ -613,9 +605,9 @@ function ipa_hbac_association_widget(spec) {
         });
 
         dialog.open();
-    }
+    };
 
-    function remove(container) {
+    that.remove = function(container) {
 
         var values = that.get_selected_values();
 
@@ -628,9 +620,9 @@ function ipa_hbac_association_widget(spec) {
         var label = IPA.metadata[that.other_entity].label;
         var title = 'Remove '+label+' from '+that.entity_name+' '+pkey;
 
-        var dialog = ipa_deleter_dialog({
-            'name': 'deleter_dialog',
+        var dialog = ipa_association_deleter_dialog({
             'title': title,
+            'parent': container,
             'entity_name': that.entity_name,
             'pkey': pkey,
             'other_entity': that.other_entity,
@@ -648,11 +640,11 @@ function ipa_hbac_association_widget(spec) {
         });
 
         dialog.open();
-    }
+    };
 
-    function save(container) {
+    that.save = function(container) {
         return [];
-    }
+    };
 
     return that;
 }
@@ -661,9 +653,6 @@ function ipa_hbac_accesstime_widget(spec) {
 
     spec = spec || {};
 
-    spec.load = spec.load || load;
-    spec.save = spec.save || save;
-
     var that = ipa_table_widget(spec);
 
     that.super_create = that.super('create');
@@ -704,13 +693,12 @@ function ipa_hbac_accesstime_widget(spec) {
         }).appendTo(buttons);
     };
 
-    function load(container, result) {
+    that.load = function(container, result) {
         var values = result[that.name] || '';
-
-        if (values == '') {
-            $('input[name="'+that.name+'"][value="all"]', container).attr('checked', 'checked');
-        } else {
+        if (values) {
             $('input[name="'+that.name+'"][value=""]', container).attr('checked', 'checked');
+        } else {
+            $('input[name="'+that.name+'"][value="all"]', container).attr('checked', 'checked');
         }
 
         that.tbody.empty();
@@ -720,11 +708,122 @@ function ipa_hbac_accesstime_widget(spec) {
             $('span[name="'+that.name+'"]', tr).html(values[i]);
             tr.appendTo(that.tbody);
         }
-    }
+    };
 
-    function save(container) {
+    that.add = function(container) {
+
+        var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || '';
+        var title = 'Add '+that.label+' to '+that.entity_name+' '+pkey;
+
+        var dialog = ipa_dialog({
+            'title': title,
+            'parent': container
+        });
+
+        dialog.add_field(ipa_text_widget({
+            'name': that.name,
+            'label': that.label
+        }));
+
+        dialog.create = function() {
+            dialog.container.append(that.label+': ');
+
+            input = $('<input/>', {
+                'type': 'text',
+                'name': that.name,
+                'size': 40
+            }).appendTo(dialog.container);
+        };
+
+        function add(on_success, on_error) {
+
+            var field = dialog.get_field(that.name);
+            var value = field.save(dialog.container)[0];
+
+            var command = ipa_command({
+                'method': that.entity_name+'_add_'+that.name
+            });
+            command.add_arg(pkey);
+            command.set_option(that.name, value);
+
+            command.execute(
+                function() {
+                    that.refresh(container);
+                    if (on_success) on_success();
+                },
+                function() {
+                    that.refresh(container);
+                    if (on_error) on_error();
+                }
+            );
+        }
+
+        dialog.add_button('Add', function() {
+            add();
+        });
+
+        dialog.add_button('Add and Close', function() {
+            add(
+                function() { dialog.close(); },
+                function() { dialog.close(); }
+            );
+        });
+
+        dialog.add_button('Cancel', function() {
+            dialog.close();
+        });
+
+        dialog.open();
+    };
+
+    that.remove = function(container) {
+
+        var values = that.get_selected_values();
+
+        if (!values.length) {
+            alert('Select '+that.label+' to be removed.');
+            return;
+        }
+
+        var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || '';
+        var title = 'Remove '+that.label+' from '+that.entity_name+' '+pkey;
+
+        var dialog = ipa_deleter_dialog({
+            'title': title,
+            'parent': container,
+            'values': values
+        });
+
+        that.remove = function() {
+            var batch = ipa_batch_command();
+
+            for (var i=0; i<values.length; i++) {
+                var command = ipa_command({
+                    'method': that.entity_name+'_remove_'+that.name
+                });
+                command.add_arg(pkey);
+                command.set_option(that.name, values[i]);
+                batch.add_command(command);
+            }
+
+            batch.execute(
+                function() {
+                    that.refresh(container);
+                    dialog.close();
+                },
+                function() {
+                    that.refresh(container);
+                    dialog.close();
+                }
+            );
+        };
+
+        dialog.open();
+    };
+
+    that.save = function(container) {
         return [];
-    }
+    };
 
     return that;
 }
diff --git a/install/static/ipa.js b/install/static/ipa.js
index be8e3b6ad569797ed6e4c2a6107449b2bb2dba6f..1bcc748e4ad82d58221ad2fa645178ec28fcf169 100644
--- a/install/static/ipa.js
+++ b/install/static/ipa.js
@@ -109,6 +109,81 @@ var IPA = ( function () {
     return that;
 }());
 
+function ipa_command(spec) {
+
+    spec = spec || {};
+
+    var that = {};
+    that.method = spec.method;
+
+    that.params = spec.params || [];
+    that.params[0] = spec.args || [];
+    that.params[1] = spec.options || {};
+
+    that.add_arg = function(arg) {
+        that.params[0].push(arg);
+    };
+
+    that.get_args = function() {
+        return that.params[0];
+    };
+
+    that.set_option = function(name, value) {
+        that.params[1][name] = value;
+    };
+
+    that.get_option = function(name) {
+        return that.params[1][name];
+    };
+
+    that.get_options = function() {
+        return that.params[1];
+    };
+
+    that.execute = function(on_success, on_error) {
+        ipa_cmd(
+            that.method,
+            that.get_args(),
+            that.get_options(),
+            on_success,
+            on_error
+        );
+    };
+
+    that.to_string = function() {
+        var string = that.method.replace(/_/g, '-');
+
+        var args = that.get_args();
+        for (var i=0; i<args.length; i++) {
+            string += ' '+args[i];
+        }
+
+        var options = that.get_options();
+        for (var name in options) {
+            string += ' --'+name+'=\''+options[name]+'\'';
+        }
+
+        return string;
+    };
+
+    return that;
+}
+
+function ipa_batch_command(spec) {
+
+    spec = spec || {};
+
+    spec.method = 'batch';
+
+    var that = ipa_command(spec);
+
+    that.add_command = function(command) {
+        that.add_arg(command);
+    };
+
+    return that;
+}
+
 /* call an IPA command over JSON-RPC
  * arguments:
  *   name - name of the command or method if objname is set
diff --git a/install/static/policy.js b/install/static/policy.js
index f0fa0cd9addf2bd196e7cdcba2a452bfc5874d81..24333a5dbd98627d25971be6d33334d669499e1f 100644
--- a/install/static/policy.js
+++ b/install/static/policy.js
@@ -179,8 +179,7 @@ function ipa_records_facet(spec){
 
 
         var delete_dialog = $('<div/>', {
-            title: IPA.messages.button.delete,
-            'class': 'search-dialog-delete'
+            title: IPA.messages.button.delete
         });
         var to_delete_table =
             $('<table class="search-table" >'+
diff --git a/install/static/search.js b/install/static/search.js
index 508f6ed40e9d0bdcf0d9e39089fa0f69f1ef7757..dafa7a55399182315455670147b1853b6b96d59a 100644
--- a/install/static/search.js
+++ b/install/static/search.js
@@ -144,8 +144,7 @@ function search_create(entity_name, columns, container) {
     function delete_on_click_outer() {
         var delete_list = [];
         var delete_dialog = $('<div></div>', {
-            title: IPA.messages.button.delete,
-            'class': 'search-dialog-delete'
+            title: IPA.messages.button.delete
         });
 
         function delete_on_click() {
diff --git a/install/static/test/data/hbac_add_accesstime.json b/install/static/test/data/hbac_add_accesstime.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c631155b2bc8f8b7418136d7e352ed7df5dadc6
--- /dev/null
+++ b/install/static/test/data/hbac_add_accesstime.json
@@ -0,0 +1,7 @@
+{
+    "error": null,
+    "id": 0,
+    "result": {
+        "result": true
+    }
+}
diff --git a/install/static/test/data/hbac_remove_accesstime.json b/install/static/test/data/hbac_remove_accesstime.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c631155b2bc8f8b7418136d7e352ed7df5dadc6
--- /dev/null
+++ b/install/static/test/data/hbac_remove_accesstime.json
@@ -0,0 +1,7 @@
+{
+    "error": null,
+    "id": 0,
+    "result": {
+        "result": true
+    }
+}
diff --git a/install/static/widget.js b/install/static/widget.js
index 739694324c87ded83f0f6acf44df45bb8971a857..af17b93009aa6d586903fd074a88a2574f6c41b0 100755
--- a/install/static/widget.js
+++ b/install/static/widget.js
@@ -72,16 +72,9 @@ function ipa_text_widget(spec) {
 
     spec = spec || {};
 
-    spec.setup = spec.setup || setup;
-    spec.load = spec.load || load;
-    spec.save = spec.save || save;
-
     var that = ipa_widget(spec);
 
-    function setup(container) {
-    }
-
-    function load(container, result) {
+    that.load = function(container, result) {
         that.value = result[that.name] || '';
         var input = $('input[name="'+that.name+'"]', container);
 
@@ -92,9 +85,9 @@ function ipa_text_widget(spec) {
         } else {
             input.val(that.value);
         }
-    }
+    };
 
-    function save(container) {
+    that.save = function(container) {
         var values = [];
 
         if (that.value) {
@@ -106,7 +99,7 @@ function ipa_text_widget(spec) {
         }
 
         return values;
-    }
+    };
 
     return that;
 }
@@ -469,5 +462,296 @@ function ipa_table_widget(spec) {
             that.create_column(spec.columns[i]);
         }
     }
+
     return that;
-}
\ No newline at end of file
+}
+
+/**
+ * This is a base class for dialog boxes.
+ */
+function ipa_dialog(spec) {
+
+    spec = spec || {};
+
+    var that = {};
+
+    that.title = spec.title;
+    that.parent = spec.parent;
+    that._entity_name = spec.entity_name;
+
+    that.container = $('<div/>').appendTo(that.parent);
+    that.width = spec.width || 400;
+
+    that.buttons = {};
+
+    that.fields = [];
+    that.fields_by_name = {};
+
+    that.super = function(name) {
+        var method = that[name];
+        return function () {
+            return method.apply(that, arguments);
+        };
+    };
+
+    that.__defineGetter__("entity_name", function(){
+        return that._entity_name;
+    });
+
+    that.__defineSetter__("entity_name", function(entity_name){
+        that._entity_name = entity_name;
+
+        for (var i=0; i<that.fields.length; i++) {
+            that.fields[i].entity_name = entity_name;
+        }
+    });
+
+    that.add_button = function(name, handler) {
+        that.buttons[name] = handler;
+    };
+
+    that.get_field = function(name) {
+        return that.fields_by_name[name];
+    };
+
+    that.add_field = function(field) {
+        field.entity_name = that.entity_name;
+        that.fields.push(field);
+        that.fields_by_name[field.name] = field;
+    };
+
+    /**
+     * Create content layout
+     */
+    that.create = function() {
+    };
+
+    /**
+     * Setup behavior
+     */
+    that.setup = function() {
+    };
+
+    /**
+     * Open dialog
+     */
+    that.open = function() {
+
+        that.create();
+        that.setup();
+
+        that.container.dialog({
+            'title': that.title,
+            'modal': true,
+            'width': that.width,
+            'buttons': that.buttons
+        });
+    };
+
+    that.option = function(name, value) {
+        that.container.dialog('option', name, value);
+    };
+
+    that.close = function() {
+        that.container.dialog('destroy');
+        that.container.remove();
+    };
+
+    return that;
+}
+
+/**
+ * This dialog provides an interface for searching and selecting
+ * values from the available results.
+ */
+function ipa_adder_dialog(spec) {
+
+    spec = spec || {};
+
+    var that = ipa_dialog(spec);
+
+    that.width = spec.width || 600;
+
+    that.super_open = that.super('open');
+
+    that.create = function() {
+
+        var search_panel = $('<div/>').appendTo(that.container);
+
+        that.filter_field = $('<input/>', {
+            type: 'text'
+        }).appendTo(search_panel);
+
+        that.find_button = $('<input/>', {
+            type: 'button',
+            value: 'Find'
+        }).appendTo(search_panel);
+
+        var results_panel = $('<div/>').appendTo(that.container);
+        results_panel.css('border', '2px solid rgb(0, 0, 0)');
+        results_panel.css('position', 'relative');
+        results_panel.css('height', '200px');
+
+        var available_panel = $('<div/>').appendTo(results_panel);
+        available_panel.css('float', 'left');
+
+        $('<div/>', {
+            text: 'Available'
+        }).appendTo(available_panel);
+
+        that.available_list = $('<select/>', {
+            width: '150px',
+            size: '10',
+            multiple: 'true'
+        }).appendTo(available_panel);
+
+        var buttons_panel = $('<div/>').appendTo(results_panel);
+        buttons_panel.css('float', 'left');
+
+        var p = $('<p/>').appendTo(buttons_panel);
+        that.remove_button = $('<input />', {
+            type: 'button',
+            value: '<<'
+        }).appendTo(p);
+
+        p = $('<p/>').appendTo(buttons_panel);
+        that.add_button = $('<input />', {
+            type: 'button',
+            value: '>>'
+        }).appendTo(p);
+
+        var selected_panel = $('<div/>').appendTo(results_panel);
+        selected_panel.css('float', 'left');
+
+        $('<div/>', {
+            text: 'Prospective'
+        }).appendTo(selected_panel);
+
+        that.selected_list = $('<select/>', {
+            width: '150px',
+            size: '10',
+            multiple: 'true'
+        }).appendTo(selected_panel);
+    };
+
+    that.setup = function() {
+
+        that.add_button.click(function(){
+            var values = $(':selected', that.available_list).detach();
+            values.each(function(i, selected){
+                that.selected_list.append(selected);
+            });
+        });
+
+        that.remove_button.click(function(){
+            var values = $(':selected', that.selected_list).detach();
+            values.each(function(i, selected){
+                that.available_list.append(selected);
+            });
+        });
+
+        that.find_button.click(function(){
+            that.search();
+        });
+    };
+
+    that.open = function() {
+        that.buttons = {
+            'Enroll': that.add,
+            'Cancel': that.close
+        };
+
+        that.super_open();
+    };
+
+    that.get_filter = function() {
+        return that.filter_field.val();
+    };
+
+    that.clear_available_values = function() {
+        that.available_list.html('');
+    };
+
+    that.clear_selected_values = function() {
+        that.selected_list.html('');
+    };
+
+    that.add_available_value = function(value) {
+        $('<option></option>',{
+            'value': value,
+            'html': value
+        }).appendTo(that.available_list);
+    };
+
+    that.add_selected_value = function(value) {
+        $('<option></option>',{
+            'value': value,
+            'html': value
+        }).appendTo(that.available_list);
+    };
+
+    that.get_selected_values = function() {
+        var values = [];
+        that.selected_list.children().each(function (i, selected) {
+            values.push(selected.value);
+        });
+        return values;
+    };
+
+    that.close = function() {
+        that.container.dialog('close');
+    };
+
+    return that;
+}
+
+/**
+ * This dialog displays the values to be deleted.
+ */
+function ipa_deleter_dialog(spec) {
+
+    spec = spec || {};
+
+    var that = ipa_dialog(spec);
+
+    that.title = spec.title || IPA.messages.button.deletes;
+    that.remove = spec.remove;
+
+    that.super_open = that.super('open');
+
+    that.values = spec.values || [];
+
+    that.add_value = function(value) {
+        that.values.push(value);
+    };
+
+    that.set_values = function(values) {
+        that.values = that.values.concat(values);
+    };
+
+    that.create = function() {
+        var ul = $('<ul/>');
+        ul.appendTo(that.container);
+
+        for (var i=0; i<that.values.length; i++) {
+            $('<li/>',{
+                'text': that.values[i]
+            }).appendTo(ul);
+        }
+
+        $('<p/>', {
+            'text': IPA.messages.search.delete_confirm
+        }).appendTo(that.container);
+    };
+
+    that.open = function() {
+        that.buttons = {
+            'Delete': that.remove,
+            'Cancel': that.close
+        };
+
+        that.super_open();
+    };
+
+    return that;
+}
-- 
1.6.6.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to