Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/moses-smt/mosesdecoder.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorphikoehn <pkoehn@inf.ed.ac.uk>2013-09-26 02:16:53 +0400
committerphikoehn <pkoehn@inf.ed.ac.uk>2013-09-26 02:16:53 +0400
commit1e702c46b2445730baa9a3ee0a8a8a94a07e67ef (patch)
treec64f07a1857c6f8146dcd6e619b5869a294f88e8
parent429a195c68cd172dc6fb0d67bd8908d5414b6d92 (diff)
updated web interface for experiment.perl
-rw-r--r--scripts/ems/web/analysis.php12
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/CHANGELOG1197
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/MIT-LICENSE20
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/README.rdoc59
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/lib/prototype.js4874
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/builder.js136
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/controls.js965
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/dragdrop.js974
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/effects.js1123
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/scriptaculous.js68
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/slider.js275
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/sound.js59
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/unittest.js568
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_result.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_text.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result.html9
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result_single.html3
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter2_test.html86
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter_test.html71
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplacecollectioneditor_test.html60
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplaceeditor_test.html116
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop2_test.html85
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop3_test.html90
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop4_test.html41
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop5_test.html42
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop6_test.html76
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop7_test.html211
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop8_test.html142
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop9_test.html47
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_delay_test.html84
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_test.html120
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dropmarker.pngbin0 -> 213 bytes
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_direct_test.html35
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_puff_test.html65
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_scale_test.html29
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_shake.html55
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects2_test.html63
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects3_test.html36
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects4_test.html31
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5_test.html483
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5b_test.html39
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects6_test.html61
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_blind_test.html65
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_float_appear_test.html46
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_grow_strink_test.html38
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_highlight_bg_image.html57
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_limit_test.html30
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_test.html67
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_random_demo.html76
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_test.html74
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_toggle_test.html36
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/icon.pngbin0 -> 281 bytes
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/index.html91
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/position_clone_test.html124
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/slider_test.html152
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable2_test.html148
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable3_test.html40
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable4_test.html88
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable5_test.html43
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable6_test.html148
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_nested_test.html57
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_test.html141
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_tree_test.html185
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sound_test.html21
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sword.mp3bin0 -> 17759 bytes
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/texteffects_test.html52
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_functional_tests.html20
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_unit_tests.html20
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/test.css90
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_ipce_alt_text.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result2.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_tagged.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_text.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_updater_result.html20
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result.html11
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result_nobr.html1
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_autocompleter_test.html243
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_inplaceeditor_test.html895
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/bdd_test.html150
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/builder_test.html262
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/dragdrop_test.html131
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/effects_test.html547
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/element_test.html116
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/icon.pngbin0 -> 281 bytes
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/index.html70
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/loading_test.html41
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/position_clone_test.html312
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/slider_test.html437
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/sortable_test.html205
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/string_test.html71
-rw-r--r--scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/unittest_test.html154
-rw-r--r--scripts/ems/web/overview.php30
-rwxr-xr-xscripts/ems/web/progress.perl175
94 files changed, 18284 insertions, 13 deletions
diff --git a/scripts/ems/web/analysis.php b/scripts/ems/web/analysis.php
index f4beaa274..726e30fbd 100644
--- a/scripts/ems/web/analysis.php
+++ b/scripts/ems/web/analysis.php
@@ -1055,7 +1055,7 @@ function sentence_annotation($count,$filter) {
list($sentence,$brackets,$nt,$words) = split("\t",$data[$i]);
if ($sentence != $last_sentence) { $span = 0; }
$last_sentence = $sentence;
- if ($filter == "" || array_key_exists($sentence,$retained)) {
+ if (array_key_exists($sentence,$retained)) {
$segmentation[$sentence][$span]["brackets"] = $brackets;
# $segmentation[$sentence][$span]["nt"] = $nt;
$segmentation[$sentence][$span]["words"] = rtrim($words);
@@ -1082,7 +1082,7 @@ function sentence_annotation($count,$filter) {
list($sentence,$brackets,$nt,$words) = split("\t",$data[$i]);
if ($sentence != $last_sentence) { $span = 0; }
$last_sentence = $sentence;
- if ($filter == "" || array_key_exists($sentence,$retained)) {
+ if (array_key_exists($sentence,$retained)) {
$segmentation_out[$sentence][$span]["brackets"] = $brackets;
$segmentation_out[$sentence][$span]["nt"] = $nt;
$segmentation_out[$sentence][$span]["words"] = rtrim($words);
@@ -1108,7 +1108,7 @@ function sentence_annotation($count,$filter) {
list($sentence,$depth,$start_div,$end_div,$start_div_in,$end_div_in,$children) = split(" ",$data[$i]);
if ($sentence != $last_sentence) { $n = 0; }
$last_sentence = $sentence;
- if ($filter == "" || array_key_exists($sentence,$retained)) {
+ if (array_key_exists($sentence,$retained)) {
$node[$sentence][$n]['depth'] = $depth;
$node[$sentence][$n]['start_div'] = $start_div;
$node[$sentence][$n]['end_div'] = $end_div;
@@ -1241,7 +1241,7 @@ function input_annotation($sentence,$input,$segmentation,$filter) {
for($sep_end=1;$sep_end<=count($word);$sep_end++) {
if ($separable[$sep_end] == 1) {
# one table for each separable block
- print "<table cellpadding=1 cellspacing=0 border=0 style=\"display: inline;\">";
+ print "<table cellpadding=1 cellspacing=0 border=0 style=\"display: inline-table;\">";
for($level=$max_level;$level>=1;$level--) {
# rows for phrase display
print "<tr style=\"height:5px;\">";
@@ -1448,8 +1448,8 @@ function biconcor($query) {
<input type=submit onclick=\"show_biconcor($sentence,encodeBase64(document.getElementById('BiconcorQuery').value));\" value=\"look up\">
</form>
<div class=\"biconcor-content\">";
- $cmd = "./biconcor -l $dir/model/biconcor.$biconcor -Q ".base64_encode($query)." 2>/dev/null";
- #print $cmd."<p>";
+ $cmd = "./biconcor -html -l $dir/model/biconcor.$biconcor -Q ".base64_encode($query)." 2>/dev/null";
+ # print $cmd."<p>";
system($cmd);
# print "<p>done.";
print "</div></center>";
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/CHANGELOG b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/CHANGELOG
new file mode 100644
index 000000000..d112a9599
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/CHANGELOG
@@ -0,0 +1,1197 @@
+*V1.8.3* (October 8, 2009)
+
+* Update to Prototype 1.6.1
+
+* Effect.toggle to return effect (to be able to do Effect.toggle(element, 'appear', {sync: true});) [RStankov]
+
+* Use element.identify() for fetching element.id in Sortable.create [RStankov]
+
+* Fix deprecated usage of Position.cumulativeOffset. [#182 state:resolved] [James Wheare]
+
+* Make loader work for application/xhtml+xml served documents. Closes #95. [Pavel Sedek]
+
+* Check for Windows Media plugin and RealPlayer plugin in Firefox on Windows to allow sound playback. Closes #36, #86. [Alexander Gavazov et al.]
+
+* Remove dead code in effects.js. Closes #125. [Confusioner]
+
+*V1.8.2* (November 18, 2008)
+
+* Update to Prototype 1.6.0.3
+
+* Make sure InPlaceEditor converts HTML entities to text. [Sean Kirby]
+
+* Fix that Builder.node did not return extended elements on IE. Closes #71 and #77.
+
+* Fix a bug in Sortable.destroy to make sure it's called on the referenced Sortable only, which allows for the correct intialization of nested Sortables. Closes Trac #8615. [Leon Chevalier]
+
+* Change Effect.Base#render not to use eval(), so certain JavaScript runtime environments (like Adobe AIR) that do not support eval() work. [King Maxemilian, John-David Dalton]
+
+* Fixed a calculation error in Effect.Transitions.pulse that could lead to flickering, add easing and change it to be a normal 0 to 1 transition that can be used with any effects; Effect.Pulsate now uses its own implementation. [Thomas Fuchs]
+
+* Fixed Effect.ScrollTo. Changeset 8686 had a typo, document.viewport.getScrollOffsets[0] is always undefined. Removed the max check as it is not a cross-browser way to get scroll height and breaks the effect. Depending on scrollTo to do the right thing. Closes #11306. [Nick Stakenburg]
+
+* Update version check so all Prototype versions can be required, not just x.x.x. Closes #10966. [Nick Stakenburg]
+
+* Using $$ in the loader instead of getElementsByTagName to prevent limitations. Closes #9032. [Nick Stakenburg]
+
+* Fix some missing semicolons. [jdalton]
+
+* Fix an issue with Effect.ScrollTo that caused Firefox to scroll to the wrong offset in some situations. Closes #10245. [nik.wakelin]
+
+* Fixes an issue with IE ghosting on non-absolute elements. Closes #10423. [Tanrikut, tdd]
+
+*V1.8.1* (January 3, 2008)
+
+* Fix Element#getStyles in IE. Closes #10563. [Tobie Langel]
+
+* Update to Prototype 1.6.0.1 as of 8551.
+
+* Fix a regression with autocompleters not responding correctly to cursor keys on both Safari and IE. Closes #10107. [thx Zman771]
+
+*V1.8.0* (November 6, 2007)
+
+* Update to Prototype 1.6.0 final
+
+* Ajax.InPlaceEditor now can deal with callbacks that return an object. Closes #10064. [tdd]
+
+* Fix a potential problem with the loader and Firefox 2.0 on the Mac. Closes #9951. [awaters]
+
+* Add duration and distance options to Effect.Shake. Closes #8637. [amiel, rmm5t]
+
+* Update code to use new Hash implemention in Prototype 1.6. Update InPlaceEditor to use new Class.create syntax. [tdd]
+
+*V1.8.0 preview 0* (October 12, 2007)
+
+* Update to new Class.create syntax in Prototype 1.6; update to latest Prototype 1.6 trunk.
+
+* Fix bottom CSS property reassignment and initialization in queues for Effect#SlideUp. Closes #7412, #7761.
+
+* Fix an issue with String#parseStyle that could sometimes cause errors on Safari 2.
+
+* Refactoring to use Prototype 1.6. Remove dependency of Effect.tagifyText from builder. Use Prototype code style rules more consistently.
+
+* Remove the deprecated Effect2 namespace.
+
+* Update to Prototype 1.6.0_rc0.
+
+* Some effect code refactoring to take advantage of new Prototype 1.6 features.
+
+* Effect.ScrollTo is now no longer a core effect (returns a Effect.Tween instance now).
+
+* Add Effect.Tween, a new core effect. This effect tweens between two values and sets a property or calls a method on an object (including DOM elements); or allows for a callback method, which will be automatically bound to the object.
+ Examples:
+ var whatever = { blech: 0 };
+ new Effect.Tween(whatever, 5, 0, 'blech'); // sets property on the object
+ new Effect.Tween('foo', 10, 20, 'innerHTML'); // sets property on the 'foo' DOM element
+ new Effect.Tween('foo', 10, 20, 'update'); // method call on 'foo' DOM element
+ new Effect.Tween('foo', 50, 0, { duration: 2.0 }, function(p){
+ this.setStyle({border:p.toFixed(3)+'px solid red'});
+ });
+ new Effect.Tween(null, 0, 100, function(p){ scrollTo(0,p) }); // scrolls the window
+
+* Revert the workaround for the Firefox issue that makes autocompleter input field values be remembered correctly when the back button is hit to return to a page that contains autocompleted values, as this can cause "Are you sure you want to navigate away?" popups. Closes #8411. [okada]
+
+* Improve the way deactivating the active droppable is handled. Closes #9072. [Karsten Sperling]
+
+* Next version will be 1.8.0. Update to Prototype 1.6.0_pre1.
+
+* Make draggable initialization faster. Closes #8697. [ssinghi]
+
+* Make BDD-style testing compatible with IE6 and IE7. Closes #8972. [steveluscher]
+
+* Add BDD methods to booleans. Closes #9147. [steveluscher]
+
+* Add support for full CSS inheritance in Effect.Morph. Closes #9054. [Tobie]
+ IMPORTANT: Note that this could potentially change the outcome of classname-based morphs, so be sure to check your morph effects if you use this feature.
+ For this feature, the new method Element#getStyles is introduced, which returns an objects which properties correspond to the CSS properties found in Element.CSS_PROPERTIES. Note that this method doesn't work seemlessly across browsers for certain non-measurable CSS properties, such as float.
+
+* Add the externalControlOnly option to the in-place editors to allow for external controls to exclusively trigger the in-place editing. Closes #9024. [tdd]
+
+* Complete rewrite of Ajax.InPlaceEditor and Ajax.InPlaceCollectionEditor. [tdd]
+ THIS UPDATE MIGHT AFFECT BACKWARDS COMPATIBILITY.
+ Be sure to properly test, especially if you're using multi-line editing and/or monkeypatching.
+ Read more about all the added goodness in this article:
+ http://mir.aculo.us/2007/7/17/in-place-editing-the-summer-2007-rewrite
+
+* Update to Prototype 1.5.2_rc0 r7076:
+ - Works around bugs in Safari 1 and Safari 2 Regexp engines that could cause crashes
+ - Fixes a rendering issue with opacity-based effects and floating elements on Safari
+
+* Mild refactoring of sound.js to take advantage of new Prototype features.
+
+* Add highlight element method as a shortcut to Effect.Highlight.
+ Example:
+ $('message').highlight({startcolor:'#ff0000'}).update('KTHXBYE');
+
+* Improve performance of String.prototype.parseStyle by caching the dummy element used.
+
+* Add combined effects as element methods.
+ Examples:
+ $('message').appear().update('Oh noes!');
+ $('login').shake({ duration: 2 });
+
+* Add Effect.Transitions.spring, which simulates a spring which oscillates while coming to rest. This transition is specifically targeted towards use with Effect.Move, for example as a reverteffect when using Draggables, as it will have return values >1 and cause temporary "overshooting" of the effect. Closes #8474. [edg2s]
+
+* Fix effects initialization if no options are given. Fixes #7809. [thx Kroc Camen]
+
+* Fix incorrect placement on drop for absolute ghosting elements. Update to Prototype 1.5.2_rc0 r6955 (required for #8581). Closes #8581. [tdd]
+
+* Make sure the autocompletion happens on the token where the cursor is, not the last token when using tokenized autocompleting text fields. Closes #8588. [tdd]
+
+* Fix that non-Mozilla browsers would display messages with the autocompleter back-button fix introduced in 1.7.1 beta 2. Fixes #7752, #8411. [josh, stetz]
+
+*V1.7.1 beta 3* (May 19, 2007)
+
+* Update to Prototype 1.5.1 final
+
+* New elements and handles options for Sortable.create which take arrays of elements or element ids. These overrule the normal handle and elements finding options on initialization of the sortable, and can yield huge performance increases in situations where these elements or ids are known at call time. [Thomas Fuchs]
+
+* Major performance improvement of Sortable.create when using the handle option. [Tobie Langel]
+
+* Fix Builder.node double quote escaping in attributes, fixes #8125. [Aa!]
+
+*V1.7.1 beta 2* (April 28, 2007)
+
+* Update to Prototype 1.5.1_rc4
+ - Various optimizations and fixes
+ - http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6604
+
+* Fix autocompleter indicator not appearing when calling activate() directly. Don't show indicator for local autocompleting. Fixes #7770. [pyro8019]
+
+* Don't clear out autocompleting fields in Mozilla-based browsers when navigating back to a page with the Back button, fixes #7752. [seanc]
+
+*V1.7.1 beta 1* (March 12, 2007)
+
+* Update to Prototype 1.5.1 r6386
+ - Fixes SlideUp/SlideDown on IE
+ - Fixes an opacity problem with IE
+ - Performance optimizations
+ - See http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6381 for more information
+
+* Make builder unit tests work on IE
+
+* Fix id assignment for sounds on Firefox/Windows, fixes #7709 [Robert Wallis]
+
+* Add Sound.enable() and Sound.disable() to globally turn off Sound.play()
+
+* Added Sound.play(url,options) in new sound.js file. scriptaculous.js automatically includes this file.
+ Based on code by Jules Gravinese, used with permission.
+
+ The sound player uses native sound support on IE, and falls back to using <embed> on other browsers,
+ which means it uses QuickTime for most cases. The recommended format to use is MP3.
+
+ Examples:
+ Sound.play('blah.mp3');
+ // --> plays sound immediately in 'global' track
+ Sound.play('blah.mp3',{replace:true});
+ // --> stop playing all sounds in 'global' track, and play new sound
+ Sound.play('blah.mp3',{track:'mytrack'});
+ // --> places the sound in the 'mytrack' track
+ Sound.play('blah.mp3',{track:'mytrack',replace:true});
+ // --> stop playing all sounds in 'mytrack' track, and play new sound
+
+ The sound effect used in the functional test is "Sword being drawn" by James Greever, released as freeware.
+
+* Various effects engine optimizations [Tobie Langel, Thomas Fuchs]
+
+* Make Ajax.InPlaceEditor more customizable: [thx godlie]
+ - Add an okLink option to Ajax.InPlaceEditor so you can have a link instead of a button. Uses the 'editor_ok_link' CSS class for styling, fixes #6455
+ - Add an cancelButton option to Ajax.InPlaceEditor, uses the 'editor_cancel_button' CSS class
+ - Add textBefore-, textBetween- and textAfterControls (which default to empty strings)
+ - For consistency, cancel link now also gets 'editor_cancel_link' CSS class
+
+* Add an onDropped callback to Draggables, that fires at the end of a drag when the Draggable was dropped on a Droppable
+
+* Add revert: 'failure' option to Draggables to only revert if not dropped on a valid drop target, fixes #6909 [davidw]
+
+* Update to new Prototype Browser detection
+
+* Fix a memory leak with Effect.Morph in Firefox, fixes #7558 [Malard]
+
+* Add ability to nest single nodes in Builder.node in addition to arrays of nodes.
+ Examples:
+ var element = Builder.node('div', Builder.node('span','blah'));
+
+ Builder.dump();
+ var element = DIV(SPAN('blah'));
+
+*V1.7.0* (January 19, 2007)
+
+* Cleanups for Effect.Morph
+
+* Monkeypatch Prototype 1.5.0 to incorporate [6002], fixes setStyle({opacity:0}) for IE
+
+* Fix Effect.inspect() for Prototype 1.5.0 final hash changes
+
+* Update to Prototype 1.5.0 final
+
+* New option keepBackgroundImage: true for Effect.Highlight, fixes #5037 [docwhat, tomg]
+
+* Minor tweaks for issues with application/xhtml+xml documents on Firefox, fixes #6836 [sjinks]
+
+* Fix a possible exception with Sortables, fixes #6828 [craiggwilson]
+
+* Update to Prototype 1.5.0_rc2 revision [5844] (as of Rails 1.2 RC 2)
+
+*V1.7.0 beta 2* (December 18, 2006)
+
+* Change the default setting for effects to support up to 60fps, if renderable by the browser. Add performance info to effects unit test.
+
+* Change get/setOpacity to use Prototype's new support for cross-browser opacity.
+
+* Update to Prototype 1.5.0_rc2 revision [5741], which fixes some of the reported issues with beta 1 (see Prototype's CHANGELOG for more):
+ * Opera 9, while not officially supported, should work now with Prototype and script.aculo.us
+ * Fixes issue with Safari when using Prototype's Ajax helpers with HTTP authorization
+
+* Add hash and CSS className support to Effect.Morph, fixes #6674 [Tobie]
+ Examples:
+ $(element).morph('myClass')
+ // will morph to all the properties specified
+ // in .className (in your external stylesheet).
+ // All properties which cannot be morphed (such as font-style)
+ // will be applied AfterFinish
+ $(element).morph('font-size: 10px') // or
+ $(element).morph({fontSize: '10px'}) // will morph the font-size to 10px
+
+*V1.7.0 beta 1* (November 21, 2006)
+
+* Add Element.morph() and Element.Methods.morph() as a shortcut to Effect.Morph
+ Example:
+ // basic Effect.Morph
+ $('error_message').morph('color:#f00;font-size:17px');
+ // fade out after a while
+ $('error_message').show().morph('font-size:17px').morph('opacity:0',{delay:4});
+
+* Update to Prototype 1.5.0_rc2 revision [5580]
+
+* Add a paramName option to the inplace editor for overriding the default parameter name of "value"
+
+* Add Effect.Transform that generates parallel executing Effect.Morph sets
+ Example:
+ // set up transformation
+ var transformation = new Effect.Transform([
+ { 'div.morphing': 'font-size:20px;padding-left:40em' },
+ { 'blah' : 'width:480px;border-width:10px;border-right-width:20px;margin:200px;margin-bottom:-20px;font-size:30px' }
+ ],{ duration: 0.5 });
+ // play transformation (can be called more than once)
+ transformation.play();
+
+* Add Effect.Morph core effect that morphs to a given CSS style rule. Effect.Morph does take orginal styles given by CSS style rules or the style attribute into consideration when calculating the transforms. It works with all length and color based CSS properties, including margins, paddings, borders, opacity and text/background colors.
+ Example:
+ new Effect.Morph('mydiv',{
+ style: 'font-size:3em;color:#f00;border-width:2em',
+ duration: 2.0
+ });
+
+*V1.6.5* (November 8, 2006)
+
+* Update to Prototype 1.5.0_rc1 revision [5462]
+
+* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd]
+
+ var node = Builder.node('label', { htmlFor: 'myinput' });
+
+* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo]
+
+* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower]
+
+* Add rails-trunk update task, clean up references to MIT license
+
+* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue
+
+* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues
+
+ new Effect.Event({ afterFinish:function(){
+ // do some code here
+ }, position: 'end' });
+
+* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC
+
+* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel]
+
+* Add Builder.build() to create nodes from strings containing HTML, [DHH]
+
+ var node = Builder.build("<p>this is <b>neat!</b></p>");
+
+* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo]
+
+ For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses.
+
+* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin]
+
+* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd]
+
+*V1.6.4* (September 6, 2006)
+
+* Hotfix IE issues with patched Prototype V1.5.0_rc1
+
+*V1.6.3* (September 5, 2006)
+
+* Update Prototype to V1.5.0_rc1
+
+* Merge assertElementsMatch and assertElementMatches from Prototype's [4986] unittest.js [Sam Stephenson]
+
+* Update Prototype to revision [4930]
+
+* Fix various issues with IE detection and Opera, and setOpacity, fixes #3886, #5973
+
+* Make Sortable.serialize handle DOM IDs like "some_element_1" correctly, fixes #5324
+
+* Add assertRespondsTo and shouldRespondTo assertions
+
+* Add experimental alternate syntax for unit tests (Behaviour Driven Development-style)
+
+* Add support for onStart, onDrag and onEnd events directly on Draggables (invoked from the Draggables.notify), fixes #4747 [thx scriptkitchen]
+
+* Add element shortcuts to Builder that can be activated by calling Builder.dump() (see the unit test), fixes #4260 [thx napalm]
+
+* Fix selection of correct option in SELECT element generated by InPlaceCollectionEditor for indexed option arrays, fixes #4789 [thx steve]
+
+* Add autoSelect option to Autocompleters to auto select an entry if only one is returned, fixes #5183 [thx cassiano dandrea]
+
+* Added delay option to Draggables and Sortables, see test/functional/dragdrop_delay_test.html for usage, implements #3325 [thx lsimon, tomg]
+
+* Remove revert cache code obsoleted by #4706, fixes #3436 (again) [thx tomg]
+
+* Fix autoscrolling inside scrollable containers when window is scrolled too, fixes #5200 [thx wseitz]
+
+* Make Effect.Puff work correctly for floating elements, fixes #3777 [thx michael hartl]
+
+* 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]
+
+* Add assertIndentical and assertNotIdentical unit test assertions, which test for equality and common type, fixes #5822 [thx glazedginger]
+
+* Add integration test for Ajax autocompleter for results with no linebreaks, #4149
+
+* Fix an issue with redrawing ghosted draggables that are inside a scrolled container, fixes #3860 [thx gkupps, tsukue]
+
+* Added a custom exception to all base effects when used on non-existing DOM elements, added a assertRaise method to unit tests
+
+* Fix autoscrolling when dragging an element unto a scrollable container, fixes #5017 [thx tomg]
+
+* Fix a condition where overriding the endeffect on Draggables without overriding the starteffect too leads to a Javascript error [thx Javier Martinez]
+
+* Fix a possible error with the drag/drop logic (affects the solution to #4706)
+
+*V1.6.2*
+
+* 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]
+
+* Fix possible memory leaks with Draggables, fixes #3436 [thx aal]
+
+* Throw nicer errors when requires script.aculo.us libraries are not loaded, fixes #5339
+
+* Make slider handles work when not displayed initially by using CSS width/height, fixes #4011 [thx foysavas]
+
+* Update sortable functional test with onUpdate counter
+
+* Make more Element extensions unit tests work on Safari
+
+* Add the assertMatch unit test assertion for asserts with RegExps [thx Ian Tyndall]
+
+* Fix a problem with Effect.Move causing "jumping" elements because of very low float numbers in some situations
+
+* Fix a missing semicolon in dragdrop.js, fixes #5569 [thx mackalicious]
+
+* Fix a slight inaccuracy with Effect.Scale that could lead the scaling to be one pixel off
+
+* Be more prototypish with Effect.Transitions.linear
+
+* Make Effect.Scale recognize font sizes that use the pt unit, fixes #4136 [thx aljoscha]
+
+* Fix IE hack in Effect.Opacity, fixes #5444 [thx nicholas]
+
+* Fix IFRAME layout fix for IE and Autocompleter, fixes #5192 [thx tommy skaue]
+
+* Fix only option in onEmptyHover, fiex #5348 [thx glenn nilsson]
+
+* Fix Effect.BlindDown and SwitchOff handling of supplied callbacks, fixes #5089 [thx martinstrom]
+
+* Fix a problem with field focus on Ajax.InPlaceEditor and loading external text, fixes #4988, #5244 [thx rob]
+
+* Do not attempt to scroll if scrollspeed is 0/0, fixes #5035 [thx tomg]
+
+* Fix a problem with Sortable Tree serialization, fixes #4939, #4688, #4767 [thx Sammi Williams]
+
+* Fix an endless loop with sliders, fixes #3226, #4051, #4765 [thx jeff]
+
+* Make autocompleter work with update DIVs that have scrollbars, fixes #4782 [thx Tommy Skaue]
+
+* Corrected options parsing on switchoff effect, fixes #4710 [thx haldini]
+
+*V1.6.1*
+
+* Update to Prototype 1.5.0_rc0
+
+* Add Draggable object as third parameter to snap, fixes #4074 [thx mdaines]
+
+* Fix an IE flicker with SlideUp/SlideDown, fixes #3774, [thx sbbowers]
+
+* Add parsing/setting of any currently set opacity CSS rule to default opacity effect on draggables, fixes #3682 [thx Mike A. Owens]
+
+* Added prototype $() performance patch from #4477 and updated effects.js to new Element.addMethods() syntax
+
+* Sortable trees [thx Sammi Williams, sammi@oriontransfer.co.nz]
+ - Added functional test (test/functional/sortable_tree_test.html)
+ - removed greedy option
+ - modified the way Droppables.show works - added affected list
+ - added Droppables.findDeepestChild
+ - modified Sortable.options to work for trees
+ - modified Sortable.onEmptyHover with additional logic to insert
+ the element at a certain place according to the overlap
+ - modified Sortable.onHover to avoid DOM Exceptions
+ - modified Sortable.create to support the creation of Sortable trees
+ - added two convenience functions - Sortable.findElements and
+ Sortable.findTreeElements
+ - Added Sortable.tree (and a number of private functions to facilitate it)
+ Returns a tree structure:
+ var root = {
+ id: null,
+ parent: null,
+ children: <children>,
+ container: <sortable element>,
+ }
+ var child = {
+ parent: <node>,
+ children: <array>,
+ id: <string> (as per options.format),
+ element: <element>,
+ container: <element>,
+ position: <integer>
+ }
+ This is intended to become part of the public API, and can be used to manipulate
+ the tree programatically.
+ - Modified Sortable.serialize to use Sortable.tree when set in the options.
+
+* Fix a problem with window scrolling on draggables [thx Gregory Hill]
+
+* Let the benchmark method return the time taken in ms, so it can be used for time-based assertions
+
+* Fix problem with id-based handle names and draggables
+
+* More Element.childrenWithClassName optimization
+
+* Added benchmark method to unittest.js; some cleaning up of unit tests
+
+* Add fix for IE memory leaks in included prototype.js from [4094]
+
+*V1.6.0*
+
+* Major speedup for sortable with handles initialization [thx Jamis Buck]
+
+* Update to latest Prototype 1.5.0_pre1 trunk
+
+* Add functional "random effects" test, also for browser compatibility testing
+
+* Fix two typos introduced with the 1.5 Methods syntax update
+
+* Add functional test for $$-triggered effects with .visualEffect
+
+* Fix shift-tab for autocompleter in Safari, fixes #4423 [thx matt]
+
+* Prepare for script.aculo.us 1.6, add Prototype 1.5 requirement and check that Element.Methods is available in the scriptaculous loader
+
+* Refactor effects.js to use the new Prototype 1.5 Element Methods syntax
+
+* Update to latest Prototype 1.5.0_pre0 trunk
+
+* Fix a problem with the draggable window scrolling code and scrolling inside overflow containers
+
+* Add passing through of scroll options from Sortable to Draggable [thx Gregory Hill]
+
+* Make it possible to scroll window on dragging, #3921 [thx rdmiller]
+
+* Make Element.forceRerendering give up on any exception (this fixes various problems with IE)
+
+* added visualEffect method for the Element Mixin, fixed so you can chain multiple calls. [Rick Olson]
+
+* Fix only option on Sortable.create to accept multiple class names, fixes #3427 [thx glenn nilsson]
+
+* Added workaround for a rendering bug in Safari when using floating elements with Effect.Appear
+
+* Update lib/prototype.js to Prototype 1.5.0_pre0
+
+*V1.5.3*
+
+* Change version number to V1.5.3, prepare Rakefile
+
+* Remove unneeded height restoring in Effect.BlindDown as that is handled internally by the restoreAfterFinish option to Effect.Scale, fixes #3667 [thx Ross Lawley]
+
+* Added Ajax.InPlaceCollectionEditor which uses a SELECT element instead of a text field (see test/functional/ajax_inplacecollectioneditor_test.html for usage), #3491 [thx anna]
+
+* Enable in place editor to use RJS (implements a new evalScripts option for the in place editor), #3490 [thx Richard Livsey]
+
+* Added Sortable.setSequence to programmatically reorder a Sortable, #3711 [thx Mike A. Owens]
+
+* Added unit test for #3732 (currently fails due to Prototype #3877) [thx michal]
+
+* Fix span positioning for sliders with ranges not starting at 0, fixes #3731 [thx michal]
+
+* Make name option on Sortable.serialize work again, fixes #3873
+
+* Make dragging cancel only on ESC key, not on any key, fixes #3817
+
+* Fix Rakefile for V1.5.2
+
+*V1.5.2*
+
+* Change version number to V1.5.2
+
+* Fix a wrong parameter in dragdrop.js, fixes #3555
+
+* Fix two typos in effects.js, fixes #3481 [thx jtolds]
+
+* Add assertEnumEqual for unit testing (from Prototype SVN trunk) [Sam Stephenson]
+
+* Add Sortable.sequence method to extract the current sequence of a Sortable as an array, fixes #3675 [thx sphivo]
+
+* Add limit option to effect queues to limit the maximum number of effects in a queue, new unit tests for scoped effect queues, fixes #3498 [thx Abdur-Rahman Advany]
+
+* Fix Element.collectTextNodesIgnoreClass to correctly filter child nodes, fixes #3380 [thx lam]
+
+* Fix a condition where OPTION elements could cause unwanted dragging on Draggables, fixes #3441 [thx tom]
+
+* Fix a crash because of an IE bug in Effect.SlideDown, fixes #3192 [thx Rob Mayhew]
+
+* Added experimental auto-scroll option to Draggables and Sortables, activate with scroll: 'id_of_scroll_container_element'.
+ Note: needs testing, call syntax might change
+ See test/functional/dragdrop3_test.html for usage/demo
+
+* Added activate method to Autocompleter that allows you to trigger the suggestions through other means than user input [DHH]
+
+*V1.5.1*
+
+* Add select option to Autocompleter to optionally use textnodes from elements with a specific CSS class (see test/functional/ajax_autocompleter_test.html for usage)
+
+* In-place editor: add ok/cancel visibility options and onblur() submission, fixes #3233 [thx pulsation]
+ Note: currently, blur form submission breaks the cancel link functionality, if enabled
+
+* Added Effect.toggle for slide, blind and appear/fade effects, fixes #2704 [thx Azad]
+
+* Added selective component loading to scriptaculous.js, see test/unit/loading_test.html for usage [thx David Zülke]
+
+* Added local/scoped effect queues [thx David Zülke]
+
+* New core effect Effect.Move that can do absolute/relative movement [thx David Zülke]
+
+* Make default effects options modifyable globally by setting Effect.DefaultOptions
+
+* Make Draggables recognize top/left CSS properties defined in an external stylesheet, fixes #3205 [thx ansonparker]
+
+* Fixed draggables starting to drag even if mouse button was released with no movement, [thx topfunky]
+
+* Updated the README to reflect final status
+
+*V1.5.0*
+
+* Prepared for V1.5.0 final
+
+* Update lib/prototype.js to Prototype 1.4.0 final
+
+*V1.5.0_rc6*
+
+* Update lib/prototype.js to Prototype 1.4.0_rc4
+
+* Fix Effect.SlideDown/SlideUp on Internet Explorer, includes a change to Effect.Scale, (should) fix #2962 and others, [thx wyldeone]
+
+* Make Draggables that are reverting cancel the default revert effect when they are dragged again while reverting, fixes #3188, [thx maverick]
+
+* Fix a problem with a wrong reference in Effect.Pulsate, fixes #3184, [thx cyx_]
+
+* Fix Sortable.findElements for XHTML in Gecko, fixes #3081, [thx fgnass]
+
+* Fix a problem with the slider getting NaN results when clicking directly on the track, fixes #3020, [thx rectalogic]
+
+* Fix a problem with Safari not doing sub-pixel rendering when setting opacity to 1 with Element.setOpacity
+
+* Fix slider to make handle width/height count for track length, fixes #3040, fixes #3017, [thx buggedcom]
+
+* Added Basic unit test for Effect.inspect
+
+* Fix Effect.multiple to deal correctly with delays
+
+* Safeguard Effect.Base.render to only do updates when Effect is in running state, fixes #2912
+
+* Added inspect method to Effect.Base
+
+* Added functional test for DOM-based UL sortables #3016
+
+* Added offset option to Effect.ScrollTo
+
+* More effects.js/dragdrop.js refactoring
+
+* Refactoring and optimizations for effects (not complete yet)
+
+* Refactoring and optimizations for Draggables/Droppables/Sortables (not complete yet)
+
+*V1.5.0_rc5*
+
+* Make Droppables.remove accept DOM IDs in addition to elements
+
+* Added some unit tests for drag and drop
+
+* Update lib/prototype.js to Prototype 1.4.0_rc3
+
+* Make 'contents' a synonym for 'content' on Effect.Scale scaleMode option
+
+* Fix some possible exceptions in slider.js
+
+* Support for various snapping options on Draggables, adresses #2826, [thx saimonmoore]
+
+* Support horizontal ghostable Sortables, fixes #2794, [thx johnm]
+
+* Prevent an exception on IE with a functional test, see #2706
+
+* Add functional testing of hoverclasses for sortables
+
+* Add an assert for correct UTF-8 return chars in Autocompleter
+
+* Correct IE detection in Autocompleter for Opera, fixes #2558 [thx gary]
+
+* Add onDrag callback to Draggable observers, #2827 [thx saimonmoore]
+
+* Added Form.Element.DelayedObserver to controls.js for live-search fields
+
+* Remove Element.Class in favour of Prototype Element.ClassNames, new function Element.childrenWithClassName()
+
+* Update Copyright notice in slider.js
+
+* Fix slider firing onChange events to eagerly on dragging a handle [thx wombert]
+
+* Fix a problem with Start/End spans and single handles
+
+* Add event property to Slider object so that callbacks can determine if setValue originated from a UI event or from script
+
+* Fix Builder.node() throwing unresolved errors in IE6, #2707 [thx flwombat]
+
+* Give currently active handle on slider the "selected" CSS class
+
+* Add start and end spans to slider
+
+* Make track clickable for sliders (moves last active handle [or first handle] to nearest possible position)
+
+* Make initial values on slider work for single and multiple handle sliders
+
+*V1.5.0_rc4*
+
+* Abort Effect.Highlight on elements which have display:none set (prevents problem with Safari)
+
+* Make Effect.Queue an Enumerable, fix a problem with Effect.Grow, more unit tests
+
+* Added restricted option to prevent moved of handles prior/after adjacent handles on Sliders with multiple handles
+
+* Update lib/prototype.js to Prototype 1.4.0_rc2
+
+* Fix a bug with wrongly scrolling to the page top in Ajax.InPlaceEditor (circumvents various browser bugs) [Jon Tirsen], #2616
+
+* major slider refactoring, changed slider range to default to [0,1]. Slider Range can be set with range:$R(from,to) option. The increment option is not active for now.
+
+* Added spans support for Control.Slider to mark spans bordered by slider handles, see unit test [thx to www.bartenbach.de for sponsoring this functionality]
+
+* Added preliminary support for optional multiple handles to Control.Slider [thx to www.bartenbach.de for sponsoring this functionality]
+
+* Fixed wrong inclusion of libs in inplace editor functional test
+
+* Fixed Effect.SlideDown/SlideUp to honor refactoring of Effect.Scale, fixes #2523 [thx obiwanki]
+
+* Reset the zIndex on Draggables correctly, #2483 [thx Jon Whitcraft]
+
+* Fix onChange callback on Sortables when dragging between sortables, #2488 [thx Dylan Greene]
+
+* Removed Builder code from effects.js, removed Object.debug (implemented as Test.Unit.inspect)
+
+* Added slider unit tests, fixed handling of values to autocalculate min/max, fixed upper/lower boundaries on setting the value programmatically
+
+* Synced to Rails 1.0 release candidate, update to Prototype 1.4.0_rc1, removed util.js, merged rests of util.js into effects.js to prepare for refactoring
+
+* Give Builder it's own file
+
+* Fix a logic issue with Autocompleter [thx tshinnic], #2457
+
+*V1.5.0_rc3*
+
+* Make Effect position available to callbacks
+
+* Droppables.fire: send event to onDrop callback [François Beausoleil], #2389
+
+* InPlaceEditor: Add disabling the field while loadTextURL loads and add a class while loading, plus fix various bugs with Internet Explorer and InPlaceEditor, [Jon Tirsen] #2302, #2303
+
+* Made Droppables.remove work again [thx Mindaugas Pelionis], #2409
+
+* Fixed that IE6 would incorrectly render the "fix-windowed-elements-overlapping" IFRAME on autocompletion [thx tshinnic], #2403
+
+* Fixed Element.getOpacity throwing an error on Safari in some situations (this caused the autocompleter not to work)
+
+* Added format option to Sortable.create and Sortable.serialize to allow custom id formats. The format option takes a regular expression where the first grouping that matches is used for building the parameters. The default format is /^[^_]*_(.*)$/ which matches the string_identifier format. If you want to use the full id of the elements, use "format: /(.*)/". More examples are available in the sortable unit test file.
+
+* Started refactorings to use the new Prototype features and general code-cleanup
+
+* Update lib/prototype.js to Prototype 1.4.0_pre11
+
+* Fixed a typo breaking the up arrow key for autocompletion [thx tshinnic], #2406
+
+* Changed the handle option on Draggbles to accept classnames, or ids or elements [thx to Andrew West], #2274
+
+* Force indicator to be hidden on hiding autocompletion update element, #2342
+
+* Make Draggables honor external CSS positioning [thx to Mark Shawkey], #2359
+
+* Make zindex handling for Draggables honor external CSS styles
+
+* Fix two Sortable.serialize issues, [thx Avi, Gorou], #2339, #2357
+
+* Make Element.getOpacity work with IE, added unit tests [thx to Greg Hill]
+
+* Make Element.setOpacity honor non-alpha filters on IE (it now works with filters for alpha PNGs)
+
+* Fixed that Element.class.remove wrongly deleted spaces between class names, fixes #2311, #2313
+
+* Fixed Builder for OPTION and OPTGROUP tags on Firefox < 1.5 and Internet Explorer 6, completely fixes #2325
+
+* Improved Builder implementation to deal with Firefox-specific requirements and innerHTML parsing, partly fixes #2325
+
+*V1.5.0_rc2*
+
+* Update lib/prototype.js to corrected Prototype 1.4.0_pre7 (fixed a problem with IE)
+
+* Update lib/prototype.js to Prototype 1.4.0_pre7
+
+* Reverted to patched version of Prototype 1.4.0_pre4 for the time being (getResponseHeader problem on Mozilla)
+
+* Attempt to fix crashes in Safari 2.0.1, probably related to the event registering und unregistering in Draggables, possibly fixes #2310
+
+* Update lib/prototype.js to Prototype 1.4.0_pre6
+
+* Changed effects_test.html functional test to incoporate Firefox anti-flicker overflow:hidden CSS property
+
+*V1.5.0_rc1*
+
+* Prepared Rakefile and README for V1.5.0_rc1 release
+
+* Droppables w/greedy and hoverclass are now reverted when dragged item is no longer over them, fixes #2184
+
+* Let Effect.Highlight correctly parse IE colors, add String.prototype.parseColor() for this, fixes #2037
+
+* Fix Effect.Highlight to restore background image only if there was one
+
+* Made Effect.tagifyText work again on IE
+
+* Added String.prototype.toArray because Strings aren't iterable on IE
+
+* Fixed Element.getOpacity falsely returning 0 on IE
+
+* Some cleaning up in util.js
+
+* Cleaned up Effect.Opacity
+
+* Removed useless line in Position.page
+
+* Make scriptaculous.js work if a query strings are used when calling it
+
+* Fixed typos in slider.js and the functional test
+
+* Fixed a bug with Safari and the InPlaceEditor with form submission. Add support for interpreting simple <br>s into linebreaks. [Jon Tirsen]
+
+* New Control.Slider() for horizontal and vertical sliders [Marty Haught]
+
+* Fixed autoapplying a 'layout' on IE with Effect.Opacity not working for elements given as id string
+
+* Make Effect.Parallel render final frames and call beforeFinish/afterFinish on included effects
+
+* Make Element.setOpacity work correctly again (browser-specific extensions, except for IE, are disabled at this time)
+
+* Added focusing the text field or text area created when using Ajax.InPlaceEditor #2126 [thx to Lee Mallabone]
+
+* Fixed Element.Class.childrenWith not returning the correct elements #2120 [cmees AT rogers DOT com]
+
+* Added MIT-LICENSE header to scriptaculous.js, cut back on license info in other libs to keep files smaller
+
+* Fix issues with form elements inside draggables not clickable with Firefox #2129
+
+* Fixed an error in dragdrop.js with Draggables when no Droppables are defined
+
+* Fixed an issue with Element.makePositioned causing Effect.SlideDown to fail on Safari
+
+* Make effects "stateless" by cleaning up element.style after finish of effect #2133 [agr30 AT uni-koeln DOT de]
+
+* Add "internal" events to effects, to make them more easily extendable [Martin Bialasinski]
+
+* Set container element height to auto on finishing Effect.BlindDown und Effect.SlideDown #2123 [Tony Arnold]
+
+* Fixed a weird char in dragdrop.js
+
+* Controls.js Autocompleter.Base.updateElement() hook #2116 [Rob Wills]
+
+* Refactoring to use the Prototype enumerable extensions
+
+* Update to Prototype 1.4.0_pre4
+
+*V1.5.0_pre4*
+
+* Added a queue option to effects for easy stacking and simple timeline building. Valid values are "front", "end" and "parallel" (default), see for test/functional/effects_queue_test.html for usage
+
+* Added a setup function to the core effects that gets called by Effect.Base when first entering into running state, which allows them to query the current state of an element or other page properties when queuing and/or delays are used
+
+* Added a state instance variable to Effect.Base that indicates whether a effect that uses the queue is idle, running or finished
+
+* Fixed a flicker with Effect.Puff
+
+* General code cleaning to get rid of (legitimate) Mozilla strict javascript warnings
+
+* Changes to assertVisible in unittest.js
+
+* Slight refactoring of Effect.Text, now known as Effect.multiple(), change first parameter to also accept an array of strings or elements, or a NodeList of elements (if a single element or a string is given, defaults to $('element').childNodes)
+
+* Made tagifyText work with IE. defaults to a style of "position: relative; zoom:1;" for the created SPAN wrappers. It also replaces spaces with non-breakable spaces. These sit-ups are required to work around problems with rendering elements with the proprietary IE "layout" and non-quirksmode documents.
+
+* Add a break to scriptaculous.js when the includes are done [thx to Danilo Celic]
+
+* Fixed a problem with the Autocompleter when hitting ESC would select the entry in IE and redisplay the entries box in Safari
+
+* Fixed that the onDrop callback on Droppables didn't receive the dopped element as second parameter
+
+* Make check for correct Prototype version on loading script.aculo.us
+
+* Changed implementation of Builder to an innerHTML-based approach to make it work with IE6 (note: removed special "style" handling for now)
+
+* Changed non-sync Effects to use a common setInterval call for better timing and page update speeds. See the new Effect.Queue object.
+
+* Fixed a problem with setting opacity in Effect.Opacity to very small values
+
+* Changed the implemention of Effect.Base to use setInterval
+
+* Set version number to 1.5_pre4_trunk
+
+* Added experimental Effect.Text function that allows to start delayed text effects, see test/functional/texteffects_test.html.
+
+* Added experimental Effect.tagifyText(element) which wraps an elements text nodes characters in relatively positioned span elements
+
+* Added "delay" option to Effect.Base to start an effect only after a specified delay
+
+* Finetuning unittest.js + even more unit tests
+
+* Added support for Firefox and Konqueror automatic unit testing on Linux [Michael Schuerig]
+
+* Added basic unit test files for Effects, updated unit testing tests
+
+* Fix typo in lib/prototype.js fix in R2069 (whoops)
+
+* Added unit test for Position.clone
+
+* Made the Postition.cumulative override recognize KHTML and AppleWebKit
+
+* Fix the "hide form controls" iframe fix on the Autocompleter on Internet Explorer
+
+*V1.5.0_pre3*
+
+* More positioning fixes, expanded Element.clone [thx to Michael Schuerig]
+
+* Fixed some JavaScript warnings about redeclared vars [Courtenay]
+
+* Fixed a problem with autocompleting update divs not correctly positioned inside positioned elements [thx to Jonathan Feinberg]
+
+* Workaround for a Safari bug on absolutely positioned children of the BODY element
+
+* Added test/run_functional_test.html to more easily find your way around in the functional tests
+
+* Fixed some missing var declarations in effects.js
+
+* Support for automatic unit testing on IE/Win [Jon Tirsen]
+
+* Added loading the text for the Ajax.InPlaceEditor from the server, more CSS support [Richard Livsey, Jon Tirsen]
+
+* Made builder_test.html unit test work with Safari, fixed (one of two) caching issues with javascripttest.rb, added ajax_autocompleter_test.html to Rakefile unittests
+
+* Fixed Element.Class getting false matches on class names like classA-foobar, added unit tests [Martin Bialasinski]
+
+* Added a test to evluate the Fade/Appear effects across browsers and elements (test/functional/effects6_test.html)
+
+* Framework for completely self-running in-browser unit tests on Mac OS X (try "rake unittest") [Jon Tirsen]
+
+* Updates to Ajax.InPlaceEditor (Highlighting, Ajax options, more) [Jon Tirsen]
+
+* Made event registering on Draggables happen per drag for improved performance [thx to Cathy]
+
+* Moved Element.collectTextNodesIgnoreClass to util.js (preparation for refactoring)
+
+* Made sortable onChange option work again
+
+* Fixed a bug with Sortables resulting in wrong result when using Sortable.serialize with onUpdate on ghostly Sortables [thx Richard Livsey, Caleb Buxton]
+
+* Changed version number in scriptaculous.js to 1.5_pre3
+
+* Moved setting focus in Autocompleter to updateElement function to make it overridable [Brian Palmer]
+
+* Added special handling for style attributes to Builder [Michael Schuerig]
+
+* Changed opacity=1.0 check back to be inline with its original (pre 1.5) implementation to prevent flickering in Firefox < 1.1 on opacity-based effects (this also fixes flickering with drag-and-drop, sortable lists and autocompleting text fields). Note that this potentially breaks correct colors in some situations. [thx to David Zülke]
+
+* Automatically deactivate browser built-in autocompletion on autocompleting textfields, fixes part of Rails #1824.
+
+* Fixed a problem with Ajax.InPlaceEditor causing a JavaScript exception on Safari [thx to Patrick Lenz]
+
+*V1.5.0_pre2*
+
+* Fixed a weird character in dragdrop.js, added check to allow empty containers on Sortables (useful with dropOnEmpty option) [thx to Dave Strus]
+
+* Added unit test runner file test/run_unit_tests.html, new unit test files must be listed in test/unit/index.html
+
+* Added unit tests for Prototype string functions
+
+*V1.5.0_pre1*
+
+* Prepared README for V1.5.0_pre1
+
+* Added a main scriptaculous.js file to load in the other libraries transparently:
+
+ <script src="path/to/prototype.js" type="text/javascript"></script>
+ <script src="path/to/scriptaculous.js" type="text/javascript"></script>
+
+ in the HEAD section of an HTML file is now all that's needed to include all of the script.aculo.us libraries,
+ given that they all can be accessed by the same path as scriptaculous.js is.
+
+* Fixed possible problem with greedy Droppables when using the dropOnEmpty option on Sortable.create
+
+* Added new CSS/background color features to Ajax.InPlaceEditor [Jon Tirsen]
+
+* Added unit test for Autocompleter, first Version
+
+* Added Event.simulateKey/s to unittest.js. Note that due to a bug in Firefox this will only work with Firefox up to v1.0.4 (see https://bugzilla.mozilla.org/show_bug.cgi?id=289940)
+
+* Fixed a condition where standard a href=xxx links wouldn't work in autocomplete results. These do now, the onclick event is not cancelled. [thx to Jasper Slits]
+
+* Fix showing ghosting marker only on ghosting Sortables
+
+* Some more Builder stuff, expanded builder unit tests
+
+* Moved stuff that didn't belong into specific libs into util.js; util.js is now required for all script.aculo.us libs
+
+* Corrected weirdness in unittest.js
+
+* Added dropOnEmpty option to Sortables to allow dropping on empty lists (see test/functional/sortable3_test.html)
+
+* Changed algoritm for drag/drop position setting
+
+* Changed workaround for class attributes (fixes a Firefox 1.0 error) from klass to className to be more Javascriptesque [thx to Martin Bialasinski]
+
+* Fixed a typo in ajax_inplaceeditor_test.html
+
+* Updated Rakefile to add unittest.js and util.js to the package
+
+* Added util.js which contains various utlity functions and extensions to Prototype
+
+* Major restructuring
+
+* Added TEXTAREA support to Ajax.InPlaceEditor [Sanford Barr]
+
+* Added Ghost Train alpha 0.1.0. See ghosttrain/test.html.
+
+* More features for Ajax.InPlaceEditor [Jon Tirsen]
+
+* Tweaks to unittest.css [Thomas Fuchs]
+
+* Refactoring and new features in unittest.js [Thomas Fuchs] [Jon Tirsen]
+
+* Fixed a wrong variable reference in Effect.Scale
+
+* Fix Element.makePositioned to recognize the 'static' position
+
+* Allow to choose the parameter name for Ajax.Autocompleter [Cameron Braid]
+
+* Changed resolving indicator DOM element more flexibility [Cameron Braid]
+
+* Fixed a reference in Ajax.InPlaceEditor
+
+* Added contributors to unittest.js
+
+* Souped-up Ajax.InPlaceEditor, added support for a form id and specifying all the texts through options [Jon Tirsen]
+
+* Make unit testing look good [Michael Schuerig]
+
+* Changed default revert duration for Draggables to distance-dependent algorithm [suggested by San]
+
+* Fix double unescaping in Autocompleter
+
+* Refactoring auf Autocompleter classes to use camelCase (note: changes the syntax of some of the options)
+
+* Add updateElement option to Autocompleter [Rob Sharp]
+
+* Updated Ajax.InPlaceEditor, refactoring of unit testing [Jon Tirsen]
+
+* Added preliminary version of Ajax.InPlaceEditor to controls.js; added experimental Firefox only functional testing for it (inplaceeditor_result.html) [Jon Tirsen]
+
+* Added some addtional test files.
+
+* Fixes a bug with Droppables not recognizing a drop if no hoverclass is given [thanks drewie]
+
+* Fixes to ghosting marker, allow a predefined marker (element with id "dropmarker").
+
+* Changed Effect.Opacity to better handle 100% opacity
+
+* Various fixes to ghosting, improves compatiblity with Safari and IE. [thanks to David Zülke]
+
+* Added experimental ghosting option to Sortables. See sortable_functional_ghosting.html for usage.
+
+* Renamed the clone option on Draggables to "ghosting".
+
+* Added experimental "clone" option to Draggable to so that a "clone" stays in place while dragging a translucent version of the draggable element. Currently, this requires relatively positioned elements, and doesn't work with sortable lists (but should after some tweaking). See dragdrop_function_4.html test file for details.
+
+* Added Element.getStyle to find computed CSS styles of an element. Note: doesn't work in all cases in Safari, see my bug report at http://bugzilla.opendarwin.org/show_bug.cgi?id=4125
+
+*1.1beta1*
+
+* Fixed rendering of last frame of animation when from/to is not 0.0/1.0. [thanks to David Zülke]
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2 (patched w/ workaround for Ajax.Updater init bug)
+
+* Some refactoring of controls.js to get rid of "dirty" implementation detail (dont' ask)
+
+* Added returning the generated combined effects to allow for .cancel() on all effects
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2
+
+*Rails 0.13.1*
+
+* Updated Ajax.Autocompleter to deal with parameters options correctly [Martin Marinschek]
+
+* Updated controls.js to allow multple matches in local localcompletion [Ivan Krstic]
+
+* Make version of prototype.js in lib have a nicer Event object [David Zülke]
+
+* Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
+
+* Experimental: make version of prototype.js in lib destroy events on page unload to prevent browser memory leaks
+
+* Fixed a possible memory leak in dragdrop.js
+
+* Make version of prototype.js in lib compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() for testing [David Zülke]
+
+* Make effects.js, dragdrop.js and controls.js compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() [David Zülke]
+
+* Changed some tests to work better
+
+* Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
+
+* Removed a possible memory leaks with IE with sortables and droppables (removed references from elements)
+
+* Changes to class extension in effects.js
+
+* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with set CSS classes)
+
+* Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js
+
+* Added Effect.ScrollTo to smoothly scroll the page to an element
+
+* Better Firefox flickering handling on SlideUp/SlideDown
+
+* Some cleaning up in effects.js
+
+* Removed a possible memory leak in IE with draggables
+
+* Added support for cancelling dragging my hitting ESC
+
+* Changed logic of drag-and-drop to only include the last referenced droppable when firing a drop event. This change also offers slight performance gains. [Dominik Wagner]
+
+* Added addtional effects test page, added tests for scriptfragment matching
+
+*1.0.0*
+
+* Changed auto-hiding update div in Ajax.Autocompleter
+
+* Changed default serialization on Ajax.Autocompleter to use Form.Element.serialize
+
+* Added test file for drag/drop inside scrolled elements
+
+* Fixed dragging of unpositioned elements in Internet Explorer
+
+* Change default behaviour of Ajax.Autocompleter to do automatic overlapping, sizing and appear/fade effects
+
+* Fixed Internet Explorer hide-windowed-controls iframe handling
+
+* Changed Ajax.Autocompleter event handling
+
+* Added onShow/onHide callbacks to Ajax.Autocompleter to allow for customized handling/effects
+
+* Fixed SlideUp/SlideDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed BlindUp/BlindDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed draggables with revert:false on repeated drags behaving badly
+
+* Expanded the revert option on draggables to optionally take a function and revert only if it returns true
+
+* Added the dragged element as a parameter to the Draggables.notify callbacks [Michael Sokolov]
+
+* Removed a deprecated reference to Effect2 om Effect.Fold
+
+* Make the percentage on Element.setContentZoom absolute
+
+* Corrected rendering of Ajax.AutoCompleter when focus is lost while updating
+
+* Added (crude) functional tests
+
+* Some slight refactoring in controls.js
+
+* Changed dragdrop.js to use the Effect namespace for its effects
+
+* Updated to Prototype 1.3.0: removal of prototype-ext.js; refactoring.
+
+* Fixed behaviour of cursor keys in Safari on autocomplete script
+
+* Fixed Position.within_including_scrolloffsets
+
+* Fixed sortables that are absolutely positioned
+
+* Fixed unhandled whitespace in Ajax.Autocompleter
+
+* Updated prototype-ext.js to include additions for Ajax.Autocompleter
+
+* Added controls.js, contains AJAX autocompleting text fields from #960
+
+* Refactored Event object
+
+* Renamed effects2.js to effects.js
+
+* Fixed draggables on pages with no droppables
+
+* Moved Event, Position and Element.Class to prototype-ext.js in preparation to Rails 0.13
+
+* Added Effect.Transitions.pulse
+
+* Added Effect.Pulsate and Effect.Fold effect by Justin Palmer
+
+* Added transitions by Mark Pilgrim: .full, .none
+
+* Added effects by Mark Pilgrim: Effect.Grow, Effect.Shrink
+
+* Changed effects namespace to Effect. (Effect2 is deprecated, but works too)
+
+* Changed old Effect.ContentZoom class to Element.setContentZoom() function
+
+* Greatly expanded Effect.Highlight to have user-defined colors and autodetecting the background color
+
+* Converted remaining effects (Squish, Highlight) to new format
+
+* Sortable.create now passes the zindex, starteffect, reverteffect and endeffect options to the underlying Draggables
+
+* Sortable.serialize now honors the only option on Sortable.create
+
+* New overridable options on Draggables: zindex, starteffect, reverteffect, endeffect
+
+* Fix a Gecko engine flicker on Sortables in dragdrop.js
+
+* Fixed event.isLeftClick
+
+* Some small changes in effects2.js
+
+* Refactoring of dragdrop.js
+
+* Added an Object.prototype.inspect() and more verbose messages for js unit testing
+
+* Added test/unittest.js and initial tests in test/html.
+
+* Cleaning up of effects2.js (convert tabs to spaces)
+
+* Added Rakefile for distribution packaging (default task = make distribution, rake clean for cleaning up)
+
+* Initial check-in and directory layout for the script.aculo.us JavaScripts
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/MIT-LICENSE b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/MIT-LICENSE
new file mode 100644
index 000000000..6d1340dbc
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/README.rdoc b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/README.rdoc
new file mode 100644
index 000000000..21f8c8cf6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/README.rdoc
@@ -0,0 +1,59 @@
+== script.aculo.us web 2.0 javascript
+
+The Web is changing. The 30-year-old terminal-like technology it was originally
+is gradually giving way to new ways of doing things. The power of AJAX allows
+for rich user interaction without the trouble that has bugged traditional
+web applications.
+
+Building upon the wonderful Prototype JavaScript library, script.aculo.us
+provides you with some great additional ingredients to mix in.
+
+For more information, see http://script.aculo.us/
+
+== What's new in this release?
+
+See the CHANGELOG file for information on what's new.
+
+You can follow http://twitter.com/scriptaculous if you want
+to be updated as we fix bugs and add new features.
+
+== Installation/Usage
+
+script.aculo.us includes the Prototype JavaScript Framework
+V1.6.0. You can use later versions, as they become available
+(see http://prototypejs.org/).
+
+Put prototype.js, and the six files scriptaculous.js,
+builder.js, effects.js, dragdrop.js, controls.js and slider.js
+in a directory of your website, e.g. /javascripts.
+
+(The sound.js and unittest.js files are optional)
+
+Now, you can include the scripts by adding the following
+tags to the HEAD section of your HTML pages:
+
+ <script src="/javascripts/prototype.js" type="text/javascript"></script>
+ <script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
+
+scriptaculous.js will automatically load the other files of the
+script.aculo.us distribution in, provided they are accessible
+via the same path.
+
+See http://wiki.script.aculo.us/scriptaculous/show/Usage for detailed
+usage instructions.
+
+== The distribution
+
+Besides the script.aculo.us files in src, there's a complete
+test tree included which holds functional and unit tests for
+script.aculo.us.
+
+If you need examples on how to implement things, the best place to
+start is by opening test/run_functional_tests.html or
+test/run_unit_tests.html in your browser, and looking at
+the sources of the examples provided.
+
+== License
+
+script.aculo.us is licensed under the terms of the MIT License,
+see the included MIT-LICENSE file. \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/lib/prototype.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/lib/prototype.js
new file mode 100644
index 000000000..845ab7fb4
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/lib/prototype.js
@@ -0,0 +1,4874 @@
+/* Prototype JavaScript framework, version 1.6.1
+ * (c) 2005-2009 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.6.1',
+
+ Browser: (function(){
+ var ua = navigator.userAgent;
+ var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
+ return {
+ IE: !!window.attachEvent && !isOpera,
+ Opera: isOpera,
+ WebKit: ua.indexOf('AppleWebKit/') > -1,
+ Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
+ MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
+ }
+ })(),
+
+ BrowserFeatures: {
+ XPath: !!document.evaluate,
+ SelectorsAPI: !!document.querySelector,
+ ElementExtensions: (function() {
+ var constructor = window.Element || window.HTMLElement;
+ return !!(constructor && constructor.prototype);
+ })(),
+ SpecificElementExtensions: (function() {
+ if (typeof window.HTMLDivElement !== 'undefined')
+ return true;
+
+ var div = document.createElement('div');
+ var form = document.createElement('form');
+ var isSupported = false;
+
+ if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
+ isSupported = true;
+ }
+
+ div = form = null;
+
+ return isSupported;
+ })()
+ },
+
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+ emptyFunction: function() { },
+ K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+var Abstract = { };
+
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) { }
+ }
+
+ return returnValue;
+ }
+};
+
+/* Based on Alex Arnell's inheritance implementation. */
+
+var Class = (function() {
+ function subclass() {};
+ function create() {
+ var parent = null, properties = $A(arguments);
+ if (Object.isFunction(properties[0]))
+ parent = properties.shift();
+
+ function klass() {
+ this.initialize.apply(this, arguments);
+ }
+
+ Object.extend(klass, Class.Methods);
+ klass.superclass = parent;
+ klass.subclasses = [];
+
+ if (parent) {
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0; i < properties.length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = Prototype.emptyFunction;
+
+ klass.prototype.constructor = klass;
+ return klass;
+ }
+
+ function addMethods(source) {
+ var ancestor = this.superclass && this.superclass.prototype;
+ var properties = Object.keys(source);
+
+ if (!Object.keys({ toString: true }).length) {
+ if (source.toString != Object.prototype.toString)
+ properties.push("toString");
+ if (source.valueOf != Object.prototype.valueOf)
+ properties.push("valueOf");
+ }
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && Object.isFunction(value) &&
+ value.argumentNames().first() == "$super") {
+ var method = value;
+ value = (function(m) {
+ return function() { return ancestor[m].apply(this, arguments); };
+ })(property).wrap(method);
+
+ value.valueOf = method.valueOf.bind(method);
+ value.toString = method.toString.bind(method);
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ }
+
+ return {
+ create: create,
+ Methods: {
+ addMethods: addMethods
+ }
+ };
+})();
+(function() {
+
+ var _toString = Object.prototype.toString;
+
+ function extend(destination, source) {
+ for (var property in source)
+ destination[property] = source[property];
+ return destination;
+ }
+
+ function inspect(object) {
+ try {
+ if (isUndefined(object)) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : String(object);
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ }
+
+ function toJSON(object) {
+ var type = typeof object;
+ switch (type) {
+ case 'undefined':
+ case 'function':
+ case 'unknown': return;
+ case 'boolean': return object.toString();
+ }
+
+ if (object === null) return 'null';
+ if (object.toJSON) return object.toJSON();
+ if (isElement(object)) return;
+
+ var results = [];
+ for (var property in object) {
+ var value = toJSON(object[property]);
+ if (!isUndefined(value))
+ results.push(property.toJSON() + ': ' + value);
+ }
+
+ return '{' + results.join(', ') + '}';
+ }
+
+ function toQueryString(object) {
+ return $H(object).toQueryString();
+ }
+
+ function toHTML(object) {
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
+ }
+
+ function keys(object) {
+ var results = [];
+ for (var property in object)
+ results.push(property);
+ return results;
+ }
+
+ function values(object) {
+ var results = [];
+ for (var property in object)
+ results.push(object[property]);
+ return results;
+ }
+
+ function clone(object) {
+ return extend({ }, object);
+ }
+
+ function isElement(object) {
+ return !!(object && object.nodeType == 1);
+ }
+
+ function isArray(object) {
+ return _toString.call(object) == "[object Array]";
+ }
+
+
+ function isHash(object) {
+ return object instanceof Hash;
+ }
+
+ function isFunction(object) {
+ return typeof object === "function";
+ }
+
+ function isString(object) {
+ return _toString.call(object) == "[object String]";
+ }
+
+ function isNumber(object) {
+ return _toString.call(object) == "[object Number]";
+ }
+
+ function isUndefined(object) {
+ return typeof object === "undefined";
+ }
+
+ extend(Object, {
+ extend: extend,
+ inspect: inspect,
+ toJSON: toJSON,
+ toQueryString: toQueryString,
+ toHTML: toHTML,
+ keys: keys,
+ values: values,
+ clone: clone,
+ isElement: isElement,
+ isArray: isArray,
+ isHash: isHash,
+ isFunction: isFunction,
+ isString: isString,
+ isNumber: isNumber,
+ isUndefined: isUndefined
+ });
+})();
+Object.extend(Function.prototype, (function() {
+ var slice = Array.prototype.slice;
+
+ function update(array, args) {
+ var arrayLength = array.length, length = args.length;
+ while (length--) array[arrayLength + length] = args[length];
+ return array;
+ }
+
+ function merge(array, args) {
+ array = slice.call(array, 0);
+ return update(array, args);
+ }
+
+ function argumentNames() {
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
+ .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
+ .replace(/\s+/g, '').split(',');
+ return names.length == 1 && !names[0] ? [] : names;
+ }
+
+ function bind(context) {
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+ var __method = this, args = slice.call(arguments, 1);
+ return function() {
+ var a = merge(args, arguments);
+ return __method.apply(context, a);
+ }
+ }
+
+ function bindAsEventListener(context) {
+ var __method = this, args = slice.call(arguments, 1);
+ return function(event) {
+ var a = update([event || window.event], args);
+ return __method.apply(context, a);
+ }
+ }
+
+ function curry() {
+ if (!arguments.length) return this;
+ var __method = this, args = slice.call(arguments, 0);
+ return function() {
+ var a = merge(args, arguments);
+ return __method.apply(this, a);
+ }
+ }
+
+ function delay(timeout) {
+ var __method = this, args = slice.call(arguments, 1);
+ timeout = timeout * 1000
+ return window.setTimeout(function() {
+ return __method.apply(__method, args);
+ }, timeout);
+ }
+
+ function defer() {
+ var args = update([0.01], arguments);
+ return this.delay.apply(this, args);
+ }
+
+ function wrap(wrapper) {
+ var __method = this;
+ return function() {
+ var a = update([__method.bind(this)], arguments);
+ return wrapper.apply(this, a);
+ }
+ }
+
+ function methodize() {
+ if (this._methodized) return this._methodized;
+ var __method = this;
+ return this._methodized = function() {
+ var a = update([this], arguments);
+ return __method.apply(null, a);
+ };
+ }
+
+ return {
+ argumentNames: argumentNames,
+ bind: bind,
+ bindAsEventListener: bindAsEventListener,
+ curry: curry,
+ delay: delay,
+ defer: defer,
+ wrap: wrap,
+ methodize: methodize
+ }
+})());
+
+
+Date.prototype.toJSON = function() {
+ return '"' + this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z"';
+};
+
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+var PeriodicalExecuter = Class.create({
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ execute: function() {
+ this.callback(this);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.execute();
+ this.currentlyExecuting = false;
+ } catch(e) {
+ this.currentlyExecuting = false;
+ throw e;
+ }
+ }
+ }
+});
+Object.extend(String, {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ },
+ specialChar: {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '\\': '\\\\'
+ }
+});
+
+Object.extend(String.prototype, (function() {
+
+ function prepareReplacement(replacement) {
+ if (Object.isFunction(replacement)) return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+ }
+
+ function gsub(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = prepareReplacement(replacement);
+
+ if (Object.isString(pattern))
+ pattern = RegExp.escape(pattern);
+
+ if (!(pattern.length || pattern.source)) {
+ replacement = replacement('');
+ return replacement + source.split('').join(replacement) + replacement;
+ }
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ }
+
+ function sub(pattern, replacement, count) {
+ replacement = prepareReplacement(replacement);
+ count = Object.isUndefined(count) ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ }
+
+ function scan(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return String(this);
+ }
+
+ function truncate(length, truncation) {
+ length = length || 30;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : String(this);
+ }
+
+ function strip() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ }
+
+ function stripTags() {
+ return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
+ }
+
+ function stripScripts() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ }
+
+ function extractScripts() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ }
+
+ function evalScripts() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ }
+
+ function escapeHTML() {
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+ }
+
+ function unescapeHTML() {
+ return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
+ }
+
+
+ function toQueryParams(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var key = decodeURIComponent(pair.shift());
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ return hash;
+ });
+ }
+
+ function toArray() {
+ return this.split('');
+ }
+
+ function succ() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ }
+
+ function times(count) {
+ return count < 1 ? '' : new Array(count + 1).join(this);
+ }
+
+ function camelize() {
+ var parts = this.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+
+ var camelized = this.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++)
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+ return camelized;
+ }
+
+ function capitalize() {
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ }
+
+ function underscore() {
+ return this.replace(/::/g, '/')
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2')
+ .replace(/-/g, '_')
+ .toLowerCase();
+ }
+
+ function dasherize() {
+ return this.replace(/_/g, '-');
+ }
+
+ function inspect(useDoubleQuotes) {
+ var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
+ if (character in String.specialChar) {
+ return String.specialChar[character];
+ }
+ return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+
+ function toJSON() {
+ return this.inspect(true);
+ }
+
+ function unfilterJSON(filter) {
+ return this.replace(filter || Prototype.JSONFilter, '$1');
+ }
+
+ function isJSON() {
+ var str = this;
+ if (str.blank()) return false;
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+ }
+
+ function evalJSON(sanitize) {
+ var json = this.unfilterJSON();
+ try {
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+ } catch (e) { }
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+ }
+
+ function include(pattern) {
+ return this.indexOf(pattern) > -1;
+ }
+
+ function startsWith(pattern) {
+ return this.indexOf(pattern) === 0;
+ }
+
+ function endsWith(pattern) {
+ var d = this.length - pattern.length;
+ return d >= 0 && this.lastIndexOf(pattern) === d;
+ }
+
+ function empty() {
+ return this == '';
+ }
+
+ function blank() {
+ return /^\s*$/.test(this);
+ }
+
+ function interpolate(object, pattern) {
+ return new Template(this, pattern).evaluate(object);
+ }
+
+ return {
+ gsub: gsub,
+ sub: sub,
+ scan: scan,
+ truncate: truncate,
+ strip: String.prototype.trim ? String.prototype.trim : strip,
+ stripTags: stripTags,
+ stripScripts: stripScripts,
+ extractScripts: extractScripts,
+ evalScripts: evalScripts,
+ escapeHTML: escapeHTML,
+ unescapeHTML: unescapeHTML,
+ toQueryParams: toQueryParams,
+ parseQuery: toQueryParams,
+ toArray: toArray,
+ succ: succ,
+ times: times,
+ camelize: camelize,
+ capitalize: capitalize,
+ underscore: underscore,
+ dasherize: dasherize,
+ inspect: inspect,
+ toJSON: toJSON,
+ unfilterJSON: unfilterJSON,
+ isJSON: isJSON,
+ evalJSON: evalJSON,
+ include: include,
+ startsWith: startsWith,
+ endsWith: endsWith,
+ empty: empty,
+ blank: blank,
+ interpolate: interpolate
+ };
+})());
+
+var Template = Class.create({
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ if (object && Object.isFunction(object.toTemplateReplacements))
+ object = object.toTemplateReplacements();
+
+ return this.template.gsub(this.pattern, function(match) {
+ if (object == null) return (match[1] + '');
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3];
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + String.interpret(ctx);
+ });
+ }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = (function() {
+ function each(iterator, context) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ iterator.call(context, value, index++);
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ }
+
+ function eachSlice(number, iterator, context) {
+ var index = -number, slices = [], array = this.toArray();
+ if (number < 1) return array;
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.collect(iterator, context);
+ }
+
+ function all(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!iterator.call(context, value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ }
+
+ function any(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!iterator.call(context, value, index))
+ throw $break;
+ });
+ return result;
+ }
+
+ function collect(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator.call(context, value, index));
+ });
+ return results;
+ }
+
+ function detect(iterator, context) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ }
+
+ function findAll(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index))
+ results.push(value);
+ });
+ return results;
+ }
+
+ function grep(filter, iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+
+ if (Object.isString(filter))
+ filter = new RegExp(RegExp.escape(filter));
+
+ this.each(function(value, index) {
+ if (filter.match(value))
+ results.push(iterator.call(context, value, index));
+ });
+ return results;
+ }
+
+ function include(object) {
+ if (Object.isFunction(this.indexOf))
+ if (this.indexOf(object) != -1) return true;
+
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ }
+
+ function inGroupsOf(number, fillWith) {
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ }
+
+ function inject(memo, iterator, context) {
+ this.each(function(value, index) {
+ memo = iterator.call(context, memo, value, index);
+ });
+ return memo;
+ }
+
+ function invoke(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ }
+
+ function max(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index);
+ if (result == null || value >= result)
+ result = value;
+ });
+ return result;
+ }
+
+ function min(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index);
+ if (result == null || value < result)
+ result = value;
+ });
+ return result;
+ }
+
+ function partition(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ (iterator.call(context, value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ }
+
+ function pluck(property) {
+ var results = [];
+ this.each(function(value) {
+ results.push(value[property]);
+ });
+ return results;
+ }
+
+ function reject(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator.call(context, value, index))
+ results.push(value);
+ });
+ return results;
+ }
+
+ function sortBy(iterator, context) {
+ return this.map(function(value, index) {
+ return {
+ value: value,
+ criteria: iterator.call(context, value, index)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ }
+
+ function toArray() {
+ return this.map();
+ }
+
+ function zip() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (Object.isFunction(args.last()))
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ }
+
+ function size() {
+ return this.toArray().length;
+ }
+
+ function inspect() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+
+
+
+
+
+
+
+
+
+ return {
+ each: each,
+ eachSlice: eachSlice,
+ all: all,
+ every: all,
+ any: any,
+ some: any,
+ collect: collect,
+ map: collect,
+ detect: detect,
+ findAll: findAll,
+ select: findAll,
+ filter: findAll,
+ grep: grep,
+ include: include,
+ member: include,
+ inGroupsOf: inGroupsOf,
+ inject: inject,
+ invoke: invoke,
+ max: max,
+ min: min,
+ partition: partition,
+ pluck: pluck,
+ reject: reject,
+ sortBy: sortBy,
+ toArray: toArray,
+ entries: toArray,
+ zip: zip,
+ size: size,
+ inspect: inspect,
+ find: detect
+ };
+})();
+function $A(iterable) {
+ if (!iterable) return [];
+ if ('toArray' in Object(iterable)) return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+}
+
+function $w(string) {
+ if (!Object.isString(string)) return [];
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+Array.from = $A;
+
+
+(function() {
+ var arrayProto = Array.prototype,
+ slice = arrayProto.slice,
+ _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
+
+ function each(iterator) {
+ for (var i = 0, length = this.length; i < length; i++)
+ iterator(this[i]);
+ }
+ if (!_each) _each = each;
+
+ function clear() {
+ this.length = 0;
+ return this;
+ }
+
+ function first() {
+ return this[0];
+ }
+
+ function last() {
+ return this[this.length - 1];
+ }
+
+ function compact() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ }
+
+ function flatten() {
+ return this.inject([], function(array, value) {
+ if (Object.isArray(value))
+ return array.concat(value.flatten());
+ array.push(value);
+ return array;
+ });
+ }
+
+ function without() {
+ var values = slice.call(arguments, 0);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ }
+
+ function reverse(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ }
+
+ function uniq(sorted) {
+ return this.inject([], function(array, value, index) {
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+ array.push(value);
+ return array;
+ });
+ }
+
+ function intersect(array) {
+ return this.uniq().findAll(function(item) {
+ return array.detect(function(value) { return item === value });
+ });
+ }
+
+
+ function clone() {
+ return slice.call(this, 0);
+ }
+
+ function size() {
+ return this.length;
+ }
+
+ function inspect() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+
+ function toJSON() {
+ var results = [];
+ this.each(function(object) {
+ var value = Object.toJSON(object);
+ if (!Object.isUndefined(value)) results.push(value);
+ });
+ return '[' + results.join(', ') + ']';
+ }
+
+ function indexOf(item, i) {
+ i || (i = 0);
+ var length = this.length;
+ if (i < 0) i = length + i;
+ for (; i < length; i++)
+ if (this[i] === item) return i;
+ return -1;
+ }
+
+ function lastIndexOf(item, i) {
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+ var n = this.slice(0, i).reverse().indexOf(item);
+ return (n < 0) ? n : i - n - 1;
+ }
+
+ function concat() {
+ var array = slice.call(this, 0), item;
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ item = arguments[i];
+ if (Object.isArray(item) && !('callee' in item)) {
+ for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
+ array.push(item[j]);
+ } else {
+ array.push(item);
+ }
+ }
+ return array;
+ }
+
+ Object.extend(arrayProto, Enumerable);
+
+ if (!arrayProto._reverse)
+ arrayProto._reverse = arrayProto.reverse;
+
+ Object.extend(arrayProto, {
+ _each: _each,
+ clear: clear,
+ first: first,
+ last: last,
+ compact: compact,
+ flatten: flatten,
+ without: without,
+ reverse: reverse,
+ uniq: uniq,
+ intersect: intersect,
+ clone: clone,
+ toArray: clone,
+ size: size,
+ inspect: inspect,
+ toJSON: toJSON
+ });
+
+ var CONCAT_ARGUMENTS_BUGGY = (function() {
+ return [].concat(arguments)[0][0] !== 1;
+ })(1,2)
+
+ if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
+
+ if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
+ if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
+})();
+function $H(object) {
+ return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+ function initialize(object) {
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+ }
+
+ function _each(iterator) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ }
+
+ function set(key, value) {
+ return this._object[key] = value;
+ }
+
+ function get(key) {
+ if (this._object[key] !== Object.prototype[key])
+ return this._object[key];
+ }
+
+ function unset(key) {
+ var value = this._object[key];
+ delete this._object[key];
+ return value;
+ }
+
+ function toObject() {
+ return Object.clone(this._object);
+ }
+
+ function keys() {
+ return this.pluck('key');
+ }
+
+ function values() {
+ return this.pluck('value');
+ }
+
+ function index(value) {
+ var match = this.detect(function(pair) {
+ return pair.value === value;
+ });
+ return match && match.key;
+ }
+
+ function merge(object) {
+ return this.clone().update(object);
+ }
+
+ function update(object) {
+ return new Hash(object).inject(this, function(result, pair) {
+ result.set(pair.key, pair.value);
+ return result;
+ });
+ }
+
+ function toQueryPair(key, value) {
+ if (Object.isUndefined(value)) return key;
+ return key + '=' + encodeURIComponent(String.interpret(value));
+ }
+
+ function toQueryString() {
+ return this.inject([], function(results, pair) {
+ var key = encodeURIComponent(pair.key), values = pair.value;
+
+ if (values && typeof values == 'object') {
+ if (Object.isArray(values))
+ return results.concat(values.map(toQueryPair.curry(key)));
+ } else results.push(toQueryPair(key, values));
+ return results;
+ }).join('&');
+ }
+
+ function inspect() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+
+ function toJSON() {
+ return Object.toJSON(this.toObject());
+ }
+
+ function clone() {
+ return new Hash(this);
+ }
+
+ return {
+ initialize: initialize,
+ _each: _each,
+ set: set,
+ get: get,
+ unset: unset,
+ toObject: toObject,
+ toTemplateReplacements: toObject,
+ keys: keys,
+ values: values,
+ index: index,
+ merge: merge,
+ update: update,
+ toQueryString: toQueryString,
+ inspect: inspect,
+ toJSON: toJSON,
+ clone: clone
+ };
+})());
+
+Hash.from = $H;
+Object.extend(Number.prototype, (function() {
+ function toColorPart() {
+ return this.toPaddedString(2, 16);
+ }
+
+ function succ() {
+ return this + 1;
+ }
+
+ function times(iterator, context) {
+ $R(0, this, true).each(iterator, context);
+ return this;
+ }
+
+ function toPaddedString(length, radix) {
+ var string = this.toString(radix || 10);
+ return '0'.times(length - string.length) + string;
+ }
+
+ function toJSON() {
+ return isFinite(this) ? this.toString() : 'null';
+ }
+
+ function abs() {
+ return Math.abs(this);
+ }
+
+ function round() {
+ return Math.round(this);
+ }
+
+ function ceil() {
+ return Math.ceil(this);
+ }
+
+ function floor() {
+ return Math.floor(this);
+ }
+
+ return {
+ toColorPart: toColorPart,
+ succ: succ,
+ times: times,
+ toPaddedString: toPaddedString,
+ toJSON: toJSON,
+ abs: abs,
+ round: round,
+ ceil: ceil,
+ floor: floor
+ };
+})());
+
+function $R(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var ObjectRange = Class.create(Enumerable, (function() {
+ function initialize(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ }
+
+ function _each(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ }
+
+ function include(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+
+ return {
+ initialize: initialize,
+ _each: _each,
+ include: include
+ };
+})());
+
+
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+};
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (Object.isFunction(responder[callback])) {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) { }
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() { Ajax.activeRequestCount++ },
+ onComplete: function() { Ajax.activeRequestCount-- }
+});
+Ajax.Base = Class.create({
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: '',
+ evalJSON: true,
+ evalJS: true
+ };
+ Object.extend(this.options, options || { });
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (Object.isString(this.options.parameters))
+ this.options.parameters = this.options.parameters.toQueryParams();
+ else if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
+ }
+});
+Ajax.Request = Class.create(Ajax.Base, {
+ _complete: false,
+
+ initialize: function($super, url, options) {
+ $super(options);
+ this.transport = Ajax.getTransport();
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = Object.clone(this.options.parameters);
+
+ if (!['get', 'post'].include(this.method)) {
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = Object.toQueryString(params)) {
+ if (this.method == 'get')
+ this.url += (this.url.include('?') ? '&' : '?') + params;
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ params += '&_=';
+ }
+
+ try {
+ var response = new Ajax.Response(this);
+ if (this.options.onCreate) this.options.onCreate(response);
+ Ajax.Responders.dispatch('onCreate', this, response);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (Object.isFunction(extras.push))
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >= 200 && status < 300);
+ },
+
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) { return 0 }
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ if (this.options.evalJS == 'force'
+ || (this.options.evalJS && this.isSameOrigin() && contentType
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name) || null;
+ } catch (e) { return null; }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval((this.transport.responseText || '').unfilterJSON());
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+
+
+
+
+
+
+
+Ajax.Response = Class.create({
+ initialize: function(request){
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = String.interpret(transport.responseText);
+ this.headerJSON = this._getHeaderJSON();
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
+ this.responseJSON = this._getResponseJSON();
+ }
+ },
+
+ status: 0,
+
+ statusText: '',
+
+ getStatus: Ajax.Request.prototype.getStatus,
+
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) { return '' }
+ },
+
+ getHeader: Ajax.Request.prototype.getHeader,
+
+ getAllHeaders: function() {
+ try {
+ return this.getAllResponseHeaders();
+ } catch (e) { return null }
+ },
+
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ },
+
+ getAllResponseHeaders: function() {
+ return this.transport.getAllResponseHeaders();
+ },
+
+ _getHeaderJSON: function() {
+ var json = this.getHeader('X-JSON');
+ if (!json) return null;
+ json = decodeURIComponent(escape(json));
+ try {
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ },
+
+ _getResponseJSON: function() {
+ var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
+ try {
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+ initialize: function($super, container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ };
+
+ options = Object.clone(options);
+ var onComplete = options.onComplete;
+ options.onComplete = (function(response, json) {
+ this.updateContent(response.responseText);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
+ }).bind(this);
+
+ $super(url, options);
+ },
+
+ updateContent: function(responseText) {
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
+ options = this.options;
+
+ if (!options.evalScripts) responseText = responseText.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (options.insertion) {
+ if (Object.isString(options.insertion)) {
+ var insertion = { }; insertion[options.insertion] = responseText;
+ receiver.insert(insertion);
+ }
+ else options.insertion(receiver, responseText);
+ }
+ else receiver.update(responseText);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+ initialize: function($super, container, url, options) {
+ $super(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = { };
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(response) {
+ if (this.options.decay) {
+ this.decay = (response.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = response.responseText;
+ }
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+
+
+
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+ if (Object.isString(element))
+ element = document.getElementById(element);
+ return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+ document._getElementsByXPath = function(expression, parentElement) {
+ var results = [];
+ var query = document.evaluate(expression, $(parentElement) || document,
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
+ results.push(Element.extend(query.snapshotItem(i)));
+ return results;
+ };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+ Object.extend(Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+}
+
+
+(function(global) {
+
+ var SETATTRIBUTE_IGNORES_NAME = (function(){
+ var elForm = document.createElement("form");
+ var elInput = document.createElement("input");
+ var root = document.documentElement;
+ elInput.setAttribute("name", "test");
+ elForm.appendChild(elInput);
+ root.appendChild(elForm);
+ var isBuggy = elForm.elements
+ ? (typeof elForm.elements.test == "undefined")
+ : null;
+ root.removeChild(elForm);
+ elForm = elInput = null;
+ return isBuggy;
+ })();
+
+ var element = global.Element;
+ global.Element = function(tagName, attributes) {
+ attributes = attributes || { };
+ tagName = tagName.toLowerCase();
+ var cache = Element.cache;
+ if (SETATTRIBUTE_IGNORES_NAME && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ return Element.writeAttribute(document.createElement(tagName), attributes);
+ }
+ if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+ return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+ };
+ Object.extend(global.Element, element || { });
+ if (element) global.Element.prototype = element.prototype;
+})(this);
+
+Element.cache = { };
+Element.idCounter = 1;
+
+Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function(element) {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+
+ hide: function(element) {
+ element = $(element);
+ element.style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ element = $(element);
+ element.style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: (function(){
+
+ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
+ var el = document.createElement("select"),
+ isBuggy = true;
+ el.innerHTML = "<option value=\"test\">test</option>";
+ if (el.options && el.options[0]) {
+ isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
+ }
+ el = null;
+ return isBuggy;
+ })();
+
+ var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
+ try {
+ var el = document.createElement("table");
+ if (el && el.tBodies) {
+ el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
+ var isBuggy = typeof el.tBodies[0] == "undefined";
+ el = null;
+ return isBuggy;
+ }
+ } catch (e) {
+ return true;
+ }
+ })();
+
+ var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
+ var s = document.createElement("script"),
+ isBuggy = false;
+ try {
+ s.appendChild(document.createTextNode(""));
+ isBuggy = !s.firstChild ||
+ s.firstChild && s.firstChild.nodeType !== 3;
+ } catch (e) {
+ isBuggy = true;
+ }
+ s = null;
+ return isBuggy;
+ })();
+
+ function update(element, content) {
+ element = $(element);
+
+ if (content && content.toElement)
+ content = content.toElement();
+
+ if (Object.isElement(content))
+ return element.update().insert(content);
+
+ content = Object.toHTML(content);
+
+ var tagName = element.tagName.toUpperCase();
+
+ if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
+ element.text = content;
+ return element;
+ }
+
+ if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) {
+ if (tagName in Element._insertionTranslations.tags) {
+ while (element.firstChild) {
+ element.removeChild(element.firstChild);
+ }
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+ .each(function(node) {
+ element.appendChild(node)
+ });
+ }
+ else {
+ element.innerHTML = content.stripScripts();
+ }
+ }
+ else {
+ element.innerHTML = content.stripScripts();
+ }
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ }
+
+ return update;
+ })(),
+
+ replace: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ else if (!Object.isElement(content)) {
+ content = Object.toHTML(content);
+ var range = element.ownerDocument.createRange();
+ range.selectNode(element);
+ content.evalScripts.bind(content).defer();
+ content = range.createContextualFragment(content.stripScripts());
+ }
+ element.parentNode.replaceChild(content, element);
+ return element;
+ },
+
+ insert: function(element, insertions) {
+ element = $(element);
+
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+ insertions = {bottom:insertions};
+
+ var content, insert, tagName, childNodes;
+
+ for (var position in insertions) {
+ content = insertions[position];
+ position = position.toLowerCase();
+ insert = Element._insertionTranslations[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ insert(element, content);
+ continue;
+ }
+
+ content = Object.toHTML(content);
+
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+ if (position == 'top' || position == 'after') childNodes.reverse();
+ childNodes.each(insert.curry(element));
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ return element;
+ },
+
+ wrap: function(element, wrapper, attributes) {
+ element = $(element);
+ if (Object.isElement(wrapper))
+ $(wrapper).writeAttribute(attributes || { });
+ else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+ else wrapper = new Element('div', wrapper);
+ if (element.parentNode)
+ element.parentNode.replaceChild(wrapper, element);
+ wrapper.appendChild(element);
+ return wrapper;
+ },
+
+ inspect: function(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return Element.recursivelyCollect(element, 'parentNode');
+ },
+
+ descendants: function(element) {
+ return Element.select(element, "*");
+ },
+
+ firstDescendant: function(element) {
+ element = $(element).firstChild;
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ return $(element);
+ },
+
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
+ previousSiblings: function(element) {
+ return Element.recursivelyCollect(element, 'previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return Element.recursivelyCollect(element, 'nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return Element.previousSiblings(element).reverse()
+ .concat(Element.nextSiblings(element));
+ },
+
+ match: function(element, selector) {
+ if (Object.isString(selector))
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(element.parentNode);
+ var ancestors = Element.ancestors(element);
+ return Object.isNumber(expression) ? ancestors[expression] :
+ Selector.findElement(ancestors, expression, index);
+ },
+
+ down: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return Element.firstDescendant(element);
+ return Object.isNumber(expression) ? Element.descendants(element)[expression] :
+ Element.select(element, expression)[index || 0];
+ },
+
+ previous: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+ var previousSiblings = Element.previousSiblings(element);
+ return Object.isNumber(expression) ? previousSiblings[expression] :
+ Selector.findElement(previousSiblings, expression, index);
+ },
+
+ next: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+ var nextSiblings = Element.nextSiblings(element);
+ return Object.isNumber(expression) ? nextSiblings[expression] :
+ Selector.findElement(nextSiblings, expression, index);
+ },
+
+
+ select: function(element) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return Selector.findChildElements(element, args);
+ },
+
+ adjacent: function(element) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return Selector.findChildElements(element.parentNode, args).without(element);
+ },
+
+ identify: function(element) {
+ element = $(element);
+ var id = Element.readAttribute(element, 'id');
+ if (id) return id;
+ do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
+ Element.writeAttribute(element, 'id', id);
+ return id;
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (Prototype.Browser.IE) {
+ var t = Element._attributeTranslations.read;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ if (name.include(':')) {
+ return (!element.attributes || !element.attributes[name]) ? null :
+ element.attributes[name].value;
+ }
+ }
+ return element.getAttribute(name);
+ },
+
+ writeAttribute: function(element, name, value) {
+ element = $(element);
+ var attributes = { }, t = Element._attributeTranslations.write;
+
+ if (typeof name == 'object') attributes = name;
+ else attributes[name] = Object.isUndefined(value) ? true : value;
+
+ for (var attr in attributes) {
+ name = t.names[attr] || attr;
+ value = attributes[attr];
+ if (t.values[attr]) name = t.values[attr](element, value);
+ if (value === false || value === null)
+ element.removeAttribute(name);
+ else if (value === true)
+ element.setAttribute(name, name);
+ else element.setAttribute(name, value);
+ }
+ return element;
+ },
+
+ getHeight: function(element) {
+ return Element.getDimensions(element).height;
+ },
+
+ getWidth: function(element) {
+ return Element.getDimensions(element).width;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ var elementClassName = element.className;
+ return (elementClassName.length > 0 && (elementClassName == className ||
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ if (!Element.hasClassName(element, className))
+ element.className += (element.className ? ' ' : '') + className;
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ element.className = element.className.replace(
+ new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element[Element.hasClassName(element, className) ?
+ 'removeClassName' : 'addClassName'](element, className);
+ },
+
+ cleanWhitespace: function(element) {
+ element = $(element);
+ var node = element.firstChild;
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.blank();
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+
+ if (element.compareDocumentPosition)
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+ if (ancestor.contains)
+ return ancestor.contains(element) && ancestor !== element;
+
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = Element.cumulativeOffset(element);
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ style = style == 'float' ? 'cssFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value || value == 'auto') {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+ return value == 'auto' ? null : value;
+ },
+
+ getOpacity: function(element) {
+ return $(element).getStyle('opacity');
+ },
+
+ setStyle: function(element, styles) {
+ element = $(element);
+ var elementStyle = element.style, match;
+ if (Object.isString(styles)) {
+ element.style.cssText += ';' + styles;
+ return styles.include('opacity') ?
+ element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+ }
+ for (var property in styles)
+ if (property == 'opacity') element.setOpacity(styles[property]);
+ else
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+ property] = styles[property];
+
+ return element;
+ },
+
+ setOpacity: function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ var display = Element.getStyle(element, 'display');
+ if (display != 'none' && display != null) // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ if (Prototype.Browser.Opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return element;
+ element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+ if (element._overflow !== 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return element;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (element.tagName.toUpperCase() == 'BODY') break;
+ var p = Element.getStyle(element, 'position');
+ if (p !== 'static') break;
+ }
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'position') == 'absolute') return element;
+
+ var offsets = Element.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ return element;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'position') == 'relative') return element;
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ return element;
+ },
+
+ cumulativeScrollOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ getOffsetParent: function(element) {
+ if (element.offsetParent) return $(element.offsetParent);
+ if (element == document.body) return $(element);
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return $(element);
+
+ return $(document.body);
+ },
+
+ viewportOffset: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ if (element.offsetParent == document.body &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ clonePosition: function(element, source) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || { });
+
+ source = $(source);
+ var p = Element.viewportOffset(source);
+
+ element = $(element);
+ var delta = [0, 0];
+ var parent = null;
+ if (Element.getStyle(element, 'position') == 'absolute') {
+ parent = Element.getOffsetParent(element);
+ delta = Element.viewportOffset(parent);
+ }
+
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if (options.setWidth) element.style.width = source.offsetWidth + 'px';
+ if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+ return element;
+ }
+};
+
+Object.extend(Element.Methods, {
+ getElementsBySelector: Element.Methods.select,
+
+ childElements: Element.Methods.immediateDescendants
+});
+
+Element._attributeTranslations = {
+ write: {
+ names: {
+ className: 'class',
+ htmlFor: 'for'
+ },
+ values: { }
+ }
+};
+
+if (Prototype.Browser.Opera) {
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+ function(proceed, element, style) {
+ switch (style) {
+ case 'left': case 'top': case 'right': case 'bottom':
+ if (proceed(element, 'position') === 'static') return null;
+ case 'height': case 'width':
+ if (!Element.visible(element)) return null;
+
+ var dim = parseInt(proceed(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ var properties;
+ if (style === 'height') {
+ properties = ['border-top-width', 'padding-top',
+ 'padding-bottom', 'border-bottom-width'];
+ }
+ else {
+ properties = ['border-left-width', 'padding-left',
+ 'padding-right', 'border-right-width'];
+ }
+ return properties.inject(dim, function(memo, property) {
+ var val = proceed(element, property);
+ return val === null ? memo : memo - parseInt(val, 10);
+ }) + 'px';
+ default: return proceed(element, style);
+ }
+ }
+ );
+
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+ function(proceed, element, attribute) {
+ if (attribute === 'title') return element.title;
+ return proceed(element, attribute);
+ }
+ );
+}
+
+else if (Prototype.Browser.IE) {
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+ try { element.offsetParent }
+ catch(e) { return $(document.body) }
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ $w('positionedOffset viewportOffset').each(function(method) {
+ Element.Methods[method] = Element.Methods[method].wrap(
+ function(proceed, element) {
+ element = $(element);
+ try { element.offsetParent }
+ catch(e) { return Element._returnOffset(0,0) }
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ offsetParent.setStyle({ zoom: 1 });
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+ });
+
+ Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
+ function(proceed, element) {
+ try { element.offsetParent }
+ catch(e) { return Element._returnOffset(0,0) }
+ return proceed(element);
+ }
+ );
+
+ Element.Methods.getStyle = function(element, style) {
+ element = $(element);
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value && element.currentStyle) value = element.currentStyle[style];
+
+ if (style == 'opacity') {
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if (value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+
+ if (value == 'auto') {
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+ return element['offset' + style.capitalize()] + 'px';
+ return null;
+ }
+ return value;
+ };
+
+ Element.Methods.setOpacity = function(element, value) {
+ function stripAlpha(filter){
+ return filter.replace(/alpha\([^\)]*\)/gi,'');
+ }
+ element = $(element);
+ var currentStyle = element.currentStyle;
+ if ((currentStyle && !currentStyle.hasLayout) ||
+ (!currentStyle && element.style.zoom == 'normal'))
+ element.style.zoom = 1;
+
+ var filter = element.getStyle('filter'), style = element.style;
+ if (value == 1 || value === '') {
+ (filter = stripAlpha(filter)) ?
+ style.filter = filter : style.removeAttribute('filter');
+ return element;
+ } else if (value < 0.00001) value = 0;
+ style.filter = stripAlpha(filter) +
+ 'alpha(opacity=' + (value * 100) + ')';
+ return element;
+ };
+
+ Element._attributeTranslations = (function(){
+
+ var classProp = 'className';
+ var forProp = 'for';
+
+ var el = document.createElement('div');
+
+ el.setAttribute(classProp, 'x');
+
+ if (el.className !== 'x') {
+ el.setAttribute('class', 'x');
+ if (el.className === 'x') {
+ classProp = 'class';
+ }
+ }
+ el = null;
+
+ el = document.createElement('label');
+ el.setAttribute(forProp, 'x');
+ if (el.htmlFor !== 'x') {
+ el.setAttribute('htmlFor', 'x');
+ if (el.htmlFor === 'x') {
+ forProp = 'htmlFor';
+ }
+ }
+ el = null;
+
+ return {
+ read: {
+ names: {
+ 'class': classProp,
+ 'className': classProp,
+ 'for': forProp,
+ 'htmlFor': forProp
+ },
+ values: {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute);
+ },
+ _getAttr2: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+ _getAttrNode: function(element, attribute) {
+ var node = element.getAttributeNode(attribute);
+ return node ? node.value : "";
+ },
+ _getEv: (function(){
+
+ var el = document.createElement('div');
+ el.onclick = Prototype.emptyFunction;
+ var value = el.getAttribute('onclick');
+ var f;
+
+ if (String(value).indexOf('{') > -1) {
+ f = function(element, attribute) {
+ attribute = element.getAttribute(attribute);
+ if (!attribute) return null;
+ attribute = attribute.toString();
+ attribute = attribute.split('{')[1];
+ attribute = attribute.split('}')[0];
+ return attribute.strip();
+ };
+ }
+ else if (value === '') {
+ f = function(element, attribute) {
+ attribute = element.getAttribute(attribute);
+ if (!attribute) return null;
+ return attribute.strip();
+ };
+ }
+ el = null;
+ return f;
+ })(),
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+ title: function(element) {
+ return element.title;
+ }
+ }
+ }
+ }
+ })();
+
+ Element._attributeTranslations.write = {
+ names: Object.extend({
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ }, Element._attributeTranslations.read.names),
+ values: {
+ checked: function(element, value) {
+ element.checked = !!value;
+ },
+
+ style: function(element, value) {
+ element.style.cssText = value ? value : '';
+ }
+ }
+ };
+
+ Element._attributeTranslations.has = {};
+
+ $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+ 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
+ Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+ Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+ });
+
+ (function(v) {
+ Object.extend(v, {
+ href: v._getAttr2,
+ src: v._getAttr2,
+ type: v._getAttr,
+ action: v._getAttrNode,
+ disabled: v._flag,
+ checked: v._flag,
+ readonly: v._flag,
+ multiple: v._flag,
+ onload: v._getEv,
+ onunload: v._getEv,
+ onclick: v._getEv,
+ ondblclick: v._getEv,
+ onmousedown: v._getEv,
+ onmouseup: v._getEv,
+ onmouseover: v._getEv,
+ onmousemove: v._getEv,
+ onmouseout: v._getEv,
+ onfocus: v._getEv,
+ onblur: v._getEv,
+ onkeypress: v._getEv,
+ onkeydown: v._getEv,
+ onkeyup: v._getEv,
+ onsubmit: v._getEv,
+ onreset: v._getEv,
+ onselect: v._getEv,
+ onchange: v._getEv
+ });
+ })(Element._attributeTranslations.read.values);
+
+ if (Prototype.BrowserFeatures.ElementExtensions) {
+ (function() {
+ function _descendants(element) {
+ var nodes = element.getElementsByTagName('*'), results = [];
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.tagName !== "!") // Filter out comment nodes.
+ results.push(node);
+ return results;
+ }
+
+ Element.Methods.down = function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return element.firstDescendant();
+ return Object.isNumber(expression) ? _descendants(element)[expression] :
+ Element.select(element, expression)[index || 0];
+ }
+ })();
+ }
+
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1) ? 0.999999 :
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
+ return element;
+ };
+}
+
+else if (Prototype.Browser.WebKit) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+
+ if (value == 1)
+ if(element.tagName.toUpperCase() == 'IMG' && element.width) {
+ element.width++; element.width--;
+ } else try {
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch (e) { }
+
+ return element;
+ };
+
+ Element.Methods.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return Element._returnOffset(valueL, valueT);
+ };
+}
+
+if ('outerHTML' in document.documentElement) {
+ Element.Methods.replace = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+ if (Element._insertionTranslations.tags[tagName]) {
+ var nextSibling = element.next();
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ parent.removeChild(element);
+ if (nextSibling)
+ fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+ else
+ fragments.each(function(node) { parent.appendChild(node) });
+ }
+ else element.outerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+}
+
+Element._returnOffset = function(l, t) {
+ var result = [l, t];
+ result.left = l;
+ result.top = t;
+ return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html) {
+ var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+ if (t) {
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ } else div.innerHTML = html;
+ return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
+ },
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
+ },
+ bottom: function(element, node) {
+ element.appendChild(node);
+ },
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
+ },
+ tags: {
+ TABLE: ['<table>', '</table>', 1],
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+ SELECT: ['<select>', '</select>', 1]
+ }
+};
+
+(function() {
+ var tags = Element._insertionTranslations.tags;
+ Object.extend(tags, {
+ THEAD: tags.TBODY,
+ TFOOT: tags.TBODY,
+ TH: tags.TD
+ });
+})();
+
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ attribute = Element._attributeTranslations.has[attribute] || attribute;
+ var node = $(element).getAttributeNode(attribute);
+ return !!(node && node.specified);
+ }
+};
+
+Element.Methods.ByTag = { };
+
+Object.extend(Element, Element.Methods);
+
+(function(div) {
+
+ if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
+ window.HTMLElement = { };
+ window.HTMLElement.prototype = div['__proto__'];
+ Prototype.BrowserFeatures.ElementExtensions = true;
+ }
+
+ div = null;
+
+})(document.createElement('div'))
+
+Element.extend = (function() {
+
+ function checkDeficiency(tagName) {
+ if (typeof window.Element != 'undefined') {
+ var proto = window.Element.prototype;
+ if (proto) {
+ var id = '_' + (Math.random()+'').slice(2);
+ var el = document.createElement(tagName);
+ proto[id] = 'x';
+ var isBuggy = (el[id] !== 'x');
+ delete proto[id];
+ el = null;
+ return isBuggy;
+ }
+ }
+ return false;
+ }
+
+ function extendElementWith(element, methods) {
+ for (var property in methods) {
+ var value = methods[property];
+ if (Object.isFunction(value) && !(property in element))
+ element[property] = value.methodize();
+ }
+ }
+
+ var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
+
+ if (Prototype.BrowserFeatures.SpecificElementExtensions) {
+ if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
+ return function(element) {
+ if (element && typeof element._extendedByPrototype == 'undefined') {
+ var t = element.tagName;
+ if (t && (/^(?:object|applet|embed)$/i.test(t))) {
+ extendElementWith(element, Element.Methods);
+ extendElementWith(element, Element.Methods.Simulated);
+ extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
+ }
+ }
+ return element;
+ }
+ }
+ return Prototype.K;
+ }
+
+ var Methods = { }, ByTag = Element.Methods.ByTag;
+
+ var extend = Object.extend(function(element) {
+ if (!element || typeof element._extendedByPrototype != 'undefined' ||
+ element.nodeType != 1 || element == window) return element;
+
+ var methods = Object.clone(Methods),
+ tagName = element.tagName.toUpperCase();
+
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+ extendElementWith(element, methods);
+
+ element._extendedByPrototype = Prototype.emptyFunction;
+ return element;
+
+ }, {
+ refresh: function() {
+ if (!Prototype.BrowserFeatures.ElementExtensions) {
+ Object.extend(Methods, Element.Methods);
+ Object.extend(Methods, Element.Methods.Simulated);
+ }
+ }
+ });
+
+ extend.refresh();
+ return extend;
+})();
+
+Element.hasAttribute = function(element, attribute) {
+ if (element.hasAttribute) return element.hasAttribute(attribute);
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+ if (!methods) {
+ Object.extend(Form, Form.Methods);
+ Object.extend(Form.Element, Form.Element.Methods);
+ Object.extend(Element.Methods.ByTag, {
+ "FORM": Object.clone(Form.Methods),
+ "INPUT": Object.clone(Form.Element.Methods),
+ "SELECT": Object.clone(Form.Element.Methods),
+ "TEXTAREA": Object.clone(Form.Element.Methods)
+ });
+ }
+
+ if (arguments.length == 2) {
+ var tagName = methods;
+ methods = arguments[1];
+ }
+
+ if (!tagName) Object.extend(Element.Methods, methods || { });
+ else {
+ if (Object.isArray(tagName)) tagName.each(extend);
+ else extend(tagName);
+ }
+
+ function extend(tagName) {
+ tagName = tagName.toUpperCase();
+ if (!Element.Methods.ByTag[tagName])
+ Element.Methods.ByTag[tagName] = { };
+ Object.extend(Element.Methods.ByTag[tagName], methods);
+ }
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!Object.isFunction(value)) continue;
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = value.methodize();
+ }
+ }
+
+ function findDOMClass(tagName) {
+ var klass;
+ var trans = {
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+ "FrameSet", "IFRAME": "IFrame"
+ };
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName.capitalize() + 'Element';
+ if (window[klass]) return window[klass];
+
+ var element = document.createElement(tagName);
+ var proto = element['__proto__'] || element.constructor.prototype;
+ element = null;
+ return proto;
+ }
+
+ var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
+ Element.prototype;
+
+ if (F.ElementExtensions) {
+ copy(Element.Methods, elementPrototype);
+ copy(Element.Methods.Simulated, elementPrototype, true);
+ }
+
+ if (F.SpecificElementExtensions) {
+ for (var tag in Element.Methods.ByTag) {
+ var klass = findDOMClass(tag);
+ if (Object.isUndefined(klass)) continue;
+ copy(T[tag], klass.prototype);
+ }
+ }
+
+ Object.extend(Element, Element.Methods);
+ delete Element.ByTag;
+
+ if (Element.extend.refresh) Element.extend.refresh();
+ Element.cache = { };
+};
+
+
+document.viewport = {
+
+ getDimensions: function() {
+ return { width: this.getWidth(), height: this.getHeight() };
+ },
+
+ getScrollOffsets: function() {
+ return Element._returnOffset(
+ window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+ }
+};
+
+(function(viewport) {
+ var B = Prototype.Browser, doc = document, element, property = {};
+
+ function getRootElement() {
+ if (B.WebKit && !doc.evaluate)
+ return document;
+
+ if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
+ return document.body;
+
+ return document.documentElement;
+ }
+
+ function define(D) {
+ if (!element) element = getRootElement();
+
+ property[D] = 'client' + D;
+
+ viewport['get' + D] = function() { return element[property[D]] };
+ return viewport['get' + D]();
+ }
+
+ viewport.getWidth = define.curry('Width');
+
+ viewport.getHeight = define.curry('Height');
+})(document.viewport);
+
+
+Element.Storage = {
+ UID: 1
+};
+
+Element.addMethods({
+ getStorage: function(element) {
+ if (!(element = $(element))) return;
+
+ var uid;
+ if (element === window) {
+ uid = 0;
+ } else {
+ if (typeof element._prototypeUID === "undefined")
+ element._prototypeUID = [Element.Storage.UID++];
+ uid = element._prototypeUID[0];
+ }
+
+ if (!Element.Storage[uid])
+ Element.Storage[uid] = $H();
+
+ return Element.Storage[uid];
+ },
+
+ store: function(element, key, value) {
+ if (!(element = $(element))) return;
+
+ if (arguments.length === 2) {
+ Element.getStorage(element).update(key);
+ } else {
+ Element.getStorage(element).set(key, value);
+ }
+
+ return element;
+ },
+
+ retrieve: function(element, key, defaultValue) {
+ if (!(element = $(element))) return;
+ var hash = Element.getStorage(element), value = hash.get(key);
+
+ if (Object.isUndefined(value)) {
+ hash.set(key, defaultValue);
+ value = defaultValue;
+ }
+
+ return value;
+ },
+
+ clone: function(element, deep) {
+ if (!(element = $(element))) return;
+ var clone = element.cloneNode(deep);
+ clone._prototypeUID = void 0;
+ if (deep) {
+ var descendants = Element.select(clone, '*'),
+ i = descendants.length;
+ while (i--) {
+ descendants[i]._prototypeUID = void 0;
+ }
+ }
+ return Element.extend(clone);
+ }
+});
+/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license. Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+
+ if (this.shouldUseSelectorsAPI()) {
+ this.mode = 'selectorsAPI';
+ } else if (this.shouldUseXPath()) {
+ this.mode = 'xpath';
+ this.compileXPathMatcher();
+ } else {
+ this.mode = "normal";
+ this.compileMatcher();
+ }
+
+ },
+
+ shouldUseXPath: (function() {
+
+ var IS_DESCENDANT_SELECTOR_BUGGY = (function(){
+ var isBuggy = false;
+ if (document.evaluate && window.XPathResult) {
+ var el = document.createElement('div');
+ el.innerHTML = '<ul><li></li></ul><div><ul><li></li></ul></div>';
+
+ var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
+ "//*[local-name()='li' or local-name()='LI']";
+
+ var result = document.evaluate(xpath, el, null,
+ XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+ isBuggy = (result.snapshotLength !== 2);
+ el = null;
+ }
+ return isBuggy;
+ })();
+
+ return function() {
+ if (!Prototype.BrowserFeatures.XPath) return false;
+
+ var e = this.expression;
+
+ if (Prototype.Browser.WebKit &&
+ (e.include("-of-type") || e.include(":empty")))
+ return false;
+
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
+ return false;
+
+ if (IS_DESCENDANT_SELECTOR_BUGGY) return false;
+
+ return true;
+ }
+
+ })(),
+
+ shouldUseSelectorsAPI: function() {
+ if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+
+ if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
+
+ if (!Selector._div) Selector._div = new Element('div');
+
+ try {
+ Selector._div.querySelector(this.expression);
+ } catch(e) {
+ return false;
+ }
+
+ return true;
+ },
+
+ compileMatcher: function() {
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+ c = Selector.criteria, le, p, m, len = ps.length, name;
+
+ if (Selector._cache[e]) {
+ this.matcher = Selector._cache[e];
+ return;
+ }
+
+ this.matcher = ["this.matcher = function(root) {",
+ "var r = root, h = Selector.handlers, c = false, n;"];
+
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i = 0; i<len; i++) {
+ p = ps[i].re;
+ name = ps[i].name;
+ if (m = e.match(p)) {
+ this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
+ new Template(c[name]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.matcher.push("return h.unique(n);\n}");
+ eval(this.matcher.join('\n'));
+ Selector._cache[this.expression] = this.matcher;
+ },
+
+ compileXPathMatcher: function() {
+ var e = this.expression, ps = Selector.patterns,
+ x = Selector.xpath, le, m, len = ps.length, name;
+
+ if (Selector._cache[e]) {
+ this.xpath = Selector._cache[e]; return;
+ }
+
+ this.matcher = ['.//*'];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i = 0; i<len; i++) {
+ name = ps[i].name;
+ if (m = e.match(ps[i].re)) {
+ this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
+ new Template(x[name]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.xpath = this.matcher.join('');
+ Selector._cache[this.expression] = this.xpath;
+ },
+
+ findElements: function(root) {
+ root = root || document;
+ var e = this.expression, results;
+
+ switch (this.mode) {
+ case 'selectorsAPI':
+ if (root !== document) {
+ var oldId = root.id, id = $(root).identify();
+ id = id.replace(/([\.:])/g, "\\$1");
+ e = "#" + id + " " + e;
+ }
+
+ results = $A(root.querySelectorAll(e)).map(Element.extend);
+ root.id = oldId;
+
+ return results;
+ case 'xpath':
+ return document._getElementsByXPath(this.xpath, root);
+ default:
+ return this.matcher(root);
+ }
+ },
+
+ match: function(element) {
+ this.tokens = [];
+
+ var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+ var le, p, m, len = ps.length, name;
+
+ while (e && le !== e && (/\S/).test(e)) {
+ le = e;
+ for (var i = 0; i<len; i++) {
+ p = ps[i].re;
+ name = ps[i].name;
+ if (m = e.match(p)) {
+ if (as[name]) {
+ this.tokens.push([name, Object.clone(m)]);
+ e = e.replace(m[0], '');
+ } else {
+ return this.findElements(document).include(element);
+ }
+ }
+ }
+ }
+
+ var match = true, name, matches;
+ for (var i = 0, token; token = this.tokens[i]; i++) {
+ name = token[0], matches = token[1];
+ if (!Selector.assertions[name](element, matches)) {
+ match = false; break;
+ }
+ }
+
+ return match;
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector:" + this.expression.inspect() + ">";
+ }
+});
+
+if (Prototype.BrowserFeatures.SelectorsAPI &&
+ document.compatMode === 'BackCompat') {
+ Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
+ var div = document.createElement('div'),
+ span = document.createElement('span');
+
+ div.id = "prototype_test_id";
+ span.className = 'Test';
+ div.appendChild(span);
+ var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
+ div = span = null;
+ return isIgnored;
+ })();
+}
+
+Object.extend(Selector, {
+ _cache: { },
+
+ xpath: {
+ descendant: "//*",
+ child: "/*",
+ adjacent: "/following-sibling::*[1]",
+ laterSibling: '/following-sibling::*',
+ tagName: function(m) {
+ if (m[1] == '*') return '';
+ return "[local-name()='" + m[1].toLowerCase() +
+ "' or local-name()='" + m[1].toUpperCase() + "']";
+ },
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+ id: "[@id='#{1}']",
+ attrPresence: function(m) {
+ m[1] = m[1].toLowerCase();
+ return new Template("[@#{1}]").evaluate(m);
+ },
+ attr: function(m) {
+ m[1] = m[1].toLowerCase();
+ m[3] = m[5] || m[6];
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+ },
+ pseudo: function(m) {
+ var h = Selector.xpath.pseudos[m[1]];
+ if (!h) return '';
+ if (Object.isFunction(h)) return h(m);
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+ },
+ operators: {
+ '=': "[@#{1}='#{3}']",
+ '!=': "[@#{1}!='#{3}']",
+ '^=': "[starts-with(@#{1}, '#{3}')]",
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+ '*=': "[contains(@#{1}, '#{3}')]",
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+ },
+ pseudos: {
+ 'first-child': '[not(preceding-sibling::*)]',
+ 'last-child': '[not(following-sibling::*)]',
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
+ 'empty': "[count(*) = 0 and (count(text()) = 0)]",
+ 'checked': "[@checked]",
+ 'disabled': "[(@disabled) and (@type!='hidden')]",
+ 'enabled': "[not(@disabled) and (@type!='hidden')]",
+ 'not': function(m) {
+ var e = m[6], p = Selector.patterns,
+ x = Selector.xpath, le, v, len = p.length, name;
+
+ var exclusion = [];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i = 0; i<len; i++) {
+ name = p[i].name
+ if (m = e.match(p[i].re)) {
+ v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+ return "[not(" + exclusion.join(" and ") + ")]";
+ },
+ 'nth-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+ },
+ 'nth-last-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+ },
+ 'nth-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("position() ", m);
+ },
+ 'nth-last-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+ },
+ 'first-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+ },
+ 'last-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+ },
+ 'only-of-type': function(m) {
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+ },
+ nth: function(fragment, m) {
+ var mm, formula = m[6], predicate;
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ if (mm = formula.match(/^(\d+)$/)) // digit only
+ return '[' + fragment + "= " + mm[1] + ']';
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (mm[1] == "-") mm[1] = -1;
+ var a = mm[1] ? Number(mm[1]) : 1;
+ var b = mm[2] ? Number(mm[2]) : 0;
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
+ return new Template(predicate).evaluate({
+ fragment: fragment, a: a, b: b });
+ }
+ }
+ }
+ },
+
+ criteria: {
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
+ attr: function(m) {
+ m[3] = (m[5] || m[6]);
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
+ },
+ pseudo: function(m) {
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+ },
+ descendant: 'c = "descendant";',
+ child: 'c = "child";',
+ adjacent: 'c = "adjacent";',
+ laterSibling: 'c = "laterSibling";'
+ },
+
+ patterns: [
+ { name: 'laterSibling', re: /^\s*~\s*/ },
+ { name: 'child', re: /^\s*>\s*/ },
+ { name: 'adjacent', re: /^\s*\+\s*/ },
+ { name: 'descendant', re: /^\s/ },
+
+ { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
+ { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ },
+ { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ },
+ { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
+ { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
+ { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }
+ ],
+
+ assertions: {
+ tagName: function(element, matches) {
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ },
+
+ className: function(element, matches) {
+ return Element.hasClassName(element, matches[1]);
+ },
+
+ id: function(element, matches) {
+ return element.id === matches[1];
+ },
+
+ attrPresence: function(element, matches) {
+ return Element.hasAttribute(element, matches[1]);
+ },
+
+ attr: function(element, matches) {
+ var nodeValue = Element.readAttribute(element, matches[1]);
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
+ }
+ },
+
+ handlers: {
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ a.push(node);
+ return a;
+ },
+
+ mark: function(nodes) {
+ var _true = Prototype.emptyFunction;
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = _true;
+ return nodes;
+ },
+
+ unmark: (function(){
+
+ var PROPERTIES_ATTRIBUTES_MAP = (function(){
+ var el = document.createElement('div'),
+ isBuggy = false,
+ propName = '_countedByPrototype',
+ value = 'x'
+ el[propName] = value;
+ isBuggy = (el.getAttribute(propName) === value);
+ el = null;
+ return isBuggy;
+ })();
+
+ return PROPERTIES_ATTRIBUTES_MAP ?
+ function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node.removeAttribute('_countedByPrototype');
+ return nodes;
+ } :
+ function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = void 0;
+ return nodes;
+ }
+ })(),
+
+ index: function(parentNode, reverse, ofType) {
+ parentNode._countedByPrototype = Prototype.emptyFunction;
+ if (reverse) {
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+ var node = nodes[i];
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ } else {
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ },
+
+ unique: function(nodes) {
+ if (nodes.length == 0) return nodes;
+ var results = [], n;
+ for (var i = 0, l = nodes.length; i < l; i++)
+ if (typeof (n = nodes[i])._countedByPrototype == 'undefined') {
+ n._countedByPrototype = Prototype.emptyFunction;
+ results.push(Element.extend(n));
+ }
+ return Selector.handlers.unmark(results);
+ },
+
+ descendant: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName('*'));
+ return results;
+ },
+
+ child: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ for (var j = 0, child; child = node.childNodes[j]; j++)
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+ }
+ return results;
+ },
+
+ adjacent: function(nodes) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ var next = this.nextElementSibling(node);
+ if (next) results.push(next);
+ }
+ return results;
+ },
+
+ laterSibling: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, Element.nextSiblings(node));
+ return results;
+ },
+
+ nextElementSibling: function(node) {
+ while (node = node.nextSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ previousElementSibling: function(node) {
+ while (node = node.previousSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ tagName: function(nodes, root, tagName, combinator) {
+ var uTagName = tagName.toUpperCase();
+ var results = [], h = Selector.handlers;
+ if (nodes) {
+ if (combinator) {
+ if (combinator == "descendant") {
+ for (var i = 0, node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName(tagName));
+ return results;
+ } else nodes = this[combinator](nodes);
+ if (tagName == "*") return nodes;
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
+ return results;
+ } else return root.getElementsByTagName(tagName);
+ },
+
+ id: function(nodes, root, id, combinator) {
+ var targetNode = $(id), h = Selector.handlers;
+
+ if (root == document) {
+ if (!targetNode) return [];
+ if (!nodes) return [targetNode];
+ } else {
+ if (!root.sourceIndex || root.sourceIndex < 1) {
+ var nodes = root.getElementsByTagName('*');
+ for (var j = 0, node; node = nodes[j]; j++) {
+ if (node.id === id) return [node];
+ }
+ }
+ }
+
+ if (nodes) {
+ if (combinator) {
+ if (combinator == 'child') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (targetNode.parentNode == node) return [targetNode];
+ } else if (combinator == 'descendant') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
+ } else if (combinator == 'adjacent') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
+ return [targetNode];
+ } else nodes = h[combinator](nodes);
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node == targetNode) return [targetNode];
+ return [];
+ }
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+ },
+
+ className: function(nodes, root, className, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ return Selector.handlers.byClassName(nodes, root, className);
+ },
+
+ byClassName: function(nodes, root, className) {
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
+ var needle = ' ' + className + ' ';
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+ nodeClassName = node.className;
+ if (nodeClassName.length == 0) continue;
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+ results.push(node);
+ }
+ return results;
+ },
+
+ attrPresence: function(nodes, root, attr, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var results = [];
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.hasAttribute(node, attr)) results.push(node);
+ return results;
+ },
+
+ attr: function(nodes, root, attr, value, operator, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var handler = Selector.operators[operator], results = [];
+ for (var i = 0, node; node = nodes[i]; i++) {
+ var nodeValue = Element.readAttribute(node, attr);
+ if (nodeValue === null) continue;
+ if (handler(nodeValue, value)) results.push(node);
+ }
+ return results;
+ },
+
+ pseudo: function(nodes, name, value, root, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ return Selector.pseudos[name](nodes, value, root);
+ }
+ },
+
+ pseudos: {
+ 'first-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.previousElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'last-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.nextElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'only-child': function(nodes, value, root) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+ results.push(node);
+ return results;
+ },
+ 'nth-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root);
+ },
+ 'nth-last-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true);
+ },
+ 'nth-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
+ },
+ 'nth-last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
+ },
+ 'first-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
+ },
+ 'last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
+ },
+ 'only-of-type': function(nodes, formula, root) {
+ var p = Selector.pseudos;
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+ },
+
+ getIndices: function(a, b, total) {
+ if (a == 0) return b > 0 ? [b] : [];
+ return $R(1, total).inject([], function(memo, i) {
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+ return memo;
+ });
+ },
+
+ nth: function(nodes, formula, root, reverse, ofType) {
+ if (nodes.length == 0) return [];
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ var h = Selector.handlers, results = [], indexed = [], m;
+ h.mark(nodes);
+ for (var i = 0, node; node = nodes[i]; i++) {
+ if (!node.parentNode._countedByPrototype) {
+ h.index(node.parentNode, reverse, ofType);
+ indexed.push(node.parentNode);
+ }
+ }
+ if (formula.match(/^\d+$/)) { // just a number
+ formula = Number(formula);
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.nodeIndex == formula) results.push(node);
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (m[1] == "-") m[1] = -1;
+ var a = m[1] ? Number(m[1]) : 1;
+ var b = m[2] ? Number(m[2]) : 0;
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+ for (var j = 0; j < l; j++)
+ if (node.nodeIndex == indices[j]) results.push(node);
+ }
+ }
+ h.unmark(nodes);
+ h.unmark(indexed);
+ return results;
+ },
+
+ 'empty': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (node.tagName == '!' || node.firstChild) continue;
+ results.push(node);
+ }
+ return results;
+ },
+
+ 'not': function(nodes, selector, root) {
+ var h = Selector.handlers, selectorType, m;
+ var exclusions = new Selector(selector).findElements(root);
+ h.mark(exclusions);
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node._countedByPrototype) results.push(node);
+ h.unmark(exclusions);
+ return results;
+ },
+
+ 'enabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node.disabled && (!node.type || node.type !== 'hidden'))
+ results.push(node);
+ return results;
+ },
+
+ 'disabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.disabled) results.push(node);
+ return results;
+ },
+
+ 'checked': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.checked) results.push(node);
+ return results;
+ }
+ },
+
+ operators: {
+ '=': function(nv, v) { return nv == v; },
+ '!=': function(nv, v) { return nv != v; },
+ '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
+ '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
+ '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+ '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
+ '-').include('-' + (v || "").toUpperCase() + '-'); }
+ },
+
+ split: function(expression) {
+ var expressions = [];
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+ expressions.push(m[1].strip());
+ });
+ return expressions;
+ },
+
+ matchElements: function(elements, expression) {
+ var matches = $$(expression), h = Selector.handlers;
+ h.mark(matches);
+ for (var i = 0, results = [], element; element = elements[i]; i++)
+ if (element._countedByPrototype) results.push(element);
+ h.unmark(matches);
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ if (Object.isNumber(expression)) {
+ index = expression; expression = false;
+ }
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ expressions = Selector.split(expressions.join(','));
+ var results = [], h = Selector.handlers;
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
+ selector = new Selector(expressions[i].strip());
+ h.concat(results, selector.findElements(element));
+ }
+ return (l > 1) ? h.unique(results) : results;
+ }
+});
+
+if (Prototype.Browser.IE) {
+ Object.extend(Selector.handlers, {
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ if (node.tagName !== "!") a.push(node);
+ return a;
+ }
+ });
+}
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+
+var Form = {
+ reset: function(form) {
+ form = $(form);
+ form.reset();
+ return form;
+ },
+
+ serializeElements: function(elements, options) {
+ if (typeof options != 'object') options = { hash: !!options };
+ else if (Object.isUndefined(options.hash)) options.hash = true;
+ var key, value, submitted = false, submit = options.submit;
+
+ var data = elements.inject({ }, function(result, element) {
+ if (!element.disabled && element.name) {
+ key = element.name; value = $(element).getValue();
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
+ if (key in result) {
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return options.hash ? data : Object.toQueryString(data);
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, options) {
+ return Form.serializeElements(Form.getElements(form), options);
+ },
+
+ getElements: function(form) {
+ var elements = $(form).getElementsByTagName('*'),
+ element,
+ arr = [ ],
+ serializers = Form.Element.Serializers;
+ for (var i = 0; element = elements[i]; i++) {
+ arr.push(element);
+ }
+ return arr.inject([], function(elements, child) {
+ if (serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ })
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('disable');
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('enable');
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ var elements = $(form).getElements().findAll(function(element) {
+ return 'hidden' != element.type && !element.disabled;
+ });
+ var firstByIndex = elements.findAll(function(element) {
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+ }).sortBy(function(element) { return element.tabIndex }).first();
+
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
+ return /^(?:input|select|textarea)$/i.test(element.tagName);
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ },
+
+ request: function(form, options) {
+ form = $(form), options = Object.clone(options || { });
+
+ var params = options.parameters, action = form.readAttribute('action') || '';
+ if (action.blank()) action = window.location.href;
+ options.parameters = form.serialize(true);
+
+ if (params) {
+ if (Object.isString(params)) params = params.toQueryParams();
+ Object.extend(options.parameters, params);
+ }
+
+ if (form.hasAttribute('method') && !options.method)
+ options.method = form.method;
+
+ return new Ajax.Request(action, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+};
+
+Form.Element.Methods = {
+
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ setValue: function(element, value) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ Form.Element.Serializers[method](element, value);
+ return element;
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ try {
+ element.focus();
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
+ !(/^(?:button|reset|submit)$/i.test(element.type))))
+ element.select();
+ } catch (e) { }
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.disabled = false;
+ return element;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element, value) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element, value);
+ default:
+ return Form.Element.Serializers.textarea(element, value);
+ }
+ },
+
+ inputSelector: function(element, value) {
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
+ else element.checked = !!value;
+ },
+
+ textarea: function(element, value) {
+ if (Object.isUndefined(value)) return element.value;
+ else element.value = value;
+ },
+
+ select: function(element, value) {
+ if (Object.isUndefined(value))
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ else {
+ var opt, currentValue, single = !Object.isArray(value);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ currentValue = this.optionValue(opt);
+ if (single) {
+ if (currentValue == value) {
+ opt.selected = true;
+ return;
+ }
+ }
+ else opt.selected = value.include(currentValue);
+ }
+ }
+ },
+
+ selectOne: function(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
+ },
+
+ selectMany: function(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(this.optionValue(opt));
+ }
+ return values;
+ },
+
+ optionValue: function(opt) {
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+ initialize: function($super, element, frequency, callback) {
+ $super(callback, frequency);
+ this.element = $(element);
+ this.lastValue = this.getValue();
+ },
+
+ execute: function() {
+ var value = this.getValue();
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
+ this.lastValue != value : String(this.lastValue) != String(value)) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback, this);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+(function() {
+
+ var Event = {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+ KEY_INSERT: 45,
+
+ cache: {}
+ };
+
+ var docEl = document.documentElement;
+ var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
+ && 'onmouseleave' in docEl;
+
+ var _isButton;
+ if (Prototype.Browser.IE) {
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
+ _isButton = function(event, code) {
+ return event.button === buttonMap[code];
+ };
+ } else if (Prototype.Browser.WebKit) {
+ _isButton = function(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 1 && event.metaKey;
+ default: return false;
+ }
+ };
+ } else {
+ _isButton = function(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ };
+ }
+
+ function isLeftClick(event) { return _isButton(event, 0) }
+
+ function isMiddleClick(event) { return _isButton(event, 1) }
+
+ function isRightClick(event) { return _isButton(event, 2) }
+
+ function element(event) {
+ event = Event.extend(event);
+
+ var node = event.target, type = event.type,
+ currentTarget = event.currentTarget;
+
+ if (currentTarget && currentTarget.tagName) {
+ if (type === 'load' || type === 'error' ||
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
+ && currentTarget.type === 'radio'))
+ node = currentTarget;
+ }
+
+ if (node.nodeType == Node.TEXT_NODE)
+ node = node.parentNode;
+
+ return Element.extend(node);
+ }
+
+ function findElement(event, expression) {
+ var element = Event.element(event);
+ if (!expression) return element;
+ var elements = [element].concat(element.ancestors());
+ return Selector.findElement(elements, expression, 0);
+ }
+
+ function pointer(event) {
+ return { x: pointerX(event), y: pointerY(event) };
+ }
+
+ function pointerX(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollLeft: 0 };
+
+ return event.pageX || (event.clientX +
+ (docElement.scrollLeft || body.scrollLeft) -
+ (docElement.clientLeft || 0));
+ }
+
+ function pointerY(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollTop: 0 };
+
+ return event.pageY || (event.clientY +
+ (docElement.scrollTop || body.scrollTop) -
+ (docElement.clientTop || 0));
+ }
+
+
+ function stop(event) {
+ Event.extend(event);
+ event.preventDefault();
+ event.stopPropagation();
+
+ event.stopped = true;
+ }
+
+ Event.Methods = {
+ isLeftClick: isLeftClick,
+ isMiddleClick: isMiddleClick,
+ isRightClick: isRightClick,
+
+ element: element,
+ findElement: findElement,
+
+ pointer: pointer,
+ pointerX: pointerX,
+ pointerY: pointerY,
+
+ stop: stop
+ };
+
+
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+ m[name] = Event.Methods[name].methodize();
+ return m;
+ });
+
+ if (Prototype.Browser.IE) {
+ function _relatedTarget(event) {
+ var element;
+ switch (event.type) {
+ case 'mouseover': element = event.fromElement; break;
+ case 'mouseout': element = event.toElement; break;
+ default: return null;
+ }
+ return Element.extend(element);
+ }
+
+ Object.extend(methods, {
+ stopPropagation: function() { this.cancelBubble = true },
+ preventDefault: function() { this.returnValue = false },
+ inspect: function() { return '[object Event]' }
+ });
+
+ Event.extend = function(event, element) {
+ if (!event) return false;
+ if (event._extendedByPrototype) return event;
+
+ event._extendedByPrototype = Prototype.emptyFunction;
+ var pointer = Event.pointer(event);
+
+ Object.extend(event, {
+ target: event.srcElement || element,
+ relatedTarget: _relatedTarget(event),
+ pageX: pointer.x,
+ pageY: pointer.y
+ });
+
+ return Object.extend(event, methods);
+ };
+ } else {
+ Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
+ Object.extend(Event.prototype, methods);
+ Event.extend = Prototype.K;
+ }
+
+ function _createResponder(element, eventName, handler) {
+ var registry = Element.retrieve(element, 'prototype_event_registry');
+
+ if (Object.isUndefined(registry)) {
+ CACHE.push(element);
+ registry = Element.retrieve(element, 'prototype_event_registry', $H());
+ }
+
+ var respondersForEvent = registry.get(eventName);
+ if (Object.isUndefined(respondersForEvent)) {
+ respondersForEvent = [];
+ registry.set(eventName, respondersForEvent);
+ }
+
+ if (respondersForEvent.pluck('handler').include(handler)) return false;
+
+ var responder;
+ if (eventName.include(":")) {
+ responder = function(event) {
+ if (Object.isUndefined(event.eventName))
+ return false;
+
+ if (event.eventName !== eventName)
+ return false;
+
+ Event.extend(event, element);
+ handler.call(element, event);
+ };
+ } else {
+ if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
+ (eventName === "mouseenter" || eventName === "mouseleave")) {
+ if (eventName === "mouseenter" || eventName === "mouseleave") {
+ responder = function(event) {
+ Event.extend(event, element);
+
+ var parent = event.relatedTarget;
+ while (parent && parent !== element) {
+ try { parent = parent.parentNode; }
+ catch(e) { parent = element; }
+ }
+
+ if (parent === element) return;
+
+ handler.call(element, event);
+ };
+ }
+ } else {
+ responder = function(event) {
+ Event.extend(event, element);
+ handler.call(element, event);
+ };
+ }
+ }
+
+ responder.handler = handler;
+ respondersForEvent.push(responder);
+ return responder;
+ }
+
+ function _destroyCache() {
+ for (var i = 0, length = CACHE.length; i < length; i++) {
+ Event.stopObserving(CACHE[i]);
+ CACHE[i] = null;
+ }
+ }
+
+ var CACHE = [];
+
+ if (Prototype.Browser.IE)
+ window.attachEvent('onunload', _destroyCache);
+
+ if (Prototype.Browser.WebKit)
+ window.addEventListener('unload', Prototype.emptyFunction, false);
+
+
+ var _getDOMEventName = Prototype.K;
+
+ if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
+ _getDOMEventName = function(eventName) {
+ var translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
+ return eventName in translations ? translations[eventName] : eventName;
+ };
+ }
+
+ function observe(element, eventName, handler) {
+ element = $(element);
+
+ var responder = _createResponder(element, eventName, handler);
+
+ if (!responder) return element;
+
+ if (eventName.include(':')) {
+ if (element.addEventListener)
+ element.addEventListener("dataavailable", responder, false);
+ else {
+ element.attachEvent("ondataavailable", responder);
+ element.attachEvent("onfilterchange", responder);
+ }
+ } else {
+ var actualEventName = _getDOMEventName(eventName);
+
+ if (element.addEventListener)
+ element.addEventListener(actualEventName, responder, false);
+ else
+ element.attachEvent("on" + actualEventName, responder);
+ }
+
+ return element;
+ }
+
+ function stopObserving(element, eventName, handler) {
+ element = $(element);
+
+ var registry = Element.retrieve(element, 'prototype_event_registry');
+
+ if (Object.isUndefined(registry)) return element;
+
+ if (eventName && !handler) {
+ var responders = registry.get(eventName);
+
+ if (Object.isUndefined(responders)) return element;
+
+ responders.each( function(r) {
+ Element.stopObserving(element, eventName, r.handler);
+ });
+ return element;
+ } else if (!eventName) {
+ registry.each( function(pair) {
+ var eventName = pair.key, responders = pair.value;
+
+ responders.each( function(r) {
+ Element.stopObserving(element, eventName, r.handler);
+ });
+ });
+ return element;
+ }
+
+ var responders = registry.get(eventName);
+
+ if (!responders) return;
+
+ var responder = responders.find( function(r) { return r.handler === handler; });
+ if (!responder) return element;
+
+ var actualEventName = _getDOMEventName(eventName);
+
+ if (eventName.include(':')) {
+ if (element.removeEventListener)
+ element.removeEventListener("dataavailable", responder, false);
+ else {
+ element.detachEvent("ondataavailable", responder);
+ element.detachEvent("onfilterchange", responder);
+ }
+ } else {
+ if (element.removeEventListener)
+ element.removeEventListener(actualEventName, responder, false);
+ else
+ element.detachEvent('on' + actualEventName, responder);
+ }
+
+ registry.set(eventName, responders.without(responder));
+
+ return element;
+ }
+
+ function fire(element, eventName, memo, bubble) {
+ element = $(element);
+
+ if (Object.isUndefined(bubble))
+ bubble = true;
+
+ if (element == document && document.createEvent && !element.dispatchEvent)
+ element = document.documentElement;
+
+ var event;
+ if (document.createEvent) {
+ event = document.createEvent('HTMLEvents');
+ event.initEvent('dataavailable', true, true);
+ } else {
+ event = document.createEventObject();
+ event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
+ }
+
+ event.eventName = eventName;
+ event.memo = memo || { };
+
+ if (document.createEvent)
+ element.dispatchEvent(event);
+ else
+ element.fireEvent(event.eventType, event);
+
+ return Event.extend(event);
+ }
+
+
+ Object.extend(Event, Event.Methods);
+
+ Object.extend(Event, {
+ fire: fire,
+ observe: observe,
+ stopObserving: stopObserving
+ });
+
+ Element.addMethods({
+ fire: fire,
+
+ observe: observe,
+
+ stopObserving: stopObserving
+ });
+
+ Object.extend(document, {
+ fire: fire.methodize(),
+
+ observe: observe.methodize(),
+
+ stopObserving: stopObserving.methodize(),
+
+ loaded: false
+ });
+
+ if (window.Event) Object.extend(window.Event, Event);
+ else window.Event = Event;
+})();
+
+(function() {
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+ Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
+
+ var timer;
+
+ function fireContentLoadedEvent() {
+ if (document.loaded) return;
+ if (timer) window.clearTimeout(timer);
+ document.loaded = true;
+ document.fire('dom:loaded');
+ }
+
+ function checkReadyState() {
+ if (document.readyState === 'complete') {
+ document.stopObserving('readystatechange', checkReadyState);
+ fireContentLoadedEvent();
+ }
+ }
+
+ function pollDoScroll() {
+ try { document.documentElement.doScroll('left'); }
+ catch(e) {
+ timer = pollDoScroll.defer();
+ return;
+ }
+ fireContentLoadedEvent();
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
+ } else {
+ document.observe('readystatechange', checkReadyState);
+ if (window == top)
+ timer = pollDoScroll.defer();
+ }
+
+ Event.observe(window, 'load', fireContentLoadedEvent);
+})();
+
+Element.addMethods();
+
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+ Before: function(element, content) {
+ return Element.insert(element, {before:content});
+ },
+
+ Top: function(element, content) {
+ return Element.insert(element, {top:content});
+ },
+
+ Bottom: function(element, content) {
+ return Element.insert(element, {bottom:content});
+ },
+
+ After: function(element, content) {
+ return Element.insert(element, {after:content});
+ }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+var Position = {
+ includeScrollOffsets: false,
+
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = Element.cumulativeScrollOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+
+ cumulativeOffset: Element.Methods.cumulativeOffset,
+
+ positionedOffset: Element.Methods.positionedOffset,
+
+ absolutize: function(element) {
+ Position.prepare();
+ return Element.absolutize(element);
+ },
+
+ relativize: function(element) {
+ Position.prepare();
+ return Element.relativize(element);
+ },
+
+ realOffset: Element.Methods.cumulativeScrollOffset,
+
+ offsetParent: Element.Methods.getOffsetParent,
+
+ page: Element.Methods.viewportOffset,
+
+ clone: function(source, target, options) {
+ options = options || { };
+ return Element.clonePosition(target, source, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+ function iter(name) {
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+ }
+
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+ function(element, className) {
+ className = className.toString().strip();
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+ } : function(element, className) {
+ className = className.toString().strip();
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+ if (!classNames && !className) return elements;
+
+ var nodes = $(element).getElementsByTagName('*');
+ className = ' ' + className + ' ';
+
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+ (classNames && classNames.all(function(name) {
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
+ }))))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ };
+
+ return function(className, parentElement) {
+ return $(parentElement || document.body).getElementsByClassName(className);
+ };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/ \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/builder.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/builder.js
new file mode 100644
index 000000000..f1f42b9ac
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/builder.js
@@ -0,0 +1,136 @@
+// script.aculo.us builder.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+ NODEMAP: {
+ AREA: 'map',
+ CAPTION: 'table',
+ COL: 'table',
+ COLGROUP: 'table',
+ LEGEND: 'fieldset',
+ OPTGROUP: 'select',
+ OPTION: 'select',
+ PARAM: 'object',
+ TBODY: 'table',
+ TD: 'table',
+ TFOOT: 'table',
+ TH: 'table',
+ THEAD: 'table',
+ TR: 'table'
+ },
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+ // due to a Firefox bug
+ node: function(elementName) {
+ elementName = elementName.toUpperCase();
+
+ // try innerHTML approach
+ var parentTag = this.NODEMAP[elementName] || 'div';
+ var parentElement = document.createElement(parentTag);
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+ } catch(e) {}
+ var element = parentElement.firstChild || null;
+
+ // see if browser added wrapping tags
+ if(element && (element.tagName.toUpperCase() != elementName))
+ element = element.getElementsByTagName(elementName)[0];
+
+ // fallback to createElement approach
+ if(!element) element = document.createElement(elementName);
+
+ // abort if nothing could be created
+ if(!element) return;
+
+ // attributes (or text)
+ if(arguments[1])
+ if(this._isStringOrNumber(arguments[1]) ||
+ (arguments[1] instanceof Array) ||
+ arguments[1].tagName) {
+ this._children(element, arguments[1]);
+ } else {
+ var attrs = this._attributes(arguments[1]);
+ if(attrs.length) {
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" +elementName + " " +
+ attrs + "></" + elementName + ">";
+ } catch(e) {}
+ element = parentElement.firstChild || null;
+ // workaround firefox 1.0.X bug
+ if(!element) {
+ element = document.createElement(elementName);
+ for(attr in arguments[1])
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+ }
+ if(element.tagName.toUpperCase() != elementName)
+ element = parentElement.getElementsByTagName(elementName)[0];
+ }
+ }
+
+ // text, or array of children
+ if(arguments[2])
+ this._children(element, arguments[2]);
+
+ return $(element);
+ },
+ _text: function(text) {
+ return document.createTextNode(text);
+ },
+
+ ATTR_MAP: {
+ 'className': 'class',
+ 'htmlFor': 'for'
+ },
+
+ _attributes: function(attributes) {
+ var attrs = [];
+ for(attribute in attributes)
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
+ return attrs.join(" ");
+ },
+ _children: function(element, children) {
+ if(children.tagName) {
+ element.appendChild(children);
+ return;
+ }
+ if(typeof children=='object') { // array can hold nodes and text
+ children.flatten().each( function(e) {
+ if(typeof e=='object')
+ element.appendChild(e);
+ else
+ if(Builder._isStringOrNumber(e))
+ element.appendChild(Builder._text(e));
+ });
+ } else
+ if(Builder._isStringOrNumber(children))
+ element.appendChild(Builder._text(children));
+ },
+ _isStringOrNumber: function(param) {
+ return(typeof param=='string' || typeof param=='number');
+ },
+ build: function(html) {
+ var element = this.node('div');
+ $(element).update(html.strip());
+ return element.down();
+ },
+ dump: function(scope) {
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each( function(tag){
+ scope[tag] = function() {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ };
+ });
+ }
+}; \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/controls.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/controls.js
new file mode 100644
index 000000000..7392fb664
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/controls.js
@@ -0,0 +1,965 @@
+// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = { };
+Autocompleter.Base = Class.create({
+ baseInitialize: function(element, update, options) {
+ element = $(element);
+ this.element = element;
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+ this.oldElementValue = this.element.value;
+
+ if(this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || { };
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if(typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+ // Force carriage returns as token delimiters anyway
+ if (!this.options.tokens.include('\n'))
+ this.options.tokens.push('\n');
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix &&
+ (Prototype.Browser.IE) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '<iframe id="' + this.update.id + '_iefix" '+
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function() {
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function() {
+ this.stopIndicator();
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--;
+ else this.index = this.entryCount-1;
+ this.getEntry(this.index).scrollIntoView(true);
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++;
+ else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+ var value = '';
+ if (this.options.select) {
+ var nodes = $(selectedElement).select('.' + this.options.select) || [];
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+ } else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+ var bounds = this.getTokenBounds();
+ if (bounds[0] != -1) {
+ var newValue = this.element.value.substr(0, bounds[0]);
+ var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value + this.element.value.substr(bounds[1]);
+ } else {
+ this.element.value = value;
+ }
+ this.oldElementValue = this.element.value;
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.down());
+
+ if(this.update.firstChild && this.update.down().childNodes) {
+ this.entryCount =
+ this.update.down().childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if(this.entryCount==1 && this.options.autoSelect) {
+ this.selectEntry();
+ this.hide();
+ } else {
+ this.render();
+ }
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ this.tokenBounds = null;
+ if(this.getToken().length>=this.options.minChars) {
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ this.oldElementValue = this.element.value;
+ },
+
+ getToken: function() {
+ var bounds = this.getTokenBounds();
+ return this.element.value.substring(bounds[0], bounds[1]).strip();
+ },
+
+ getTokenBounds: function() {
+ if (null != this.tokenBounds) return this.tokenBounds;
+ var value = this.element.value;
+ if (value.strip().empty()) return [-1, 0];
+ var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+ var offset = (diff == this.oldElementValue.length ? 1 : 0);
+ var prevTokenPos = -1, nextTokenPos = value.length;
+ var tp;
+ for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
+ tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+ if (tp > prevTokenPos) prevTokenPos = tp;
+ tp = value.indexOf(this.options.tokens[index], diff + offset);
+ if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+ }
+ return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
+ }
+});
+
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
+ var boundary = Math.min(newS.length, oldS.length);
+ for (var index = 0; index < boundary; ++index)
+ if (newS[index] != oldS[index])
+ return index;
+ return boundary;
+};
+
+Ajax.Autocompleter = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, url, options) {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function() {
+ this.startIndicator();
+
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
+ encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ?
+ this.options.callback(this.element, entry) : entry;
+
+ if(this.options.defaultParams)
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function(request) {
+ this.updateChoices(request.responseText);
+ }
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, array, options) {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function() {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function(instance) {
+ var ret = []; // Beginning matches
+ var partial = []; // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ elem.indexOf(entry);
+
+ while (foundPos != -1) {
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ } else if (entry.length >= instance.options.partialChars &&
+ instance.options.partialSearch && foundPos != -1) {
+ if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+ foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if (partial.length)
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || { });
+ }
+});
+
+// AJAX in-place editor and collection editor
+// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+ setTimeout(function() {
+ Field.activate(field);
+ }, 1);
+};
+
+Ajax.InPlaceEditor = Class.create({
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = element = $(element);
+ this.prepareOptions();
+ this._controls = { };
+ arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+ Object.extend(this.options, options || { });
+ if (!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + '-inplaceeditor';
+ if ($(this.options.formId))
+ this.options.formId = '';
+ }
+ if (this.options.externalControl)
+ this.options.externalControl = $(this.options.externalControl);
+ if (!this.options.externalControl)
+ this.options.externalControlOnly = false;
+ this._originalBackground = this.element.getStyle('background-color') || 'transparent';
+ this.element.title = this.options.clickToEditText;
+ this._boundCancelHandler = this.handleFormCancellation.bind(this);
+ this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+ this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+ this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+ this._boundWrapperHandler = this.wrapUp.bind(this);
+ this.registerListeners();
+ },
+ checkForEscapeOrReturn: function(e) {
+ if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+ if (Event.KEY_ESC == e.keyCode)
+ this.handleFormCancellation(e);
+ else if (Event.KEY_RETURN == e.keyCode)
+ this.handleFormSubmission(e);
+ },
+ createControl: function(mode, handler, extraClasses) {
+ var control = this.options[mode + 'Control'];
+ var text = this.options[mode + 'Text'];
+ if ('button' == control) {
+ var btn = document.createElement('input');
+ btn.type = 'submit';
+ btn.value = text;
+ btn.className = 'editor_' + mode + '_button';
+ if ('cancel' == mode)
+ btn.onclick = this._boundCancelHandler;
+ this._form.appendChild(btn);
+ this._controls[mode] = btn;
+ } else if ('link' == control) {
+ var link = document.createElement('a');
+ link.href = '#';
+ link.appendChild(document.createTextNode(text));
+ link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+ link.className = 'editor_' + mode + '_link';
+ if (extraClasses)
+ link.className += ' ' + extraClasses;
+ this._form.appendChild(link);
+ this._controls[mode] = link;
+ }
+ },
+ createEditField: function() {
+ var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+ var fld;
+ if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
+ fld = document.createElement('input');
+ fld.type = 'text';
+ var size = this.options.size || this.options.cols || 0;
+ if (0 < size) fld.size = size;
+ } else {
+ fld = document.createElement('textarea');
+ fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+ fld.cols = this.options.cols || 40;
+ }
+ fld.name = this.options.paramName;
+ fld.value = text; // No HTML breaks conversion anymore
+ fld.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ fld.onblur = this._boundSubmitHandler;
+ this._controls.editor = fld;
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+ createForm: function() {
+ var ipe = this;
+ function addText(mode, condition) {
+ var text = ipe.options['text' + mode + 'Controls'];
+ if (!text || condition === false) return;
+ ipe._form.appendChild(document.createTextNode(text));
+ };
+ this._form = $(document.createElement('form'));
+ this._form.id = this.options.formId;
+ this._form.addClassName(this.options.formClassName);
+ this._form.onsubmit = this._boundSubmitHandler;
+ this.createEditField();
+ if ('textarea' == this._controls.editor.tagName.toLowerCase())
+ this._form.appendChild(document.createElement('br'));
+ if (this.options.onFormCustomization)
+ this.options.onFormCustomization(this, this._form);
+ addText('Before', this.options.okControl || this.options.cancelControl);
+ this.createControl('ok', this._boundSubmitHandler);
+ addText('Between', this.options.okControl && this.options.cancelControl);
+ this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+ addText('After', this.options.okControl || this.options.cancelControl);
+ },
+ destroy: function() {
+ if (this._oldInnerHTML)
+ this.element.innerHTML = this._oldInnerHTML;
+ this.leaveEditMode();
+ this.unregisterListeners();
+ },
+ enterEditMode: function(e) {
+ if (this._saving || this._editing) return;
+ this._editing = true;
+ this.triggerCallback('onEnterEditMode');
+ if (this.options.externalControl)
+ this.options.externalControl.hide();
+ this.element.hide();
+ this.createForm();
+ this.element.parentNode.insertBefore(this._form, this.element);
+ if (!this.options.loadTextURL)
+ this.postProcessEditField();
+ if (e) Event.stop(e);
+ },
+ enterHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.addClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onEnterHover');
+ },
+ getText: function() {
+ return this.element.innerHTML.unescapeHTML();
+ },
+ handleAJAXFailure: function(transport) {
+ this.triggerCallback('onFailure', transport);
+ if (this._oldInnerHTML) {
+ this.element.innerHTML = this._oldInnerHTML;
+ this._oldInnerHTML = null;
+ }
+ },
+ handleFormCancellation: function(e) {
+ this.wrapUp();
+ if (e) Event.stop(e);
+ },
+ handleFormSubmission: function(e) {
+ var form = this._form;
+ var value = $F(this._controls.editor);
+ this.prepareSubmission();
+ var params = this.options.callback(form, value) || '';
+ if (Object.isString(params))
+ params = params.toQueryParams();
+ params.editorId = this.element.id;
+ if (this.options.htmlResponse) {
+ var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Updater({ success: this.element }, this.url, options);
+ } else {
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.url, options);
+ }
+ if (e) Event.stop(e);
+ },
+ leaveEditMode: function() {
+ this.element.removeClassName(this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ if (this.options.externalControl)
+ this.options.externalControl.show();
+ this._saving = false;
+ this._editing = false;
+ this._oldInnerHTML = null;
+ this.triggerCallback('onLeaveEditMode');
+ },
+ leaveHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.removeClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onLeaveHover');
+ },
+ loadExternalText: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this._controls.editor.disabled = true;
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._form.removeClassName(this.options.loadingClassName);
+ var text = transport.responseText;
+ if (this.options.stripLoadedTextTags)
+ text = text.stripTags();
+ this._controls.editor.value = text;
+ this._controls.editor.disabled = false;
+ this.postProcessEditField();
+ }.bind(this),
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+ postProcessEditField: function() {
+ var fpc = this.options.fieldPostCreation;
+ if (fpc)
+ $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+ },
+ prepareOptions: function() {
+ this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+ Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+ [this._extraDefaultOptions].flatten().compact().each(function(defs) {
+ Object.extend(this.options, defs);
+ }.bind(this));
+ },
+ prepareSubmission: function() {
+ this._saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ registerListeners: function() {
+ this._listeners = { };
+ var listener;
+ $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
+ listener = this[pair.value].bind(this);
+ this._listeners[pair.key] = listener;
+ if (!this.options.externalControlOnly)
+ this.element.observe(pair.key, listener);
+ if (this.options.externalControl)
+ this.options.externalControl.observe(pair.key, listener);
+ }.bind(this));
+ },
+ removeForm: function() {
+ if (!this._form) return;
+ this._form.remove();
+ this._form = null;
+ this._controls = { };
+ },
+ showSaving: function() {
+ this._oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ this.element.addClassName(this.options.savingClassName);
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ },
+ triggerCallback: function(cbName, arg) {
+ if ('function' == typeof this.options[cbName]) {
+ this.options[cbName](this, arg);
+ }
+ },
+ unregisterListeners: function() {
+ $H(this._listeners).each(function(pair) {
+ if (!this.options.externalControlOnly)
+ this.element.stopObserving(pair.key, pair.value);
+ if (this.options.externalControl)
+ this.options.externalControl.stopObserving(pair.key, pair.value);
+ }.bind(this));
+ },
+ wrapUp: function(transport) {
+ this.leaveEditMode();
+ // Can't use triggerCallback due to backward compatibility: requires
+ // binding + direct element
+ this._boundComplete(transport, this.element);
+ }
+});
+
+Object.extend(Ajax.InPlaceEditor.prototype, {
+ dispose: Ajax.InPlaceEditor.prototype.destroy
+});
+
+Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
+ initialize: function($super, element, url, options) {
+ this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+ $super(element, url, options);
+ },
+
+ createEditField: function() {
+ var list = document.createElement('select');
+ list.name = this.options.paramName;
+ list.size = 1;
+ this._controls.editor = list;
+ this._collection = this.options.collection || [];
+ if (this.options.loadCollectionURL)
+ this.loadCollection();
+ else
+ this.checkForExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+
+ loadCollection: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this.showLoadingText(this.options.loadingCollectionText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ var js = transport.responseText.strip();
+ if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+ throw('Server returned an invalid collection representation.');
+ this._collection = eval(js);
+ this.checkForExternalText();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadCollectionURL, options);
+ },
+
+ showLoadingText: function(text) {
+ this._controls.editor.disabled = true;
+ var tempOption = this._controls.editor.firstChild;
+ if (!tempOption) {
+ tempOption = document.createElement('option');
+ tempOption.value = '';
+ this._controls.editor.appendChild(tempOption);
+ tempOption.selected = true;
+ }
+ tempOption.update((text || '').stripScripts().stripTags());
+ },
+
+ checkForExternalText: function() {
+ this._text = this.getText();
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ else
+ this.buildOptionList();
+ },
+
+ loadExternalText: function() {
+ this.showLoadingText(this.options.loadingText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._text = transport.responseText.strip();
+ this.buildOptionList();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+
+ buildOptionList: function() {
+ this._form.removeClassName(this.options.loadingClassName);
+ this._collection = this._collection.map(function(entry) {
+ return 2 === entry.length ? entry : [entry, entry].flatten();
+ });
+ var marker = ('value' in this.options) ? this.options.value : this._text;
+ var textFound = this._collection.any(function(entry) {
+ return entry[0] == marker;
+ }.bind(this));
+ this._controls.editor.update('');
+ var option;
+ this._collection.each(function(entry, index) {
+ option = document.createElement('option');
+ option.value = entry[0];
+ option.selected = textFound ? entry[0] == marker : 0 == index;
+ option.appendChild(document.createTextNode(entry[1]));
+ this._controls.editor.appendChild(option);
+ }.bind(this));
+ this._controls.editor.disabled = false;
+ Field.scrollFreeActivate(this._controls.editor);
+ }
+});
+
+//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
+//**** This only exists for a while, in order to let ****
+//**** users adapt to the new API. Read up on the new ****
+//**** API and convert your code to it ASAP! ****
+
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
+ if (!options) return;
+ function fallback(name, expr) {
+ if (name in options || expr === undefined) return;
+ options[name] = expr;
+ };
+ fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+ options.cancelLink == options.cancelButton == false ? false : undefined)));
+ fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+ options.okLink == options.okButton == false ? false : undefined)));
+ fallback('highlightColor', options.highlightcolor);
+ fallback('highlightEndColor', options.highlightendcolor);
+};
+
+Object.extend(Ajax.InPlaceEditor, {
+ DefaultOptions: {
+ ajaxOptions: { },
+ autoRows: 3, // Use when multi-line w/ rows == 1
+ cancelControl: 'link', // 'link'|'button'|false
+ cancelText: 'cancel',
+ clickToEditText: 'Click to edit',
+ externalControl: null, // id|elt
+ externalControlOnly: false,
+ fieldPostCreation: 'activate', // 'activate'|'focus'|false
+ formClassName: 'inplaceeditor-form',
+ formId: null, // id|elt
+ highlightColor: '#ffff99',
+ highlightEndColor: '#ffffff',
+ hoverClassName: '',
+ htmlResponse: true,
+ loadingClassName: 'inplaceeditor-loading',
+ loadingText: 'Loading...',
+ okControl: 'button', // 'link'|'button'|false
+ okText: 'ok',
+ paramName: 'value',
+ rows: 1, // If 1 and multi-line, uses autoRows
+ savingClassName: 'inplaceeditor-saving',
+ savingText: 'Saving...',
+ size: 0,
+ stripLoadedTextTags: false,
+ submitOnBlur: false,
+ textAfterControls: '',
+ textBeforeControls: '',
+ textBetweenControls: ''
+ },
+ DefaultCallbacks: {
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ onComplete: function(transport, element) {
+ // For backward compatibility, this one is bound to the IPE, and passes
+ // the element directly. It was too often customized, so we don't break it.
+ new Effect.Highlight(element, {
+ startcolor: this.options.highlightColor, keepBackgroundImage: true });
+ },
+ onEnterEditMode: null,
+ onEnterHover: function(ipe) {
+ ipe.element.style.backgroundColor = ipe.options.highlightColor;
+ if (ipe._effect)
+ ipe._effect.cancel();
+ },
+ onFailure: function(transport, ipe) {
+ alert('Error communication with the server: ' + transport.responseText.stripTags());
+ },
+ onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+ onLeaveEditMode: null,
+ onLeaveHover: function(ipe) {
+ ipe._effect = new Effect.Highlight(ipe.element, {
+ startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+ restorecolor: ipe._originalBackground, keepBackgroundImage: true
+ });
+ }
+ },
+ Listeners: {
+ click: 'enterEditMode',
+ keydown: 'checkForEscapeOrReturn',
+ mouseover: 'enterHover',
+ mouseout: 'leaveHover'
+ }
+});
+
+Ajax.InPlaceCollectionEditor.DefaultOptions = {
+ loadingCollectionText: 'Loading options...'
+};
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create({
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+}); \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/dragdrop.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/dragdrop.js
new file mode 100644
index 000000000..15c6dbca6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/dragdrop.js
@@ -0,0 +1,974 @@
+// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(Object.isUndefined(Effect))
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || { });
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if(Object.isArray(containment)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ if(options.accept) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
+
+ isContained: function(element, drop) {
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
+ },
+
+ isAffected: function(point, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(drop.hoverclass)
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(point, element) {
+ if(!this.drops.length) return;
+ var drop, affected = [];
+
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
+ });
+
+ if(affected.length>0)
+ drop = Droppables.findDeepestChild(affected);
+
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
+ if (drop) {
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ if (drop != this.last_active) Droppables.activate(drop);
+ }
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+ if (this.last_active.onDrop) {
+ this.last_active.onDrop(element, this.last_active.element, event);
+ return true;
+ }
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+};
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ } else {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
+ },
+
+ deactivate: function() {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+ },
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create({
+ initialize: function(element) {
+ var defaults = {
+ handle: false,
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ },
+ endeffect: function(element) {
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function(){
+ Draggable._dragging[element] = false
+ }
+ });
+ },
+ zindex: 1000,
+ revert: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
+ Object.extend(defaults, {
+ starteffect: function(element) {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || { });
+
+ this.element = $(element);
+
+ if(options.handle && Object.isString(options.handle))
+ this.handle = this.element.down('.'+options.handle, 0);
+
+ if(!this.handle) this.handle = $(options.handle);
+ if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function() {
+ return([
+ parseInt(Element.getStyle(this.element,'left') || '0'),
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
+ },
+
+ initDrag: function(event) {
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+ Draggable._dragging[this.element]) return;
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = this.element.cumulativeOffset();
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function(event) {
+ this.dragging = true;
+ if(!this.delta)
+ this.delta = this.currentDelta();
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+ if (!this._originallyAbsolute)
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+
+ if(!this.options.quiet){
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ }
+
+ Draggables.notify('onDrag', this, event);
+
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
+
+ Event.stop(event);
+ },
+
+ finishDrag: function(event, success) {
+ this.dragging = false;
+
+ if(this.options.quiet){
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ Droppables.show(pointer, this.element);
+ }
+
+ if(this.options.ghosting) {
+ if (!this._originallyAbsolute)
+ Position.relativize(this.element);
+ delete this._originallyAbsolute;
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ var dropped = false;
+ if(success) {
+ dropped = Droppables.fire(event, this.element);
+ if (!dropped) dropped = false;
+ }
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ if (dropped == 0 || revert != 'failure')
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function(event) {
+ if(event.keyCode!=Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function(event) {
+ if(!this.dragging) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function(point) {
+ var pos = this.element.cumulativeOffset();
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(Object.isFunction(this.options.snap)) {
+ p = this.options.snap(p[0],p[1],this);
+ } else {
+ if(Object.isArray(this.options.snap)) {
+ p = p.map( function(v, i) {
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
+ } else {
+ p = p.map( function(v) {
+ return (v/this.options.snap).round()*this.options.snap }.bind(this));
+ }
+ }}
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ if(!(speed[0] || speed[1])) return;
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+ }
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if (this._isScrollChild) {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight;
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
+ }
+});
+
+Draggable._dragging = { };
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create({
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+});
+
+var Sortable = {
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+
+ sortables: { },
+
+ _findRootElement: function(element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
+ },
+
+ destroy: function(element){
+ element = $(element);
+ var s = Sortable.sortables[element.id];
+
+ if(s) {
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+
+ delete Sortable.sortables[s.element.id];
+ }
+ },
+
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false,
+ treeTag: 'ul',
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ delay: 0,
+ hoverclass: null,
+ ghosting: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+
+ // these take arrays of elements or ids and can be
+ // used for better initialization performance
+ elements: false,
+ handles: false,
+
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || { });
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ quiet: options.quiet,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ tree: options.tree,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover
+ };
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
+ };
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
+ options.droppables.push(element);
+ }
+
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
+ var handle = options.handles ? $(options.handles[i]) :
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
+ options.droppables.push(e);
+ });
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
+
+ // keep reference
+ this.sortables[element.identify()] = options;
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ Sortable.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Sortable._marker.hide();
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker =
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = dropon.cumulativeOffset();
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+ else
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+
+ Sortable._marker.show();
+ },
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: $(children[i]).down(options.treeTag)
+ };
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child);
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ tree: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, arguments[1] || { });
+
+ var root = {
+ id: null,
+ parent: null,
+ children: [],
+ container: element,
+ position: 0
+ };
+
+ return Sortable._tree(element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || { });
+
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || { });
+
+ var nodeMap = { };
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
+ }
+};
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+ if (child.parentNode == element) return true;
+ return Element.isParent(child.parentNode, element);
+};
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+};
+
+Element.offsetSize = function (element, type) {
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}; \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/effects.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/effects.js
new file mode 100644
index 000000000..066ee5909
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/effects.js
@@ -0,0 +1,1123 @@
+// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if (this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if (this.slice(0,1) == '#') {
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if (this.length==7) color = this.toLowerCase();
+ }
+ }
+ return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ return element;
+};
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ Transitions: {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + .5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
+ return pos > 1 ? 1 : pos;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
+ },
+ pulse: function(pos, pulses) {
+ return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
+ },
+ spring: function(pos) {
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+ },
+ DefaultOptions: {
+ duration: 1.0, // seconds
+ fps: 100, // 100= assume 66fps max.
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ },
+ tagifyText: function(element) {
+ var tagifyStyle = 'position:relative';
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if (child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ new Element('span', {style: tagifyStyle}).update(
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if (((typeof element == 'object') ||
+ Object.isFunction(element)) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || { });
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect, options) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+
+ return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, options || {}));
+ }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ var position = Object.isString(effect.options.queue) ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if (!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if (this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ for(var i=0, len=this.effects.length;i<len;i++)
+ this.effects[i] && this.effects[i].loop(timePos);
+ }
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function(queueName) {
+ if (!Object.isString(queueName)) return queueName;
+
+ return this.instances.get(queueName) ||
+ this.instances.set(queueName, new Effect.ScopedQueue());
+ }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+ position: null,
+ start: function(options) {
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn+(this.options.duration*1000);
+ this.fromToDelta = this.options.to-this.options.from;
+ this.totalTime = this.finishOn-this.startOn;
+ this.totalFrames = this.options.fps*this.options.duration;
+
+ this.render = (function() {
+ function dispatch(effect, eventName) {
+ if (effect.options[eventName + 'Internal'])
+ effect.options[eventName + 'Internal'](effect);
+ if (effect.options[eventName])
+ effect.options[eventName](effect);
+ }
+
+ return function(pos) {
+ if (this.state === "idle") {
+ this.state = "running";
+ dispatch(this, 'beforeSetup');
+ if (this.setup) this.setup();
+ dispatch(this, 'afterSetup');
+ }
+ if (this.state === "running") {
+ pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
+ this.position = pos;
+ dispatch(this, 'beforeUpdate');
+ if (this.update) this.update(pos);
+ dispatch(this, 'afterUpdate');
+ }
+ };
+ })();
+
+ this.event('beforeStart');
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).add(this);
+ },
+ loop: function(timePos) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if (this.finish) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / this.totalTime,
+ frame = (pos * this.totalFrames).round();
+ if (frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ cancel: function() {
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).remove(this);
+ this.state = 'finished';
+ },
+ event: function(eventName) {
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if (this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ var data = $H();
+ for(property in this)
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+ initialize: function(effects) {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function(position) {
+ this.effects.invoke('render', position);
+ },
+ finish: function(position) {
+ this.effects.each( function(effect) {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if (effect.finish) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+ initialize: function(object, from, to) {
+ object = Object.isString(object) ? $(object) : object;
+ var args = $A(arguments), method = args.last(),
+ options = args.length == 5 ? args[3] : null;
+ this.method = Object.isFunction(method) ? method.bind(object) :
+ Object.isFunction(object[method]) ? object[method].bind(object) :
+ function(value) { object[method] = value };
+ this.start(Object.extend({ from: from, to: to }, options || { }));
+ },
+ update: function(position) {
+ this.method(position);
+ }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+ initialize: function() {
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+ },
+ update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ // make this work on IE on elements without 'layout'
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ var options = Object.extend({
+ from: this.element.getOpacity() || 0.0,
+ to: 1.0
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ update: function(position) {
+ this.element.setOpacity(position);
+ }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if (this.options.mode == 'absolute') {
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
+ },
+ update: function(position) {
+ this.element.setStyle({
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
+ top: (this.options.y * position + this.originalTop).round() + 'px'
+ });
+ }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+ return new Effect.Move(element,
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+ initialize: function(element, percent) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = this.element.getStyle('position');
+
+ this.originalStyle = { };
+ ['top','left','width','height','fontSize'].each( function(k) {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each( function(fontSizeType) {
+ if (fontSize.indexOf(fontSizeType)>0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ this.dims = null;
+ if (this.options.scaleMode=='box')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if (/^content/.test(this.options.scaleMode))
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if (!this.dims)
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function(position) {
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+ if (this.options.scaleContent && this.fontSize)
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function(position) {
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+ },
+ setDimensions: function(height, width) {
+ var d = { };
+ if (this.options.scaleX) d.width = width.round() + 'px';
+ if (this.options.scaleY) d.height = height.round() + 'px';
+ if (this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ } else {
+ if (this.options.scaleY) d.top = -topd + 'px';
+ if (this.options.scaleX) d.left = -leftd + 'px';
+ }
+ }
+ this.element.setStyle(d);
+ }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ // Prevent executing on elements not in the layout flow
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+ // Disable background image during the effect
+ this.oldStyle = { };
+ if (!this.options.keepBackgroundImage) {
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+ this.element.setStyle({backgroundImage: 'none'});
+ }
+ if (!this.options.endcolor)
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if (!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
+ // init color calculations
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+ },
+ update: function(position) {
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+ },
+ finish: function() {
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = function(element) {
+ var options = arguments[1] || { },
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset();
+
+ if (options.offset) elementOffsets[1] += options.offset;
+
+ return new Effect.Tween(null,
+ scrollOffsets.top,
+ elementOffsets[1],
+ options,
+ function(p){ scrollTo(scrollOffsets.left, p.round()); }
+ );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ var options = Object.extend({
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) {
+ if (effect.options.to!=0) return;
+ effect.element.hide().setStyle({opacity: oldOpacity});
+ }
+ }, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from).show();
+ }}, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+ element = $(element);
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ return new Effect.Parallel(
+ [ new Effect.Scale(element, 200,
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+ Object.extend({ duration: 1.0,
+ beforeSetupInternal: function(effect) {
+ Position.absolutize(effect.effects[0].element);
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().setStyle(oldStyle); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindUp = function(element) {
+ element = $(element);
+ element.makeClipping();
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindDown = function(element) {
+ element = $(element);
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+ }
+ });
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
+ return new Effect.Parallel(
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+ Object.extend(
+ { duration: 0.5,
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ distance: 20,
+ duration: 0.5
+ }, arguments[1] || {});
+ var distance = parseFloat(options.distance);
+ var split = parseFloat(options.duration) / 10.0;
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned().setStyle(oldStyle);
+ }}); }}); }}); }}); }}); }});
+};
+
+Effect.SlideDown = function(element) {
+ element = $(element).cleanWhitespace();
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: window.opera ? 0 : 1,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.SlideUp = function(element) {
+ element = $(element).cleanWhitespace();
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, window.opera ? 0 : 1,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || { })
+ );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
+ restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ });
+};
+
+Effect.Grow = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetup: function(effect) {
+ effect.element.hide().makeClipping().makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ new Effect.Parallel(
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function(effect) {
+ effect.effects[0].element.setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+ }
+ }, options)
+ );
+ }
+ });
+};
+
+Effect.Shrink = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel(
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+ }, options)
+ );
+};
+
+Effect.Pulsate = function(element) {
+ element = $(element);
+ var options = arguments[1] || { },
+ oldOpacity = element.getInlineOpacity(),
+ transition = options.transition || Effect.Transitions.linear,
+ reverser = function(pos){
+ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
+ };
+
+ return new Effect.Opacity(element,
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+ }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ element.makeClipping();
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().setStyle(oldStyle);
+ } });
+ }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ style: { }
+ }, arguments[1] || { });
+
+ if (!Object.isString(options.style)) this.style = $H(options.style);
+ else {
+ if (options.style.include(':'))
+ this.style = options.style.parseStyle();
+ else {
+ this.element.addClassName(options.style);
+ this.style = $H(this.element.getStyles());
+ this.element.removeClassName(options.style);
+ var css = this.element.getStyles();
+ this.style = this.style.reject(function(style) {
+ return style.value == css[style.key];
+ });
+ options.afterFinishInternal = function(effect) {
+ effect.element.addClassName(effect.options.style);
+ effect.transforms.each(function(transform) {
+ effect.element.style[transform.style] = '';
+ });
+ };
+ }
+ }
+ this.start(options);
+ },
+
+ setup: function(){
+ function parseColor(color){
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+ color = color.parseColor();
+ return $R(0,2).map(function(i){
+ return parseInt( color.slice(i*2+1,i*2+3), 16 );
+ });
+ }
+ this.transforms = this.style.map(function(pair){
+ var property = pair[0], value = pair[1], unit = null;
+
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+ value = value.parseColor();
+ unit = 'color';
+ } else if (property == 'opacity') {
+ value = parseFloat(value);
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ } else if (Element.CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ }
+
+ var originalValue = this.element.getStyle(property);
+ return {
+ style: property.camelize(),
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+ targetValue: unit=='color' ? parseColor(value) : value,
+ unit: unit
+ };
+ }.bind(this)).reject(function(transform){
+ return (
+ (transform.originalValue == transform.targetValue) ||
+ (
+ transform.unit != 'color' &&
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+ )
+ );
+ });
+ },
+ update: function(position) {
+ var style = { }, transform, i = this.transforms.length;
+ while(i--)
+ style[(transform = this.transforms[i]).style] =
+ transform.unit=='color' ? '#'+
+ (Math.round(transform.originalValue[0]+
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+ (Math.round(transform.originalValue[1]+
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+ (Math.round(transform.originalValue[2]+
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+ (transform.originalValue +
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+ (transform.unit === null ? '' : transform.unit);
+ this.element.setStyle(style, true);
+ }
+});
+
+Effect.Transform = Class.create({
+ initialize: function(tracks){
+ this.tracks = [];
+ this.options = arguments[1] || { };
+ this.addTracks(tracks);
+ },
+ addTracks: function(tracks){
+ tracks.each(function(track){
+ track = $H(track);
+ var data = track.values().first();
+ this.tracks.push($H({
+ ids: track.keys().first(),
+ effect: Effect.Morph,
+ options: { style: data }
+ }));
+ }.bind(this));
+ return this;
+ },
+ play: function(){
+ return new Effect.Parallel(
+ this.tracks.map(function(track){
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+ var elements = [$(ids) || $$(ids)].flatten();
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+ }).flatten(),
+ this.options
+ );
+ }
+});
+
+Element.CSS_PROPERTIES = $w(
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+ 'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+ var style, styleRules = $H();
+ if (Prototype.Browser.WebKit)
+ style = new Element('div',{style:this}).style;
+ else {
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+ style = String.__parseStyleElement.childNodes[0].style;
+ }
+
+ Element.CSS_PROPERTIES.each(function(property){
+ if (style[property]) styleRules.set(property, style[property]);
+ });
+
+ if (Prototype.Browser.IE && this.include('opacity'))
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+ return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+ Element.getStyles = function(element) {
+ var css = document.defaultView.getComputedStyle($(element), null);
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+ styles[property] = css[property];
+ return styles;
+ });
+ };
+} else {
+ Element.getStyles = function(element) {
+ element = $(element);
+ var css = element.currentStyle, styles;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+ results[property] = css[property];
+ return results;
+ });
+ if (!styles.opacity) styles.opacity = element.getOpacity();
+ return styles;
+ };
+}
+
+Effect.Methods = {
+ morph: function(element, style) {
+ element = $(element);
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+ return element;
+ },
+ visualEffect: function(element, effect, options) {
+ element = $(element);
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[klass](element, options);
+ return element;
+ },
+ highlight: function(element, options) {
+ element = $(element);
+ new Effect.Highlight(element, options);
+ return element;
+ }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+ 'pulsate shake puff squish switchOff dropOut').each(
+ function(effect) {
+ Effect.Methods[effect] = function(element, options){
+ element = $(element);
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+ return element;
+ };
+ }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+ function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods); \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/scriptaculous.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/scriptaculous.js
new file mode 100644
index 000000000..6bf437acc
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/scriptaculous.js
@@ -0,0 +1,68 @@
+// script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+ Version: '1.8.3',
+ require: function(libraryName) {
+ try{
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+ } catch(e) {
+ // for xhtml+xml served content, fall back to DOM methods
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = libraryName;
+ document.getElementsByTagName('head')[0].appendChild(script);
+ }
+ },
+ REQUIRED_PROTOTYPE: '1.6.0.3',
+ load: function() {
+ function convertVersionString(versionString) {
+ var v = versionString.replace(/_.*|\./g, '');
+ v = parseInt(v + '0'.times(4-v.length));
+ return versionString.indexOf('_') > -1 ? v-1 : v;
+ }
+
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ (convertVersionString(Prototype.Version) <
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+ Scriptaculous.REQUIRED_PROTOTYPE);
+
+ var js = /scriptaculous\.js(\?.*)?$/;
+ $$('head script[src]').findAll(function(s) {
+ return s.src.match(js);
+ }).each(function(s) {
+ var path = s.src.replace(js, ''),
+ includes = s.src.match(/\?.*load=([a-z,]*)/);
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+ function(include) { Scriptaculous.require(path+include+'.js') });
+ });
+ }
+};
+
+Scriptaculous.load(); \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/slider.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/slider.js
new file mode 100644
index 000000000..eb8305582
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/slider.js
@@ -0,0 +1,275 @@
+// script.aculo.us slider.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Marty Haught, Thomas Fuchs
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if (!Control) var Control = { };
+
+// options:
+// axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+// onChange(value)
+// onSlide(value)
+Control.Slider = Class.create({
+ initialize: function(handle, track, options) {
+ var slider = this;
+
+ if (Object.isArray(handle)) {
+ this.handles = handle.collect( function(e) { return $(e) });
+ } else {
+ this.handles = [$(handle)];
+ }
+
+ this.track = $(track);
+ this.options = options || { };
+
+ this.axis = this.options.axis || 'horizontal';
+ this.increment = this.options.increment || 1;
+ this.step = parseInt(this.options.step || '1');
+ this.range = this.options.range || $R(0,1);
+
+ this.value = 0; // assure backwards compat
+ this.values = this.handles.map( function() { return 0 });
+ this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+ this.options.startSpan = $(this.options.startSpan || null);
+ this.options.endSpan = $(this.options.endSpan || null);
+
+ this.restricted = this.options.restricted || false;
+
+ this.maximum = this.options.maximum || this.range.end;
+ this.minimum = this.options.minimum || this.range.start;
+
+ // Will be used to align the handle onto the track, if necessary
+ this.alignX = parseInt(this.options.alignX || '0');
+ this.alignY = parseInt(this.options.alignY || '0');
+
+ this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+ this.handleLength = this.isVertical() ?
+ (this.handles[0].offsetHeight != 0 ?
+ this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
+ (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
+ this.handles[0].style.width.replace(/px$/,""));
+
+ this.active = false;
+ this.dragging = false;
+ this.disabled = false;
+
+ if (this.options.disabled) this.setDisabled();
+
+ // Allowed values array
+ this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+ if (this.allowedValues) {
+ this.minimum = this.allowedValues.min();
+ this.maximum = this.allowedValues.max();
+ }
+
+ this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.update.bindAsEventListener(this);
+
+ // Initialize handles in reverse (make sure first handle is active)
+ this.handles.each( function(h,i) {
+ i = slider.handles.length-1-i;
+ slider.setValue(parseFloat(
+ (Object.isArray(slider.options.sliderValue) ?
+ slider.options.sliderValue[i] : slider.options.sliderValue) ||
+ slider.range.start), i);
+ h.makePositioned().observe("mousedown", slider.eventMouseDown);
+ });
+
+ this.track.observe("mousedown", this.eventMouseDown);
+ document.observe("mouseup", this.eventMouseUp);
+ document.observe("mousemove", this.eventMouseMove);
+
+ this.initialized = true;
+ },
+ dispose: function() {
+ var slider = this;
+ Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ this.handles.each( function(h) {
+ Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+ });
+ },
+ setDisabled: function(){
+ this.disabled = true;
+ },
+ setEnabled: function(){
+ this.disabled = false;
+ },
+ getNearestValue: function(value){
+ if (this.allowedValues){
+ if (value >= this.allowedValues.max()) return(this.allowedValues.max());
+ if (value <= this.allowedValues.min()) return(this.allowedValues.min());
+
+ var offset = Math.abs(this.allowedValues[0] - value);
+ var newValue = this.allowedValues[0];
+ this.allowedValues.each( function(v) {
+ var currentOffset = Math.abs(v - value);
+ if (currentOffset <= offset){
+ newValue = v;
+ offset = currentOffset;
+ }
+ });
+ return newValue;
+ }
+ if (value > this.range.end) return this.range.end;
+ if (value < this.range.start) return this.range.start;
+ return value;
+ },
+ setValue: function(sliderValue, handleIdx){
+ if (!this.active) {
+ this.activeHandleIdx = handleIdx || 0;
+ this.activeHandle = this.handles[this.activeHandleIdx];
+ this.updateStyles();
+ }
+ handleIdx = handleIdx || this.activeHandleIdx || 0;
+ if (this.initialized && this.restricted) {
+ if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+ sliderValue = this.values[handleIdx-1];
+ if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+ sliderValue = this.values[handleIdx+1];
+ }
+ sliderValue = this.getNearestValue(sliderValue);
+ this.values[handleIdx] = sliderValue;
+ this.value = this.values[0]; // assure backwards compat
+
+ this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
+ this.translateToPx(sliderValue);
+
+ this.drawSpans();
+ if (!this.dragging || !this.event) this.updateFinished();
+ },
+ setValueBy: function(delta, handleIdx) {
+ this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
+ handleIdx || this.activeHandleIdx || 0);
+ },
+ translateToPx: function(value) {
+ return Math.round(
+ ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
+ (value - this.range.start)) + "px";
+ },
+ translateToValue: function(offset) {
+ return ((offset/(this.trackLength-this.handleLength) *
+ (this.range.end-this.range.start)) + this.range.start);
+ },
+ getRange: function(range) {
+ var v = this.values.sortBy(Prototype.K);
+ range = range || 0;
+ return $R(v[range],v[range+1]);
+ },
+ minimumOffset: function(){
+ return(this.isVertical() ? this.alignY : this.alignX);
+ },
+ maximumOffset: function(){
+ return(this.isVertical() ?
+ (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+ this.track.style.height.replace(/px$/,"")) - this.alignY :
+ (this.track.offsetWidth != 0 ? this.track.offsetWidth :
+ this.track.style.width.replace(/px$/,"")) - this.alignX);
+ },
+ isVertical: function(){
+ return (this.axis == 'vertical');
+ },
+ drawSpans: function() {
+ var slider = this;
+ if (this.spans)
+ $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
+ if (this.options.startSpan)
+ this.setSpan(this.options.startSpan,
+ $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
+ if (this.options.endSpan)
+ this.setSpan(this.options.endSpan,
+ $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
+ },
+ setSpan: function(span, range) {
+ if (this.isVertical()) {
+ span.style.top = this.translateToPx(range.start);
+ span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+ } else {
+ span.style.left = this.translateToPx(range.start);
+ span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+ }
+ },
+ updateStyles: function() {
+ this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
+ Element.addClassName(this.activeHandle, 'selected');
+ },
+ startDrag: function(event) {
+ if (Event.isLeftClick(event)) {
+ if (!this.disabled){
+ this.active = true;
+
+ var handle = Event.element(event);
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var track = handle;
+ if (track==this.track) {
+ var offsets = this.track.cumulativeOffset();
+ this.event = event;
+ this.setValue(this.translateToValue(
+ (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
+ ));
+ var offsets = this.activeHandle.cumulativeOffset();
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ } else {
+ // find the handle (prevents issues with Safari)
+ while((this.handles.indexOf(handle) == -1) && handle.parentNode)
+ handle = handle.parentNode;
+
+ if (this.handles.indexOf(handle)!=-1) {
+ this.activeHandle = handle;
+ this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+ this.updateStyles();
+
+ var offsets = this.activeHandle.cumulativeOffset();
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ }
+ }
+ }
+ Event.stop(event);
+ }
+ },
+ update: function(event) {
+ if (this.active) {
+ if (!this.dragging) this.dragging = true;
+ this.draw(event);
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ Event.stop(event);
+ }
+ },
+ draw: function(event) {
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var offsets = this.track.cumulativeOffset();
+ pointer[0] -= this.offsetX + offsets[0];
+ pointer[1] -= this.offsetY + offsets[1];
+ this.event = event;
+ this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+ if (this.initialized && this.options.onSlide)
+ this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
+ },
+ endDrag: function(event) {
+ if (this.active && this.dragging) {
+ this.finishDrag(event, true);
+ Event.stop(event);
+ }
+ this.active = false;
+ this.dragging = false;
+ },
+ finishDrag: function(event, success) {
+ this.active = false;
+ this.dragging = false;
+ this.updateFinished();
+ },
+ updateFinished: function() {
+ if (this.initialized && this.options.onChange)
+ this.options.onChange(this.values.length>1 ? this.values : this.value, this);
+ this.event = null;
+ }
+}); \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/sound.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/sound.js
new file mode 100644
index 000000000..a286eb98e
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/sound.js
@@ -0,0 +1,59 @@
+// script.aculo.us sound.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Based on code created by Jules Gravinese (http://www.webveteran.com/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+Sound = {
+ tracks: {},
+ _enabled: true,
+ template:
+ new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),
+ enable: function(){
+ Sound._enabled = true;
+ },
+ disable: function(){
+ Sound._enabled = false;
+ },
+ play: function(url){
+ if(!Sound._enabled) return;
+ var options = Object.extend({
+ track: 'global', url: url, replace: false
+ }, arguments[1] || {});
+
+ if(options.replace && this.tracks[options.track]) {
+ $R(0, this.tracks[options.track].id).each(function(id){
+ var sound = $('sound_'+options.track+'_'+id);
+ sound.Stop && sound.Stop();
+ sound.remove();
+ });
+ this.tracks[options.track] = null;
+ }
+
+ if(!this.tracks[options.track])
+ this.tracks[options.track] = { id: 0 };
+ else
+ this.tracks[options.track].id++;
+
+ options.id = this.tracks[options.track].id;
+ $$('body')[0].insert(
+ Prototype.Browser.IE ? new Element('bgsound',{
+ id: 'sound_'+options.track+'_'+options.id,
+ src: options.url, loop: 1, autostart: true
+ }) : Sound.template.evaluate(options));
+ }
+};
+
+if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
+ if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
+ Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>');
+ else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('Windows Media') != -1 }))
+ Sound.template = new Template('<object id="sound_#{track}_#{id}" type="application/x-mplayer2" data="#{url}"></object>');
+ else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('RealPlayer') != -1 }))
+ Sound.template = new Template('<embed type="audio/x-pn-realaudio-plugin" style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>');
+ else
+ Sound.play = function(){};
+} \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/unittest.js b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/unittest.js
new file mode 100644
index 000000000..33a0c7157
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/src/unittest.js
@@ -0,0 +1,568 @@
+// script.aculo.us unittest.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
+// (c) 2005-2009 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// experimental, Firefox-only
+Event.simulateMouse = function(element, eventName) {
+ var options = Object.extend({
+ pointerX: 0,
+ pointerY: 0,
+ buttons: 0,
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false
+ }, arguments[2] || {});
+ var oEvent = document.createEvent("MouseEvents");
+ oEvent.initMouseEvent(eventName, true, true, document.defaultView,
+ options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
+ options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
+
+ if(this.mark) Element.remove(this.mark);
+ this.mark = document.createElement('div');
+ this.mark.appendChild(document.createTextNode(" "));
+ document.body.appendChild(this.mark);
+ this.mark.style.position = 'absolute';
+ this.mark.style.top = options.pointerY + "px";
+ this.mark.style.left = options.pointerX + "px";
+ this.mark.style.width = "5px";
+ this.mark.style.height = "5px;";
+ this.mark.style.borderTop = "1px solid red;";
+ this.mark.style.borderLeft = "1px solid red;";
+
+ if(this.step)
+ alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
+
+ $(element).dispatchEvent(oEvent);
+};
+
+// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
+// You need to downgrade to 1.0.4 for now to get this working
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
+Event.simulateKey = function(element, eventName) {
+ var options = Object.extend({
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false,
+ keyCode: 0,
+ charCode: 0
+ }, arguments[2] || {});
+
+ var oEvent = document.createEvent("KeyEvents");
+ oEvent.initKeyEvent(eventName, true, true, window,
+ options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
+ options.keyCode, options.charCode );
+ $(element).dispatchEvent(oEvent);
+};
+
+Event.simulateKeys = function(element, command) {
+ for(var i=0; i<command.length; i++) {
+ Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
+ }
+};
+
+var Test = {};
+Test.Unit = {};
+
+// security exception workaround
+Test.Unit.inspect = Object.inspect;
+
+Test.Unit.Logger = Class.create();
+Test.Unit.Logger.prototype = {
+ initialize: function(log) {
+ this.log = $(log);
+ if (this.log) {
+ this._createLogTable();
+ }
+ },
+ start: function(testName) {
+ if (!this.log) return;
+ this.testName = testName;
+ this.lastLogLine = document.createElement('tr');
+ this.statusCell = document.createElement('td');
+ this.nameCell = document.createElement('td');
+ this.nameCell.className = "nameCell";
+ this.nameCell.appendChild(document.createTextNode(testName));
+ this.messageCell = document.createElement('td');
+ this.lastLogLine.appendChild(this.statusCell);
+ this.lastLogLine.appendChild(this.nameCell);
+ this.lastLogLine.appendChild(this.messageCell);
+ this.loglines.appendChild(this.lastLogLine);
+ },
+ finish: function(status, summary) {
+ if (!this.log) return;
+ this.lastLogLine.className = status;
+ this.statusCell.innerHTML = status;
+ this.messageCell.innerHTML = this._toHTML(summary);
+ this.addLinksToResults();
+ },
+ message: function(message) {
+ if (!this.log) return;
+ this.messageCell.innerHTML = this._toHTML(message);
+ },
+ summary: function(summary) {
+ if (!this.log) return;
+ this.logsummary.innerHTML = this._toHTML(summary);
+ },
+ _createLogTable: function() {
+ this.log.innerHTML =
+ '<div id="logsummary"></div>' +
+ '<table id="logtable">' +
+ '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+ '<tbody id="loglines"></tbody>' +
+ '</table>';
+ this.logsummary = $('logsummary');
+ this.loglines = $('loglines');
+ },
+ _toHTML: function(txt) {
+ return txt.escapeHTML().replace(/\n/g,"<br/>");
+ },
+ addLinksToResults: function(){
+ $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
+ td.title = "Run only this test";
+ Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
+ });
+ $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
+ td.title = "Run all tests";
+ Event.observe(td, 'click', function(){ window.location.search = "";});
+ });
+ }
+};
+
+Test.Unit.Runner = Class.create();
+Test.Unit.Runner.prototype = {
+ initialize: function(testcases) {
+ this.options = Object.extend({
+ testLog: 'testlog'
+ }, arguments[1] || {});
+ this.options.resultsURL = this.parseResultsURLQueryParameter();
+ this.options.tests = this.parseTestsQueryParameter();
+ if (this.options.testLog) {
+ this.options.testLog = $(this.options.testLog) || null;
+ }
+ if(this.options.tests) {
+ this.tests = [];
+ for(var i = 0; i < this.options.tests.length; i++) {
+ if(/^test/.test(this.options.tests[i])) {
+ this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
+ }
+ }
+ } else {
+ if (this.options.test) {
+ this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
+ } else {
+ this.tests = [];
+ for(var testcase in testcases) {
+ if(/^test/.test(testcase)) {
+ this.tests.push(
+ new Test.Unit.Testcase(
+ this.options.context ? ' -> ' + this.options.titles[testcase] : testcase,
+ testcases[testcase], testcases["setup"], testcases["teardown"]
+ ));
+ }
+ }
+ }
+ }
+ this.currentTest = 0;
+ this.logger = new Test.Unit.Logger(this.options.testLog);
+ setTimeout(this.runTests.bind(this), 1000);
+ },
+ parseResultsURLQueryParameter: function() {
+ return window.location.search.parseQuery()["resultsURL"];
+ },
+ parseTestsQueryParameter: function(){
+ if (window.location.search.parseQuery()["tests"]){
+ return window.location.search.parseQuery()["tests"].split(',');
+ };
+ },
+ // Returns:
+ // "ERROR" if there was an error,
+ // "FAILURE" if there was a failure, or
+ // "SUCCESS" if there was neither
+ getResult: function() {
+ var hasFailure = false;
+ for(var i=0;i<this.tests.length;i++) {
+ if (this.tests[i].errors > 0) {
+ return "ERROR";
+ }
+ if (this.tests[i].failures > 0) {
+ hasFailure = true;
+ }
+ }
+ if (hasFailure) {
+ return "FAILURE";
+ } else {
+ return "SUCCESS";
+ }
+ },
+ postResults: function() {
+ if (this.options.resultsURL) {
+ new Ajax.Request(this.options.resultsURL,
+ { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
+ }
+ },
+ runTests: function() {
+ var test = this.tests[this.currentTest];
+ if (!test) {
+ // finished!
+ this.postResults();
+ this.logger.summary(this.summary());
+ return;
+ }
+ if(!test.isWaiting) {
+ this.logger.start(test.name);
+ }
+ test.run();
+ if(test.isWaiting) {
+ this.logger.message("Waiting for " + test.timeToWait + "ms");
+ setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
+ } else {
+ this.logger.finish(test.status(), test.summary());
+ this.currentTest++;
+ // tail recursive, hopefully the browser will skip the stackframe
+ this.runTests();
+ }
+ },
+ summary: function() {
+ var assertions = 0;
+ var failures = 0;
+ var errors = 0;
+ var messages = [];
+ for(var i=0;i<this.tests.length;i++) {
+ assertions += this.tests[i].assertions;
+ failures += this.tests[i].failures;
+ errors += this.tests[i].errors;
+ }
+ return (
+ (this.options.context ? this.options.context + ': ': '') +
+ this.tests.length + " tests, " +
+ assertions + " assertions, " +
+ failures + " failures, " +
+ errors + " errors");
+ }
+};
+
+Test.Unit.Assertions = Class.create();
+Test.Unit.Assertions.prototype = {
+ initialize: function() {
+ this.assertions = 0;
+ this.failures = 0;
+ this.errors = 0;
+ this.messages = [];
+ },
+ summary: function() {
+ return (
+ this.assertions + " assertions, " +
+ this.failures + " failures, " +
+ this.errors + " errors" + "\n" +
+ this.messages.join("\n"));
+ },
+ pass: function() {
+ this.assertions++;
+ },
+ fail: function(message) {
+ this.failures++;
+ this.messages.push("Failure: " + message);
+ },
+ info: function(message) {
+ this.messages.push("Info: " + message);
+ },
+ error: function(error) {
+ this.errors++;
+ this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
+ },
+ status: function() {
+ if (this.failures > 0) return 'failed';
+ if (this.errors > 0) return 'error';
+ return 'passed';
+ },
+ assert: function(expression) {
+ var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
+ try { expression ? this.pass() :
+ this.fail(message); }
+ catch(e) { this.error(e); }
+ },
+ assertEqual: function(expected, actual) {
+ var message = arguments[2] || "assertEqual";
+ try { (expected == actual) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertInspect: function(expected, actual) {
+ var message = arguments[2] || "assertInspect";
+ try { (expected == actual.inspect()) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertEnumEqual: function(expected, actual) {
+ var message = arguments[2] || "assertEnumEqual";
+ try { $A(expected).length == $A(actual).length &&
+ expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
+ this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
+ ', actual ' + Test.Unit.inspect(actual)); }
+ catch(e) { this.error(e); }
+ },
+ assertNotEqual: function(expected, actual) {
+ var message = arguments[2] || "assertNotEqual";
+ try { (expected != actual) ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertIdentical: function(expected, actual) {
+ var message = arguments[2] || "assertIdentical";
+ try { (expected === actual) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotIdentical: function(expected, actual) {
+ var message = arguments[2] || "assertNotIdentical";
+ try { !(expected === actual) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNull: function(obj) {
+ var message = arguments[1] || 'assertNull';
+ try { (obj==null) ? this.pass() :
+ this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertMatch: function(expected, actual) {
+ var message = arguments[2] || 'assertMatch';
+ var regex = new RegExp(expected);
+ try { (regex.exec(actual)) ? this.pass() :
+ this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertHidden: function(element) {
+ var message = arguments[1] || 'assertHidden';
+ this.assertEqual("none", element.style.display, message);
+ },
+ assertNotNull: function(object) {
+ var message = arguments[1] || 'assertNotNull';
+ this.assert(object != null, message);
+ },
+ assertType: function(expected, actual) {
+ var message = arguments[2] || 'assertType';
+ try {
+ (actual.constructor == expected) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + (actual.constructor) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotOfType: function(expected, actual) {
+ var message = arguments[2] || 'assertNotOfType';
+ try {
+ (actual.constructor != expected) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + (actual.constructor) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertInstanceOf: function(expected, actual) {
+ var message = arguments[2] || 'assertInstanceOf';
+ try {
+ (actual instanceof expected) ? this.pass() :
+ this.fail(message + ": object was not an instance of the expected type"); }
+ catch(e) { this.error(e); }
+ },
+ assertNotInstanceOf: function(expected, actual) {
+ var message = arguments[2] || 'assertNotInstanceOf';
+ try {
+ !(actual instanceof expected) ? this.pass() :
+ this.fail(message + ": object was an instance of the not expected type"); }
+ catch(e) { this.error(e); }
+ },
+ assertRespondsTo: function(method, obj) {
+ var message = arguments[2] || 'assertRespondsTo';
+ try {
+ (obj[method] && typeof obj[method] == 'function') ? this.pass() :
+ this.fail(message + ": object doesn't respond to [" + method + "]"); }
+ catch(e) { this.error(e); }
+ },
+ assertReturnsTrue: function(method, obj) {
+ var message = arguments[2] || 'assertReturnsTrue';
+ try {
+ var m = obj[method];
+ if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+ m() ? this.pass() :
+ this.fail(message + ": method returned false"); }
+ catch(e) { this.error(e); }
+ },
+ assertReturnsFalse: function(method, obj) {
+ var message = arguments[2] || 'assertReturnsFalse';
+ try {
+ var m = obj[method];
+ if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+ !m() ? this.pass() :
+ this.fail(message + ": method returned true"); }
+ catch(e) { this.error(e); }
+ },
+ assertRaise: function(exceptionName, method) {
+ var message = arguments[2] || 'assertRaise';
+ try {
+ method();
+ this.fail(message + ": exception expected but none was raised"); }
+ catch(e) {
+ ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e);
+ }
+ },
+ assertElementsMatch: function() {
+ var expressions = $A(arguments), elements = $A(expressions.shift());
+ if (elements.length != expressions.length) {
+ this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
+ return false;
+ }
+ elements.zip(expressions).all(function(pair, index) {
+ var element = $(pair.first()), expression = pair.last();
+ if (element.match(expression)) return true;
+ this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
+ }.bind(this)) && this.pass();
+ },
+ assertElementMatches: function(element, expression) {
+ this.assertElementsMatch([element], expression);
+ },
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
+ },
+ _isVisible: function(element) {
+ element = $(element);
+ if(!element.parentNode) return true;
+ this.assertNotNull(element);
+ if(element.style && Element.getStyle(element, 'display') == 'none')
+ return false;
+
+ return this._isVisible(element.parentNode);
+ },
+ assertNotVisible: function(element) {
+ this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
+ },
+ assertVisible: function(element) {
+ this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
+ },
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
+ }
+};
+
+Test.Unit.Testcase = Class.create();
+Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
+ initialize: function(name, test, setup, teardown) {
+ Test.Unit.Assertions.prototype.initialize.bind(this)();
+ this.name = name;
+
+ if(typeof test == 'string') {
+ test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
+ test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
+ this.test = function() {
+ eval('with(this){'+test+'}');
+ }
+ } else {
+ this.test = test || function() {};
+ }
+
+ this.setup = setup || function() {};
+ this.teardown = teardown || function() {};
+ this.isWaiting = false;
+ this.timeToWait = 1000;
+ },
+ wait: function(time, nextPart) {
+ this.isWaiting = true;
+ this.test = nextPart;
+ this.timeToWait = time;
+ },
+ run: function() {
+ try {
+ try {
+ if (!this.isWaiting) this.setup.bind(this)();
+ this.isWaiting = false;
+ this.test.bind(this)();
+ } finally {
+ if(!this.isWaiting) {
+ this.teardown.bind(this)();
+ }
+ }
+ }
+ catch(e) { this.error(e); }
+ }
+});
+
+// *EXPERIMENTAL* BDD-style testing to please non-technical folk
+// This draws many ideas from RSpec http://rspec.rubyforge.org/
+
+Test.setupBDDExtensionMethods = function(){
+ var METHODMAP = {
+ shouldEqual: 'assertEqual',
+ shouldNotEqual: 'assertNotEqual',
+ shouldEqualEnum: 'assertEnumEqual',
+ shouldBeA: 'assertType',
+ shouldNotBeA: 'assertNotOfType',
+ shouldBeAn: 'assertType',
+ shouldNotBeAn: 'assertNotOfType',
+ shouldBeNull: 'assertNull',
+ shouldNotBeNull: 'assertNotNull',
+
+ shouldBe: 'assertReturnsTrue',
+ shouldNotBe: 'assertReturnsFalse',
+ shouldRespondTo: 'assertRespondsTo'
+ };
+ var makeAssertion = function(assertion, args, object) {
+ this[assertion].apply(this,(args || []).concat([object]));
+ };
+
+ Test.BDDMethods = {};
+ $H(METHODMAP).each(function(pair) {
+ Test.BDDMethods[pair.key] = function() {
+ var args = $A(arguments);
+ var scope = args.shift();
+ makeAssertion.apply(scope, [pair.value, args, this]); };
+ });
+
+ [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each(
+ function(p){ Object.extend(p, Test.BDDMethods) }
+ );
+};
+
+Test.context = function(name, spec, log){
+ Test.setupBDDExtensionMethods();
+
+ var compiledSpec = {};
+ var titles = {};
+ for(specName in spec) {
+ switch(specName){
+ case "setup":
+ case "teardown":
+ compiledSpec[specName] = spec[specName];
+ break;
+ default:
+ var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
+ var body = spec[specName].toString().split('\n').slice(1);
+ if(/^\{/.test(body[0])) body = body.slice(1);
+ body.pop();
+ body = body.map(function(statement){
+ return statement.strip()
+ });
+ compiledSpec[testName] = body.join('\n');
+ titles[testName] = specName;
+ }
+ }
+ new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
+}; \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_result.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_result.html
new file mode 100644
index 000000000..55dcbeae1
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_result.html
@@ -0,0 +1 @@
+Server received: To be edited \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_text.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_text.html
new file mode 100644
index 000000000..a6f35d132
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_ajax_inplaceeditor_text.html
@@ -0,0 +1 @@
+Text from server \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result.html
new file mode 100644
index 000000000..8ecd6c51f
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result.html
@@ -0,0 +1,9 @@
+<ul>
+ <li>test1<span class="selectme">selectme1</span></li><li><span class="selectme">selectme2</span>test2</li>
+ <li>test3<span class="selectme">selectme3</span></li>
+<li><b>BOLD</b><span class="selectme">selectme4<b>boldinselectme</b></span></li>
+
+ <li><span class="informal">(GET ME NOT)</span>(GET &lt;ME&gt; INSTEAD)<span class="selectme">(forselectme!)</span></li>
+
+ <li><span class="selectme">Here we have <a href="_autocomplete_result.html">a link</a> which should work</span></li>
+</ul> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result_single.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result_single.html
new file mode 100644
index 000000000..d6f66fb04
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/_autocomplete_result_single.html
@@ -0,0 +1,3 @@
+<ul>
+ <li>test1<span class="selectme">selectme1</span></li>
+</ul> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter2_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter2_test.html
new file mode 100644
index 000000000..53e8aec58
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter2_test.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Autocompleter functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ .selected { background-color: #888; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Autocompleter functional test file</h1>
+
+
+
+This is an incremental Ajax autocompleter. Type something, then type a comma, than type more. This autocompleter features an indicator.<br/>
+<div id="ac1_indicator" style="display:none">NOW FETCHING RESULTS</div>
+Autocompleter ac1: <input type="text" id="ac1" autocomplete="off"/>
+<div id="ac1update" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac1','ac1update','_autocomplete_result.html', {
+ tokens: ',', indicator: 'ac1_indicator'
+ } );
+// ]]>
+</script>
+
+<br/><br/>
+Non-incremental Ajax autocompleter.<br/>
+Autocompleter ac2: <input id="ac2" type="text" autocomplete="off"/>
+<div id="ac2update" style="display:none;border:1px solid black;background-color:white;"></div>
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac2','ac2update','_autocomplete_result.html');
+// ]]>
+</script>
+
+<br/><br/>
+Non-incremental Ajax autocompleter.<br/>
+Autocompleter ac3: <input id="ac3" type="text" autocomplete="off"/>
+<div id="ac3update" style="display:none;border:1px solid black;background-color:white;"></div>
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac3','ac3update','_autocomplete_result.html');
+// ]]>
+</script>
+
+<br/><br/>
+
+Local incremental array autocompleter ac4<br/> with full-search. Type 'Jac', hit enter a few <br/>times, type 'gne'.<br/> <textarea rows=5 cols=40 id="ac4" autocomplete="off"></textarea>
+<div id="ac4update" style="display:none;border:1px solid black;background-color:white;"></div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Autocompleter.Local('ac4','ac4update',
+ new Array("John Jackson", "", "Jack Johnson", "", "Jane Agnews"), { tokens: new Array(',','\n'), fullSearch: true, partialSearch: true });
+// ]]>
+</script>
+<br/><br/>
+
+Local incremental array autocompleter ac5<br/> with fixed height and scrollbar. Type 'Jac', hit enter a few <br/>times, type 'gne'.<br/> <input id="ac5" type="text" autocomplete="off"/>
+<div id="ac5update" style="display:none;border:1px solid black;background-color:white;height:50px;overflow:auto;"></div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Autocompleter.Local('ac5','ac5update',
+ new Array("John Jackson", "Jack Johnson", "Jane Agnews", "Jack Johnson", "Jane Agnews", "Jack Johnson", "Jane Agnews"), { tokens: new Array(',','\n'), fullSearch: true, partialSearch: true });
+// ]]>
+</script>
+
+
+<br /><br /><br />
+<br /><br /><br />
+<div id="debug" style="font-size:11px;"></div>
+
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter_test.html
new file mode 100644
index 000000000..e2e43d909
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_autocompleter_test.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Autocompleter functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ .selected { background-color: #888; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Autocompleter functional test file</h1>
+
+
+Autocompleter ac1 (updated panel is relative, so no overlapping should occur): <input id="ac1" name="ac1" type="text"/>
+<div id="ac1update" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac1','ac1update','_autocomplete_result.html');
+// ]]>
+</script>
+
+<br/>
+
+Autocompleter ac2 w/ parameters: <input id="ac2" type="text" name="ac2"/>
+<div id="ac2update" style="display:none;border:1px solid black;background-color:white;"></div>
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac2','ac2update','_autocomplete_result.html',{parameters:'a=b&b=c'});
+// ]]>
+</script>
+
+<br/>
+
+Autocompleter ac3 (nested in postion:relative div, selects "selectme" class):
+<br/>
+<div style="position:relative">
+<input id="ac3" type="text"/>
+<div id="ac3update" style="display:none;border:1px solid black;background-color:white;"></div>
+</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac3','ac3update','_autocomplete_result.html',{select:'selectme'});
+// ]]>
+</script>
+
+<br/><select><option>First Item</option><option>Second Item</option><option>Third Item</option></select>
+
+<br/><br/>
+Autocompleter ac4 (autoselects option if single single option is returned):
+<br/>
+<input id="ac4" type="text"/>
+<div id="ac4update" style="display:none;border:1px solid black;background-color:white;"></div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Ajax.Autocompleter('ac4','ac4update','_autocomplete_result_single.html',{select:'selectme',autoSelect:true});
+// ]]>
+</script>
+
+<div id="debug" style="font-size:11px;"></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplacecollectioneditor_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplacecollectioneditor_test.html
new file mode 100644
index 000000000..773b715de
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplacecollectioneditor_test.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Demo</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ .inplaceeditor-saving { background: url(wait.gif) bottom right no-repeat; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Demo</h1>
+<p>
+ Demo of the Ajax.InPlaceCollectionEditor.
+</p>
+
+<p id="tobeedited">three</p> (should autoselect "three")
+<script>
+new Ajax.InPlaceCollectionEditor(
+ 'tobeedited', '_ajax_inplaceeditor_result.html', {
+ collection: ['one','two','three'],
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+
+<p id="tobeedited2">two</p> (should autoselect "two")
+<script>
+new Ajax.InPlaceCollectionEditor(
+ 'tobeedited2', '_ajax_inplaceeditor_result.html', {
+ collection: [[0,'one'],[1,'two'],[2,'three']],
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+<p id="tobeedited3">three</p> (should manually select "one")
+<script>
+new Ajax.InPlaceCollectionEditor(
+ 'tobeedited3', '_ajax_inplaceeditor_result.html', {
+ collection: [[0,'one'],[1,'two'],[2,'three']],
+ value: 0,
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+<p id="tobeedited4">one</p> (should manually select "two")
+<script>
+new Ajax.InPlaceCollectionEditor(
+ 'tobeedited4', '_ajax_inplaceeditor_result.html', {
+ collection: ['one','two','three'],
+ value: 'two',
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplaceeditor_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplaceeditor_test.html
new file mode 100644
index 000000000..bffeb866b
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/ajax_inplaceeditor_test.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Demo</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ .inplaceeditor-saving { background: url(wait.gif) bottom right no-repeat; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Demo</h1>
+<p>
+ Demo of the Ajax.InPlaceEditor.
+</p>
+
+<h1 id="tobeedited">To be edited</h1>
+<script>
+new Ajax.InPlaceEditor($('tobeedited'), '_ajax_inplaceeditor_result.html', {
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+</script>
+
+<h1 id="tobeeditedblur">To be edited w/ blur</h1>
+<script>
+new Ajax.InPlaceEditor($('tobeeditedblur'), '_ajax_inplaceeditor_result.html', {
+ submitOnBlur: true, okButton: false, cancelLink: true,
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+</script>
+
+<h1 id="tobeeditedoklink">To be edited w/ okLink and cancelButton</h1>
+<script>
+new Ajax.InPlaceEditor($('tobeeditedoklink'),
+ '_ajax_inplaceeditor_result.html', {
+ okButton: false,
+ okLink: true,
+ cancelButton: true,
+ cancelLink: false,
+ textBeforeControls: ' ---> ',
+ textBetweenControls: ' | ',
+ textAfterControls: ' <--- ',
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+<h1 id="tobeeditedoklinkonly">To be edited w/ okLink only </h1>
+<script>
+new Ajax.InPlaceEditor($('tobeeditedoklinkonly'),
+ '_ajax_inplaceeditor_result.html', {
+ okButton: false,
+ okLink: true,
+ cancelButton: false,
+ cancelLink: false,
+ textBeforeControls: ' ---> ',
+ textBetweenControls: ' | ', // will not be used, as one control only
+ textAfterControls: ' <--- ',
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+});
+</script>
+
+
+<span id="tobeedited2">With external edit control and custom parameter name</span> &nbsp; <a id="tobeedited2EditControl" href="#">edit</a>
+<script>
+new Ajax.InPlaceEditor($('tobeedited2'), '_ajax_inplaceeditor_result.html', {
+ externalControl: 'tobeedited2EditControl',
+ paramName: 'foobar',
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+</script>
+
+<table>
+ <tbody>
+ <tr>
+ <td><span id="tobeeditedTD">test</span></td>
+ <td><a id="tobeeditedTDEditControl" href="#">edit</a></td>
+ </tr>
+ </tbody>
+</table>
+
+<script>
+new Ajax.InPlaceEditor($('tobeeditedTD'), '_ajax_inplaceeditor_result.html', {
+ externalControl: 'tobeeditedTDEditControl'
+ });
+</script>
+
+<p id="tobeedited3">Multi row editor: Lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum lorum ipsum</p>
+<script>
+new Ajax.InPlaceEditor($('tobeedited3'), '_ajax_inplaceeditor_result.html', {
+ rows:5,
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+</script>
+
+<p id="tobeedited4">Loads text from server</p>
+<script>
+new Ajax.InPlaceEditor($('tobeedited4'), '_ajax_inplaceeditor_result.html',
+ {ajaxOptions: {method: 'get'}, //override so we can use a static for the result and to load the text
+ loadTextURL: '_ajax_inplaceeditor_text.html'
+ });
+</script>
+
+<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
+<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
+<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
+
+<h1 id="tobeeditedFarDown">Editor very far down to test scrolling bug</h1>
+<script>
+new Ajax.InPlaceEditor($('tobeeditedFarDown'), '../unit/_ajax_inplaceeditor_result.html');
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop2_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop2_test.html
new file mode 100644
index 000000000..37ac6e8c7
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop2_test.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ #thelist li { background: green; margin:5px; padding: 30px; }
+ #thelist2 li { background: #ffb; margin:2px; padding: 2px; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>Draggables/Droppables</h2>
+
+<div id="revertbox1" class="box1" style="z-index:1000;width:150px;height:150px;background:#bbf;">
+ <span id="handle1">drag here</span><br/>
+ <input type="checkbox" id="shouldrevert1"/> Revert?
+</div>
+
+<div id="revertbox2" class="box" style="z-index:1000;width:150px;height:150px;background:#bbf;">
+ <span id="handle2">drag here</span><br/>
+ <input type="checkbox" id="shouldrevert2"/> Revert?
+ I've onStart, onDrag and onEnd events!<br/>
+ <span id="event-info"></span>
+</div>
+
+<div id="specialbox" class="box" style="z-index:1000;width:150px;height:150px;background:#fbb;">
+ This box overrides the default endeffect
+</div>
+
+<div id="specialbox2" class="box" style="z-index:1000;width:150px;height:150px;background:#fbb;">
+ This box overrides the default starteffect
+</div>
+
+<div id="specialbox3" class="box" style="z-index:1000;width:150px;height:150px;background:#fbb;">
+ This box overrides the default end- and starteffects
+</div>
+
+<div id="droptarget1" style="width:200px;height:200px;background-color:#eee;">accepts first box</div>
+<div id="droptarget2" style="width:200px;height:200px;background-color:#eee;">accepts second box</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Draggable('revertbox1',{scroll:window,handle:'handle1',revert:function(element){return ($('shouldrevert1').checked)}});
+ new Draggable('revertbox2',{
+ handle:'handle2',
+ revert:function(element){return ($('shouldrevert2').checked)},
+ onStart:function(){$('revertbox2').setStyle({backgroundColor:'#bfb'})},
+ onDrag:function(){$('event-info').update('drag!')},
+ onEnd:function(){alert('end!')}
+ });
+
+ Droppables.add('droptarget1',{accept:['box1','otherstuff'],onDrop:function(){alert('drop!')}});
+ Droppables.add('droptarget2',{accept:'box',onDrop:function(){alert('drop!')}});
+
+
+ new Draggable('specialbox',{
+ endeffect:function(){
+ new Effect.Highlight('specialbox',{queue:'end'});
+ }
+ });
+ new Draggable('specialbox2',{
+ starteffect:function(){
+ new Effect.Highlight('specialbox2',{queue:'end'});
+ }
+ });
+ new Draggable('specialbox3',{
+ starteffect:function(){
+ new Effect.Highlight('specialbox3',{queue:'end'});
+ },
+ endeffect:function(){
+ new Effect.Highlight('specialbox3',{queue:'end'});
+ }
+ });
+// ]]>
+</script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop3_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop3_test.html
new file mode 100644
index 000000000..6fca7b021
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop3_test.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ #thelist li { background: green; margin:5px; padding: 30px; }
+ #thelist2 li { background: #ffb; margin:2px; padding: 2px; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>Draggables/Droppables</h2>
+
+<div style="width:400px;height:400px;overflow:scroll;position:relative;" id="scroll-container">
+
+<ul id="thelist2" style="padding: 2px; background:red;">
+<li>Relatively here!</li>
+<li><input onclick="this.checked = !this.checked" name="x" id="x" type="checkbox"/>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+</ul>
+
+</div>
+
+<pre id="debug"></pre>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+// Sortable.create('thelist', {overlap: 'horizontal', constraint: false});
+Position.includeScrollOffsets = true;
+Sortable.create('thelist2',{scroll:'scroll-container'});
+
+// ]]>
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop4_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop4_test.html
new file mode 100644
index 000000000..56ec04eaf
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop4_test.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body style="background-color:#eee;">
+<div style="position:relative;margin-left:100px;top:40px;background-color:white;">
+(inside position:relative container)
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>Draggables/Droppables</h2>
+
+<div id="absolute_positioned_element" class="box1" style="width:150px;height:150px;background:#bbf;">
+ <b>Ghosting effect</b>
+ <input type="text" value="blah"/>
+ <div id="hurradiegams">test!</div>
+ <br/>
+</div>
+
+<a href="#" onclick="alert($('hurradiegams').innerHTML); return false;">alert contents of test div</a>
+
+<div id="absolute_positioned_element2" class="box1" style="width:150px;height:150px;background:#bbf;">
+ <span id="handle1">Ghost effect</span><br/>
+</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Position.includeScrollOffsets = true;
+
+ new Draggable('absolute_positioned_element',{ghosting: true});
+ new Draggable('absolute_positioned_element2',{ghosting: true, revert:true});
+// ]]>
+</script>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop5_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop5_test.html
new file mode 100644
index 000000000..c84f9e130
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop5_test.html
@@ -0,0 +1,42 @@
+<html>
+<head>
+<title>script.aculo.us Drag and drop functional test file</title>
+<script src="../../lib/prototype.js" type="text/javascript"></script>
+<script src="../../src/scriptaculous.js" type="text/javascript"></script>
+<script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<style>
+ div.hoverclass123 {
+ border:1px solid red;
+ }
+</style>
+<body>
+
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>w/o hoverclass</h2>
+
+<div id="cart" class="cart" style="text-align:center;height:50px;padding:10px;background-color:#fba">
+### DROP HERE ###
+</div>
+
+<script type="text/javascript">Droppables.add('cart', {onDrop:function(element,dropon){alert('w/o hoverclass, should be \'product_id\':' + encodeURIComponent(element.id) + ', dropon should be \'cart\':' + dropon.id)}})</script>
+
+<br/>
+
+<img alt="Product2" id="product_id" src="icon.png" /> &lt;-- drag this!
+
+<script type="text/javascript">new Draggable('product_id', {revert:true})</script>
+
+<h2>w/ hoverclass</h2>
+
+
+<div id="carth" class="cart" style="text-align:center;height:50px;padding:10px;background-color:#fba">
+### DROP HERE ###
+</div>
+
+<script type="text/javascript">Droppables.add('carth', {hoverclass:'hoverclass123',onDrop:function(element, dropon, event){alert('w/ hoverclass: should be \'product_id\':' + encodeURIComponent(element.id) + ', dropon should be \'carth\':' + dropon.id)}})</script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop6_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop6_test.html
new file mode 100644
index 000000000..23ade0ab4
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop6_test.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ div.box { background: green; width:100px; height:100px }
+ div.box-container { background: yellow; width:200px; height:200px }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>Draggables/Droppables</h2>
+
+<div id="box-normal" class="box">
+ Normal box
+</div>
+
+<div id="box-grid-numeric" class="box">
+ snap: 25
+</div>
+
+<div id="box-grid-array" class="box">
+ snap: [5,25]
+</div>
+
+<div id="box-grid-procedural" class="box">
+ snap: procedural (e.g. constrain to box)
+</div>
+
+<div class="box-container">
+ <div id="box-grid-procedural-gets-draggable" class="box">
+ snap: procedural (e.g. constrain to parent element)
+ </div>
+</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Draggable('box-normal',{snap:false,revert:true});
+ new Draggable('box-grid-numeric',{snap:25,revert:true});
+ new Draggable('box-grid-array',{snap:[5,25],revert:true});
+ new Draggable('box-grid-procedural',{
+ snap: function(x,y) {
+ return[
+ x<100 ? (x > 0 ? x : 0 ) : 100,
+ y<50 ? (y > 0 ? y : 0) : 50];
+ },
+ revert:true
+ });
+ new Draggable('box-grid-procedural-gets-draggable',{
+ snap: function(x,y,draggable) {
+ function constrain(n, lower, upper) {
+ if (n > upper) return upper;
+ else if (n < lower) return lower;
+ else return n;
+ }
+
+ element_dimensions = Element.getDimensions(draggable.element);
+ parent_dimensions = Element.getDimensions(draggable.element.parentNode);
+ return[
+ constrain(x, 0, parent_dimensions.width - element_dimensions.width),
+ constrain(y, 0, parent_dimensions.height - element_dimensions.height)];
+ },
+ revert:true
+ });
+// ]]>
+</script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop7_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop7_test.html
new file mode 100644
index 000000000..dd74db1fe
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop7_test.html
@@ -0,0 +1,211 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title></title>
+<script src="../../lib/prototype.js" type="text/javascript"></script>
+<script src="../../src/scriptaculous.js" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+
+Position.includeScrollOffsets = true;
+
+Draggables.clear = function (event) {
+ while (Draggables.drags.length) {
+ var d = Draggables.drags.pop();
+ var e = d.element;
+ d.stopScrolling();
+ d.destroy();
+ d.element = null;
+ if (e.parentNode) {e.parentNode.removeChild(e)};
+ }
+}
+
+function cleanup() { //try to remove circular references
+ lis = document.getElementsByTagName("li");
+ for (i = 0; i < lis.length; i++) {
+ if (lis[i].longListItem) {lis[i].longListItem.destroy();}
+ else if (lis[i].container) {lis[i].container.destroy();}
+ }
+ Draggables.clear();
+}
+
+window.onload = function() {
+ var li = $("masterList").getElementsByTagName('LI');
+ for (var i = 0; i < li.length; i++) {
+ //var d = new LongListItem(li[i]);
+ //li[i].onmousedown = d.onMouseDown.bindAsEventListener(d);
+ var d = new Draggable(li[i],
+ {revert: true,
+ ghosting: false,
+ scroll: "rightContainers"
+ });
+
+ }
+
+ var divs = $("rightContainers").getElementsByTagName("div");
+ for (i = 0; i < divs.length; i++) {
+ if (divs[i].className && Element.hasClassName(divs[i], "container")) {
+ Droppables.add(divs[i].id, {hoverclass: "hover", scrollingParent: "rightContainers"});
+ }
+ }
+ Event.observe(window, 'unload', cleanup, false);
+}
+//]]>
+</script>
+<style type="text/css">
+html, body {
+ margin:0; padding: 0;
+ height: 100% !important;
+}
+body {
+ position:relative;
+ color: black;
+ background-color: white;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: small;
+}
+h1 {font-size:115%;}
+h2 {font-size: 110%;}
+h3 {font-size: 105%;}
+div, p, li, td {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: small;
+}
+p {margin: 0 0 .7em 0; padding:0;}
+ul {
+ position:relative;
+ list-style: none;
+ margin:0; padding:0;
+ overflow: visible;
+}
+li {position:relative;}
+
+.instructions {font-style:italic;}
+#leftDiv {
+ position: absolute;
+ top: 0; left: 0; bottom: 0;
+ width: 30%;
+ margin: 0; padding: 7px;
+ border-right: 2px solid #bb9;
+ background-color: #eed;
+}
+
+#leftDiv li, #rightContainers div.container li {
+ margin: 3px 0; padding: 3px 3em 3px 10px;
+ border: 2px solid #456;
+ background-color: #cde;
+ cursor: move;
+}
+
+#rightContainers {
+ padding: .5em;
+ position: absolute;
+ top: 0; bottom: 0; right: 0; left: 35%;
+ overflow:auto;
+}
+
+#rightContainers div.container{
+ background-color: #bb9;
+ margin: 0 0 40px 0; padding: 0 0 1px 0;
+ border: 2px solid #775;
+}
+
+#rightContainers div.container h2{
+ margin:0; padding: 2px 1em 0 1em;
+ text-align:center;
+}
+
+#rightContainers div.container ul {
+ margin: 5px; padding: 0 3px;
+ background-color: white;
+ border: 1px solid black;
+}
+
+#rightContainers div.container ul.empty {
+ padding: 3px 0;
+}
+
+#rightContainers div.hover {
+ background-color: #eed;
+}
+</style>
+<!--[if IE]><style type="text/css">
+#leftDiv {
+ height: expression((document.body.clientHeight - 44) + "px");
+}
+#leftDiv ul{width:93%;}
+#leftDiv li div.count {
+ right:4px;
+ top:4px;
+}
+#rightContainers li a.remove {
+ display:block;
+ float:none;
+ position:absolute;
+ top: 4px;
+ right: 1.6em;
+ margin:0; padding:0 .2em;
+}
+</style><![endif]-->
+</head>
+<body>
+<div id="leftDiv" class="">
+<form id="frmContinue" action="#" method="post">
+<p class="instructions">Shrink your window until the right-hand pane is scrollable.</p>
+<p class="instructions">Drag from the list on left to groups on the right, force the right-hand pane to scroll.</p>
+<input name="data" type="hidden" value=" ">
+</form>
+<ul id="masterList">
+<li id="drag1">One</li>
+<li id="drag2">Two</li>
+<li id="drag3">Three</li>
+<li id="drag4">Four</li>
+<li id="drag5">Five</li>
+<li id="drag6">Six</li>
+<li id="drag7">Seven</li>
+<li id="drag8">Eight</li>
+</ul>
+</div>
+
+<div id="rightContainers" class="">
+</form>
+<div id="grp1" class="container">
+ <h2><span id="grp1_name">Group 1</span></h2>
+ <ul id="grp1ul" class="empty"></ul>
+</div>
+<div id="grp2" class="container">
+ <h2><span id="grp2_name">Group 2</span></h2>
+ <ul id="grp2ul" class="empty"></ul>
+</div>
+<div id="grp3" class="container">
+ <h2><span id="grp3_name">Group 3</span></h2>
+ <ul id="grp3ul" class="empty"></ul>
+</div>
+<div id="grp4" class="container">
+ <h2><span id="grp4_name">Group 4</span></h2>
+ <ul id="grp4ul" class="empty"></ul>
+</div>
+<div id="grp5" class="container">
+ <h2><span id="grp5_name">Group 5</span></h2>
+ <ul id="grp5ul" class="empty"></ul>
+</div>
+<div id="grp6" class="container">
+ <h2><span id="grp6_name">Group 6</span></h2>
+ <ul id="grp6ul" class="empty"></ul>
+</div>
+<div id="grp7" class="container">
+ <h2><span id="grp7_name">Group 7</span></h2>
+ <ul id="grp7ul" class="empty"></ul>
+</div>
+<div id="grp8" class="container">
+ <h2><span id="grp8_name">Group 8</span></h2>
+ <ul id="grp8ul" class="empty"></ul>
+</div>
+<div id="grp9" class="container">
+ <h2><span id="grp9_name">Group 9</span></h2>
+ <ul id="grp9ul" class="empty"></ul>
+</div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop8_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop8_test.html
new file mode 100644
index 000000000..a6a0ff5e6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop8_test.html
@@ -0,0 +1,142 @@
+<html>
+<head>
+<title>Drag &amp; Drop</title>
+
+<style type="text/css">
+
+td
+{
+ width: 10em;
+ text-align: center;
+}
+
+table.mytable {
+ list-style-type: none;
+ padding: 4px 4px 0 4px;
+ margin: 0px;
+ font-size: 13px;
+ font-family: Arial, sans-serif;
+}
+
+table.mytable tr {
+ margin-bottom: 4px;
+ padding: 2px 2px;
+ border: 1px solid #c00;
+ background-color: #eee;
+}
+
+div.draggable {
+ cursor:move;
+ padding:2px;
+ background-color: #BBCCDD;
+}
+
+div.dropsite {
+ padding:2px;
+ background-color: #DDBB99;
+}
+
+div.hoverclass123
+{
+ border:1px solid red;
+}
+
+</style>
+
+<script language="JavaScript" type="text/javascript" src="../../lib/prototype.js"></script>
+<script language="JavaScript" type="text/javascript" src="../../src/scriptaculous.js"></script>
+<script language="JavaScript" type="text/javascript">
+
+Position.includeScrollOffsets = true;
+
+window.onload = function()
+{
+ var t1 = document.getElementById("t1");
+ add_divs(t1, 'td', 'draggable');
+ var trs = t1.getElementsByTagName("tr");
+ for (var i = 0; i < trs.length; i++)
+ {
+ var divs = document.getElementsByClassName("draggable", trs[i]);
+ var drag_text = divs[2].innerHTML;
+ for (var j = 0; j < divs.length; ++j)
+ {
+ new Draggable(divs[j], {ghosting:true, revert:true});
+ }
+ }
+
+ var t2 = document.getElementById("t2");
+ add_divs(t2, 'td', 'dropsite');
+ var divs = document.getElementsByClassName("dropsite", t2);
+ for (var j = 0; j < divs.length; ++j)
+ {
+ Droppables.add(divs[j], {accept:'draggable',
+ hoverclass:'hoverclass123',
+ onDrop:function(element, dropon, event)
+ { debug("dropped " + element.innerHTML + " on "
+ + dropon.innerHTML + "\n")}});
+ }
+};
+
+function debug(text)
+{
+ document.getElementById('debug').innerHTML
+ = "<pre>" + text + "</pre>";
+}
+
+function add_divs(table, tag, classname)
+{
+ var items = table.getElementsByTagName(tag);
+ for (var i = 0; i < items.length; i++)
+ items[i].innerHTML =
+ "<div class='" + classname + "'>" + items[i].innerHTML + "</div>";
+}
+
+
+</script>
+</head>
+<body>
+
+<p>Drag from this table:</p>
+<DIV STYLE="padding-left: 50pt;">
+<DIV STYLE="overflow: auto; width: 250; height: 100;
+ border: 1px gray solid;
+ padding:0px; margin: 0px;">
+<table id="t1" class="sortable mytable">
+ <tr><td>one</td><td>1</td><td>uno</td></tr>
+ <tr><td>two</td><td>2</td><td>dos</td></tr>
+ <tr><td>three</td><td>3</td><td>tres</td></tr>
+ <tr><td>four</td><td>4</td><td>quatro</td></tr>
+ <tr><td>five</td><td>5</td><td>cinco</td></tr>
+ <tr><td>six</td><td>6</td><td>seis</td></tr>
+ <tr><td>seven</td><td>7</td><td>siete</td></tr>
+ <tr><td>eight</td><td>8</td><td>ocho</td></tr>
+ <tr><td>nine</td><td>9</td><td>nueve</td></tr>
+ <tr><td>ten</td><td>10</td><td>diez</td></tr>
+</table>
+</DIV>
+</DIV>
+<p>
+<p>Drop on this table:</p>
+<DIV STYLE="padding-left: 50pt;">
+<DIV STYLE="overflow: auto; width: 250; height: 100;
+ border: 1px gray solid;
+ padding:0px; margin: 0px;">
+<table id="t2" class="sortable mytable">
+ <tr><td>eleven</td><td>11</td><td>once</td></tr>
+ <tr><td>twelve</td><td>12</td><td>doce</td></tr>
+ <tr><td>thirteen</td><td>13</td><td>trece</td></tr>
+ <tr><td>fourteen</td><td>14</td><td>catorce</td></tr>
+ <tr><td>fifteen</td><td>15</td><td>quince</td></tr>
+ <tr><td>sixteen</td><td>16</td><td>dieciseis</td></tr>
+ <tr><td>seventeen</td><td>17</td><td>diecisiete</td></tr>
+ <tr><td>eightteen</td><td>18</td><td>dieciocho</td></tr>
+ <tr><td>nineteen</td><td>19</td><td>diecinueve</td></tr>
+ <tr><td>twenty</td><td>20</td><td>veinte</td></tr>
+</table>
+</DIV>
+</DIV>
+<p>
+<div id="debug"></div>
+</p>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop9_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop9_test.html
new file mode 100644
index 000000000..c7d44d05f
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop9_test.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title></title>
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="source" style="height: 100px; width: 100px; background-color: gray;">
+ Draggable
+ </div>
+ <script type="text/javascript">
+ //<![CDATA[
+ new Draggable("source", {
+ revert:"failure",
+ onDropped: function(element){ $(element).update('I WAS DROPPED!') },
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.Move(element, {
+ x: -left_offset, y: -top_offset, duration: dur,
+ transition: Effect.Transitions.spring,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ }
+ });
+ //]]>
+ </script>
+
+ <br/>
+
+ <div id="target" style="height: 100px; width: 100px; background-color: green;">
+ Good Target
+ </div>
+
+ <script type="text/javascript">
+ //<![CDATA[
+ Droppables.add("target", {
+ onDrop:function(element){ Effect.Puff($('source')); }
+ });
+ //]]>
+ </script>
+
+ <br/>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_delay_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_delay_test.html
new file mode 100644
index 000000000..df60977c2
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_delay_test.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>script.aculo.us functional test</title>
+ <script type="text/javascript" src="../../lib/prototype.js"></script>
+ <script type="text/javascript" src="../../src/effects.js"></script>
+ <script type="text/javascript" src="../../src/dragdrop.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ var myStartEffect = function(element) {
+ element._opacity = Element.getOpacity(element);
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ new Effect.Highlight(element, {});
+ }
+ //]]>
+ </script>
+ <style type="text/css">
+ /*<![CDATA[*/
+ h1 {font-size: 1.2em; text-align:center;}
+ li {
+ margin: 5px auto;
+ padding: 2px;
+ width: 200px;
+ text-align:center;
+ list-style-type:none;
+ border: 2px solid #779;
+ background-color: #dde
+ }
+ div {
+ margin: 5px auto;
+ padding: 2px;
+ width: 300px;
+ text-align:center;
+ border: 2px solid #797;
+ background-color: #ded
+ }
+ /*]]>*/
+ </style>
+</head>
+
+<body>
+ <h1>No delay sortable</h1>
+
+ <ul id="sort1">
+ <li id="s1_1">one</li>
+
+ <li id="s1_2">two</li>
+
+ <li id="s1_3">three</li>
+ </ul>
+
+ <h1>Delayed sortable (500 ms)</h1>
+
+ <ul id="sort2">
+ <li id="s2_1">one</li>
+
+ <li id="s2_2">two</li>
+
+ <li id="s2_3">three</li>
+ </ul>
+
+ <h1>No delay draggable</h1>
+
+ <div id="drag1">
+ Lorem ipsum
+ </div>
+
+ <h1>Delayed draggable (1000 ms)</h1>
+
+ <div id="drag2">
+ Lorem ipsum
+ </div>
+
+ <script type="text/javascript" charset="utf-8">
+ Sortable.create('sort1', {starteffect: myStartEffect});
+ Sortable.create('sort2', {starteffect:myStartEffect, delay:500});
+ new Draggable('drag1', {starteffect:myStartEffect});
+ new Draggable('drag2', {starteffect:myStartEffect, delay:1000});
+ </script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_test.html
new file mode 100644
index 000000000..1079f3703
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dragdrop_test.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ #thelist li { background: green; margin:5px; padding: 30px; }
+ #thelist2 li { background: #ffb; margin:2px; padding: 2px; }
+ #revertbox2 { position:absolute;top:40px;left:50px;z-index:1000;width:150px;height:150px;background:#bbf; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<h2>Draggables/Droppables</h2>
+
+<a href="#" onclick="alert($H(Sortable.sortables).inspect());return false">inspect sortables</a>
+
+<div id="revertbox1" class="box1" style="opacity:0.5;z-index:1000;width:150px;height:150px;background:#bfb;">
+ <span class="handle1">drag here</span>
+ <span class="handle1">(but not here)</span><br/>
+ <input type="checkbox" id="shouldrevert1"/> Revert?
+</div>
+
+<div id="revertbox2" class="box">
+ <span id="handle2">drag here</span><br/>
+ <input type="checkbox" id="shouldrevert2"/> Revert?
+</div>
+
+<div id="xxxx">testtest</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Draggable('revertbox1',{scroll:window,zindex:-5,handle:'handle1',revert:function(element){return ($('shouldrevert1').checked)}});
+ new Draggable('revertbox2',{scroll:window,handle:'handle2',revert:function(element){return ($('shouldrevert2').checked)}});
+ Droppables.add('xxxx',{accept:['box1','box2'],onDrop:function(){alert('drop!')}});
+// ]]>
+</script>
+
+
+
+
+<ul id="thelist" style="padding: 10px; position: absolute; top:20px; left:200px;z-index:1000;">
+<li id="thelist_4">Hey there! I'm absolutely positioned</li>
+<li id="thelist_1">one<br/><form id="form1"><input type="checkbox" onclick="this.checked = !this.checked" value="x" name="x" id="xyz"/><input type="text" id="xxx"></input></form></li>
+<li id="thelist_2">two<br/><form id="form2"><input type="text" id="xyx"></input></form></li>
+<li id="thelist_3">three<br/><form id="form3"><input type="text" id="xu3"></input></form></li>
+</ul>
+
+<ul id="thelist2" style="padding: 2px; background:red;">
+<li>Relatively here!</li>
+<li><input onclick="this.checked = !this.checked" name="x" id="x" type="checkbox"/>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+</ul>
+
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+// Sortable.create('thelist', {overlap: 'horizontal', constraint: false});
+Sortable.create('thelist');
+Sortable.create('thelist2');
+
+// ]]>
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dropmarker.png b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dropmarker.png
new file mode 100644
index 000000000..77d7387b6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/dropmarker.png
Binary files differ
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_direct_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_direct_test.html
new file mode 100644
index 000000000..cff8ad7ff
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_direct_test.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #888; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<a href="#" onclick="$$('div.d').each( function(e) { e.visualEffect('highlight',{duration:1.5}) }); return false;">Highlight</a> |
+<a href="#" onclick="$$('div.d').each( function(e) { e.visualEffect('blind_up','d1',{duration:1.5}) }); return false;">BlindUp</a> |
+<a href="#" onclick="$$('div.d').each( function(e) { e.visualEffect('blind_down',{duration:1.5}) }); return false;">BlindDown</a> |
+<a href="#" onclick="$$('div.d').each( function(e) { e.visualEffect('slide_up',{duration:1.5}) }); return false;">SlideUp</a> |
+<a href="#" onclick="$$('div.d').each( function(e) { e.visualEffect('slide_down',{duration:1.5}) }); return false;">SlideDown</a>
+
+<div class="d"><div style="overflow:hidden">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien sollicitudin ultricies. Aliquam hendrerit orci et odio. Suspendisse volutpat wisi at sem. Integer eget nulla. Duis eu diam a nunc condimentum tempus. Praesent gravida metus vitae massa. Aliquam neque magna, fringilla eu, porta id, interdum sit amet, dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem est, ultrices sit amet, condimentum vitae, vehicula a, massa.
+</div></div>
+
+<div class="d"><div style="overflow:hidden">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien sollicitudin ultricies. Aliquam hendrerit orci et odio. Suspendisse volutpat wisi at sem. Integer eget nulla. Duis eu diam a nunc condimentum tempus. Praesent gravida metus vitae massa. Aliquam neque magna, fringilla eu, porta id, interdum sit amet, dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem est, ultrices sit amet, condimentum vitae, vehicula a, massa.
+</div></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_puff_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_puff_test.html
new file mode 100644
index 000000000..47a3cb0a4
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_puff_test.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <script type="text/javascript" charset="utf-8">
+ Position.includeScrollOffsets = true;
+ </script>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.Puff</h2>
+
+<div id="p1" style="width:100px;height:100px;background-color:#dde;" onclick="Effect.Puff(this)">
+ click to test puff, no position set
+</div>
+
+<div id="p2" style="float:right;width:100px;height:100px;background-color:#dde;" onclick="Effect.Puff(this)">
+ click to test puff, floats
+</div>
+
+<div id="p3" style="position:absolute;left:200px;top:100px;width:100px;height:100px;background-color:#dde;" onclick="Effect.Puff(this)">
+ click to test puff, absolute position set
+</div>
+
+<h3>Floating inside a container</h3>
+
+<div style="width:300px;height:300px;border:1px solid red">
+ <div style="float:left;width:100px;height:100px;background-color:#888;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#999;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#aaa;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#bbb;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#ccc;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#ddd;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#eee;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#777;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+ <div style="float:left;width:100px;height:100px;background-color:#666;" onclick="Effect.Puff(this)">
+ click to puff
+ </div>
+</div>
+
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_scale_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_scale_test.html
new file mode 100644
index 000000000..215205df8
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_scale_test.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #scaleable { background-color: #888; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<a href="#" onclick="new Effect.Scale( 'scaleable', 20,{ scaleX: true, scaleY: false }); return false;">Scale X only</a> |
+<a href="#" onclick="new Effect.Scale( 'scaleable', 20,{ scaleX: false, scaleY: true }); return false;">Scale Y only</a> |
+<a href="#" onclick="new Effect.Scale( 'scaleable', 20,{ scaleX: true, scaleY: true }); return false;">Scale X and Y</a>
+
+<div id="scaleable">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien sollicitudin ultricies. Aliquam hendrerit orci et odio. Suspendisse volutpat wisi at sem. Integer eget nulla. Duis eu diam a nunc condimentum tempus. Praesent gravida metus vitae massa. Aliquam neque magna, fringilla eu, porta id, interdum sit amet, dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem est, ultrices sit amet, condimentum vitae, vehicula a, massa.
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_shake.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_shake.html
new file mode 100644
index 000000000..c65848cef
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effect_shake.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+<body>
+<h1>script.aculo.us Effect.shake functional test file</h1>
+
+<h2>Effect.Shake</h2>
+
+<div id="debug"> </div>
+
+
+<a href="#" onclick="new Effect.Shake(this); return false;">shake</a><br/>
+<a href="#" onclick="new Effect.Shake(this, {distance:2}); return false;">shake 2</a><br/>
+<a href="#" onclick="new Effect.Shake(this, {distance:30}); return false;">shake 30</a><br/>
+<a href="#" onclick="new Effect.Shake(this, {distance:60}); return false;">shake 60</a><br/>
+
+<style type="text/css" media="screen">
+/* <![CDATA[ */
+ #shake10, #shake20, #shake30 { margin-left: 50px; }
+/* ]]> */
+</style>
+
+<a href="#" onclick="shake_these();return false;">shake these</a><br/>
+
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+function shake_these(){
+ new Effect.Shake("shake10", {distance:10});
+ new Effect.Shake("shake20", {distance:20});
+ new Effect.Shake("shake30", {distance:30});
+}
+// ]]>
+</script>
+
+
+<div id="shake10">shake 10</div>
+<div id="shake20">shake 20</div>
+<div id="shake30">shake 30</div>
+
+<a href="#" onclick="new Effect.Shake(this, {duration:2.0}); return false;">shake slow</a><br/>
+<a href="#" onclick="new Effect.Shake(this, {duration:0.2}); return false;">shake fast</a><br/>
+
+<a href="#" onclick="new Effect.Shake(this, {distance:2, duration:2.0}); return false;">shake 2 slow</a><br/>
+<a href="#" onclick="new Effect.Shake(this, {distance:60, duration:0.2}); return false;">shake 60 fast</a><br/>
+
+
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects2_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects2_test.html
new file mode 100644
index 000000000..f88581eab
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects2_test.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>Untitled Document</title>
+<style type="text/css">
+#menu {
+ width: 300px;
+ border: 1px #000 solid;
+}
+.menu_header {
+ background-color: #00CC99;
+ color: #FFFFFF;
+}
+.menu_block {
+ background-color: #006699;
+ color: #FFFFFF;
+ overflow:hidden;
+}
+.menu_block div {
+}
+.close_block {
+ position: relative;
+ width: 100%;
+ bottom: 0px;
+ height: 15px;
+ text-align: center;
+ display: block;
+}
+</style>
+<script src="../../lib/prototype.js" type="text/javascript"></script>
+<script src="../../src/scriptaculous.js" type="text/javascript"></script>
+<script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<div id="menu">
+ <div class="menu_header" id="menu_header1"><a href="#" onClick="new Effect.SlideDown('menu_block1'); return false;">HEADER 1</a></div>
+ <div class="menu_block_container" id="menu_block_container1">
+ <div class="menu_block" id="menu_block1"><div>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ <a href="#" class="close_block" onClick="new Effect.SlideUp('menu_block1'); return false;">close</a></div></div>
+ </div>
+ <div class="menu_header" id="menu_header2"><a href="#" onClick="new Effect.SlideDown('menu_block2'); return false;">HEADER 2</a></div>
+ <div class="menu_block_container" id="menu_block_container2">
+ <div class="menu_block" id="menu_block2"><div>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ text<br>
+ <a href="#" class="close_block" onClick="new Effect.SlideUp('menu_block2'); return false;">close</a></div></div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects3_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects3_test.html
new file mode 100644
index 000000000..dfd2e975d
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects3_test.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.SlideDown/Effect.SlideUp</h2>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ var effect_1 = null;
+// ]]>
+</script>
+
+<a href="#" onclick="effect_1 = Effect.SlideDown('d1',{duration:1.0}); return false;">Start slide down</a> |
+<a href="#" onclick="effect_1 = Effect.SlideUp('d1',{duration:1.0}); return false;">Start slide up</a> |
+<a href="#" onclick="effect_1.cancel(); return false;">cancel()</a> |
+<a href="#" onclick="alert(Object.inspect($('d1').firstChild.style)); return false;">inspect()</a> |
+<a href="#" onclick="$('d1').firstChild.innerHTML += $('d1').firstChild.innerHTML; return false;">add content</a>
+
+<div id="d1" style="display:none;"><div style="background-color:#ff8080;width:300px;border:2px solid red;padding:10px;">
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien sollicitudin ultricies. Aliquam hendrerit orci et odio. Suspendisse volutpat wisi at sem. Integer eget nulla. Duis eu diam a nunc condimentum tempus. Praesent gravida metus vitae massa. Aliquam neque magna, fringilla eu, porta id, interdum sit amet, dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem est, ultrices sit amet, condimentum vitae, vehicula a, massa.
+</p>
+</div></div>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects4_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects4_test.html
new file mode 100644
index 000000000..e71bee912
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects4_test.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #888; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<a href="#" onclick="new Effect.Highlight('d1',{duration:1.5}); return false;">Highlight</a> |
+<a href="#" onclick="new Effect.BlindUp('d1',{duration:1.5}); return false;">BlindUp</a> |
+<a href="#" onclick="new Effect.BlindDown('d1',{duration:1.5}); return false;">BlindDown</a> |
+<a href="#" onclick="new Effect.SlideUp('d1',{duration:1.5}); return false;">SlideUp</a> |
+<a href="#" onclick="new Effect.SlideDown('d1',{duration:1.5}); return false;">SlideDown</a>
+
+<div id="d1"><div style="overflow:hidden">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien sollicitudin ultricies. Aliquam hendrerit orci et odio. Suspendisse volutpat wisi at sem. Integer eget nulla. Duis eu diam a nunc condimentum tempus. Praesent gravida metus vitae massa. Aliquam neque magna, fringilla eu, porta id, interdum sit amet, dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem est, ultrices sit amet, condimentum vitae, vehicula a, massa.
+</div></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5_test.html
new file mode 100644
index 000000000..344d6ebe5
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5_test.html
@@ -0,0 +1,483 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us ScrollTo effect functional test</h1>
+
+<a href="#" onclick="new Effect.ScrollTo('down-below',{duration:5.0}); return false;">scroll (slow-mo) down-below...</a>,
+<a href="#" onclick="new Effect.ScrollTo('last-heading'); return false;">scroll last-heading</a>
+
+<h2 id="first-heading"><b>first-heading</b>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2 id="down-below"><b>DOWN BELOW</b>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<a href="#" onclick="new Effect.ScrollTo('first-heading'); return false;">scroll...</a>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2>Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+<h2 id="last-heading">Heading 2</h2>
+<ul>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+</ul>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5b_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5b_test.html
new file mode 100644
index 000000000..160f29d52
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects5b_test.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+
+<div style="height: 200px;">&nbsp;</div>
+
+<h1>script.aculo.us ScrollTo effect (with floats) functional test</h1>
+
+(this test only applies to Firefox)
+
+ <div style="float: right; padding: 10px; background: #ccc; height: 1900px;">
+
+ <h2>top of float</h2>
+
+ <a href="#" onclick="new Effect.ScrollTo('bottom-of-float');return false;">scroll to bottom!</a>
+
+ <div style="height: 1500px;">&nbsp;</div>
+
+ <h2 id="bottom-of-float">Bottom of Float</h2>
+
+ w00t
+
+ </div>
+
+ <script>
+ window.scrollBy(0, 200);
+ </script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects6_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects6_test.html
new file mode 100644
index 000000000..fe1f9b051
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects6_test.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us Fade/Appear effect functional test</h1>
+<p>Note: these tests use the browser default CSS style rules.</p>
+
+<h2>DIV</h2>
+<div id="test_div">TEST</div>
+<a href="#" onclick="Effect.Fade('test_div'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_div'); return false;">Effect.Appear</a>
+
+<h2>SPAN</h2>
+<span id="test_span">TEST</span><br/>
+<a href="#" onclick="Effect.Fade('test_span'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_span'); return false;">Effect.Appear</a>
+
+<h2>P</h2>
+<p id="test_p">TEST</p><br/>
+<a href="#" onclick="Effect.Fade('test_p'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_p'); return false;">Effect.Appear</a>
+
+<h2>IMG</h2>
+<img id="test_img" src="icon.png" alt="test image" /><br/>
+<a href="#" onclick="Effect.Fade('test_img'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_img'); return false;">Effect.Appear</a>
+
+
+<hr/>
+
+<p style="color:red;">The following elements are not supported with Fade/Appear on all browsers!</p>
+
+<h2>TABLE</h2>
+<table id="test_table"><tbody><tr><td>TEST</td></tr></tbody></table>
+<a href="#" onclick="Effect.Fade('test_table'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_table'); return false;">Effect.Appear</a>
+
+<h2>TBODY</h2>
+<table><tbody id="test_tbody"><tr><td>TEST</td></tr></tbody></table>
+<a href="#" onclick="Effect.Fade('test_tbody'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_tbody'); return false;">Effect.Appear</a>
+
+<h2>TR</h2>
+<table><tbody><tr id="test_tr"><td>TEST</td></tr></tbody></table>
+<a href="#" onclick="Effect.Fade('test_tr'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_tr'); return false;">Effect.Appear</a>
+
+<h2>TD</h2>
+<table><tbody><tr><td id="test_td">TEST</td></tr></tbody></table>
+<a href="#" onclick="Effect.Fade('test_td'); return false;">Effect.Fade</a> |
+<a href="#" onclick="Effect.Appear('test_td'); return false;">Effect.Appear</a>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_blind_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_blind_test.html
new file mode 100644
index 000000000..b469a117e
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_blind_test.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #fcb; width: 200px; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.BlindUp/Effect.BlindDown</h2>
+
+<div id="d1">
+ Lorem ipsum dolor sit amet
+ <ul>
+ <li>test!</li>
+ <li>test!</li>
+ </ul>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ <img src="icon.png" alt="test!"/>
+ Lorem ipsum dolor sit amet
+ <ul>
+ <li>test!</li>
+ <li>test!</li>
+ </ul>
+ Lorem ipsum dolor sit amet
+ <ul>
+ <li>test!</li>
+ <li>test!</li>
+ </ul>
+ Lorem ipsum dolor sit amet
+ <ul>
+ <li>test!</li>
+ <li>test!</li>
+ </ul>
+</div>
+
+<p>
+ <a href="#" onclick="Effect.BlindDown('d1');; return false;">BlindDown()</a>
+</p>
+
+<p>
+ <a href="#" onclick="Effect.BlindUp('d1');; return false;">BlindUp()</a>
+</p>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_float_appear_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_float_appear_test.html
new file mode 100644
index 000000000..1a5272570
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_float_appear_test.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us functional test file</h1>
+<p>
+ See if workaround for Safari and floating elements with Effect.Appear works.
+</p>
+
+<a href="#" onclick="Effect.Appear('float_div_left'); return false;">float:left</a> |
+<a href="#" onclick="Effect.Appear('float_div_right'); return false;">float:right</a> |
+<a href="#" onclick="$('float_div_right').setOpacity(1)">float:right (setOpacity 1)</a> |
+<a href="#" onclick="Effect.Appear('icon'); return false;">image (non-floating)</a> |
+<a href="#" onclick="Effect.Appear('float_icon'); return false;">image (floating)</a> |
+<a href="#" onclick="$('float_icon').setOpacity(1);">image (setOpacity 1)</a>
+
+<hr/>
+
+<div id="float_div_left" style="float:left;display:none">
+ Lorem ipsum dolor sit amet,<br/>
+ consectetur adipisicing elit,<br/>
+ sed do eiusmod tempor incididunt<br/>
+ ut labore et dolore magna aliqua.
+</div>
+
+<div id="float_div_right" style="float:right;opacity:0.4">
+ Lorem ipsum dolor sit amet,<br/>
+ consectetur adipisicing elit,<br/>
+ sed do eiusmod tempor incididunt<br/>
+ ut labore et dolore magna aliqua.
+</div>
+
+<img id="icon" src="icon.png" style="display:none" alt="" />
+
+<img id="float_icon" src="icon.png" style="float:left;opacity:0.4" alt="" />
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_grow_strink_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_grow_strink_test.html
new file mode 100644
index 000000000..9607d3598
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_grow_strink_test.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #fcb; width: 200px; height: 200px; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.Grow/Effect.Shrink</h2>
+
+<div id="d1" style="font-size: 2em;">
+ <p style="font-size:1em;">Lorem ipsum dolor sit amet</p>
+</div>
+
+<p>
+ Grow:
+ <a href="#" onclick="Effect.Grow('d1');; return false;">Grow()</a>
+</p>
+
+<p>
+ Shrink:
+ <a href="#" onclick="Effect.Shrink('d1');; return false;">Shrink()</a>
+</p>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_highlight_bg_image.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_highlight_bg_image.html
new file mode 100644
index 000000000..cb0adf284
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_highlight_bg_image.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title></title>
+<script type="text/javascript" src="../../lib/prototype.js"></script> <script type="text/javascript" src="../../src/scriptaculous.js?load=effects"></script>
+<script type="text/javascript">
+//<![CDATA[
+
+Li = {
+ onMouseDown_image: function(event) {
+ new Effect.Highlight(this, {keepBackgroundImage:true});
+ },
+ onMouseDown_without: function(event) {
+ new Effect.Highlight(this);
+ }
+}
+
+window.onload = function() {
+ var li = $("with").getElementsByTagName('LI');
+ for (var i = 0; i < li.length; i++) {
+ li[i].onmousedown = Li.onMouseDown_image.bindAsEventListener(li[i]);
+ }
+ var li = $("without").getElementsByTagName('LI');
+ for (i = 0; i < li.length; i++) {
+ li[i].onmousedown = Li.onMouseDown_without.bindAsEventListener(li[i]);
+ }
+}
+
+//]]>
+</script>
+<style type="text/css">
+body { color: black; background-color: white;
+ font-family: Verdana, Arial, Helvetica, sans-serif; } ul { list-style: none; margin:0; padding:0; }
+li {
+ margin: 3px 0; padding: 3px 3em 3px 24px; border: 2px solid #456; background-image: url(icon.png); background-repeat: no-repeat; background-position: 3px 3px;
+}
+#with li {background-color: #cde;}
+#without li {background-color: #ced;} </style>
+</head>
+<body>
+<p>Test of <code>keepBackgroundImage</code> parameter for <code>Effect.Highlight</code>. Click items to show effect.</p>
+<p>With the <code>keepBackgroundImage</code> parameter.</p>
+<ul id="with">
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ul>
+
+<p>Without the parameter.</p>
+<ul id="without">
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ul>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_limit_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_limit_test.html
new file mode 100644
index 000000000..64a784289
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_limit_test.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #fcb; width: 200px; height: 200px; float:left; }
+ #d2 { background-color: #cfb; font-size: 2em; width: 200px; height: 200px; float:left; }
+ #d3 { background-color: #bcf; font-size: 2em; width: 200px; height: 200px; float:left; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.Queue limit</h2>
+
+<a href="#" onclick="Effect.SlideUp('slidingtwice',{queue:{scope:'myscope', position:'end', limit: 1}});">up</a>
+<a href="#" onclick="Effect.SlideDown('slidingtwice',{queue:{scope:'myscope', position:'end', limit: 1}});">down</a>
+<div id="slidingtwice"><div style="background-color:#000;color:white;font-size:20px;height:300px;width:150px;">
+ Do a bit sliding in parallel, with a scoped queue, but I am limited to one : ) so don't try over and over again...
+</div></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_test.html
new file mode 100644
index 000000000..753cb8aa4
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_queue_test.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #d1 { background-color: #fcb; width: 200px; height: 200px; float:left; }
+ #d2 { background-color: #cfb; font-size: 2em; width: 200px; height: 200px; float:left; }
+ #d3 { background-color: #bcf; font-size: 2em; width: 200px; height: 200px; float:left; }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.Queue</h2>
+
+<div id="d1" style="font-size: 2em;">
+ <p style="font-size:1em;">Lorem ipsum dolor sit amet</p>
+</div>
+
+<div id="d2">
+ <p>Lorem ipsum dolor sit amet</p>
+</div>
+
+<div id="d3">
+ <p>Lorem ipsum dolor sit amet</p>
+</div>
+
+<div style="clear: both">
+ <a href="#" onclick="startTimeline(); return false;">Start queued effects</a> (in 'global' queue)
+</div>
+
+<div id="sliding"><div style="background-color:#ccc;font-size:20px;height:300px;width:150px;">
+ <a href="#" onclick="Effect.SlideUp('sliding',{queue:{scope:'myscope', position:'end'}}); Effect.SlideDown('sliding',{queue:{scope:'myscope', position:'end'}}); return false;">
+ Do a bit sliding in parallel, with a scoped queue
+ </a>
+</div></div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ function startTimeline() {
+ // 3x highlight in front
+ for(var i=0; i<3; i++)
+ new Effect.Highlight('d3', { duration: 1.0, queue: 'front' });
+
+ // insert scale at very beginning
+ new Effect.Scale('d1', 75, { scaleContent: true, duration: 1.0, queue: 'front' });
+
+ // parallel implied, delay 0.5 sec
+ new Effect.Highlight('d1', { delay: 0.5 });
+
+ // puff at end
+ new Effect.Puff('d2', { duration: 4.0, queue: 'end' });
+ }
+// ]]>
+</script>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_random_demo.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_random_demo.html
new file mode 100644
index 000000000..5f6fef314
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_random_demo.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ div.demo { font-size: 70pt; float: left }
+ div#info { font: 10px/11px Tahoma, Arial, sans-serif; }
+ /* ]]> */
+ </style>
+ <script type="text/javascript" language="javascript" charset="utf-8">
+ // <![CDATA[
+ function startDemo() {
+ $$('div.demo').each( function(d) {
+ d.visualEffect(
+ ['fade','appear','blind_up','blind_down','puff','switch_off','drop_out','shake',
+ 'slide_up','slide_down','pulsate','squish','fold','grow','shrink'][Math.round(Math.random()*14)],
+ { duration:0.5+Math.random()*5, delay: Math.random()*3 });
+ });
+ $('info').update(
+ Effect.Queues.get('global').collect( function(e) {
+ return e.inspect().escapeHTML()
+ }).join('<br/>'));
+ }
+ // ]]>
+ </script>
+</head>
+<body>
+<h1>Random effects demo</h1>
+<a href="#" onclick="startDemo(); return false;">Start...</a> |
+<a href="#" onclick="$('info').toggle(); return false">Show/hide log</a>
+
+<div class="demo" style="background-color:#f00"><div>
+DIV1
+</div></div>
+
+<div class="demo" style="background-color:#ff0"><div>
+DIV2
+</div></div>
+
+<div class="demo" style="background-color:#0f0"><div>
+DIV3
+</div></div>
+
+<div class="demo" style="background-color:#0ff"><div>
+DIV4
+</div></div>
+
+<div class="demo" style="background-color:#f00"><div>
+DIV5
+</div></div>
+
+<div class="demo" style="background-color:#ff0"><div>
+DIV6
+</div></div>
+
+<div class="demo" style="background-color:#f00"><div>
+DIV7
+</div></div>
+
+<div class="demo" style="background-color:#ff0"><div>
+DIV8
+</div></div>
+
+<div class="demo" style="background-color:#0f0"><div>
+DIV9
+</div></div>
+
+<div id="info" style="clear:both; display:none"> </div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_test.html
new file mode 100644
index 000000000..55307d919
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_test.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+<body>
+<h1>script.aculo.us Effects functional test file</h1>
+
+<h2>Effect.Highlight</h2>
+
+<div id="debug"> </div>
+
+<a href="#" onclick="new Effect.SlideDown('d1'); return false;">asdasd</a>
+
+<div id="d1" onclick="new Effect.SlideUp('d1');" style="overflow:hidden;"><div style="background-color:#ff8080;">
+
+ (highlight to red)
+
+</div></div>
+
+<div id="d2" style="width:100px;height:100px;background-color:#80ff80;">
+ (highlight to greenish)
+</div>
+
+<div id="d3" style="width:100px;height:100px;background-color:#dde;">
+ (bottom-right-grow)
+</div>
+
+<div id="d4" style="width:100px;height:100px;background-color:#dde;" onclick="Effect.Shake(this)">
+ click to test shake
+</div>
+
+<div id="d5" style="width:100px;height:100px;background-color:#dde;" onclick="Effect.Puff(this)">
+ click to test puff
+</div>
+<p>
+ update callbacks: <span id="d5_after">(waiting)</span> -- <span id="d5_before">(waiting)</span>
+</p>
+<a href="#" onclick="$('d5').appear({beforeUpdate:before,afterUpdate:after}); return false;">show puff div again</a>
+
+<a href="#" onclick="Effect.Appear('d6')">test appear</a>
+<div id="d6" style="width:100px;height:100px;background-color:#dde;display:none">
+ appear
+</div>
+
+<a href="#" onclick="Effect.Grow('d7')">test grow</a>
+<div id="d7" style="width:100px;height:100px;background-color:#dde;display:none">
+ grow
+</div>
+
+<a href="#" onclick="Effect.Pulsate('d8')">test pulsate default times (5)</a>
+<a href="#" onclick="Effect.Pulsate('d8', {pulses: 2})">test pulsate 2 times</a>
+<div id="d8" style="width:100px;height:100px;background-color:#dde;">
+ pulsate
+</div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ new Effect.Highlight("d2",{startcolor:"#000000"});
+ new Effect.Grow("d3",{duration:5.0,direction: 'bottom-right',opacityTransition:Effect.Transitions.linear});
+ new Effect.BlindDown("d1");
+
+ var afterUpdates = 0, beforeUpdates = 0;
+ function after(){ afterUpdates++; $('d5_after').update(afterUpdates); }
+ function before(){ beforeUpdates--; $('d5_before').update(beforeUpdates); }
+// ]]>
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_toggle_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_toggle_test.html
new file mode 100644
index 000000000..d2add6412
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/effects_toggle_test.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Effects functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us Effect.toggle functional test file</h1>
+
+<a href="#" onclick="Effect.toggle('d1','slide'); return false;">Toggle slide</a>
+<div id="d1" style="display:none;"><div style="background-color:#ff8080;width:300px;border:2px solid red;padding:10px;">
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien </p>
+</div></div>
+
+<a href="#" onclick="Effect.toggle('d2','BLIND'); return false;">Toggle blind</a>
+<div id="d2" style="display:none;"><div style="background-color:#ff8080;width:300px;border:2px solid red;padding:10px;">
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien </p>
+</div></div>
+
+
+<a href="#" onclick="Effect.toggle('d3','appear'); return false;">Toggle appear</a>
+<div id="d3" style="display:none;"><div style="background-color:#ff8080;width:300px;border:2px solid red;padding:10px;">
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas enim. Nulla facilisi. Vestibulum accumsan augue vulputate justo. Fusce faucibus. Sed blandit, neque sed lacinia nonummy, diam quam imperdiet justo, at dictum augue nunc a neque. Sed urna lacus, tincidunt at, aliquam id, fringilla id, felis. Vivamus feugiat molestie quam. Sed id dolor. Sed ac purus id sapien </p>
+</div></div>
+
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/icon.png b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/icon.png
new file mode 100644
index 000000000..f752986b7
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/icon.png
Binary files differ
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/index.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/index.html
new file mode 100644
index 000000000..72ff3c43d
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/index.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us functional tests</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body class="navigation">
+
+<h1>script.aculo.us<br/>Functional Tests</h1>
+
+<p id="version"></p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ $('version').innerHTML = 'script.aculo.us version '+Scriptaculous.Version+'<br/>Prototype version ' + Prototype.Version;
+// ]]>
+</script>
+
+<p><a href="http://wiki.script.aculo.us/scriptaculous/show/UnitTesting" target="test">Documentation</a></p>
+
+<h2>Effects</h2>
+<ul>
+ <li><b><a href="effects_random_demo.html" target="test">Random effects test</a></b></li>
+ <li><a href="effects_test.html" target="test">effects_test</a></li>
+ <li><a href="effect_direct_test.html" target="test">$$ selector effects/visualEffect</a></li>
+ <li><a href="effects_queue_test.html" target="test">effects_queue</a></li>
+ <li><a href="effects_queue_limit_test.html" target="test">effects_queue_limit</a></li>
+ <li><a href="effects_toggle_test.html" target="test">Effect.toggle</a></li>
+ <li><a href="effects2_test.html" target="test">effects2_test</a></li>
+ <li><a href="effects3_test.html" target="test">effects3_test</a></li>
+ <li><a href="effects4_test.html" target="test">effects4_test</a></li>
+ <li><a href="effects5_test.html" target="test">effects5_test</a></li>
+ <li><a href="effects5b_test.html" target="test">effects5b_test</a></li>
+ <li><a href="effects6_test.html" target="test">effects6_test</a></li>
+ <li><a href="effect_shake.html" target="test">effect shake</a></li>
+ <li><a href="effects_grow_strink_test.html" target="test">Grow/Shrink</a></li>
+ <li><a href="effects_blind_test.html" target="test">BlindUp/BlindDown</a></li>
+ <li><a href="effect_scale_test.html" target="test">Effect.Scale</a></li>
+ <li><a href="effect_puff_test.html" target="test">Effect.Puff</a></li>
+ <li><a href="effects_float_appear_test.html" target="test">Test for Safari .Appear w/ floats</a></li>
+ <li><a href="effects_highlight_bg_image.html" target="test">Effect.Highlight keepBackgroundImage option</a></li>
+ <li><a href="texteffects_test.html" target="test">texteffects_test.html</a></li>
+</ul>
+
+<h2>Controls</h2>
+<ul>
+ <li><a href="ajax_autocompleter_test.html" target="test">ajax_autocompleter_test</a></li>
+ <li><a href="ajax_autocompleter2_test.html" target="test">ajax_autocompleter2_test</a></li>
+ <li><a href="ajax_inplaceeditor_test.html" target="test">ajax_inplaceeditor_test</a></li>
+ <li><a href="ajax_inplacecollectioneditor_test.html" target="test">ajax_inplacecollectioneditor_test</a></li>
+ <li><a href="slider_test.html" target="test">slider_test</a></li>
+</ul>
+
+<h2>Drag &amp; Drop</h2>
+<ul>
+ <li><a href="dragdrop_test.html" target="test">dragdrop_test</a></li>
+ <li><a href="dragdrop2_test.html" target="test">dragdrop2_test</a></li>
+ <li><a href="dragdrop3_test.html" target="test">dragdrop3_test</a></li>
+ <li><a href="dragdrop4_test.html" target="test">dragdrop4_test</a></li>
+ <li><a href="dragdrop5_test.html" target="test">dragdrop5_test</a></li>
+ <li><a href="dragdrop6_test.html" target="test">dragdrop6_test: snap option</a></li>
+ <li><a href="dragdrop7_test.html" target="test">dragdrop7_test</a></li>
+ <li><a href="dragdrop8_test.html" target="test">dragdrop8_test</a></li>
+ <li><a href="dragdrop9_test.html" target="test">Revert: failure</a></li>
+ <li><a href="dragdrop_delay_test.html" target="test">dragdrop delay test</a></li>
+ <li><a href="sortable_test.html" target="test">sortable_test</a></li>
+ <li><a href="sortable2_test.html" target="test">sortable2_test</a></li>
+ <li><a href="sortable3_test.html" target="test">sortable3_test</a></li>
+ <li><a href="sortable4_test.html" target="test">sortable4_test</a></li>
+ <li><a href="sortable5_test.html" target="test">sortable5_test</a></li>
+ <li><a href="sortable6_test.html" target="test">sortable5_test</a></li>
+ <li><a href="sortable_tree_test.html" target="test">Sortable trees</a></li>
+</ul>
+
+<h2>Sound (experimental)</h2>
+<ul>
+ <li><a href="sound_test.html" target="test">sound_test.html</a></li>
+</ul>
+
+<h2>Miscellaneous</h2>
+<ul>
+ <li><a href="position_clone_test.html" target="test">position_clone_test</a></li>
+</ul>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/position_clone_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/position_clone_test.html
new file mode 100644
index 000000000..58907fbb1
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/position_clone_test.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>prototype.js Position.clone functional test</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <style type="text/css">
+ .margins { margin:20px; }
+ .nomargins { margin:0; }
+ </style>
+ </head>
+ <body>
+
+
+ <div id="container" style="position:relative; top:10px; width:300px; height:100px; overflow: auto;">
+
+ <div id="container2" style="position:relative; top:10px; width:400px; height:150px; overflow: auto;">
+
+ <div id="test1" style="border:1px solid black; position:absolute; left: 100px; top: 10px; width:100px; height:200px;">
+ abs
+ </div>
+
+ <div id="test2" style="border:1px solid black; position:relative; left: 50px; top: 0px;">
+ rel
+ </div>
+
+ <div id="test3" style="border:1px solid black; position:static;">
+ static
+ </div>
+
+ </div>
+
+ </div>
+
+ <div id="c3" style="position:absolute;top:140px;left:55px;width:100px;height:20px;">
+ abs-body child
+ </div>
+
+ <p id="p1" style="background-color:#eee;">
+ unpositioned p
+ </p>
+
+ <script type="text/javascript" language="javascript">
+ // <![CDATA[
+ function d(el, marker) {
+ $('debug').innerHTML =
+ 'orig: ' + Object.inspect(Position.page($(el))) + ', ' +
+ 'clone: ' + Object.inspect(Position.page($(marker)));
+ }
+ function testA(el) {
+ Position.clone(el, 'marker');
+ d(el, 'marker');
+ }
+ function testB(el) {
+ Element.hide('marker2');
+ Position.clone(el, 'marker2');
+ Element.show('marker2');
+ d(el, 'marker2');
+ }
+ function testC(el) {
+ Position.clone(el, 'marker3');
+ d(el, 'marker3');
+ }
+ function testD(el) {
+ Position.clone(el, 'marker4');
+ d(el, 'marker4');
+ }
+ // ]]>
+ </script>
+
+ <div id="actions" style="position:absolute;top:400px;">
+ <a href="#" onclick="Element.toggle('big'); return false;">Toggle page scrolling</a> |
+ Page margings: <a href="#" onclick="document.body.className = 'margins'">on</a> |
+ <a href="#" onclick="document.body.className = 'nomargins'">off</a>
+ <br/><br/>
+ Absolute marker in position:relative container DIV:<br/>
+ <a href="#" onclick="testA('test1'); return false;">Mark abs</a> |
+ <a href="#" onclick="testA('test2'); return false;">Mark rel</a> |
+ <a href="#" onclick="testA('test3'); return false;">Mark static</a> |
+ <a href="#" onclick="testA('c3'); return false;">Mark abs-body child</a> |
+ <a href="#" onclick="testA('p1'); return false;">Mark p</a>
+ <br/><br/>
+ Hidden marker (display:none), in position:relative container DIV switched on when clone is finished:<br/>
+ <a href="#" onclick="testB('test1'); return false;">Mark abs</a> |
+ <a href="#" onclick="testB('test2'); return false;">Mark rel</a> |
+ <a href="#" onclick="testB('test3'); return false;">Mark static</a> |
+ <a href="#" onclick="testB('c3'); return false;">Mark abs-body child</a> |
+ <a href="#" onclick="testB('p1'); return false;">Mark p</a>
+ <br/><br/>
+ Absolute marker, child of BODY:<br/>
+ <a href="#" onclick="testC('test1'); return false;">Mark abs</a> |
+ <a href="#" onclick="testC('test2'); return false;">Mark rel</a> |
+ <a href="#" onclick="testC('test3'); return false;">Mark static</a> |
+ <a href="#" onclick="testC('c3'); return false;">Mark abs-body child</a> |
+ <a href="#" onclick="testC('p1'); return false;">Mark p</a>
+ <br/><br/>
+ Fixed marker, child of BODY:<br/>
+ <a href="#" onclick="testD('test1'); return false;">Mark abs</a> |
+ <a href="#" onclick="testD('test2'); return false;">Mark rel</a> |
+ <a href="#" onclick="testD('test3'); return false;">Mark static</a> |
+ <a href="#" onclick="testD('c3'); return false;">Mark abs-body child</a> |
+ <a href="#" onclick="testD('p1'); return false;">Mark p</a> |
+ <div id="debug"></div>
+ </div>
+
+ <div id="marker-container" style="position:relative;left:400px;top:20px;width:100px;height:100px;">
+ <div id="blah" style="top:20px;">
+ <div id="marker" style="position:absolute;background-color:#f00;opacity:0.5;z-index:10000;width:10px;height:10px;">!</div>
+ </div>
+ <div id="marker2" style="display:none;position:absolute;background-color:#0f0;opacity:0.5;z-index:10000;width:10px;height:10px;">!</div>
+ </div>
+
+
+
+ <div id="marker3" style="position:absolute;background-color:#00f;opacity:0.5;z-index:10000;width:10px;height:10px;">!</div>
+
+ <div id="marker4" style="position:fixed;background-color:#08f;opacity:0.5;z-index:10000;width:10px;height:10px;">!</div>
+
+ <div id="big" style="display:none;height:10000px;"> </div>
+
+ </body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/slider_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/slider_test.html
new file mode 100644
index 000000000..719686c74
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/slider_test.html
@@ -0,0 +1,152 @@
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+<head>
+ <title>Text effects tests</title>
+ <script type="text/javascript" src="../../lib/prototype.js"></script>
+ <script type="text/javascript" src="../../src/scriptaculous.js"></script>
+</head>
+<body>
+
+ <h1>Sliders</h1>
+
+ <h2>Standard horizontal slider</h2>
+
+ <div id="track1" style="width:200px;background-color:#aaa;height:5px;">
+ <div id="handle1" style="width:5px;height:10px;background-color:#f00;"> </div>
+ </div>
+
+ <p id="debug1"> </p>
+
+ <h2>Vertical slider</h2>
+
+ <div id="track2" style="height:100px;background-color:#aaa;width:5px;">
+ <div id="handle2" style="width:10px;height:5px;background-color:#f00;"> </div>
+ </div>
+
+ <p id="debug2"> </p>
+
+ <h2>Slider with predefined values [2,4,6,8] and a non-default range [2,15]</h2>
+
+ <div id="track3" style="width:200px;background-color:#aaa;height:5px;">
+ <div id="handle3" style="width:5px;height:10px;background-color:#f00;"> </div>
+ </div>
+
+ <p id="debug3"> </p>
+
+ <h2>Slider with multiple handles</h2>
+
+ <div id="track4" style="width:200px;background-color:#aaa;height:5px;position:relative;">
+ <div id="handle4-1" style="position:absolute;top:0;left:0;width:5px;height:10px;background-color:#f00;"> </div>
+ <div id="handle4-2" style="position:absolute;top:0;left:0;width:5px;height:10px;background-color:#0f0;"> </div>
+ <div id="handle4-3" style="position:absolute;top:0;left:0;width:5px;height:10px;background-color:#00f;"> </div>
+ </div>
+
+ <p id="debug4"> </p>
+
+ <h2>Slider with multiple handles and predefined values</h2>
+
+ <div id="track5" style="width:200px;background-color:#aaa;height:5px;position:relative;">
+ <div id="handle5-1" style="opacity:0.5;position:absolute;top:0;left:0;width:5px;height:10px;background-color:#f00;"> </div>
+ <div id="handle5-2" style="opacity:0.5;position:absolute;top:0;left:0;width:5px;height:10px;background-color:#0f0;"> </div>
+ <div id="handle5-3" style="opacity:0.5;position:absolute;top:0;left:0;width:5px;height:10px;background-color:#00f;"> </div>
+ </div>
+
+ <p id="debug5"> </p>
+
+ <h2>Slider with multiple handles, external controls, handles are restricted (can't be moved prior/after adjacent handles)</h2>
+
+ <div id="track6" style="width:200px;background-color:#aaa;height:5px;position:relative;">
+ <div id="handle6-1" style="position:absolute;top:0;left:0;width:5px;height:10px;background-color:#f00;"> </div>
+ <div id="handle6-2" style="position:absolute;top:0;left:0;width:5px;height:10px;background-color:#0f0;"> </div>
+ </div>
+
+ <br/><br/>
+ <a href="#" onclick="slider6.setValueBy(-0.1);return false;">&lt;--</a>
+ <a href="#" onclick="slider6.setValueBy(0.1);return false;">--&gt;</a>
+
+ <p id="debug6"> </p>
+
+ <h2>Fun with spans</h2>
+
+ <style>
+ #track7 div.handle {
+ background-color:#aaa;
+ color:#444;
+ top:0;
+ left:0;
+ position:absolute;
+ z-index:2;
+ height:100px;
+ font-size:20px;
+ }
+ #track7 div.handle.selected {
+ background-color:#444;
+ color:#fff;
+ }
+ </style>
+
+ <div id="track7" style="width:300px;background-color:#cbf;height:50px;position:relative;z-index:0;">
+ <div id="handle7-1" class="handle">1</div>
+ <div id="handle7-2" class="handle">2</div>
+ <div id="handle7-3" class="handle">3</div>
+
+ <div id="span7-1" style="top:0;left:0;position:absolute;background-color:#000;height:50px;z-index:1;"> </div>
+ <div id="span7-2" style="top:0;left:0;position:absolute;background-color:#444;height:50px;z-index:1;"> </div>
+
+ <div id="span7-start" style="top:0;left:0;position:absolute;background-color:#f00;height:50px;z-index:1;"> </div>
+ <div id="span7-end" style="top:0;left:0;position:absolute;background-color:#00f;height:50px;z-index:1;"> </div>
+ </div>
+
+ <br/><br/><br/><br/>
+
+ <h2>Slider with span and [1,10] range (test for #3731)</h2>
+
+ <div id="zoom-track" style="width:300px;background-color:#aaa;height:20px;position:relative;z-index:0;">
+ <div id="zoom-handle-1" style="position:absolute;background-color:#f00;height:20px;z-index:2">!</div>
+ <div id="zoom-handle-2" style="position:absolute;background-color:#0f0;height:20px;z-index:2">!</div>
+ <div id="zoom-track-selected" style="position:absolute;background-color:#00f;height:20px;z-index:1"> </div>
+ </div>
+
+
+ <!-- FIXME: add more demos here -->
+
+ <script type="text/javascript">
+ // <![CDATA[
+ new Control.Slider('handle1','track1',{
+ sliderValue:0.5,
+ onSlide:function(v){$('debug1').innerHTML='slide: '+v},
+ onChange:function(v){$('debug1').innerHTML='changed! '+v}});
+ new Control.Slider('handle2','track2',{axis:'vertical',
+ onSlide:function(v){$('debug2').innerHTML='slide: '+v},
+ onChange:function(v){$('debug2').innerHTML='changed! '+v}});
+ new Control.Slider('handle3','track3',{values:[2,4,6,8],range:$R(2,15),
+ onSlide:function(v){$('debug3').innerHTML='slide: '+v},
+ onChange:function(v){$('debug3').innerHTML='changed! '+v}});
+ new Control.Slider(['handle4-1','handle4-2','handle4-3'],'track4',{
+ onSlide:function(v){$('debug4').innerHTML='slide: '+v.inspect()},
+ onChange:function(v){$('debug4').innerHTML='changed! '+v.inspect()}});
+ new Control.Slider(['handle5-1','handle5-2','handle5-3'],'track5',{values:[0,0.2,0.4,0.6,0.8],
+ onSlide:function(v){$('debug5').innerHTML='slide: '+v.inspect()},
+ onChange:function(v){$('debug5').innerHTML='changed! '+v.inspect()}});
+ var slider6 = new Control.Slider(['handle6-1','handle6-2'],'track6',{
+ sliderValue:[0.3, 0.8],
+ restricted:true,
+ onSlide:function(v){$('debug6').innerHTML='slide: '+v.inspect()},
+ onChange:function(v){$('debug6').innerHTML='changed! '+v.inspect()}});
+ new Control.Slider(['handle7-1','handle7-2','handle7-3'], 'track7',
+ { spans:['span7-1','span7-2'],
+ startSpan:'span7-start',
+ endSpan:'span7-end',
+ range:$R(0,300) });
+ new Control.Slider(
+ ['zoom-handle-1','zoom-handle-2'],'zoom-track',{
+ sliderValue:[1,10], range:$R(1,10),
+ values:[1,2,3,4,5,6,7,8,9,10],
+ restricted:true,
+ spans:['zoom-track-selected'] });
+ // ]]>
+ </script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable2_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable2_test.html
new file mode 100644
index 000000000..61ea03c14
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable2_test.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Sortable ghosting functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style>
+ ul.testlist {
+ list-style-type:none;
+ margin:0;
+ padding:0;
+ }
+ ul.testlist li {
+ width:200px;
+ font:12px Verdana;
+ padding:4px;
+ cursor:move;
+ }
+ ul.testlist li.over {
+ background-color:#fcb;
+ }
+ ul.testlist li img {
+ float:left;
+ margin-right:8px;
+ }
+ div.dropmarker {
+ height:6px;
+ width:200px;
+ background: url(dropmarker.png) left top;
+ margin-top:-3px;
+ margin-left:-5px;
+ z-index:1000;
+ overflow: hidden;
+ }
+ #testlist4 li {
+ float:left;
+ }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Sortable ghosting functional test file</h1>
+
+<h2>Ghosting</h2>
+
+<ul id="testlist" class="testlist">
+<li id="item_1"><img src="icon.png" alt=""/> Lorem ipsum dolor</li>
+<li id="item_2"><img src="icon.png" alt=""/> sit amet</li>
+<li id="item_3"><img src="icon.png" alt=""/> consectetur adipisicing</li>
+<li id="item_4"><img src="icon.png" alt=""/> elit</li>
+<li id="item_5"><img src="icon.png" alt=""/> sed do eiusmod</li>
+<li id="item_6"><img src="icon.png" alt=""/> tempor incididunt</li>
+<li id="item_7"><img src="icon.png" alt=""/> ut labore et dolore</li>
+<li id="item_8"><img src="icon.png" alt=""/> magna aliqua</li>
+</ul>
+
+<p id="testlist_serialize">(waiting for onChange)</p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Sortable.create('testlist',{ghosting:true,constraint:false,hoverclass:'over',
+ onUpdate:function(sortable){alert(Sortable.serialize(sortable))},
+ onChange:function(element){$('testlist_serialize').innerHTML = Sortable.serialize(element.parentNode)}
+ });
+// ]]>
+</script>
+
+<h2>No ghosting</h2>
+
+<ul id="testlist2" class="testlist">
+<li id="item_9"><img src="icon.png" alt=""/> Lorem ipsum dolor</li>
+<li id="item_10"><img src="icon.png" alt=""/> sit amet</li>
+<li id="item_11"><img src="icon.png" alt=""/> consectetur adipisicing</li>
+<li id="item_12"><img src="icon.png" alt=""/> elit</li>
+<li id="item_13"><img src="icon.png" alt=""/> sed do eiusmod</li>
+<li id="item_14"><img src="icon.png" alt=""/> tempor incididunt</li>
+<li id="item_15"><img src="icon.png" alt=""/> ut labore et dolore</li>
+<li id="item_16"><img src="icon.png" alt=""/> magna aliqua</li>
+</ul>
+
+<p id="testlist2_serialize">(waiting for onChange)</p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Sortable.create('testlist2',{ghosting:false,constraint:false,hoverclass:'over',
+ onUpdate:function(sortable){alert(Sortable.serialize(sortable))},
+ onChange:function(element){$('testlist2_serialize').innerHTML = Sortable.serialize(element.parentNode)}
+ });
+// ]]>
+</script>
+
+<h2>Ghosting (inside position:relative container)</h2>
+<div style="position:relative;left:100px;top:-5px;">
+<ul id="testlist3" class="testlist">
+<li id="item_17"><img src="icon.png" alt=""/> Lorem ipsum dolor</li>
+<li id="item_18"><img src="icon.png" alt=""/> sit amet</li>
+<li id="item_19"><img src="icon.png" alt=""/> consectetur adipisicing</li>
+<li id="item_20"><img src="icon.png" alt=""/> elit</li>
+<li id="item_21"><img src="icon.png" alt=""/> sed do eiusmod</li>
+<li id="item_22"><img src="icon.png" alt=""/> tempor incididunt</li>
+<li id="item_23"><img src="icon.png" alt=""/> ut labore et dolore</li>
+<li id="item_24"><img src="icon.png" alt=""/> magna aliqua</li>
+</ul>
+</div>
+<p id="testlist3_serialize">(waiting for onChange)</p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Sortable.create('testlist3',{ghosting:true,constraint:false,
+ onUpdate:function(sortable){alert(Sortable.serialize(sortable))},
+ onChange:function(element){$('testlist3_serialize').innerHTML = Sortable.serialize(element.parentNode)}
+ });
+// ]]>
+</script>
+
+
+<h2>Ghosting (inside position:relative container)</h2>
+<div style="position:relative;left:100px;top:-5px;">
+<ul id="testlist4" class="testlist">
+<li id="item_417"><img src="icon.png" alt=""/> Lorem ipsum dolor</li>
+<li id="item_418"><img src="icon.png" alt=""/> sit amet</li>
+<li id="item_419"><img src="icon.png" alt=""/> consectetur adipisicing</li>
+<li id="item_420"><img src="icon.png" alt=""/> elit</li>
+<li id="item_421"><img src="icon.png" alt=""/> sed do eiusmod</li>
+<li id="item_422"><img src="icon.png" alt=""/> tempor incididunt</li>
+<li id="item_423"><img src="icon.png" alt=""/> ut labore et dolore</li>
+<li id="item_424"><img src="icon.png" alt=""/> magna aliqua</li>
+</ul>
+</div>
+<p id="testlist4_serialize">(waiting for onChange)</p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Sortable.create('testlist4',{overlap:'horizontal',ghosting:true,constraint:false,
+ onUpdate:function(sortable){alert(Sortable.serialize(sortable))},
+ onChange:function(element){$('testlist4_serialize').innerHTML = Sortable.serialize(element.parentNode)}
+ });
+// ]]>
+</script>
+
+
+<div id="debug"></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable3_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable3_test.html
new file mode 100644
index 000000000..8d9e10442
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable3_test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us sortable functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ ul { height: 100px; border:1px dotted #888; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Sortable two-lists w/ dropOnEmpty functional test file</h1>
+
+<ul id="thelist1">
+<li id="thelist1_1">Hey there! I'm item#1/1</li>
+<li id="thelist1_2">Hey there! I'm item#1/2</li>
+<li id="thelist1_3">Hey there! I'm item#1/3</li>
+</ul>
+
+<ul id="thelist2">
+</ul>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ Sortable.create('thelist1',{containment:['thelist1','thelist2'], dropOnEmpty:true});
+ Sortable.create('thelist2',{containment:['thelist1','thelist2'], dropOnEmpty:true});
+// ]]>
+</script>
+
+<a href="#" onclick="alert(Sortable.serialize('thelist1'));return false;">Serialize sortable1</a>
+<a href="#" onclick="alert(Sortable.serialize('thelist2'));return false;">Serialize sortable2</a>
+
+<div id="debug"></div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable4_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable4_test.html
new file mode 100644
index 000000000..f80ce5f6d
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable4_test.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us sortable functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ ul.sortablelist {
+ list-style-image:none;
+ list-style-type:none;
+ margin-top:5px;
+ margin:0px;
+ padding:0px;
+ }
+
+ ul.sortabledemo li {
+ padding:0px;
+ margin:0px;
+ }
+
+ span.handle {
+ background-color: #E8A400;
+ color:white;
+ cursor: move;
+ }
+
+ li.green {
+ background-color: #ECF3E1;
+ border:1px solid #C5DEA1;
+ cursor: move;
+ }
+
+ li.orange {
+ border:1px solid #E8A400;
+ background-color: #FFF4D8;
+ }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us: Two floating sortables with containment and dropOnEmpty</h1>
+
+<div style="height:200px;">
+<div style="float:left;">
+<h3>This is the first list</h3>
+ <ul class="sortabledemo" id="firstlist" style="height:150px;width:200px;">
+ <li class="green" id="firstlist_firstlist1">Item 1 from first list.</li>
+ <li class="green" id="firstlist_firstlist2">Item 2 from first list.</li>
+ <li class="green" id="firstlist_firstlist3">Item 3 from first list.</li>
+ </ul>
+</div>
+ <div style="float:left;">
+ <h3>And now the second list</h3>
+ <ul class="sortabledemo" id="secondlist" style="height:150px;width:200px;">
+ <li class="orange" id="secondlist_secondlist1">
+ <span class="handle">DRAG HERE</span> Item 1 from second list.
+ </li>
+ <li class="orange" id="secondlist_secondlist2">
+ <span class="handle">DRAG HERE</span> Item 2 from second list.
+ </li>
+ <li class="orange" id="secondlist_secondlist3">
+ <span class="handle">DRAG HERE</span> Item 3 from second list.
+ </li>
+ </ul>
+</div>
+</div>
+
+<hr style="clear:both" />
+
+<pre id="firstlist_debug"></pre>
+<pre id="secondlist_debug"></pre>
+
+ <script type="text/javascript">
+ // <![CDATA[
+ Sortable.create("firstlist",
+ {dropOnEmpty:true,containment:["firstlist","secondlist"],constraint:false,
+ onChange:function(){$('firstlist_debug').innerHTML = Sortable.serialize('firstlist') }});
+ Sortable.create("secondlist",
+ {dropOnEmpty:true,handle:'handle',containment:["firstlist","secondlist"],constraint:false,
+ onChange:function(){$('secondlist_debug').innerHTML = Sortable.serialize('secondlist') }});
+ // ]]>
+ </script>
+
+ </body>
+ </html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable5_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable5_test.html
new file mode 100644
index 000000000..52c39e1d6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable5_test.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us sortable functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+
+ <div id="container_div">
+
+ </div>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ var new_ul_id = 'new_id_123';
+ var ul = document.createElement("ul");
+ var ul_id = document.createAttribute("id");
+ ul_id.nodeValue = new_ul_id;
+ ul.setAttributeNode(ul_id);
+
+ var li = document.createElement("li");
+ li.setAttribute("id", "test_1");
+ li.appendChild(document.createTextNode("blah1"));
+ ul.appendChild(li);
+
+ var li2 = document.createElement("li");
+ li2.setAttribute("id", "test_2");
+ li2.appendChild(document.createTextNode("blah2"));
+ ul.appendChild(li2);
+
+ $('container_div').appendChild(ul);
+
+ Sortable.create(new_ul_id, { onUpdate: function() { alert(Sortable.serialize('new_id_123')); } });
+// ]]>
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable6_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable6_test.html
new file mode 100644
index 000000000..b802f105d
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable6_test.html
@@ -0,0 +1,148 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head runat="server">
+ <title>script.aculo.us Drag and drop functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <style type="text/css" media="screen">
+ #thelist li { background: green; margin:5px; padding: 30px; }
+ #thelist2 li { background: #ffb; margin:2px; padding: 2px; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Drag and drop functional test file</h1>
+
+<p>Scroll window down to test autoscrolling inside scrollable elements when window is scrolled</p>
+
+<h2>Draggables/Droppables</h2>
+
+<div style="width:400px;height:400px;overflow:scroll;position:relative;" id="scroll-container">
+
+<ul id="thelist2" style="padding: 2px; background:red;">
+<li>Relatively here!</li>
+<li><input onclick="this.checked = !this.checked" name="x" id="x" type="checkbox"/>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+</ul>
+
+</div>
+<h1> Some space in between</h1>
+<div style="width:400px;height:400px;overflow:scroll" id="scroll-container-mod">
+
+<ul id="thelist2-mod" style="padding: 2px; background:red;">
+<li>Relatively here!</li>
+<li><input onclick="this.checked = !this.checked" name="y" id="y" type="checkbox"/>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+<li>one</li>
+</ul>
+
+</div>
+
+<pre id="debug"></pre>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+// Sortable.create('thelist', {overlap: 'horizontal', constraint: false});
+Position.includeScrollOffsets = true;
+
+Sortable.create('thelist2',{scroll:'scroll-container'});
+Sortable.create('thelist2-mod',{scroll:'scroll-container-mod'});
+
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_nested_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_nested_test.html
new file mode 100644
index 000000000..74a7e575e
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_nested_test.html
@@ -0,0 +1,57 @@
+<html>
+<head>
+ <title>Nested Sortable element bug</title>
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+</head>
+<body>
+
+<ul id ="route">
+
+ <li id="39" class="segment">
+ <h2 id="39_title"> <span id="39_note" class="segment_title">COLLEGE AVE</span></h2>
+ <ul id="39_entries">
+ <li id="39:3" class="entry">625</li>
+ <li id="39:4" class="entry">617</li>
+ <li id="39:5" class="entry">601</li>
+ </ul>
+ </li>
+
+ <li id="40" class="segment">
+ <h2 id="40_title">Right <span id="40_note" class="segment_title">COLLEGE CT</span></h2>
+ <ul id="40_entries">
+ <li id="40:7" class="entry">14</li>
+ <li id="40:8" class="entry">27</li>
+ <li id="40:9" class="entry">30</li>
+ </ul>
+ </li>
+</ul>
+
+<script type="text/javascript">
+Sortable.create(
+ "route",
+ {
+ handle:'segment_title',
+ format: /([0-9]+)/
+ }
+);
+
+
+
+Sortable.create("39_entries", {
+ dropOnEmpty:true,
+ constraint:false,
+ format: /[0-9]+:([0-9]+)/
+ }
+);
+
+Sortable.create("40_entries", {
+ dropOnEmpty:true,
+ constraint:false,
+ format: /[0-9]+:([0-9]+)/
+ }
+);
+
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_test.html
new file mode 100644
index 000000000..e86babea7
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_test.html
@@ -0,0 +1,141 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us sortable functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ #thelist li { background: green; margin:5px; padding: 30px; }
+ div.dropmarker {
+ height:6px;
+ width:200px;
+ background: url(dropmarker.png) left top;
+ margin-top:-3px;
+ margin-left:-5px;
+ z-index:1000;
+ overflow: hidden;
+ }
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ var callsToOnUpdate = 0;
+ </script>
+</head>
+<body>
+<ul id="thelist">
+<li id="thelist_1">Hey there! I'm item#1</li>
+<li id="thelist_2">Hey there! I'm item#2</li>
+<li id="thelist_3">Hey there! I'm item#3</li>
+</ul>
+
+<a href="#" onclick="Sortable.create('thelist',{onUpdate:function(){$('debug').update(++callsToOnUpdate+' call(s) to onUpdate')}});return false;">Create sortable</a> |
+<a href="#" onclick="Sortable.destroy('thelist');return false;">Destroy sortable</a> |
+<a href="#" onclick="alert(Sortable.serialize('thelist'));return false;">Serialize sortable</a>
+
+<ul id="thehandlelist">
+<li id="thehandlelist_1">Hey there! I'm item#1<span class="handle">HANDLE</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+</li>
+<li id="thehandlelist_2">Hey there! I'm item#2<span class="handle">HANDLE</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+</li>
+<li id="thehandlelist_3">Hey there! I'm item#3<span class="handle">HANDLE</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+<span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span><span>S</span>
+</li>
+</ul>
+
+<a href="#" onclick="Sortable.create('thehandlelist',{handle:'handle',onUpdate:function(){$('debug').update(++callsToOnUpdate+' call(s) to onUpdate')}});return false;">Create sortable</a> |
+<a href="#" onclick="Sortable.destroy('thehandlelist');return false;">Destroy sortable</a> |
+<a href="#" onclick="alert(Sortable.serialize('thehandlelist'));return false;">Serialize sortable</a>
+
+<p id="debug">no calls to onUpdate</p>
+
+<ul id="sortable_elements_handles">
+ <li id="s_1">s1 <span class="handle" id="h_1">handle</span></li>
+ <li id="s_2">s2 <span class="handle" id="h_2">handle</span></li>
+ <li id="s_3">s3 <span class="handle" id="h_3">handle</span></li>
+ <li id="s_4">s4 <span class="handle" id="h_4">handle</span></li>
+ <li id="s_5">s5 <span class="handle" id="h_5">handle</span></li>
+ <li id="s_6">s6 <span class="handle" id="h_6">handle</span></li>
+ <li id="s_7">s7 <span class="handle" id="h_7">handle</span></li>
+ <li id="s_8">s8 <span class="handle" id="h_8">handle</span></li>
+ <li id="s_9">s9 <span class="handle" id="h_9">handle</span></li>
+ <li id="s_10">s10 <span class="handle" id="h_10">handle</span></li>
+</ul>
+
+<script type="text/javascript" charset="utf-8">
+ function initializePreselected(){
+ Sortable.create('sortable_elements_handles',{
+ handle: 'handle',
+ handles: ['h_1','h_2','h_3','h_4','h_5','h_6','h_7','h_8','h_9','h_10'],
+ elements: ['s_1','s_2','s_3','s_4','s_5','s_6','s_7','s_8','s_9','s_10']
+ });
+ }
+ function initializeNormal(){
+ Sortable.create('sortable_elements_handles',{
+ handle: 'handle'
+ });
+ }
+ function benchmark(method,times){
+ var now = new Date();
+ times.times(method);
+ $('benchmark').update((new Date()-now)+'ms');
+ }
+</script>
+
+20 times: <a href="#" onclick="benchmark(function(){initializePreselected()},20);return false">Init with Preselection</a> |
+<a href="#" onclick="benchmark(function(){initializeNormal()},20);return false">Init normally</a> <span id="benchmark"></span>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_tree_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_tree_test.html
new file mode 100644
index 000000000..431537338
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sortable_tree_test.html
@@ -0,0 +1,185 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>Sortable tree test</title>
+ <script src="../../lib/prototype.js" type="text/javascript" language="javascript" charset="utf-8"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript" language="javascript" charset="utf-8"></script>
+ <style type="text/css">
+ ul {padding-top:4px; padding-bottom: 2px; border: 1px solid #ccf;}
+ li {border: 1px solid #fcc;}
+ </style>
+ </head>
+
+ <body>
+ <a href="#" onclick="alert(Sortable.serialize('menu'));return false">serialize 1</a>
+
+ <ul id="menu" style="padding-top: 6px; padding-bottom: 6px;">
+ <li class="edit_link level0" id="t1_7">
+ System
+ <ul class="edit_list">
+ <li class="edit_link level1" id="t1_8">
+ Page Not Found
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t1_9">
+ Translation Not Available
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level0" id="t1_10">
+ Main Menu
+ <ul class="edit_list">
+ <li class="edit_link level1" id="t1_1">
+ Welcome
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t1_2">
+ Software
+ <ul class="edit_list">
+ <li class="edit_link level2" id="t1_4">
+ Serial Console
+ <ul class="edit_list">
+ <li class="edit_link level3" id="t1_6">
+ Features
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level2" id="t1_5">
+ Property Manager
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level2" id="t1_11">
+ Geomap
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level1" id="t1_12">
+ Services
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t1_13">
+ Software
+ <ul class="edit_list">
+ <li class="edit_link level2" id="t1_14">
+ Serial Console
+ <ul class="edit_list">
+ <li class="edit_link level3" id="t1_15">
+ Features
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level2" id="t1_16">
+ Property Manager
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level2" id="t1_17">
+ Geomap
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level1" id="t1_18">
+ Services
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <script type="text/javascript">
+ //<![CDATA[
+ Sortable.create('menu', {tree:true,scroll:window});
+ //]]>
+ </script>
+
+ <ul id="menu2" style="padding-top: 6px; padding-bottom: 6px;">
+ <li class="edit_link level0" id="t2_7">
+ System
+ <ul class="edit_list">
+ <li class="edit_link level1" id="t2_8">
+ Page Not Found
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t2_9">
+ Translation Not Available
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level0" id="t2_10">
+ Main Menu
+ <ul class="edit_list">
+ <li class="edit_link level1" id="t2_1">
+ Welcome
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t2_2">
+ Software
+ <ul class="edit_list">
+ <li class="edit_link level2" id="t2_4">
+ Serial Console
+ <ul class="edit_list">
+ <li class="edit_link level3" id="t2_6">
+ Features
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level2" id="t2_5">
+ Property Manager
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level2" id="t2_11">
+ Geomap
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level1" id="t2_12">
+ Services
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level1" id="t2_13">
+ Software
+ <ul class="edit_list">
+ <li class="edit_link level2" id="t2_14">
+ Serial Console
+ <ul class="edit_list">
+ <li class="edit_link level3" id="t2_15">
+ Features
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level2" id="t2_16">
+ Property Manager
+ <ul class="edit_list"></ul>
+ </li>
+ <li class="edit_link level2" id="t2_17">
+ Geomap
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ <li class="edit_link level1" id="t2_18">
+ Services
+ <ul class="edit_list"></ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <script type="text/javascript">
+ //<![CDATA[
+ Sortable.create('menu2', {tree:true,scroll:window});
+ //]]>
+ </script>
+
+ </body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sound_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sound_test.html
new file mode 100644
index 000000000..91edd038a
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sound_test.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Sound functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>script.aculo.us Sound test file</h1>
+
+<a href="#" onclick="Sound.play('sword.mp3'); return false">play sound (parallel)</a>
+
+<a href="#" onclick="Sound.play('sword.mp3',{replace:true}); return false">play sound (overwrite)</a>
+
+<a href="#" onclick="Sound.disable(); return false">Mute</a>
+<a href="#" onclick="Sound.enable(); return false">Enable sounds</a>
+
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sword.mp3 b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sword.mp3
new file mode 100644
index 000000000..9bfda65f9
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/sword.mp3
Binary files differ
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/texteffects_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/texteffects_test.html
new file mode 100644
index 000000000..b7e3807e0
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/functional/texteffects_test.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+<head>
+ <title>Text effects tests</title>
+ <script type="text/javascript" src="../../lib/prototype.js"></script>
+ <script type="text/javascript" src="../../src/scriptaculous.js"></script>
+ <style>
+ div#many_test span { font-size:40pt; color: white; background:black; width:100px; float:left; position: relative; }
+ </style>
+</head>
+<body>
+ <h1 id="h1_text" style="font:20pt Lucida Grande;color:#fff;text-align:center;background-color:#482;">
+ Maybe this is useful? <img src="icon.png" alt="blah"/> Dunno...
+ </h1>
+ <a href="#" onclick="Effect.multiple('h1_text', Effect.Appear, {speed:0.05, afterFinishInternal:function(){}}); return false;">Appear</a> |
+ <a href="#" onclick="Effect.multiple('h1_text', Effect.Fade, {speed:0.05, afterFinishInternal:function(){}}); return false;">Fade</a> |
+ <a href="#" onclick="Effect.multiple('h1_text', Effect.DropOut, {speed:0.07, afterFinishInternal:function(){}}); return false;">DropOut</a> |
+ <a href="#" onclick="alert($('h1_text').innerHTML); return false;">show H1 innerHTML</a>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ <p id="p_text" style="font:12px Verdana;color:red;font-weight:bold;">THIS IS A WARNING!</p>
+ <p>
+ <a href="#" onclick="Effect.multiple('p_text', Effect.Appear, {speed:0.05, afterFinishInternal:function(){}}); return false;">Appear</a> |
+ <a href="#" onclick="Effect.multiple('p_text', Effect.Fade, {speed:0.05, afterFinishInternal:function(){}}); return false;">Fade</a> |
+ <a href="#" onclick="Effect.multiple('p_text', Effect.DropOut, {speed:0.07, afterFinishInternal:function(){}}); return false;">DropOut</a>
+ </p>
+
+ <div id="many_test" style="height:50px;">1234567890ABCDEFG</div>
+ <div style="clear:both;"> </div>
+
+ <a href="#" onclick="Effect.multiple('many_test', Effect.Appear, {speed:0.5, duration:3.0, afterFinishInternal:function(){}}); return false;">Appear</a> |
+ <a href="#" onclick="Effect.multiple('many_test', Effect.Fade, {speed:0.05, afterFinishInternal:function(){}}); return false;">Fade</a> |
+ <a href="#" onclick="Effect.multiple($('many_test').childNodes, Effect.DropOut, {speed:0.07, afterFinishInternal:function(){}}); return false;">DropOut</a> |
+ <a href="#" onclick="Effect.multiple($('many_test').childNodes, Effect.Highlight, {speed:0.07, afterFinishInternal:function(){}}); return false;">Highlight</a> |
+ <a href="#" onclick="Effect.multiple($('many_test').childNodes, Effect.BlindDown, {speed:0.15, afterFinishInternal:function(){}}); return false;">BlindDown</a>
+
+ <script type="text/javascript" language="javascript">
+ // <![CDATA[
+ Effect.tagifyText('h1_text');
+ Effect.tagifyText('p_text');
+ Effect.tagifyText('many_test');
+ // ]]>
+ </script>
+
+ <br/><br/>
+
+ <a href="#" onclick="Effect.multiple(document.getElementsByTagName('span'), Effect.Fade, {speed:0.04, afterFinishInternal:function(){}}); return false;">Fade all spans on page</a>
+ <p id="debug"> <p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_functional_tests.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_functional_tests.html
new file mode 100644
index 000000000..bd2674551
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_functional_tests.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>script.aculo.us functional tests</title>
+ </head>
+
+ <frameset cols="250,*">
+ <frame name="controls" src="functional/index.html" />
+ <frame name="test" />
+ </frameset>
+
+ <noframes>
+ <body>
+ Heya, 1995!
+ </body>
+ </noframes>
+
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_unit_tests.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_unit_tests.html
new file mode 100644
index 000000000..969f21ac0
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/run_unit_tests.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>script.aculo.us Unit Test Runner</title>
+ </head>
+
+ <frameset cols="250,*">
+ <frame name="controls" src="unit/index.html" />
+ <frame name="test" />
+ </frameset>
+
+ <noframes>
+ <body>
+ Heya, 1995!
+ </body>
+ </noframes>
+
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/test.css b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/test.css
new file mode 100644
index 000000000..8c738a396
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/test.css
@@ -0,0 +1,90 @@
+body, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li {
+ font-family: sans-serif;
+}
+
+body {
+ font-size:0.8em;
+}
+
+.navigation {
+ background: #9DC569;
+ color: #fff;
+}
+
+.navigation h1 {
+ font-size: 20px;
+}
+
+.navigation h2 {
+ font-size: 16px;
+ font-weight: normal;
+ margin: 0;
+ border: 1px solid #e8a400;
+ border-bottom: 0;
+ background: #ffc;
+ color: #E8A400;
+ padding: 8px;
+ padding-bottom: 0;
+}
+
+.navigation ul {
+ margin-top: 0;
+ border: 1px solid #E8A400;
+ border-top: none;
+ background: #ffc;
+ padding: 8px;
+ margin-left: 0;
+}
+
+.navigation ul li {
+ font-size: 12px;
+ list-style-type: none;
+ margin-top: 1px;
+ margin-bottom: 1px;
+ color: #555;
+}
+
+.navigation a {
+ color: #ffc;
+}
+
+.navigation ul li a {
+ color: #000;
+}
+
+#log {
+ padding-bottom: 1em;
+ border-bottom: 2px solid #000;
+ margin-bottom: 2em;
+}
+
+#logsummary {
+ margin-bottom: 1em;
+ padding: 1ex;
+ border: 1px solid #000;
+ font-weight: bold;
+}
+
+#logtable {
+ width:100%;
+ border-collapse: collapse;
+ border: 1px dotted #666;
+}
+
+#logtable td, #logtable th {
+ text-align: left;
+ padding: 3px 8px;
+ border: 1px dotted #666;
+}
+
+#logtable .passed {
+ background-color: #cfc;
+}
+
+#logtable .failed, #logtable .error {
+ background-color: #fcc;
+}
+
+#logtable .nameCell {
+ cursor: pointer;
+} \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_ipce_alt_text.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_ipce_alt_text.html
new file mode 100644
index 000000000..bdeac894f
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_ipce_alt_text.html
@@ -0,0 +1 @@
+ntbe
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result.html
new file mode 100644
index 000000000..55dcbeae1
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result.html
@@ -0,0 +1 @@
+Server received: To be edited \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result2.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result2.html
new file mode 100644
index 000000000..33502d92d
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_result2.html
@@ -0,0 +1 @@
+New to be edited - edited
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_tagged.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_tagged.html
new file mode 100644
index 000000000..eb53d10ff
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_tagged.html
@@ -0,0 +1 @@
+<span>New to be edited - edited</span>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_text.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_text.html
new file mode 100644
index 000000000..a6f35d132
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_inplaceeditor_text.html
@@ -0,0 +1 @@
+Text from server \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_updater_result.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_updater_result.html
new file mode 100644
index 000000000..5f11f56ce
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_ajax_updater_result.html
@@ -0,0 +1,20 @@
+Test text
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ alert('fragment1 hit!');
+// ]]>
+</script>
+
+more test text
+
+
+<script>alert('fragment2 hit!')</script>
+
+
+even more test text
+
+<script type="text/javascript">
+ alert('fragment3 hit!');
+</script> some other test text
+
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result.html
new file mode 100644
index 000000000..f03b34ffc
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result.html
@@ -0,0 +1,11 @@
+<ul>
+ <li>test1</li><li>test2</li>
+ <li>test3</li>
+<li><b>BOLD</b></li>
+
+ <li><span class="informal">(GET ME NOT)</span>(GET &lt;ME&gt; INSTEAD)</li>
+
+ <li>Here we have <a href="_autocomplete_result.html">a link</a> which should work</li>
+
+ <li>Here we have some international ©âˆÃ®Äç†∑rß</li>
+</ul> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result_nobr.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result_nobr.html
new file mode 100644
index 000000000..742ff18f1
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/_autocomplete_result_nobr.html
@@ -0,0 +1 @@
+<ul><li>test1</li><li>test2</li><li>test3</li><li><b>BOLD</b></li><li><span class="informal">(GET ME NOT)</span>(GET &lt;ME&gt; INSTEAD)</li><li>Here we have <a href="_autocomplete_result.html">a link</a> which should work</li><li>Here we have some international ©âˆÃ®Äç†∑rß</li></ul> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_autocompleter_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_autocompleter_test.html
new file mode 100644
index 000000000..a1a63d2d6
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_autocompleter_test.html
@@ -0,0 +1,243 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- vim:expandtab=on
+ -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style>
+ .selected { background-color: #888; }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for Ajax.Autocompleter in controls.js.
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<input id="ac_input" type="text" autocomplete="off" />
+<div id="ac_update" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+<input id="ac_input_br" type="text" autocomplete="off" />
+<div id="ac_update_br" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+<input id="ac2_input" type="text" autocomplete="off" />
+<div id="ac2_update" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+<input id="actoken_input" type="text" autocomplete="off" />
+<div id="actoken_update" style="display:none;border:1px solid black;background-color:white;position:relative;"></div>
+
+<input id="dummy_element" type="text" autocomplete="off" />
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+
+ new Test.Unit.Runner({
+
+ // Integration test, tests the entire cycle
+ testAjaxAutocompleter: function() { with(this) {
+ var ac = new Ajax.Autocompleter('ac_input','ac_update','_autocomplete_result.html',
+ { method: 'get' }); //override so we can use a static for the result
+ assertInstanceOf(Ajax.Autocompleter, ac);
+
+ // box not visible
+ assertNotVisible('ac_update');
+
+ // focus, but box not visible
+ Event.simulateMouse('ac_input', 'click');
+ assertNotVisible('ac_update');
+
+ Event.simulateKeys('ac_input','abcdefg');
+ assertEqual('abcdefg', $('ac_input').value);
+
+ // check box popping up on input
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update');
+ assertEqual('test1', $('ac_update').firstChild.firstChild.innerHTML);
+ assertEqual('test2', $('ac_update').firstChild.firstChild.nextSibling.innerHTML);
+
+ // intl. characters return (UTF-8)
+ assertEqual('Here we have some international ©âˆÃ®Äç†∑rß', $('ac_update').firstChild.lastChild.innerHTML);
+
+ // first entry should be selected
+ assert(Element.hasClassName($('ac_update').firstChild.firstChild, 'selected'),'Selected item should have a className of: selected');
+
+ Event.simulateKey('ac_input','keypress',{keyCode:Event.KEY_DOWN});
+
+ // second entry should be selected
+ assert(!Element.hasClassName($('ac_update').firstChild.firstChild),'Item shouldn\'t have a className of: selected');
+ assert(Element.hasClassName($('ac_update').firstChild.firstChild.nextSibling, 'selected'),'Second entry should have a className of: selected');
+
+ // check selecting with <TAB>
+ Event.simulateKey('ac_input','keypress',{keyCode:Event.KEY_TAB});
+ assertEqual('test2',$('ac_input').value);
+
+ // check box going away
+ wait(500, function() { with(this) {
+ assertNotVisible('ac_update');
+
+ // check selecting with mouse click
+ Event.simulateKeys('ac_input','3');
+ assertEqual('test23', $('ac_input').value);
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update');
+ Event.simulateMouse($('ac_update').firstChild.childNodes[4],'click');
+
+ wait(1000, function() { with(this) {
+ // tests if removal of 'informal' nodes and HTML escaping works
+ assertEqual('(GET <ME> INSTEAD)',$('ac_input').value);
+ assertNotVisible('ac_update');
+
+ // check cancelling with <ESC>
+ Event.simulateKeys('ac_input','abcdefg');
+
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update');
+ assertEqual('(GET <ME> INSTEAD)abcdefg', $('ac_input').value);
+
+ Event.simulateKey('ac_input','keypress',{keyCode:Event.KEY_DOWN});
+ Event.simulateKey('ac_input','keypress',{keyCode:Event.KEY_ESC});
+
+ assertEqual('(GET <ME> INSTEAD)abcdefg', $('ac_input').value);
+ }});
+ }});
+ }});
+ }});
+ }});
+ }},
+
+ testAfterUpdateElement: function() { with(this) {
+ var ac = new Ajax.Autocompleter('ac2_input','ac2_update','_autocomplete_result.html',
+ { method: 'get',
+ afterUpdateElement: function(element,selectedElement) {
+ element.value = 'afterupdate:' + selectedElement.tagName;
+ }
+ });
+ assertInstanceOf(Ajax.Autocompleter, ac);
+
+ Event.simulateMouse('ac2_input', 'click');
+ Event.simulateKeys('ac2_input','abcdefg');
+
+ wait(1000, function() { with(this) {
+ assertVisible('ac2_update');
+ Event.simulateKey('ac2_input','keypress',{keyCode:Event.KEY_TAB});
+
+ assertEqual('afterupdate:LI',$('ac2_input').value);
+ }});
+ }},
+
+ testTokenizing: function() { with(this) {
+ var actoken = new Ajax.Autocompleter('actoken_input','ac_update','_autocomplete_result.html',
+ { tokens:',', method: 'get' });
+ assertInstanceOf(Ajax.Autocompleter, actoken);
+
+ Event.simulateKeys('actoken_input','abc');
+
+ wait(1000, function() { with(this) {
+ Event.simulateKey('actoken_input','keypress',{keyCode:Event.KEY_TAB});
+ assertEqual('test1',$('actoken_input').value);
+ Event.simulateKeys('actoken_input',',abc');
+ wait(1000, function() { with(this) {
+ Event.simulateKey('actoken_input','keypress',{keyCode:Event.KEY_DOWN});
+ Event.simulateKey('actoken_input','keypress',{keyCode:Event.KEY_TAB});
+ assertEqual('test1,test2',$('actoken_input').value);
+ // Simulating KEY_LEFT's prior to a 'b' doesn't work! So slightly ugly here...
+ $('actoken_input').value = 'test1b,test2';
+ actoken.onObserverEvent();
+ wait(1000, function() { with(this) {
+ for (var index = 0; index < 2; ++index)
+ Event.simulateKey('actoken_input', 'keypress', {keyCode: Event.KEY_DOWN});
+ Event.simulateKey('actoken_input', 'keypress', {keyCode: Event.KEY_TAB});
+ assertEqual('test3,test2', $('actoken_input').value);
+ }});
+ }});
+ }});
+ }},
+
+ // Same integration test, results has no linebreaks
+ testAjaxAutocompleterNoLinebreaksInResult: function() { with(this) {
+ var ac = new Ajax.Autocompleter('ac_input_br','ac_update_br','_autocomplete_result_nobr.html',
+ { method: 'get' }); //override so we can use a static for the result
+ assertInstanceOf(Ajax.Autocompleter, ac);
+
+ // box not visible
+ assertNotVisible('ac_update_br');
+
+ // focus, but box not visible
+ Event.simulateMouse('ac_input_br', 'click');
+ assertNotVisible('ac_update_br');
+
+ Event.simulateKeys('ac_input_br','abcdefg');
+ assertEqual('abcdefg', $('ac_input_br').value);
+
+ // check box popping up on input
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update_br');
+ assertEqual('test1', $('ac_update_br').firstChild.firstChild.innerHTML);
+ assertEqual('test2', $('ac_update_br').firstChild.firstChild.nextSibling.innerHTML);
+
+ // intl. characters return (UTF-8)
+ assertEqual('Here we have some international ©âˆÃ®Äç†∑rß', $('ac_update_br').firstChild.lastChild.innerHTML);
+
+ // first entry should be selected
+ assert(Element.hasClassName($('ac_update_br').firstChild.firstChild, 'selected'),'Selected item should have a className of: selected');
+
+ Event.simulateKey('ac_input_br','keypress',{keyCode:Event.KEY_DOWN});
+
+ // second entry should be selected
+ assert(!Element.hasClassName($('ac_update_br').firstChild.firstChild),'Item shouldn\'t have a className of: selected');
+ assert(Element.hasClassName($('ac_update_br').firstChild.firstChild.nextSibling, 'selected'),'Second entry should have a className of: selected');
+
+ // check selecting with <TAB>
+ Event.simulateKey('ac_input_br','keypress',{keyCode:Event.KEY_TAB});
+ assertEqual('test2',$('ac_input_br').value);
+
+ // check box going away
+ wait(500, function() { with(this) {
+ assertNotVisible('ac_update_br');
+
+ // check selecting with mouse click
+ Event.simulateKeys('ac_input_br','3');
+ assertEqual('test23', $('ac_input_br').value);
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update_br');
+ Event.simulateMouse($('ac_update_br').firstChild.childNodes[4],'click');
+
+ wait(1000, function() { with(this) {
+ // tests if removal of 'informal' nodes and HTML escaping works
+ assertEqual('(GET <ME> INSTEAD)',$('ac_input_br').value);
+ assertNotVisible('ac_update_br');
+
+ // check cancelling with <ESC>
+ Event.simulateKeys('ac_input_br','abcdefg');
+
+ wait(1000, function() { with(this) {
+ assertVisible('ac_update_br');
+ assertEqual('(GET <ME> INSTEAD)abcdefg', $('ac_input_br').value);
+
+ Event.simulateKey('ac_input_br','keypress',{keyCode:Event.KEY_DOWN});
+ Event.simulateKey('ac_input_br','keypress',{keyCode:Event.KEY_ESC});
+
+ assertEqual('(GET <ME> INSTEAD)abcdefg', $('ac_input_br').value);
+ }});
+ }});
+ }});
+ }});
+ }});
+ }}
+
+ });
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_inplaceeditor_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_inplaceeditor_test.html
new file mode 100644
index 000000000..3fd97398f
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/ajax_inplaceeditor_test.html
@@ -0,0 +1,895 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for <code>Ajax.InPlaceEditor</code> and <code>Ajax.InPlaceCollectionEditor</code> in controls.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<h1 id="tobeedited">To be edited</h1>
+<a id="tobeeditedEditControl" href="#">edit</a>
+
+<p id="newtbe">New to be edited</p>
+<p id="newtbe_external">External control for it</p>
+
+<p id="contains_ampersand">Me & Myself</p>
+
+<div id="tobeeditedMultiLine">First line<br/>
+Second line<br/>
+Third line</div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ var IPCE_COLLECTION = [
+ ['tbe', 'To be edited'],
+ ['ntbe', 'New to be edited'],
+ ['ntbe2', 'New to be edited 2'],
+ ['ntbe3', 'New to be edited 3']
+ ];
+
+ new Test.Unit.Runner({
+
+ setup: function() { with(this) {
+ inPlaceEditor = new Ajax.InPlaceEditor($('tobeedited'), '_ajax_inplaceeditor_result.html', {
+ externalControl: $('tobeeditedEditControl'),
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+ inPlaceEditorMultiLine = new Ajax.InPlaceEditor($('tobeeditedMultiLine'), '_ajax_inplaceeditor_result.html', {
+ ajaxOptions: {method: 'get'} //override so we can use a static for the result
+ });
+ }},
+
+ teardown: function() { with(this) {
+ inPlaceEditor.dispose();
+ inPlaceEditorMultiLine.dispose();
+ }},
+
+ // Original-version tests, still pass thx to backward compatibility
+
+ // Integration test, tests the entire cycle
+ testInPlaceEditor: function() { with(this) {
+ Event.simulateMouse('tobeedited','click');
+ assertHidden($('tobeedited'));
+ assertNotNull(document.forms[0]);
+ assertEqual("cancel", document.forms[0].lastChild.innerHTML);
+ assertVisible(document.forms[0]);
+
+ Event.simulateMouse(document.forms[0].lastChild,'click');
+ assertNull(document.forms[0]);
+ assertVisible($('tobeedited'));
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'));
+ Event.simulateMouse('tobeedited','mouseover');
+ Event.simulateMouse('tobeedited','click');
+
+ assertEqual("INPUT", document.forms[0].firstChild.tagName);
+ assertEqual("To be edited", document.forms[0].firstChild.value);
+ assertEqual("INPUT", document.forms[0].childNodes[1].tagName);
+ assertEqual("submit", document.forms[0].childNodes[1].type);
+ assertEqual("To be edited", document.forms[0].firstChild.value);
+ assert(Element.hasClassName(document.forms[0], 'inplaceeditor-form'),
+ "form doesn't have proper class: " + document.forms[0].className);
+
+ Event.simulateMouse(document.forms[0].childNodes[1],'click');
+
+ assertVisible($('tobeedited'));
+ assertEqual("Saving...", $('tobeedited').innerHTML);
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'));
+ assert(Element.hasClassName($('tobeedited'), 'inplaceeditor-saving'),
+ "doesn't have saving class");
+
+ wait(1000, function() {
+ assertEqual("Server received: To be edited", $('tobeedited').innerHTML);
+ assertNull(document.forms[0]);
+ assertVisible($('tobeedited'));
+ assert(!Element.hasClassName($('tobeedited'), 'inplaceeditor-saving'));
+ });
+ }},
+
+ testHovering: function() { with(this) {
+ Event.simulateMouse('tobeedited','mouseover');
+ assertEqual("rgb(255, 255, 153)", Element.getStyle('tobeedited','background-color'));
+
+ Event.simulateMouse('tobeedited','mouseout');
+ wait(1100, function() {
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'),
+ "should be transparent after mouse leaves element");
+
+ Event.simulateMouse('tobeedited','click');
+ })
+ }},
+
+ testLoadsTextFromServer: function() { with(this) {
+ inPlaceEditor.options.loadTextURL = '_ajax_inplaceeditor_text.html';
+ inPlaceEditor.enterEditMode();
+ assertEqual('Loading...', inPlaceEditor._form.value.value);
+ assert(inPlaceEditor._form.value.disabled);
+ assert(Element.hasClassName(inPlaceEditor._form, 'inplaceeditor-loading'));
+ wait(1000, function() {
+ assertEqual('Text from server', inPlaceEditor._form.value.value);
+ assert(!inPlaceEditor._form.value.disabled);
+ });
+ }},
+
+ testDisposesProperly: function() { with(this) {
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'));
+ inPlaceEditor.dispose();
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'));
+ assertVisible($('tobeedited'));
+ Event.simulateMouse('tobeedited','click');
+ assertVisible($('tobeedited'));
+ }},
+
+ testUsesTextAreaWhenMoreThanOneRows: function() { with(this) {
+ inPlaceEditor.options.rows = 5;
+ inPlaceEditor.enterEditMode();
+ assertEqual("TEXTAREA", document.forms[0].firstChild.tagName);
+ assertEqual("BR", document.forms[0].childNodes[1].tagName);
+ }},
+
+ testCanSpecifyAllTextsThroughOptions: function() { with(this) {
+ // swedish translation ;-)
+ inPlaceEditor.options.okText = "spara";
+ inPlaceEditor.options.cancelText = "avbryt";
+ inPlaceEditor.options.savingText = "Sparar...";
+ inPlaceEditor.enterEditMode();
+ assertEqual("spara", document.forms[0].lastChild.previousSibling.value);
+ assertEqual("avbryt", document.forms[0].lastChild.innerHTML);
+ inPlaceEditor.showSaving();
+ assertEqual("Sparar...", $('tobeedited').innerHTML);
+ }},
+
+ testCanSpecifyFormIdThroughOptions: function() { with(this) {
+ inPlaceEditor.enterEditMode();
+ // default form id
+ assertEqual("tobeedited-inplaceeditor", document.forms[0].id);
+ inPlaceEditor.leaveEditMode();
+ inPlaceEditor.options.formId = "myFormId";
+ inPlaceEditor.enterEditMode();
+ assertEqual("myFormId", document.forms[0].id);
+ }},
+
+ testCantEditWhileSaving: function() { with(this) {
+ inPlaceEditor.prepareSubmission();
+ Event.simulateMouse('tobeedited','mouseover');
+ assertEqual("transparent", Element.getStyle('tobeedited','background-color'));
+ Event.simulateMouse('tobeedited','click');
+ assertVisible($('tobeedited'));
+ }},
+
+ testCallbackFunctionGetsCalled: function() { with(this) {
+ var called = false;
+ inPlaceEditor.options.callback = function(form) {
+ called = true;
+ }
+ Event.simulateMouse('tobeedited','click');
+ Event.simulateMouse(document.forms[0].childNodes[1],'click');
+ assert(called, "callback was not called");
+ }},
+
+ testCanUseExternalElementToGoIntoEditMode: function() { with(this) {
+ Event.simulateMouse('tobeeditedEditControl','click');
+ assertNotNull(document.forms[0], "external control didn't work");
+ // doesn't work if you click it again while in edit mode
+ Event.simulateMouse('tobeeditedEditControl','click');
+ assertNull(document.forms[1], "external control created two forms");
+ assertNotVisible($('tobeeditedEditControl'));
+ Event.simulateMouse(document.forms[0].childNodes[2],'click');
+ assertVisible($('tobeeditedEditControl'));
+ }},
+
+ // Rewritten-version tests
+ testControlOptions: function() {with(this) {
+ // Default, then explicit default-equivalent, settings
+ [{}, { okControl: 'button', cancelControl: 'link' }].each(function(opts) {
+ var ipe = new Ajax.InPlaceEditor('newtbe', '', opts);
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(1, submits.length, 'Not just one submit');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.okText, submits[0].value, 'Incorrect button label');
+ assert(submits[0].hasClassName('editor_ok_button'), 'Missing class name on ok button');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(1, links.length, 'Not just one link');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.cancelText, links[0].firstChild.nodeValue, 'Incorrect cancel link text');
+ assert(links[0].href.endsWith('#'), 'Incorrect cancel link href');
+ assert(links[0].hasClassName('editor_cancel_link'), 'Missing class name on cancel link');
+ ipe.dispose();
+ });
+ // Reverse: ok link, cancel button
+ var ipe = new Ajax.InPlaceEditor('newtbe', '', { okControl: 'link', cancelControl: 'button' });
+ Event.simulateMouse('newtbe', 'click');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(1, links.length, 'Not just one link');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.okText, links[0].firstChild.nodeValue, 'Incorrect ok link text');
+ assert(links[0].href.endsWith('#'), 'Incorrect ok link href');
+ assert(links[0].hasClassName('editor_ok_link'), 'Missing class name on ok link');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(1, submits.length, 'Not just one submit');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.cancelText, submits[0].value, 'Incorrect button label');
+ assert(submits[0].hasClassName('editor_cancel_button'), 'Missing class name on cancel button');
+ ipe.dispose();
+ // Full links
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { okControl: 'link' });
+ Event.simulateMouse('newtbe', 'click');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(2, links.length, 'There should be two links');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.okText, links[0].firstChild.nodeValue, 'Incorrect ok link text');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.cancelText, links[1].firstChild.nodeValue, 'Incorrect cancel link text');
+ assert(links[0].href.endsWith('#'), 'Incorrect ok link href');
+ assert(links[1].href.endsWith('#'), 'Incorrect cancel link href');
+ assert(links[0].hasClassName('editor_ok_link'), 'Missing class name on ok link');
+ assert(links[1].hasClassName('editor_cancel_link'), 'Missing class name on cancel link');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(0, submits.length, 'There should be no submit');
+ ipe.dispose();
+ // Full buttons
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { cancelControl: 'button' });
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(2, submits.length, 'There should be two submits');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.okText, submits[0].value, 'Incorrect ok button text');
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.cancelText, submits[1].value, 'Incorrect cancel button text');
+ assert(submits[0].hasClassName('editor_ok_button'), 'Missing class name on ok button');
+ assert(submits[1].hasClassName('editor_cancel_button'), 'Missing class name on cancel button');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(0, links.length, 'There should be no link');
+ ipe.dispose();
+ // No cancel
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { cancelControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(1, submits.length, 'Not just one submit');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(0, links.length, 'There should be no link');
+ ipe.dispose();
+ // No OK
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { okControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(0, submits.length, 'There should be no submit');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(1, links.length, 'Not just one link');
+ ipe.dispose();
+ // Nothing
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { okControl: false, cancelControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(0, submits.length, 'There should be no submit');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(0, links.length, 'There should be no link');
+ ipe.dispose();
+ // Texts: default mode
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { okControl: false, cancelControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var submits = $('newtbe-inplaceeditor').getInputs('submit');
+ assertEqual(0, submits.length, 'There should be no submit');
+ var links = $$('#newtbe-inplaceeditor a');
+ assertEqual(0, links.length, 'There should be no link');
+ ipe.dispose();
+ // Texts: before w/ controls
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textBeforeControls: '[' });
+ Event.simulateMouse('newtbe', 'click');
+ var text = $('newtbe-inplaceeditor').childNodes[1];
+ assertEqual(3, text.nodeType, 'Missing/misplaced initial text');
+ assertEqual('[', text.nodeValue, 'Incorrect text');
+ ipe.dispose();
+ // Texts: after w/ controls
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textAfterControls: ']' });
+ Event.simulateMouse('newtbe', 'click');
+ var text = $('newtbe-inplaceeditor').childNodes[3];
+ assertEqual(3, text.nodeType, 'Missing/misplaced final text');
+ assertEqual(']', text.nodeValue, 'Incorrect text');
+ ipe.dispose();
+ // Texts: between w/ controls
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textBetweenControls: ' ' });
+ Event.simulateMouse('newtbe', 'click');
+ var text = $('newtbe-inplaceeditor').childNodes[2];
+ assertEqual(3, text.nodeType, 'Missing/misplaced middle text');
+ assertEqual(' ', text.nodeValue, 'Incorrect text');
+ ipe.dispose();
+ // Texts: before w/ no control
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textBeforeControls: '[', okControl: false, cancelControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var nodes = $('newtbe-inplaceeditor').childNodes;
+ assertEqual(1, nodes.length, 'Too many nodes in the form.');
+ ipe.dispose();
+ // Texts: after w/ no control
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textAfterControls: ']', okControl: false, cancelControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var nodes = $('newtbe-inplaceeditor').childNodes;
+ assertEqual(1, nodes.length, 'Too many nodes in the form.');
+ ipe.dispose();
+ // Texts: between w/ less than two controls
+ ipe = new Ajax.InPlaceEditor('newtbe', '', { textBetweenControls: ' ', okControl: false });
+ Event.simulateMouse('newtbe', 'click');
+ var nodes = $('newtbe-inplaceeditor').childNodes;
+ assertEqual(2, nodes.length, 'The form should have only two nodes (edit+cancel)');
+ assertEnumEqual(['input', 'a'], $A(nodes).pluck('tagName').invoke('toLowerCase'), 'Incorrect nodes');
+ ipe.dispose();
+ }},
+
+ testExternalControlOnly: function() {with(this) {
+ var ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', {
+ externalControl: 'newtbe_external'
+ });
+ Event.simulateMouse('newtbe', 'click');
+ assert(ipe._editing, 'Clicking on the element should turn editable.');
+ ipe.leaveEditMode();
+ Event.simulateMouse('newtbe_external', 'click');
+ assert(ipe._editing, 'Clicking on the external control should turn editable.');
+ ipe.dispose();
+ ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', {
+ externalControl: 'newtbe_external', externalControlOnly: true
+ });
+ Event.simulateMouse('newtbe', 'click');
+ assert(!ipe._editing, 'Clicking on the element should not turn editable.');
+ Event.simulateMouse('newtbe_external', 'click');
+ assert(ipe._editing, 'Clicking on the external control should turn editable.');
+ ipe.dispose();
+ }},
+
+ testNewCallbacks: function() {with(this) {
+ var called = [];
+ var opts = {
+ onEnterHover: function() { called.push('onEnterHover') },
+ onEnterEditMode: function() { called.push('onEnterEditMode') },
+ onLeaveEditMode: function() { called.push('onLeaveEditMode') },
+ callback: function(form) {
+ called.push('callback');
+ return form.serialize();
+ },
+ onFailure: function() { called.push('onFailure') },
+ onComplete: function() { called.push('onComplete') },
+ onLeaveEditMode: function() { called.push('onLeaveEditMode') }
+ }
+ // Proper success
+ $('newtbe').update('New to be edited');
+ var ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', opts);
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ var postUpdateHTML;
+ wait(1000, function() {
+ assertEnumEqual(['onEnterHover', 'onEnterEditMode', 'callback', 'onLeaveEditMode', 'onComplete'],
+ called.uniq(), 'Incorrect callback sequence');
+ postUpdateHTML = $('newtbe').innerHTML.strip();
+ assertEqual('New to be edited - edited', postUpdateHTML, 'Update trouble');
+ ipe.dispose();
+ // Failure
+ called.clear();
+ // Any ideas? Requesting file:// URLs on non-existent stuff doesn't trigger A.U's onFailure...
+ });
+ }},
+
+ testCallbackFunctionReturnTypes: function() { with(this) {
+ var params = [];
+ var responder = {
+ onCreate: function(req) {
+ params.push(req.options.parameters);
+ }
+ };
+ Ajax.Responders.register(responder);
+ var ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', {
+ callback: function(form) {
+ return 'foo=bar';
+ }
+ });
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(200, function() {
+ assert(params[0] && params[0].foo == 'bar');
+ ipe.dispose();
+ ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', {
+ callback: function(form) {
+ return { bar: '?', 'r&d': 42 };
+ }
+ });
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(200, function() {
+ assert(params[1] && params[1].bar == '?' && params[1]['r&d'] == 42);
+ ipe.dispose();
+ Ajax.Responders.unregister(responder);
+ })
+ });
+ }},
+
+ testHtmlResponse: function() {with(this) {
+ // Default (true) -> A.U w/ evalScripts: true
+ $('newtbe').update('New to be edited');
+ var ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ var postUpdateHTML;
+ wait(1000, function() {
+ postUpdateHTML = $('newtbe').innerHTML.strip();
+ assertEqual('New to be edited - edited', postUpdateHTML, 'Should have updated contents');
+ ipe.dispose();
+ // Explicit htmlResponse: true -> A.U w/ evalScripts: true
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', { htmlResponse: true });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ postUpdateHTML = $('newtbe').innerHTML.strip();
+ assertEqual('New to be edited - edited', postUpdateHTML, 'Should have updated contents');
+ ipe.dispose();
+ // Explicit htmlResponse: false -> A.R
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', { htmlResponse: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ postUpdateHTML = $('newtbe').innerHTML.strip();
+ assertEqual(ipe.options.savingText, postUpdateHTML, 'Should not have updated contents');
+ ipe.dispose();
+ });
+ });
+ });
+ }},
+
+ testSingleOrMultipleRows: function() {with(this) {
+ // Single-line value, rows <= 1 -> 1
+ $('newtbe').update('New to be edited');
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('input', ipe._controls.editor.tagName.toLowerCase());
+ ipe.dispose();
+ // Single-line value, rows > 1 (2) -> 2
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { rows: 2 });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('textarea', ipe._controls.editor.tagName.toLowerCase());
+ assertEqual(2, ipe._controls.editor.rows);
+ ipe.dispose();
+ // Multiple-line value, rows <= 1, autoRows default (3) -> 3
+ $('newtbe').update('Line 1\nLine 2\nLine 3');
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('textarea', ipe._controls.editor.tagName.toLowerCase());
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.autoRows, ipe._controls.editor.rows);
+ ipe.dispose();
+ // Multiple-line value, rows <= 1, autoRows custom (5) -> 5
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { autoRows: 5 });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('textarea', ipe._controls.editor.tagName.toLowerCase());
+ assertEqual(5, ipe._controls.editor.rows);
+ ipe.dispose();
+ // Multiple-line value, rows > 1 (2), autoRows default (3) -> 2
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { rows: 2 });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('textarea', ipe._controls.editor.tagName.toLowerCase());
+ assertEqual(2, ipe._controls.editor.rows);
+ ipe.dispose();
+ // Multiple-line value, rows > 1 (2), autoRows custom (5) -> 2
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { rows: 2, autoRows: 5 });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('textarea', ipe._controls.editor.tagName.toLowerCase());
+ assertEqual(2, ipe._controls.editor.rows);
+ ipe.dispose();
+ }},
+
+ testFormCustomizationCallback: function() {with(this) {
+ var ipe = new Ajax.InPlaceEditor('newtbe', '_ajax_inplaceeditor_result2.html', {
+ onFormCustomization: function(ipe, form) {
+ form.appendChild(new Element('input', { type: 'text', name: 'test', value: 'foobar' }));
+ }
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assertEqual('foobar', Form.serialize(ipe._form, true).test, 'Custom field not present');
+ ipe.dispose();
+ }},
+
+ testPostCreationBehavior: function() {with(this) {
+ var focused = false, activated = false;
+ function override(name, fx) {
+ arguments.callee.backups[name] = Field.Methods[name];
+ Field.Methods[name] = fx;
+ };
+ override.backups = {};
+ function restore() {
+ $A(arguments).each(function(n) {
+ Field.Methods[name] = override.backups[name];
+ });
+ Element.addMethods();
+ };
+ override('activate', function(elt) {
+ override.backups['activate'](elt);
+ activated = true;
+ });
+ override('focus', function(elt) { focused = true; });
+ Element.addMethods();
+ // fieldPostCreation default (activate)
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assert(focused && activated, "Should be focused and activated (resp. " + focused + " and " + activated + ')');
+ ipe.dispose();
+ // fieldPostCreation == 'focus'
+ focused = activated = false;
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { fieldPostCreation: 'focus' });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assert(focused && !activated, "Should be focused, not activated (resp. " + focused + " and " + activated + ')');
+ ipe.dispose();
+ // fieldPostCreation == false
+ focused = activated = false;
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { fieldPostCreation: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assert(!focused && !activated, "Should be neither focused nor activated (resp. " + focused + " and " + activated + ')');
+ ipe.dispose();
+ // fieldPostCreation == non-false yet neither activate nor focus -> default
+ focused = activated = false;
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { fieldPostCreation: 'foobar' });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ assert(focused && activated, "Should be focused and activated (resp. " + focused + " and " + activated + ')');
+ ipe.dispose();
+ restore('activate', 'focus');
+ }},
+
+ testResponseTagStripping: function() {with(this) {
+ // stripLoadedTextTags default (false)
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html',
+ { loadTextURL: '_ajax_inplaceeditor_tagged.html' });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ wait(1000, function() {
+ assertEqual('<span>New to be edited - edited</span>', ipe._controls.editor.value.strip());
+ ipe.dispose();
+ // stripLoadedTextTags == true
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html',
+ { loadTextURL: '_ajax_inplaceeditor_tagged.html',
+ stripLoadedTextTags: true });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ wait(1000, function() {
+ assertEqual('New to be edited - edited', ipe._controls.editor.value.strip());
+ ipe.dispose();
+ });
+ });
+ }},
+
+ testSubmitOnBlur: function() {with(this) {
+ // submitOnBlur default (false)
+ $('newtbe').update('To be edited');
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ ipe._controls.editor.blur();
+ wait(1000, function() {
+ assertEqual('To be edited', ipe._controls.editor ? ipe._controls.editor.value : '');
+ ipe.dispose();
+ // submitOnBlur == true
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { submitOnBlur: true });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ ipe._controls.editor.blur();
+ wait(1200, function() {
+ assertEqual('New to be edited - edited', $('newtbe').innerHTML.strip());
+ ipe.dispose();
+ });
+ });
+ }},
+
+ testEscReturnKeys: function() {with(this) {
+ // No controls, Esc
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { okControl: false, cancelControl: false});
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_ESC });
+ assert(!ipe._editing, 'Esc should have disabled IPE');
+ ipe.dispose();
+ // Cancel control, Esc
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { okControl: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_ESC });
+ assert(!ipe._editing, 'Esc should have disabled IPE');
+ ipe.dispose();
+ // OK control, Esc
+ var ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { cancelControl: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_ESC });
+ assert(!ipe._editing, 'Esc should have disabled IPE');
+ ipe.dispose();
+ // Both controls, Esc
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_ESC });
+ assert(!ipe._editing, 'Esc should have disabled IPE');
+ ipe.dispose();
+ // No controls, Return
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { okControl: false, cancelControl: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ assertEqual('New to be edited - edited', $('newtbe').innerHTML.strip());
+ ipe.dispose();
+ // Cancel control, Return
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { okControl: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ assertEqual('New to be edited - edited', $('newtbe').innerHTML.strip());
+ ipe.dispose();
+ // OK control, Return
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { cancelControl: false });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ assertEqual('New to be edited - edited', $('newtbe').innerHTML.strip());
+ ipe.dispose();
+ // Both controls, Return
+ $('newtbe').update('New to be edited');
+ ipe = new Ajax.InPlaceEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html');
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ Event.simulateKey('newtbe', 'keydown', { keyCode: Event.KEY_RETURN });
+ wait(1000, function() {
+ assertEqual('New to be edited - edited', $('newtbe').innerHTML.strip());
+ ipe.dispose();
+ });
+ });
+ });
+ });
+ }},
+
+ testIPCEBasic: function() {with(this) {
+ // Basic creation, population and choice.
+ $('newtbe').update('ntbe');
+ var fieldValue = '';
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: IPCE_COLLECTION, callback: function(f, value) {
+ fieldValue = value;
+ }, onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ assertEqual('test', editor.name);
+ assertEqual('select', editor.tagName.toLowerCase());
+ assertEqual(IPCE_COLLECTION.length, editor.options.length, 'Incorrect amount of options');
+ for (var index = 0; index < IPCE_COLLECTION.length; ++index) {
+ var ref = IPCE_COLLECTION[index];
+ var item = editor.options[index];
+ assertEqual(ref[0], item.value, 'Incorrect OPTION value');
+ assertEqual(ref[1], item.text.strip(), 'Incorrect OPTION text');
+ };
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item');
+ editor.selectedIndex = 2;
+ Event.simulateMouse(ipe._controls.ok, 'click');
+ assertEqual('ntbe2', fieldValue);
+ ipe.dispose();
+ // Test the value option
+ $('newtbe').update('ntbe');
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: IPCE_COLLECTION, onComplete: Prototype.emptyFunction,
+ value: 'ntbe2'
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ editor = ipe._controls.editor;
+ assertEqual(2, editor.selectedIndex, 'Did not properly select item');
+ ipe.dispose();
+ }},
+
+ testIPCECollectionSyntaxes: function() {with(this) {
+ // Array of two-item arrays (0 = value, 1 = text)
+ $('newtbe').update('ntbe');
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: IPCE_COLLECTION, onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item');
+ // (further contents testing already done in Basic)
+ ipe.dispose();
+ // Array of one-item arrays
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: [['tbe'], ['ntbe'], ['ntbe2'], ['ntbe3']],
+ onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item');
+ assertEqual('ntbe', $F(editor).strip(), 'Did not properly define text');
+ ipe.dispose();
+ // Array of items
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: ['tbe', 'ntbe', 'ntbe2', 'ntbe3'],
+ onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item');
+ assertEqual('ntbe', $F(editor).strip(), 'Did not properly define text');
+ ipe.dispose();
+ }},
+
+ testIPCEAlternateTextOptions: function() {with(this) {
+ // loadTextURL (check loading text, verify alternate text eventually)
+ $('newtbe').update('New to be edited');
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ collection: IPCE_COLLECTION, loadTextURL: '_ajax_inplaceeditor_ipce_alt_text.html',
+ onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ var text = editor.options[editor.selectedIndex].text.strip();
+ assertEqual(Ajax.InPlaceEditor.DefaultOptions.loadingText, text);
+ wait(1200, function() {
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item based on alternate text.');
+ ipe.dispose();
+ });
+ }},
+
+ testIPCEDynamicCollectionOptions: function() {with(this) {
+ // loadCollectionURL, default loadingCollectionText
+ $('newtbe').update('ntbe');
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ loadCollectionURL: '_ajax_inplaceeditor_ipce_collection.js',
+ onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ var text = editor.options[editor.selectedIndex].text.strip();
+ assertEqual(Ajax.InPlaceCollectionEditor.DefaultOptions.loadingCollectionText, text);
+ wait(1000, function() {
+ assertEqual(5, ipe._collection.length);
+ assertEqual(2, editor.selectedIndex, 'Did not properly select item');
+ ipe.dispose();
+ // loadCollectionURL, custom loadingCollectionText
+ $('newtbe').update('bar');
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ loadCollectionURL: '_ajax_inplaceeditor_ipce_collection.js',
+ loadingCollectionText: 'There we go...',
+ onComplete: Prototype.emptyFunction
+ });
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ editor = ipe._controls.editor;
+ text = editor.options[editor.selectedIndex].text.strip();
+ assertEqual('There we go...', text);
+ wait(1000, function() {
+ assertEqual(1, editor.selectedIndex, 'Did not properly select item');
+ ipe.dispose();
+ });
+ });
+ }},
+
+ testIPCEATPlusDC: function() {with(this) {
+ // loadCollectionURL, loadTextURL
+ $('newtbe').update('Like I care');
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ loadCollectionURL: '_ajax_inplaceeditor_ipce_collection.js',
+ loadingCollectionText: 'There we go...',
+ loadTextURL: '_ajax_inplaceeditor_ipce_alt_text.html',
+ loadingText: 'OK, so, the text...',
+ onComplete: Prototype.emptyFunction
+ });
+ ipe._regularCFET = ipe.checkForExternalText;
+ ipe.checkForExternalText = function() {
+ assert(5, ipe._collection.length);
+ ipe._regularCFET();
+ var editor = ipe._controls.editor;
+ var text = editor.options[editor.selectedIndex].text.strip();
+ assertEqual('OK, so, the text...', text);
+ };
+ Event.simulateMouse('newtbe', 'mouseover');
+ Event.simulateMouse('newtbe', 'click');
+ var editor = ipe._controls.editor;
+ var text = editor.options[editor.selectedIndex].text.strip();
+ assertEqual('There we go...', text);
+ wait(2000, function() {
+ assertEqual(2, editor.selectedIndex, 'Did not properly select item');
+ ipe.dispose();
+ });
+ }},
+
+ testDeprecationLayer: function() {with(this) {
+ // FIXME: needs to be coded yet, doesn't it?
+ var ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ okButton: false, cancelLink: false
+ });
+ assertIdentical(false, ipe.options.okControl, 'OK control should be disabled');
+ assertIdentical(false, ipe.options.cancelControl, 'Cancel control should be disabled');
+ ipe.dispose();
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ okLink: true, cancelButton: true
+ });
+ assertEqual('link', ipe.options.okControl, 'OK control should be a link');
+ assertEqual('button', ipe.options.cancelControl, 'Cancel control should be a button');
+ ipe.dispose();
+ ipe = new Ajax.InPlaceCollectionEditor('newtbe',
+ '_ajax_inplaceeditor_result2.html', { paramName: 'test',
+ highlightcolor: '#ff0000', highlightendcolor: '#00ff00'
+ });
+ assertEqual('#ff0000', ipe.options.highlightColor, 'Highlight color was not migrated');
+ assertEqual('#00ff00', ipe.options.highlightEndColor, 'Highlight end color was not migrated');
+ ipe.dispose();
+ }},
+
+
+ testShouldShowAmpersandsProperly: function() {with(this) {
+ var ipe = new Ajax.InPlaceEditor('contains_ampersand', '', {});
+ Event.simulateMouse('contains_ampersand', 'click');
+ assertEqual("Me & Myself", $$('form#contains_ampersand-inplaceeditor input.editor_field')[0].value);
+ ipe.dispose();
+ }}
+ // FIXME: add AC w/o key conflicts?
+ // FIXME: doc w/ full details on what's new, what's changed, etc. + deprecation layer info.
+ });
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/bdd_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/bdd_test.html
new file mode 100644
index 000000000..3f6373027
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/bdd_test.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<div id="d">initial</div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+var moo = 0;
+
+var assertMethods = [];
+for(method in Test.Unit.Assertions.prototype) {
+ if(/^assert/.test(method)) assertMethods.push(method);
+}
+
+var testObj = {
+ isNice: function(){
+ return true;
+ },
+ isBroken: function(){
+ return false;
+ }
+}
+
+Test.context("BDD-style testing",{
+
+ setup: function() {
+ $('d').update('setup!');
+ moo++;
+ },
+
+ teardown: function() {
+ moo--;
+ },
+
+ 'should run setup before each specification': function(){
+ assert($('d').innerHTML == 'setup!');
+ assert(moo == 1);
+ },
+
+ 'should run teardown after each specification': function(){
+ assert(moo == 1);
+ },
+
+ 'should provide extensions to tie in isSomething and respondsTo object methods': function(){
+ Object.extend(testObj, Test.BDDMethods);
+
+ testObj.shouldBe('nice');
+ testObj.shouldNotBe('broken');
+
+ testObj.shouldRespondTo('isNice');
+ testObj.shouldRespondTo('isBroken');
+ },
+
+ 'should automatically add extensions to strings': function(){
+ 'a'.shouldEqual('a');
+ 'a'.shouldNotEqual('b');
+ 'a'.shouldNotBeNull();
+ 'a'.shouldBeA(String);
+
+ var aString = 'boo!';
+ aString.shouldEqual('boo!');
+ aString.shouldBeA(String);
+ aString.shouldNotBeA(Number);
+ },
+
+ 'should automatically add extensions to numbers': function(){
+ var n = 123;
+ n.shouldEqual(123);
+ n.shouldNotEqual(4);
+
+ n.shouldBeA(Number);
+ n.shouldNotBeA(Test);
+ },
+
+ 'should automatically add extensions to arrays': function(){
+ ['a'].shouldNotBeA(String);
+ [1,2,3].shouldBeAn(Array);
+ [1,2,3].shouldEqualEnum([1,2,3]);
+ },
+
+ 'should automatically add extensions to booleans': function(){
+ var theTruth = true;
+ var lies = false;
+
+ theTruth.shouldNotBeA(String);
+ lies.shouldBeA(Boolean);
+ 'false'.shouldNotBeA(Boolean);
+
+ theTruth.shouldEqual(true);
+ lies.shouldNotEqual(true);
+ },
+
+ 'should support the eval() method': function(){
+ eval('2*2').shouldEqual(4);
+ },
+
+ 'should support equality assertion': function(){
+ assertEqual(1, 1);
+ assertEqual('a', 'a');
+ assertEqual(1, '1');
+
+ var x = 1;
+ var y = 1;
+ assertEqual(1, x)
+ assertEqual(x, y);
+ },
+
+ 'should provide all assertions': function(){
+ assertMethods.each(function(m){
+ assert(typeof this[m] == 'function');
+ }.bind(this));
+ },
+
+ 'should support deferred execution': function(){
+ wait(10,function(){
+ 'a'.shouldEqual('a');
+ });
+
+ wait(10,function(){
+ 'a'.shouldEqual('a');
+ wait(10,function(){
+ 'a'.shouldEqual('a');
+ wait(10,function(){
+ 'a'.shouldEqual('a');
+ });
+ });
+ });
+ }
+
+});
+
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/builder_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/builder_test.html
new file mode 100644
index 000000000..09f70f7be
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/builder_test.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for builder.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<div id="result"></div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ // Serializes a node and it's contents to plain old HTML
+ // IMPORTANT: style attributes can't be correctly serialized cross-browser wise,
+ // so the contents of style attributes must match what IE thinks is correct
+ function serializeNode(node){
+ if(node.nodeType == 3) return node.nodeValue;
+ node = $(node);
+ var tag = node.tagName.toLowerCase();
+ return '<' + ([tag].concat($A(node.attributes).map(function(attr){
+ // Filter out stuff that we don't need
+ if(attr.nodeName == '_extended' || attr.nodeName == '_counted' ||
+ typeof attr.nodeValue == 'function' ||!Element.hasAttribute(node, attr.nodeName)) return;
+ // remove trailing ; in style attributes on Firefox
+ var value = node.readAttribute(attr.nodeName);
+ if(attr.nodeName == 'style' && value.endsWith(';'))
+ value = value.substr(0, value.length-1);
+ return attr.nodeName + '="' + value + '"'
+ }).compact().sort())).join(' ') + '>' + $A(node.childNodes).map(serializeNode).join('') +
+ '</' + tag + '>';
+ }
+
+ new Test.Unit.Runner({
+
+ setup: function() {
+ $('result').innerHTML = '';
+ },
+
+ testBuilderBasics: function() { with(this) {
+ var element = Builder.node('div');
+ assertEqual('DIV', element.nodeName);
+
+ var element = Builder.node('div',{id:'mydiv'})
+ assertEqual('mydiv', element.id);
+
+ var element = Builder.node('div',{id:'mydiv',className:'one two'})
+ assertEqual('mydiv', element.id);
+ assertEqual('one two', element.className);
+
+ var element = Builder.node('span','text 123 <blah>');
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('text 123 &lt;blah&gt;', element.innerHTML);
+
+ var element = Builder.node('span',123);
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('123', element.innerHTML);
+
+ var element = Builder.node('span',['test']);
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('test', element.innerHTML);
+
+ var element = Builder.node('span',['test',123]);
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('test123', element.innerHTML);
+
+ var element = Builder.node('span',{},['test',123]);
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('test123', element.innerHTML);
+
+ var element = Builder.node('span',{id:'myspan'},['test',123]);
+ assertEqual('SPAN', element.nodeName);
+ assertEqual('myspan', element.id);
+ assertEqual('test123', element.innerHTML);
+
+ var element = Builder.node('div',[1,2,[3],[[[4],5],6],7,8,[[[[9]]],0]]);
+ assertEqual('1234567890',element.innerHTML);
+
+ var element = Builder.node('div',[1,'2',['3'],[[[4],'5'],6],7,'8',[[[['9']]],0]]);
+ assertEqual('1234567890',element.innerHTML);
+
+ var element = Builder.node('div',{id:'mydiv'},[1,2,[3],[[[4],5],6],7,8,[[[[9]]],0]]);
+ assertEqual('1234567890',element.innerHTML);
+
+ var element = Builder.node('div',{id:'mydiv'},[1,'2',['3'],[[[4],'5'],6],7,'8',[[[['9']]],0]]);
+ assertEqual('1234567890',element.innerHTML);
+ assertEqual(10, element.childNodes.length);
+
+ var element = Builder.node('div', Builder.node('span'));
+ assertEqual(1, element.childNodes.length);
+ assertEqual('SPAN', element.childNodes[0].tagName);
+
+ var element = Builder.node('div', {id:'mydiv'}, Builder.node('span'));
+ assertEqual(1, element.childNodes.length);
+ assertEqual('mydiv', element.id);
+ assertEqual('SPAN', element.childNodes[0].tagName);
+ }},
+
+ testBuilderClassAndFor: function() { with(this) {
+ var elt = Builder.node('div', { className: 'demoClass' });
+ assertEqual('demoClass', elt.className);
+ var elt = Builder.node('label', { htmlFor: 'mydiv' });
+ assertEqual('mydiv', elt.htmlFor);
+ }},
+
+ testBuilderExtendsElement: function() { with(this) {
+ assertRespondsTo('hide', Builder.node('div'));
+ }},
+
+ testBuilderAllXHTMLTags: function() { with(this) {
+ var XHTML_TAGS = [
+ 'a','abbr','acronym','address','applet','area',
+ 'b','bdo','big','blockquote','br','button',
+ 'caption','cite','code','col','colgroup',
+ 'dd','del','dfn','div','dl','dt',
+ 'em',
+ 'fieldset','form',
+ 'h1','h2','h3','h4','h5','h6','hr',
+ 'i','iframe','img','input','ins',
+ 'kbd',
+ 'label','legend','li',
+ 'map',
+ 'object','ol','optgroup','option',
+ 'p','param','pre',
+ 'q',
+ 'samp','script','select','small','span','strong','style','sub','sup',
+ 'table','tbody','td','textarea','tfoot','th','thead','tr','tt',
+ 'ul','var']
+
+ XHTML_TAGS.each(function(tag) {
+ try {
+ var element = Builder.node(tag);
+ assertNotNull(element, 'Tag "'+tag+'" expected, but was null.');
+ assertEqual(tag.toUpperCase(), element.nodeName);
+
+ var element = Builder.node(tag,{id:'tag_'+tag+'_test_id'});
+ assertEqual(tag.toUpperCase(), element.nodeName);
+ assertEqual('tag_'+tag+'_test_id', element.id, 'Setting id attribute for "'+tag+'" failed!');
+ } catch(e) {
+ assert(false, 'Error while creating node of type '+tag+'. Note: Firefox bug in 1.0.X on option and optgroup, fixed in 1.5b1. Internet Explorer 6 doesn\'t support the ABBR tag and has no standard DOM implementation for tables.');
+ }
+ });
+ }},
+
+ // special case, because requires workarounds on IE and Firefox < 1.5
+ testBuilderOptionTag: function() { with(this) {
+ assertEqual('', Builder.node('option').innerHTML);
+ assertEqual('test', Builder.node('option','test').innerHTML);
+ assertEqual('', Builder.node('option',{className:'test'}).innerHTML);
+ assertEqual('test', Builder.node('option',{className:'test'},'test').innerHTML);
+ assertEqual('test', Builder.node('option',{},'test').innerHTML);
+
+ var selectElement = Builder.node('select');
+ var optionElement = Builder.node('option',{className:'test',id:'option_123'},123);
+ selectElement.appendChild(optionElement);
+ document.body.appendChild(selectElement);
+ assertEqual('123', $('option_123').innerHTML);
+ }},
+
+ testBuilderContatenation: function() { with(this) {
+ var element = Builder.node('div', [Builder.node('span')]);
+ assertEqual('DIV', element.nodeName);
+ assertEqual(1, element.childNodes.length);
+ assertEqual('SPAN', element.firstChild.nodeName);
+
+ var element = Builder.node('div', [Builder.node('span'),'text']);
+ assertEqual(2, element.childNodes.length);
+ assertEqual(0, element.firstChild.childNodes.length);
+ assertEqual('DIV', element.nodeName);
+ assertEqual('SPAN', element.firstChild.nodeName);
+ assertEqual(3, element.firstChild.nextSibling.nodeType);
+
+ var element = Builder.node('div', [Builder.node('span',[Builder.node('strong','blah')]),'text']);
+ assertEqual(2, element.childNodes.length);
+ assertEqual(1, element.firstChild.childNodes.length);
+ assertEqual('DIV', element.nodeName);
+ assertEqual('SPAN', element.firstChild.nodeName);
+ assertEqual('STRONG', element.firstChild.firstChild.nodeName);
+ assertEqual('blah', element.firstChild.firstChild.innerHTML);
+ assertEqual(3, element.firstChild.nextSibling.nodeType);
+ }},
+
+ testBuilderComplexExample: function() { with(this) {
+ var element = Builder.node('div',{id:'ghosttrain'},[
+ Builder.node('div',{style:'font-weight: bold; font-size: 11px'},[
+ Builder.node('h1','Ghost Train'),
+ "testtext", 2, 3, 4,
+ Builder.node('ul',[
+ Builder.node('li',{onclick:'alert(\'test\')'},'click me')
+ ]),
+ ]),
+ ]);
+ assertEqual('DIV', element.nodeName);
+
+ $('result').appendChild(element);
+
+ // browsers aren't sure about upper and lower case on elements
+ assertEqual(
+ '<div id="ghosttrain"><div style="font-weight: bold; font-size: 11px">' +
+ '<h1>Ghost Train</h1>testtext234<ul><li onclick="alert(\'test\')">click me</li></ul></div></div>',
+ serializeNode($('result').childNodes[0]));
+ }},
+
+ testBuilderShortcuts: function() { with(this) {
+ Builder.dump();
+
+ var element = DIV(SPAN());
+ assertEqual('SPAN', element.childNodes[0].tagName);
+
+ var element = DIV({id:'test'},SPAN());
+ assertEqual('SPAN', element.childNodes[0].tagName);
+
+ var element = DIV({id:'ghosttrain'},[
+ DIV({style:'font-weight: bold; font-size: 11px'},[
+ H1('Ghost Train'),
+ "testtext", 2, 3, 4,
+ UL([
+ LI({onclick:'alert(\'test\')'},'click me')
+ ]),
+ ]),
+ ]);
+ assertEqual('DIV', element.nodeName);
+
+ $('result').appendChild(element);
+
+ assertEqual(
+ '<div id="ghosttrain"><div style="font-weight: bold; font-size: 11px">' +
+ '<h1>Ghost Train</h1>testtext234<ul><li onclick="alert(\'test\')">click me</li></ul></div></div>',
+ serializeNode($('result').childNodes[0]));
+ }},
+
+ testBuilderBuild: function() { with(this) {
+ ['<span>this is <b>neat!</b></span>',' \n<span>this is <b>neat!</b></span>\n '].each(
+ function(html){
+ var node = Builder.build(html);
+ assertEqual('<span>this is <b>neat!</b></span>', serializeNode(node));
+ });
+ }},
+
+ testBuilderAttributeEscaping: function() { with(this) {
+ var element = Builder.node('div',{blah:"<foo'bar&baz\"bat>"});
+ assertEqual("<foo'bar&baz\"bat>", $(element).readAttribute('blah'));
+ }}
+
+ });
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/dragdrop_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/dragdrop_test.html
new file mode 100644
index 000000000..686bd0f6f
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/dragdrop_test.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #div_absolute_test { position: absolute }
+ /* ]]> */
+ </style>
+
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Test of drag &amp; drop functions in dragdrop.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<p id="p_test">p_test</p>
+<p id="p_test2">p_test2</p>
+<p id="p_test3">p_test3</p>
+<img id="img_test" src="icon.png" alt="img_text"/>
+<div id="droppable_test">droppable_test</div>
+
+<div id="div_test">div_test</div>
+<div id="div_absolute_test">div_absolute_test</div>
+<div id="div_absolute_inline_test" style="position:absolute">div_absolute_inline_test</div>
+
+<div id="droppable_container">
+ <div id="d1">droppable_test</div>
+ <div id="d2">droppable_test</div>
+</div>
+
+<div id="droppable_container_2">
+ <div id="d3">droppable_test</div>
+</div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ new Test.Unit.Runner({
+
+ testDraggableBasics: function() { with(this) {
+ var d = new Draggable('p_test');
+ assertInstanceOf(Draggable, d);
+ }},
+
+ testDraggableStartEffect: function() { with(this) {
+ var d = new Draggable('p_test2');
+ assert(d.options.starteffect, 'There should be a default start effect.');
+ d = new Draggable('p_test3', { endeffect: Prototype.EmptyFunction });
+ assert(undefined === d.options.startEffect, 'There should be no default start effect.');
+ }},
+
+ testAutoPositioning: function() { with(this) {
+ assertEqual('static', Element.getStyle('div_test','position'));
+ new Draggable('div_test');
+ new Draggable('div_absolute_test');
+ new Draggable('div_absolute_inline_test');
+ assertEqual('relative', Element.getStyle('div_test','position'));
+ assertEqual('absolute', Element.getStyle('div_absolute_test','position'));
+ assertEqual('absolute', Element.getStyle('div_absolute_inline_test','position'));
+ }},
+
+ testDroppbalesBasics: function() { with(this) {
+ assertEqual(0, Droppables.drops.length);
+ assertEqual('static', Element.getStyle('droppable_test','position'));
+
+ Droppables.add('droppable_test');
+ assertEqual(1, Droppables.drops.length);
+ assertEqual('relative', Element.getStyle('droppable_test','position'));
+
+ Droppables.remove('droppable_test');
+ assertEqual(0, Droppables.drops.length);
+
+ // accept option should take strings or array of strings
+ Droppables.add('droppable_test',{accept:'document'});
+ assertEqual(['document'].inspect(), Droppables.drops[0].accept.inspect());
+ Droppables.remove('droppable_test');
+
+ Droppables.add('droppable_test',{accept:['document','image']});
+ assertEqual(['document','image'].inspect(), Droppables.drops[0].accept.inspect());
+ Droppables.remove('droppable_test');
+ }},
+
+ testDroppableContainment: function() { with(this) {
+ // Droppable containers should be cached
+ Droppables.add('droppable_test', {
+ containment:'droppable_container' });
+ assertEqual(1, Droppables.drops[0]._containers.length);
+ assertEqual($('droppable_container'), Droppables.drops[0]._containers[0]);
+ assert(Droppables.isContained($('d1'), Droppables.drops[0]));
+ assert(Droppables.isContained($('d2'), Droppables.drops[0]));
+ assert(!Droppables.isContained($('d3'), Droppables.drops[0]));
+ Droppables.remove('droppable_test');
+
+ Droppables.add('droppable_test', {
+ containment:['droppable_container','droppable_container_2'] });
+ assertEqual(2, Droppables.drops[0]._containers.length);
+ assertEqual($('droppable_container'), Droppables.drops[0]._containers[0]);
+ assertEqual($('droppable_container_2'), Droppables.drops[0]._containers[1]);
+ assert(Droppables.isContained($('d1'), Droppables.drops[0]));
+ assert(Droppables.isContained($('d2'), Droppables.drops[0]));
+ assert(Droppables.isContained($('d3'), Droppables.drops[0]));
+ Droppables.remove('droppable_test');
+ }},
+
+ testDroppablesIsAffected: function() { with(this) {
+ Droppables.add('droppable_test');
+
+ Position.prepare();
+ assert(!Droppables.isAffected([-10, -10], null, Droppables.drops[0]));
+
+ var p = Position.page($('droppable_test'));
+ assert(Droppables.isAffected(p, null, Droppables.drops[0]));
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/effects_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/effects_test.html
new file mode 100644
index 000000000..5ef1658f5
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/effects_test.html
@@ -0,0 +1,547 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ #rotfl {
+ color: red;
+ font-family: serif;
+ font-style: italic;
+ font-size: 40px;
+ background: #fed;
+ padding: 1em;
+ width: 400px;
+ }
+ .final {
+ color: #fff;
+ font-style: italic;
+ background: #000;
+ opacity: 0.5;
+ }
+ body div.final {
+ font-size: 20px;
+ }
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for effects.js
+</p>
+
+<!-- generated elements go in here -->
+<div id="sandbox"></div>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<div class="morphing blub" style="font-size:25px;color:#f00">Well</div>
+<div class="morphing">You know</div>
+<div id="blah" style="border:1px solid black;width:100px">Whoo-hoo!</div>
+
+<div id="error_message">ERROR MESSAGE</div>
+<div id="error_message_2">SECOND ERROR MESSAGE</div>
+<div id="error_message_3" style="border:1px solid red; width:100px; color: #f00">THIRD ERROR MESSAGE</div>
+
+<ul class="error-list" id="error_test_ul">
+ <li>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</li>
+ <li>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li>
+ <li>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris</li>
+ <li>nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in</li>
+ <li>reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</li>
+</ul>
+
+<div id="rotfl">ROTFL</div>
+
+<div id="tween">foo!</div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ var TAGS =
+ ['div','span','ol','ul','table','p','h1','h2','h3','h4','h5','h6'];
+
+ var COMBINED_EFFECTS =
+ ['Fade','Appear','BlindUp','BlindDown','Puff','SwitchOff','DropOut','Shake',
+ 'SlideUp','SlideDown','Pulsate','Squish','Fold','Grow','Shrink'];
+
+ var COMBINED_RJS_EFFECTS = $w('fade appear blind_up blind_down puff switch_off '+
+ 'drop_out shake slide_up slide_down pulsate squish fold grow shrink');
+
+ var tmp, tmp2;
+
+ new Test.Unit.Runner({
+
+ setup: function() { with (this) {
+ $('sandbox').innerHTML = "";
+ }},
+
+ teardown: function() { with(this) {
+ // remove all queued effects
+ Effect.Queue.each(function(e) { e.cancel() });
+ }},
+
+ testExceptionOnNonExistingElement: function() { with(this) {
+ assertRaise('ElementDoesNotExistError',
+ function(){new Effect.Opacity('nothing-to-see-here')});
+ assertRaise('ElementDoesNotExistError',
+ function(){new Effect.Move('nothing-to-see-here')});
+ assertRaise('ElementDoesNotExistError',
+ function(){new Effect.Scale('nothing-to-see-here')});
+ assertRaise('ElementDoesNotExistError',
+ function(){new Effect.Highlight('nothing-to-see-here')});
+ }},
+
+ testCallbacks: function() { with(this) {
+ tmp = tmp2 = 0;
+ var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5,
+ beforeStart: function() { tmp++ },
+ beforeStartInternal: function() { tmp++ },
+ beforeSetup: function() { tmp++ },
+ beforeSetupInternal: function() { tmp++ },
+ afterSetup: function() { tmp++ },
+ afterSetupInternal: function() { tmp++ },
+ beforeUpdate: function() { tmp2++ },
+ beforeUpdateInternal: function() { tmp2++ },
+ beforeFinish: function() { tmp++ },
+ beforeFinishInternal: function() { tmp++ },
+ afterFinish: function() { tmp++ },
+ afterFinishInternal: function() { tmp++ }
+ });
+ wait(1000, function() {
+ assertEqual(10, tmp);
+ assert(tmp2 > 0);
+ });
+ }},
+
+ testEvent: function() { with(this) {
+ tmp = 0;
+ new Effect.Event({ afterFinish:function(){ tmp++ }, position:'end'});
+ wait(100, function() {
+ assertEqual(1, tmp);
+ });
+ }},
+
+ testTransition: function() { with(this) {
+ // false implies linear
+ var e = new Effect.Opacity('sandbox',{transition:false,from:0.0,to:0.25,duration:0.5});
+ assert(e.options.transition == Effect.Transitions.linear);
+
+ wait(1000, function() {
+ assertEqual(0.25, $('sandbox').getStyle('opacity'));
+ // default to sinoidal
+ var e = new Effect.Opacity('sandbox',{from:0.0,to:0.25,duration:0.5});
+ assert(e.options.transition == Effect.Transitions.sinoidal);
+ wait(1000, function() {
+ assertEqual(0.25, $('sandbox').getStyle('opacity'));
+
+ var transitions = [
+ { transition: Effect.Transitions.linear, expected: 1 },
+ { transition: Effect.Transitions.sinoidal, expected: 1 },
+ { transition: Effect.Transitions.reverse, expected: 0 },
+ { transition: Effect.Transitions.flicker, expected: 1 },
+ { transition: Effect.Transitions.wobble, expected: 1 },
+ { transition: Effect.Transitions.pulse, expected: 1 },
+ { transition: Effect.Transitions.none, expected: 0 }
+ ];
+
+ transitions.each(function(t){
+ var e = new Effect.Opacity('sandbox',{sync:true, from:0, to: 1, transition:t.transition});
+ assert(e.options.transition == t.transition);
+ e.render(1.0);
+ assertEqual(t.expected, e.position, t.transition);
+ });
+
+ });
+ });
+ }},
+
+ testInspect: function() { with(this) {
+ var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5});
+ info( e1.inspect() );
+ assertEqual(0, e1.inspect().indexOf('#<Effect:'));
+ assert(e1.inspect().indexOf('idle')>0);
+ wait(1000, function() {
+ assert(e1.inspect().indexOf('finished')>0);
+ });
+ }},
+
+ testDefaultOptions: function() { with(this) {
+ var oldDefaultOptions = Object.extend({},Effect.DefaultOptions);
+
+ assertEqual(1.0, Effect.DefaultOptions.duration);
+ Effect.DefaultOptions.duration = 0.5;
+ var e1 = new Effect.Opacity('sandbox');
+ assertEqual(0.5, e1.options.duration);
+
+ wait(750, function() {
+ assertEqual('finished', e1.state);
+ Effect.DefaultOptions = oldDefaultOptions;
+ });
+ }},
+
+ testEffectsQueue: function() { with(this) {
+ var e1 = new Effect.Highlight('sandbox');
+ var e2 = new Effect.Appear('sandbox');
+
+ assertEqual(2, Effect.Queue.effects.length);
+
+ tmp = 0;
+ Effect.Queue.each(function(e) { tmp++ });
+ assertEqual(2, tmp);
+
+ // the internal interval timer should be active
+ assertNotNull(Effect.Queue.interval);
+ e1.cancel();
+ e2.cancel();
+ assertEqual(0, Effect.Queue.effects.length);
+
+ // should be inactive after all effects are removed from queue
+ assertNull(Effect.Queue.interval);
+
+ // should be in e3,e1,e2 order
+ var e1 = new Effect.Highlight('sandbox');
+ var e2 = new Effect.Appear('sandbox',{queue:'end'});
+ var e3 = new Effect.Fade('sandbox',{queue:'front'});
+ assert(e2.startOn > e1.startOn);
+ assert(e3.startOn < e1.startOn);
+ assert(e3.startOn < e2.startOn);
+ assertEqual(3, Effect.Queue.effects.length);
+
+ Effect.Queue.each(function(e) { e.cancel() });
+ assertEqual(0, Effect.Queue.effects.length);
+ }},
+
+ testScopedEffectsQueue: function() { with(this) {
+ var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope'} } );
+ var e2 = new Effect.Appear('sandbox', {queue: {scope:'myscope'} } );
+ var e3 = new Effect.Highlight('sandbox', {queue: {scope:'secondscope'} } );
+ var e4 = new Effect.Appear('sandbox');
+
+ assertEqual(2, Effect.Queues.get('myscope').effects.length);
+ assertEqual(1, Effect.Queues.get('secondscope').effects.length);
+ assertEqual(1, Effect.Queues.get('global').effects.length);
+ assertEqual(Effect.Queue.effects.length, Effect.Queues.get('global').effects.length);
+
+ var tmp = 0;
+ Effect.Queues.get('myscope').effects.each(function(e) { tmp++ });
+ assertEqual(2, tmp);
+
+ // the internal interval timer should be active
+ assertNotNull(Effect.Queues.get('myscope').interval);
+ assertNotNull(Effect.Queues.get('secondscope').interval);
+ assertNotNull(Effect.Queues.get('global').interval);
+
+ e1.cancel(); e2.cancel(); e3.cancel(); e4.cancel();
+
+ assertEqual(0, Effect.Queues.get('myscope').effects.length);
+ assertEqual(0, Effect.Queues.get('secondscope').effects.length);
+ assertEqual(0, Effect.Queues.get('global').effects.length);
+
+ // should be inactive after all effects are removed from queues
+ assertNull(Effect.Queues.get('myscope').interval);
+ assertNull(Effect.Queues.get('secondscope').interval);
+ assertNull(Effect.Queues.get('global').interval);
+
+ // should be in e3 and e4 together and then e1,e2 order
+ var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope'} } );
+ var e2 = new Effect.Appear('sandbox', {queue: {position: 'end', scope:'myscope'} } );
+ var e3 = new Effect.Fade('sandbox', {queue: {position: 'front', scope:'myscope'} } );
+ var e4 = new Effect.Appear('sandbox');
+ assert(e2.startOn > e1.startOn);
+ assert(e3.startOn < e1.startOn);
+ assert(e3.startOn < e2.startOn);
+ assert(e3.startOn = e4.startOn);
+ assertEqual(3, Effect.Queues.get('myscope').effects.length);
+
+ Effect.Queues.get('myscope').each(function(e) { e.cancel() });
+ assertEqual(0, Effect.Queues.get('myscope').effects.length);
+
+ Effect.Queues.get('global').each(function(e) { e.cancel() });
+ assertEqual(0, Effect.Queues.get('global').effects.length);
+
+ // should only allow the first two effects and ignore the third
+ var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope', limit: 2} } );
+ var e2 = new Effect.Appear('sandbox', {queue: {position: 'end', scope:'myscope', limit: 2} } );
+ var e3 = new Effect.Fade('sandbox', {queue: {position: 'front', scope:'myscope', limit: 2} } );
+
+ assertEqual(2, Effect.Queues.get('myscope').effects.length);
+ }},
+
+ testEffectMultiple: function() { with(this) {
+ $('sandbox').appendChild(Builder.node('div',{id:'test_1'}));
+ $('sandbox').appendChild(Builder.node('div',{id:'test_2'},[Builder.node('div',{id:'test_2a'})]));
+ $('sandbox').appendChild(Builder.node('div',{id:'test_3'}));
+
+ // only direct child elements
+ Effect.multiple('sandbox',Effect.Fade);
+ assertEqual(3, Effect.Queue.effects.length);
+
+ Effect.Queue.each(function(e) { e.cancel() });
+ assertEqual(0, Effect.Queue.effects.length);
+
+ // call with array
+ Effect.multiple(['test_1','test_3'],Effect.Puff);
+ assertEqual(2, Effect.Queue.effects.length);
+ }},
+
+ testEffectTagifyText: function() { with(this) {
+ $('sandbox').innerHTML = "Blah<strong>bleb</strong> Blub";
+ assertEqual(3, $('sandbox').childNodes.length);
+ Effect.tagifyText('sandbox');
+ assertEqual(10, $('sandbox').childNodes.length);
+
+ Effect.multiple('sandbox', Effect.Fade);
+ assertEqual(10, Effect.Queue.effects.length);
+ }},
+
+ testEffectParallel: function() { with(this) {
+ assert( new Effect.Parallel() );
+ assert( new Effect.Parallel([]) );
+ assert( new Effect.Parallel([],{}) );
+ assert( new Effect.Parallel([
+ new Effect.Event({sync:true})
+ ],{ duration: 2}) );
+ }},
+
+ testEffectTween: function() { with(this) {
+ // basic initialization
+ assert(new Effect.Tween(null,0,0,function(){}));
+ assert(new Effect.Tween(null,0,0,{duration:0.1},function(){}));
+
+ // fun with objects
+ var object = {
+ blech: 2,
+ foo: function(p){
+ this.bar = p;
+ }
+ };
+ assert(new Effect.Tween(object,0,1,{transition:Effect.Transitions.reverse},'blech'));
+ assert(new Effect.Tween(object,0,1,'foo'));
+
+ // fun with elements
+ assert(new Effect.Tween('tween',50,1,'update'));
+
+ wait(1500, function(){
+ assertEqual(0, object.blech);
+ assertEqual(1, object.bar);
+ assertEqual('1', $('tween').innerHTML);
+ });
+ }},
+
+ // test if all combined effects correctly initialize themselves
+ testCombinedEffectsInitialize: function() { with(this) {
+ COMBINED_EFFECTS.each(function(fx,idx){
+ info('Effect.'+fx);
+ $('sandbox').innerHTML = "";
+ $('sandbox').appendChild(
+ Builder.node('div',{id:'test_element'},
+ Builder.node('span','test'))); //some effects require a child element
+
+ // should work with new Effect.Blah syntax
+ var effect = new Effect[fx]('test_element');
+ assertEqual(0, effect.currentFrame);
+
+ // and without the 'new'
+ var effect = Effect[fx]('test_element');
+ assertEqual(0, effect.currentFrame);
+
+ // visualEffect
+ assert($('test_element') == $('test_element').visualEffect(COMBINED_RJS_EFFECTS[idx]));
+
+ // direct element extension
+ var method = COMBINED_EFFECTS[idx].charAt(0).toLowerCase() + COMBINED_EFFECTS[idx].substring(1)
+ assert($('test_element') == $('test_element')[method]());
+
+ // options parsing (shake, squish and grow are special here)
+ if(!['Shake','Squish','Grow'].include(fx)) {
+ var effect = Effect[fx]('test_element',{duration:2.0});
+ assertEqual(2.0, effect.options.duration, fx);
+ }
+ });
+ }},
+
+ testSynchronizedEffects: function() { with(this) {
+ var e1 = new Effect.Fade('sandbox',{sync:true});
+ wait(250, function() {
+ // effect should still be at frame 0
+ assertEqual(0, e1.currentFrame);
+ assertEqual('idle', e1.state);
+ e1.render(0.01);
+
+ // no frame count for sync effects
+ assertEqual(0, e1.currentFrame);
+ assertEqual('running', e1.state);
+ });
+ }},
+
+ testEffectPosition: function() { with(this) {
+ var testeffect = new Effect.Opacity('sandbox',{
+ afterSetup: function(effect) { effect.frames = 0; },
+ afterUpdate: function(effect) { effect.frames++; $('sandbox').update(effect.position); },
+ duration: 0.5, from: 1.0, to: 0.5
+ });
+ assertNull(testeffect.position);
+ assertEqual('idle', testeffect.state);
+ wait(1000, function() {
+ info('Rendered ' + testeffect.frames + ' frames in .5 seconds ' +
+ '(~' + (testeffect.frames/0.5) + 'fps of a possible 60fps, ' +
+ 'note that this can exceed 60fps because of additional last frame rendering)');
+ assertEqual('0.5', $('sandbox').innerHTML);
+ assertEqual(0.5, testeffect.position);
+ assertEqual('finished', testeffect.state);
+ });
+ }},
+
+ testRenderPerformance: function() { with(this) {
+ info('The render() method is generated on a per-effect basis')
+ var e = new Effect.Opacity('sandbox',{sync:true});
+ benchmark(function(){
+ e.render(0.5);
+ },1000, 'Without events');
+ var e = new Effect.Opacity('sandbox',{sync:true,afterUpdate:function(){return}});
+ benchmark(function(){
+ e.render(0.5);
+ },1000, 'With afterUpdate event');
+ }},
+
+ testElementMorph: function() { with(this) {
+ $('error_test_ul').morph('font-size:40px', {duration: 0.5}).setStyle({marginRight:'17px'});
+ $('error_message_2').morph({
+ fontSize: '20px',
+ color: '#f00',
+ backgroundColor: '#ffffff'
+ },
+ {
+ duration:0.5
+ });
+ $('error_message_3').morph('final', {duration:0.5});
+ wait(1000,function(){
+ assertEqual('17px', $('error_test_ul').getStyle('margin-right'));
+ assertEqual('40px', $('error_test_ul').getStyle('font-size'));
+ assertEqual('#ffffff', $('error_message_2').getStyle('background-color').parseColor());
+ assertEqual('20px', $('error_message_2').getStyle('font-size'));
+ assertEqual('italic', $('error_message_3').getStyle('font-style'));
+ assertEqual('20px', $('error_message_3').getStyle('font-size'));
+ assertEqual(.5, $('error_message_3').getStyle('opacity'));
+ assertEqual('', $('error_message_3').style.fontSize);
+ });
+ }},
+
+ testElementMorphChaining: function() { with(this) {
+ $('error_message').morph('font-size:17px').morph('opacity:0',{delay:2});
+ wait(3100,function(){ // 2000ms delay + 1000ms default duration
+ assertEqual(0, $('error_message').getStyle('opacity'));
+ });
+ }},
+
+ testTransformBySelector: function() { with(this) {
+ new Effect.Transform([
+ { 'ul.error-list li': 'font-size:20px;text-indent:40pt' }
+ ],{ duration: 0.5 }).play();
+
+ wait(700,function(){
+ var idx = 0;
+ $A($('error_test_ul').cleanWhitespace().childNodes).each(function(node){
+ assertEqual('20px', $(node).getStyle('font-size'));
+ assertEqual('40pt', $(node).getStyle('text-indent'));
+ idx++;
+ });
+ assertEqual(5, idx);
+ });
+ }},
+
+ testTransformUsesCSSClassPresets: function() { with(this) {
+ assertEqual('40px', $('rotfl').getStyle('font-size'));
+
+ // Render the effect at half-way through, font-size should be
+ // exactly half-way between original and target
+ new Effect.Transform([
+ { 'rotfl': 'font-size:20px;text-indent:40pt;background-color:#888' }
+ ],{ sync:true }).play().render(0.5);
+
+ wait(1100,function(){
+ // should be 30px = 40px + (20px-40px)/2
+ assertEqual('30px', $('rotfl').getStyle('font-size'));
+ });
+ }},
+
+ testTransformMultiple: function() { with(this) {
+ var transformation = new Effect.Transform([
+ { 'div.morphing': 'font-size:20px;padding-left:40em;opacity:0.5' },
+ { 'blah' :
+ 'width:480px;border-width:10px;border-right-width:20px;' +
+ 'margin:20px;margin-bottom:-20px;font-size:30px;' +
+ 'background:#954' }
+ ],{ duration: 0.5 });
+
+ var generatedEffect = transformation.play();
+
+ assertEqual(3, generatedEffect.effects.length);
+
+ wait(700, function(){
+ // have a look at the generated color transforms for the 3rd found element
+ // which is the "blah" div
+ assertEqual('blah', generatedEffect.effects[2].element.id);
+ assertEnumEqual([255,255,255],
+ generatedEffect.effects[2].transforms.detect( function(transform){
+ return (transform.style == 'backgroundColor')
+ }).originalValue);
+ assertEnumEqual([153,85,68],
+ generatedEffect.effects[2].transforms.detect( function(transform){
+ return (transform.style == 'backgroundColor')
+ }).targetValue);
+
+ assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
+ assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
+ assertEqual('30px', $('blah').getStyle('font-size'));
+
+ // border-width/border-right-width should be set independently
+ assertEqual('10px', $('blah').getStyle('border-top-width'));
+ assertEqual('10px', $('blah').getStyle('border-bottom-width'));
+ assertEqual('10px', $('blah').getStyle('border-left-width'));
+ assertEqual('20px', $('blah').getStyle('border-right-width'));
+
+ // colors should assume transition from
+ // #ffffff (white) if original was transparent
+ // we now should have arrived at the given color
+ assertEqual('#995544', $('blah').getStyle('background-color').parseColor());
+
+ // play again = should have same values
+ transformation.play();
+ wait(700, function(){
+ assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
+ assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
+ assertEqual('30px', $('blah').getStyle('font-size'));
+
+ $('blah').setStyle({fontSize:'100px'});
+ assertEqual('100px', $('blah').getStyle('font-size'));
+ transformation.play();
+ wait(700, function(){
+ assertEqual('30px', $('blah').getStyle('font-size'));
+
+ new Effect.Transform([
+ { 'blah': 'color: #80d980; background: #208020' }
+ ],{ duration: 1.1 }).play();
+ wait(1500, function(){
+ assertEqual('#80d980', $('blah').getStyle('color').parseColor());
+ assertEqual('#208020', $('blah').getStyle('background-color').parseColor());
+ });
+ });
+ });
+ });
+ }}
+
+ });
+
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/element_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/element_test.html
new file mode 100644
index 000000000..8ac5416af
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/element_test.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ #style_test_1 { color:rgb(0, 0, 255); background-color: rgb(0, 0, 255); }
+ blah { color:rgb(0, 255, 0); }
+ #op2 { opacity:0.5;filter:alpha(opacity=50)progid:DXImageTransform.Microsoft.Blur(strength=10);}
+ #allStyles_1 {font-size: 12px;}
+ #allStyles_2 {opacity:0.5; filter:alpha(opacity=50);}
+ #allStyles_3 {opacity:0.5;}
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for Element extensions in effects.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Test elements follow -->
+<div id="test_1" class="a bbbbbbbbbbbb cccccccccc dddd"> </div>
+
+<div id="test_2" class="classA-foobar classB-foobar"> </div> <span> </span>
+
+<div id="style_test_1" style="display:none;"></div>
+<div id="style_test_2" class="blah" style="font-size:11px;"></div>
+
+<div id="style_test_3">blah</div>
+
+<div id="test_whitespace"> <span> </span>
+
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+<!-- Test Element opacity functions -->
+<img id="op1" alt="op2" src="icon.png" style="opacity:0.5;filter:alpha(opacity=50)" />
+<img id="op2" alt="op2" src="icon.png"/>
+<img id="op3" alt="op3" src="icon.png"/>
+<img id="op4-ie" alt="op3" src="icon.png" style="filter:alpha(opacity=30)" />
+
+<!-- Test Element.childrenWithClassName -->
+<div id="Container" class="moo hoo">
+ <span id="1" class="firstClass">First class</span>
+ <span id="2" class="secondClass">Second class</span>
+ <span id="3" class="firstClass secondClass">First and Second class</span>
+ <span id="4" class="thirdClass">Third class <span id="5" class="firstClass">Nested First class</span></span>
+
+ <div id="collect">1<span class="ignore"><span class="someclass">2</span>3</span><ul><li class="ignore">4</li></ul></div>
+
+</div>
+
+<div id="perftest1"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
+<div id="allStyles_1"></div>
+<div id="allStyles_2"></div>
+<div id="allStyles_3"></div>
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ new Test.Unit.Runner({
+
+ testElementCollectTextNodes: function() { with(this) {
+ assertEqual('1234', Element.collectTextNodes('collect'));
+ assert(benchmark(function(){
+ Element.collectTextNodes('collect')
+ },50) < 1000);
+
+ benchmark(function(){
+ Element.collectTextNodes('collect')
+ },10,'Element.collectTextNodes');
+
+ assertEqual('1234', Element.collectTextNodesIgnoreClass('collect', 'somethingcompletelydifferent'));
+ assertEqual('1', $('collect').collectTextNodesIgnoreClass('ignore'));
+ benchmark(function(){
+ Element.collectTextNodesIgnoreClass('collect','ignore')
+ },10,'Element.collectTextNodesIgnoreClass');
+
+ assertEqual('134', Element.collectTextNodesIgnoreClass('collect', 'someclass'));
+ }},
+
+ testVisualEffect: function() { with(this) {
+ assert($('style_test_3') == $('style_test_3').visualEffect('fade'));
+ wait(1500,function(){
+ assert(!$('style_test_3').visible())
+ });
+ }},
+
+ testParseStylePerformance: function() { with(this) {
+ benchmark(function(){
+ "font:12px/15pt Verdana;opacity:0.4;border:4px dotted red".parseStyle();
+ },100);
+ }},
+
+ testGetStyles: function() { with(this) {
+ assertEqual('12px', $('allStyles_1').getStyles().fontSize);
+ assertEqual(1, parseFloat($('allStyles_1').getStyles().opacity));
+ assertEqual(0.5, parseFloat($('allStyles_2').getStyles().opacity));
+ assertEqual(0.5, parseFloat($('allStyles_3').getStyles().opacity));
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/icon.png b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/icon.png
new file mode 100644
index 000000000..f752986b7
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/icon.png
Binary files differ
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/index.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/index.html
new file mode 100644
index 000000000..70a3dbb0e
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/index.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body class="navigation">
+
+<h1>script.aculo.us<br/>Unit Tests</h1>
+
+<p id="version"></p>
+
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ $('version').innerHTML = 'script.aculo.us version '+Scriptaculous.Version+'<br/>Prototype version ' + Prototype.Version;
+// ]]>
+</script>
+
+<p><a href="http://wiki.script.aculo.us/scriptaculous/show/UnitTesting" target="test">Documentation</a></p>
+
+<h2>scriptaculous.js</h2>
+<ul>
+ <li><a href="loading_test.html" target="test">Dynamic loading test</a></li>
+</ul>
+
+<h2>effects.js</h2>
+<ul>
+ <li><a href="effects_test.html" target="test">Effects test</a></li>
+ <li><a href="string_test.html" target="test">String test</a></li>
+ <li><a href="element_test.html" target="test">Element extensions test</a></li>
+ <li><a href="position_clone_test.html" target="test">Position.clone test</a></li>
+</ul>
+
+<h2>dragdrop.js</h2>
+<ul>
+ <li><a href="dragdrop_test.html" target="test">Drag &amp; Drop test</a></li>
+ <li><a href="sortable_test.html" target="test">Sortable test</a></li>
+</ul>
+
+<h2>builder.js</h2>
+<ul>
+ <li><a href="builder_test.html" target="test">Builder test</a></li>
+</ul>
+
+<h2>controls.js</h2>
+<ul>
+ <li><a href="ajax_autocompleter_test.html" target="test">Ajax.Autocompleter test</a></li>
+ <li><a href="ajax_inplaceeditor_test.html" target="test">Ajax.InPlaceEditor test</a></li>
+ <li>Note: unit tests work on Firefox only. The controls themselves are fully supported on IE6+, Firefox and Safari.</li>
+</ul>
+
+<h2>slider.js</h2>
+<ul>
+ <li><a href="slider_test.html" target="test">Control.Slider test</a></li>
+</ul>
+
+
+<h2>unittest.js</h2>
+<ul>
+ <li><a href="unittest_test.html" target="test">Unittest test</a></li>
+ <li><a href="bdd_test.html" target="test">BDD test</a></li>
+</ul>
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/loading_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/loading_test.html
new file mode 100644
index 000000000..d36f96ccc
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/loading_test.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js?load=effects,dragdrop" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Test dynamic loading in scriptaculous.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ new Test.Unit.Runner({
+
+ testDynamicLoading: function() { with(this) {
+
+ // not loaded: controls
+ assertNull(Ajax.Autocompleter || null);
+ assertNull(Form.Element.DelayedObserver || null);
+
+ // we loading dragdrop
+ assertNotNull(Draggable || null);
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/position_clone_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/position_clone_test.html
new file mode 100644
index 000000000..0644c631b
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/position_clone_test.html
@@ -0,0 +1,312 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for Postion.clone (to be moved to Prototype)
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ function prepareTarget(contained, position1, position2) {
+ var target;
+ if($('target_div')) Element.remove('target_div');
+ if($('container_div')) Element.remove('container_div');
+ if(contained) {
+ target = Builder.node('div',
+ {id: 'container_div', style: 'position:' + position1},
+ [Builder.node('div', {id: 'target_div', style: 'position: ' +position2})]);
+ } else {
+ target = Builder.node('div',
+ {id: 'target_div', style: 'position:' + position1}, '456');
+ }
+ document.body.appendChild(target);
+ Position.clone($('source_div'),$('target_div'));
+ }
+
+ function prepareTargetHidden(contained, position1, position2) {
+ var target;
+ if($('target_div')) Element.remove('target_div');
+ if($('container_div')) Element.remove('container_div');
+ if(contained) {
+ target = Builder.node('div',
+ {id: 'container_div', style: 'position:' + position1},
+ [Builder.node('div', {id: 'target_div', style: 'display:none; position: ' +position2})]);
+ } else {
+ target = Builder.node('div',
+ {id: 'target_div', style: 'display:none; position:' + position1}, '456');
+ }
+ document.body.appendChild(target);
+ Position.clone($('source_div'),$('target_div'));
+ Element.show($('target_div'));
+ }
+
+ new Test.Unit.Runner({
+
+ teardown: function() {
+ Element.remove($('source_div'));
+ },
+
+ testPositionCloneFromAbsolute: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'position:absolute; top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect([120, 20]);
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTarget(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTarget(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTarget(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTarget(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTarget(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTarget(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTarget(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTarget(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }},
+
+ testPositionCloneFromRelative: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'position:relative; top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect(Position.page($('source_div')));
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTarget(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTarget(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTarget(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTarget(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTarget(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTarget(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTarget(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTarget(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }},
+
+ testPositionCloneFromStatic: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect(Position.page($('source_div')));
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTarget(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTarget(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTarget(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTarget(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTarget(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTarget(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTarget(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTarget(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }},
+
+ testPositionCloneFromAbsoluteWithHiddenTarget: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'position:absolute; top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect([120, 20]);
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTargetHidden(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTargetHidden(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTargetHidden(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTargetHidden(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTargetHidden(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTargetHidden(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }},
+
+ testPositionCloneFromRelativeWithHiddenTarget: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'position:relative; top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect(Position.page($('source_div')));
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTargetHidden(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTargetHidden(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTargetHidden(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTargetHidden(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTargetHidden(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTargetHidden(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }},
+
+ testPositionCloneFromStaticWithHiddenTarget: function() { with(this) {
+ var source = Builder.node('div',
+ {id: 'source_div', style: 'top:20px; left:120px; width:100px; height:50px;'}, '123');
+ document.body.appendChild(source);
+ var expected = Object.inspect(Position.page($('source_div')));
+ assertEqual(expected, Object.inspect(Position.page($('source_div'))));
+
+ prepareTargetHidden(false, 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute BODY child");
+
+ prepareTargetHidden(false, 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of absolute BODY child");
+
+ prepareTargetHidden(true, 'absolute', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of absolute BODY child");
+
+ prepareTargetHidden(true, 'relative', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of relative BODY child");
+
+ prepareTargetHidden(true, 'relative', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of relative BODY child");
+
+ prepareTargetHidden(true, 'static', 'absolute');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to absolute child of static BODY child");
+
+ prepareTargetHidden(true, 'static', 'fixed');
+ assertEqual(expected, Object.inspect(Position.page($('target_div'))),
+ "Clone to fixed child of static BODY child");
+ }}
+
+ });
+
+// ]]>
+</script>
+
+<!-- Test elements will be inserted after this -->
+
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/slider_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/slider_test.html
new file mode 100644
index 000000000..4d3d0d0de
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/slider_test.html
@@ -0,0 +1,437 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for slider.js
+</p>
+
+<div id="track1" style="width:200px;background-color:#aaa;height:5px;">
+ <div id="handle1" style="width:15px;height:25px;background-color:#f00;"> </div>
+</div>
+
+<div id="track2-vertical" style="height:100px;background-color:#aaa;width:5px;">
+ <div id="handle2-vertical" style="width:25px;height:10px;background-color:#f00;"> </div>
+</div>
+
+<div id="track2-horizontal" style="height:5px;background-color:#aaa;width:100px;">
+ <div id="handle2-horizontal" style="width:10px;height:25px;background-color:#f00;"> </div>
+</div>
+
+<div id="track3" style="width:300px;background-color:#cfb;height:30px;">
+ <span id="handle3-1">1</span>
+ <span id="handle3-2">2</span>
+ <span id="handle3-3">3</span>
+</div>
+
+<div id="track4" style="width:300px;position:relative;background-color:#cbf;height:30px;">
+ <span id="handle4-1" style="top:0;left:0;position:absolute;background-color:#f00;">1</span>
+ <span id="handle4-2" style="top:0;left:0;position:absolute;background-color:#0f0;">2</span>
+ <span id="handle4-3" style="top:0;left:0;position:absolute;background-color:#00f;">3</span>
+</div>
+
+<div id="track5" style="width:300px;background-color:#cbf;height:30px;position:relative;z-index:0;">
+ <div id="handle5-1" style="top:0;left:0;position:absolute;background-color:#f00;z-index:2">1</div>
+ <div id="handle5-2" style="top:0;left:0;position:absolute;background-color:#0f0;z-index:2">2</div>
+ <div id="handle5-3" style="top:0;left:0;position:absolute;background-color:#00f;z-index:2">3</div>
+
+ <div id="span5-1" style="top:0;left:0;position:absolute;background-color:#000;height:20px;z-index:1;"> </div>
+ <div id="span5-2" style="top:0;left:0;position:absolute;background-color:#444;height:20px;z-index:1;"> </div>
+</div>
+
+<div id="track6" style="width:20px;background-color:#cbf;height:100px;position:relative;z-index:0;">
+ <div id="handle6-1" style="top:0;left:0;height:13px;position:absolute;background-color:#f00;z-index:2">1</div>
+ <div id="handle6-2" style="top:0;left:0;height:13px;position:absolute;background-color:#0f0;z-index:2">2</div>
+ <div id="handle6-3" style="top:0;left:0;height:13px;position:absolute;background-color:#00f;z-index:2">3</div>
+
+ <div id="span6-1" style="top:0;left:0;position:absolute;background-color:#000;width:20px;z-index:1;"> </div>
+ <div id="span6-2" style="top:0;left:0;position:absolute;background-color:#444;width:20px;z-index:1;"> </div>
+</div>
+
+<div id="track7" style="width:200px;background-color:#cbf;height:30px;position:relative;z-index:0;">
+ <div id="handle7-1" style="top:0;left:0;position:absolute;background-color:#f88;z-index:2">1</div>
+ <div id="handle7-2" style="top:0;left:0;position:absolute;background-color:#8f8;z-index:2">2</div>
+ <div id="handle7-3" style="top:0;left:0;position:absolute;background-color:#88f;z-index:2">3</div>
+
+ <div id="span7-1" style="top:0;left:0;position:absolute;background-color:#000;height:20px;z-index:1;"> </div>
+ <div id="span7-2" style="top:0;left:0;position:absolute;background-color:#444;height:20px;z-index:1;"> </div>
+
+ <div id="span7-start" style="top:0;left:0;position:absolute;background-color:#f00;height:20px;z-index:1;"> </div>
+ <div id="span7-end" style="top:0;left:0;position:absolute;background-color:#00f;height:20px;z-index:1;"> </div>
+</div>
+
+
+<div id="debug"> </div>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+ var globalValue;
+
+ new Test.Unit.Runner({
+
+ testSliderBasics: function() { with(this) {
+ var slider = new Control.Slider('handle1', 'track1');
+ assertInstanceOf(Control.Slider, slider);
+
+ assertEqual('horizontal', slider.axis);
+ assertEqual(false, slider.disabled);
+ assertEqual(0, slider.value);
+
+ slider.dispose();
+ }},
+
+ testSliderValues: function() { with(this) {
+ ['horizontal', 'vertical'].each( function(axis) {
+ var slider = new Control.Slider('handle2-'+axis, 'track2-'+axis, {values:[0.2,0.4,0.6,0.8,1],axis:axis});
+ assertEqual(axis, slider.axis);
+ assertEqual(0.2, slider.value);
+
+ slider.setValue(0.35);
+ assertEqual(0.4, slider.value);
+
+ slider.setValueBy(0.1);
+ assertEqual(0.6, slider.value);
+ slider.setValueBy(-0.6);
+ assertEqual(0.2, slider.value);
+
+ slider.setValue(1);
+ assertEqual(1, slider.value);
+
+ slider.setValue(-2);
+ assertEqual(0.2, slider.value);
+
+ slider.setValue(55555);
+ assertEqual(1, slider.value);
+
+ // leave active to be able to play around with the sliders
+ // slider.dispose();
+ });
+ assertEqual("90px", $('handle2-horizontal').style.left);
+ assertEqual("90px", $('handle2-vertical').style.top);
+ }},
+
+ testSliderInitialValues: function() { with(this) {
+ var slider = new Control.Slider('handle1', 'track1',{sliderValue:0.5});
+ assertEqual(0.5, slider.value);
+
+ var slider = new Control.Slider(['handle4-1','handle4-2','handle4-3'], 'track4', {
+ sliderValue:[50,145,170],
+ values:[50,150,160,170,180],
+ range:$R(50,180)
+ });
+ assertEqual(50, slider.value);
+ assertEqual(50, slider.values[0]);
+ assertEqual(150, slider.values[1]);
+ assertEqual(170, slider.values[2]);
+ slider.dispose();
+
+ var slider = new Control.Slider(['handle4-1','handle4-2','handle4-3'], 'track4', {
+ sliderValue:[50,145,170],
+ values:[50,150,160,170,180]
+ });
+ assertEqual(50, slider.value);
+ assertEqual(50, slider.values[0]);
+ assertEqual(150, slider.values[1]);
+ assertEqual(170, slider.values[2]);
+ slider.dispose();
+
+ var slider = new Control.Slider(['handle4-1','handle4-2','handle4-3'], 'track4', {
+ restricted:true,
+ sliderValue:[50,145,170],
+ values:[50,150,160,170,180]
+ });
+ assertEqual(50, slider.value);
+ assertEqual(50, slider.values[0]);
+ assertEqual(150, slider.values[1]);
+ assertEqual(170, slider.values[2]);
+ slider.dispose();
+ }},
+
+ testSliderOnChange: function() { with(this) {
+ var slider = new Control.Slider('handle1', 'track1', { onChange:function(v){ globalValue = v; } });
+ slider.setValue(1);
+ assert(1, globalValue);
+ assert(1, slider.value);
+
+ slider.setDisabled();
+ slider.setValue(0.5);
+ assert(1, globalValue);
+ assert(1, slider.value);
+
+ slider.setEnabled();
+ slider.setValue(0.2);
+ assert(0.2, globalValue);
+ assert(0.2, slider.value);
+
+ // s.event should be null if setValue is called from script
+ var slider = new Control.Slider(['handle3-1','handle3-2','handle3-3'], 'track3', {
+ onChange:function(v, s){ if(!s.event) globalValue = v; } });
+
+ slider.setValue(0.5,1);
+ assertEqual([0,0.5,0].inspect(), globalValue.inspect());
+ assert(!slider.event);
+
+ slider.dispose();
+ }},
+
+ testMultipleHandles: function() { with(this) {
+ var slider = new Control.Slider(['handle3-1','handle3-2','handle3-3'], 'track3', {range:$R(0,300)});
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(50, 1);
+ slider.setValue(70, 2);
+ assertEqual(20, slider.values[0]);
+ assertEqual(50, slider.values[1]);
+ assertEqual(70, slider.values[2]);
+ assertEqual("20px", slider.handles[0].style.left);
+ assertEqual("49px", slider.handles[1].style.left);
+ assertEqual("68px", slider.handles[2].style.left);
+
+ // should change last manipulated handled by -10,
+ // so check for handle with idx 2
+ slider.setValueBy(-10);
+ assertEqual(60, slider.values[2]);
+
+ slider.setValueBy(10, 0);
+ assertEqual(20, slider.values[0]);
+ slider.setValueBy(10, 1);
+ assertEqual(60, slider.values[1]);
+ slider.setValueBy(20, slider.activeHandleIdx);
+ assertEqual(80, slider.values[1]);
+ }},
+
+ testMultipleHandlesValues: function() { with(this) {
+ var slider = new Control.Slider(['handle4-1','handle4-2','handle4-3'], 'track4', {values:[50,150,160,170,180],range:$R(50,180)});
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(150, 2);
+ slider.setValue(179, 1);
+
+ assertEqual(50, slider.values[0]);
+ assertEqual(150, slider.values[2]);
+ assertEqual(180, slider.values[1]);
+
+ assertEqual("0px", slider.handles[0].style.left);
+ assertEqual("225px", slider.handles[2].style.left);
+ assertEqual("293px", slider.handles[1].style.left);
+
+ assertEqual($R(50,150).inspect(), slider.getRange().inspect());
+ assertEqual(30, slider.getRange(1).end-slider.getRange(1).start);
+ }},
+
+ testMultipleHandlesSpans: function() { with(this) {
+ var slider = new Control.Slider(['handle5-1','handle5-2','handle5-3'], 'track5',
+ {spans:['span5-1','span5-2'],range:$R(0,300)});
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(100, 1);
+ slider.setValue(150, 2);
+
+ assertEqual("20px", $('span5-1').style.left);
+ assertEqual("78px", $('span5-1').style.width);
+ assertEqual("98px", $('span5-2').style.left);
+ assertEqual("49px", $('span5-2').style.width);
+
+ slider.setValue(30, 0);
+ slider.setValue(110, 1);
+ slider.setValue(90, 2);
+
+ assertEqual("29px", $('span5-1').style.left);
+ assertEqual("59px", $('span5-1').style.width);
+ assertEqual("88px", $('span5-2').style.left);
+ assertEqual("20px", $('span5-2').style.width);
+
+ slider.dispose();
+ }},
+
+ testMultipleHandlesSpansStartEnd: function() { with(this) {
+ var slider = new Control.Slider(['handle7-1','handle7-2','handle7-3'], 'track7',
+ { spans:['span7-1','span7-2'],
+ startSpan:'span7-start',
+ endSpan:'span7-end',
+ range:$R(0,200) });
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(100, 1);
+ slider.setValue(150, 2);
+ assertEqual("0px", $('span7-start').style.left);
+ assertEqual("19px", $('span7-start').style.width);
+ assertEqual("145px", $('span7-end').style.left);
+ assertEqual("48px", $('span7-end').style.width);
+
+ slider.dispose();
+ }},
+
+ testSingleHandleSpansStartEnd: function() { with(this) {
+ var slider = new Control.Slider('handle7-1', 'track7',
+ { spans:['span7-1','span7-2'],
+ startSpan:'span7-start',
+ endSpan:'span7-end',
+ range:$R(0,200) });
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ assertEqual("0px", $('span7-start').style.left);
+ assertEqual("19px", $('span7-start').style.width);
+ assertEqual("19px", $('span7-end').style.left);
+ assertEqual("174px", $('span7-end').style.width);
+
+ slider.dispose();
+ }},
+
+ testMultipleHandlesStyles: function() { with(this) {
+ var slider = new Control.Slider(['handle7-1','handle7-2','handle7-3'], 'track7',
+ { spans:['span7-1','span7-2'],
+ startSpan:'span7-start',
+ endSpan:'span7-end',
+ range:$R(0,200) });
+ assertInstanceOf(Control.Slider, slider);
+ assert(Element.hasClassName('handle7-1','selected'));
+ assert(!Element.hasClassName('handle7-2','selected'));
+ assert(!Element.hasClassName('handle7-3','selected'));
+
+ slider.setValue(20, 0);
+ assert(Element.hasClassName('handle7-1','selected'));
+ assert(!Element.hasClassName('handle7-2','selected'));
+ assert(!Element.hasClassName('handle7-3','selected'));
+
+ slider.setValue(100, 1);
+ assert(!Element.hasClassName('handle7-1','selected'));
+ assert(Element.hasClassName('handle7-2','selected'));
+ assert(!Element.hasClassName('handle7-3','selected'));
+
+ slider.setValue(150, 2);
+ assert(!Element.hasClassName('handle7-1','selected'));
+ assert(!Element.hasClassName('handle7-2','selected'));
+ assert(Element.hasClassName('handle7-3','selected'));
+
+ slider.dispose();
+ }},
+
+ testMultipleHandlesSpansRestricted: function() { with(this) {
+ var slider = new Control.Slider(['handle5-1','handle5-2','handle5-3'], 'track5',
+ {restricted:true,spans:['span5-1','span5-2'],range:$R(0,300)});
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(100, 1);
+ slider.setValue(150, 2);
+ assertEqual(0, slider.values[0]);
+ assertEqual(0, slider.values[1]);
+ assertEqual(150, slider.values[2]);
+
+ slider.setValue(150, 2);
+ slider.setValue(100, 1);
+ slider.setValue(20, 0);
+ assertEqual(20, slider.values[0]);
+ assertEqual(100, slider.values[1]);
+ assertEqual(150, slider.values[2]);
+ assertEqual("20px", $('span5-1').style.left);
+ assertEqual("78px", $('span5-1').style.width);
+ assertEqual("98px", $('span5-2').style.left);
+ assertEqual("49px", $('span5-2').style.width);
+
+ slider.setValue(30, 0);
+ slider.setValue(110, 1);
+ slider.setValue(90, 2);
+ assertEqual(30, slider.values[0]);
+ assertEqual(110, slider.values[1]);
+ assertEqual(110, slider.values[2], '???');
+
+ assertEqual("29px", $('span5-1').style.left);
+ assertEqual("78px", $('span5-1').style.width);
+ assertEqual("107px", $('span5-2').style.left);
+ assertEqual("0px", $('span5-2').style.width);
+
+ slider.dispose();
+ }},
+
+ testMultipleHandlesSpansVertical: function() { with(this) {
+ var slider = new Control.Slider(['handle6-1','handle6-2','handle6-3'], 'track6', {axis:'vertical',spans:['span6-1','span6-2'],range:$R(0,100)});
+ assertInstanceOf(Control.Slider, slider);
+
+ slider.setValue(20, 0);
+ slider.setValue(80, 1);
+ slider.setValue(90, 2);
+
+ assertEqual("17px", $('span6-1').style.top);
+ assertEqual("52px", $('span6-1').style.height);
+ assertEqual("70px", $('span6-2').style.top);
+ assertEqual("9px", $('span6-2').style.height);
+
+ slider.setValue(30, 0);
+ slider.setValue(20, 1);
+ slider.setValue(95, 2);
+
+ assertEqual("17px", $('span6-1').style.top);
+ assertEqual("9px", $('span6-1').style.height);
+ assertEqual("26px", $('span6-2').style.top);
+ assertEqual("57px", $('span6-2').style.height);
+ }},
+
+ testRange: function() { with(this) {
+ var slider = new Control.Slider('handle1','track1');
+ assertEqual(0, slider.value);
+ slider.setValue(1);
+ assertEqual("185px", $('handle1').style.left);
+ slider.dispose();
+
+ var slider = new Control.Slider('handle1','track1',{range:$R(10,20)});
+ assertEqual(10, slider.value);
+ assertEqual("0px", $('handle1').style.left);
+ slider.setValue(15);
+ assertEqual("93px", $('handle1').style.left);
+ slider.setValue(20);
+ assertEqual("185px", $('handle1').style.left);
+ slider.dispose();
+ }},
+
+ // test for #3732
+ testRangeValues: function() { with(this) {
+ // test for non-zero starting range
+ var slider = new Control.Slider('handle1','track1',{
+ range:$R(1,3), values:[1,2,3]
+ });
+ assertEqual(1, slider.value);
+ assertEqual("0px", $('handle1').style.left);
+ slider.setValue(2);
+ assertEqual("93px", $('handle1').style.left);
+ slider.setValue(3);
+ assertEqual("185px", $('handle1').style.left);
+ slider.dispose();
+
+ // test zero-starting range
+ var slider = new Control.Slider('handle1','track1',{
+ range:$R(0,2), values:[0,1,2]
+ });
+ assertEqual(0, slider.value);
+ assertEqual("0px", $('handle1').style.left);
+ slider.setValue(1);
+ assertEqual("93px", $('handle1').style.left);
+ slider.setValue(2);
+ assertEqual("185px", $('handle1').style.left);
+ slider.dispose();
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/sortable_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/sortable_test.html
new file mode 100644
index 000000000..c2bafd0b9
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/sortable_test.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Test of sortable functions in dragdrop.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+
+<ul id="sortable1">
+ <li id="item_1" class="a">item 1</li>
+ <li id="item_2" class="c b">item 1<ul><li id="item_99">!!!</li></ul></li>
+ <li id="item_3" class="b">item 1</li>
+ <li id="item_xy" class="x y">item 1</li>
+ <!-- a comment -->
+</ul>
+
+<div id="sortable2">
+ <div id="item_4">item 4</div> <div id="item_5">item 5</div>
+ <img src="icon.png" alt="img"/>
+ <!-- a comment -->
+</div>
+
+<div id="sortable3">
+
+</div>
+
+<!--
+ By default, _ is the only valid seperator
+ for the DOM ids. Complex element ids as in
+ the form of "some_element_id_1" should also
+ be parsed correctly (only the last part should
+ be serialized)
+-->
+<ul id="sortable_complex">
+ <li id="a_b_item_1" class="a">item 1</li>
+ <li id="ab_item_2" class="c b">item 1
+ <ul>
+ <li id="item_99">!!!</li>
+ </ul>
+ </li>
+ <li id="a-b-item_3z_33" class="b">item 1</li>
+ <li id="a-item-xy" class="x y">item 1</li>
+ <!-- a comment -->
+</ul>
+
+
+<ul id="sortable_specialcreate">
+ <li id="y1item">item 1</li>
+ <li id="y2item">item 1<ul><li id="yyyy9928282hjhd">!!!</li></ul></li>
+</ul>
+
+<ul id="sortable_specialformat">
+ <li id="x1item">item 1</li>
+ <li id="x2item">item 1<ul><li id="xxxxx88888item">!!!</li></ul></li>
+</ul>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ new Test.Unit.Runner({
+
+ setup: function() { with(this) {
+ Sortable.create('sortable1',{only:['a','b']});
+ Sortable.create('sortable2',{tag:'div'});
+ Sortable.create('sortable3');
+ Sortable.create('sortable_specialcreate',{ format:/(\d+)/ });
+ Sortable.create('sortable_specialformat');
+ Sortable.create('sortable_complex');
+ }},
+
+ teardown: function() { with(this) {
+ Sortable.destroy('sortable1');
+ Sortable.destroy('sortable2');
+ Sortable.destroy('sortable3');
+ Sortable.destroy('sortable_specialformat');
+ Sortable.destroy('sortable_specialcreate');
+ Sortable.destroy('sortable_complex');
+ }},
+
+ testSortableSerializeSequenceBasics: function() { with(this) {
+ assertEqual('sortable1[]=1&sortable1[]=2&sortable1[]=3', Sortable.serialize('sortable1'));
+
+ // test empty sortable
+ assertEqual('', Sortable.serialize('sortable3'));
+ assertEnumEqual([], Sortable.sequence('sortable3'));
+
+ Element.remove('item_4');
+ assertEqual('sortable2[]=5', Sortable.serialize('sortable2'));
+ assertEnumEqual(['5'], Sortable.sequence('sortable2'));
+ }},
+
+ testSortableSerializeFormat: function() { with(this) {
+ // should correctly serialize from option given to Sortable.create()
+ assertEqual('sortable_specialcreate[]=1&sortable_specialcreate[]=2',
+ Sortable.serialize('sortable_specialcreate'));
+
+ benchmark(function(){
+ Sortable.serialize('sortable_specialcreate')
+ },1,'Sortable.serialize');
+
+ // test special format given explicitly
+ assertEqual('sortable_specialformat[]=1&sortable_specialformat[]=2',
+ Sortable.serialize('sortable_specialformat', {format:/(\d+)/}));
+
+ // return full id
+ assertEqual('sortable_specialformat[]=x1item&sortable_specialformat[]=x2item',
+ Sortable.serialize('sortable_specialformat', {format:/(.*)/}));
+
+ // test default format given explicitly
+ assertEqual('sortable1[]=1&sortable1[]=2&sortable1[]=3',
+ Sortable.serialize('sortable1',{format:/^[^_]*_(.*)$/}));
+
+ // Ensure default options.format handles longer, more complex list
+ // item IDs
+ assertEqual('sortable_complex[]=1&sortable_complex[]=2&sortable_complex[]=33&sortable_complex[]=',
+ Sortable.serialize('sortable_complex'));
+ }},
+
+ testSortableSerializeRule: function() { with(this) {
+ var ids = ['x','x-y','test_test','x_y_z','x_y-x_z'];
+ ids.each(function(id){
+ assertEqual('1',
+ (id+'_1').match(Sortable.SERIALIZE_RULE)[1]);
+ });
+
+ assertNull('x'.match(Sortable.SERIALIZE_RULE));
+ }},
+
+ testSortableSerializeName: function() { with(this) {
+ assertEqual('dumdidu[]=1&dumdidu[]=2',
+ Sortable.serialize('sortable_specialcreate',{name:'dumdidu'}));
+ }},
+
+ testSortableSequenceFormat: function() { with(this) {
+ // shauld correctly serialize from option given to Sortable.create()
+ assertEnumEqual(['1','2'],
+ Sortable.sequence('sortable_specialcreate'));
+
+ // test special format given explicitly
+ assertEnumEqual(['1','2'],
+ Sortable.sequence('sortable_specialformat', {format:/(\d+)/}));
+
+ // return full id
+ assertEnumEqual(['x1item','x2item'],
+ Sortable.sequence('sortable_specialformat', {format:/(.*)/}));
+
+ // test default format given explicitly
+ assertEnumEqual(['1','2','3'],
+ Sortable.sequence('sortable1',{format:/^[^_]*_(.*)$/}));
+ }},
+
+ testSortableFindElements: function() { with(this) {
+ assertEqual(3, Sortable.findElements($('sortable1'),{tag:'li',only:['a','b']}).length);
+ benchmark(function(){
+ Sortable.findElements($('sortable1'),{tag:'li',only:['a','b']})
+ },1,'Sortable.findElements/1');
+
+ assertEqual(1, Sortable.findElements($('sortable1'),{tag:'li',only:['x']}).length);
+ assertEqual(1, Sortable.findElements($('sortable1'),{tag:'li',only:'a'}).length);
+ assertEqual(2, Sortable.findElements($('sortable1'),{tag:'li',only:'b'}).length);
+ assertEqual(4, Sortable.findElements($('sortable1'),{tag:'li',only:['a','b','x']}).length);
+ }},
+
+ testSortableSetSequence: function() { with(this) {
+ // make sure assigning current sequence is a no-op
+ var o = Sortable.sequence('sortable1');
+ Sortable.setSequence('sortable1', ['1','2','3']);
+ assertEnumEqual(o, Sortable.sequence('sortable1'));
+
+ // check new sequence
+ Sortable.setSequence('sortable1', ['3','2','1']);
+ assertEnumEqual(['3','2','1'], Sortable.sequence('sortable1'));
+
+ // non-default format
+ Sortable.setSequence('sortable_specialformat', ['2','1'], { format:/(\d+)/ });
+ assertEnumEqual(['2','1'], Sortable.sequence('sortable_specialformat'));
+
+ // invalid sequence ids should be ignored
+ Sortable.setSequence('sortable1', ['x', '1', 'y', '2', '3', 'z']);
+ assertEnumEqual(['1', '2', '3'], Sortable.sequence('sortable1'));
+
+ // elements omitted in new sequence should be cropped
+ Sortable.setSequence('sortable1', ['1', '3']);
+ assertEnumEqual(['1', '3'], Sortable.sequence('sortable1'));
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html>
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/string_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/string_test.html
new file mode 100644
index 000000000..7d0fc2d57
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/string_test.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ Tests for String.prototype extensions in effects.js
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ new Test.Unit.Runner({
+
+ testStringParseColor: function() { with(this) {
+ assertEqual('#000000', "#000000".parseColor());
+ assertEqual('#000000', "rgb(0,0,0)".parseColor());
+ assertEqual('#000000', "rgb(0, 0, 0)".parseColor());
+ assertEqual('#000000', "#000".parseColor());
+
+ assertEqual('#1', "#1".parseColor());
+ assertEqual('#12', "#12".parseColor());
+ assertEqual('#112233', "#123".parseColor());
+ assertEqual('#1234', "#1234".parseColor());
+ assertEqual('#12345', "#12345".parseColor());
+ assertEqual('#123456', "#123456".parseColor());
+
+ assertEqual('#abcdef', "#aBcDeF".parseColor());
+ assertEqual('#aabbcc', "#aBc".parseColor());
+
+ assertEqual('white', "white".parseColor());
+ assertEqual('#123456', "#123456".parseColor('#000000')); // default to #000000 if not parseable
+ assertEqual('#000000', "white".parseColor('#000000')); // default to #000000 if not parseable
+
+ assertEqual('#ffffff', "rgb(255,255,255)".parseColor());
+ assertEqual('#ff0000', "rgb(255,0,0)".parseColor());
+ assertEqual('#00ff00', "rgb(0,255,0)".parseColor());
+ assertEqual('#0000ff', "rgb(0,0,255)".parseColor());
+ }},
+
+ testStringParseStyle: function() { with(this) {
+ var expected = "#<Hash:{'fontSize': '11px'}>";
+ var expectedMultiple = "#<Hash:{'fontSize': '11px', 'width': '780px'}>";
+
+ assertInspect(expected, "font-size:11px".parseStyle());
+ assertInspect(expected, "font-SIZE: 11px".parseStyle());
+ assertInspect(expected, "font-size:11px ".parseStyle());
+ assertInspect(expected, " Font-size: 11px ".parseStyle());
+
+ assertInspect(expectedMultiple, " font-size: 11px;width:780px".parseStyle());
+
+ }}
+
+ });
+
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/unittest_test.html b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/unittest_test.html
new file mode 100644
index 000000000..39c078959
--- /dev/null
+++ b/scripts/ems/web/javascripts/scriptaculous-js-1.8.3/test/unit/unittest_test.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>script.aculo.us Unit test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../lib/prototype.js" type="text/javascript"></script>
+ <script src="../../src/scriptaculous.js" type="text/javascript"></script>
+ <script src="../../src/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../test.css" type="text/css" />
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ #testcss1 { font-size:11px; color: #f00; }
+ #testcss2 { font-size:12px; color: #0f0; display: none; }
+ /* ]]> */
+ </style>
+</head>
+<body>
+<h1>script.aculo.us Unit test file</h1>
+<p>
+ This is a preliminary version mostly for testing the unittest library.
+</p>
+
+<!-- Log output -->
+<div id="testlog"> </div>
+
+<!-- Test elements follow -->
+<div id="test_1" class="a bbbbbbbbbbbb cccccccccc dddd"> </div>
+
+<div id="test_2"> <span> </span>
+
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+<ul id="tlist"><li id="tlist_1">x1</li><li id="tlist_2">x2</li></ul>
+<ul id="tlist2"><li class="a" id="tlist2_1">x1</li><li id="tlist2_2">x2</li></ul>
+
+<div id="testmoveby" style="background-color:#333;width:100px;">XXXX</div>
+
+<div id="testcss1">testcss1<span id="testcss1_span" style="display:none;">blah</span></div><div id="testcss2">testcss1</div>
+
+<!-- Tests follow -->
+<script type="text/javascript" language="javascript" charset="utf-8">
+// <![CDATA[
+
+ var testObj = {
+ isNice: function(){
+ return true;
+ },
+ isBroken: function(){
+ return false;
+ }
+ }
+
+ new Test.Unit.Runner({
+
+ testAssertEqual: function() { with(this) {
+ assertEqual(0, 0);
+ assertEqual(0, 0, "test");
+
+ assertEqual(0,'0');
+ assertEqual(65.0, 65);
+
+ assertEqual("a", "a");
+ assertEqual("a", "a", "test");
+
+ assertNotEqual(0, 1);
+ assertNotEqual("a","b");
+ assertNotEqual({},{});
+ assertNotEqual([],[]);
+ assertNotEqual([],{});
+ }},
+
+ testAssertRespondsTo: function() { with(this) {
+ assertRespondsTo('isNice', testObj);
+ assertRespondsTo('isBroken', testObj);
+ }},
+
+ testAssertIndentical: function() { with(this) {
+ assertIdentical(0, 0);
+ assertIdentical(0, 0, "test");
+ assertIdentical(1, 1);
+ assertIdentical('a', 'a');
+ assertIdentical('a', 'a', "test");
+ assertIdentical('', '');
+ assertIdentical(undefined, undefined);
+ assertIdentical(null, null);
+ assertIdentical(true, true);
+ assertIdentical(false, false);
+
+ var obj = {a:'b'};
+ assertIdentical(obj, obj);
+
+ assertNotIdentical({1:2,3:4},{1:2,3:4});
+
+ assertIdentical(1, 1.0); // both are typeof == 'number'
+
+ assertNotIdentical(1, '1');
+ assertNotIdentical(1, '1.0');
+ }},
+
+ testAssertMatch: function() { with(this) {
+ assertMatch(/knowmad.jpg$/, 'http://script.aculo.us/images/knowmad.jpg');
+ assertMatch(/Fuc/, 'Thomas Fuchs');
+ assertMatch(/^\$(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/, '$19.95');
+ assertMatch(/(\d{3}\) ?)|(\d{3}[- \.])?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$/, '704-343-9330');
+ assertMatch(/^(?:(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))))$/, '2001-06-16');
+ assertMatch(/^((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m\s*-\s*((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m$/i, '2:00PM-2:15PM');
+
+ }},
+
+ testAssertInstanceOf: function() { with(this) {
+ assertInstanceOf(Effect.Opacity, new Effect.Opacity('testcss1',{sync:true}));
+ assertNotInstanceOf(String, new Effect.Opacity('testcss1',{sync:true}));
+
+ // note: fails with firefox 1.0.X (bug, fixed in Deer Park)
+ assertNotInstanceOf(Effect.Parallel, new Effect.Opacity('testcss1',{sync:true}), "(note: fails with firefox 1.0.X, fixed in Deer Park)");
+ }},
+
+ testAssertReturns: function() { with(this) {
+
+ assertReturnsTrue('isNice',testObj);
+ assertReturnsFalse('isBroken',testObj);
+
+ assertReturnsTrue('nice',testObj);
+ assertReturnsFalse('broken',testObj);
+
+ }},
+
+ testAssertVisible: function() { with(this) {
+ assertVisible('testcss1');
+ assertNotVisible('testcss1_span');
+ assertNotVisible('testcss2', "Due to a Safari bug, this test fails in Safari.");
+
+ Element.hide('testcss1');
+ assertNotVisible('testcss1');
+ assertNotVisible('testcss1_span');
+ Element.show('testcss1');
+ assertVisible('testcss1');
+ assertNotVisible('testcss1_span');
+
+ Element.show('testcss1_span');
+ assertVisible('testcss1_span');
+ Element.hide('testcss1');
+ assertNotVisible('testcss1_span'); // hidden by parent
+ }}
+
+ }, "testlog");
+// ]]>
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/scripts/ems/web/overview.php b/scripts/ems/web/overview.php
index 47d3f8850..c49e74be6 100644
--- a/scripts/ems/web/overview.php
+++ b/scripts/ems/web/overview.php
@@ -13,7 +13,7 @@ function setup() {
print "<TR><TD><A HREF=\"?setup=$dir[0]\">$dir[0]</A></TD><TD>$dir[1]</TD><TD>$dir[2]</TD><TD>$dir[3]</TD></TR>\n";
}
print "</TABLE>\n";
- print "<P>To add experiment, edit the file 'setup' in the web directory.";
+ print "<P>To add experiment, edit /fs/thor4/html/experiment/setup";
}
function overview() {
@@ -85,6 +85,17 @@ function overview() {
if ($info->last_step == "TUNING<BR>tune") {
print "<BR>".tune_status($id);
}
+ else if ($info->last_step == "TRAINING<BR>run-giza" ||
+ $info->last_step == "TRAINING<BR>run-giza-inverse" ||
+ preg_match('/EVALUATION.+decode/',$info->last_step,$dummy) ||
+ $info->last_step == "TRAINING<BR>extract-phrases") {
+ $module_step = explode("<BR>",$info->last_step);
+ $step_file = "$dir/steps/$id/$module_step[0]_$module_step[1].$id";
+ print "<BR><span id='$module_step[0]-$module_step[1]-$id'><img src=\"spinner.gif\" width=12 height=12></span>";
+?><script language="javascript" type="text/javascript">
+new Ajax.Updater("<?php print "$module_step[0]-$module_step[1]-$id"; ?>", '?setStepStatus=' + encodeURIComponent("<?php print $step_file; ?>"), { method: 'get', evalScripts: true });</script>
+<?php
+ }
}
else if (property_exists($info,"result")) {
print mytime($info->end,1);
@@ -241,10 +252,6 @@ function lowlightAll() {
}
}
-function highlightScore() {
-
-}
-
highlightBest();
//-->
</script>
@@ -259,9 +266,12 @@ function mytime($timestamp,$running) {
return strftime("%T",$timestamp);
}
if ($timestamp + 5*24*3600 > time()) {
- return strftime("%a %H:%M",$timestamp);
+ return strftime("%a %H:%M",$timestamp);
}
- return strftime("%d %b",$timestamp);
+ if ($timestamp + 180*24*3600 > time()) {
+ return strftime("%d %b",$timestamp);
+ }
+ return strftime("%d %b %g",$timestamp);
}
function output_score($id,$info) {
@@ -385,3 +395,9 @@ function show() {
readfile($fullname);
exit;
}
+
+function set_step_status($fileName) {
+ $cmd = "./progress.perl $fileName 2>/dev/null";
+ #print $cmd."<p>";
+ system($cmd);
+}
diff --git a/scripts/ems/web/progress.perl b/scripts/ems/web/progress.perl
new file mode 100755
index 000000000..6e26a7881
--- /dev/null
+++ b/scripts/ems/web/progress.perl
@@ -0,0 +1,175 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Date::Parse;
+
+my $file = $ARGV[0] || die;
+die unless -e $file;
+
+my $start;
+open(OUT,$file.".STDOUT");
+my $start_line = <OUT>;
+if ($start_line =~ /starting at (.+) on \S+$/) {
+ $start = str2time($1);
+}
+close(OUT);
+my $current = time();
+
+&progress_run_giza($file) if $file =~ /TRAINING_run-giza/;
+&progress_extract($file) if $file =~ /TRAINING_extract-phrases/;
+&progress_decode($file) if $file =~ /EVALUATION_.+_decode/;
+
+sub progress_extract {
+ my ($file) = @_;
+
+ my $dot_line = `tail -n 1 $file.STDERR`;
+ chop($dot_line);
+ $dot_line =~ s/^\.//g;
+ my $lines_processed = length($dot_line)*10000;
+
+ my $total = `grep ^total $file.STDOUT`;
+ return unless $total =~ /^total=(\d+)/;
+ my $lines_total = $1;
+
+ my $ratio = $lines_processed/$lines_total;
+ my $remaining = &generic_remaining($ratio);
+ print &format_progress($ratio,$remaining);
+}
+
+sub progress_run_giza {
+ my ($file) = @_;
+ my $info;
+ my $max_sent = 0;
+ my $sent = 0;
+
+ my ($iter_m1,$iter_hmm,$iter_m3,$iter_m4) = (5,5,5,5);
+ my $ratio = "?";
+ my $already = 0;
+ my $added = 0;
+ my $total = 1;
+ my $factor;
+
+ open(GIZA,$file.".STDOUT");
+ while(<GIZA>) {
+ $iter_m1 = $1 if /^model1iterations = (\d+)/;
+ $iter_hmm = $1 if /^hmmiterations = (\d+)/;
+ $iter_m3 = $1 if /^model3iterations = (\d+)/;
+ $iter_m4 = $1 if /^model4iterations = (\d+)/;
+
+ if (/starting at (.+) on \S+$/) {
+ $info = "start";
+ $total = $iter_m1/10+$iter_hmm+$iter_m3+$iter_m4*3;
+ }
+ elsif (/Model1 Training Started at: (.+)/) {
+ $info = "m1:it1";
+ $added += $2;
+ }
+ elsif (/Model 1 Iteration: (\d+) took: (\d+) seconds/) {
+ $info = "m1:it".($1+1);
+ $info = "hmm:it1" if $1 == $iter_m1;
+ $added += $2;
+ $already = $1;
+ $factor = ($1 == $iter_m1) ? 1 : 0.1;
+ }
+ elsif (/Hmm Iteration: (\d+) took: (\d+) seconds/) {
+ $info = "hmm:it".($1+1);
+ $info = "m3:it1" if $1 == $iter_hmm;
+ $added += $2;
+ $already = $iter_m1/10+$1;
+ $factor = 1;
+ }
+ elsif (/THTo3 Viterbi Iteration : (\d+) took: (\d+) seconds/) {
+ $info = "m3:it2";
+ $added += $2;
+ $already = $iter_m1/10+$iter_hmm+1;
+ $factor = 1;
+ }
+ elsif (/Model3 Viterbi Iteration : (\d+) took: (\d+) seconds/) {
+ $info = "m3:it".($1+1);
+ $info = "m4:it1" if $1 == $iter_m3;
+ $added += $2;
+ $already = $iter_m1/10+$iter_hmm+$1;
+ $factor = ($1 == $iter_m3) ? 3 : 1;
+ }
+ elsif (/T3To4 Viterbi Iteration : (\d+) took: (\d+) seconds/) {
+ $info = "m4:it2";
+ $added += $2;
+ $already = $iter_m1/10+$iter_hmm+$iter_m3+3;
+ $factor = 3;
+ }
+ elsif (/Model4 Viterbi Iteration : (\d+) took: (\d+) seconds/) {
+ $info = "m4:it".($1-$iter_m3+1);
+ $added += $2;
+ $already = $iter_m1/10+$iter_hmm+$iter_m3+3*($1-$iter_m3);
+ $factor = 3;
+ }
+ elsif (/\[sent:(\d+)\]/) {
+ $sent = $1;
+ $max_sent = $1 if $1 > $max_sent;
+ }
+ }
+ close(GIZA);
+
+ if ($sent > 0) {
+ $already += $sent/$max_sent * $factor;
+ }
+ else {
+ $already += (($current-$start-$added)/($current-$start)-1);
+ }
+
+ return $info unless $already > 0;
+ $ratio = $already/$total;
+ my $remaining = &generic_remaining($ratio);
+ print $info."<BR>".&format_progress($ratio,$remaining);
+}
+
+sub progress_decode {
+ my ($file) = @_;
+ open(FILE,$file);
+ my ($input_file,$output_file);
+ while(<FILE>) {
+ $input_file = $1 if /\< *(\S+)/;
+ $output_file = $1 if /\> *(\S+)/;
+ }
+ close(FILE);
+ return unless defined($input_file);
+ return unless defined($output_file);
+
+ return unless $file =~ /^(.+)\/steps\/\d+\/EVAL/;
+ my $base_dir = $1;
+
+ return unless $input_file =~ /(\/evaluation\/[^\/]+)$/;
+ $input_file = $base_dir.$1;
+ return unless $output_file =~ /(\/evaluation\/[^\/]+)$/;
+ $output_file = $base_dir.$1;
+ return unless -e $input_file && -e $output_file;
+
+ my $total = int(`cat $input_file | wc -l`);
+ my $already = int(`cat $output_file | wc -l`);
+ return unless $already;
+
+ my $ratio = $already/$total;
+ my $remaining = &generic_remaining($ratio);
+ print &format_progress($ratio,$remaining);
+}
+
+sub generic_remaining {
+ my ($ratio) = @_;
+ return ($current-$start)*(1/$ratio-1);
+}
+
+sub format_progress {
+ my ($ratio,$remaining) = @_;
+ return "" if $ratio eq "?";
+ $ratio = .99 if $ratio >= 1;
+ $remaining = 60 if $remaining < 60;
+ if ($remaining >= 36000) {
+ return sprintf("%d%s %dh left\n",$ratio*100,'%',$remaining/3600);
+ }
+ if ($remaining >= 3600) {
+ return sprintf("%d%s %.1fh left\n",$ratio*100,'%',$remaining/3600);
+ }
+ return sprintf("%d%s %dm left\n",$ratio*100,'%',$remaining/60);
+}
+
+