Item Level Undo

    Also adding some unit tests for details.
    Using JQuery UI buttons for update and reset


This has the added benefit of letting the user know when the screen has been submitted, as the "undo" buttons go away.
From d6e723dcba77e1da9d67b01a397b6e9f863503f9 Mon Sep 17 00:00:00 2001
From: Adam Young <ayo...@redhat.com>
Date: Wed, 29 Sep 2010 14:58:30 -0400
Subject: [PATCH] Item Level Undo

Also adding some unit tests for details.
Using JQuery UI buttons for update and reset
---
 install/static/details.js                   |  145 +++++++++++++++++----------
 install/static/test/data/json_metadata.json |    2 +-
 install/static/test/details_tests.html      |   22 ++++
 install/static/test/details_tests.js        |   92 +++++++++++++++++
 4 files changed, 208 insertions(+), 53 deletions(-)
 create mode 100644 install/static/test/details_tests.html
 create mode 100644 install/static/test/details_tests.js

diff --git a/install/static/details.js b/install/static/details.js
index f68c773..0740f65 100644
--- a/install/static/details.js
+++ b/install/static/details.js
@@ -1,5 +1,6 @@
 /*  Authors:
  *    Pavel Zuna <pz...@redhat.com>
+ *    Adam Young <ayo...@redhat.com>
  *
  * Copyright (C) 2010 Red Hat
  * see file 'COPYING' for use and warranty information
@@ -39,8 +40,8 @@ function ipa_details_create(obj_name, dls, container)
 
     container.append('<div class="details-buttons"></div>');
     var jobj = container.children().last();
-    jobj.append('<a class="details-reset" href="jslink">Reset</a>');
-    jobj.append('<a class="details-update" href="jslink">Update</a>');
+    jobj.append('<a class="details-reset ui-state-default ui-corner-all input_link " href="jslink"><span class="ui-icon ui-icon-refresh" ></span> Reset</a>');
+    jobj.append('<a class="details-update ui-state-default ui-corner-all input_link  " href="jslink"><span class="ui-icon ui-icon-check" ></span>Update</a>');
 
     container.append('<hr />');
 
@@ -54,21 +55,23 @@ function ipa_details_create(obj_name, dls, container)
     jobj.append('<a href="#details-viewtype">Back to Top</a>');
 }
 
-var _ipa_h2_template = '<h2 onclick="_h2_on_click(this)">&#8722; I</h2>';
-var _ipa_dl_template = '<dl id="I" class="entryattrs"></dl>';
-var _ipa_dt_template = '<dt title="T">N:</dt>';
 
 function ipa_generate_dl(jobj, id, name, dts)
 {
     if (!dts)
         return;
 
-    var obj_name = jobj.parent().attr('title');
+    var parent = jobj.parent();
+    var obj_name = parent.attr('title');
 
-    jobj.after(_ipa_h2_template.replace('I', name));
-    jobj = jobj.next();
-    jobj.after(_ipa_dl_template.replace('I', id));
-    jobj = jobj.next();
+    parent.append($("<h2/>",{
+        click: function(){_h2_on_click(this)},
+        html:"&#8722; "+name
+    }));
+
+    var dl = $('<dl></dl>',{
+        id:id,
+        "class":"entryattrs"})
 
     for (var i = 0; i < dts.length; ++i) {
         var label = '';
@@ -79,12 +82,14 @@ function ipa_generate_dl(jobj, id, name, dts)
         }
         if ((!label) && (dts[i].length > 1))
             label = dts[i][1];
-        jobj.append(
-            _ipa_dt_template.replace('T', dts[i][0]).replace('N', label)
+        dl.append(
+            $('<dt/>',{
+                title:dts[i][0],
+                html:label+":"})
         );
     }
-
-    jobj.after('<hr />');
+    parent.append(dl);
+    parent.append('<hr/>');
 }
 
 function ipa_details_load(obj_name, pkey, on_win, on_fail, sampleData)
@@ -201,6 +206,7 @@ function ipa_details_update(obj_name, pkey, on_win, on_fail)
 var _ipa_a_add_template =
     '<a href="jslink" onclick="return (_ipa_add_on_click(this))" title="A">Add</a>';
 var _ipa_span_doc_template = '<span class="attrhint">Hint: D</span>';
+var _ipa_span_hint_template = '<span class="attrhint">Hint: D</span>';
 
 /* populate definition lists with the class 'entryattrs' with entry attributes
  *
@@ -239,26 +245,29 @@ function ipa_details_display(obj_name, entry_attrs)
         } else {
             /* title contains attribute name - default behaviour */
             var multivalue = false;
