adhearsion 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.version +1 -1
  2. data/CHANGELOG +43 -25
  3. data/Rakefile +0 -5
  4. data/TODO +51 -2
  5. data/ahn +2 -1
  6. data/apps/default/Rakefile +16 -7
  7. data/apps/default/config/adhearsion.yml +22 -1
  8. data/apps/default/config/helpers/manager_proxy.yml +1 -0
  9. data/apps/default/config/helpers/micromenus/images/arrow-off.gif +0 -0
  10. data/apps/default/config/helpers/micromenus/images/arrow-on.gif +0 -0
  11. data/apps/default/config/helpers/micromenus/images/error.gif +0 -0
  12. data/apps/default/config/helpers/micromenus/images/folder-off.gif +0 -0
  13. data/apps/default/config/helpers/micromenus/images/folder-on.gif +0 -0
  14. data/apps/default/config/helpers/micromenus/images/folder.png +0 -0
  15. data/apps/default/config/helpers/micromenus/images/ggbridge.jpg +0 -0
  16. data/apps/default/config/helpers/micromenus/images/green.png +0 -0
  17. data/apps/default/config/helpers/micromenus/images/microbrowser.bg.gif +0 -0
  18. data/apps/default/config/helpers/micromenus/images/red.png +0 -0
  19. data/apps/default/config/helpers/micromenus/images/url-off.gif +0 -0
  20. data/apps/default/config/helpers/micromenus/images/url-on.gif +0 -0
  21. data/apps/default/config/helpers/micromenus/images/yellow.png +0 -0
  22. data/apps/default/config/helpers/micromenus/javascripts/animation.js +1341 -0
  23. data/apps/default/config/helpers/micromenus/javascripts/carousel.js +1238 -0
  24. data/apps/default/config/helpers/micromenus/javascripts/columnav.js +306 -0
  25. data/apps/default/config/helpers/micromenus/javascripts/connection.js +965 -0
  26. data/apps/default/config/helpers/micromenus/javascripts/container.js +4727 -0
  27. data/apps/default/config/helpers/micromenus/javascripts/container_core.js +2915 -0
  28. data/apps/default/config/helpers/micromenus/javascripts/dom.js +892 -0
  29. data/apps/default/config/helpers/micromenus/javascripts/dragdrop.js +2921 -907
  30. data/apps/default/config/helpers/micromenus/javascripts/event.js +1771 -0
  31. data/apps/default/config/helpers/micromenus/javascripts/yahoo.js +433 -0
  32. data/apps/default/config/helpers/micromenus/stylesheets/carousel.css +78 -0
  33. data/apps/default/config/helpers/micromenus/stylesheets/columnav.css +135 -0
  34. data/apps/default/config/helpers/micromenus/stylesheets/microbrowsers.css +42 -0
  35. data/apps/default/config/helpers/multi_messenger.yml +5 -1
  36. data/apps/default/config/migration.rb +10 -0
  37. data/apps/default/extensions.rb +1 -1
  38. data/apps/default/helpers/factorial.alien.c +3 -3
  39. data/apps/default/helpers/lookup.rb +2 -1
  40. data/apps/default/helpers/manager_proxy.rb +67 -15
  41. data/apps/default/helpers/micromenus.rb +173 -31
  42. data/apps/default/helpers/multi_messenger.rb +20 -3
  43. data/lib/adhearsion.rb +218 -88
  44. data/lib/constants.rb +1 -0
  45. data/lib/core_extensions.rb +15 -9
  46. data/lib/phone_number.rb +85 -0
  47. data/lib/rami.rb +3 -2
  48. data/lib/servlet_container.rb +47 -24
  49. data/lib/sexy_migrations.rb +70 -0
  50. data/test/asterisk_module_test.rb +9 -9
  51. data/test/specs/numerical_string_spec.rb +53 -0
  52. metadata +31 -11
  53. data/apps/default/config/helpers/micromenus/javascripts/builder.js +0 -131
  54. data/apps/default/config/helpers/micromenus/javascripts/controls.js +0 -834
  55. data/apps/default/config/helpers/micromenus/javascripts/effects.js +0 -956
  56. data/apps/default/config/helpers/micromenus/javascripts/prototype.js +0 -2319
  57. data/apps/default/config/helpers/micromenus/javascripts/scriptaculous.js +0 -51
  58. data/apps/default/config/helpers/micromenus/javascripts/slider.js +0 -278
  59. data/apps/default/config/helpers/micromenus/javascripts/unittest.js +0 -557
  60. data/apps/default/config/helpers/micromenus/stylesheets/firefox.css +0 -10
  61. data/apps/default/config/helpers/micromenus/stylesheets/firefox.xul.css +0 -44
