summaryrefslogtreecommitdiffstats
path: root/ipa-server/ipa-gui/ipagui/static/javascript/dynamicedit.js
blob: b25fb6c4adcfdcd0078f9c916950c2ba1c184044 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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;
}