~ideamonk/sahana-eden/latheme

« back to all changes in this revision

Viewing changes to static/selenium/core/xpath/util.js

  • Committer: Fran Boon
  • Date: 2009-01-21 00:06:49 UTC
  • Revision ID: flavour@partyvibe.com-20090121000649-9ja31auafrrd1051
Added Selenium into static along with some initial Tests (Register/Login)
Unit Tests started via 2 approaches: SeleniumRC & WebTest (Selenium more promising)
Updated code for PyLint recommendations
Remove unused files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2005 Google
 
2
//
 
3
// Author: Steffen Meschkat <mesch@google.com>
 
4
//
 
5
// Miscellaneous utility and placeholder functions.
 
6
 
 
7
// Dummy implmentation for the logging functions. Replace by something
 
8
// useful when you want to debug.
 
9
function xpathLog(msg) {};
 
10
function xsltLog(msg) {};
 
11
function xsltLogXml(msg) {};
 
12
 
 
13
var ajaxsltIsIE6 = navigator.appVersion.match(/MSIE 6.0/);
 
14
 
 
15
// Throws an exception if false.
 
16
function assert(b) {
 
17
  if (!b) {
 
18
    throw "Assertion failed";
 
19
  }
 
20
}
 
21
 
 
22
// Splits a string s at all occurrences of character c. This is like
 
23
// the split() method of the string object, but IE omits empty
 
24
// strings, which violates the invariant (s.split(x).join(x) == s).
 
25
function stringSplit(s, c) {
 
26
  var a = s.indexOf(c);
 
27
  if (a == -1) {
 
28
    return [ s ];
 
29
  }
 
30
  var parts = [];
 
31
  parts.push(s.substr(0,a));
 
32
  while (a != -1) {
 
33
    var a1 = s.indexOf(c, a + 1);
 
34
    if (a1 != -1) {
 
35
      parts.push(s.substr(a + 1, a1 - a - 1));
 
36
    } else {
 
37
      parts.push(s.substr(a + 1));
 
38
    }
 
39
    a = a1;
 
40
  }
 
41
  return parts;
 
42
}
 
43
 
 
44
// The following function does what document.importNode(node, true)
 
45
// would do for us here; however that method is broken in Safari/1.3,
 
46
// so we have to emulate it.
 
47
function xmlImportNode(doc, node) {
 
48
  if (node.nodeType == DOM_TEXT_NODE) {
 
49
    return domCreateTextNode(doc, node.nodeValue);
 
50
 
 
51
  } else if (node.nodeType == DOM_CDATA_SECTION_NODE) {
 
52
    return domCreateCDATASection(doc, node.nodeValue);
 
53
 
 
54
  } else if (node.nodeType == DOM_ELEMENT_NODE) {
 
55
    var newNode = domCreateElement(doc, node.nodeName);
 
56
    for (var i = 0; i < node.attributes.length; ++i) {
 
57
      var an = node.attributes[i];
 
58
      var name = an.nodeName;
 
59
      var value = an.nodeValue;
 
60
      domSetAttribute(newNode, name, value);
 
61
    }
 
62
 
 
63
    for (var c = node.firstChild; c; c = c.nextSibling) {
 
64
      var cn = arguments.callee(doc, c);
 
65
      domAppendChild(newNode, cn);
 
66
    }
 
67
 
 
68
    return newNode;
 
69
 
 
70
  } else {
 
71
    return domCreateComment(doc, node.nodeName);
 
72
  }
 
73
}
 
74
 
 
75
// A set data structure. It can also be used as a map (i.e. the keys
 
76
// can have values other than 1), but we don't call it map because it
 
77
// would be ambiguous in this context. Also, the map is iterable, so
 
78
// we can use it to replace for-in loops over core javascript Objects.
 
79
// For-in iteration breaks when Object.prototype is modified, which
 
80
// some clients of the maps API do.
 
81
//
 
82
// NOTE(mesch): The set keys by the string value of its element, NOT
 
83
// by the typed value. In particular, objects can't be used as keys.
 
84
//
 
85
// @constructor
 
86
function Set() {
 
87
  this.keys = [];
 
88
}
 
89
 
 
90
Set.prototype.size = function() {
 
91
  return this.keys.length;
 
92
}
 
93
 
 
94
// Adds the entry to the set, ignoring if it is present.
 
