The IPA.entity_select_widget has been modified into a searchable and
editable drop down list.

Ticket #1361

--
Endi S. Dewata
From 5affc4f0a2748a1882b4f883b657ffcc5bfbf7d5 Mon Sep 17 00:00:00 2001
From: Endi S. Dewata <edew...@redhat.com>
Date: Fri, 15 Jul 2011 12:18:59 -0500
Subject: [PATCH] Entity select widget improvements

The IPA.entity_select_widget has been modified into a searchable and
editable drop down list.

Ticket #1361
---
 install/ui/aci.js                |   41 +++--
 install/ui/details.js            |   53 +++---
 install/ui/dialog.js             |    6 +-
 install/ui/entitle.js            |    8 +-
 install/ui/hbac.js               |    4 +-
 install/ui/host.js               |    9 +-
 install/ui/ipa.css               |  212 +++++++++++----------
 install/ui/jsl.conf              |    2 +-
 install/ui/policy.js             |    9 +-
 install/ui/search.js             |   11 +-
 install/ui/serverconfig.js       |    5 +-
 install/ui/service.js            |    7 +-
 install/ui/test/aci_tests.js     |    2 +-
 install/ui/test/details_tests.js |   14 +-
 install/ui/test/widget_tests.js  |   11 +-
 install/ui/user.js               |   12 +-
 install/ui/widget.js             |  378 ++++++++++++++++++++++++--------------
 17 files changed, 468 insertions(+), 316 deletions(-)

