Merge commit 'a4cb4d96face514924387d34746b3148848ac092' into zope-2.13
[Plinn.git] / skins / ajax_scripts / widget_form_manager.js
1 // © 2009 Benoît Pin
2 // http://plinn.org
3 // Licence GPL
4 //
5 //
6
7 var WidgetBasedFormManager;
8
9 (function(){
10 WidgetBasedFormManager = function(widgets, editingArea, dataArea, dataAreaSpecs, afterShow) {
11 /* widgets : {'add':element, 'edit':element} element targets nodes to clone.
12 * editingArea : surrounding element where form is
13 * dataArea : element where data are
14 * dataAreaSpecs : by default, param used to indicate the total number of columns
15 * afterShow : function called after a widget insertion
16 */
17 var thisWgtManager = this;
18 this.widgets = widgets;
19 this.openedWidget = null;
20 this.dataArea = dataArea;
21 this.dataAreaSpecs = dataAreaSpecs;
22 this.afterShow = afterShow;
23
24 var form = editingArea.getElementsByTagName('form')[0];
25 this.form = form;
26 var fm = new FormManager(form);
27 fm.onBeforeSubmit = function(fm, evt){return thisWgtManager.onBeforeSubmit(fm, evt);};
28 fm.onResponseLoad = function(req){thisWgtManager.loadResponse(req);};
29
30 addListener(this.form, 'click', function(evt){thisWgtManager.clickHandler(evt);});
31
32 };
33
34 WidgetBasedFormManager.prototype.showAddWidget = function(dest) {
35 if (this.openedWidget)
36 return;
37 var wdgtCopy = this.widgets['add'].cloneNode(true);
38 wdgtCopy.removeAttribute('id');
39 this.openedWidget = wdgtCopy;
40 dest.appendChild(wdgtCopy);
41 if (this.addButton)
42 this.addButton.style.visibility = 'hidden';
43 if (this.afterShow)
44 this.afterShow(this);
45 };
46
47 WidgetBasedFormManager.prototype.showPopulatedWidget = function(dest, url) {
48 var req = new XMLHttpRequest();
49 req.open("GET", url, false);
50 showProgressImage();
51 req.send(null);
52 hideProgressImage();
53
54 if (req.status != 200){
55 alert(req.status);
56 return;
57 }
58
59 var wdgtCopy = this.widgets['edit'].cloneNode(true);
60 wdgtCopy.removeAttribute('id');
61 var tmpForm = document.createElement('form');
62 tmpForm.appendChild(wdgtCopy);
63
64 var fields = req.responseXML.documentElement.childNodes;
65 var input, field, value;
66 for (var i = 0 ; i<fields.length; i++) {
67 field = fields[i];
68 if (!field.firstChild)
69 continue;
70
71 value = field.firstChild.nodeValue;
72 input = tmpForm.elements.namedItem(field.nodeName);
73
74 switch (input.tagName) {
75 case 'INPUT':
76 input.value = value;
77 break;
78 case 'TEXTAREA':
79 input.appendChild(document.createTextNode(value));
80 }
81 }
82 dest.appendChild(wdgtCopy);
83 if (this.afterShow)
84 this.afterShow(this);
85 };
86
87 WidgetBasedFormManager.prototype.cancelWidget = function() {
88 var parent = this.openedWidget.parentNode;
89 parent.removeChild(this.openedWidget);
90 this.openedWidget = null;
91 if (this.addButton)
92 this.addButton.style.visibility = 'visible';
93 if (this.previousRecState) {
94 this.previousRecState.style.display = '';
95 this.previousRecState = null;
96 }
97 };
98
99 WidgetBasedFormManager.prototype.updateEditedRecord = function(node) {
100 var parent = this.openedWidget.parentNode;
101 parent.removeChild(this.openedWidget);
102 this.openedWidget = null;
103 if (this.addButton)
104 this.addButton.style.visibility = 'visible';
105
106 parent = this.previousRecState.parentNode;
107 parent.replaceChild(node, this.previousRecState);
108 };
109
110 WidgetBasedFormManager.prototype.clickHandler = function(evt) {
111 var target = getTargetedObject(evt);
112 if (target.tagName == 'IMG') {
113 var parent = target.parentNode;
114 if (parent.tagName == 'A') {
115 switch (parent.name) {
116 case 'add' :
117 disableDefault(evt);
118 disablePropagation(evt);
119 parent.blur();
120 this.addButton = parent;
121 this.showAddWidget(this.form);
122 break;
123 case 'rm' :
124 disableDefault(evt);
125 disablePropagation(evt);
126 this.deleteRecord(parent);
127 break;
128 case 'edit' :
129 disableDefault(evt);
130 disablePropagation(evt);
131 if (!this.openedWidget) {
132 var rec = this._storePreviousState(parent);
133 var container = this._prepareEditingContainer(rec);
134 this.showPopulatedWidget(container, parent.href);
135 }
136 break;
137 }
138 }
139 }
140 };
141
142 WidgetBasedFormManager.prototype._storePreviousState = function(recChild) {
143 var rec = recChild;
144 while(!(this.isRootRecordElement(rec)))
145 rec = rec.parentNode;
146 rec.style.display = 'none';
147 this.previousRecState = rec;
148 return rec
149 };
150
151 WidgetBasedFormManager.prototype._prepareEditingContainer = function(rec) {
152 /* default behaviour. May be redefined by an instance */
153 var tbody = document.createElement('tbody');
154 var tr = document.createElement('tr');
155 var td = document.createElement('td')
156 td.colSpan = this.dataAreaSpecs;
157
158 tbody.appendChild(tr);
159 tr.appendChild(td)
160
161 if (rec.nextSibling)
162 rec.parentNode.insertBefore(tbody, rec.nextSibling);
163 else
164 rec.parentNode.appendChild(tbody);
165
166 this.openedWidget = tbody;
167 return td
168 };
169
170
171
172 WidgetBasedFormManager.prototype.deleteRecord = function(link) {
173 var req = new XMLHttpRequest();
174
175 var thisManager = this;
176 req.onreadystatechange = function() {
177 switch (req.readyState) {
178 case 1 :
179 showProgressImage();
180 break;
181 case 4 :
182 hideProgressImage();
183 if (req.status == 200)
184 thisManager._deleteHtmlRecord(req, link);
185 else
186 alert('Error: ' + req.status);
187 };
188 };
189 var url = link.href;
190 req.open("POST", url, true);
191 req.send(null);
192 };
193
194
195 WidgetBasedFormManager.prototype._deleteHtmlRecord = function(req, link) {
196 var doc = req.responseXML.documentElement;
197 switch (doc.nodeName) {
198 case 'done':
199 var rec = link.parentNode;
200 while(!(this.isRootRecordElement(rec)))
201 rec = rec.parentNode;
202 this.dataArea.removeChild(rec);
203 break;
204 case 'error':
205 alert(doc.firstChild.nodeValue);
206 break;
207 }
208 };
209
210 WidgetBasedFormManager.prototype.isRootRecordElement = function(e) {
211 /* default behaviour. May be redefined by an instance */
212 return (e.tagName == 'TBODY')
213 };
214
215 WidgetBasedFormManager.prototype.onBeforeSubmit = function(fm, evt) {
216 if (fm.submitButton.name == 'cancel'){
217 this.cancelWidget();
218 return 'cancelSubmit';
219 }
220 };
221
222
223 WidgetBasedFormManager.prototype.loadResponse = function(req) {
224 if (req.status == 200) {
225 var doc = req.responseXML.documentElement;
226 switch (doc.nodeName) {
227 case 'computedField':
228 switch(doc.getAttribute('type')) {
229 case 'added' :
230 this.cancelWidget();
231 this.dataArea.appendChild(getCopyOfNode(doc.firstChild));
232 break;
233
234 case 'edited' :
235 this.updateEditedRecord(getCopyOfNode(doc.firstChild));
236 }
237 break;
238
239 case 'error':
240 alert(doc.firstChild.nodeValue);
241 break;
242
243 case 'fragments' :
244 var fragments = req.responseXML.documentElement.childNodes;
245 var fragment, dest, scripts;
246 for (var i=0 ; i<fragments.length ; i++) {
247 fragment = fragments[i];
248 if (fragment.nodeName == 'fragment') {
249 dest = document.getElementById(fragment.getAttribute('id'));
250 dest.innerHTML = fragment.firstChild.nodeValue;
251
252 scripts = dest.getElementsByTagName('script');
253 for (var j=0 ; j < scripts.length ; j++)
254 globalScriptRegistry.loadScript(scripts[j]);
255 }
256 }
257 break;
258 }
259 }
260 else
261 alert(req.statut);
262 };
263
264 })();