95
Set.prototype.add = function(key, opt_value) {
 
96
  var value = opt_value || 1;
 
97
  if (!this.contains(key)) {
 
98
    this[':' + key] = value;
 
99
    this.keys.push(key);
 
100
  }
 
101
}
 
102
 
 
103
// Sets the entry in the set, adding if it is not yet present.
 
104
Set.prototype.set = function(key, opt_value) {
 
105
  var value = opt_value || 1;
 
106
  if (!this.contains(key)) {
 
107
    this[':' + key] = value;
 
108
    this.keys.push(key);
 
109
  } else {
 
110
    this[':' + key] = value;
 
111
  }
 
112
}
 
113
 
 
114
// Increments the key's value by 1. This works around the fact that
 
115
// numbers are always passed by value, never by reference, so that we
 
116
// can't increment the value returned by get(), or the iterator
 
117
// argument. Sets the key's value to 1 if it doesn't exist yet.
 
118
Set.prototype.inc = function(key) {
 
119
  if (!this.contains(key)) {
 
120
    this[':' + key] = 1;
 
121
    this.keys.push(key);
 
122
  } else {
 
123
    this[':' + key]++;
 
124
  }
 
125
}
 
126
 
 
127
Set.prototype.get = function(key) {
 
128
  if (this.contains(key)) {
 
129
    return this[':' + key];
 
130
  } else {
 
131
    var undefined;
 
132
    return undefined;
 
133
  }
 
134
}
 
135
 
 
136
// Removes the entry from the set.
 
137
Set.prototype.remove = function(key) {
 
138
  if (this.contains(key)) {
 
139
    delete this[':' + key];
 
140
    removeFromArray(this.keys, key, true);
 
141
  }
 
142
}
 
143
 
 
144
// Tests if an entry is in the set.
 
145
Set.prototype.contains = function(entry) {
 
146
  return typeof this[':' + entry] != 'undefined';
 
147
}
 
148
 
 
149
// Gets a list of values in the set.
 
150
Set.prototype.items = function() {
 
151
  var list = [];
 
152
  for (var i = 0; i < this.keys.length; ++i) {
 
153
    var k = this.keys[i];
 
154
    var v = this[':' + k];
 
155
    list.push(v);
 
156
  }
 
157
  return list;
 
158
}
 
159
 
 
160
 
 
161
// Invokes function f for every key value pair in the set as a method
 
162
// of the set.
 
163
Set.prototype.map = function(f) {
 
164
  for (var i = 0; i < this.keys.length; ++i) {
 
165
    var k = this.keys[i];
 
166
    f.call(this, k, this[':' + k]);
 
167
  }
 
168
}
 
169
 
 
170
Set.prototype.clear = function() {
 
171
  for (var i = 0; i < this.keys.length; ++i) {
 
172
    delete this[':' + this.keys[i]];
 
173
  }
 
174
  this.keys.length = 0;
 
175
}
 
176
 
 
177
 
 
178
// Applies the given function to each element of the array, preserving
 
179
// this, and passing the index.
 
180
function mapExec(array, func) {
 
181
  for (var i = 0; i < array.length; ++i) {
 
182
    func.call(this, array[i], i);
 
183
  }
 
184
}
 
185
 
 
186
// Returns an array that contains the return value of the given
 
187
// function applied to every element of the input array.
 
188
function mapExpr(array, func) {
 
189
  var ret = [];
 
190
  for (var i = 0; i < array.length; ++i) {
 
191
    ret.push(func(array[i]));
 
192
  }
 
193
  return ret;
 
194
};
 
195
 
 
196
// Reverses the given array in place.
 
197
function reverseInplace(array) {
 
198
  for (var i = 0; i < array.length / 2; ++i) {
 
199
    var h = array[i];
 
200
    var ii = array.length - i - 1;
 
201
    array[i] = array[ii];
 
202
    array[ii] = h;
 
203
  }
 
204
}
 
205
 
 
206
// Removes value from array. Returns the number of instances of value
 
207
// that were removed from array.
 
208
function removeFromArray(array, value, opt_notype) {
 
209
  var shift = 0;
 
210
  for (var i = 0; i < array.length; ++i) {
 
211
    if (array[i] === value || (opt_notype && array[i] == value)) {
 
212
      array.splice(i--, 1);
 
213
      shift++;
 
214
    }
 
215
  }
 
216
  return shift;
 
217
}
 