@@ -0,0 +1,306 @@
1
+ /*
2
+ * Copyright (c) 2007, David A. Lindquist (stringify.com)
3
+ * Some Rights Reserved
4
+ *
5
+ * This code is licensed under the Creative Commons Attribution 2.5 License
6
+ * (http://creativecommons.org/licenses/by/2.5/). Please maintain the above
7
+ * license and copyright statements when using this code.
8
+ *
9
+ * $Id: columnav.js 481 2007-02-21 05:56:01Z david $
10
+ */
11
+ YAHOO.namespace('extension');
12
+
13
+ YAHOO.extension.ColumNav = function(id, cfg) {
14
+ this._init(id, cfg);
15
+ };
16
+
17
+ YAHOO.extension.ColumNav.prototype = {
18
+
19
+ DOM: YAHOO.util.Dom,
20
+ EVT: YAHOO.util.Event,
21
+ CON: YAHOO.util.Connect,
22
+
23
+ ERROR_MSG: 'data unavailable',
24
+
25
+ // PUBLIC API
26
+
27
+ reset: function() {
28
+ this.carousel.clear();
29
+ this._init(this.id, this.cfg);
30
+ },
31
+
32
+ // PRIVATE API
33
+
34
+ _init: function(id, cfg) {
35
+ this.id = id;
36
+ this.cfg = cfg; // make this a YAHOO.util.Config object?
37
+
38
+ this.source = cfg.source;
39
+ this.linkAction = cfg.linkAction || this._defaultLinkAction;
40
+ this.request = null;
41
+ this.counter = 1;
42
+ this.numScrolled = 0;
43
+ this.moving = false;
44
+ this.carousel = new YAHOO.extension.Carousel(id,
45
+ {
46
+ 'animationCompleteHandler': this._animationCompleteHandler,
47
+ 'loadPrevHandler': this._loadPrevHandler,
48
+ 'numVisible': cfg.numVisible || 1,
49
+ 'prevElement': cfg.prevElement || cfg.prevId,
50
+ 'scrollInc': 1
51
+ });
52
+ this.carousel.cn = this;
53
+
54
+ var notOpera = (navigator.userAgent.match(/opera/i) == null);
55
+ var kl = new YAHOO.util.KeyListener(this.carousel.carouselElem,
56
+ { ctrl: notOpera, keys: [37, 38, 39, 40] },
57
+ { fn: this._handleKeypress,
58
+ scope: this,
59
+ correctScope: true });
60
+ kl.enable();
61
+
62
+ var source = this.source;
63
+ if (source && source.nodeType == 1)
64
+ this._addMenu(source);
65
+ else if (typeof source == 'string')
66
+ this._makeRequest(source);
67
+ else
68
+ this._handleFailure({});
69
+ },
70
+
71
+ _loadPrevHandler: function(type, args) {
72
+ this.cn._abortRequest();
73
+ },
74
+
75
+ _makeRequest: function(url) {
76
+ var callback = {
77
+ 'success': this._handleSuccess,
78
+ 'failure': this._handleFailure,
79
+ 'scope': this,
80
+ 'timeout': 5000
81
+ };
82
+ this._abortRequest();
83
+ this.request = this.CON.asyncRequest('GET', url, callback);
84
+ },
85
+
86
+ _abortRequest: function() {
87
+ if (this.request && this.CON.isCallInProgress(this.request))
88
+ this.CON.abort(this.request);
89
+ },
90
+
91
+ _handleSuccess: function(o) {
92
+ this._addMenu(o.responseXML.documentElement);
93
+ },
94
+
95
+ _handleFailure: function(o) {
96
+ var list = document.createElement('ul');
97
+ var item = document.createElement('li');
98
+ var span = document.createElement('span');
99
+ span.className = 'columnav-error';
100
+ span.appendChild(document.createTextNode(this.ERROR_MSG));
101
+ item.appendChild(span);
102
+ list.appendChild(item);
103
+ this._addMenu(list);
104
+ },
105
+
106
+ _handleKeypress: function(type, args, o) {
107
+ var key = args[0];
108
+ var evt = args[1];
109
+ var target = this.EVT.getTarget(evt);
110
+ if (target.tagName != 'A') {
111
+ var links = this._getNodes(this.carousel.carouselList.lastChild,
112
+ this._links);
113
+ links[0].focus();
114
+ return;
115
+ }
116
+ switch (key) {
117
+ case 37: // left
118
+ var menu = target.parentNode.parentNode;
119
+ if (this._shouldScrollPrev(menu))
120
+ o.carousel.scrollPrev();
121
+ else {
122
+ var prevMenu = this._prevMenu(menu);
123
+ if (prevMenu)
124
+ this._focus(prevMenu);
125
+ }
126
+ break;
127
+ case 38: // up
128
+ if (target.previousSibling)
129
+ target.previousSibling.focus();
130
+ break;
131
+ case 39: // right
132
+ this._next(evt);
133
+ break;
134
+ case 40: // down
135
+ if (target.nextSibling)
136
+ target.nextSibling.focus();
137
+ break;
138
+ }
139
+ this.EVT.stopEvent(evt);
140
+ },
141
+
142
+ _addMenu: function(node) {
143
+ var menu = this._createMenu(node);
144
+ this.carousel.addItem(this.counter++, menu);
145
+ if (this._shouldScrollNext()) {
146
+ this.carousel.scrollNext();
147
+ this.moving = true;
148
+ } else {
149
+ if (this.counter > 2)
150
+ this._focus(menu);
151
+ }
152
+ },
153
+
154
+ _shouldScrollNext: function() {
155
+ var numVisible = this.carousel.cfg.getProperty('numVisible');
156
+ return ((this.counter - 1) - this.numScrolled > numVisible);
157
+ },
158
+
159
+ _shouldScrollPrev: function(menu) {
160
+ var menus = this._getNodes(this.carousel.carouselList,
161
+ this._childElements);
162
+ var i = 0;
163
+ for ( ; i < menus.length; i++) {
164
+ if (menu == menus[i]) break;
165
+ }
166
+ return (i == this.numScrolled);
167
+ },
168
+
169
+ _prevMenu: function(menu) {
170
+ var prevLi = menu.previousSibling;
171
+ if (prevLi)
172
+ return prevLi.getElementsByTagName('div')[0];
173
+ return null;
174
+ },
175
+
176
+ _next: function(e) {
177
+ if (this.moving)
178
+ return;
179
+ var target = this.EVT.getTarget(e);
180
+ if (target.tagName == 'SPAN')
181
+ target = target.parentNode;
182
+ this._removeMenus(target);
183
+ var href = target.getAttribute('href');
184
+ var rel = target.getAttribute('rel');
185
+ var list = target.list;
186
+ if (href !== null)
187
+ this._highlight(target);
188
+ if (list)
189
+ this._addMenu(list);
190
+ else if (rel == 'ajax')
191
+ this._makeRequest(href);
192
+ else {
193
+ if (this.linkAction(e))
194
+ return true;
195
+ }
196
+ this.EVT.preventDefault(e);
197
+ },
198
+
199
+ _removeMenus: function(target) {
200
+ var li = target.parentNode.parentNode;
201
+ var list = this.carousel.carouselList;
202
+ while (li != list.lastChild) {
203
+ list.removeChild(list.lastChild);
204
+ this.counter--;
205
+ }
206
+ },
207
+
208
+ _highlight: function(target) {
209
+ var items = this._getNodes(target.parentNode, this._childElements);
210
+ for (var i = 0; i < items.length; i++)
211
+ this.DOM.removeClass(items[i], 'columnav-active');
212
+ this.DOM.addClass(target, 'columnav-active');
213
+ },
214
+
215
+ _focus: function(menu) {
216
+ var links = this._getNodes(menu, this._links);
217
+ for (var i = 0; i < links.length; i++) {
218
+ if (this.DOM.hasClass(links[i], 'columnav-active')) {
219
+ links[i].focus();
220
+ return;
221
+ }
222
+ }
223
+ links[0].focus();
224
+ },
225
+
226
+ _animationCompleteHandler: function(type, args) {
227
+ this.cn.moving = false;
228
+ if (args[0] == 'next') {
229
+ this.cn.numScrolled++;
230
+ this.cn._focus(this.carouselList.lastChild);
231
+ }
232
+ if (args[0] == 'prev') {
233
+ this.cn._removeLastMenu();
234
+ this.cn.numScrolled--;
235
+ if (this.cfg.getProperty('numVisible') == 1)
236
+ this.cn._focus(this.carouselList.lastChild);
237
+ }
238
+ },
239
+
240
+ _removeLastMenu: function() {
241
+ var list = this.carousel.carouselList;
242
+ list.removeChild(list.lastChild);
243
+ this.counter--;
244
+ },
245
+
246
+ _createMenu: function(node) {
247
+ var menu = document.createElement('div');
248
+ var items = this._getNodes(node, this._childElements);
249
+ for (var i = 0; i < items.length; i++) {
250
+ var ce = this._getNodes(items[i], this._childElements);
251
+ var link = ce[0], list = ce[1];
252
+ var text = link.firstChild.data;
253
+ var href = link.getAttribute('href');
254
+ var rel = link.getAttribute('rel');
255
+ var cls = link.getAttribute('class') || link.className;
256
+ var a = document.createElement('a');
257
+ var span = document.createElement('span');
258
+ span.appendChild(document.createTextNode(text));
259
+ a.appendChild(span);
260
+ a.setAttribute('href', href || 'javascript:void(0)');
261
+ a.setAttribute('rel', rel);
262
+ a.list = list;
263
+ if (cls)
264
+ this.DOM.addClass(a, cls);
265
+ if (list || rel == 'ajax')
266
+ this.DOM.addClass(a, 'columnav-has-menu');
267
+ this.EVT.addListener(a, 'click', this._next, this, true);
268
+ menu.appendChild(a);
269
+ }
270
+ return menu;
271
+ },
272
+
273
+ _defaultLinkAction: function() { return true; },
274
+
275
+ _getNodes: function(root, filter) {
276
+ var node = root;
277
+ var nodes = [];
278
+ var next;
279
+ var f = filter || function() { return true; }
280
+ while (node != null) {
281
+ if (node.hasChildNodes())
282
+ node = node.firstChild;
283
+ else if (node != root && null != (next = node.nextSibling))
284
+ node = next;
285
+ else {
286
+ next = null;
287
+ for ( ; node != root; node = node.parentNode) {
288
+ next = node.nextSibling;
289
+ if (next != null) break;
290
+ }
291
+ node = next;
292
+ }
293
+ if (node != null && f(node, root))
294
+ nodes.push(node);
295
+ }
296
+ return nodes;
297
+ },
298
+
299
+ _childElements: function(node, root) {
300
+ return (node.nodeType == 1 && node.parentNode == root);
301
+ },
302
+
303
+ _links: function(node) { return (node.tagName == 'A'); }
304
+ };
305
+
306
+ YAHOO.extension.ColumnNav = YAHOO.extension.ColumNav;
@@ -0,0 +1,965 @@
1
+ /*
2
+ Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.net/yui/license.txt
5
+ version: 0.12.2
6
+ */
7
+ /**
8
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
9
+ * object. It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
10
+ * interactive states and server response, returning the results to a pre-defined
11
+ * callback you create.
12
+ *
13
+ * @namespace YAHOO.util
14
+ * @module connection
15
+ * @requires yahoo
16
+ */
17
+
18
+ /**
19
+ * The Connection Manager singleton provides methods for creating and managing
20
+ * asynchronous transactions.
21
+ *
22
+ * @class Connect
23
+ */
24
+ YAHOO.util.Connect =
25
+ {
26
+ /**
27
+ * @description Array of MSFT ActiveX ids for XMLHttpRequest.
28
+ * @property _msxml_progid
29
+ * @private
30
+ * @static
31
+ * @type array
32
+ */
33
+ _msxml_progid:[
34
+ 'MSXML2.XMLHTTP.3.0',
35
+ 'MSXML2.XMLHTTP',
36
+ 'Microsoft.XMLHTTP'
37
+ ],
38
+
39
+ /**
40
+ * @description Object literal of HTTP header(s)
41
+ * @property _http_header
42
+ * @private
43
+ * @static
44
+ * @type object
45
+ */
46
+ _http_header:{},
47
+
48
+ /**
49
+ * @description Determines if HTTP headers are set.
50
+ * @property _has_http_headers
51
+ * @private
52
+ * @static
53
+ * @type boolean
54
+ */
55
+ _has_http_headers:false,
56
+
57
+ /**
58
+ * @description Determines if a default header of
59
+ * Content-Type of 'application/x-www-form-urlencoded'
60
+ * will be added to any client HTTP headers sent for POST
61
+ * transactions.
62
+ * @property _use_default_post_header
63
+ * @private
64
+ * @static
65
+ * @type boolean
66
+ */
67
+ _use_default_post_header:true,
68
+
69
+ /**
70
+ * @description Determines if a default header of
71
+ * Content-Type of 'application/x-www-form-urlencoded'
72
+ * will be added to any client HTTP headers sent for POST
73
+ * transactions.
74
+ * @property _default_post_header
75
+ * @private
76
+ * @static
77
+ * @type boolean
78
+ */
79
+ _default_post_header:'application/x-www-form-urlencoded',
80
+
81
+ /**
82
+ * @description Property modified by setForm() to determine if the data
83
+ * should be submitted as an HTML form.
84
+ * @property _isFormSubmit
85
+ * @private
86
+ * @static
87
+ * @type boolean
88
+ */
89
+ _isFormSubmit:false,
90
+
91
+ /**
92
+ * @description Property modified by setForm() to determine if a file(s)
93
+ * upload is expected.
94
+ * @property _isFileUpload
95
+ * @private
96
+ * @static
97
+ * @type boolean
98
+ */
99
+ _isFileUpload:false,
100
+
101
+ /**
102
+ * @description Property modified by setForm() to set a reference to the HTML
103
+ * form node if the desired action is file upload.
104
+ * @property _formNode
105
+ * @private
106
+ * @static
107
+ * @type object
108
+ */
109
+ _formNode:null,
110
+
111
+ /**
112
+ * @description Property modified by setForm() to set the HTML form data
113
+ * for each transaction.
114
+ * @property _sFormData
115
+ * @private
116
+ * @static
117
+ * @type string
118
+ */
119
+ _sFormData:null,
120
+
121
+ /**
122
+ * @description Collection of polling references to the polling mechanism in handleReadyState.
123
+ * @property _poll
124
+ * @private
125
+ * @static
126
+ * @type object
127
+ */
128
+ _poll:{},
129
+
130
+ /**
131
+ * @description Queue of timeout values for each transaction callback with a defined timeout value.
132
+ * @property _timeOut
133
+ * @private
134
+ * @static
135
+ * @type object
136
+ */
137
+ _timeOut:{},
138
+
139
+ /**
140
+ * @description The polling frequency, in milliseconds, for HandleReadyState.
141
+ * when attempting to determine a transaction's XHR readyState.
142
+ * The default is 50 milliseconds.
143
+ * @property _polling_interval
144
+ * @private
145
+ * @static
146
+ * @type int
147
+ */
148
+ _polling_interval:50,
149
+
150
+ /**
151
+ * @description A transaction counter that increments the transaction id for each transaction.
152
+ * @property _transaction_id
153
+ * @private
154
+ * @static
155
+ * @type int
156
+ */
157
+ _transaction_id:0,
158
+
159
+ /**
160
+ * @description Member to add an ActiveX id to the existing xml_progid array.
161
+ * In the event(unlikely) a new ActiveX id is introduced, it can be added
162
+ * without internal code modifications.
163
+ * @method setProgId
164
+ * @public
165
+ * @static
166
+ * @param {string} id The ActiveX id to be added to initialize the XHR object.
167
+ * @return void
168
+ */
169
+ setProgId:function(id)
170
+ {
171
+ this._msxml_progid.unshift(id);
172
+ },
173
+
174
+ /**
175
+ * @description Member to enable or disable the default POST header.
176
+ * @method setDefaultPostHeader
177
+ * @public
178
+ * @static
179
+ * @param {boolean} b Set and use default header - true or false .
180
+ * @return void
181
+ */
182
+ setDefaultPostHeader:function(b)
183
+ {
184
+ this._use_default_post_header = b;
185
+ },
186
+
187
+ /**
188
+ * @description Member to modify the default polling interval.
189
+ * @method setPollingInterval
190
+ * @public
191
+ * @static
192
+ * @param {int} i The polling interval in milliseconds.
193
+ * @return void
194
+ */
195
+ setPollingInterval:function(i)
196
+ {
197
+ if(typeof i == 'number' && isFinite(i)){
198
+ this._polling_interval = i;
199
+ }
200
+ },
201
+
202
+ /**
203
+ * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
204
+ * the XMLHttpRequest instance and the transaction id.
205
+ * @method createXhrObject
206
+ * @private
207
+ * @static
208
+ * @param {int} transactionId Property containing the transaction id for this transaction.
209
+ * @return object
210
+ */
211
+ createXhrObject:function(transactionId)
212
+ {
213
+ var obj,http;
214
+ try
215
+ {
216
+ // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
217
+ http = new XMLHttpRequest();
218
+ // Object literal with http and tId properties
219
+ obj = { conn:http, tId:transactionId };
220
+ }
221
+ catch(e)
222
+ {
223
+ for(var i=0; i<this._msxml_progid.length; ++i){
224
+ try
225
+ {
226
+ // Instantiates XMLHttpRequest for IE and assign to http.
227
+ http = new ActiveXObject(this._msxml_progid[i]);
228
+ // Object literal with conn and tId properties
229
+ obj = { conn:http, tId:transactionId };
230
+ break;
231
+ }
232
+ catch(e){}
233
+ }
234
+ }
235
+ finally
236
+ {
237
+ return obj;
238
+ }
239
+ },
240
+
241
+ /**
242
+ * @description This method is called by asyncRequest to create a
243
+ * valid connection object for the transaction. It also passes a
244
+ * transaction id and increments the transaction id counter.
245
+ * @method getConnectionObject
246
+ * @private
247
+ * @static
248
+ * @return {object}
249
+ */
250
+ getConnectionObject:function()
251
+ {
252
+ var o;
253
+ var tId = this._transaction_id;
254
+
255
+ try
256
+ {
257
+ o = this.createXhrObject(tId);
258
+ if(o){
259
+ this._transaction_id++;
260
+ }
261
+ }
262
+ catch(e){}
263
+ finally
264
+ {
265
+ return o;
266
+ }
267
+ },
268
+
269
+ /**
270
+ * @description Method for initiating an asynchronous request via the XHR object.
271
+ * @method asyncRequest
272
+ * @public
273
+ * @static
274
+ * @param {string} method HTTP transaction method
275
+ * @param {string} uri Fully qualified path of resource
276
+ * @param {callback} callback User-defined callback function or object
277
+ * @param {string} postData POST body
278
+ * @return {object} Returns the connection object
279
+ */
280
+ asyncRequest:function(method, uri, callback, postData)
281
+ {
282
+ var o = this.getConnectionObject();
283
+
284
+ if(!o){
285
+ return null;
286
+ }
287
+ else{
288
+ if(this._isFormSubmit){
289
+ if(this._isFileUpload){
290
+ this.uploadFile(o.tId, callback, uri, postData);
291
+ this.releaseObject(o);
292
+
293
+ return;
294
+ }
295
+
296
+ //If the specified HTTP method is GET, setForm() will return an
297
+ //encoded string that is concatenated to the uri to
298
+ //create a querystring.
299
+ if(method == 'GET'){
300
+ if(this._sFormData.length != 0){
301
+ // If the URI already contains a querystring, append an ampersand
302
+ // and then concatenate _sFormData to the URI.
303
+ uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
304
+ }
305
+ else{
306
+ uri += "?" + this._sFormData;
307
+ }
308
+ }
309
+ else if(method == 'POST'){
310
+ //If POST data exist in addition to the HTML form data,
311
+ //it will be concatenated to the form data.
312
+ postData = postData?this._sFormData + "&" + postData:this._sFormData;
313
+ }
314
+ }
315
+
316
+ o.conn.open(method, uri, true);
317
+
318
+ if(this._isFormSubmit || (postData && this._use_default_post_header)){
319
+ this.initHeader('Content-Type', this._default_post_header);
320
+ if(this._isFormSubmit){
321
+ this.resetFormState();
322
+ }
323
+ }
324
+
325
+ if(this._has_http_headers){
326
+ this.setHeader(o);
327
+ }
328
+
329
+ this.handleReadyState(o, callback);
330
+ o.conn.send(postData || null);
331
+
332
+ return o;
333
+ }
334
+ },
335
+
336
+ /**
337
+ * @description This method serves as a timer that polls the XHR object's readyState
338
+ * property during a transaction, instead of binding a callback to the
339
+ * onreadystatechange event. Upon readyState 4, handleTransactionResponse
340
+ * will process the response, and the timer will be cleared.
341
+ * @method handleReadyState
342
+ * @private
343
+ * @static
344
+ * @param {object} o The connection object
345
+ * @param {callback} callback The user-defined callback object
346
+ * @return {void}
347
+ */
348
+ handleReadyState:function(o, callback)
349
+ {
350
+ var oConn = this;
351
+
352
+ if(callback && callback.timeout){
353
+ this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
354
+ }
355
+
356
+ this._poll[o.tId] = window.setInterval(
357
+ function(){
358
+ if(o.conn && o.conn.readyState == 4){
359
+ window.clearInterval(oConn._poll[o.tId]);
360
+ delete oConn._poll[o.tId];
361
+
362
+ if(callback && callback.timeout){
363
+ delete oConn._timeOut[o.tId];
364
+ }
365
+
366
+ oConn.handleTransactionResponse(o, callback);
367
+ }
368
+ }
369
+ ,this._polling_interval);
370
+ },
371
+
372
+ /**
373
+ * @description This method attempts to interpret the server response and
374
+ * determine whether the transaction was successful, or if an error or
375
+ * exception was encountered.
376
+ * @method handleTransactionResponse
377
+ * @private
378
+ * @static
379
+ * @param {object} o The connection object
380
+ * @param {object} callback The sser-defined callback object
381
+ * @param {boolean} isAbort Determines if the transaction was aborted.
382
+ * @return {void}
383
+ */
384
+ handleTransactionResponse:function(o, callback, isAbort)
385
+ {
386
+ // If no valid callback is provided, then do not process any callback handling.
387
+ if(!callback){
388
+ this.releaseObject(o);
389
+ return;
390
+ }
391
+
392
+ var httpStatus, responseObject;
393
+
394
+ try
395
+ {
396
+ if(o.conn.status !== undefined && o.conn.status != 0){
397
+ httpStatus = o.conn.status;
398
+ }
399
+ else{
400
+ httpStatus = 13030;
401
+ }
402
+ }
403
+ catch(e){
404
+ // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
405
+ // when the o object's status and statusText properties are
406
+ // unavailable, and a query attempt throws an exception.
407
+ httpStatus = 13030;
408
+ }
409
+
410
+ if(httpStatus >= 200 && httpStatus < 300){
411
+ try
412
+ {
413
+ responseObject = this.createResponseObject(o, callback.argument);
414
+ if(callback.success){
415
+ if(!callback.scope){
416
+ callback.success(responseObject);
417
+ }
418
+ else{
419
+ // If a scope property is defined, the callback will be fired from
420
+ // the context of the object.
421
+ callback.success.apply(callback.scope, [responseObject]);
422
+ }
423
+ }
424
+ }
425
+ catch(e){}
426
+ }
427
+ else{
428
+ try
429
+ {
430
+ switch(httpStatus){
431
+ // The following cases are wininet.dll error codes that may be encountered.
432
+ case 12002: // Server timeout
433
+ case 12029: // 12029 to 12031 correspond to dropped connections.
434
+ case 12030:
435
+ case 12031:
436
+ case 12152: // Connection closed by server.
437
+ case 13030: // See above comments for variable status.
438
+ responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
439
+ if(callback.failure){
440
+ if(!callback.scope){
441
+ callback.failure(responseObject);
442
+ }
443
+ else{
444
+ callback.failure.apply(callback.scope, [responseObject]);
445
+ }
446
+ }
447
+ break;
448
+ default:
449
+ responseObject = this.createResponseObject(o, callback.argument);
450
+ if(callback.failure){
451
+ if(!callback.scope){
452
+ callback.failure(responseObject);
453
+ }
454
+ else{
455
+ callback.failure.apply(callback.scope, [responseObject]);
456
+ }
457
+ }
458
+ }
459
+ }
460
+ catch(e){}
461
+ }
462
+
463
+ this.releaseObject(o);
464
+ responseObject = null;
465
+ },
466
+
467
+ /**
468
+ * @description This method evaluates the server response, creates and returns the results via
469
+ * its properties. Success and failure cases will differ in the response
470
+ * object's property values.
471
+ * @method createResponseObject
472
+ * @private
473
+ * @static
474
+ * @param {object} o The connection object
475
+ * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
476
+ * @return {object}
477
+ */
478
+ createResponseObject:function(o, callbackArg)
479
+ {
480
+ var obj = {};
481
+ var headerObj = {};
482
+
483
+ try
484
+ {
485
+ var headerStr = o.conn.getAllResponseHeaders();
486
+ var header = headerStr.split('\n');
487
+ for(var i=0; i<header.length; i++){
488
+ var delimitPos = header[i].indexOf(':');
489
+ if(delimitPos != -1){
490
+ headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
491
+ }
492
+ }
493
+ }
494
+ catch(e){}
495
+
496
+ obj.tId = o.tId;
497
+ obj.status = o.conn.status;
498
+ obj.statusText = o.conn.statusText;
499
+ obj.getResponseHeader = headerObj;
500
+ obj.getAllResponseHeaders = headerStr;
501
+ obj.responseText = o.conn.responseText;
502
+ obj.responseXML = o.conn.responseXML;
503
+
504
+ if(typeof callbackArg !== undefined){
505
+ obj.argument = callbackArg;
506
+ }
507
+
508
+ return obj;
509
+ },
510
+
511
+ /**
512
+ * @description If a transaction cannot be completed due to dropped or closed connections,
513
+ * there may be not be enough information to build a full response object.
514
+ * The failure callback will be fired and this specific condition can be identified
515
+ * by a status property value of 0.
516
+ *
517
+ * If an abort was successful, the status property will report a value of -1.
518
+ *
519
+ * @method createExceptionObject
520
+ * @private
521
+ * @static
522
+ * @param {int} tId The Transaction Id
523
+ * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
524
+ * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
525
+ * @return {object}
526
+ */
527
+ createExceptionObject:function(tId, callbackArg, isAbort)
528
+ {
529
+ var COMM_CODE = 0;
530
+ var COMM_ERROR = 'communication failure';
531
+ var ABORT_CODE = -1;
532
+ var ABORT_ERROR = 'transaction aborted';
533
+
534
+ var obj = {};
535
+
536
+ obj.tId = tId;
537
+ if(isAbort){
538
+ obj.status = ABORT_CODE;
539
+ obj.statusText = ABORT_ERROR;
540
+ }
541
+ else{
542
+ obj.status = COMM_CODE;
543
+ obj.statusText = COMM_ERROR;
544
+ }
545
+
546
+ if(callbackArg){
547
+ obj.argument = callbackArg;
548
+ }
549
+
550
+ return obj;
551
+ },
552
+
553
+ /**
554
+ * @description Public method that stores the custom HTTP headers for each transaction.
555
+ * @method initHeader
556
+ * @public
557
+ * @static
558
+ * @param {string} label The HTTP header label
559
+ * @param {string} value The HTTP header value
560
+ * @return {void}
561
+ */
562
+ initHeader:function(label,value)
563
+ {
564
+ if(this._http_header[label] === undefined){
565
+ this._http_header[label] = value;
566
+ }
567
+ else{
568
+ // Concatenate multiple values, comma-delimited,
569
+ // for the same header label,
570
+ this._http_header[label] = value + "," + this._http_header[label];
571
+ }
572
+
573
+ this._has_http_headers = true;
574
+ },
575
+
576
+ /**
577
+ * @description Accessor that sets the HTTP headers for each transaction.
578
+ * @method setHeader
579
+ * @private
580
+ * @static
581
+ * @param {object} o The connection object for the transaction.
582
+ * @return {void}
583
+ */
584
+ setHeader:function(o)
585
+ {
586
+ for(var prop in this._http_header){
587
+ if(this._http_header.hasOwnProperty(prop)){
588
+ o.conn.setRequestHeader(prop, this._http_header[prop]);
589
+ }
590
+ }
591
+ delete this._http_header;
592
+
593
+ this._http_header = {};
594
+ this._has_http_headers = false;
595
+ },
596
+
597
+ /**
598
+ * @description This method assembles the form label and value pairs and
599
+ * constructs an encoded string.
600
+ * asyncRequest() will automatically initialize the
601
+ * transaction with a HTTP header Content-Type of
602
+ * application/x-www-form-urlencoded.
603
+ * @method setForm
604
+ * @public
605
+ * @static
606
+ * @param {string || object} form id or name attribute, or form object.
607
+ * @param {string} optional boolean to indicate SSL environment.
608
+ * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
609
+ * @return {string} string of the HTML form field name and value pairs..
610
+ */
611
+ setForm:function(formId, isUpload, secureUri)
612
+ {
613
+ this.resetFormState();
614
+ var oForm;
615
+ if(typeof formId == 'string'){
616
+ // Determine if the argument is a form id or a form name.
617
+ // Note form name usage is deprecated but supported
618
+ // here for legacy reasons.
619
+ oForm = (document.getElementById(formId) || document.forms[formId]);
620
+ }
621
+ else if(typeof formId == 'object'){
622
+ // Treat argument as an HTML form object.
623
+ oForm = formId;
624
+ }
625
+ else{
626
+ return;
627
+ }
628
+
629
+ // If the isUpload argument is true, setForm will call createFrame to initialize
630
+ // an iframe as the form target.
631
+ //
632
+ // The argument secureURI is also required by IE in SSL environments
633
+ // where the secureURI string is a fully qualified HTTP path, used to set the source
634
+ // of the iframe, to a stub resource in the same domain.
635
+ if(isUpload){
636
+
637
+ // Create iframe in preparation for file upload.
638
+ this.createFrame(secureUri?secureUri:null);
639
+
640
+ // Set form reference and file upload properties to true.
641
+ this._isFormSubmit = true;
642
+ this._isFileUpload = true;
643
+ this._formNode = oForm;
644
+
645
+ return;
646
+ }
647
+
648
+ var oElement, oName, oValue, oDisabled;
649
+ var hasSubmit = false;
650
+
651
+ // Iterate over the form elements collection to construct the
652
+ // label-value pairs.
653
+ for (var i=0; i<oForm.elements.length; i++){
654
+ oElement = oForm.elements[i];
655
+ oDisabled = oForm.elements[i].disabled;
656
+ oName = oForm.elements[i].name;
657
+ oValue = oForm.elements[i].value;
658
+
659
+ // Do not submit fields that are disabled or
660
+ // do not have a name attribute value.
661
+ if(!oDisabled && oName)
662
+ {
663
+ switch (oElement.type)
664
+ {
665
+ case 'select-one':
666
+ case 'select-multiple':
667
+ for(var j=0; j<oElement.options.length; j++){
668
+ if(oElement.options[j].selected){
669
+ if(window.ActiveXObject){
670
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
671
+ }
672
+ else{
673
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
674
+ }
675
+
676
+ }
677
+ }
678
+ break;
679
+ case 'radio':
680
+ case 'checkbox':
681
+ if(oElement.checked){
682
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
683
+ }
684
+ break;
685
+ case 'file':
686
+ // stub case as XMLHttpRequest will only send the file path as a string.
687
+ case undefined:
688
+ // stub case for fieldset element which returns undefined.
689
+ case 'reset':
690
+ // stub case for input type reset button.
691
+ case 'button':
692
+ // stub case for input type button elements.
693
+ break;
694
+ case 'submit':
695
+ if(hasSubmit == false){
696
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
697
+ hasSubmit = true;
698
+ }
699
+ break;
700
+ default:
701
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
702
+ break;
703
+ }
704
+ }
705
+ }
706
+
707
+ this._isFormSubmit = true;
708
+ this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
709
+
710
+ return this._sFormData;
711
+ },
712
+
713
+ /**
714
+ * @description Resets HTML form properties when an HTML form or HTML form
715
+ * with file upload transaction is sent.
716
+ * @method resetFormState
717
+ * @private
718
+ * @static
719
+ * @return {void}
720
+ */
721
+ resetFormState:function(){
722
+ this._isFormSubmit = false;
723
+ this._isFileUpload = false;
724
+ this._formNode = null;
725
+ this._sFormData = "";
726
+ },
727
+
728
+ /**
729
+ * @description Creates an iframe to be used for form file uploads. It is remove from the
730
+ * document upon completion of the upload transaction.
731
+ * @method createFrame
732
+ * @private
733
+ * @static
734
+ * @param {string} secureUri Optional qualified path of iframe resource for SSL in IE.
735
+ * @return {void}
736
+ */
737
+ createFrame:function(secureUri){
738
+
739
+ // IE does not allow the setting of id and name attributes as object
740
+ // properties via createElement(). A different iframe creation
741
+ // pattern is required for IE.
742
+ var frameId = 'yuiIO' + this._transaction_id;
743
+ if(window.ActiveXObject){
744
+ var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
745
+
746
+ // IE will throw a security exception in an SSL environment if the
747
+ // iframe source is undefined.
748
+ if(typeof secureUri == 'boolean'){
749
+ io.src = 'javascript:false';
750
+ }
751
+ else if(typeof secureURI == 'string'){
752
+ // Deprecated
753
+ io.src = secureUri;
754
+ }
755
+ }
756
+ else{
757
+ var io = document.createElement('iframe');
758
+ io.id = frameId;
759
+ io.name = frameId;
760
+ }
761
+
762
+ io.style.position = 'absolute';
763
+ io.style.top = '-1000px';
764
+ io.style.left = '-1000px';
765
+
766
+ document.body.appendChild(io);
767
+ },
768
+
769
+ /**
770
+ * @description Parses the POST data and creates hidden form elements
771
+ * for each key-value, and appends them to the HTML form object.
772
+ * @method appendPostData
773
+ * @private
774
+ * @static
775
+ * @param {string} postData The HTTP POST data
776
+ * @return {array} formElements Collection of hidden fields.
777
+ */
778
+ appendPostData:function(postData)
779
+ {
780
+ var formElements = [];
781
+ var postMessage = postData.split('&');
782
+ for(var i=0; i < postMessage.length; i++){
783
+ var delimitPos = postMessage[i].indexOf('=');
784
+ if(delimitPos != -1){
785
+ formElements[i] = document.createElement('input');
786
+ formElements[i].type = 'hidden';
787
+ formElements[i].name = postMessage[i].substring(0,delimitPos);
788
+ formElements[i].value = postMessage[i].substring(delimitPos+1);
789
+ this._formNode.appendChild(formElements[i]);
790
+ }
791
+ }
792
+
793
+ return formElements;
794
+ },
795
+
796
+ /**
797
+ * @description Uploads HTML form, including files/attachments, to the
798
+ * iframe created in createFrame.
799
+ * @method uploadFile
800
+ * @private
801
+ * @static
802
+ * @param {int} id The transaction id.
803
+ * @param {object} callback - User-defined callback object.
804
+ * @param {string} uri Fully qualified path of resource.
805
+ * @return {void}
806
+ */
807
+ uploadFile:function(id, callback, uri, postData){
808
+
809
+ // Each iframe has an id prefix of "yuiIO" followed
810
+ // by the unique transaction id.
811
+ var frameId = 'yuiIO' + id;
812
+ var io = document.getElementById(frameId);
813
+
814
+ // Initialize the HTML form properties in case they are
815
+ // not defined in the HTML form.
816
+ this._formNode.action = uri;
817
+ this._formNode.method = 'POST';
818
+ this._formNode.target = frameId;
819
+
820
+ if(this._formNode.encoding){
821
+ // IE does not respect property enctype for HTML forms.
822
+ // Instead use property encoding.
823
+ this._formNode.encoding = 'multipart/form-data';
824
+ }
825
+ else{
826
+ this._formNode.enctype = 'multipart/form-data';
827
+ }
828
+
829
+ if(postData){
830
+ var oElements = this.appendPostData(postData);
831
+ }
832
+
833
+ this._formNode.submit();
834
+
835
+ if(oElements && oElements.length > 0){
836
+ try
837
+ {
838
+ for(var i=0; i < oElements.length; i++){
839
+ this._formNode.removeChild(oElements[i]);
840
+ }
841
+ }
842
+ catch(e){}
843
+ }
844
+
845
+ // Reset HTML form status properties.
846
+ this.resetFormState();
847
+
848
+ // Create the upload callback handler that fires when the iframe
849
+ // receives the load event. Subsequently, the event handler is detached
850
+ // and the iframe removed from the document.
851
+
852
+ var uploadCallback = function()
853
+ {
854
+ var obj = {};
855
+ obj.tId = id;
856
+ obj.argument = callback.argument;
857
+
858
+ try
859
+ {
860
+ obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
861
+ obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
862
+ }
863
+ catch(e){}
864
+
865
+ if(callback.upload){
866
+ if(!callback.scope){
867
+ callback.upload(obj);
868
+ }
869
+ else{
870
+ callback.upload.apply(callback.scope, [obj]);
871
+ }
872
+ }
873
+
874
+ if(YAHOO.util.Event){
875
+ YAHOO.util.Event.removeListener(io, "load", uploadCallback);
876
+ }
877
+ else if(window.detachEvent){
878
+ io.detachEvent('onload', uploadCallback);
879
+ }
880
+ else{
881
+ io.removeEventListener('load', uploadCallback, false);
882
+ }
883
+ setTimeout(function(){ document.body.removeChild(io); }, 100);
884
+ };
885
+
886
+
887
+ // Bind the onload handler to the iframe to detect the file upload response.
888
+ if(YAHOO.util.Event){
889
+ YAHOO.util.Event.addListener(io, "load", uploadCallback);
890
+ }
891
+ else if(window.attachEvent){
892
+ io.attachEvent('onload', uploadCallback);
893
+ }
894
+ else{
895
+ io.addEventListener('load', uploadCallback, false);
896
+ }
897
+ },
898
+
899
+ /**
900
+ * @description Method to terminate a transaction, if it has not reached readyState 4.
901
+ * @method abort
902
+ * @public
903
+ * @static
904
+ * @param {object} o The connection object returned by asyncRequest.
905
+ * @param {object} callback User-defined callback object.
906
+ * @param {string} isTimeout boolean to indicate if abort was a timeout.
907
+ * @return {boolean}
908
+ */
909
+ abort:function(o, callback, isTimeout)
910
+ {
911
+ if(this.isCallInProgress(o)){
912
+ o.conn.abort();
913
+ window.clearInterval(this._poll[o.tId]);
914
+ delete this._poll[o.tId];
915
+ if(isTimeout){
916
+ delete this._timeOut[o.tId];
917
+ }
918
+
919
+ this.handleTransactionResponse(o, callback, true);
920
+
921
+ return true;
922
+ }
923
+ else{
924
+ return false;
925
+ }
926
+ },
927
+
928
+ /**
929
+ * Public method to check if the transaction is still being processed.
930
+ *
931
+ * @method isCallInProgress
932
+ * @public
933
+ * @static
934
+ * @param {object} o The connection object returned by asyncRequest
935
+ * @return {boolean}
936
+ */
937
+ isCallInProgress:function(o)
938
+ {
939
+ // if the XHR object assigned to the transaction has not been dereferenced,
940
+ // then check its readyState status. Otherwise, return false.
941
+ if(o.conn){
942
+ return o.conn.readyState != 4 && o.conn.readyState != 0;
943
+ }
944
+ else{
945
+ //The XHR object has been destroyed.
946
+ return false;
947
+ }
948
+ },
949
+
950
+ /**
951
+ * @description Dereference the XHR instance and the connection object after the transaction is completed.
952
+ * @method releaseObject
953
+ * @private
954
+ * @static
955
+ * @param {object} o The connection object
956
+ * @return {void}
957
+ */
958
+ releaseObject:function(o)
959
+ {
960
+ //dereference the XHR instance.
961
+ o.conn = null;
962
+ //dereference the connection object.
963
+ o = null;
964
+ }
965
+ };