[Freeipa-devel] [PATCH] extract shared dyamic edit code
Kevin McCarthy
kmccarth at redhat.com
Fri Sep 28 18:58:59 UTC 2007
No new code here, just extracting shared code so I can use it on the
useredit page too.
Depends on:
freeipa-221-groupedit_use_dns.patch
freeipa-222-nestedgroups.patch
freeipa-225-editgroupui.patch
freeipa-226-groupmember_sorting.patch
-Kevin
-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1191005756 25200
# Node ID 27fb698fd454fe04913c9074c790c3163ca83d47
# Parent ea4707434a517839c30c6f88f6ad302e91189e48
Extract the shared dynamic edit code.
Rename groupeditsearch.kid to dynamiceditsearch.kid
diff -r ea4707434a51 -r 27fb698fd454 ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py Fri Sep 28 09:59:04 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py Fri Sep 28 11:55:56 2007 -0700
@@ -444,13 +444,11 @@ class Root(controllers.RootController):
turbogears.flash("Group add failed: " + str(e) + "<br/>" + str(e.detail))
return dict(form=group_new_form, tg_template='ipagui.templates.groupnew')
- @expose("ipagui.templates.groupeditsearch")
+ @expose("ipagui.templates.dynamiceditsearch")
@identity.require(identity.not_anonymous())
def groupedit_search(self, **kw):
"""Searches for users+groups and displays list of results in a table.
- This method is used for the ajax search on the group edit page.
- It's not re-usable because the ajax/dom manipulation is tightly
- bound to the groupedit page"""
+ This method is used for the ajax search on the group edit page."""
client.set_krbccache(os.environ["KRB5CCNAME"])
users = []
groups = []
diff -r ea4707434a51 -r 27fb698fd454 ipa-server/ipa-gui/ipagui/static/javascript/dynamicedit.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/static/javascript/dynamicedit.js Fri Sep 28 11:55:56 2007 -0700
@@ -0,0 +1,171 @@
+/**
+ * dynamicedit.js
+ *
+ * Shared code, data, and functions for the dynamic add/remove lists on the
+ * edit group/user pages.
+ *
+ * These functions have specific expectations of the page they are used on:
+ *
+ * - If you want to preserve the dn_to_info_hash on round trip:
+ * - The form must have a 'form_dn_to_info_json' hidden field.
+ * - The form must have onsubmit="preSubmit()" set in its tag.
+ * - Restoring the contents of add/remove lists on round trip unfortunately
+ * can't be shared because it is a mixture of python and javascript. See
+ * the bottom part editgroup.kid for example code on this.
+ *
+ * - The page must have a div: 'newmembers'
+ * that new members are dynamically added to.
+ *
+ * - The page must have a div: 'delmembers'
+ * that removed members are dynamically added to.
+ *
+ * - Hidden fields called 'dnadd' and 'dndel' will be dynamically created,
+ * holding the values of the 'dn' passed to addmember() and removemember()
+ *
+ * Other Notes:
+ *
+ * - Many of the fields refer to 'dn'. There is no intrinsic reason this has
+ * to be a dn (it can hold any "unique id" for the objects to add/remove)
+ *
+ * - Similarly, the word 'member' is used because the code was originally
+ * written for editgroup. A 'member' is just a 'thing' to add/remove.
+ * On the useredit pages, for example, a 'member' is actually a group.
+ */
+
+// Stored as the values in the dn_to_info_hash
+MemberDisplayInfo = Class.create();
+MemberDisplayInfo.prototype = {
+ initialize: function(name, descr, type) {
+ this.name = name;
+ this.descr = descr;
+ this.type = type;
+ },
+};
+
+
+// this is used for round-trip recontruction of the names.
+// the hidden fields only contain dns.
+var dn_to_info_hash = new Hash();
+
+// used to filter search results.
+// records dns already in the group
+var member_hash = new Hash();
+
+// used to prevent double adding
+// records dns to be added
+var added_hash = new Hash();
+
+// Tracks the div ids that each member belongs to.
+// Since dn's will contain illegal characters for div ids, this is used
+// to map them to the correct div
+var dn_to_member_div_id = new Hash();
+
+
+
+/*
+ * Renders the information about the member into the passed in
+ * element. This is used by addmember and removemember to
+ * consistently create the dom for the member information
+ * (name, descr) and add icons/font changes correct for each type.
+ */
+function renderMemberInfo(newdiv, info) {
+ if (info.type == "user") {
+ newdiv.appendChild(document.createTextNode(
+ info.name.escapeHTML() + " " + info.descr.escapeHTML() + " "));
+ } else if (info.type == "group") {
+ ital = document.createElement('i');
+ ital.appendChild(document.createTextNode(
+ info.name.escapeHTML() + " " +
+ info.descr.escapeHTML() + " "));
+ newdiv.appendChild(ital);
+ }
+}
+
+/*
+ * Callback used for afterFinish in scriptaculous effect
+ */
+function removeElement(effect) {
+ Element.remove(effect.element);
+}
+
+function addmember(dn, info) {
+ dn_to_info_hash[dn] = info;
+
+ if ((added_hash[dn] == 1) || (member_hash[dn] == 1)) {
+ return null;
+ }
+ added_hash[dn] = 1;
+
+ var newdiv = document.createElement('div');
+ renderMemberInfo(newdiv, info);
+
+ var undolink = document.createElement('a');
+ undolink.setAttribute('href', '');
+ undolink.setAttribute('onclick',
+ 'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
+ 'added_hash.remove("' + jsStringEscape(dn) + '");' +
+ 'return false;');
+ undolink.appendChild(document.createTextNode("undo"));
+ newdiv.appendChild(undolink);
+
+ var dnInfo = document.createElement('input');
+ dnInfo.setAttribute('type', 'hidden');
+ dnInfo.setAttribute('name', 'dnadd');
+ dnInfo.setAttribute('value', dn);
+ newdiv.appendChild(dnInfo);
+
+ newdiv.style.display = 'none';
+ $('newmembers').appendChild(newdiv);
+
+ return newdiv
+}
+
+function addmemberHandler(element, dn, info) {
+ var newdiv = addmember(dn, info)
+ if (newdiv != null) {
+ new Effect.Fade(Element.up(element));
+ new Effect.Appear(newdiv);
+ /* Element.up(element).remove(); */
+ }
+}
+
+function removemember(dn, info) {
+ dn_to_info_hash[dn] = info;
+
+ var newdiv = document.createElement('div');
+ renderMemberInfo(newdiv, info);
+
+ orig_div_id = dn_to_member_div_id[dn];
+ var undolink = document.createElement('a');
+ undolink.setAttribute('href', '');
+ undolink.setAttribute('onclick',
+ 'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
+ "new Effect.Appear($('" + orig_div_id + "'));" +
+ 'return false;');
+ undolink.appendChild(document.createTextNode("undo"));
+ newdiv.appendChild(undolink);
+
+ var dnInfo = document.createElement('input');
+ dnInfo.setAttribute('type', 'hidden');
+ dnInfo.setAttribute('name', 'dndel');
+ dnInfo.setAttribute('value', dn);
+ newdiv.appendChild(dnInfo);
+
+ newdiv.style.display = 'none';
+ $('delmembers').appendChild(newdiv);
+
+ return newdiv
+}
+
+function removememberHandler(element, dn, info) {
+ var newdiv = removemember(dn, info);
+ new Effect.Fade(Element.up(element));
+ new Effect.Appear(newdiv);
+ /* Element.up(element).remove(); */
+}
+
+function preSubmit() {
+ var json = dn_to_info_hash.toJSON();
+ $('form_dn_to_info_json').value = json;
+ return true;
+}
diff -r ea4707434a51 -r 27fb698fd454 ipa-server/ipa-gui/ipagui/templates/dynamiceditsearch.kid
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/templates/dynamiceditsearch.kid Fri Sep 28 11:55:56 2007 -0700
@@ -0,0 +1,79 @@
+<div xmlns:py="http://purl.org/kid/ns#">
+
+<?python
+from ipagui.helpers import ipahelper
+#
+# This file is used to render the results from an AJAX search onto a page.
+# It has many expectations of the page being rendered into:
+# - Source page must have included dynamicedit.js and followed all of its
+# requirements
+#
+?>
+ <div id="search-results-count">
+ </div>
+ <?python
+ criteria_esc = ipahelper.javascript_string_escape(criteria)
+ ?>
+ <script type="text/javascript">
+ search_string = "${criteria_esc}";
+ results_counter = 0;
+ </script>
+ <?python search_div_counter = 1 ?>
+ <div py:for="entities in (users, groups)">
+ <div py:if='(entities != None) and (len(entities) > 0)'>
+ <div py:for="entity in entities" id="search-${search_div_counter}">
+ <?python
+ ent_dn_esc = ipahelper.javascript_string_escape(entity.dn)
+ ent_uid = entity.uid
+ if ent_uid:
+ ent_name = "%s %s" % (entity.givenName, entity.sn)
+ ent_descr = "(%s)" % entity.uid
+ ent_type = "user"
+ else:
+ ent_name = entity.cn
+ ent_descr = "[group]"
+ ent_type = "group"
+ ent_name_esc = ipahelper.javascript_string_escape(ent_name)
+ ent_descr_esc = ipahelper.javascript_string_escape(ent_descr)
+ ent_type_esc = ipahelper.javascript_string_escape(ent_type)
+ ?>
+ <span id="search-info-${search_div_counter}"></span>
+ <script type="text/javascript">
+ if ((added_hash["${ent_dn_esc}"] == 1) ||
+ (member_hash["${ent_dn_esc}"] == 1)) {
+ $("search-${search_div_counter}").style.display = 'none';
+ } else {
+ results_counter = results_counter + 1;
+ }
+
+ renderMemberInfo($('search-info-${search_div_counter}'),
+ new MemberDisplayInfo('${ent_name_esc}',
+ '${ent_descr_esc}',
+ '${ent_type_esc}'));
+ </script>
+ <a href=""
+ onclick="addmemberHandler(this, '${ent_dn_esc}',
+ new MemberDisplayInfo('${ent_name_esc}',
+ '${ent_descr_esc}',
+ '${ent_type_esc}'));
+ return false;"
+ >add</a>
+ <?python
+ search_div_counter = search_div_counter + 1
+ ?>
+ </div>
+ </div>
+ </div>
+ <script type="text/javascript">
+ if (results_counter == 0) {
+ var message = "No results found for " + search_string;
+ } else {
+ var message = results_counter + " results found:";
+ }
+ $('search-results-count').appendChild(document.createTextNode(message));
+ </script>
+ <script py:if="counter < 0">
+ $('search-results-count').appendChild(document.createTextNode(
+ " (truncated)"));
+ </script>
+</div>
diff -r ea4707434a51 -r 27fb698fd454 ipa-server/ipa-gui/ipagui/templates/groupeditform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid Fri Sep 28 09:59:04 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid Fri Sep 28 11:55:56 2007 -0700
@@ -7,40 +7,12 @@ from ipagui.helpers import ipahelper
from ipagui.helpers import ipahelper
?>
+ <script type="text/javascript" charset="utf-8"
+ src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
<?python searchurl = tg.url('/groupedit_search') ?>
<script type="text/javascript">
-
- // Stored as the values in the dn_to_info_hash
- MemberDisplayInfo = Class.create();
- MemberDisplayInfo.prototype = {
- initialize: function(name, descr, type) {
- this.name = name;
- this.descr = descr;
- this.type = type;
- },
- };
-
-
- // this is used for round-trip recontruction of the names.
- // the hidden fields only contain dns.
- var dn_to_info_hash = new Hash();
-
- // used to filter search results.
- // records dns already in the group
- var member_hash = new Hash();
-
- // used to prevent double adding
- // records dns to be added
- var added_hash = new Hash();
-
- // Tracks the div ids that each member belongs to.
- // Since dn's will contain illegal characters for div ids, this is used
- // to map them to the correct div
- var dn_to_member_div_id = new Hash();
-
-
function toggleProtectedFields(checkbox) {
var gidnumberField = $('form_gidnumber');
if (checkbox.checked) {
@@ -50,108 +22,6 @@ from ipagui.helpers import ipahelper
gidnumberField.disabled = true;
$('form_editprotected').value = '';
}
- }
-
- /*
- * Renders the information about the member into the passed in
- * element. This is used by addmember and removemember to
- * consistently create the dom for the member information
- * (name, descr) and add icons/font changes correct for each type.
- */
- function renderMemberInfo(newdiv, info) {
- if (info.type == "user") {
- newdiv.appendChild(document.createTextNode(
- info.name.escapeHTML() + " " + info.descr.escapeHTML() + " "));
- } else if (info.type == "group") {
- ital = document.createElement('i');
- ital.appendChild(document.createTextNode(
- info.name.escapeHTML() + " " +
- info.descr.escapeHTML() + " "));
- newdiv.appendChild(ital);
- }
- }
-
- /*
- * Callback used for afterFinish in scriptaculous effect
- */
- function removeElement(effect) {
- Element.remove(effect.element);
- }
-
- function addmember(dn, info) {
- dn_to_info_hash[dn] = info;
-
- if ((added_hash[dn] == 1) || (member_hash[dn] == 1)) {
- return null;
- }
- added_hash[dn] = 1;
-
- var newdiv = document.createElement('div');
- renderMemberInfo(newdiv, info);
-
- var undolink = document.createElement('a');
- undolink.setAttribute('href', '');
- undolink.setAttribute('onclick',
- 'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
- 'added_hash.remove("' + jsStringEscape(dn) + '");' +
- 'return false;');
- undolink.appendChild(document.createTextNode("undo"));
- newdiv.appendChild(undolink);
-
- var dnInfo = document.createElement('input');
- dnInfo.setAttribute('type', 'hidden');
- dnInfo.setAttribute('name', 'dnadd');
- dnInfo.setAttribute('value', dn);
- newdiv.appendChild(dnInfo);
-
- newdiv.style.display = 'none';
- $('newmembers').appendChild(newdiv);
-
- return newdiv
- }
-
- function addmemberHandler(element, dn, info) {
- var newdiv = addmember(dn, info)
- if (newdiv != null) {
- new Effect.Fade(Element.up(element));
- new Effect.Appear(newdiv);
- /* Element.up(element).remove(); */
- }
- }
-
- function removemember(dn, info) {
- dn_to_info_hash[dn] = info;
-
- var newdiv = document.createElement('div');
- renderMemberInfo(newdiv, info);
-
- orig_div_id = dn_to_member_div_id[dn];
- var undolink = document.createElement('a');
- undolink.setAttribute('href', '');
- undolink.setAttribute('onclick',
- 'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
- "new Effect.Appear($('" + orig_div_id + "'));" +
- 'return false;');
- undolink.appendChild(document.createTextNode("undo"));
- newdiv.appendChild(undolink);
-
- var dnInfo = document.createElement('input');
- dnInfo.setAttribute('type', 'hidden');
- dnInfo.setAttribute('name', 'dndel');
- dnInfo.setAttribute('value', dn);
- newdiv.appendChild(dnInfo);
-
- newdiv.style.display = 'none';
- $('delmembers').appendChild(newdiv);
-
- return newdiv
- }
-
- function removememberHandler(element, dn, info) {
- var newdiv = removemember(dn, info);
- new Effect.Fade(Element.up(element));
- new Effect.Appear(newdiv);
- /* Element.up(element).remove(); */
}
function enterDoSearch(e) {
@@ -177,12 +47,6 @@ from ipagui.helpers import ipahelper
parameters: { criteria: $('criteria').value },
evalScripts: true });
return false;
- }
-
- function preSubmit() {
- var json = dn_to_info_hash.toJSON();
- $('form_dn_to_info_json').value = json;
- return true;
}
</script>
diff -r ea4707434a51 -r 27fb698fd454 ipa-server/ipa-gui/ipagui/templates/groupeditsearch.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupeditsearch.kid Fri Sep 28 09:59:04 2007 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-<div xmlns:py="http://purl.org/kid/ns#">
-
-<?python
-from ipagui.helpers import ipahelper
-?>
- <div id="search-results-count">
- </div>
- <?python
- criteria_esc = ipahelper.javascript_string_escape(criteria)
- ?>
- <script type="text/javascript">
- search_string = "${criteria_esc}";
- results_counter = 0;
- </script>
- <?python search_div_counter = 1 ?>
- <div py:for="entities in (users, groups)">
- <div py:if='(entities != None) and (len(entities) > 0)'>
- <div py:for="entity in entities" id="search-${search_div_counter}">
- <?python
- ent_dn_esc = ipahelper.javascript_string_escape(entity.dn)
- ent_uid = entity.uid
- if ent_uid:
- ent_name = "%s %s" % (entity.givenName, entity.sn)
- ent_descr = "(%s)" % entity.uid
- ent_type = "user"
- else:
- ent_name = entity.cn
- ent_descr = "[group]"
- ent_type = "group"
- ent_name_esc = ipahelper.javascript_string_escape(ent_name)
- ent_descr_esc = ipahelper.javascript_string_escape(ent_descr)
- ent_type_esc = ipahelper.javascript_string_escape(ent_type)
- ?>
- <span id="search-info-${search_div_counter}"></span>
- <script type="text/javascript">
- if ((added_hash["${ent_dn_esc}"] == 1) ||
- (member_hash["${ent_dn_esc}"] == 1)) {
- $("search-${search_div_counter}").style.display = 'none';
- } else {
- results_counter = results_counter + 1;
- }
-
- renderMemberInfo($('search-info-${search_div_counter}'),
- new MemberDisplayInfo('${ent_name_esc}',
- '${ent_descr_esc}',
- '${ent_type_esc}'));
- </script>
- <a href=""
- onclick="addmemberHandler(this, '${ent_dn_esc}',
- new MemberDisplayInfo('${ent_name_esc}',
- '${ent_descr_esc}',
- '${ent_type_esc}'));
- return false;"
- >add</a>
- <?python
- search_div_counter = search_div_counter + 1
- ?>
- </div>
- </div>
- </div>
- <script type="text/javascript">
- if (results_counter == 0) {
- var message = "No results found for " + search_string;
- } else {
- var message = results_counter + " results found:";
- }
- $('search-results-count').appendChild(document.createTextNode(message));
- </script>
- <script py:if="counter < 0">
- $('search-results-count').appendChild(document.createTextNode(
- " (truncated)"));
- </script>
-</div>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 4054 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20070928/89d6c7a5/attachment.bin>
More information about the Freeipa-devel
mailing list