218
 
 
219
// Shallow-copies an array to the end of another array
 
220
// Basically Array.concat, but works with other non-array collections
 
221
function copyArray(dst, src) {
 
222
  if (!src) return;
 
223
  var dstLength = dst.length;
 
224
  for (var i = src.length - 1; i >= 0; --i) {
 
225
    dst[i+dstLength] = src[i];
 
226
  }
 
227
}
 
228
 
 
229
/**
 
230
 * This is an optimization for copying attribute lists in IE. IE includes many
 
231
 * extraneous properties in its DOM attribute lists, which take require
 
232
 * significant extra processing when evaluating attribute steps. With this
 
233
 * function, we ignore any such attributes that has an empty string value.
 
234
 */
 
235
function copyArrayIgnoringAttributesWithoutValue(dst, src)
 
236
{
 
237
  if (!src) return;
 
238
  for (var i = src.length - 1; i >= 0; --i) {
 
239
    // this test will pass so long as the attribute has a non-empty string
 
240
    // value, even if that value is "false", "0", "undefined", etc.
 
241
    if (src[i].nodeValue) {
 
242
      dst.push(src[i]);
 
243
    }
 
244
  }
 
245
}
 
246
 
 
247
// Returns the text value of a node; for nodes without children this
 
248
// is the nodeValue, for nodes with children this is the concatenation
 
249
// of the value of all children. Browser-specific optimizations are used by
 
250
// default; they can be disabled by passing "true" in as the second parameter.
 
251
function xmlValue(node, disallowBrowserSpecificOptimization) {
 
252
  if (!node) {
 
253
    return '';
 
254
  }
 
255
 
 
256
  var ret = '';
 
257
  if (node.nodeType == DOM_TEXT_NODE ||
 
258
      node.nodeType == DOM_CDATA_SECTION_NODE) {
 
259
    ret += node.nodeValue;
 
260
 
 
261
  } else if (node.nodeType == DOM_ATTRIBUTE_NODE) {
 
262
    if (ajaxsltIsIE6) {
 
263
      ret += xmlValueIE6Hack(node);
 
264
    } else {
 
265
      ret += node.nodeValue;
 
266
    }
 
267
  } else if (node.nodeType == DOM_ELEMENT_NODE ||
 
268
             node.nodeType == DOM_DOCUMENT_NODE ||
 
269
             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
 
270
    if (!disallowBrowserSpecificOptimization) {
 
271
      // IE, Safari, Opera, and friends
 
272
      var innerText = node.innerText;
 
273
      if (innerText != undefined) {
 
274
        return innerText;
 
275
      }
 
276
      // Firefox
 
277
      var textContent = node.textContent;
 
278
      if (textContent != undefined) {
 
279
        return textContent;
 
280
      }
 
281
    }
 
282
    // pobrecito!
 
283
    var len = node.childNodes.length;
 
284
    for (var i = 0; i < len; ++i) {
 
285
      ret += arguments.callee(node.childNodes[i]);
 
286
    }
 
287
  }
 
288
  return ret;
 
289
}
 
290
 
 
291
function xmlValueIE6Hack(node) {
 
292
    // Issue 19, IE6 mangles href attribute when it's a javascript: url
 
293
    var nodeName = node.nodeName;
 
294
    var nodeValue = node.nodeValue;
 
295
    if (nodeName.length != 4) return nodeValue;
 
296
    if (!/^href$/i.test(nodeName)) return nodeValue;
 
297
    if (!/^javascript:/.test(nodeValue)) return nodeValue;
 
298
    return unescape(nodeValue);
 
299
}
 
300
 
 
301
// Returns the representation of a node as XML text.
 
302
function xmlText(node, opt_cdata) {
 
303
  var buf = [];
 
304
  xmlTextR(node, buf, opt_cdata);
 
305
  return buf.join('');
 
306
}
 