-            var hint_span = '';
+            var hint_span = null;
 
             var param_info = ipa_get_param_info(obj_name, attr);
             if (param_info) {
                 if (param_info['multivalue'] || param_info['class'] == 'List')
                     multivalue = true;
                 var hint = param_info['hint'];
-                if (hint)
-                    hint_span = _ipa_span_hint_template.replace('D', hint);
+                if (hint){
+                    hint_span = $("<span />",{
+                        "class":"attrhint",
+                        html:"Hint: " + hint});
+                }
             }
 
             var value = entry_attrs[attr];
             if (value) {
                 ipa_insert_first_dd(
-                    jobj, ipa_create_input(obj_name, attr, value[0]) + hint_span
+                    jobj, ipa_create_input(obj_name, attr, value[0],hint_span)
                 );
                 for (var i = 1; i < value.length; ++i) {
                     jobj = jobj.next();
                     ipa_insert_other_dd(
-                      jobj, ipa_create_input(obj_name, attr, value[i])
+                      jobj, ipa_create_input(obj_name, attr, value[i],hint_span)
                     );
                 }
                 if (multivalue) {
@@ -269,11 +278,11 @@ function ipa_details_display(obj_name, entry_attrs)
             } else {
                 if (multivalue) {
                     ipa_insert_first_dd(
-                        jobj, _ipa_a_add_template.replace('A', attr) + hint_span
+                        jobj, _ipa_a_add_template.replace('A', attr) /*.append( hint_span)*/
                     );
                 } else {
                     ipa_insert_first_dd(
-                        jobj, ipa_create_input(obj_name, attr, '') + hint_span
+                        jobj, ipa_create_input(obj_name, attr, '')/*.append( hint_span)*/
                     );
                 }
             }
@@ -281,18 +290,16 @@ function ipa_details_display(obj_name, entry_attrs)
     });
 }
 
-var _ipa_dd_first_template = '<dd class="first">I</dd>';
 
 function ipa_insert_first_dd(jobj, content)
 {
-    jobj.after(_ipa_dd_first_template.replace('I', content));
-}
+    jobj.after( $('<dd class="first"></dd>').append(content))
 
-var _ipa_dd_other_template = '<dd class="other">I</dd>';
+}
 
 function ipa_insert_other_dd(jobj, content)
 {
-    jobj.after(_ipa_dd_other_template.replace('I', content));
+    jobj.after($('<dd class="other"></dd>').append(content));
 }
 
 