diff --git a/install/ui/aci.js b/install/ui/aci.js
index 1a95af0e7f9d663fccb98d472aee3b2a8fee2868..54050c79cfa2f88fae87907cae67bb71affb7082 100644
--- a/install/ui/aci.js
+++ b/install/ui/aci.js
@@ -50,7 +50,8 @@ IPA.entity_factories.permission = function() {
             }]}).
         standard_association_facets().
         adder_dialog({
-            height: '400',
+            width: 500,
+            height: 400,
             fields:[
                 'cn',
                 {
@@ -165,12 +166,16 @@ IPA.entity_factories.delegation = function() {
                 fields:[
                     'aciname',
                     {
-                        factory:IPA.entity_select_widget,
-                        name: 'group', entity: 'group'
+                        factory: IPA.entity_select_widget,
+                        name: 'group',
+                        other_entity: 'group',
+                        other_field: 'cn'
                     },
                     {
-                        factory:IPA.entity_select_widget,
-                        name: 'memberof', entity: 'group',
+                        factory: IPA.entity_select_widget,
+                        name: 'memberof',
+                        other_entity: 'group',
+                        other_field: 'cn',
                         join: true
                     },
                     {
@@ -183,13 +188,19 @@ IPA.entity_factories.delegation = function() {
             fields:[
                 'aciname',
                 {
-                    factory:IPA.entity_select_widget,
-                    name: 'group', entity: 'group', undo: false
+                    factory: IPA.entity_select_widget,
+                    name: 'group',
+                    other_entity: 'group',
+                    other_field: 'cn',
+                    undo: false
                 },
                 {
-                    factory:IPA.entity_select_widget,
-                    name: 'memberof', entity: 'group',
-                    join: true, undo: false
+                    factory: IPA.entity_select_widget,
+                    name: 'memberof',
+                    other_entity: 'group',
+                    other_field: 'cn',
+                    join: true,
+                    undo: false
                 },
                 {
                     factory:IPA.attributes_widget,
@@ -402,8 +413,12 @@ IPA.target_section = function(spec) {
         cols: 30, rows: 1,
         undo: that.undo
     });
-    that.group_select = IPA.entity_select_widget(
-        {name: 'targetgroup', entity:'group', undo: that.undo});
+    that.group_select = IPA.entity_select_widget({
+        name: 'targetgroup',
+        other_entity: 'group',
+        other_field: 'cn',
+        undo: that.undo
+    });
     that.type_select = IPA.select_widget({name: 'type', undo: that.undo});
     that.attribute_table = IPA.attributes_widget({
         name: 'attrs', undo: that.undo});
@@ -506,7 +521,7 @@ IPA.target_section = function(spec) {
                 that.group_select.create(span);
             },
             load: function(record){
-                that.group_select.entity_select.val(record.targetgroup);
+                that.group_select.list.val(record.targetgroup);
             },
             save: function(record){
                 record.targetgroup = that.group_select.save()[0];
diff --git a/install/ui/details.js b/install/ui/details.js
index b31305c693de767ec2381192759ca9839ca6894c..82804b538618e884025990907e235a6050b8f2b0 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -26,8 +26,8 @@
 
 /* REQUIRES: ipa.js */
 
-IPA.expanded_icon = 'ui-icon-expanded';
-IPA.collapsed_icon = 'ui-icon-collapsed';
+IPA.expanded_icon = 'expanded-icon';
+IPA.collapsed_icon = 'collapsed-icon';
 
 IPA.details_section = function(spec) {
 
@@ -111,8 +111,11 @@ IPA.details_section = function(spec) {
         for (var i=0; i<fields.length; i++) {
             var field = fields[i];
 
-            var span = $('<span/>', { 'name': field.name }).appendTo(container);
-            field.create(span);
+            var field_container = $('<div/>', {
+                name: field.name,
+                'class': 'details-field'
+            }).appendTo(container);
+            field.create(field_container);
         }
     };
 
@@ -126,8 +129,8 @@ IPA.details_section = function(spec) {
         for (var i=0; i<fields.length; i++) {
             var field = fields[i];
 
-            var span = $('span[name='+field.name+']', this.container).first();
-            field.setup(span);
+            var field_container = $('.details-field[name='+field.name+']', this.container).first();
+            field.setup(field_container);
         }
     };
 
@@ -245,12 +248,13 @@ IPA.details_list_section = function(spec) {
                 title: label
             }).appendTo(dl);
 
-            var dd = $('<dd/>', {
-                'class': 'first'
-            }).appendTo(dl);
+            var dd = $('<dd/>').appendTo(dl);
 
-            var span = $('<span/>', { 'name': field.name }).appendTo(dd);
-            field.create(span);
+            var field_container = $('<div/>', {
+                name: field.name,
+                'class': 'details-field'
+            }).appendTo(dd);
+            field.create(field_container);
         }
     };
 
@@ -437,7 +441,7 @@ IPA.details_facet = function(spec) {
 
             var icon = $('<span/>', {
                 name: 'icon',
-                'class': 'ui-icon section-expand '+IPA.expanded_icon
+                'class': 'icon section-expand '+IPA.expanded_icon
             }).appendTo(header);
 
             header.append(' ');
@@ -680,23 +684,26 @@ IPA.button = function(spec) {
         id: spec.id,
         name: spec.name,
         href: spec.href || '#' + (spec.name || 'button'),
-        html: spec.label,
         title: spec.title || spec.label,
-        'class': 'ui-state-default ui-corner-all',
-        style: spec.style
+        'class': 'ui-state-default ui-corner-all input_link',
+        style: spec.style,
+        click: spec.click,
+        blur: spec.blur
     });
 
-    if (spec.click) {
-        button.click(spec.click);
-    }
-
     if (spec['class']) button.addClass(spec['class']);
-    button.addClass('input_link');
 
     if (spec.icon) {
-        button.prepend('<span class="ui-icon '+spec.icon+'" ></span> ');
-    } else {
-        button.addClass('button-without-icon');
+        $('<span/>', {
+            'class': 'icon '+spec.icon
+        }).appendTo(button);
+    }
+
+    if (spec.label) {
+        $('<span/>', {
+            'class': 'button-label',
+            html: spec.label
+        }).appendTo(button);
     }
 
     return button;
diff --git a/install/ui/dialog.js b/install/ui/dialog.js
index 607684297dfd548e1c5c75b6c6e661d7908dd730..9d22da7f19acb6f1d798f5a8fcbbf217b625b6c8 100644
--- a/install/ui/dialog.js
+++ b/install/ui/dialog.js
@@ -35,7 +35,7 @@ IPA.dialog = function(spec) {
     that.template = spec.template;
     that._entity_name = spec.entity_name;
 
-    that.width = spec.width || '400px';
+    that.width = spec.width || 400;
     that.height = spec.height;
 
     that.buttons = {};
@@ -375,7 +375,8 @@ IPA.adder_dialog = function (spec) {
 
     var that = IPA.dialog(spec);
 
-    that.width = spec.width || '600px';
+    that.width = spec.width || 600;
+    that.height = spec.height || 360;
 
     that.columns = $.ordered_map();
 
@@ -534,7 +535,6 @@ IPA.adder_dialog = function (spec) {
         that.find_button = IPA.button({
             name: 'find',
             'label': button.val(),
-            'icon': 'ui-icon-search',
             'click': function() { that.search(); }
         });
         button.replaceWith(that.find_button);
diff --git a/install/ui/entitle.js b/install/ui/entitle.js
index 4775af4bff7a353a9139858506024a626ce4e125..b3b09e562f078be33e8a4a0913bc8d1f4b8cfdcd 100644
--- a/install/ui/entitle.js
+++ b/install/ui/entitle.js
@@ -337,7 +337,7 @@ IPA.entitle.details_facet = function(spec) {
         that.register_online_button = IPA.action_button({
             name: 'register',
             label: IPA.messages.objects.entitle.register,
-            icon: 'ui-icon-plus',
+            icon: 'add-icon',
             click: function() {
                 var dialog = that.entity.get_dialog('online_registration');
                 dialog.open(that.container);
@@ -350,7 +350,7 @@ IPA.entitle.details_facet = function(spec) {
         that.register_offline_button = IPA.action_button({
             name: 'import',
             label: IPA.messages.objects.entitle.import,
-            icon: 'ui-icon-plus',
+            icon: 'add-icon',
             click: function() {
                 var dialog = that.entity.get_dialog('offline_registration');
                 dialog.open(that.container);
@@ -426,7 +426,7 @@ IPA.entitle.search_facet = function(spec) {
         that.consume_button = IPA.action_button({
             name: 'consume',
             label: IPA.messages.objects.entitle.consume,
-            icon: 'ui-icon-plus',
+            icon: 'add-icon',
             click: function() {
                 var dialog = that.entity.get_dialog('consume');
                 dialog.open(that.container);
@@ -439,7 +439,7 @@ IPA.entitle.search_facet = function(spec) {
         that.import_button = IPA.action_button({
             name: 'import',
             label: IPA.messages.objects.entitle.import_button,
-            icon: 'ui-icon-plus',
+            icon: 'add-icon',
             click: function() {
                 var dialog = that.entity.get_dialog('import');
                 dialog.open(that.container);
diff --git a/install/ui/hbac.js b/install/ui/hbac.js
index 87f8a36dc447a74188abde4b4a2337d945759f9a..d7c0b94622d678ca6315e8ebac04c5ce2aefc136 100644
--- a/install/ui/hbac.js
+++ b/install/ui/hbac.js
@@ -787,7 +787,7 @@ IPA.hbacrule_accesstime_widget = function(spec) {
         button.replaceWith(IPA.button({
             name: 'remove',
             'label': button.val(),
-            'icon': 'ui-icon-trash',
+            'icon': 'remove-icon',
             'click': function() { that.remove(that.container); }
         }));
 
@@ -795,7 +795,7 @@ IPA.hbacrule_accesstime_widget = function(spec) {
         button.replaceWith(IPA.button({
             name: 'add',
             'label': button.val(),
-            'icon': 'ui-icon-plus',
+            'icon': 'add-icon',
             'click': function() { that.add(that.container); }
         }));
 
diff --git a/install/ui/host.js b/install/ui/host.js
index 704783eec0b3955d0decb6db163d32c8e5565559..e9adcd4f796860ff41aadda59f0410ca4a28fbf5 100644
--- a/install/ui/host.js
+++ b/install/ui/host.js
@@ -102,13 +102,14 @@ IPA.entity_factories.host = function () {
         }).
         standard_association_facets().
         adder_dialog({
-            width:500,
+            width: 400,
+            height: 250,
             fields:[
                 {
-                    factory:IPA.entity_select_widget,
+                    factory: IPA.entity_select_widget,
                     name: 'fqdn',
-                    field_name:'idnsname',
-                    entity: 'dnszone',
+                    other_entity: 'dnszone',
+                    other_field: 'idnsname',
                     label: IPA.messages.objects.service.host,
                     editable: true,
                     undo: false
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index a363154789040bd7a41f9f161c3941f8fa999585..ce5b1fba61c318e838d0821602e39d99eff02f6d 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -121,11 +121,10 @@ body {
 }
 
 .ui-widget {
-    font-size: 1em;
+    font-size: 11px;
 }
 
 .input_link {
-    padding: .4em 1em .4em 0em;
     text-decoration: none;
     position: relative;
     cursor: pointer;
@@ -136,54 +135,52 @@ body {
     color:black;
 }
 
-.input_link span.ui-icon {
-    -moz-border-radius: 0.3em;
-        -webkit-border-radius: 0.3em;
-    border: 1px solid #B8B8B8;
+.input_link_label {
+
+}
+
+.icon {
+    display: inline-block;
+    height: 16px;
+    width: 16px;
     vertical-align: middle;
 }
 
-.input_link span.search-icon {
-	background: url(search-icon.png);
-	border: none;
-	margin: -1px 0 0 !important;
-	float: right;
-	position: relative;
+.expanded-icon {
+    background: url(arrow_expanded.png);
 }
 
-.input_link span.add-icon {
+.collapsed-icon {
+    background: url(arrow_collapsed.png);
+}
+
+.search-icon {
+	background: url(search-icon.png) no-repeat;
+}
+
+.add-icon {
 	background: url(add-icon.png);
-	border: none;
 	margin: -4px 0 0 1px;
 }
 
-.input_link span.remove-icon {
+.remove-icon {
 	background: url(remove-icon.png);
-	border: none;
 	margin: -4px 0 0 1px;
 }
 
-.input_link span.update-icon {
+.update-icon {
 	background: url(update-icon.png);
-	border: none;
 	margin: -4px 0 0 1px;
 }
 
-.input_link span.reset-icon {
+.reset-icon {
 	background: url(reset-icon.png);
-	border: none;
-	margin: -4px 0 0 1px;
-}
-
-.input_link span.enroll-icon {
-	background: url(enroll-icon.png);
-	border: none;
 	margin: -4px 0 0 1px;
 }
 
 .ipa-icon {
-        font-size: 0.7em;
-        padding-right: 0.3em;
+    font-size: 0.7em;
+    padding-right: 0.3em;
 }
 
 /*  ----  Header  ----  */
@@ -557,7 +554,7 @@ div.tabs {
 
 .facet-controls a {
 	font-size: 1.3em !important;
-	padding: 0 6px 0 0;
+	margin: 0 6px 0 0;
 }
 
 /* ---- Facet Content ---- */
@@ -605,11 +602,23 @@ div.tabs {
     border-radius: 15px !important;
 	border: 1px solid #9f9e9e;
 	background: url("search-bg.png");
-	height: 18px;
-	padding-left: 8px;
+	height: 20px;
+    line-height: 20px;
+	padding: 0 8px 0;
     margin: 5px 0 5px;
 }
 
+.search-filter input {
+	width: 193px;
+	border: none;
+	background: transparent;
+	height: 18px;
+}
+
+.search-filter a {
+    padding: 3px;
+}
+
 .search-controls {
     -moz-border-radius: .7em .7em 0 0;
         -webkit-border-radius: .7em .7em 0 0;
@@ -632,7 +641,7 @@ div.tabs {
 }
 
 .search-table thead tr th {
-    padding-left: 0.5em;
+    padding: 0 0.5em;
     background-color:#f6f6f6;
     color:#333333;
     text-align: left;
@@ -640,6 +649,10 @@ div.tabs {
     height: 25px;
 }
 
+.search-table thead tr th .action-button {
+    margin: 0 0 0 0.5em;
+}
+
 .search-table tbody td {
     padding-left: 0.5em;
 }
@@ -793,26 +806,12 @@ dl.entryattrs dt {
 
 dl.entryattrs dd {
     float: left;
-    padding-bottom: 0.8em;
-        margin-left: 0;
-}
-
-dl.entryattrs dd.first {
+    margin-bottom: 1em;
     margin-left: 0;
     margin-top: 0.5em;
     font-weight: bold;
 }
 
-dl.entryattrs dd.other {
-    clear: both;
-    margin-left: 10.7em;
-}
-
-dl.entryattrs input {
-    margin-right: 0.5em;
-    margin-bottom: 1em;
-}
-
 dl.entryattrs input.otp {
     min-width: 15em;
     width: 15em;
@@ -883,14 +882,6 @@ dl.aci-target input {
         width: 46em;
 }
 
-#memberof-entity-select {
-        margin-right: 1em;
-}
-
-#group-entity-select {
-        margin-right: 1em;
-}
-
 span.attrhint {
     font-size: 8pt;
     left: 5em;
@@ -904,32 +895,6 @@ span.attrhint {
     padding:0;
 }
 
-/*
- the positions for these are in the large icon image,
- and need to be specified in pixels.
-*/
-.ui-icon {
-    /* background-image: url("ui-icons_222222_256x240.png"); */
-    background-color: #e2e2e2;
-    display: inline-block;
-}
-
-.ui-icon-expanded {
-    background: url(arrow_expanded.png);
-}
-
-.ui-icon-collapsed {
-    background: url(arrow_collapsed.png);
-}
-
-.ui-icon-plus {
-    background-position: -16px -129px;
-}
-
-.ui-icon-trash {
-    background-position: -176px -97px;
-}
-
 .ui-widget-content {
 }
 
@@ -976,14 +941,16 @@ a {
     text-align: left;
 }
 
-//.ui-dialog .ui-dialog-content {
+/*
+.ui-dialog .ui-dialog-content {
         min-height: 26em !important;
-}//
+}
+*/
 
 .ui-widget input, .ui-widget select,
 .ui-widget textarea, .ui-widget button {
     font-family: "Liberation Sans", Arial, sans-serif;
-    font-size: 1.3em;
+    font-size: 11px;
     margin-right: .1em;
 }
 
@@ -998,20 +965,6 @@ a {
          padding: 0.4em 1em;
 }
 
-span.ui-icon-search {
-        background-color: transparent !important;
-    border: medium none !important;
-    color: #FFFFFF !important;
-        margin-left: 0 !important;
-}
-
-a[name=find] {
-    margin: 6px;
-    padding: 3px 3px 2px;
-    position: absolute;
-    right: 0;
-}
-
 [title=">>"] {
     margin-top: 1em !important;
 }
@@ -1036,6 +989,10 @@ span.main-separator{
     font-size: 0.9em;
 }
 
+.action-button .button-label {
+    padding: 0 0.2em;
+}
+
 a.action-button-disabled {
     color: gray;
     cursor: default;
@@ -1055,9 +1012,7 @@ a.action-button-disabled {
 }
 
 .aci-attribute-table th.aci-attribute-column{
-    float: left;
     width: 20.5em;
-    padding: 0.8em 0.5em;
 }
 
 .entity-views{
@@ -1211,3 +1166,60 @@ table.scrollable tbody {
     width: 23em;
     height: 4em;
 }
+
+/* ---- Widgets ---- */
+
+.text-widget input {
+    width: 250px;
+}
+
+.multivalued-text-widget [name=value] {
+    margin-bottom: 1em;
+}
+
+.multivalued-text-widget input {
+    width: 250px;
+}
+
+.combo-widget-input {
+    display: inline-block;
+    position: relative;
+}
+
+.combo-widget-input input {
+    width: 250px;
+}
+
+.combo-widget-input .expanded-icon {
+    display: inline-block;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    margin-top: -2px;
+    margin-right: 3px;
+}
+
+.combo-widget-list {
+    visibility: hidden;
+    border: 1px solid #A0A0A0;
+    background: #EEEEEE;
+    padding: 5px;
+    position: absolute;
+    left: 0;
+    right: 0;
+    z-index: 1;
+}
+
+.combo-widget-list input {
+    width: 238px;
+}
+
+.combo-widget-list .search-icon {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    margin-top: -2px;
+    margin-right: 3px;
+}
diff --git a/install/ui/jsl.conf b/install/ui/jsl.conf
index 06fdb60041fac13c52f3031b2745c8ab04533f8a..09db971201cb3fd4c6f78fe1205b98816941d3b4 100644
--- a/install/ui/jsl.conf
+++ b/install/ui/jsl.conf
@@ -113,7 +113,7 @@
 #
 # Common uses for webpages might be:
 +define window
-#+define document
++define document
 +define alert
 +define $ 
 +define JSON
diff --git a/install/ui/policy.js b/install/ui/policy.js
index 46582f468c7f74ab2b3f6dd8a95b164a079e7926..dd4efa0257c7d33c3ccab13f1e422dcf5d574e20 100644
--- a/install/ui/policy.js
+++ b/install/ui/policy.js
@@ -46,12 +46,15 @@ IPA.entity_factories.pwpolicy = function() {
         adder_dialog({
             fields:[
                 {
-                    factory:IPA.entity_select_widget,
+                    factory: IPA.entity_select_widget,
                     name: 'cn',
-                    entity: 'group',
+                    other_entity: 'group',
+                    other_field: 'cn',
                     undo: false
                 },
-                'cospriority']
+                'cospriority'],
+            width: 400,
+            height: 250
         }).
         build();
 };
diff --git a/install/ui/search.js b/install/ui/search.js
index 29c52c879600e0332698ad2e13bdfc075624f736..1b07908b8c735e54adbd8cd5c85c4fcfd389d8bd 100644
--- a/install/ui/search.js
+++ b/install/ui/search.js
@@ -96,15 +96,18 @@ IPA.search_facet = function(spec) {
 
         that.facet_create_header(container);
 
-        var span = $('<span/>', {
+        var span = $('<div/>', {
             'class': 'right-aligned-facet-controls'
         }).appendTo(that.controls);
 
+        var filter_container = $('<div/>', {
+            'class': 'search-filter'
+        }).appendTo(span);
+
         that.filter = $('<input/>', {
             type: 'text',
-                        'class': 'search-filter',
             name: 'filter'
-        }).appendTo(span);
+        }).appendTo(filter_container);
 
         that.filter.keypress(function(e) {
             /* if the key pressed is the enter key */
@@ -120,7 +123,7 @@ IPA.search_facet = function(spec) {
                 that.find();
                 return false;
             }
-        }).appendTo(span);
+        }).appendTo(filter_container);
 
         span.append(IPA.create_network_spinner());
 
diff --git a/install/ui/serverconfig.js b/install/ui/serverconfig.js
index 9779dccaec84aecbf26270c5c3fa87f35f6edacd..d595e6cc6d5f8dddea81827dff8bfdce974676fd 100644
--- a/install/ui/serverconfig.js
+++ b/install/ui/serverconfig.js
@@ -49,9 +49,10 @@ IPA.entity_factories.config = function(){
                         'ipausersearchfields',
                         'ipadefaultemaildomain',
                         {
-                            factory:IPA.entity_select_widget,
+                            factory: IPA.entity_select_widget,
                             name: 'ipadefaultprimarygroup',
-                            entity: 'group'
+                            other_entity: 'group',
+                            other_field: 'cn'
                         },
                         'ipahomesrootdir',
                         'ipamaxusernamelength',
diff --git a/install/ui/service.js b/install/ui/service.js
index 618269c8f2557344a23223e15be1e4a8f72490d3..d2a4189ccbe349320342f03a4e7d154457e41b92 100644
--- a/install/ui/service.js
+++ b/install/ui/service.js
@@ -72,7 +72,8 @@ IPA.entity_factories.service = function() {
         standard_association_facets().
         adder_dialog({
             factory: IPA.service_add_dialog,
-            width: '450px'
+            width: 400,
+            height: 250
         }).
         build();
 };
@@ -121,8 +122,8 @@ IPA.service_add_dialog = function(spec) {
         })).
         field(IPA.entity_select_widget({
             name: 'host',
-            field_name: 'fqdn',
-            entity: 'host',
+            other_entity: 'host',
+            other_field: 'fqdn',
             label: IPA.messages.objects.service.host,
             undo: false
         })).
diff --git a/install/ui/test/aci_tests.js b/install/ui/test/aci_tests.js
index d51f1ea6d1aec5f5f204390b258155f96612e6ef..604a48b3a01b585cae12d748d42ccb9a21601361 100644
--- a/install/ui/test/aci_tests.js
+++ b/install/ui/test/aci_tests.js
@@ -134,7 +134,7 @@ test("Testing aci grouptarget.", function() {
     var selected = $(target_section.type_select+":selected");
 
     same(selected.val(), 'targetgroup' , 'group control selected');
-    ok ($('#targetgroup-entity-select option').length > 2,
+    ok ($('option', selected.group_select).length > 2,
         'group select populated');
 
 });
diff --git a/install/ui/test/details_tests.js b/install/ui/test/details_tests.js
index 1b19f4b3e91d9b05f54243257801a2372afa13a2..28e2029de4a2e5ce3396f2de408ad930529217f2 100644
--- a/install/ui/test/details_tests.js
+++ b/install/ui/test/details_tests.js
@@ -98,14 +98,14 @@ test("Testing IPA.details_section.create().", function() {
             'Checking field '+field.name+'\'s label'
         );
 
-        var span = $('span[name='+field.name+']', dl);
+        var field_container = $('.details-field[name='+field.name+']', dl);
 
         ok(
-            span.length,
-            'Checking span tag for field '+field.name
+            field_container.length,
+            'Checking container tag for field '+field.name
         );
 
-        var dd = $('dd', span);
+        var dd = $('dd', field_container);
 
         ok(
             dd.length == 0,
@@ -316,9 +316,9 @@ test("Testing IPA.details_section_setup again()",function(){
         '3 dd'
     );
 
-    var span = $('span[name="cn"]', dd[0]);
+    var field_container = $('.details-field[name="cn"]', dd[0]);
     same(
-        span.length, 1,
-        '1 span'
+        field_container.length, 1,
+        '1 field container'
     );
 });
diff --git a/install/ui/test/widget_tests.js b/install/ui/test/widget_tests.js
index 1abac1ca0a8cc91b50a814770da086890103da56..c3ae8bea1df00041d44726e4850caf509ab0b713 100644
--- a/install/ui/test/widget_tests.js
+++ b/install/ui/test/widget_tests.js
@@ -265,10 +265,15 @@ test("IPA.select_widget" ,function(){
 
 
 test("IPA.entity_select_widget" ,function(){
+
     var widget = IPA.entity_select_widget({
-        name: 'uid', entity:'user',field_name:'uid'});
+        name: 'uid',
+        other_entity: 'user',
+        other_field: 'uid'
+    });
+
     base_widget_test(widget,'user','test_value');
-    ok( $('#uid-entity-select option').length > 1,"options populatedfrom AJAX");
+    ok( $('option', widget.container).length > 1,"options populated from AJAX");
     mock_record = {'uid':'kfrog'};
     widget.load(mock_record);
     same(widget.values[0],'kfrog','select set from values');
@@ -278,7 +283,7 @@ test("IPA.entity_select_widget" ,function(){
 test("IPA.entity_link_widget" ,function(){
     var widget = IPA.entity_link_widget({
         name: 'gidnumber',
-        other_entity:'group',
+        other_entity:'group'
     });
     base_widget_test(widget,'user','test_value');
 
diff --git a/install/ui/user.js b/install/ui/user.js
index 07fe7fbd40110159af8d514a450cc8acebde2494..5d104bfc6575e182d547990f4b7075fe1277cefe 100644
--- a/install/ui/user.js
+++ b/install/ui/user.js
@@ -96,7 +96,9 @@ IPA.entity_factories.user = function() {
                 ['ou',
                  {
                      factory:IPA.entity_select_widget,
-                     name: 'manager', entity: 'user', field_name: 'uid'
+                     name: 'manager',
+                     other_entity: 'user',
+                     other_field: 'uid'
                  }
                 ]
             },
@@ -325,9 +327,7 @@ IPA.user_password_widget = function(spec) {
                 html: IPA.messages.objects.user.new_password
             }).appendTo(dl);
 
-            var dd = $('<dd/>', {
-                'class': 'first'
-            }).appendTo(dl);
+            var dd = $('<dd/>').appendTo(dl);
 
             dialog.password1 = $('<input/>', {
                 type: 'password'
@@ -337,9 +337,7 @@ IPA.user_password_widget = function(spec) {
                 html: IPA.messages.objects.user.repeat_password
             }).appendTo(dl);
 
-            dd = $('<dd/>', {
-                'class': 'first'
-            }).appendTo(dl);
+            dd = $('<dd/>').appendTo(dl);
 
             dialog.password2 = $('<input/>', {
                 type: 'password'
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 90ebaba1f3b643feee7133f68748044794894594..9c5d7d7a430e266423500e0229cad7436c9f5f27 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -227,6 +227,7 @@ IPA.widget = function(spec) {
     };
 
     that.create = function(container) {
+        container.addClass('widget');
         that.container = container;
     };
 
@@ -395,6 +396,10 @@ IPA.text_widget = function(spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('text-widget');
+
         $('<label/>', {
             name: that.name,
             style: 'display: none;'
@@ -535,6 +540,10 @@ IPA.multivalued_text_widget = function(spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('multivalued-text-widget');
+
         var div = $('<div/>', {
             name: 'value'
         }).appendTo(container);
@@ -766,6 +775,10 @@ IPA.checkbox_widget = function (spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('checkbox-widget');
+
         $('<input/>', {
             type: 'checkbox',
             name: that.name,
@@ -833,6 +846,10 @@ IPA.checkboxes_widget = function (spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('checkboxes-widget');
+
         var vertical = that.direction === 'vertical';
 
         for (var i=0; i<that.options.length; i++) {
@@ -920,6 +937,10 @@ IPA.radio_widget = function(spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('radio-widget');
+
         for (var i=0; i<that.options.length; i++) {
             var option = that.options[i];
 
@@ -996,6 +1017,10 @@ IPA.select_widget = function(spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('select-widget');
+
         var select = $('<select/>', {
             name: that.name
         }).appendTo(container);
@@ -1074,6 +1099,10 @@ IPA.textarea_widget = function (spec) {
 
     that.create = function(container) {
 
+        that.widget_create(container);
+
+        container.addClass('textarea-widget');
+
         $('<textarea/>', {
             name: that.name,
             rows: that.rows,
@@ -1252,6 +1281,8 @@ IPA.table_widget = function (spec) {
 
         that.widget_create(container);
 
+        container.addClass('table-widget');
+
         that.table = $('<table/>', {
             'class': 'search-table'
         }).appendTo(container);
@@ -1602,149 +1633,227 @@ IPA.table_widget = function (spec) {
     return that;
 };
 
+IPA.combo_widget = function(spec) {
+
+    spec = spec || {};
+
+    var that = IPA.widget(spec);
+
+    that.editable = spec.editable;
+    that.searchable = spec.searchable;
+    that.list_size = spec.list_size || 5;
+
+    that.create = function(container) {
+
+        that.widget_create(container);
+
+        container.addClass('combo-widget');
+
+        $(document).keyup(function(e) {
+            if (e.which == 27) { // Escape
+                that.close();
+            }
+        });
+
+        that.input_container = $('<div/>', {
+            'class': 'combo-widget-input'
+        }).appendTo(container);
+
+        that.text = $('<label/>', {
+            name: that.name,
+            style: 'display: none;'
+        }).appendTo(that.input_container);
+
+        that.input = $('<input/>', {
+            type: 'text',
+            name: that.name,
+            title: that.tooltip,
+            readonly: !that.editable,
+            keyup: function() {
+                that.validate();
+            },
+            click: function() {
+                if (that.editable) return false;
+                if (that.is_open()) {
+                    that.close();
+                } else {
+                    that.open();
+                }
+                return false;
+            }
+        }).appendTo(that.input_container);
+
+        that.open_button = IPA.action_button({
+            name: 'open',
+            icon: 'expanded-icon',
+            click: function() {
+                if (that.is_open()) {
+                    that.close();
+                } else {
+                    that.open();
+                }
+                return false;
+            }
+        }).appendTo(that.input_container);
+
+        that.list_container = $('<div/>', {
+            'class': 'combo-widget-list'
+        }).appendTo(that.input_container);
+
+        var div = $('<div/>', {
+            style: 'position: relative; width: 100%;'
+        }).appendTo(that.list_container);
+
+        if (that.searchable) {
+            that.filter = $('<input/>', {
+                type: 'text',
+                name: 'filter',
+                keypress: function(e) {
+                    if (e.which == 13) { // Enter
+                        that.search();
+                    }
+                }
+            }).appendTo(div);
+
+            that.search_button = IPA.action_button({
+                name: 'search',
+                icon: 'search-icon',
+                click: function() {
+                    that.search();
+                    return false;
+                }
+            }).appendTo(div);
+
+            div.append('<br/>');
+        }
+
+        that.list = $('<select/>', {
+            name: 'list',
+            size: that.list_size,
+            style: 'width: 100%',
+            click: function(){
+                that.close();
+                var value = $('option:selected', that.list).val();
+                that.input.val(value);
+                IPA.select_range(that.input, 0, 0);
+
+                that.validate();
+                that.set_dirty(that.test_dirty());
+            }
+        }).appendTo(div);
+
+        if (that.undo) {
+            container.append(' ');
+            that.create_undo(container);
+
+            var undo = that.get_undo();
+            undo.click(function() {
+                that.reset();
+            });
+        }
+
+        that.create_error_link(container);
+
+        that.search();
+    };
+
+    that.open = function() {
+        that.list_container.css('visibility', 'visible');
+    };
+
+    that.close = function() {
+        that.list_container.css('visibility', 'hidden');
+    };
+
+    that.is_open = function() {
+        return that.list_container.css('visibility') == 'visible';
+    };
+
+    that.search = function() {
+    };
+
+    that.update = function() {
+        that.close();
+        if (that.writable) {
+            that.text.css('display', 'none');
+            that.input.css('display', 'inline');
+            that.input.val(that.values[0]);
+            that.open_button.css('display', 'inline');
+        } else {
+            that.text.css('display', 'inline');
+            that.text.html(that.values[0]);
+            that.input.css('display', 'none');
+            that.open_button.css('display', 'none');
+            that.input.val(that.values[0]);
+        }
+        if (that.searchable) {
+            that.filter.empty();
+            that.search();
+        }
+    };
+
+    that.save = function() {
+        var value = that.input.val();
+        return value === '' ? [] : [value];
+    };
+
+    that.create_option = function(text, value) {
+        return $('<option/>', {
+            text: text,
+            value: value
+        }).appendTo(that.list);
+    };
+
+    that.remove_options = function() {
+        that.list.empty();
+    };
+
+    return that;
+};
+
 IPA.entity_select_widget = function(spec) {
 
-    var that = IPA.widget(spec);
-    var entity = spec.entity || 'group';
-    var field_name = spec.field_name || 'cn';
-    var editable = spec.editable || false;
+    spec = spec || {};
+    spec.searchable = spec.searchable === undefined ? true : spec.searchable;
 
-    function populate_select(value) {
-        function find_success(result) {
-            $('option', that.entity_select).remove();
+    var that = IPA.combo_widget(spec);
 
-            // add default empty value
-            $('<option/>', {
-                text: '',
-                value: ''
-            }).
-            appendTo(that.entity_select);
+    that.other_entity = spec.other_entity;
+    that.other_field = spec.other_field;
 
-            var entities = result.result.result;
-            for (var i =0; i < result.result.count; i +=1){
-                var entity = entities[i];
-                var field_array = entity[field_name];
-                var field_value = field_array[0];
-                var option =
-                    $('<option/>',{
-                        text:field_value,
-                        value:field_value
-                    }).
-                    appendTo(that.entity_select);
-                if (value === field_value){
-                    option.attr('selected','selected');
-                }
-            }
-            that.set_dirty(that.test_dirty());
-        }
-        function find_error(err){
-        }
-        IPA.command({
-            entity: entity,
+    that.search = function() {
+
+        var filter = that.filter.val();
+
+        var command = IPA.command({
+            entity: that.other_entity,
             method: 'find',
-            args:[that.entity_filter.val()],
-            options:{},
-            on_success:find_success,
-            on_error:find_error
-        }).execute();
-    }
-
-    that.create = function(container) {
-
-        if (editable){
-            that.edit_box = $('<input />',{
-                type: 'text',
-                title: that.tooltip,
-                name: that.name,
-                keyup:function(){
-                    that.validate();
-                }
-            });
-
-            $('<div style:"display=block;" />').
-                append(that.edit_box).
-                appendTo(container);
-        }
-
-        that.create_error_link(container);
-
-        that.entity_select = $('<select/>', {
-            id: that.name + '-entity-select',
-            change: function(){
-                that.validate();
-                if (editable){
-                    that.edit_box.val(
-                        $('option:selected', that.entity_select).val());
-                    IPA.select_range(that.edit_box,0,0);
-                }
-                that.set_dirty(that.test_dirty());
-            }
-        }).appendTo(container);
-
-        that.entity_filter = $('<input/>', {
-            size:10,
-            type: 'text',
-            id: 'entity_filter',
-            style: 'display: none;',
-            keyup: function(){
-                populate_select(current_value());
-            }
-        }).appendTo(container);
-
-        $('<a/>', {
-            href: '',
-            text: 'add ' +entity + ' filter: ',
-            click: function() {
-                that.entity_filter.css('display','inline');
-                $(this).css('display','none');
-                return false;
-            }
-        }).appendTo(container);
-
-        if (that.undo) {
-            that.create_undo(container);
-        }
-        var undo = that.get_undo();
-        undo.click(function() {
-            that.reset();
+            args: [filter]
         });
 
-        populate_select();
-    };
+        command.on_success = function(data, text_status, xhr) {
 
-    that.reset = function() {
-        that.entity_filter.val(that.values[0]);
-        populate_select(that.values[0]);
-        if (editable){
-            that.edit_box.val(that.values[0]);
-        }
-        that.validate();
-        that.set_dirty(false);
-    };
+            that.remove_options();
 
-    that.load = function(record) {
-        var value = record[that.name];
-        if (value instanceof Array) {
-            that.values = value;
-        } else {
-            that.values = value ? [value] : [''];
-        }
-        that.reset();
-    };
+            that.create_option();
 
-    function current_value(){
-        var value;
-        if (editable){
-            value = that.edit_box.val();
-        }else{
-            value = $('option:selected', that.entity_select).val();
-        }
-        return value;
-    }
+            var entries = data.result.result;
+            for (var i=0; i<data.result.count; i++) {
+                var entry = entries[i];
+                var values = entry[that.other_field];
+                var value = values[0];
 
-    that.save = function() {
-        var value = current_value();
-        return [value];
+                var option = that.create_option(value, value);
+
+                if (filter === value) {
+                    option.attr('selected', 'selected');
+                }
+            }
+
+            that.set_dirty(that.test_dirty());
+        };
+
+        command.execute();
     };
 
     return that;
@@ -1759,9 +1868,8 @@ IPA.entity_link_widget = function(spec) {
     }
     that.other_pkeys = spec.other_pkeys || other_pkeys;
 
-    that.super_create = that.create;
     that.create = function(container) {
-        that.super_create(container);
+        that.widget_create(container);
         that.link =
         $('<a/>', {
             href: 'jslink',
@@ -1780,10 +1888,8 @@ IPA.entity_link_widget = function(spec) {
             appendTo(container);
     };
 
-    that.super_load = that.load;
-
     that.load = function (record){
-        that.super_load(record);
+        that.widget_load(record);
         if (that.values || that.values.length > 0){
             that.nonlink.html(that.values[0]);
             that.link.html(that.values[0]);
-- 
1.7.5.1

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

Reply via email to