307
 
 
308
function xmlTextR(node, buf, cdata) {
 
309
  if (node.nodeType == DOM_TEXT_NODE) {
 
310
    buf.push(xmlEscapeText(node.nodeValue));
 
311
 
 
312
  } else if (node.nodeType == DOM_CDATA_SECTION_NODE) {
 
313
    if (cdata) {
 
314
      buf.push(node.nodeValue);
 
315
    } else {
 
316
      buf.push('<![CDATA[' + node.nodeValue + ']]>');
 
317
    }
 
318
 
 
319
  } else if (node.nodeType == DOM_COMMENT_NODE) {
 
320
    buf.push('<!--' + node.nodeValue + '-->');
 
321
 
 
322
  } else if (node.nodeType == DOM_ELEMENT_NODE) {
 
323
    buf.push('<' + xmlFullNodeName(node));
 
324
    for (var i = 0; i < node.attributes.length; ++i) {
 
325
      var a = node.attributes[i];
 
326
      if (a && a.nodeName && a.nodeValue) {
 
327
        buf.push(' ' + xmlFullNodeName(a) + '="' +
 
328
                 xmlEscapeAttr(a.nodeValue) + '"');
 
329
      }
 
330
    }
 
331
 
 
332
    if (node.childNodes.length == 0) {
 
333
      buf.push('/>');
 
334
    } else {
 
335
      buf.push('>');
 
336
      for (var i = 0; i < node.childNodes.length; ++i) {
 
337
        arguments.callee(node.childNodes[i], buf, cdata);
 
338
      }
 
339
      buf.push('</' + xmlFullNodeName(node) + '>');
 
340
    }
 
341
 
 
342
  } else if (node.nodeType == DOM_DOCUMENT_NODE ||
 
343
             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
 
344
    for (var i = 0; i < node.childNodes.length; ++i) {
 
345
      arguments.callee(node.childNodes[i], buf, cdata);
 
346
    }
 
347
  }
 
348
}
 
349
 
 
350
function xmlFullNodeName(n) {
 
351
  if (n.prefix && n.nodeName.indexOf(n.prefix + ':') != 0) {
 
352
    return n.prefix + ':' + n.nodeName;
 
353
  } else {
 
354
    return n.nodeName;
 
355
  }
 
356
}
 
357
 
 
358
// Escape XML special markup chracters: tag delimiter < > and entity
 
359
// reference start delimiter &. The escaped string can be used in XML
 
360
// text portions (i.e. between tags).
 
361
function xmlEscapeText(s) {
 
362
  return ('' + s).replace(/&/g, '&amp;').replace(/</g, '&lt;').
 
363
    replace(/>/g, '&gt;');
 
364
}
 
365
 
 
366
// Escape XML special markup characters: tag delimiter < > entity
 
367
// reference start delimiter & and quotes ". The escaped string can be
 
368
// used in double quoted XML attribute value portions (i.e. in
 
369
// attributes within start tags).
 