@@ -308,32 +315,37 @@ var _ipa_param_type_2_handler_map = {
  * arguments:
  *   attr - LDAP attribute name
  *   value - the attributes value */
-function ipa_create_input(obj_name, attr, value)
+function ipa_create_input(obj_name, attr, value,hint)
 {
+    var input = $("<label>",{html:value.toString()});
     var param_info = ipa_get_param_info(obj_name, attr);
     if (!param_info) {
         /* no information about the param is available, default to text input */
-        return (_ipa_create_text_input(attr, value, null));
-    }
-
-    /* check if the param value can be modified */
-    if (param_info['primary_key'] || ('no_update' in param_info['flags']))
-        return (value.toString());
-
-    /* call handler by param class */
-    var handler = _ipa_param_type_2_handler_map[param_info['class']];
-    if (handler) {
-        if (param_info['multivalue'] || param_info['class'] == 'List') {
-            return (
-                handler(attr, value, param_info) +
-                    _ipa_create_remove_link(attr, param_info)
-            );
+        input = _ipa_create_text_input(attr, value, null);
+        if (hint){
+            input.after(hint);
+        }
+    }else if (param_info['primary_key'] || 
+              ('no_update' in param_info['flags'])){
+        /* check if the param value can be modified */
+        input = (value.toString());
+        var input = $("<label>",{html:value.toString()});
+    }else{
+        /* call handler by param class */
+        var handler = _ipa_param_type_2_handler_map[param_info['class']];
+        if (handler) {
+            if (param_info['multivalue'] || param_info['class'] == 'List') {
+                input = handler(attr, value, param_info) +
+                    _ipa_create_remove_link(attr, param_info);
+            }else{
+                input =  (handler(attr, value, param_info));
+                if (hint){
+                    input.after(hint);
+                }
+            }
         }
-        return (handler(attr, value, param_info));
     }
-
-    /* no handler for this type? don't allow modification */
-    return (value.toString());
+    return input;
 }
 
 /* HTML template for _ipa_create_remove_link() */
@@ -361,17 +373,46 @@ var _ipa_input_text_template =
 /* creates a input box for editing a string attribute */
 function _ipa_create_text_input(attr, value, param_info)
 {
-    return (
-        _ipa_input_text_template.replace('A', attr).replace(
-            'V', value.toString()
-        )
-    );
+    return $("<input/>",{
+        type:"text",
+        name:attr,
+        value:value.toString(),
+        change: function(){
+            var validation_info=param_info;
+            var undo_link=this.nextElementSibling;
+            undo_link.style.display ="inline";
+            if(false){
+                var error_link = undo_link.nextElementSibling;
+                error_link.style.display ="block";
+            }
+        }
+    }).after($("<a/>",{
+        html:"undo",
+        "class":"ui-state-highlight ui-corner-all",
+        style:"display:none",
+        click: function(){
+            var key = this.previousElementSibling.name;
+            var entity_divs = $(this).parents('.details-container');
+            var entry_attrs = ipa_details_cache[entity_divs[0].id];
+            var previous_value = entry_attrs[key];
+            if (previous_value){
+                this.previousElementSibling.value =  previous_value;
+            }
+            this.style.display = "none";
+        }
+    })).after($("<span/>",{
+        html:"Does not match pattern",
+        "class":"ui-state-error ui-corner-all",
+        style:"display:none",
+    }));
+
 }
 
 function ipa_details_reset(obj_name)
 {
-    if (ipa_details_cache[obj_name])
+    if (ipa_details_cache[obj_name]){
         ipa_details_display(obj_name, ipa_details_cache[obj_name]);
+    }
 
 }
 
diff --git a/install/static/test/data/json_metadata.json b/install/static/test/data/json_metadata.json
index ef8c77b..b4f9798 100644
--- a/install/static/test/data/json_metadata.json
+++ b/install/static/test/data/json_metadata.json
@@ -3103,7 +3103,7 @@
                         "doc": "User login",
                         "exclude": null,
                         "flags": [],
-                        "hint": null,
+                        "hint": "Numeric user Identifer",
                         "include": null,
                         "label": "User login",
                         "length": null,
diff --git a/install/static/test/details_tests.html b/install/static/test/details_tests.html
new file mode 100644
index 0000000..e1b3525
--- /dev/null
+++ b/install/static/test/details_tests.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Details Test Suite</title>
+    <link rel="stylesheet" href="qunit.css" type="text/css" media="screen">
+    <script type="text/javascript" src="qunit.js"></script>
+    <script type="text/javascript" src="../jquery.js"></script>
+    <script type="text/javascript" src="../jquery.ba-bbq.js"></script>
+    <script type="text/javascript" src="../jquery-ui.js"></script>
+    <script type="text/javascript" src="../ipa.js"></script>
+    <script type="text/javascript" src="../details.js"></script>
+    <script type="text/javascript" src="details_tests.js"></script>
+</head>
+<body>
+    <h1 id="qunit-header">Details Test Suite</h1>
+    <h2 id="qunit-banner"></h2>
+    <div id="qunit-testrunner-toolbar"></div>
+    <h2 id="qunit-userAgent"></h2>
+    <ol id="qunit-tests"></ol>
+    <div id="qunit-fixture">test markup</div>
+</body>
+</html>
diff --git a/install/static/test/details_tests.js b/install/static/test/details_tests.js
new file mode 100644
index 0000000..ee5d396
--- /dev/null
+++ b/install/static/test/details_tests.js
@@ -0,0 +1,92 @@
+/*  Authors:
+ *    Adam Young <ayo...@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 only
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+
+test("Testing ipa_details_create().", function() {
+
+    var details = [
+        ['identity', 'Entity Details', [
+            ['cn', 'Entity Name'],
+            ['description', 'Description'],
+            ['number', 'Entity ID']
+        ]]
+    ];
+
+    var identity = details[0];
+    var attrs=identity[2];
+    var key = 'entity';
+
+    var container = $("<div/>",{id: "container"});
+    ipa_details_create(key, details, container)
+
+    same(container[0].title,key);
+    var dl = container.find('dl#identity');
+    ok(dl );
+
+    same(dl[0].children.length, attrs.length);
+
+});
+
+
+test("Testing  _ipa_create_text_input().", function(){
+
+    var name = "name";
+    var value="value";
+    var input = _ipa_create_text_input(name, value);
+    ok(input,"input not null");
+
+    same(input[0].name,name );
+    same(input[0].value,value );
+    same(input[0].type,"text" );
+});
+
+
+
+test("Testing ipa_generate_dl()",function(){
+
+    var details = [
+        ['cn', 'Entity Name'],
+        ['description', 'Description'],
+        ['number', 'Entity ID']
+    ];
+    var name = 'NAMENAMENAME';
+    var identity = 'IDIDID';
+    var parent = $("<div/>");
+    var jobj = $("<div title='entity'/>");
+    parent.append(jobj);
+    ipa_generate_dl(jobj, identity,name, details);
+
+    ok(parent.find('hr'));
+
+    var h2= parent.find('h2');
+    ok(h2);
+    ok(h2[0].innerHTML.indexOf(name) > 1,"find name in html");
+
+    var dl = parent.find('dl');
+    ok(dl);
+    same(dl[0].children.length,3);
+    same(dl[0].id, identity);
+    same(dl[0].children[0].title,details[0][0]);
+    same(dl[0].children[0].innerHTML,details[0][1]+":");
+    same(dl[0].children[2].title,details[2][0]);
+    same(dl[0].children[2].innerHTML,details[2][1]+":");
+
+});
\ No newline at end of file
-- 
1.7.1

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

Reply via email to