Changeset 2821

Show
Ignore:
Timestamp:
12/22/06 15:47:46 (2 months ago)
Author:
demian
Message:

updating scriptaculous to 1.6.5

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • vendor/scriptaculous/CHANGELOG

    r2697 r2821  
     1*V1.6.5* (November 8, 2006) 
     2 
     3* Update to Prototype 1.5.0_rc1 revision [5462] 
     4 
     5* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd] 
     6 
     7    var node = Builder.node('label', { htmlFor: 'myinput' }); 
     8 
     9* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo] 
     10 
     11* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower] 
     12 
     13* Add rails-trunk update task, clean up references to MIT license 
     14 
     15* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue 
     16 
     17* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues 
     18 
     19    new Effect.Event({ afterFinish:function(){ 
     20      // do some code here 
     21    }, position: 'end' }); 
     22 
     23* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC 
     24 
     25* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel] 
     26 
     27* Add Builder.build() to create nodes from strings containing HTML, [DHH] 
     28 
     29    var node = Builder.build("<p>this is <b>neat!</b></p>"); 
     30 
     31* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo] 
     32 
     33    For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses. 
     34 
     35* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin] 
     36 
     37* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd] 
     38 
     39*V1.6.4* (September 6, 2006) 
     40 
     41* Hotfix IE issues with patched Prototype V1.5.0_rc1 
     42 
     43*V1.6.3* (September 5, 2006) 
     44 
     45* Update Prototype to V1.5.0_rc1 
     46 
     47* Merge assertElementsMatch and assertElementMatches from Prototype's [4986] unittest.js [Sam Stephenson] 
     48 
     49* Update Prototype to revision [4930] 
     50 
     51* Fix various issues with IE detection and Opera, and setOpacity, fixes #3886, #5973 
     52 
     53* Make Sortable.serialize handle DOM IDs like "some_element_1" correctly, fixes #5324 
     54 
     55* Add assertRespondsTo and shouldRespondTo assertions 
     56 
     57* Add experimental alternate syntax for unit tests (Behaviour Driven Development-style) 
     58 
     59* Add support for onStart, onDrag and onEnd events directly on Draggables (invoked from the Draggables.notify), fixes #4747 [thx scriptkitchen] 
     60 
     61* Add element shortcuts to Builder that can be activated by calling Builder.dump() (see the unit test), fixes #4260 [thx napalm] 
     62 
     63* Fix selection of correct option in SELECT element generated by InPlaceCollectionEditor for indexed option arrays, fixes #4789 [thx steve] 
     64 
     65* Add autoSelect option to Autocompleters to auto select an entry if only one is returned, fixes #5183 [thx cassiano dandrea] 
     66 
     67* Added delay option to Draggables and Sortables, see test/functional/dragdrop_delay_test.html for usage, implements #3325 [thx lsimon, tomg] 
     68 
     69* Remove revert cache code obsoleted by #4706, fixes #3436 (again) [thx tomg] 
     70 
     71* Fix autoscrolling inside scrollable containers when window is scrolled too, fixes #5200 [thx wseitz] 
     72 
     73* Make Effect.Puff work correctly for floating elements, fixes #3777 [thx michael hartl] 
     74 
     75* Add version and timestamp to indvidual library files for easier identification (the files are preprocessed by the Rake fresh_scriptaculous task), fixes #3015 [thx Tobie] 
     76 
     77* Add assertIndentical and assertNotIdentical unit test assertions, which test for equality and common type, fixes #5822 [thx glazedginger] 
     78 
     79* Add integration test for Ajax autocompleter for results with no linebreaks, #4149 
     80 
     81* Fix an issue with redrawing ghosted draggables that are inside a scrolled container, fixes #3860 [thx gkupps, tsukue] 
     82 
     83* Added a custom exception to all base effects when used on non-existing DOM elements, added a assertRaise method to unit tests 
     84 
     85* Fix autoscrolling when dragging an element unto a scrollable container, fixes #5017 [thx tomg] 
     86 
     87* Fix a condition where overriding the endeffect on Draggables without overriding the starteffect too leads to a Javascript error [thx Javier Martinez] 
     88 
     89* Fix a possible error with the drag/drop logic (affects the solution to #4706) 
     90 
     91*V1.6.2* 
     92 
     93* Fix a problem in the drag and drop logic if an reverting/drag ending draggable was initialized for a new drag (for example by clicking repeatedly) for all cases where the default start/revert/end-effects are used, fixes #4706 [thx tecM0] 
     94 
     95* Fix possible memory leaks with Draggables, fixes #3436 [thx aal] 
     96 
     97* Throw nicer errors when requires script.aculo.us libraries are not loaded, fixes #5339 
     98 
     99* Make slider handles work when not displayed initially by using CSS width/height, fixes #4011 [thx foysavas] 
     100 
     101* Update sortable functional test with onUpdate counter 
     102 
     103* Make more Element extensions unit tests work on Safari 
     104 
     105* Add the assertMatch unit test assertion for asserts with RegExps [thx Ian Tyndall] 
     106 
     107* Fix a problem with Effect.Move causing "jumping" elements because of very low float numbers in some situations 
     108 
     109* Fix a missing semicolon in dragdrop.js, fixes #5569 [thx mackalicious] 
     110 
     111* Fix a slight inaccuracy with Effect.Scale that could lead the scaling to be one pixel off 
     112 
     113* Be more prototypish with Effect.Transitions.linear 
     114 
     115* Make Effect.Scale recognize font sizes that use the pt unit, fixes #4136 [thx aljoscha] 
     116 
     117* Fix IE hack in Effect.Opacity, fixes #5444 [thx nicholas] 
     118 
     119* Fix IFRAME layout fix for IE and Autocompleter, fixes #5192 [thx tommy skaue] 
     120 
     121* Fix only option in onEmptyHover, fiex #5348 [thx glenn nilsson] 
     122 
     123* Fix Effect.BlindDown and SwitchOff handling of supplied callbacks, fixes #5089 [thx martinstrom] 
     124 
     125* Fix a problem with field focus on Ajax.InPlaceEditor and loading external text, fixes #4988, #5244 [thx rob] 
     126 
     127* Do not attempt to scroll if scrollspeed is 0/0, fixes #5035 [thx tomg] 
     128 
     129* Fix a problem with Sortable Tree serialization, fixes #4939, #4688, #4767  [thx Sammi Williams] 
     130 
     131* Fix an endless loop with sliders, fixes #3226, #4051, #4765 [thx jeff] 
     132 
     133* Make autocompleter work with update DIVs that have scrollbars, fixes #4782 [thx Tommy Skaue] 
     134 
     135* Corrected options parsing on switchoff effect, fixes #4710 [thx haldini] 
     136 
    1137*V1.6.1* 
    2138 
  • vendor/scriptaculous/MIT-LICENSE

    r2697 r2821  
    1 Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     1Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    22 
    33Permission is hereby granted, free of charge, to any person obtaining 
  • vendor/scriptaculous/VERSION

    r2697 r2821  
    1 1.6.1 
     11.6.5 
  • vendor/scriptaculous/lib/prototype.js

    r2697 r2821  
    1 /*  Prototype JavaScript framework, version 1.5.0_rc0 
     1/*  Prototype JavaScript framework, version 1.5.0_rc1 
    22 *  (c) 2005 Sam Stephenson <sam@conio.net> 
    33 * 
     
    88 
    99var Prototype = { 
    10   Version: '1.5.0_rc0', 
     10  Version: '1.5.0_rc1', 
     11  BrowserFeatures: { 
     12    XPath: !!document.evaluate 
     13  }, 
     14 
    1115  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 
    12  
    1316  emptyFunction: function() {}, 
    14   K: function(x) {return x
     17  K: function(x) { return x
    1518} 
    1619 
     
    3235} 
    3336 
    34 Object.inspect = function(object) { 
    35   try { 
    36     if (object == undefined) return 'undefined'; 
    37     if (object == null) return 'null'; 
    38     return object.inspect ? object.inspect() : object.toString(); 
    39   } catch (e) { 
    40     if (e instanceof RangeError) return '...'; 
    41     throw e; 
    42   } 
    43 
     37Object.extend(Object, { 
     38  inspect: function(object) { 
     39    try { 
     40      if (object === undefined) return 'undefined'; 
     41      if (object === null) return 'null'; 
     42      return object.inspect ? object.inspect() : object.toString(); 
     43    } catch (e) { 
     44      if (e instanceof RangeError) return '...'; 
     45      throw e; 
     46    } 
     47  }, 
     48 
     49  keys: function(object) { 
     50    var keys = []; 
     51    for (var property in object) 
     52      keys.push(property); 
     53    return keys; 
     54  }, 
     55 
     56  values: function(object) { 
     57    var values = []; 
     58    for (var property in object) 
     59      values.push(object[property]); 
     60    return values; 
     61  }, 
     62 
     63  clone: function(object) { 
     64    return Object.extend({}, object); 
     65  } 
     66}); 
    4467 
    4568Function.prototype.bind = function() { 
     
    5174 
    5275Function.prototype.bindAsEventListener = function(object) { 
    53   var __method = this
     76  var __method = this, args = $A(arguments), object = args.shift()
    5477  return function(event) { 
    55     return __method.call(object, event || window.event); 
     78    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); 
    5679  } 
    5780} 
     
    103126 
    104127  registerCallback: function() { 
    105     setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 
     128    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 
     129  }, 
     130 
     131  stop: function() { 
     132    if (!this.timer) return; 
     133    clearInterval(this.timer); 
     134    this.timer = null; 
    106135  }, 
    107136 
     
    110139      try { 
    111140        this.currentlyExecuting = true; 
    112         this.callback(); 
     141        this.callback(this); 
    113142      } finally { 
    114143        this.currentlyExecuting = false; 
     
    194223 
    195224  toQueryParams: function() { 
    196     var pairs = this.match(/^\??(.*)$/)[1].split('&'); 
     225    var match = this.strip().match(/[^?]*$/)[0]; 
     226    if (!match) return {}; 
     227    var pairs = match.split('&'); 
    197228    return pairs.inject({}, function(params, pairString) { 
    198       var pair = pairString.split('='); 
    199       params[pair[0]] = pair[1]; 
     229      var pair  = pairString.split('='); 
     230      var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; 
     231      params[decodeURIComponent(pair[0])] = value; 
    200232      return params; 
    201233    }); 
     
    214246      : oStringList[0]; 
    215247 
    216     for (var i = 1, len = oStringList.length; i < len; i++) { 
     248    for (var i = 1, length = oStringList.length; i < length; i++) { 
    217249      var s = oStringList[i]; 
    218250      camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 
     
    222254  }, 
    223255 
    224   inspect: function() { 
    225     return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; 
     256  inspect: function(useDoubleQuotes) { 
     257    var escapedString = this.replace(/\\/g, '\\\\'); 
     258    if (useDoubleQuotes) 
     259      return '"' + escapedString.replace(/"/g, '\\"') + '"'; 
     260    else 
     261      return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 
    226262  } 
    227263}); 
     
    269305      if (e != $break) throw e; 
    270306    } 
     307    return this; 
     308  }, 
     309 
     310  eachSlice: function(number, iterator) { 
     311    var index = -number, slices = [], array = this.toArray(); 
     312    while ((index += number) < array.length) 
     313      slices.push(array.slice(index, index+number)); 
     314    return slices.collect(iterator || Prototype.K); 
    271315  }, 
    272316 
     
    281325 
    282326  any: function(iterator) { 
    283     var result = true; 
     327    var result = false; 
    284328    this.each(function(value, index) { 
    285329      if (result = !!(iterator || Prototype.K)(value, index)) 
     
    297341  }, 
    298342 
    299   detect: function (iterator) { 
     343  detect: function(iterator) { 
    300344    var result; 
    301345    this.each(function(value, index) { 
     
    336380    }); 
    337381    return found; 
     382  }, 
     383 
     384  inGroupsOf: function(number, fillWith) { 
     385    fillWith = fillWith || null; 
     386    var results = this.eachSlice(number); 
     387    if (results.length > 0) (number - results.last().length).times(function() { 
     388      results.last().push(fillWith) 
     389    }); 
     390    return results; 
    338391  }, 
    339392 
     
    440493  } else { 
    441494    var results = []; 
    442     for (var i = 0; i < iterable.length; i++) 
     495    for (var i = 0, length = iterable.length; i < length; i++) 
    443496      results.push(iterable[i]); 
    444497    return results; 
     
    453506Object.extend(Array.prototype, { 
    454507  _each: function(iterator) { 
    455     for (var i = 0; i < this.length; i++) 
     508    for (var i = 0, length = this.length; i < length; i++) 
    456509      iterator(this[i]); 
    457510  }, 
     
    491544 
    492545  indexOf: function(object) { 
    493     for (var i = 0; i < this.length; i++) 
     546    for (var i = 0, length = this.length; i < length; i++) 
    494547      if (this[i] == object) return i; 
    495548    return -1; 
     
    500553  }, 
    501554 
     555  reduce: function() { 
     556    return this.length > 1 ? this : this[0]; 
     557  }, 
     558 
     559  uniq: function() { 
     560    return this.inject([], function(array, value) { 
     561      return array.include(value) ? array : array.concat([value]); 
     562    }); 
     563  }, 
     564 
     565  clone: function() { 
     566    return [].concat(this); 
     567  }, 
     568 
    502569  inspect: function() { 
    503570    return '[' + this.map(Object.inspect).join(', ') + ']'; 
    504571  } 
    505572}); 
     573 
     574Array.prototype.toArray = Array.prototype.clone; 
    506575var Hash = { 
    507576  _each: function(iterator) { 
     
    526595 
    527596  merge: function(hash) { 
    528     return $H(hash).inject($H(this), function(mergedHash, pair) { 
     597    return $H(hash).inject(this, function(mergedHash, pair) { 
    529598      mergedHash[pair.key] = pair.value; 
    530599      return mergedHash; 
     
    534603  toQueryString: function() { 
    535604    return this.map(function(pair) { 
     605      if (!pair.value && pair.value !== 0) pair[1] = ''; 
     606      if (!pair.key) return; 
    536607      return pair.map(encodeURIComponent).join('='); 
    537608    }).join('&'); 
     
    562633  _each: function(iterator) { 
    563634    var value = this.start; 
    564     do
     635    while (this.include(value))
    565636      iterator(value); 
    566637      value = value.succ(); 
    567     } while (this.include(value)); 
     638    } 
    568639  }, 
    569640 
     
    600671  }, 
    601672 
    602   register: function(responderToAdd) { 
    603     if (!this.include(responderToAdd)) 
    604       this.responders.push(responderToAdd); 
    605   }, 
    606  
    607   unregister: function(responderToRemove) { 
    608     this.responders = this.responders.without(responderToRemove); 
     673  register: function(responder) { 
     674    if (!this.include(responder)) 
     675      this.responders.push(responder); 
     676  }, 
     677 
     678  unregister: function(responder) { 
     679    this.responders = this.responders.without(responder); 
    609680  }, 
    610681 
    611682  dispatch: function(callback, request, transport, json) { 
    612683    this.each(function(responder) { 
    613       if (responder[callback] && typeof responder[callback] == 'function') { 
     684      if (typeof responder[callback] == 'function') { 
    614685        try { 
    615686          responder[callback].apply(responder, [request, transport, json]); 
     
    626697    Ajax.activeRequestCount++; 
    627698  }, 
    628  
    629699  onComplete: function() { 
    630700    Ajax.activeRequestCount--; 
     
    639709      asynchronous: true, 
    640710      contentType:  'application/x-www-form-urlencoded', 
     711      encoding:     'UTF-8', 
    641712      parameters:   '' 
    642713    } 
    643714    Object.extend(this.options, options || {}); 
    644   }, 
    645  
    646   responseIsSuccess: function() { 
    647     return this.transport.status == undefined 
    648         || this.transport.status == 0 
    649         || (this.transport.status >= 200 && this.transport.status < 300); 
    650   }, 
    651  
    652   responseIsFailure: function() { 
    653     return !this.responseIsSuccess(); 
     715 
     716    this.options.method = this.options.method.toLowerCase(); 
     717    this.options.parameters = $H(typeof this.options.parameters == 'string' ? 
     718      this.options.parameters.toQueryParams() : this.options.parameters); 
    654719  } 
    655720} 
     
    667732 
    668733  request: function(url) { 
    669     var parameters = this.options.parameters || ''; 
    670     if (parameters.length > 0) parameters += '&_='; 
     734    var params = this.options.parameters; 
     735    if (params.any()) params['_'] = ''; 
     736 
     737    if (!['get', 'post'].include(this.options.method)) { 
     738      // simulate other verbs over post 
     739      params['_method'] = this.options.method; 
     740      this.options.method = 'post'; 
     741    } 
     742 
     743    this.url = url; 
     744 
     745    // when GET, append parameters to URL 
     746    if (this.options.method == 'get' && params.any()) 
     747      this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') + 
     748        params.toQueryString(); 
    671749 
    672750    try { 
    673       this.url = url; 
    674       if (this.options.method == 'get' && parameters.length > 0) 
    675         this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; 
    676  
    677751      Ajax.Responders.dispatch('onCreate', this, this.transport); 
    678752 
    679       this.transport.open(this.options.method, this.url, 
    680         this.options.asynchronous); 
    681  
    682       if (this.options.asynchronous) { 
    683         this.transport.onreadystatechange = this.onStateChange.bind(this); 
    684         setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); 
     753      this.transport.open(this.options.method.toUpperCase(), this.url, 
     754        this.options.asynchronous, this.options.username, 
     755        this.options.password); 
     756 
     757      if (this.options.asynchronous) 
     758        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); 
     759 
     760      this.transport.onreadystatechange = this.onStateChange.bind(this); 
     761      this.setRequestHeaders(); 
     762 
     763      var body = this.options.method == 'post' ? 
     764        (this.options.postBody || params.toQueryString()) : null; 
     765 
     766      this.transport.send(body); 
     767 
     768      /* Force Firefox to handle ready state 4 for synchronous requests */ 
     769      if (!this.options.asynchronous && this.transport.overrideMimeType) 
     770        this.onStateChange(); 
     771    } 
     772    catch (e) { 
     773      this.dispatchException(e); 
     774    } 
     775  }, 
     776 
     777  onStateChange: function() { 
     778    var readyState = this.transport.readyState; 
     779    if (readyState > 1) 
     780      this.respondToReadyState(this.transport.readyState); 
     781  }, 
     782 
     783  setRequestHeaders: function() { 
     784    var headers = { 
     785      'X-Requested-With': 'XMLHttpRequest', 
     786      'X-Prototype-Version': Prototype.Version, 
     787      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 
     788    }; 
     789 
     790    if (this.options.method == 'post') { 
     791      headers['Content-type'] = this.options.contentType + 
     792        (this.options.encoding ? '; charset=' + this.options.encoding : ''); 
     793 
     794      /* Force "Connection: close" for older Mozilla browsers to work 
     795       * around a bug where XMLHttpRequest sends an incorrect 
     796       * Content-length header. See Mozilla Bugzilla #246651. 
     797       */ 
     798      if (this.transport.overrideMimeType && 
     799          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 
     800            headers['Connection'] = 'close'; 
     801    } 
     802 
     803    // user-defined headers 
     804    if (typeof this.options.requestHeaders == 'object') { 
     805      var extras = this.options.requestHeaders; 
     806 
     807      if (typeof extras.push == 'function') 
     808        for (var i = 0; i < extras.length; i += 2) 
     809          headers[extras[i]] = extras[i+1]; 
     810      else 
     811        $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 
     812    } 
     813 
     814    for (var name in headers) 
     815      this.transport.setRequestHeader(name, headers[name]); 
     816  }, 
     817 
     818  success: function() { 
     819    return !this.transport.status 
     820        || (this.transport.status >= 200 && this.transport.status < 300); 
     821  }, 
     822 
     823  respondToReadyState: function(readyState) { 
     824    var state = Ajax.Request.Events[readyState]; 
     825    var transport = this.transport, json = this.evalJSON(); 
     826 
     827    if (state == 'Complete') { 
     828      try { 
     829        (this.options['on' + this.transport.status] 
     830         || this.options['on' + (this.success() ? 'Success' : 'Failure')] 
     831         || Prototype.emptyFunction)(transport, json); 
     832      } catch (e) { 
     833        this.dispatchException(e); 
    685834      } 
    686  
    687       this.setRequestHeaders(); 
    688  
    689       var body = this.options.postBody ? this.options.postBody : parameters; 
    690       this.transport.send(this.options.method == 'post' ? body : null); 
    691  
     835    } 
     836 
     837    try { 
     838      (this.options['on' + state] || Prototype.emptyFunction)(transport, json); 
     839      Ajax.Responders.dispatch('on' + state, this, transport, json); 
    692840    } catch (e) { 
    693841      this.dispatchException(e); 
    694842    } 
    695   }, 
    696  
    697   setRequestHeaders: function() { 
    698     var requestHeaders = 
    699       ['X-Requested-With', 'XMLHttpRequest', 
    700        'X-Prototype-Version', Prototype.Version, 
    701        'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; 
    702  
    703     if (this.options.method == 'post') { 
    704       requestHeaders.push('Content-type', this.options.contentType); 
    705  
    706       /* Force "Connection: close" for Mozilla browsers to work around 
    707        * a bug where XMLHttpReqeuest sends an incorrect Content-length 
    708        * header. See Mozilla Bugzilla #246651. 
    709        */ 
    710       if (this.transport.overrideMimeType) 
    711         requestHeaders.push('Connection', 'close'); 
    712     } 
    713  
    714     if (this.options.requestHeaders) 
    715       requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); 
    716  
    717     for (var i = 0; i < requestHeaders.length; i += 2) 
    718       this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); 
    719   }, 
    720  
    721   onStateChange: function() { 
    722     var readyState = this.transport.readyState; 
    723     if (readyState != 1) 
    724       this.respondToReadyState(this.transport.readyState); 
    725   }, 
    726  
    727   header: function(name) { 
     843 
     844    if (state == 'Complete') { 
     845      if ((this.getHeader('Content-type') || '').strip(). 
     846        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) 
     847          this.evalResponse(); 
     848 
     849      // avoid memory leak in MSIE: clean up 
     850      this.transport.onreadystatechange = Prototype.emptyFunction; 
     851    } 
     852  }, 
     853 
     854  getHeader: function(name) { 
    728855    try { 
    729856      return this.transport.getResponseHeader(name); 
    730     } catch (e) {
     857    } catch (e) { return null
    731858  }, 
    732859 
    733860  evalJSON: function() { 
    734861    try { 
    735       return eval('(' + this.header('X-JSON') + ')'); 
    736     } catch (e) {} 
     862      var json = this.getHeader('X-JSON'); 
     863      return json ? eval('(' + json + ')') : null; 
     864    } catch (e) { return null } 
    737865  }, 
    738866 
     
    745873  }, 
    746874 
    747   respondToReadyState: function(readyState) { 
    748     var event = Ajax.Request.Events[readyState]; 
    749     var transport = this.transport, json = this.evalJSON(); 
    750  
    751     if (event == 'Complete') { 
    752       try { 
    753         (this.options['on' + this.transport.status] 
    754          || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] 
    755          || Prototype.emptyFunction)(transport, json); 
    756       } catch (e) { 
    757         this.dispatchException(e); 
    758       } 
    759  
    760       if ((this.header('Content-type') || '').match(/^text\/javascript/i)) 
    761         this.evalResponse(); 
    762     } 
    763  
    764     try { 
    765       (this.options['on' + event] || Prototype.emptyFunction)(transport, json); 
    766       Ajax.Responders.dispatch('on' + event, this, transport, json); 
    767     } catch (e) { 
    768       this.dispatchException(e); 
    769     } 
    770  
    771     /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ 
    772     if (event == 'Complete') 
    773       this.transport.onreadystatechange = Prototype.emptyFunction; 
    774   }, 
    775  
    776875  dispatchException: function(exception) { 
    777876    (this.options.onException || Prototype.emptyFunction)(this, exception); 
     
    784883Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 
    785884  initialize: function(container, url, options) { 
    786     this.containers = { 
    787       success: container.success ? $(container.success) : $(container), 
    788       failure: container.failure ? $(container.failure) : 
    789         (container.success ? null : $(container)) 
     885    this.container = { 
     886      success: (container.success || container), 
     887      failure: (container.failure || (container.success ? null : container)) 
    790888    } 
    791889 
     
    794892 
    795893    var onComplete = this.options.onComplete || Prototype.emptyFunction; 
    796     this.options.onComplete = (function(transport, object) { 
     894    this.options.onComplete = (function(transport, param) { 
    797895      this.updateContent(); 
    798       onComplete(transport, object); 
     896      onComplete(transport, param); 
    799897    }).bind(this); 
    800898 
     
    803901 
    804902  updateContent: function() { 
    805     var receiver = this.responseIsSuccess() ? 
    806       this.containers.success : this.containers.failure; 
     903    var receiver = this.container[this.success() ? 'success' : 'failure']; 
    807904    var response = this.transport.responseText; 
    808905 
    809     if (!this.options.evalScripts) 
    810       response = response.stripScripts(); 
    811  
    812     if (receiver) { 
    813       if (this.options.insertion) { 
     906    if (!this.options.evalScripts) response = response.stripScripts(); 
     907 
     908    if (receiver = $(receiver)) { 
     909      if (this.options.insertion) 
    814910        new this.options.insertion(receiver, response); 
    815       } else { 
    816         Element.update(receiver, response); 
    817       } 
    818     } 
    819  
    820     if (this.responseIsSuccess()) { 
     911      else 
     912        receiver.update(response); 
     913    } 
     914 
     915    if (this.success()) { 
    821916      if (this.onComplete) 
    822917        setTimeout(this.onComplete.bind(this), 10); 
     
    847942 
    848943  stop: function() { 
    849     this.updater.onComplete = undefined; 
     944    this.updater.options.onComplete = undefined; 
    850945    clearTimeout(this.timer); 
    851946    (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 
     
    867962  } 
    868963}); 
    869 function $() { 
    870   var results = [], element; 
    871   for (var i = 0; i < arguments.length; i++) { 
    872     element = arguments[i]; 
    873     if (typeof element == 'string') 
    874       element = document.getElementById(element); 
    875     results.push(Element.extend(element)); 
    876   } 
    877   return results.length < 2 ? results[0] : results; 
     964function $(element) { 
     965  if (arguments.length > 1) { 
     966    for (var i = 0, elements = [], length = arguments.length; i < length; i++) 
     967      elements.push($(arguments[i])); 
     968    return elements; 
     969  } 
     970  if (typeof element == 'string') 
     971    element = document.getElementById(element); 
     972  return Element.extend(element); 
     973
     974 
     975if (Prototype.BrowserFeatures.XPath) { 
     976  document._getElementsByXPath = function(expression, parentElement) { 
     977    var results = []; 
     978    var query = document.evaluate(expression, $(parentElement) || document, 
     979      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 
     980    for (var i = 0, len = query.snapshotLength; i < len; i++) 
     981      results.push(query.snapshotItem(i)); 
     982    return results; 
     983  } 
    878984} 
    879985 
    880986document.getElementsByClassName = function(className, parentElement) { 
    881   var children = ($(parentElement) || document.body).getElementsByTagName('*'); 
    882   return $A(children).inject([], function(elements, child) { 
    883     if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 
    884       elements.push(Element.extend(child)); 
     987  if (Prototype.BrowserFeatures.XPath) { 
     988    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; 
     989    return document._getElementsByXPath(q, parentElement); 
     990  } else { 
     991    var children = ($(parentElement) || document.body).getElementsByTagName('*'); 
     992    var elements = [], child; 
     993    for (var i = 0, length = children.length; i < length; i++) { 
     994      child = children[i]; 
     995      if (Element.hasClassName(child, className)) 
     996        elements.push(Element.extend(child)); 
     997    } 
    885998    return elements; 
    886   }); 
     999  } 
    8871000} 
    8881001 
     
    8941007Element.extend = function(element) { 
    8951008  if (!element) return; 
    896   if (_nativeExtensions) return element; 
     1009  if (_nativeExtensions || element.nodeType == 3) return element; 
    8971010 
    8981011  if (!element._extended && element.tagName && element != window) { 
    899     var methods = Element.Methods, cache = Element.extend.cache; 
    900     for (property in methods) { 
     1012    var methods = Object.clone(Element.Methods), cache = Element.extend.cache; 
     1013 
     1014    if (element.tagName == 'FORM') 
     1015      Object.extend(methods, Form.Methods); 
     1016    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) 
     1017      Object.extend(methods, Form.Element.Methods); 
     1018 
     1019    for (var property in methods) { 
    9011020      var value = methods[property]; 
    9021021      if (typeof value == 'function') 
     1022        element[property] = cache.findOrStore(value); 
     1023    } 
     1024 
     1025    var methods = Object.clone(Element.Methods.Simulated), cache = Element.extend.cache; 
     1026    for (var property in methods) { 
     1027      var value = methods[property]; 
     1028      if ('function' == typeof value && !(property in element)) 
    9031029        element[property] = cache.findOrStore(value); 
    9041030    } 
     
    9221048  }, 
    9231049 
    924   toggle: function() { 
    925     for (var i = 0; i < arguments.length; i++) { 
    926       var element = $(arguments[i]); 
    927       Element[Element.visible(element) ? 'hide' : 'show'](element); 
    928     } 
    929   }, 
    930  
    931   hide: function() { 
    932     for (var i = 0; i < arguments.length; i++) { 
    933       var element = $(arguments[i]); 
    934       element.style.display = 'none'; 
    935     } 
    936   }, 
    937  
    938   show: function() { 
    939     for (var i = 0; i < arguments.length; i++) { 
    940       var element = $(arguments[i]); 
    941       element.style.display = ''; 
    942     } 
     1050  toggle: function(element) { 
     1051    element = $(element); 
     1052    Element[Element.visible(element) ? 'hide' : 'show'](element); 
     1053    return element; 
     1054  }, 
     1055 
     1056  hide: function(element) { 
     1057    $(element).style.display = 'none'; 
     1058    return element; 
     1059  }, 
     1060 
     1061  show: function(element) { 
     1062    $(element).style.display = ''; 
     1063    return element; 
    9431064  }, 
    9441065 
     
    9461067    element = $(element); 
    9471068    element.parentNode.removeChild(element); 
     1069    return element; 
    9481070  }, 
    9491071 
    9501072  update: function(element, html) { 
     1073    html = typeof html == 'undefined' ? '' : html.toString(); 
    9511074    $(element).innerHTML = html.stripScripts(); 
    9521075    setTimeout(function() {html.evalScripts()}, 10); 
     1076    return element; 
    9531077  }, 
    9541078 
     
    9641088    } 
    9651089    setTimeout(function() {html.evalScripts()}, 10); 
     1090    return element; 
     1091  }, 
     1092 
     1093  inspect: function(element) { 
     1094    element = $(element); 
     1095    var result = '<' + element.tagName.toLowerCase(); 
     1096    $H({'id': 'id', 'className': 'class'}).each(function(pair) { 
     1097      var property = pair.first(), attribute = pair.last(); 
     1098      var value = (element[property] || '').toString(); 
     1099      if (value) result += ' ' + attribute + '=' + value.inspect(true); 
     1100    }); 
     1101    return result + '>'; 
     1102  }, 
     1103 
     1104  recursivelyCollect: function(element, property) { 
     1105    element = $(element); 
     1106    var elements = []; 
     1107    while (element = element[property]) 
     1108      if (element.nodeType == 1) 
     1109        elements.push(Element.extend(element)); 
     1110    return elements; 
     1111  }, 
     1112 
     1113  ancestors: function(element) { 
     1114    return $(element).recursivelyCollect('parentNode'); 
     1115  }, 
     1116 
     1117  descendants: function(element) { 
     1118    element = $(element); 
     1119    return $A(element.getElementsByTagName('*')); 
     1120  }, 
     1121 
     1122  previousSiblings: function(element) { 
     1123    return $(element).recursivelyCollect('previousSibling'); 
     1124  }, 
     1125 
     1126  nextSiblings: function(element) { 
     1127    return $(element).recursivelyCollect('nextSibling'); 
     1128  }, 
     1129 
     1130  siblings: function(element) { 
     1131    element = $(element); 
     1132    return element.previousSiblings().reverse().concat(element.nextSiblings()); 
     1133  }, 
     1134 
     1135  match: function(element, selector) { 
     1136    element = $(element); 
     1137    if (typeof selector == 'string') 
     1138      selector = new Selector(selector); 
     1139    return selector.match(element); 
     1140  }, 
     1141 
     1142  up: function(element, expression, index) { 
     1143    return Selector.findElement($(element).ancestors(), expression, index); 
     1144  }, 
     1145 
     1146  down: function(element, expression, index) { 
     1147    return Selector.findElement($(element).descendants(), expression, index); 
     1148  }, 
     1149 
     1150  previous: function(element, expression, index) { 
     1151    return Selector.findElement($(element).previousSiblings(), expression, index); 
     1152  }, 
     1153 
     1154  next: function(element, expression, index) { 
     1155    return Selector.findElement($(element).nextSiblings(), expression, index); 
     1156  }, 
     1157 
     1158  getElementsBySelector: function() { 
     1159    var args = $A(arguments), element = $(args.shift()); 
     1160    return Selector.findChildElements(element, args); 
     1161  }, 
     1162 
     1163  getElementsByClassName: function(element, className) { 
     1164    element = $(element); 
     1165    return document.getElementsByClassName(className, element); 
    9661166  }, 
    9671167 
     
    9771177  hasClassName: function(element, className) { 
    9781178    if (!(element = $(element))) return; 
    979     return Element.classNames(element).include(className); 
     1179    var elementClassName = element.className; 
     1180    if (elementClassName.length == 0) return false; 
     1181    if (elementClassName == className || 
     1182        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 
     1183      return true; 
     1184    return false; 
    9801185  }, 
    9811186 
    9821187  addClassName: function(element, className) { 
    9831188    if (!(element = $(element))) return; 
    984     return Element.classNames(element).add(className); 
     1189    Element.classNames(element).add(className); 
     1190    return element; 
    9851191  }, 
    9861192 
    9871193  removeClassName: function(element, className) { 
    9881194    if (!(element = $(element))) return; 
    989     return Element.classNames(element).remove(className); 
     1195    Element.classNames(element).remove(className); 
     1196    return element; 
     1197  }, 
     1198 
     1199  observe: function() { 
     1200    Event.observe.apply(Event, arguments); 
     1201    return $A(arguments).first(); 
     1202  }, 
     1203 
     1204  stopObserving: function() { 
     1205    Event.stopObserving.apply(Event, arguments); 
     1206    return $A(arguments).first(); 
    9901207  }, 
    9911208 
     
    9931210  cleanWhitespace: function(element) { 
    9941211    element = $(element); 
    995     for (var i = 0; i < element.childNodes.length; i++) { 
    996       var node = element.childNodes[i]; 
     1212    var node = element.firstChild; 
     1213    while (node) { 
     1214      var nextNode = node.nextSibling; 
    9971215      if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 
    998         Element.remove(node); 
    999     } 
     1216        element.removeChild(node); 
     1217      node = nextNode; 
     1218    } 
     1219    return element; 
    10001220  }, 
    10011221 
     
    10161236        y = element.y ? element.y : element.offsetTop; 
    10171237    window.scrollTo(x, y); 
     1238    return element; 
    10181239  }, 
    10191240 
     
    10401261    for (var name in style) 
    10411262      element.style[name.camelize()] = style[name]; 
     1263    return element; 
    10421264  }, 
    10431265 
     
    10761298      } 
    10771299    } 
     1300    return element; 
    10781301  }, 
    10791302 
     
    10881311        element.style.right = ''; 
    10891312    } 
     1313    return element; 
    10901314  }, 
    10911315 
    10921316  makeClipping: function(element) { 
    10931317    element = $(element); 
    1094     if (element._overflow) return
    1095     element._overflow = element.style.overflow
     1318    if (element._overflow) return element
     1319    element._overflow = element.style.overflow || 'auto'
    10961320    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 
    10971321      element.style.overflow = 'hidden'; 
     1322    return element; 
    10981323  }, 
    10991324 
    11001325  undoClipping: function(element) { 
    11011326    element = $(element); 
    1102     if (element._overflow) return; 
    1103     element.style.overflow = element._overflow; 
    1104     element._overflow = undefined; 
     1327    if (!element._overflow) return element; 
     1328    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 
     1329    element._overflow = null; 
     1330    return element; 
     1331  } 
     1332
     1333 
     1334Element.Methods.Simulated = { 
     1335  hasAttribute: function(element, attribute) { 
     1336    return $(element).getAttributeNode(attribute).specified; 
     1337  } 
     1338
     1339 
     1340// IE is missing .innerHTML support for TABLE-related elements 
     1341if(document.all){ 
     1342  Element.Methods.update = function(element, html) { 
     1343    element = $(element); 
     1344    html = typeof html == 'undefined' ? '' : html.toString(); 
     1345    var tagName = element.tagName.toUpperCase(); 
     1346    if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) { 
     1347      var div = document.createElement('div'); 
     1348      switch (tagName) { 
     1349        case 'THEAD': 
     1350        case 'TBODY': 
     1351          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>'; 
     1352          depth = 2; 
     1353          break; 
     1354        case 'TR': 
     1355          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>'; 
     1356          depth = 3; 
     1357          break; 
     1358        case 'TD': 
     1359          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>'; 
     1360          depth = 4; 
     1361      } 
     1362      $A(element.childNodes).each(function(node){ 
     1363        element.removeChild(node) 
     1364      }); 
     1365      depth.times(function(){ div = div.firstChild }); 
     1366 
     1367      $A(div.childNodes).each( 
     1368        function(node){ element.appendChild(node) }); 
     1369    } else { 
     1370      element.innerHTML = html.stripScripts(); 
     1371    } 
     1372    setTimeout(function() {html.evalScripts()}, 10); 
     1373    return element; 
    11051374  } 
    11061375} 
     
    11101379var _nativeExtensions = false; 
    11111380 
    1112 if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { 
    1113   var HTMLElement = {} 
    1114   HTMLElement.prototype = document.createElement('div').__proto__; 
    1115 
     1381if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 
     1382  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { 
     1383    var className = 'HTML' + tag + 'Element'; 
     1384    if(window[className]) return; 
     1385    var klass = window[className] = {}; 
     1386    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; 
     1387  }); 
    11161388 
    11171389Element.addMethods = function(methods) { 
    11181390  Object.extend(Element.Methods, methods || {}); 
    11191391 
    1120   if(typeof HTMLElement != 'undefined') { 
    1121     var methods = Element.Methods, cache = Element.extend.cache; 
    1122     for (property in methods) { 
     1392  function copy(methods, destination, onlyIfAbsent) { 
     1393    onlyIfAbsent = onlyIfAbsent || false; 
     1394    var cache = Element.extend.cache; 
     1395    for (var property in methods) { 
    11231396      var value = methods[property]; 
    1124       if (typeof value == 'function') 
    1125         HTMLElement.prototype[property] = cache.findOrStore(value); 
    1126     } 
     1397      if (!onlyIfAbsent || !(property in destination)) 
     1398        destination[property] = cache.findOrStore(value); 
     1399    } 
     1400  } 
     1401 
     1402  if (typeof HTMLElement != 'undefined') { 
     1403    copy(Element.Methods, HTMLElement.prototype); 
     1404    copy(Element.Methods.Simulated, HTMLElement.prototype, true); 
     1405    copy(Form.Methods, HTMLFormElement.prototype); 
     1406    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { 
     1407      copy(Form.Element.Methods, klass.prototype); 
     1408    }); 
    11271409    _nativeExtensions = true; 
    11281410  } 
    11291411} 
    1130  
    1131 Element.addMethods(); 
    11321412 
    11331413var Toggle = new Object(); 
     
    12491529  add: function(classNameToAdd) { 
    12501530    if (this.include(classNameToAdd)) return; 
    1251     this.set(this.toArray().concat(classNameToAdd).join(' ')); 
     1531    this.set($A(this).concat(classNameToAdd).join(' ')); 
    12521532  }, 
    12531533 
    12541534  remove: function(classNameToRemove) { 
    12551535    if (!this.include(classNameToRemove)) return; 
    1256     this.set(this.select(function(className) { 
    1257       return className != classNameToRemove; 
    1258     }).join(' ')); 
     1536    this.set($A(this).without(classNameToRemove).join(' ')); 
    12591537  }, 
    12601538 
    12611539  toString: function() { 
    1262     return this.toArray().join(' '); 
     1540    return $A(this).join(' '); 
    12631541  } 
    12641542} 
     
    13551633 
    13561634    var results = []; 
    1357     for (var i = 0; i < scope.length; i++) 
     1635    for (var i = 0, length = scope.length; i < length; i++) 
    13581636      if (this.match(element = scope[i])) 
    13591637        results.push(Element.extend(element)); 
     
    13671645} 
    13681646 
     1647Object.extend(Selector, { 
     1648  matchElements: function(elements, expression) { 
     1649    var selector = new Selector(expression); 
     1650    return elements.select(selector.match.bind(selector)).collect(Element.extend); 
     1651  }, 
     1652 
     1653  findElement: function(elements, expression, index) { 
     1654    if (typeof expression == 'number') index = expression, expression = false; 
     1655    return Selector.matchElements(elements, expression || '*')[index || 0]; 
     1656  }, 
     1657 
     1658  findChildElements: function(element, expressions) { 
     1659    return expressions.map(function(expression) { 
     1660      return expression.strip().split(/\s+/).inject([null], function(results, expr) { 
     1661        var selector = new Selector(expr); 
     1662        return results.inject([], function(elements, result) { 
     1663          return elements.concat(selector.findElements(result || element)); 
     1664        }); 
     1665      }); 
     1666    }).flatten(); 
     1667  } 
     1668}); 
     1669 
    13691670function $$() { 
    1370   return $A(arguments).map(function(expression) { 
    1371     return expression.strip().split(/\s+/).inject([null], function(results, expr) { 
    1372       var selector = new Selector(expr); 
    1373       return results.map(selector.findElements.bind(selector)).flatten(); 
    1374     }); 
    1375   }).flatten(); 
    1376 
    1377 var Field = { 
    1378   clear: function() { 
    1379     for (var i = 0; i < arguments.length; i++) 
    1380       $(arguments[i]).value = ''; 
    1381   }, 
    1382  
    1383   focus: function(element) { 
    1384     $(element).focus(); 
    1385   }, 
    1386  
    1387   present: function() { 
    1388     for (var i = 0; i < arguments.length; i++) 
    1389       if ($(arguments[i]).value == '') return false; 
    1390     return true; 
    1391   }, 
    1392  
    1393   select: function(element) { 
    1394     $(element).select(); 
    1395   }, 
    1396  
    1397   activate: function(element) { 
    1398     element = $(element); 
    1399     element.focus(); 
    1400     if (element.select) 
    1401       element.select(); 
    1402   } 
    1403 
    1404  
    1405 /*--------------------------------------------------------------------------*/ 
    1406  
     1671  return Selector.findChildElements(document, $A(arguments)); 
     1672
    14071673var Form = { 
     1674  reset: function(form) { 
     1675    $(form).reset(); 
     1676    return form; 
     1677  }, 
     1678 
     1679  serializeElements: function(elements) { 
     1680    return elements.inject([], function(queryComponents, element) { 
     1681      var queryComponent = Form.Element.serialize(element); 
     1682      if (queryComponent) queryComponents.push(queryComponent); 
     1683      return queryComponents; 
     1684    }).join('&'); 
     1685  } 
     1686}; 
     1687 
     1688Form.Methods = { 
    14081689  serialize: function(form) { 
    1409     var elements = Form.getElements($(form)); 
    1410     var queryComponents = new Array(); 
    1411  
    1412     for (var i = 0; i < elements.length; i++) { 
    1413       var queryComponent = Form.Element.serialize(elements[i]); 
    1414       if (queryComponent) 
    1415         queryComponents.push(queryComponent); 
    1416     } 
    1417  
    1418     return queryComponents.join('&'); 
     1690    return Form.serializeElements($(form).getElements()); 
    14191691  }, 
    14201692 
    14211693  getElements: function(form) { 
    1422     form = $(form); 
    1423     var elements = new Array(); 
    1424  
    1425     for (var tagName in Form.Element.Serializers) { 
    1426       var tagElements = form.getElementsByTagName(tagName); 
    1427       for (var j = 0; j < tagElements.length; j++) 
    1428         elements.push(tagElements[j]); 
    1429     } 
    1430     return elements; 
     1694    return $A($(form).getElementsByTagName('*')).inject([], 
     1695      function(elements, child) { 
     1696        if (Form.Element.Serializers[child.tagName.toLowerCase()]) 
     1697          elements.push(Element.extend(child)); 
     1698        return elements; 
     1699      } 
     1700    ); 
    14311701  }, 
    14321702 
     
    14391709 
    14401710    var matchingInputs = new Array(); 
    1441     for (var i = 0; i < inputs.length; i++) { 
     1711    for (var i = 0, length = inputs.length; i < length; i++) { 
    14421712      var input = inputs[i]; 
    14431713      if ((typeName && input.type != typeName) || 
    14441714          (name && input.name != name)) 
    14451715        continue; 
    1446       matchingInputs.push(input); 
     1716      matchingInputs.push(Element.extend(input)); 
    14471717    } 
    14481718 
     
    14511721 
    14521722  disable: function(form) { 
    1453     var elements = Form.getElements(form); 
    1454     for (var i = 0; i < elements.length; i++) { 
    1455       var element = elements[i]; 
     1723    form = $(form); 
     1724    form.getElements().each(function(element) { 
    14561725      element.blur(); 
    14571726      element.disabled = 'true'; 
    1458     } 
     1727    }); 
     1728    return form; 
    14591729  }, 
    14601730 
    14611731  enable: function(form) { 
    1462     var elements = Form.getElements(form); 
    1463     for (var i = 0; i < elements.length; i++) { 
    1464       var element = elements[i]; 
     1732    form = $(form); 
     1733    form.getElements().each(function(element) { 
    14651734      element.disabled = ''; 
    1466     } 
     1735    }); 
     1736    return form; 
    14671737  }, 
    14681738 
    14691739  findFirstElement: function(form) { 
    1470     return Form.getElements(form).find(function(element) { 
     1740    return $(form).getElements().find(function(element) { 
    14711741      return element.type != 'hidden' && !element.disabled && 
    14721742        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 
     
    14751745 
    14761746  focusFirstElement: function(form) { 
    1477     Field.activate(Form.findFirstElement(form)); 
    1478   }, 
    1479  
    1480   reset: function(form) { 
    1481     $(form).reset(); 
    1482   } 
    1483 
     1747    form = $(form); 
     1748    form.findFirstElement().activate(); 
     1749    return form; 
     1750  } 
     1751
     1752 
     1753Object.extend(Form, Form.Methods); 
     1754 
     1755/*--------------------------------------------------------------------------*/ 
    14841756 
    14851757Form.Element = { 
     1758  focus: function(element) { 
     1759    $(element).focus(); 
     1760    return element; 
     1761  }, 
     1762 
     1763  select: function(element) { 
     1764    $(element).select(); 
     1765    return element; 
     1766  } 
     1767} 
     1768 
     1769Form.Element.Methods = { 
    14861770  serialize: function(element) { 
    14871771    element = $(element); 
     1772    if (element.disabled) return ''; 
    14881773    var method = element.tagName.toLowerCase(); 
    14891774    var parameter = Form.Element.Serializers[method](element); 
     
    15091794    if (parameter) 
    15101795      return parameter[1]; 
    1511   } 
    1512 
     1796  }, 
     1797 
     1798  clear: function(element) { 
     1799    $(element).value = ''; 
     1800    return element; 
     1801  }, 
     1802 
     1803  present: function(element) { 
     1804    return $(element).value != ''; 
     1805  }, 
     1806 
     1807  activate: function(element) { 
     1808    element = $(element); 
     1809    element.focus(); 
     1810    if (element.select) 
     1811      element.select(); 
     1812    return element; 
     1813  }, 
     1814 
     1815  disable: function(element) { 
     1816    element = $(element); 
     1817    element.disabled = true; 
     1818    return element; 
     1819  }, 
     1820 
     1821  enable: function(element) { 
     1822    element = $(element); 
     1823    element.blur(); 
     1824    element.disabled = false; 
     1825    return element; 
     1826  } 
     1827
     1828 
     1829Object.extend(Form.Element, Form.Element.Methods); 
     1830var Field = Form.Element; 
     1831 
     1832/*--------------------------------------------------------------------------*/ 
    15131833 
    15141834Form.Element.Serializers = { 
    15151835  input: function(element) { 
    15161836    switch (element.type.toLowerCase()) { 
    1517       case 'submit': 
    1518       case 'hidden': 
    1519       case 'password': 
    1520       case 'text': 
    1521         return Form.Element.Serializers.textarea(element); 
    15221837      case 'checkbox': 
    15231838      case 'radio': 
    15241839        return Form.Element.Serializers.inputSelector(element); 
     1840      default: 
     1841        return Form.Element.Serializers.textarea(element); 
    15251842    } 
    15261843    return false; 
     
    15441861    var value = '', opt, index = element.selectedIndex; 
    15451862    if (index >= 0) { 
    1546       opt = element.options[index]; 
    1547       value = opt.value || opt.text; 
     1863      opt = Element.extend(element.options[index]); 
     1864      // Uses the new potential extension if hasAttribute isn't native. 
     1865      value = opt.hasAttribute('value') ? opt.value : opt.text; 
    15481866    } 
    15491867    return [element.name, value]; 
     
    15531871    var value = []; 
    15541872    for (var i = 0; i < element.length; i++) { 
    1555       var opt = element.options[i]
     1873      var opt = Element.extend(element.options[i])
    15561874      if (opt.selected) 
    1557         value.push(opt.value || opt.text); 
     1875        // Uses the new potential extension if hasAttribute isn't native. 
     1876        value.push(opt.hasAttribute('value') ? opt.value : opt.text); 
    15581877    } 
    15591878    return [element.name, value]; 
     
    16291948 
    16301949  registerFormCallbacks: function() { 
    1631     var elements = Form.getElements(this.element); 
    1632     for (var i = 0; i < elements.length; i++) 
    1633       this.registerCallback(elements[i]); 
     1950    Form.getElements(this.element).each(this.registerCallback.bind(this)); 
    16341951  }, 
    16351952 
     
    16411958          Event.observe(element, 'click', this.onElementEvent.bind(this)); 
    16421959          break; 
    1643         case 'password': 
    1644         case 'text': 
    1645         case 'textarea': 
    1646         case 'select-one': 
    1647         case 'select-multiple': 
     1960        default: 
    16481961          Event.observe(element, 'change', this.onElementEvent.bind(this)); 
    16491962          break; 
     
    16801993  KEY_DOWN:     40, 
    16811994  KEY_DELETE:   46, 
     1995  KEY_HOME:     36, 
     1996  KEY_END:      35, 
     1997  KEY_PAGEUP:   33, 
     1998  KEY_PAGEDOWN: 34, 
    16821999 
    16832000  element: function(event) { 
     
    17352052  unloadCache: function() { 
    17362053    if (!Event.observers) return; 
    1737     for (var i = 0; i < Event.observers.length; i++) { 
     2054    for (var i = 0, length = Event.observers.length; i < length; i++) { 
    17382055      Event.stopObserving.apply(this, Event.observers[i]); 
    17392056      Event.observers[i][0] = null; 
     
    17432060 
    17442061  observe: function(element, name, observer, useCapture) { 
    1745     var element = $(element); 
     2062    element = $(element); 
    17462063    useCapture = useCapture || false; 
    17472064 
     
    17512068      name = 'keydown'; 
    17522069 
    1753     this._observeAndCache(element, name, observer, useCapture); 
     2070    Event._observeAndCache(element, name, observer, useCapture); 
    17542071  }, 
    17552072 
    17562073  stopObserving: function(element, name, observer, useCapture) { 
    1757     var element = $(element); 
     2074    element = $(element); 
    17582075    useCapture = useCapture || false; 
    17592076 
     
    17662083      element.removeEventListener(name, observer, useCapture); 
    17672084    } else if (element.detachEvent) { 
    1768       element.detachEvent('on' + name, observer); 
     2085      try { 
     2086        element.detachEvent('on' + name, observer); 
     2087      } catch (e) {} 
    17692088    } 
    17702089  } 
     
    18202139      element = element.offsetParent; 
    18212140      if (element) { 
    1822         p = Element.getStyle(element, 'position'); 
     2141        if(element.tagName=='BODY') break; 
     2142        var p = Element.getStyle(element, 'position'); 
    18232143        if (p == 'relative' || p == 'absolute') break; 
    18242144      } 
     
    18762196  }, 
    18772197 
    1878   clone: function(source, target) { 
    1879     source = $(source); 
    1880     target = $(target); 
    1881     target.style.position = 'absolute'; 
    1882     var offsets = this.cumulativeOffset(source); 
    1883     target.style.top    = offsets[1] + 'px'; 
    1884     target.style.left   = offsets[0] + 'px'; 
    1885     target.style.width  = source.offsetWidth + 'px'; 
    1886     target.style.height = source.offsetHeight + 'px'; 
    1887   }, 
    1888  
    18892198  page: function(forElement) { 
    18902199    var valueT = 0, valueL = 0; 
     
    19032212    element = forElement; 
    19042213    do { 
    1905       valueT -= element.scrollTop  || 0; 
    1906       valueL -= element.scrollLeft || 0; 
     2214      if (!window.opera || element.tagName=='BODY') { 
     2215        valueT -= element.scrollTop  || 0; 
     2216        valueL -= element.scrollLeft || 0; 
     2217      } 
    19072218    } while (element = element.parentNode); 
    19082219 
     
    20052316  } 
    20062317} 
     2318 
     2319Element.addMethods(); 
  • vendor/scriptaculous/src/builder.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     1// script.aculo.us builder.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    24// 
    3 // See scriptaculous.js for full license. 
     5// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     6// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    47 
    58var Builder = { 
     
    7679     return document.createTextNode(text); 
    7780  }, 
     81 
     82  ATTR_MAP: { 
     83    'className': 'class', 
     84    'htmlFor': 'for' 
     85  }, 
     86 
    7887  _attributes: function(attributes) { 
    7988    var attrs = []; 
    8089    for(attribute in attributes) 
    81       attrs.push((attribute=='className' ? 'class' : attribute) + 
     90      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + 
    8291          '="' + attributes[attribute].toString().escapeHTML() + '"'); 
    8392    return attrs.join(" "); 
     
    98107  _isStringOrNumber: function(param) { 
    99108    return(typeof param=='string' || typeof param=='number'); 
     109  }, 
     110  build: function(html) { 
     111    var element = this.node('div'); 
     112    $(element).update(html.strip()); 
     113    return element.down(); 
     114  }, 
     115  dump: function(scope) {  
     116    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope  
     117   
     118    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + 
     119      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + 
     120      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ 
     121      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ 
     122      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ 
     123      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); 
     124   
     125    tags.each( function(tag){  
     126      scope[tag] = function() {  
     127        return Builder.node.apply(Builder, [tag].concat($A(arguments)));   
     128      }  
     129    }); 
    100130  } 
    101131} 
  • vendor/scriptaculous/src/controls.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    2 //           (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) 
    3 //           (c) 2005 Jon Tirsen (http://www.tirsen.com) 
     1// script.aculo.us controls.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     4//           (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan) 
     5//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) 
    46// Contributors: 
    57//  Richard Livsey 
     
    79//  Rob Wills 
    810//  
    9 // See scriptaculous.js for full license. 
     11// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     12// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    1013 
    1114// Autocompleter.Base handles all the autocompletion functionality  
     
    3336// useful when one of the tokens is \n (a newline), as it  
    3437// allows smart autocompletion after linebreaks. 
     38 
     39if(typeof Effect == 'undefined') 
     40  throw("controls.js requires including script.aculo.us' effects.js library"); 
    3541 
    3642var Autocompleter = {} 
     
    4652    this.entryCount  = 0; 
    4753 
    48     if (this.setOptions) 
     54    if(this.setOptions) 
    4955      this.setOptions(options); 
    5056    else 
     
    5662    this.options.minChars     = this.options.minChars || 1; 
    5763    this.options.onShow       = this.options.onShow ||  
    58     function(element, update){  
    59       if(!update.style.position || update.style.position=='absolute') { 
    60         update.style.position = 'absolute'; 
    61         Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); 
    62       } 
    63       Effect.Appear(update,{duration:0.15}); 
    64     }; 
     64      function(element, update){  
     65        if(!update.style.position || update.style.position=='absolute') { 
     66          update.style.position = 'absolute'; 
     67          Position.clone(element, update, { 
     68            setHeight: false,  
     69            offsetTop: element.offsetHeight 
     70          }); 
     71        } 
     72        Effect.Appear(update,{duration:0.15}); 
     73      }; 
    6574    this.options.onHide = this.options.onHide ||  
    66     function(element, update){ new Effect.Fade(update,{duration:0.15}) }; 
    67  
    68     if (typeof(this.options.tokens) == 'string')  
     75      function(element, update){ new Effect.Fade(update,{duration:0.15}) }; 
     76 
     77    if(typeof(this.options.tokens) == 'string')  
    6978      this.options.tokens = new Array(this.options.tokens); 
    7079 
     
    95104   
    96105  fixIEOverlapping: function() { 
    97     Position.clone(this.update, this.iefix); 
     106    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); 
    98107    this.iefix.style.zIndex = 1; 
    99108    this.update.style.zIndex = 2; 
     
    203212    if(this.index > 0) this.index-- 
    204213      else this.index = this.entryCount-1; 
     214    this.getEntry(this.index).scrollIntoView(true); 
    205215  }, 
    206216   
     
    208218    if(this.index < this.entryCount-1) this.index++ 
    209219      else this.index = 0; 
     220    this.getEntry(this.index).scrollIntoView(false); 
    210221  }, 
    211222   
     
    255266      this.update.innerHTML = choices; 
    256267      Element.cleanWhitespace(this.update); 
    257       Element.cleanWhitespace(this.update.firstChild); 
    258  
    259       if(this.update.firstChild && this.update.firstChild.childNodes) { 
     268      Element.cleanWhitespace(this.update.down()); 
     269 
     270      if(this.update.firstChild && this.update.down().childNodes) { 
    260271        this.entryCount =  
    261           this.update.firstChild.childNodes.length; 
     272          this.update.down().childNodes.length; 
    262273        for (var i = 0; i < this.entryCount; i++) { 
    263274          var entry = this.getEntry(i); 
     
    270281 
    271282      this.stopIndicator(); 
    272  
    273283      this.index = 0; 
    274       this.render(); 
     284       
     285      if(this.entryCount==1 && this.options.autoSelect) { 
     286        this.selectEntry(); 
     287        this.hide(); 
     288      } else { 
     289        this.render(); 
     290      } 
    275291    } 
    276292  }, 
     
    532548    this.createForm(); 
    533549    this.element.parentNode.insertBefore(this.form, this.element); 
    534     Field.scrollFreeActivate(this.editField); 
     550    if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); 
    535551    // stop the event to avoid a page refresh in Safari 
    536552    if (evt) { 
     
    637653    this.editField.disabled = false; 
    638654    this.editField.value = transport.responseText.stripTags(); 
     655    Field.scrollFreeActivate(this.editField); 
    639656  }, 
    640657  onclickCancel: function() { 
     
    773790        optionTag = document.createElement("option"); 
    774791        optionTag.value = (e instanceof Array) ? e[0] : e; 
     792        if((typeof this.options.value == 'undefined') &&  
     793          ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true; 
    775794        if(this.options.value==optionTag.value) optionTag.selected = true; 
    776795        optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); 
  • vendor/scriptaculous/src/dragdrop.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    2 //           (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) 
     1// script.aculo.us dragdrop.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     4//           (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) 
    35//  
    4 // See scriptaculous.js for full license. 
    5  
    6 /*--------------------------------------------------------------------------*/ 
     6// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     7// For details, see the script.aculo.us web site: http://script.aculo.us/ 
     8 
     9if(typeof Effect == 'undefined') 
     10  throw("dragdrop.js requires including script.aculo.us' effects.js library"); 
    711 
    812var Droppables = { 
     
    146150   
    147151  activate: function(draggable) { 
    148     window.focus(); // allows keypress events if window isn't currently focused, fails for Safari 
    149     this.activeDraggable = draggable; 
     152    if(draggable.options.delay) {  
     153      this._timeout = setTimeout(function() {  
     154        Draggables._timeout = null;  
     155        window.focus();  
     156        Draggables.activeDraggable = draggable;  
     157      }.bind(this), draggable.options.delay);  
     158    } else { 
     159      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari 
     160      this.activeDraggable = draggable; 
     161    } 
    150162  }, 
    151163   
     
    161173    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; 
    162174    this._lastPointer = pointer; 
     175     
    163176    this.activeDraggable.updateDrag(event, pointer); 
    164177  }, 
    165178   
    166179  endDrag: function(event) { 
     180    if(this._timeout) {  
     181      clearTimeout(this._timeout);  
     182      this._timeout = null;  
     183    } 
    167184    if(!this.activeDraggable) return; 
    168185    this._lastPointer = null; 
     
    191208        if(o[eventName]) o[eventName](eventName, draggable, event); 
    192209      }); 
     210    if(draggable.options[eventName]) draggable.options[eventName](draggable, event); 
    193211  }, 
    194212   
     
    205223 
    206224var Draggable = Class.create(); 
     225Draggable._dragging    = {}; 
     226 
    207227Draggable.prototype = { 
    208228  initialize: function(element) { 
    209     var options = Object.extend(
     229    var defaults =
    210230      handle: false, 
    211       starteffect: function(element) { 
    212         element._opacity = Element.getOpacity(element);  
    213         new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});  
    214       }, 
    215231      reverteffect: function(element, top_offset, left_offset) { 
    216232        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; 
    217         element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur}); 
     233        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, 
     234          queue: {scope:'_draggable', position:'end'} 
     235        }); 
    218236      }, 
    219237      endeffect: function(element) { 
    220         var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0 
    221         new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity});  
     238        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; 
     239        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,  
     240          queue: {scope:'_draggable', position:'end'}, 
     241          afterFinish: function(){  
     242            Draggable._dragging[element] = false  
     243          } 
     244        });  
    222245      }, 
    223246      zindex: 1000, 
     
    226249      scrollSensitivity: 20, 
    227250      scrollSpeed: 15, 
    228       snap: false   // false, or xy or [x,y] or function(x,y){ return [x,y] } 
    229     }, arguments[1] || {}); 
     251      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] } 
     252      delay: 0 
     253    }; 
     254     
     255    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined') 
     256      Object.extend(defaults, { 
     257        starteffect: function(element) { 
     258          element._opacity = Element.getOpacity(element); 
     259          Draggable._dragging[element] = true; 
     260          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});  
     261        } 
     262      }); 
     263     
     264    var options = Object.extend(defaults, arguments[1] || {}); 
    230265 
    231266    this.element = $(element); 
    232267     
    233     if(options.handle && (typeof options.handle == 'string')) { 
    234       var h = Element.childrenWithClassName(this.element, options.handle, true); 
    235       if(h.length>0) this.handle = h[0]; 
    236     } 
     268    if(options.handle && (typeof options.handle == 'string')) 
     269      this.handle = this.element.down('.'+options.handle, 0); 
     270     
    237271    if(!this.handle) this.handle = $(options.handle); 
    238272    if(!this.handle) this.handle = this.element; 
    239273     
    240     if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) 
     274    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { 
    241275      options.scroll = $(options.scroll); 
     276      this._isScrollChild = Element.childOf(this.element, options.scroll); 
     277    } 
    242278 
    243279    Element.makePositioned(this.element); // fix IE     
     
    265301   
    266302  initDrag: function(event) { 
     303    if(typeof Draggable._dragging[this.element] != 'undefined' && 
     304      Draggable._dragging[this.element]) return; 
    267305    if(Event.isLeftClick(event)) {     
    268306      // abort on form elements, fixes a Firefox issue 
     
    275313        src.tagName=='TEXTAREA')) return; 
    276314         
    277       if(this.element._revert) { 
    278         this.element._revert.cancel(); 
    279         this.element._revert = null; 
    280       } 
    281        
    282315      var pointer = [Event.pointerX(event), Event.pointerY(event)]; 
    283316      var pos     = Position.cumulativeOffset(this.element); 
     
    315348     
    316349    Draggables.notify('onStart', this, event); 
     350         
    317351    if(this.options.starteffect) this.options.starteffect(this.element); 
    318352  }, 
     
    323357    Droppables.show(pointer, this.element); 
    324358    Draggables.notify('onDrag', this, event); 
     359     
    325360    this.draw(pointer); 
    326361    if(this.options.change) this.options.change(this); 
     
    334369      } else { 
    335370        p = Position.page(this.options.scroll); 
    336         p[0] += this.options.scroll.scrollLeft
    337         p[1] += this.options.scroll.scrollTop
     371        p[0] += this.options.scroll.scrollLeft + Position.deltaX
     372        p[1] += this.options.scroll.scrollTop + Position.deltaY
    338373        p.push(p[0]+this.options.scroll.offsetWidth); 
    339374        p.push(p[1]+this.options.scroll.offsetHeight); 
     
    381416    if(this.options.endeffect)  
    382417      this.options.endeffect(this.element); 
    383  
     418       
    384419    Draggables.deactivate(this); 
    385420    Droppables.reset(); 
     
    401436  draw: function(point) { 
    402437    var pos = Position.cumulativeOffset(this.element); 
     438    if(this.options.ghosting) { 
     439      var r   = Position.realOffset(this.element); 
     440      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; 
     441    } 
     442     
    403443    var d = this.currentDelta(); 
    404444    pos[0] -= d[0]; pos[1] -= d[1]; 
    405445     
    406     if(this.options.scroll && (this.options.scroll != window)) { 
     446    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { 
    407447      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; 
    408448      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; 
     
    431471    if((!this.options.constraint) || (this.options.constraint=='vertical')) 
    432472      style.top  = p[1] + "px"; 
     473     
    433474    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering 
    434475  }, 
     
    443484   
    444485  startScrolling: function(speed) { 
     486    if(!(speed[0] || speed[1])) return; 
    445487    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; 
    446488    this.lastScrolled = new Date(); 
     
    467509    Droppables.show(Draggables._lastPointer, this.element); 
    468510    Draggables.notify('onDrag', this); 
    469     Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); 
    470     Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; 
    471     Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; 
    472     if (Draggables._lastScrollPointer[0] < 0) 
    473       Draggables._lastScrollPointer[0] = 0; 
    474     if (Draggables._lastScrollPointer[1] < 0) 
    475       Draggables._lastScrollPointer[1] = 0; 
    476     this.draw(Draggables._lastScrollPointer); 
     511    if (this._isScrollChild) { 
     512      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); 
     513      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; 
     514      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; 
     515      if (Draggables._lastScrollPointer[0] < 0) 
     516        Draggables._lastScrollPointer[0] = 0; 
     517      if (Draggables._lastScrollPointer[1] < 0) 
     518        Draggables._lastScrollPointer[1] = 0; 
     519      this.draw(Draggables._lastScrollPointer); 
     520    } 
    477521     
    478522    if(this.options.change) this.options.change(this); 
     
    526570 
    527571var Sortable = { 
     572  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, 
     573   
    528574  sortables: {}, 
    529575   
     
    566612      handle:      false,      // or a CSS class 
    567613      only:        false, 
     614      delay:       0, 
    568615      hoverclass:  null, 
    569616      ghosting:    false, 
     
    571618      scrollSensitivity: 20, 
    572619      scrollSpeed: 15, 
    573       format:      /^[^_]*_(.*)$/
     620      format:      this.SERIALIZE_RULE
    574621      onChange:    Prototype.emptyFunction, 
    575622      onUpdate:    Prototype.emptyFunction 
     
    585632      scrollSpeed: options.scrollSpeed, 
    586633      scrollSensitivity: options.scrollSensitivity, 
     634      delay:       options.delay, 
    587635      ghosting:    options.ghosting, 
    588636      constraint:  options.constraint, 
     
    613661      hoverclass:  options.hoverclass, 
    614662      onHover:     Sortable.onHover 
    615       //greedy:      !options.dropOnEmpty 
    616663    } 
    617664     
     
    638685      // handles are per-draggable 
    639686      var handle = options.handle ?  
    640         Element.childrenWithClassName(e, options.handle)[0] : e;     
     687        $(e).down('.'+options.handle,0) : e;     
    641688      options.draggables.push( 
    642689        new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); 
     
    709756      var index; 
    710757       
    711       var children = Sortable.findElements(dropon, {tag: droponOptions.tag}); 
     758      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); 
    712759      var child = null; 
    713760             
     
    736783 
    737784  unmark: function() { 
    738     if(Sortable._marker) Element.hide(Sortable._marker); 
     785    if(Sortable._marker) Sortable._marker.hide(); 
    739786  }, 
    740787 
     
    745792 
    746793    if(!Sortable._marker) { 
    747       Sortable._marker = $('dropmarker') || document.createElement('DIV'); 
    748       Element.hide(Sortable._marker); 
    749       Element.addClassName(Sortable._marker, 'dropmarker'); 
    750       Sortable._marker.style.position = 'absolute'; 
     794      Sortable._marker =  
     795        ($('dropmarker') || Element.extend(document.createElement('DIV'))). 
     796          hide().addClassName('dropmarker').setStyle({position:'absolute'}); 
    751797      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); 
    752798    }     
    753799    var offsets = Position.cumulativeOffset(dropon); 
    754     Sortable._marker.style.left = offsets[0] + 'px'; 
    755     Sortable._marker.style.top = offsets[1] + 'px'; 
     800    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); 
    756801     
    757802    if(position=='after') 
    758803      if(sortable.overlap == 'horizontal')  
    759         Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px'
     804        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'})
    760805      else 
    761         Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'
    762      
    763     Element.show(Sortable._marker); 
     806        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'})
     807     
     808    Sortable._marker.show(); 
    764809  }, 
    765810   
     
    776821        element: element, 
    777822        parent: parent, 
    778         children: new Array
     823        children: []
    779824        position: parent.children.length, 
    780         container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()
     825        container: $(children[i]).down(options.treeTag
    781826      } 
    782827       
     
    789834 
    790835    return parent;  
    791   }, 
    792  
    793   /* Finds the first element of the given tag type within a parent element. 
    794     Used for finding the first LI[ST] within a L[IST]I[TEM].*/ 
    795   _findChildrenElement: function (element, containerTag) { 
    796     if (element && element.hasChildNodes) 
    797       for (var i = 0; i < element.childNodes.length; ++i) 
    798         if (element.childNodes[i].tagName == containerTag) 
    799           return element.childNodes[i]; 
    800    
    801     return null; 
    802836  }, 
    803837 
     
    816850      id: null, 
    817851      parent: null, 
    818       children: new Array
     852      children: []
    819853      container: element, 
    820854      position: 0 
    821855    } 
    822856     
    823     return Sortable._tree (element, options, root); 
     857    return Sortable._tree(element, options, root); 
    824858  }, 
    825859 
     
    870904    if (options.tree) { 
    871905      return Sortable.tree(element, arguments[1]).children.map( function (item) { 
    872         return [name + Sortable._constructIndex(item) + "=" +  
     906        return [name + Sortable._constructIndex(item) + "[id]=" +  
    873907                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); 
    874908      }).flatten().join('&'); 
     
    881915} 
    882916 
    883 /* Returns true if child is contained within element */ 
     917// Returns true if child is contained within element 
    884918Element.isParent = function(child, element) { 
    885919  if (!child.parentNode || child == element) return false; 
    886  
    887920  if (child.parentNode == element) return true; 
    888  
    889921  return Element.isParent(child.parentNode, element); 
    890922} 
     
    909941 
    910942Element.offsetSize = function (element, type) { 
    911   if (type == 'vertical' || type == 'height') 
    912     return element.offsetHeight; 
    913   else 
    914     return element.offsetWidth; 
     943  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; 
    915944} 
  • vendor/scriptaculous/src/effects.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     1// script.aculo.us effects.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    24// Contributors: 
    35//  Justin Palmer (http://encytemedia.com/) 
     
    57//  Martin Bialasinki 
    68//  
    7 // See scriptaculous.js for full license.   
     9// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     10// For details, see the script.aculo.us web site: http://script.aculo.us/  
    811 
    912// converts rgb() and #xxx to #xxxxxx format,   
     
    4245Element.setContentZoom = function(element, percent) { 
    4346  element = $(element);   
    44   Element.setStyle(element, {fontSize: (percent/100) + 'em'});    
     47  element.setStyle({fontSize: (percent/100) + 'em'});    
    4548  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 
    46 
    47  
    48 Element.getOpacity = function(element){   
     49  return element; 
     50
     51 
     52Element.getOpacity = function(element){ 
     53  element = $(element); 
    4954  var opacity; 
    50   if (opacity = Element.getStyle(element, 'opacity'))   
     55  if (opacity = element.getStyle('opacity'))   
    5156    return parseFloat(opacity);   
    52   if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))   
     57  if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))   
    5358    if(opacity[1]) return parseFloat(opacity[1]) / 100;   
    5459  return 1.0;   
     
    5863  element= $(element);   
    5964  if (value == 1){ 
    60     Element.setStyle(element, { opacity:  
     65    element.setStyle({ opacity:  
    6166      (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?  
    62       0.999999 : null }); 
    63     if(/MSIE/.test(navigator.userAgent))   
    64       Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});   
     67      0.999999 : 1.0 }); 
     68    if(/MSIE/.test(navigator.userAgent) && !window.opera)   
     69      element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});   
    6570  } else {   
    6671    if(value < 0.00001) value = 0;   
    67     Element.setStyle(element, {opacity: value}); 
    68     if(/MSIE/.test(navigator.userAgent))   
    69      Element.setStyle(element,  
    70        { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 
    71                  'alpha(opacity='+value*100+')' });   
    72   } 
     72    element.setStyle({opacity: value}); 
     73    if(/MSIE/.test(navigator.userAgent) && !window.opera)   
     74      element.setStyle( 
     75        { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + 
     76            'alpha(opacity='+value*100+')' });   
     77  } 
     78  return element; 
    7379 
    7480  
     
    7682  return $(element).style.opacity || ''; 
    7783 
    78  
    79 Element.childrenWithClassName = function(element, className, findFirst) { 
    80   var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)"); 
    81   var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) {  
    82     return (c.className && c.className.match(classNameRegExp)); 
    83   }); 
    84   if(!results) results = []; 
    85   return results; 
    86 } 
    8784 
    8885Element.forceRerendering = function(element) { 
     
    105102 
    106103var Effect = { 
     104  _elementDoesNotExistError: { 
     105    name: 'ElementDoesNotExistError', 
     106    message: 'The specified DOM element does not exist, but is required for this effect to operate' 
     107  }, 
    107108  tagifyText: function(element) { 
     109    if(typeof Builder == 'undefined') 
     110      throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); 
     111       
    108112    var tagifyStyle = 'position:relative'; 
    109     if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; 
     113    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1'; 
     114     
    110115    element = $(element); 
    111116    $A(element.childNodes).each( function(child) { 
     
    160165/* ------------- transitions ------------- */ 
    161166 
    162 Effect.Transitions = {} 
    163  
    164 Effect.Transitions.linear = function(pos) { 
    165   return pos; 
    166 
    167 Effect.Transitions.sinoidal = function(pos) { 
    168   return (-Math.cos(pos*Math.PI)/2) + 0.5; 
    169 
    170 Effect.Transitions.reverse  = function(pos) { 
    171   return 1-pos; 
    172 
    173 Effect.Transitions.flicker = function(pos) { 
    174   return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; 
    175 
    176 Effect.Transitions.wobble = function(pos) { 
    177   return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; 
    178 
    179 Effect.Transitions.pulse = function(pos) { 
    180   return (Math.floor(pos*10) % 2 == 0 ?  
    181     (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); 
    182 
    183 Effect.Transitions.none = function(pos) { 
    184   return 0; 
    185 
    186 Effect.Transitions.full = function(pos) { 
    187   return 1; 
    188 
     167Effect.Transitions = { 
     168  linear: Prototype.K, 
     169  sinoidal: function(pos) { 
     170    return (-Math.cos(pos*Math.PI)/2) + 0.5; 
     171  }, 
     172  reverse: function(pos) { 
     173    return 1-pos; 
     174  }, 
     175  flicker: function(pos) { 
     176    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; 
     177  }, 
     178  wobble: function(pos) { 
     179    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; 
     180  }, 
     181  pulse: function(pos, pulses) {  
     182    pulses = pulses || 5;  
     183    return ( 
     184      Math.round((pos % (1/pulses)) * pulses) == 0 ?  
     185            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :  
     186        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) 
     187      ); 
     188  }, 
     189  none: function(pos) { 
     190    return 0; 
     191  }, 
     192  full: function(pos) { 
     193    return 1; 
     194  } 
     195}; 
    189196 
    190197/* ------------- core effects ------------- */ 
     
    212219            e.finishOn += effect.finishOn; 
    213220          }); 
     221        break; 
     222      case 'with-last': 
     223        timestamp = this.effects.pluck('startOn').max() || timestamp; 
    214224        break; 
    215225      case 'end': 
     
    349359}); 
    350360 
     361Effect.Event = Class.create(); 
     362Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { 
     363  initialize: function() { 
     364    var options = Object.extend({ 
     365      duration: 0 
     366    }, arguments[0] || {}); 
     367    this.start(options); 
     368  }, 
     369  update: Prototype.emptyFunction 
     370}); 
     371 
    351372Effect.Opacity = Class.create(); 
    352373Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { 
    353374  initialize: function(element) { 
    354375    this.element = $(element); 
     376    if(!this.element) throw(Effect._elementDoesNotExistError); 
    355377    // make this work on IE on elements without 'layout' 
    356     if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) 
     378    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) 
    357379      this.element.setStyle({zoom: 1}); 
    358380    var options = Object.extend({ 
     
    371393  initialize: function(element) { 
    372394    this.element = $(element); 
     395    if(!this.element) throw(Effect._elementDoesNotExistError); 
    373396    var options = Object.extend({ 
    374397      x:    0, 
     
    394417  update: function(position) { 
    395418    this.element.setStyle({ 
    396       left: this.options.x  * position + this.originalLeft + 'px', 
    397       top:  this.options.y  * position + this.originalTop  + 'px' 
     419      left: Math.round(this.options.x  * position + this.originalLeft) + 'px', 
     420      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px' 
    398421    }); 
    399422  } 
     
    409432Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { 
    410433  initialize: function(element, percent) { 
    411     this.element = $(element) 
     434    this.element = $(element); 
     435    if(!this.element) throw(Effect._elementDoesNotExistError); 
    412436    var options = Object.extend({ 
    413437      scaleX: true, 
     
    434458     
    435459    var fontSize = this.element.getStyle('font-size') || '100%'; 
    436     ['em','px','%'].each( function(fontSizeType) { 
     460    ['em','px','%','pt'].each( function(fontSizeType) { 
    437461      if(fontSize.indexOf(fontSizeType)>0) { 
    438462        this.fontSize     = parseFloat(fontSize); 
     
    459483  }, 
    460484  finish: function(position) { 
    461     if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); 
     485    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); 
    462486  }, 
    463487  setDimensions: function(height, width) { 
    464488    var d = {}; 
    465     if(this.options.scaleX) d.width = width + 'px'; 
    466     if(this.options.scaleY) d.height = height + 'px'; 
     489    if(this.options.scaleX) d.width = Math.round(width) + 'px'; 
     490    if(this.options.scaleY) d.height = Math.round(height) + 'px'; 
    467491    if(this.options.scaleFromCenter) { 
    468492      var topd  = (height - this.dims[0])/2; 
     
    484508  initialize: function(element) { 
    485509    this.element = $(element); 
     510    if(!this.element) throw(Effect._elementDoesNotExistError); 
    486511    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); 
    487512    this.start(options); 
     
    548573  afterFinishInternal: function(effect) {  
    549574    if(effect.options.to!=0) return; 
    550     effect.element.hide(); 
    551     effect.element.setStyle({opacity: oldOpacity});  
     575    effect.element.hide().setStyle({opacity: oldOpacity});  
    552576  }}, arguments[1] || {}); 
    553577  return new Effect.Opacity(element,options); 
     
    564588  }, 
    565589  beforeSetup: function(effect) { 
    566     effect.element.setOpacity(effect.options.from); 
    567     effect.element.show();  
     590    effect.element.setOpacity(effect.options.from).show();  
    568591  }}, arguments[1] || {}); 
    569592  return new Effect.Opacity(element,options); 
     
    572595Effect.Puff = function(element) { 
    573596  element = $(element); 
    574   var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') }; 
     597  var oldStyle = {  
     598    opacity: element.getInlineOpacity(),  
     599    position: element.getStyle('position'), 
     600    top:  element.style.top, 
     601    left: element.style.left, 
     602    width: element.style.width, 
     603    height: element.style.height 
     604  }; 
    575605  return new Effect.Parallel( 
    576606   [ new Effect.Scale(element, 200,  
     
    579609     Object.extend({ duration: 1.0,  
    580610      beforeSetupInternal: function(effect) { 
    581         effect.effects[0].element.setStyle({position: 'absolute'}); }, 
     611        Position.absolutize(effect.effects[0].element) 
     612      }, 
    582613      afterFinishInternal: function(effect) { 
    583          effect.effects[0].element.hide(); 
    584          effect.effects[0].element.setStyle(oldStyle); } 
     614         effect.effects[0].element.hide().setStyle(oldStyle); } 
    585615     }, arguments[1] || {}) 
    586616   ); 
     
    590620  element = $(element); 
    591621  element.makeClipping(); 
    592   return new Effect.Scale(element, 0,  
     622  return new Effect.Scale(element, 0, 
    593623    Object.extend({ scaleContent: false,  
    594624      scaleX: false,  
    595625      restoreAfterFinish: true, 
    596626      afterFinishInternal: function(effect) { 
    597         effect.element.hide(); 
    598         effect.element.undoClipping(); 
     627        effect.element.hide().undoClipping(); 
    599628      }  
    600629    }, arguments[1] || {}) 
     
    605634  element = $(element); 
    606635  var elementDimensions = element.getDimensions(); 
    607   return new Effect.Scale(element, 100,  
    608     Object.extend({ scaleContent: false,  
    609       scaleX: false, 
    610       scaleFrom: 0, 
    611       scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, 
    612       restoreAfterFinish: true, 
    613       afterSetup: function(effect) { 
    614         effect.element.makeClipping(); 
    615         effect.element.setStyle({height: '0px'}); 
    616         effect.element.show();  
    617       },   
    618       afterFinishInternal: function(effect) { 
    619         effect.element.undoClipping(); 
    620       } 
    621     }, arguments[1] || {}) 
    622   ); 
     636  return new Effect.Scale(element, 100, Object.extend({  
     637    scaleContent: false,  
     638    scaleX: false, 
     639    scaleFrom: 0, 
     640    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, 
     641    restoreAfterFinish: true, 
     642    afterSetup: function(effect) { 
     643      effect.element.makeClipping().setStyle({height: '0px'}).show();  
     644    },   
     645    afterFinishInternal: function(effect) { 
     646      effect.element.undoClipping(); 
     647    } 
     648  }, arguments[1] || {})); 
    623649} 
    624650 
     
    626652  element = $(element); 
    627653  var oldOpacity = element.getInlineOpacity(); 
    628   return new Effect.Appear(element, {  
     654  return new Effect.Appear(element, Object.extend({ 
    629655    duration: 0.4, 
    630656    from: 0, 
     
    635661        scaleX: false, scaleContent: false, restoreAfterFinish: true, 
    636662        beforeSetup: function(effect) {  
    637           effect.element.makePositioned(); 
    638           effect.element.makeClipping(); 
     663          effect.element.makePositioned().makeClipping(); 
    639664        }, 
    640665        afterFinishInternal: function(effect) { 
    641           effect.element.hide(); 
    642           effect.element.undoClipping(); 
    643           effect.element.undoPositioned(); 
    644           effect.element.setStyle({opacity: oldOpacity}); 
     666          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); 
    645667        } 
    646668      }) 
    647669    } 
    648   }); 
     670  }, arguments[1] || {})); 
    649671} 
    650672 
     
    664686        }, 
    665687        afterFinishInternal: function(effect) { 
    666           effect.effects[0].element.hide(); 
    667           effect.effects[0].element.undoPositioned(); 
    668           effect.effects[0].element.setStyle(oldStyle); 
     688          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); 
    669689        }  
    670690      }, arguments[1] || {})); 
     
    688708    new Effect.Move(effect.element, 
    689709      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { 
    690         effect.element.undoPositioned(); 
    691         effect.element.setStyle(oldStyle); 
     710        effect.element.undoPositioned().setStyle(oldStyle); 
    692711  }}) }}) }}) }}) }}) }}); 
    693712} 
    694713 
    695714Effect.SlideDown = function(element) { 
    696   element = $(element); 
    697   element.cleanWhitespace(); 
     715  element = $(element).cleanWhitespace(); 
    698716  // SlideDown need to have the content of the element wrapped in a container element with fixed height! 
    699   var oldInnerBottom = $(element.firstChild).getStyle('bottom'); 
     717  var oldInnerBottom = element.down().getStyle('bottom'); 
    700718  var elementDimensions = element.getDimensions(); 
    701719  return new Effect.Scale(element, 100, Object.extend({  
     
    707725    afterSetup: function(effect) { 
    708726      effect.element.makePositioned(); 
    709       effect.element.firstChild.makePositioned(); 
     727      effect.element.down().makePositioned(); 
    710728      if(window.opera) effect.element.setStyle({top: ''}); 
    711       effect.element.makeClipping(); 
    712       effect.element.setStyle({height: '0px'}); 
    713       effect.element.show(); }, 
     729      effect.element.makeClipping().setStyle({height: '0px'}).show();  
     730    }, 
    714731    afterUpdateInternal: function(effect) { 
    715       effect.element.firstChild.setStyle({bottom: 
     732      effect.element.down().setStyle({bottom: 
    716733        (effect.dims[0] - effect.element.clientHeight) + 'px' });  
    717734    }, 
    718735    afterFinishInternal: function(effect) { 
    719       effect.element.undoClipping();  
    720       // IE will crash if child is undoPositioned first 
    721       if(/MSIE/.test(navigator.userAgent)){ 
    722         effect.element.undoPositioned(); 
    723         effect.element.firstChild.undoPositioned(); 
    724       }else{ 
    725         effect.element.firstChild.undoPositioned(); 
    726         effect.element.undoPositioned(); 
    727       } 
    728       effect.element.firstChild.setStyle({bottom: oldInnerBottom}); } 
     736      effect.element.undoClipping().undoPositioned(); 
     737      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } 
    729738    }, arguments[1] || {}) 
    730739  ); 
    731740} 
    732    
     741 
    733742Effect.SlideUp = function(element) { 
    734   element = $(element); 
    735   element.cleanWhitespace(); 
    736   var oldInnerBottom = $(element.firstChild).getStyle('bottom'); 
     743  element = $(element).cleanWhitespace(); 
     744  var oldInnerBottom = element.down().getStyle('bottom'); 
    737745  return new Effect.Scale(element, window.opera ? 0 : 1, 
    738746   Object.extend({ scaleContent: false,  
     
    743751    beforeStartInternal: function(effect) { 
    744752      effect.element.makePositioned(); 
    745       effect.element.firstChild.makePositioned(); 
     753      effect.element.down().makePositioned(); 
    746754      if(window.opera) effect.element.setStyle({top: ''}); 
    747       effect.element.makeClipping()
    748       effect.element.show(); },   
     755      effect.element.makeClipping().show()
     756    },   
    749757    afterUpdateInternal: function(effect) { 
    750       effect.element.firstChild.setStyle({bottom: 
    751         (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, 
     758      effect.element.down().setStyle({bottom: 
     759        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
     760    }, 
    752761    afterFinishInternal: function(effect) { 
    753       effect.element.hide(); 
    754       effect.element.undoClipping(); 
    755       effect.element.firstChild.undoPositioned(); 
    756       effect.element.undoPositioned(); 
    757       effect.element.setStyle({bottom: oldInnerBottom}); } 
     762      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); 
     763      effect.element.down().undoPositioned(); 
     764    } 
    758765   }, arguments[1] || {}) 
    759766  ); 
     
    762769// Bug in opera makes the TD containing this element expand for a instance after finish  
    763770Effect.Squish = function(element) { 
    764   return new Effect.Scale(element, window.opera ? 1 : 0,  
    765     { restoreAfterFinish: true, 
    766       beforeSetup: function(effect) { 
    767         effect.element.makeClipping(effect.element); },   
    768       afterFinishInternal: function(effect) { 
    769         effect.element.hide(effect.element);  
    770         effect.element.undoClipping(effect.element); } 
     771  return new Effect.Scale(element, window.opera ? 1 : 0, {  
     772    restoreAfterFinish: true, 
     773    beforeSetup: function(effect) { 
     774      effect.element.makeClipping();  
     775    },   
     776    afterFinishInternal: function(effect) { 
     777      effect.element.hide().undoClipping();  
     778    } 
    771779  }); 
    772780} 
     
    824832    duration: 0.01,  
    825833    beforeSetup: function(effect) { 
    826       effect.element.hide(); 
    827       effect.element.makeClipping(); 
    828       effect.element.makePositioned(); 
     834      effect.element.hide().makeClipping().makePositioned(); 
    829835    }, 
    830836    afterFinishInternal: function(effect) { 
     
    837843        ], Object.extend({ 
    838844             beforeSetup: function(effect) { 
    839                effect.effects[0].element.setStyle({height: '0px'}); 
    840                effect.effects[0].element.show();  
     845               effect.effects[0].element.setStyle({height: '0px'}).show();  
    841846             }, 
    842847             afterFinishInternal: function(effect) { 
    843                effect.effects[0].element.undoClipping(); 
    844                effect.effects[0].element.undoPositioned(); 
    845                effect.effects[0].element.setStyle(oldStyle);  
     848               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);  
    846849             } 
    847850           }, options) 
     
    897900    ], Object.extend({             
    898901         beforeStartInternal: function(effect) { 
    899            effect.effects[0].element.makePositioned(); 
    900            effect.effects[0].element.makeClipping(); }, 
     902           effect.effects[0].element.makePositioned().makeClipping();  
     903         }, 
    901904         afterFinishInternal: function(effect) { 
    902            effect.effects[0].element.hide(); 
    903            effect.effects[0].element.undoClipping(); 
    904            effect.effects[0].element.undoPositioned(); 
    905            effect.effects[0].element.setStyle(oldStyle); } 
     905           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } 
    906906       }, options) 
    907907  ); 
     
    913913  var oldOpacity = element.getInlineOpacity(); 
    914914  var transition = options.transition || Effect.Transitions.sinoidal; 
    915   var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; 
     915  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; 
    916916  reverser.bind(transition); 
    917917  return new Effect.Opacity(element,  
    918     Object.extend(Object.extend({  duration: 3.0, from: 0, 
     918    Object.extend(Object.extend({  duration: 2.0, from: 0, 
    919919      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } 
    920920    }, options), {transition: reverser})); 
     
    928928    width: element.style.width, 
    929929    height: element.style.height }; 
    930   Element.makeClipping(element); 
     930  element.makeClipping(); 
    931931  return new Effect.Scale(element, 5, Object.extend({    
    932932    scaleContent: false, 
     
    937937      scaleY: false, 
    938938      afterFinishInternal: function(effect) { 
    939         effect.element.hide(); 
    940         effect.element.undoClipping();  
    941         effect.element.setStyle(oldStyle); 
     939        effect.element.hide().undoClipping().setStyle(oldStyle); 
    942940      } }); 
    943941  }}, arguments[1] || {})); 
     
    945943 
    946944['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', 
    947  'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(  
     945 'collectTextNodes','collectTextNodesIgnoreClass'].each(  
    948946  function(f) { Element.Methods[f] = Element[f]; } 
    949947); 
  • vendor/scriptaculous/src/scriptaculous.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     1// script.aculo.us scriptaculous.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    24//  
    35// Permission is hereby granted, free of charge, to any person obtaining 
     
    1921// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    2022// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     23// 
     24// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    2125 
    2226var Scriptaculous = { 
    23   Version: '1.6.1', 
     27  Version: '1.6.5', 
    2428  require: function(libraryName) { 
    2529    // inserting via DOM fails in Safari 2.0, so brute force approach 
  • vendor/scriptaculous/src/slider.js

    r2697 r2821  
    1 // Copyright (c) 2005 Marty Haught, Thomas Fuchs  
     1// script.aculo.us slider.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs  
    24// 
    3 // See http://script.aculo.us for more info 
    4 //  
    5 // Permission is hereby granted, free of charge, to any person obtaining 
    6 // a copy of this software and associated documentation files (the 
    7 // "Software"), to deal in the Software without restriction, including 
    8 // without limitation the rights to use, copy, modify, merge, publish, 
    9 // distribute, sublicense, and/or sell copies of the Software, and to 
    10 // permit persons to whom the Software is furnished to do so, subject to 
    11 // the following conditions: 
    12 //  
    13 // The above copyright notice and this permission notice shall be 
    14 // included in all copies or substantial portions of the Software. 
    15 // 
    16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     5// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     6// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    237 
    248if(!Control) var Control = {}; 
     
    6549     
    6650    this.trackLength = this.maximumOffset() - this.minimumOffset(); 
    67     this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth; 
     51 
     52    this.handleLength = this.isVertical() ?  
     53      (this.handles[0].offsetHeight != 0 ?  
     54        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :  
     55      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :  
     56        this.handles[0].style.width.replace(/px$/,"")); 
    6857 
    6958    this.active   = false; 
     
    138127  setValue: function(sliderValue, handleIdx){ 
    139128    if(!this.active) { 
    140       this.activeHandle    = this.handles[handleIdx]
    141       this.activeHandleIdx = handleIdx
     129      this.activeHandleIdx = handleIdx || 0
     130      this.activeHandle    = this.handles[this.activeHandleIdx]
    142131      this.updateStyles(); 
    143132    } 
     
    181170  }, 
    182171  maximumOffset: function(){ 
    183     return(this.isVertical() ? 
    184       this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX); 
     172    return(this.isVertical() ?  
     173      (this.track.offsetHeight != 0 ? this.track.offsetHeight : 
     174        this.track.style.height.replace(/px$/,"")) - this.alignY :  
     175      (this.track.offsetWidth != 0 ? this.track.offsetWidth :  
     176        this.track.style.width.replace(/px$/,"")) - this.alignY); 
    185177  },   
    186178  isVertical:  function(){ 
     
    218210        var handle = Event.element(event); 
    219211        var pointer  = [Event.pointerX(event), Event.pointerY(event)]; 
    220         if(handle==this.track) { 
     212        var track = handle; 
     213        if(track==this.track) { 
    221214          var offsets  = Position.cumulativeOffset(this.track);  
    222215          this.event = event; 
     
    231224          while((this.handles.indexOf(handle) == -1) && handle.parentNode)  
    232225            handle = handle.parentNode; 
    233          
    234           this.activeHandle    = handle; 
    235           this.activeHandleIdx = this.handles.indexOf(this.activeHandle); 
    236           this.updateStyles(); 
    237          
    238           var offsets  = Position.cumulativeOffset(this.activeHandle); 
    239           this.offsetX = (pointer[0] - offsets[0]); 
    240           this.offsetY = (pointer[1] - offsets[1]); 
     226             
     227          if(this.handles.indexOf(handle)!=-1) { 
     228            this.activeHandle    = handle; 
     229            this.activeHandleIdx = this.handles.indexOf(this.activeHandle); 
     230            this.updateStyles(); 
     231             
     232            var offsets  = Position.cumulativeOffset(this.activeHandle); 
     233            this.offsetX = (pointer[0] - offsets[0]); 
     234            this.offsetY = (pointer[1] - offsets[1]); 
     235          } 
    241236        } 
    242237      } 
  • vendor/scriptaculous/src/unittest.js

    r2697 r2821  
    1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
    2 //           (c) 2005 Jon Tirsen (http://www.tirsen.com) 
    3 //           (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/) 
     1// script.aculo.us unittest.js v1.6.5, Wed Nov 08 14:17:49 CET 2006 
     2 
     3// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 
     4//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) 
     5//           (c) 2005, 2006 Michael Schuerig (http://www.schuerig.de/michael/) 
    46// 
    5 // Permission is hereby granted, free of charge, to any person obtaining 
    6 // a copy of this software and associated documentation files (the 
    7 // "Software"), to deal in the Software without restriction, including 
    8 // without limitation the rights to use, copy, modify, merge, publish, 
    9 // distribute, sublicense, and/or sell copies of the Software, and to 
    10 // permit persons to whom the Software is furnished to do so, subject to 
    11 // the following conditions: 
    12 //  
    13 // The above copyright notice and this permission notice shall be 
    14 // included in all copies or substantial portions of the Software. 
    15 //  
    16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    23  
     7// script.aculo.us is freely distributable under the terms of an MIT-style license. 
     8// For details, see the script.aculo.us web site: http://script.aculo.us/ 
    249 
    2510// experimental, Firefox-only 
     
    2813    pointerX: 0, 
    2914    pointerY: 0, 
    30     buttons: 0 
     15    buttons:  0, 
     16    ctrlKey:  false, 
     17    altKey:   false, 
     18    shiftKey: false, 
     19    metaKey:  false 
    3120  }, arguments[2] || {}); 
    3221  var oEvent = document.createEvent("MouseEvents"); 
    3322  oEvent.initMouseEvent(eventName, true, true, document.defaultView,  
    3423    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,  
    35     false, false, false, false, 0, $(element)); 
     24    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element)); 
    3625   
    3726  if(this.mark) Element.remove(this.mark); 
     
    9988    this.statusCell = document.createElement('td'); 
    10089    this.nameCell = document.createElement('td'); 
     90    this.nameCell.className = "nameCell"; 
    10191    this.nameCell.appendChild(document.createTextNode(testName)); 
    10292    this.messageCell = document.createElement('td'); 
     
    111101    this.statusCell.innerHTML = status; 
    112102    this.messageCell.innerHTML = this._toHTML(summary); 
     103    this.addLinksToResults(); 
    113104  }, 
    114105  message: function(message) { 
     
    132123  _toHTML: function(txt) { 
    133124    return txt.escapeHTML().replace(/\n/g,"<br/>"); 
     125  }, 
     126  addLinksToResults: function(){  
     127    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log 
     128      td.title = "Run only this test" 
     129      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;}); 
     130    }); 
     131    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log 
     132      td.title = "Run all tests" 
     133      Event.observe(td, 'click', function(){ window.location.search = "";}); 
     134    }); 
    134135  } 
    135136} 
     
    142143    }, arguments[1] || {}); 
    143144    this.options.resultsURL = this.parseResultsURLQueryParameter(); 
     145    this.options.tests      = this.parseTestsQueryParameter(); 
    144146    if (this.options.testLog) { 
    145147      this.options.testLog = $(this.options.testLog) || null; 
     
    159161        for(var testcase in testcases) { 
    160162          if(/^test/.test(testcase)) { 
    161             this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"])); 
     163            this.tests.push( 
     164               new Test.Unit.Testcase( 
     165                 this.options.context ? ' -> ' + this.options.titles[testcase] : testcase,  
     166                 testcases[testcase], testcases["setup"], testcases["teardown"] 
     167               )); 
    162168          } 
    163169        } 
     
    170176  parseResultsURLQueryParameter: function() { 
    171177    return window.location.search.parseQuery()["resultsURL"]; 
     178  }, 
     179  parseTestsQueryParameter: function(){ 
     180    if (window.location.search.parseQuery()["tests"]){ 
     181        return window.location.search.parseQuery()["tests"].split(','); 
     182    }; 
    172183  }, 
    173184  // Returns: 
     
    230241    } 
    231242    return ( 
     243      (this.options.context ? this.options.context + ': ': '') +  
    232244      this.tests.length + " tests, " +  
    233245      assertions + " assertions, " +  
     
    298310    catch(e) { this.error(e); } 
    299311  }, 
     312  assertIdentical: function(expected, actual) {  
     313    var message = arguments[2] || "assertIdentical";  
     314    try { (expected === actual) ? this.pass() :  
     315      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +   
     316        '", actual "' + Test.Unit.inspect(actual) + '"'); }  
     317    catch(e) { this.error(e); }  
     318  }, 
     319  assertNotIdentical: function(expected, actual) {  
     320    var message = arguments[2] || "assertNotIdentical";  
     321    try { !(expected === actual) ? this.pass() :  
     322      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +   
     323        '", actual "' + Test.Unit.inspect(actual) + '"'); }  
     324    catch(e) { this.error(e); }  
     325  }, 
    300326  assertNull: function(obj) { 
    301327    var message = arguments[1] || 'assertNull' 
     
    304330    catch(e) { this.error(e); } 
    305331  }, 
     332  assertMatch: function(expected, actual) { 
     333    var message = arguments[2] || 'assertMatch'; 
     334    var regex = new RegExp(expected); 
     335    try { (regex.exec(actual)) ? this.pass() : 
     336      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); } 
     337    catch(e) { this.error(e); } 
     338  }, 
    306339  assertHidden: function(element) { 
    307340    var message = arguments[1] || 'assertHidden'; 
     
    311344    var message = arguments[1] || 'assertNotNull'; 
    312345    this.assert(object != null, message); 
     346  }, 
     347  assertType: function(expected, actual) { 
     348    var message = arguments[2] || 'assertType'; 
     349    try {  
     350      (actual.constructor == expected) ? this.pass() :  
     351      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +   
     352        '", actual "' + (actual.constructor) + '"'); } 
     353    catch(e) { this.error(e); } 
     354  }, 
     355  assertNotOfType: function(expected, actual) { 
     356    var message = arguments[2] || 'assertNotOfType'; 
     357    try {  
     358      (actual.constructor != expected) ? this.pass() :  
     359      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +   
     360        '", actual "' + (actual.constructor) + '"'); } 
     361    catch(e) { this.error(e); } 
    313362  }, 
    314363  assertInstanceOf: function(expected, actual) { 
     
    325374      this.fail(message + ": object was an instance of the not expected type"); } 
    326375    catch(e) { this.error(e); }  
     376  }, 
     377  assertRespondsTo: function(method, obj) { 
     378    var message = arguments[2] || 'assertRespondsTo'; 
     379    try { 
     380      (obj[method] && typeof obj[method] == 'function') ? this.pass() :  
     381      this.fail(message + ": object doesn't respond to [" + method + "]"); } 
     382    catch(e) { this.error(e); } 
     383  }, 
     384  assertReturnsTrue: function(method, obj) { 
     385    var message = arguments[2] || 'assertReturnsTrue'; 
     386    try { 
     387      var m = obj[method]; 
     388      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; 
     389      m() ? this.pass() :  
     390      this.fail(message + ": method returned false"); } 
     391    catch(e) { this.error(e); } 
     392  }, 
     393  assertReturnsFalse: function(method, obj) { 
     394    var message = arguments[2] || 'assertReturnsFalse'; 
     395    try { 
     396      var m = obj[method]; 
     397      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; 
     398      !m() ? this.pass() :  
     399      this.fail(message + ": method returned true"); } 
     400    catch(e) { this.error(e); } 
     401  }, 
     402  assertRaise: function(exceptionName, method) { 
     403    var message = arguments[2] || 'assertRaise'; 
     404    try {  
     405      method(); 
     406      this.fail(message + ": exception expected but none was raised"); } 
     407    catch(e) { 
     408      (e.name==exceptionName) ? this.pass() : this.error(e);  
     409    } 
     410  }, 
     411  assertElementsMatch: function() { 
     412    var expressions = $A(arguments), elements = $A(expressions.shift()); 
     413    if (elements.length != expressions.length) { 
     414      this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions'); 
     415      return false; 
     416    } 
     417    elements.zip(expressions).all(function(pair, index) { 
     418      var element = $(pair.first()), expression = pair.last(); 
     419      if (element.match(expression)) return true; 
     420      this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect()); 
     421    }.bind(this)) && this.pass(); 
     422  }, 
     423  assertElementMatches: function(element, expression) { 
     424    this.assertElementsMatch([element], expression); 
     425  }, 
     426  benchmark: function(operation, iterations) { 
     427    var startAt = new Date(); 
     428    (iterations || 1).times(operation); 
     429    var timeTaken = ((new Date())-startAt); 
     430    this.info((arguments[2] || 'Operation') + ' finished ' +  
     431       iterations + ' iterations in ' + (timeTaken/1000)+'s' ); 
     432    return timeTaken; 
    327433  }, 
    328434  _isVisible: function(element) { 
     
    356462    Test.Unit.Assertions.prototype.initialize.bind(this)(); 
    357463    this.name           = name; 
    358     this.test           = test || function() {}; 
     464     
     465    if(typeof test == 'string') { 
     466      test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,'); 
     467      test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)'); 
     468      this.test = function() { 
     469        eval('with(this){'+test+'}'); 
     470      } 
     471    } else { 
     472      this.test = test || function() {}; 
     473    } 
     474     
    359475    this.setup          = setup || function() {}; 
    360476    this.teardown       = teardown || function() {}; 
     
    382498  } 
    383499}); 
     500 
     501// *EXPERIMENTAL* BDD-style testing to please non-technical folk 
     502// This draws many ideas from RSpec http://rspec.rubyforge.org/ 
     503 
     504Test.setupBDDExtensionMethods = function(){ 
     505  var METHODMAP = { 
     506    shouldEqual:     'assertEqual', 
     507    shouldNotEqual:  'assertNotEqual', 
     508    shouldEqualEnum: 'assertEnumEqual', 
     509    shouldBeA:       'assertType', 
     510    shouldNotBeA:    'assertNotOfType', 
     511    shouldBeAn:      'assertType', 
     512    shouldNotBeAn:   'assertNotOfType', 
     513    shouldBeNull:    'assertNull', 
     514    shouldNotBeNull: 'assertNotNull', 
     515     
     516    shouldBe:        'assertReturnsTrue', 
     517    shouldNotBe:     'assertReturnsFalse', 
     518    shouldRespondTo: 'assertRespondsTo' 
     519  }; 
     520  Test.BDDMethods = {}; 
     521  for(m in METHODMAP) { 
     522    Test.BDDMethods[m] = eval( 
     523      'function(){'+ 
     524      'var args = $A(arguments);'+ 
     525      'var scope = args.shift();'+ 
     526      'scope.'+METHODMAP[m]+'.apply(scope,(args || []).concat([this])); }'); 
     527  } 
     528  [Array.prototype, String.prototype, Number.prototype].each( 
     529    function(p){ Object.extend(p, Test.BDDMethods) } 
     530  ); 
     531} 
     532 
     533Test.context = function(name, spec, log){ 
     534  Test.setupBDDExtensionMethods(); 
     535   
     536  var compiledSpec = {}; 
     537  var titles = {}; 
     538  for(specName in spec) { 
     539    switch(specName){ 
     540      case "setup": 
     541      case "teardown": 
     542        compiledSpec[specName] = spec[specName]; 
     543        break; 
     544      default: 
     545        var testName = 'test'+specName.gsub(/\s+/,'-').camelize(); 
     546        var body = spec[specName].toString().split('\n').slice(1); 
     547        if(/^\{/.test(body[0])) body = body.slice(1); 
     548        body.pop(); 
     549        body = body.map(function(statement){  
     550          return statement.strip() 
     551        }); 
     552        compiledSpec[testName] = body.join('\n'); 
     553        titles[testName] = specName; 
     554    } 
     555  } 
     556  new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name }); 
     557};