370
function xmlEscapeAttr(s) {
 
371
  return xmlEscapeText(s).replace(/\"/g, '&quot;');
 
372
}
 
373
 
 
374
// Escape markup in XML text, but don't touch entity references. The
 
375
// escaped string can be used as XML text (i.e. between tags).
 
376
function xmlEscapeTags(s) {
 
377
  return s.replace(/</g, '&lt;').replace(/>/g, '&gt;');
 
378
}
 
379
 
 
380
/**
 
381
 * Wrapper function to access the owner document uniformly for document
 
382
 * and other nodes: for the document node, the owner document is the
 
383
 * node itself, for all others it's the ownerDocument property.
 
384
 *
 
385
 * @param {Node} node
 
386
 * @return {Document}
 
387
 */
 
388
function xmlOwnerDocument(node) {
 
389
  if (node.nodeType == DOM_DOCUMENT_NODE) {
 
390
    return node;
 
391
  } else {
 
392
    return node.ownerDocument;
 
393
  }
 
394
}
 
395
 
 
396
// Wrapper around DOM methods so we can condense their invocations.
 
397
function domGetAttribute(node, name) {
 
398
  return node.getAttribute(name);
 
399
}
 
400
 
 
401
function domSetAttribute(node, name, value) {
 
402
  return node.setAttribute(name, value);
 
403
}
 
404
 
 
405
function domRemoveAttribute(node, name) {
 
406
  return node.removeAttribute(name);
 
407
}
 
408
 
 
409
function domAppendChild(node, child) {
 
410
  return node.appendChild(child);
 
411
}
 
412
 
 
413
function domRemoveChild(node, child) {
 
414
  return node.removeChild(child);
 
415
}
 
416
 
 
417
function domReplaceChild(node, newChild, oldChild) {
 
418
  return node.replaceChild(newChild, oldChild);
 
419
}
 
420
 
 
421
function domInsertBefore(node, newChild, oldChild) {
 
422
  return node.insertBefore(newChild, oldChild);
 
423
}
 
424
 
 
425
function domRemoveNode(node) {
 
426
  return domRemoveChild(node.parentNode, node);
 
427
}
 
428
 
 
429
function domCreateTextNode(doc, text) {
 
430
  return doc.createTextNode(text);
 
431
}
 
432
 
 
433
function domCreateElement(doc, name) {
 
434
  return doc.createElement(name);
 
435
}
 
436
 
 
437
function domCreateAttribute(doc, name) {
 
438
  return doc.createAttribute(name);
 
439
}
 
440
 
 
441
function domCreateCDATASection(doc, data) {
 
442
  return doc.createCDATASection(data);
 
443
}
 
444
 
 
445
function domCreateComment(doc, text) {
 
446
  return doc.createComment(text);
 
447
}
 
448
 
 
449
function domCreateDocumentFragment(doc) {
 
450
  return doc.createDocumentFragment();
 
451
}
 
452
 
 
453
function domGetElementById(doc, id) {
 
454
  return doc.getElementById(id);
 
455
}
 
456
 
 
457
// Same for window methods.
 
458
function windowSetInterval(win, fun, time) {
 
459
  return win.setInterval(fun, time);
 
460
}
 
461
 
 
462
function windowClearInterval(win, id) {
 
463
  return win.clearInterval(id);
 
464
}
 
465
 
 
466
/**
 
467
 * Escape the special regular expression characters when the regular expression
 
468
 * is specified as a string.
 
469
 *
 
470
 * Based on: http://simonwillison.net/2006/Jan/20/escape/
 
471
 */
 
472
RegExp.escape = (function() {
 
473
  var specials = [
 
474
    '/', '.', '*', '+', '?', '|', '^', '$',
 
475
    '(', ')', '[', ']', '{', '}', '\\'
 
476
  ];
 
477
    
 
478
  var sRE = new RegExp(
 
479
    '(\\' + specials.join('|\\') + ')', 'g'
 
480
  );
 
481
    
 
482
  return function(text) {
 
483
    return text.replace(sRE, '\\$1');
 
484
  }
 
485
})();
 
486
 
 
487
/**
 
488
 * Determines whether a predicate expression contains a "positional selector".
 
489
 * A positional selector filters nodes from the nodelist input based on their
 
490
 * position within that list. When such selectors are encountered, the
 
491
 * evaluation of the predicate cannot be depth-first, because the positional
 
492
 * selector may be based on the result of evaluating predicates that precede
 
493
 * it.
 
494
 */
 
495
function predicateExprHasPositionalSelector(expr, isRecursiveCall) {
 
496
  if (!expr) {
 
497
    return false;
 
498
  }
 
499
  if (!isRecursiveCall && exprReturnsNumberValue(expr)) {
 
500
    // this is a "proximity position"-based predicate
 
501
    return true;
 
502
  }
 
503
  if (expr instanceof FunctionCallExpr) {
 
504
    var value = expr.name.value;
 
505
    return (value == 'last' || value == 'position');
 
506
  }
 
507
  if (expr instanceof BinaryExpr) {
 
508
    return (
 
509
      predicateExprHasPositionalSelector(expr.expr1, true) ||
 
510
      predicateExprHasPositionalSelector(expr.expr2, true));
 
511
  }
 
512
  return false;
 
513
}
 
514
 
 
515
function exprReturnsNumberValue(expr) {
 
516
  if (expr instanceof FunctionCallExpr) {
 
517
    var isMember = {
 
518
      last: true
 
519
      , position: true
 
520
      , count: true
 
521
      , 'string-length': true
 
522
      , number: true
 
523
      , sum: true
 
524
      , floor: true
 
525
      , ceiling: true
 
526
      , round: true
 
527
    };
 
528
    return isMember[expr.name.value];
 
529
  }
 
530
  else if (expr instanceof UnaryMinusExpr) {
 
531
    return true;
 
532
  }
 
533
  else if (expr instanceof BinaryExpr) {
 
534
    var isMember = {
 
535
      '+': true
 
536
      , '-': true
 
537
      , '*': true
 
538
      , mod: true
 
539
      , div: true
 
540
    };
 
541
    return isMember[expr.op.value];
 
542
  }
 
543
  else if (expr instanceof NumberExpr) {
 
544
    return true;
 
545
  }
 
546
  return false;
 
547
}
 
548
 
 
549