summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2020-07-11 05:01:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2020-07-11 05:01:38 +0000
commita6f0f039845b8131422c55a400483bbb9a53b84c (patch)
tree101ae30cce14cb8f51c65edab163382a4f59398c
parentInitial commit. (diff)
downloadsimile-timeline-a6f0f039845b8131422c55a400483bbb9a53b84c.tar.xz
simile-timeline-a6f0f039845b8131422c55a400483bbb9a53b84c.zip
Adding upstream version 2.3.0.upstream/2.3.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.project7
-rw-r--r--CHANGES.txt263
-rw-r--r--LICENSE.txt39
-rw-r--r--README.txt88
-rw-r--r--build.xml142
-rw-r--r--jetty.xml178
-rw-r--r--run2
-rw-r--r--run.bat1
-rw-r--r--src/ajax/api/content/history.html7
-rw-r--r--src/ajax/api/images/bubble-arrow-point-down.pngbin0 -> 3654 bytes
-rw-r--r--src/ajax/api/images/bubble-arrow-point-left.pngbin0 -> 3455 bytes
-rw-r--r--src/ajax/api/images/bubble-arrow-point-right.pngbin0 -> 3529 bytes
-rw-r--r--src/ajax/api/images/bubble-arrow-point-up.pngbin0 -> 3413 bytes
-rw-r--r--src/ajax/api/images/bubble-bottom-left.pngbin0 -> 3232 bytes
-rw-r--r--src/ajax/api/images/bubble-bottom-right.pngbin0 -> 3291 bytes
-rw-r--r--src/ajax/api/images/bubble-bottom.pngbin0 -> 3119 bytes
-rw-r--r--src/ajax/api/images/bubble-left.pngbin0 -> 3601 bytes
-rw-r--r--src/ajax/api/images/bubble-right.pngbin0 -> 3620 bytes
-rw-r--r--src/ajax/api/images/bubble-top-left.pngbin0 -> 3115 bytes
-rw-r--r--src/ajax/api/images/bubble-top-right.pngbin0 -> 3241 bytes
-rw-r--r--src/ajax/api/images/bubble-top.pngbin0 -> 3095 bytes
-rw-r--r--src/ajax/api/images/close-button.pngbin0 -> 624 bytes
-rw-r--r--src/ajax/api/images/copy.pngbin0 -> 196 bytes
-rw-r--r--src/ajax/api/images/message-bottom-left.pngbin0 -> 1339 bytes
-rw-r--r--src/ajax/api/images/message-bottom-right.pngbin0 -> 2074 bytes
-rw-r--r--src/ajax/api/images/message-left.pngbin0 -> 717 bytes
-rw-r--r--src/ajax/api/images/message-right.pngbin0 -> 1892 bytes
-rw-r--r--src/ajax/api/images/message-top-left.pngbin0 -> 918 bytes
-rw-r--r--src/ajax/api/images/message-top-right.pngbin0 -> 1604 bytes
-rw-r--r--src/ajax/api/scripts/ajax.js45
-rw-r--r--src/ajax/api/scripts/data-structure.js447
-rw-r--r--src/ajax/api/scripts/date-time.js452
-rw-r--r--src/ajax/api/scripts/debug.js94
-rw-r--r--src/ajax/api/scripts/dom.js344
-rw-r--r--src/ajax/api/scripts/graphics.js653
-rw-r--r--src/ajax/api/scripts/history.js220
-rw-r--r--src/ajax/api/scripts/html.js274
-rw-r--r--src/ajax/api/scripts/json.js129
-rw-r--r--src/ajax/api/scripts/platform.js114
-rw-r--r--src/ajax/api/scripts/signal.js43
-rw-r--r--src/ajax/api/scripts/string.js43
-rw-r--r--src/ajax/api/scripts/units.js64
-rw-r--r--src/ajax/api/scripts/window-manager.js414
-rw-r--r--src/ajax/api/scripts/xmlhttp.js137
-rw-r--r--src/ajax/api/simile-ajax-api.js212
-rw-r--r--src/ajax/api/simile-ajax-bundle.js2623
-rw-r--r--src/ajax/api/styles/graphics-ie6.css77
-rw-r--r--src/ajax/api/styles/graphics.css171
-rw-r--r--src/ajax/site/docs/_01.html42
-rw-r--r--src/ajax/site/docs/_02.html643
-rw-r--r--src/ajax/site/docs/_03.html811
-rw-r--r--src/ajax/site/docs/_04.html42
-rw-r--r--src/ajax/site/docs/_05.html42
-rw-r--r--src/ajax/site/docs/_06.html719
-rw-r--r--src/ajax/site/docs/_07.html42
-rw-r--r--src/ajax/site/docs/_08.html42
-rw-r--r--src/ajax/site/docs/_09.html42
-rw-r--r--src/ajax/site/docs/_10.html42
-rw-r--r--src/ajax/site/docs/_11.html42
-rw-r--r--src/ajax/site/docs/_12.html42
-rw-r--r--src/ajax/site/docs/_13.html42
-rw-r--r--src/ajax/site/docs/_14.html42
-rw-r--r--src/ajax/site/docs/_15.html69
-rw-r--r--src/ajax/site/docs/_16.html262
-rw-r--r--src/ajax/site/docs/_17.html197
-rw-r--r--src/ajax/site/docs/_18.html42
-rw-r--r--src/ajax/site/docs/constructor.gifbin0 -> 363 bytes
-rw-r--r--src/ajax/site/docs/default.css116
-rw-r--r--src/ajax/site/docs/file.gifbin0 -> 242 bytes
-rw-r--r--src/ajax/site/docs/file_list.html146
-rw-r--r--src/ajax/site/docs/function.gifbin0 -> 224 bytes
-rw-r--r--src/ajax/site/docs/index.html13
-rw-r--r--src/ajax/site/docs/object.gifbin0 -> 585 bytes
-rw-r--r--src/ajax/site/docs/overview.gifbin0 -> 614 bytes
-rw-r--r--src/ajax/site/docs/splash.html7
-rw-r--r--src/ajax/site/styles.css9
-rw-r--r--src/ajax/site/test.html57
-rw-r--r--src/graphics/blue-circle.psdbin0 -> 12382 bytes
-rw-r--r--src/graphics/bubble-arrows.pngbin0 -> 12291 bytes
-rw-r--r--src/graphics/bubble-body-and-arrows.pngbin0 -> 12699 bytes
-rw-r--r--src/graphics/bubble-body.pngbin0 -> 5455 bytes
-rw-r--r--src/graphics/bubble-bottom-arrow.pngbin0 -> 1073 bytes
-rw-r--r--src/graphics/bubble-bottom-left.pngbin0 -> 754 bytes
-rw-r--r--src/graphics/bubble-bottom-right.pngbin0 -> 803 bytes
-rw-r--r--src/graphics/bubble-bottom.pngbin0 -> 1141 bytes
-rw-r--r--src/graphics/bubble-left-arrow.pngbin0 -> 825 bytes
-rw-r--r--src/graphics/bubble-left.pngbin0 -> 5670 bytes
-rw-r--r--src/graphics/bubble-right-arrow.pngbin0 -> 941 bytes
-rw-r--r--src/graphics/bubble-right.pngbin0 -> 5686 bytes
-rw-r--r--src/graphics/bubble-top-arrow.pngbin0 -> 762 bytes
-rw-r--r--src/graphics/bubble-top-left.pngbin0 -> 560 bytes
-rw-r--r--src/graphics/bubble-top-right.pngbin0 -> 676 bytes
-rw-r--r--src/graphics/bubble-top.pngbin0 -> 905 bytes
-rw-r--r--src/graphics/bubble.psdbin0 -> 98753 bytes
-rw-r--r--src/graphics/close-button.psdbin0 -> 14850 bytes
-rw-r--r--src/graphics/copyright.psdbin0 -> 31810 bytes
-rw-r--r--src/graphics/ether.inddbin0 -> 303104 bytes
-rw-r--r--src/graphics/gray-circle.psdbin0 -> 12362 bytes
-rw-r--r--src/graphics/green-circle.psdbin0 -> 12378 bytes
-rw-r--r--src/graphics/message.pngbin0 -> 6141 bytes
-rw-r--r--src/graphics/message.psdbin0 -> 89492 bytes
-rw-r--r--src/graphics/red-circle.psdbin0 -> 12376 bytes
-rw-r--r--src/graphics/red-pin.psdbin0 -> 17116 bytes
-rw-r--r--src/graphics/sundial-simile.psdbin0 -> 966682 bytes
-rw-r--r--src/graphics/sundial.pngbin0 -> 62341 bytes
-rw-r--r--src/graphics/sundial.psdbin0 -> 125574 bytes
-rw-r--r--src/graphics/sundial.skbbin0 -> 287789 bytes
-rw-r--r--src/graphics/sundial.skpbin0 -> 356373 bytes
-rw-r--r--src/graphics/timeline.inddbin0 -> 196608 bytes
-rw-r--r--src/misc/fix_svn_props.txt43
-rw-r--r--src/misc/japanese-eras.xlsbin0 -> 77312 bytes
-rw-r--r--src/webapp/api/ext/geochrono/geochrono-api.js92
-rw-r--r--src/webapp/api/ext/geochrono/scripts/ether-painters.js204
-rw-r--r--src/webapp/api/ext/geochrono/scripts/geochrono.js518
-rw-r--r--src/webapp/api/ext/geochrono/scripts/l10n/en/labellers.js10
-rw-r--r--src/webapp/api/ext/geochrono/scripts/labellers.js52
-rw-r--r--src/webapp/api/ext/geochrono/scripts/units.js86
-rw-r--r--src/webapp/api/ext/planning/planning-api.js92
-rw-r--r--src/webapp/api/ext/planning/scripts/ether-painters.js176
-rw-r--r--src/webapp/api/ext/planning/scripts/l10n/en/labellers.js12
-rw-r--r--src/webapp/api/ext/planning/scripts/labellers.js33
-rw-r--r--src/webapp/api/ext/planning/scripts/planning.js47
-rw-r--r--src/webapp/api/ext/planning/scripts/units.js66
-rw-r--r--src/webapp/api/images/blue-circle.pngbin0 -> 534 bytes
-rw-r--r--src/webapp/api/images/bubble-bottom-arrow.pngbin0 -> 1087 bytes
-rw-r--r--src/webapp/api/images/bubble-bottom-left.pngbin0 -> 754 bytes
-rw-r--r--src/webapp/api/images/bubble-bottom-right.pngbin0 -> 803 bytes
-rw-r--r--src/webapp/api/images/bubble-bottom.pngbin0 -> 1141 bytes
-rw-r--r--src/webapp/api/images/bubble-left-arrow.pngbin0 -> 880 bytes
-rw-r--r--src/webapp/api/images/bubble-left.pngbin0 -> 5670 bytes
-rw-r--r--src/webapp/api/images/bubble-right-arrow.pngbin0 -> 941 bytes
-rw-r--r--src/webapp/api/images/bubble-right.pngbin0 -> 5686 bytes
-rw-r--r--src/webapp/api/images/bubble-top-arrow.pngbin0 -> 793 bytes
-rw-r--r--src/webapp/api/images/bubble-top-left.pngbin0 -> 560 bytes
-rw-r--r--src/webapp/api/images/bubble-top-right.pngbin0 -> 676 bytes
-rw-r--r--src/webapp/api/images/bubble-top.pngbin0 -> 905 bytes
-rw-r--r--src/webapp/api/images/close-button.pngbin0 -> 624 bytes
-rw-r--r--src/webapp/api/images/copyright-vertical.pngbin0 -> 1695 bytes
-rw-r--r--src/webapp/api/images/copyright.pngbin0 -> 1400 bytes
-rw-r--r--src/webapp/api/images/dark-blue-circle.pngbin0 -> 551 bytes
-rw-r--r--src/webapp/api/images/dark-green-circle.pngbin0 -> 513 bytes
-rw-r--r--src/webapp/api/images/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/api/images/dull-blue-circle.pngbin0 -> 539 bytes
-rw-r--r--src/webapp/api/images/dull-green-circle.pngbin0 -> 539 bytes
-rw-r--r--src/webapp/api/images/dull-red-circle.pngbin0 -> 532 bytes
-rw-r--r--src/webapp/api/images/gray-circle.pngbin0 -> 513 bytes
-rw-r--r--src/webapp/api/images/green-circle.pngbin0 -> 544 bytes
-rw-r--r--src/webapp/api/images/message-bottom-left.pngbin0 -> 1339 bytes
-rw-r--r--src/webapp/api/images/message-bottom-right.pngbin0 -> 2074 bytes
-rw-r--r--src/webapp/api/images/message-left.pngbin0 -> 717 bytes
-rw-r--r--src/webapp/api/images/message-right.pngbin0 -> 1892 bytes
-rw-r--r--src/webapp/api/images/message-top-left.pngbin0 -> 918 bytes
-rw-r--r--src/webapp/api/images/message-top-right.pngbin0 -> 1604 bytes
-rw-r--r--src/webapp/api/images/progress-running.gifbin0 -> 1002 bytes
-rw-r--r--src/webapp/api/images/red-circle.pngbin0 -> 538 bytes
-rw-r--r--src/webapp/api/images/top-bubble.pngbin0 -> 6092 bytes
-rw-r--r--src/webapp/api/scripts/band.js733
-rw-r--r--src/webapp/api/scripts/compact-painter.js1041
-rw-r--r--src/webapp/api/scripts/decorators.js184
-rw-r--r--src/webapp/api/scripts/detailed-painter.js691
-rw-r--r--src/webapp/api/scripts/ether-painters.js576
-rw-r--r--src/webapp/api/scripts/ethers.js305
-rw-r--r--src/webapp/api/scripts/event-utils.js64
-rw-r--r--src/webapp/api/scripts/ext/japanese-eras.js395
-rw-r--r--src/webapp/api/scripts/l10n/cs/labellers.js30
-rw-r--r--src/webapp/api/scripts/l10n/cs/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/de/labellers.js27
-rw-r--r--src/webapp/api/scripts/l10n/de/timeline.js8
-rw-r--r--src/webapp/api/scripts/l10n/en/labellers.js12
-rw-r--r--src/webapp/api/scripts/l10n/en/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/es/labellers.js8
-rw-r--r--src/webapp/api/scripts/l10n/es/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/fr/labellers.js8
-rw-r--r--src/webapp/api/scripts/l10n/fr/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/it/labellers.js8
-rw-r--r--src/webapp/api/scripts/l10n/it/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/nl/labellers.js11
-rw-r--r--src/webapp/api/scripts/l10n/nl/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/ru/labellers.js10
-rw-r--r--src/webapp/api/scripts/l10n/ru/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/se/labellers.js12
-rw-r--r--src/webapp/api/scripts/l10n/se/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/tr/labellers.js8
-rw-r--r--src/webapp/api/scripts/l10n/tr/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/vi/labellers.js26
-rw-r--r--src/webapp/api/scripts/l10n/vi/timeline.js9
-rw-r--r--src/webapp/api/scripts/l10n/zh/labellers.js27
-rw-r--r--src/webapp/api/scripts/l10n/zh/timeline.js9
-rw-r--r--src/webapp/api/scripts/labellers.js91
-rw-r--r--src/webapp/api/scripts/original-painter.js674
-rw-r--r--src/webapp/api/scripts/overview-painter.js258
-rw-r--r--src/webapp/api/scripts/sources.js567
-rw-r--r--src/webapp/api/scripts/themes.js180
-rw-r--r--src/webapp/api/scripts/timeline.js645
-rw-r--r--src/webapp/api/scripts/units.js68
-rw-r--r--src/webapp/api/styles/ethers.css120
-rw-r--r--src/webapp/api/styles/events.css45
-rw-r--r--src/webapp/api/styles/timeline.css65
-rw-r--r--src/webapp/api/timeline-api.js280
-rw-r--r--src/webapp/api/timeline-bundle.css229
-rw-r--r--src/webapp/api/timeline-bundle.js2835
-rw-r--r--src/webapp/doap.rdf42
-rw-r--r--src/webapp/docs/bands.html297
-rw-r--r--src/webapp/docs/basics.html138
-rw-r--r--src/webapp/docs/create-timelines.html527
-rw-r--r--src/webapp/docs/create-timelines.js224
-rw-r--r--src/webapp/docs/ether-painters.html109
-rw-r--r--src/webapp/docs/ethers.html130
-rw-r--r--src/webapp/docs/event-painters.html87
-rw-r--r--src/webapp/docs/example1.xml27
-rw-r--r--src/webapp/docs/example2.xml45
-rw-r--r--src/webapp/docs/gregorian-ether-painter.html91
-rw-r--r--src/webapp/docs/hot-zone-ether.html225
-rw-r--r--src/webapp/docs/hot-zone-gregorian-ether-painter.html233
-rw-r--r--src/webapp/docs/images/ether-coordinates.jpgbin0 -> 50493 bytes
-rw-r--r--src/webapp/docs/images/timeline.jpgbin0 -> 16568 bytes
-rw-r--r--src/webapp/docs/index.html52
-rw-r--r--src/webapp/docs/linear-ether.html88
-rw-r--r--src/webapp/docs/styles.css43
-rw-r--r--src/webapp/docs/timelines.html501
-rw-r--r--src/webapp/examples/compact-painter/compact-painter.html104
-rw-r--r--src/webapp/examples/compact-painter/data.json597
-rw-r--r--src/webapp/examples/compact-painter/no-image-40.pngbin0 -> 1383 bytes
-rw-r--r--src/webapp/examples/compact-painter/no-image-80.pngbin0 -> 2085 bytes
-rw-r--r--src/webapp/examples/cubism/blue_stripes.pngbin0 -> 116 bytes
-rw-r--r--src/webapp/examples/cubism/cubism.html76
-rw-r--r--src/webapp/examples/cubism/cubism.js108
-rw-r--r--src/webapp/examples/cubism/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/examples/dinosaurs/dinosaurs.html98
-rw-r--r--src/webapp/examples/dinosaurs/dinosaurs.xlsbin0 -> 292864 bytes
-rw-r--r--src/webapp/examples/dinosaurs/dinosaurs.xml1800
-rw-r--r--src/webapp/examples/dinosaurs/dinosaurs2.html142
-rw-r--r--src/webapp/examples/dinosaurs/layouts.js113
-rw-r--r--src/webapp/examples/dinosaurs/painters.js241
-rw-r--r--src/webapp/examples/dinosaurs/scrape-gallery.js34
-rw-r--r--src/webapp/examples/dinosaurs/scrape-list.js42
-rw-r--r--src/webapp/examples/dinosaurs/scrape-timespans.js42
-rw-r--r--src/webapp/examples/dinosaurs/unknown.pngbin0 -> 365 bytes
-rw-r--r--src/webapp/examples/examples.js123
-rw-r--r--src/webapp/examples/index.html76
-rw-r--r--src/webapp/examples/jfk/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/examples/jfk/jfk.html174
-rw-r--r--src/webapp/examples/jfk/jfk.xml954
-rw-r--r--src/webapp/examples/jfk/motorcade.pngbin0 -> 22704 bytes
-rw-r--r--src/webapp/examples/jfk_i18n/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/examples/jfk_i18n/jfk.html174
-rw-r--r--src/webapp/examples/jfk_i18n/jfk.xml954
-rw-r--r--src/webapp/examples/jfk_i18n/motorcade.pngbin0 -> 22704 bytes
-rw-r--r--src/webapp/examples/monet/green-circle.pngbin0 -> 544 bytes
-rw-r--r--src/webapp/examples/monet/impression-sunrise.pngbin0 -> 18284 bytes
-rw-r--r--src/webapp/examples/monet/monet.html96
-rw-r--r--src/webapp/examples/monet/monet.pngbin0 -> 6076 bytes
-rw-r--r--src/webapp/examples/monet/monet.xml238
-rw-r--r--src/webapp/examples/monet/water-lily-pond.pngbin0 -> 26125 bytes
-rw-r--r--src/webapp/examples/religions/christianity.html137
-rw-r--r--src/webapp/examples/religions/christianity.xml2897
-rw-r--r--src/webapp/examples/religions/jewish-history.html140
-rw-r--r--src/webapp/examples/religions/jewish.xml1201
-rw-r--r--src/webapp/examples/religions/religions.html179
-rw-r--r--src/webapp/examples/styles.css11
-rw-r--r--src/webapp/examples/test_example/blue_stripes.pngbin0 -> 116 bytes
-rw-r--r--src/webapp/examples/test_example/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/examples/test_example/firefox_mac_test_case.html46
-rw-r--r--src/webapp/examples/test_example/test.html116
-rw-r--r--src/webapp/examples/test_example/test.js287
-rw-r--r--src/webapp/examples/test_example2/blue_stripes.pngbin0 -> 116 bytes
-rw-r--r--src/webapp/examples/test_example2/cubism1.js108
-rw-r--r--src/webapp/examples/test_example2/cubism2.js242
-rw-r--r--src/webapp/examples/test_example2/dark-red-circle.pngbin0 -> 497 bytes
-rw-r--r--src/webapp/examples/test_example2/test_example2.html182
-rw-r--r--src/webapp/images/sundial.pngbin0 -> 30623 bytes
-rw-r--r--src/webapp/index.html280
-rw-r--r--src/webapp/sidebar.html23
-rw-r--r--src/webapp/styles.css17
274 files changed, 37518 insertions, 0 deletions
diff --git a/.project b/.project
new file mode 100644
index 0000000..8a2e113
--- /dev/null
+++ b/.project
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>timeline</name>
+ <comment></comment>
+ <projects>
+ </projects>
+</projectDescription>
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 0000000..9f03d9b
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,263 @@
+CHANGES.txt
+
+Version 2.3.0
+* Added test 5, really long labels, to test example page rev 1601, LarryK
+* Added tags/latest, a copy of the latest tagged release. Will be used for
+ referring to examples and other source files from the wiki. This way
+ the wiki references will not need to be updated for each release.
+* Added test example page for trying and testing event attributes
+ src/webapp/examples/test_example/test.html -- LarryK rev 1598
+* Fixed issues caused when events don't have title attribute.
+ Issue tracker #20 -- LarryK rev 1598
+* Event tape heights now use theme.event.tape.height. Better than using css since:
+ theme.event.track.height & theme.event.tape.height need to work with each other.
+ It is easier and clearer to set both in the same place (the theme), rather than
+ one in the theme and one in the css. This is a breaking change if you were
+ setting the height in the css. People were having problems with this in the
+ mailing list.
+
+ Further note about this change since it is undoing someone's work: The tape height
+ on the screen was defined purely by css. But the tape height from the theme was
+ still being used (to some extent) in the sw. In particular, the Theme's tape height
+ is returned by function _paintEventTape in file original-painter. It doesn't make
+ sense for the theme's tape height to be returned by the function when the
+ actual height of the tape was being controlled in the css file.
+ -- LarryK rev 1623
+* Un-commented-out
+ div.style.background = color;
+ from Timeline.OriginalEventPainter.prototype._createHighlightDiv function
+ to re-enable event highlighting
+ See http://groups.google.com/group/simile-widgets/browse_thread/thread/acbffeaa662722f8
+ -- Hunt Culver and LarryK rev 1628
+* Bullet-proofing: Fix for issue 34. The Monet example had a latestStart date
+ after the event's earliestEnd. This caused the tape width to be negative. This
+ caused an exception when setting the width value, but only on IE. Fix: changed
+ sources.js to sanity check dates and append error messages to event title if
+ a problem is detected. Updated test example to have events with bad dates.
+ Thank you to Tim Dimsdale for noting that the example didn't run in Monet.
+ -- LarryK rev 1629
+* Tape color for overview painter now set. Uses following precedence: event's color attribute,
+ theme.event.duration.color or css color for class timeline-small-event-tape
+ See issue 16 -- LarryK rev 1630
+* Update to send css class to computeSize. Fixes:
+ issue 13 - TIMELINE: Event labels wrap on FF 3 on Mac
+ issue 30 - TIMELINE : Event labels wrap when 'classname' attribute is added and text is bold
+ NOTE: fixes don't work unless latest Simile-Ajax library is used. Will be
+ automatically used after it is released.
+ -- LarryK rev 1638
+* Added and revised autoWidth. AutoWidth automatically calculates and sets the 'width' for
+ the Timeline's bands and for the overall Timeline. The 'width,' for horizontal
+ Timelines, is actually the 'height' style of the various divs.
+
+ The event painters do not calculate the tracks of all the events when they are loaded,
+ the event tracks are only calculated when they are viewed or are about to be viewed.
+ In the same way, the needed width is re-calculated whenever a new set of events
+ are viewed or are about to be viewed. If the new needed width is greater than the
+ current width, the increase is animated. See the example.
+
+ To use autoWidth:
+ 1) You will be modifying the classic theme's settings in your html file.
+ 2) Set the theme's autoWidth to true
+ 3) Optionally update the theme's autoWidthAnimationTime setting.
+ 4) Optionally update the autoWidthMargin settings in the Theme. The margin, per
+ band, is used to set how close the bottom of the lowest track is to the
+ edge of the band's div. The units are total track width. There are two settings,
+ one for overview bands, the second for others.
+ 5) After you have loaded your events, call tl.finishedEventLoading() where tl is the
+ Timeline object returned from Timeline.create.
+ Demo: examples/test_example2/test_example2.html
+ -- LarryK rev 1630, 1643
+* Updated License to refer to JQuery -- LarryK rev 1643
+* Added License file to zip files -- LarryK rev 1643
+* Changed example files to refer to Google Simile directory. -- LarryK rev 1643
+* Fixed: autoWidth wasn't working on Safari/Windows. -- LarryK rev 1644
+* Fixed issue 33: added event attribute durationEvent.
+ Values of isDuration and durationEvent must be true or false for JSON and
+ "true" or "false" for XML and SPARCL. Otherwise results are indeterminate.
+ This can be a breaking change for event sources that were using values
+ other than the above. -- LarryK rev 1654
+* Added event attribute trackNum for developers to specify a track number.
+ See issue 26. -- LarryK rev 1654
+* Improve autoWidth for overview bands: calculation should include overviewTrack.offset
+ -- LarryK rev 1655
+* Add English day names to en locale -- LarryK rev 1656
+* Rebuilt bundle files with new ver of Ajax lib. -- LarryK rev 1658
+* Split band.js out of timeline.js. Assign event IDs sequentially rather than using
+ random number generator. Add formated ids to event tapes, labels, icons to
+ enable a single listener to retrieve state from the id. Added support functions
+ event-utils.js. -- LarryK rev 1659
+* Highlighting testing using Religions example. Restored event highlight colors to theme
+ to fix. -- LarryK rev 1659
+* New feature: When highlighting events on a Timeline, default is to highlight the event's
+ icon or tape. If theme.event.highlightLabelBackground is true, the label's background
+ will also be changed to the highlight color. See the Jewish timeline example.
+ -- LarryK rev 1659
+* Fixed issue 31, added event's classname attribute to div for icons too.
+ -- LarryK rev 1659
+* event's tape and highlight div's need index num in id since there can be more
+ than one tape div per event. -- And id must be unique. -- LarryK rev 1661
+* Added EventPaintListener hook to original-painter. Enables clients to hook into
+ painting life cycle. See original-painter.js. -- LarryK rev 1661
+* Changed calculation of labelTop for paintImpreciseInstantEvent to be same
+ calculation as in paintPreciseDurationEvent in original-painter.
+ Problem was that label was too close to tape (and would sometimes overlap)
+ for Imprecise Instant Events. Test example 2, imprecise instant event at
+ year 4400 (with thick tape) looks much better with the change.
+ -- LarryK rev 1661
+* Added track.offset setting to original-painter. Enables specific
+ control over top margin of band event painting. Very useful when a
+ Timeline has multiple event bands or a pseudo event band that is just
+ used for labeling above an event band. -- LarryK rev 1661
+* Added instant.impreciseIconMargin to original-painter. Enables specific
+ control over top margin of icon (margin between bottom of tape and
+ top of icon). Only used if the event has a tape and an icon.
+ -- LarryK rev 1661
+* Added band arg to eventPaintListener listeners -- LarryK rev 1662
+* Reworked autoWidth to stop recursive call to painter -- LarryK rev 1663
+* Further autoWidth work to have Timeline monitor scroll of bands rather
+ than having bands call up into Timeline. Eliminated sleep for
+ smoother scrolling with autoWidth -- LarryK rev 1664
+* Use new maxHeight param from SimileAjax for setting maxHeight of
+ bubbles. Added theme.bubble.maxHeight with default of 0 (no maximum).
+ Old theme param of bubble.height is not used within source of
+ Timeline, so removed it. -- LarryK rev 1667
+* Span decorator improvements: now can have null labels. New param of
+ inFront. If true, then the span is in front of all layers but the events.
+ Now uses color attribute if present, else css. -- LarryK rev 1677
+* Span point decorator: Now uses color attribute if present, else css.
+ -- LarryK rev 1677
+* Timeline start and end feature: Optionally add theme.timeline_start,
+ theme.timeline_stop to disable movement of the Timeline beyond the
+ start and/or stop. The setting affects the entire Timeline and must
+ be set in the theme of the first band. Depending on the relative
+ resolutions of the bands, different amounts of the various bands
+ will be seen when at a start or stop edge, depending on which band
+ was being moved and by how much. In addition to setting the timeline_start
+ and _stop, you may want to add span decorators to cover up the
+ unused parts of the Timeline. See example2. Note that the Timeline
+ will not be movable past a start/stop edge but it can be initially
+ loaded beyond the edges by using the date parameter of the Band Info.
+ -- LarryK rev 1677
+
+* When you run run.bat, we now serve
+ http://localhost:9999/ajax/api - from src/webapp/ajax/api/
+ http://localhost:9999/timeline - from src/webapp/site/
+ http://localhost:9999/timeline/api - from src/webapp/timeline/api/
+ -- David H rev 1705
+
+* PointHighlightDecorator now uses the width parameter, not CSS.
+ Issue is that the Point Highlight Decorator is centered on the point in time
+ being decorated. So the JS needs to calculate based on the width--therefore
+ don't use CSS for width. Thanks to Christian Thiemann.
+* Revised all examples to use new directory layout.
+ -- LarryK rev 1729
+* Added CompactPainter, which allows for large images and can render
+ image stacks. See the new compact-painter example.
+ -- David H rev 1759
+* Added Timeline.version string in timeline.js. Issue 60.
+ Added Timeline.writeVersion -- a helper that writes out the
+ current version. Updated examples to use it.
+ Updated build.xml to include Ajax new styles directory.
+ Fixed overview painter to use event's classname attribute if present.
+ Add a test for this to test-example.
+ -- LarryK rev 1813
+* Fixed build.xml to not include .bak files.
+ Moved contents of /site up one level into /webapp -- per David H.
+ Fixed library references in all examples to match new dir layout.
+ -- LarryK rev 1814
+* Added src/misc/fix_svn_props.txt -- used to correctly set props on
+ example files. Enables them to be run in browser from svn repo.
+ Changed timeline-api to use MIT Simile Ajax v 2.2.0.
+ Changed version to 2.3.0 in anticipation of the release.
+ -- LarryK rev 1821
+* Also need to set mime type to be text/xml for xml src files.
+ -- LarryK rev 1822
+* Bug fix: misspelled className as classname -- LarryK rev 1823
+* Fixed IE-only bug. Chokes on <span id='x' />. Changed to <span id='x'></span> and all is well.
+ Another IE only bug: double class name selectors don't work on
+ IE. Eg <div class 'foo bar' /> should be selected with css selector .foo.bar (or .bar.foo)
+ Works everywhere but ie. So added label-, icon-, tape- to className plus className by
+ itself in original_painter. Additional prefixes: highlight- for event-highlight,
+ small- for overview painter. Problem was caught by test-example.
+ -- LarryK rev 1824
+* Updated jetty config file to serve
+ http://localhost:9999/timeline - from src/webapp/
+ Revised Release Notes for release.
+ -- LarryK rev 1825
+* Changed copyright link to be http://code.google.com/p/simile-widgets/
+ -- LarryK rev 1826
+
+
+
+
+Version 2.2.0 -- September 23, 2008
+* Prep for 2.2.0: updated RELEASE_NOTES -- LarryK rev 1593
+* Added comments per MPS in timeline-api.js that bundle=true
+ is needed unless you've installed full source
+ -- LarryK rev 1593
+* Added comments to original-painter.js -- LarryK rev 1593
+* Re-built to pick up new simile-ajax that includes jquery 1.2.6
+ -- eob rev 1589
+
+Version 2.1.0 -- September 19, 2008
+* Prep for 2.1.0: updated examples, readme. created RELEASE_NOTES LarryK
+* Added timeline_libraries.zip to build file. Removed install.sh
+ -- LarryK rev 1579
+* Event attribute classname is added to the classnames for the event's label
+ and tape divs. Eg classname of 'hot_event' will result in div classes of
+ 'timeline-event-label hot_event' and 'timeline-event-tape hot_event' for
+ the event's Timeline label and tape, respectively. Change is that classname
+ is now added to the tape's div. -- LarryK rev 1576
+* Re-worked function Timeline.DefaultEventSource.Event in sources.js to use
+ named arguments (via a hash/anon object) rather than positional arguments.
+ 19 positional arguments are too many! Now much easier and cleaner to add
+ additional event attributes.
+ Note: this is a breaking change for anyone who calls Event directly. But since
+ the wiki page about dynamic events recommends calling loadXML, etc, I
+ hoping that this won't cause anyone much pain. And the new format is
+ MUCH easier to use as a developer. -- LarryK rev 1576
+* New event attribute eventID is a 'cookie' attribute that is stored, not used
+ by the Timeline library. If you write a custom labeller or event bubble
+ filler, the attribute can be obtained using the getEventID() method on the
+ event object. -- LarryK rev 1576
+* New event attribute caption superceedes hoverText. hoverText is deprecated.
+ For now, it will live on for backwards compatibility. -- LarryK rev 1576
+* Event attributes barImage and barRepeat renamed to tapeImage and tapeRepeat.
+ No backwards compatibility. (Breaking change from previous checkin)
+ -- LarryK rev 1576
+* Fix: Event color attribute now properly sets the background color of the bar.
+ Note that events (where isDuration = true) have opacity applied. See
+ http://code.google.com/p/simile-widgets/wiki/Timeline_EventSources (LarryK) rev 1569
+* New event attribute barImage sets the event's bar div background-image.
+ New event attribute barRepeat sets the background-repeat. Default is 'repeat'
+ Cubism example updated to demonstrate color, textColor, barImage, barRepeat and
+ hoverText attributes. For a handy stripe generator, see
+ http://www.stripegenerator.com (LarryK) rev 1569
+* Fix: Event attribute hoverText was not properly processed by JSON or SPARCL sources
+ (LarryK) rev 1569
+* Build process now creates timeline_source.zip which has source, examples and the
+ jetty web server. Enables easy access with for folks without svn. (LarryK) rev 1569
+* Added copy of JFK timeline in examples with Dutch locale set.
+ (LarryK) rev 1560
+* Added forceLocale parameter to timeline-api.js to force a locale for testing
+ (LarryK) rev 1560
+* Added Dutch localization (Marko) rev 1560
+* Added mouse-wheel scroll. Mouse-wheel acts as left and right arrow keys. Theme
+ controls whether the mouse-wheel scrolls, zooms or moves the page (if the page
+ has a scroll-bar). Docs: see webapp/docs/create-timelines.html
+ (LarryK) rev 1553
+* Additional support in timeline-api for using your own server for Timeline
+ libraries (LarryK) rev 1553
+* Separation of javascript and css (gm.marko) rev 1326
+* Added mouse-wheel zoom functionality. It operates on a per-band basis, keeping
+ the date under the mouse cursor static while the timeline around it scales.
+ Zoom is specified as user-defined steps. Documentation and a working demo in
+ the webapp/docs/create-timelines.html page (halcyon1981) rev 1418
+* Added support for 'hoverText' - title pop-ups on Exhibit-based timelines
+ (Vincent.Vazzo) rev 1411
+
+
+Version 2.0
+* Software changes
+* Moved svn repository to Google code
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..3830502
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,39 @@
+/*
+ * (c) Copyright The SIMILE Project 2006. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Note: JQuery, www.jquery.com is included in the Ajax section of this
+ * distribution. It is covered by its own license:
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ */
+
+
+
+
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..e82a65b
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,88 @@
+
+ T I M E L I N E
+
+
+ What is this?
+ -------------
+
+ Timeline is a DHTML-based AJAXy timeline.
+
+
+ Running Timeline
+ ----------------
+
+ Timeline consists of static resources, Javascript libraries,
+ image files and css files. All you really need is to
+ serve those resources off a web server. Any web server will do.
+
+ Two ways to access the library
+
+ 1. Unzip either timeline_source.zip or timeline_libraries.zip into
+ a directory served by a webserver.
+
+ timeline_source.zip includes complete source and example files. Use your
+ browser to see the examples at
+ .../timeline_directory/src/webapp
+
+ timeline_libraries.zip is the minimum install of the bundled js libraries,
+ css and image files
+
+ 2. No web server? The timeline project includes a small webserver called
+ Jetty (use the timeline_source.zip file)
+ a) install the Java runtime from Sun
+ b) unzip timeline_source.zip to an install directory
+ c) Open a shell or command prompt to the install directory and type:
+
+ [win32]> run
+ [unix/macosx]> chmod +x run; ./run
+
+ and then point your browser to
+
+ http://127.0.0.1:9999/timeline/
+
+
+ How do I customize Timeline?
+ ----------------------------
+
+ Refer to the Timeline web site at
+ http://code.google.com/p/simile-widgets/
+
+
+ Mailing List and Forum
+ ----------------------
+
+ Join the community by joining the Google Group SIMILE Widgets
+ http://groups.google.com/group/simile-widgets/
+
+
+ Licensing and legal issues
+ --------------------------
+
+ Timeline is open source software and are licensed under the BSD license
+ located in the LICENSE.txt file located in the same directory as this very file
+ you are reading.
+
+
+
+ Credits
+ -------
+
+ This software was created by the SIMILE project and originally written
+ by the SIMILE development team (in alphabetical order):
+
+ - David Franšois Huynh <dfhuynh at csail.mit.edu>
+
+
+
+
+ --- o ---
+
+
+ Thanks for your interest.
+
+
+
+
+ The SIMILE Project
+ http://simile.mit.edu/
+
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..4c1d8b5
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,142 @@
+<!--+
+ |
+ | +===========================+
+ | | Timeline Build System |
+ | +===========================+
+ |
+ | This is just for bundling and minifying javascript and CSS files.
+ |
+ +-->
+
+<project default="all" basedir="." name="Timeline">
+
+ <property name="version" value="2.3.0" />
+
+ <target name="all" depends="timeline_source.zip, timeline_libraries.zip" />
+
+ <target name="tasks">
+ <taskdef name="jsmin"
+ classname="edu.mit.simile.jsminTask.JSMinTask"
+ classpath="tools/jsminTask.jar"/>
+ </target>
+
+ <target name="bundle" depends="tasks">
+ <!-- SimileAjax -->
+ <jsmin output="src/ajax/api/simile-ajax-bundle.js">
+ <fileset dir="src/ajax/api/scripts">
+ <include name="jquery*.js" />
+ <include name="platform.js" />
+ </fileset>
+ <fileset dir="src/ajax/api/scripts">
+ <include name="**/*.js" />
+ <exclude name="signal.js" />
+ <exclude name="jquery*.js" />
+ <exclude name="platform.js" />
+ </fileset>
+ </jsmin>
+
+ <!-- Timeline -->
+ <jsmin output="src/webapp/api/timeline-bundle.js">
+ <fileset dir="src/webapp/api/scripts">
+ <include name="*.js" />
+ </fileset>
+ </jsmin>
+
+ <concat destfile="src/webapp/api/timeline-bundle.css">
+ <fileset dir="src/webapp/api/styles">
+ <include name="**/*.css" />
+ </fileset>
+ </concat>
+ </target>
+
+ <target name="create_output1" depends="bundle">
+ <!-- Create versioned timeline dir with lib, src, examples, jetty -->
+ <delete dir="timeline_${version}"/>
+ <copy todir="timeline_${version}/lib">
+ <fileset dir="lib" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+ <copy todir="timeline_${version}/src">
+ <fileset dir="src" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+ <copy todir="timeline_${version}/tools">
+ <fileset dir="tools" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+
+ <copy file=".project" todir="timeline_${version}" />
+ <copy file="build.xml" todir="timeline_${version}" />
+ <copy file="CHANGES.txt" todir="timeline_${version}" />
+ <copy file="jetty.xml" todir="timeline_${version}" />
+ <copy file="LICENSE.txt" todir="timeline_${version}" />
+ <copy file="README.txt" todir="timeline_${version}" />
+ <copy file="run" todir="timeline_${version}" />
+ <copy file="run.bat" todir="timeline_${version}" />
+ </target>
+
+ <target name="timeline_source.zip" depends="create_output1">
+ <!-- Create timeline_source.zip - entire source tree: tools, lib, src -->
+ <delete file="timeline_source.zip" />
+ <zip destfile="timeline_source.zip"
+ basedir="."
+ update="yes"
+ duplicate="fail"
+ includes="timeline_${version}/**"
+ />
+ <delete dir="timeline_${version}"/>
+ </target>
+
+ <target name="create_output2" depends="bundle">
+ <!-- Create versioned timeline dir with just bundled libraries and support files -->
+
+ <!-- timeline files -->
+ <property name="webapp_api" value="src/webapp/api/" />
+
+ <delete dir="timeline_${version}"/>
+ <copy file="${webapp_api}timeline-api.js" todir="timeline_${version}/timeline_js" />
+ <copy file="${webapp_api}timeline-bundle.js" todir="timeline_${version}/timeline_js" />
+ <copy file="${webapp_api}timeline-bundle.css" todir="timeline_${version}/timeline_js" />
+ <copy file="LICENSE.txt" todir="timeline_${version}" />
+
+ <copy todir="timeline_${version}/timeline_js/images">
+ <fileset dir="${webapp_api}images" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+
+ <copy todir="timeline_${version}/timeline_js/scripts/l10n">
+ <fileset dir="${webapp_api}scripts/l10n" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+
+ <!-- ajax files -->
+ <property name="ajax_api" value="src/ajax/api/" />
+ <copy file="${ajax_api}simile-ajax-api.js" todir="timeline_${version}/timeline_ajax" />
+ <copy file="${ajax_api}simile-ajax-bundle.js" todir="timeline_${version}/timeline_ajax" />
+
+ <copy todir="timeline_${version}/timeline_ajax/images">
+ <fileset dir="${ajax_api}images" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+ <copy todir="timeline_${version}/timeline_ajax/styles">
+ <fileset dir="${ajax_api}styles" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+ <copy todir="timeline_${version}/timeline_ajax/content">
+ <fileset dir="${ajax_api}content" excludes="**/.svn/**, **/*.bak" />
+ </copy>
+
+ <copy file="${ajax_api}scripts/signal.js" todir="timeline_${version}/timeline_ajax/scripts" />
+
+ <!-- release files -->
+ <copy file="CHANGES.txt" todir="timeline_${version}" />
+ <copy file="LICENSE.txt" todir="timeline_${version}" />
+ <copy file="README.txt" todir="timeline_${version}" />
+ </target>
+
+ <target name="timeline_libraries.zip" depends="create_output2">
+ <!-- Create timeline_libraries.zip - entire source tree: tools, lib, src -->
+ <delete file="timeline_libraries.zip" />
+ <zip destfile="timeline_libraries.zip"
+ basedir="."
+ update="yes"
+ duplicate="fail"
+ includes="timeline_${version}/**"
+ />
+ <delete dir="timeline_${version}"/>
+ </target>
+
+</project>
diff --git a/jetty.xml b/jetty.xml
new file mode 100644
index 0000000..6b4e259
--- /dev/null
+++ b/jetty.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+
+<!-- =============================================================== -->
+<!-- Configure the Jetty Server -->
+<!-- =============================================================== -->
+<Configure id="Server" class="org.mortbay.jetty.Server">
+
+ <!-- =========================================================== -->
+ <!-- Server Thread Pool -->
+ <!-- =========================================================== -->
+ <Set name="ThreadPool">
+ <New class="org.mortbay.thread.BoundedThreadPool">
+ <Set name="minThreads">25</Set>
+ <Set name="maxThreads">250</Set>
+ </New>
+ </Set>
+
+ <!-- =========================================================== -->
+ <!-- Set connectors -->
+ <!-- =========================================================== -->
+ <!-- One of each type! -->
+ <!-- =========================================================== -->
+ <Set name="connectors">
+ <Array type="org.mortbay.jetty.Connector">
+
+ <Item>
+ <New class="org.mortbay.jetty.bio.SocketConnector">
+ <Set name="port">9999</Set>
+ <Set name="maxIdleTime">50000</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+
+ <!-- =========================================================== -->
+ <!-- Set handler Collection Structure -->
+ <!-- =========================================================== -->
+ <Set name="handler">
+ <New id="handlers" class="org.mortbay.jetty.handler.HandlerCollection">
+ <Set name="handlers">
+ <Array type="org.mortbay.jetty.Handler">
+ <Item>
+ <New id="contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
+ </Item>
+ <Item>
+ <New id="defaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+
+ <!-- ======================================================= -->
+ <!-- Configure specific contexts -->
+ <!-- ======================================================= -->
+ <Ref id="contexts">
+ <Set name="handlers">
+ <Array type="org.mortbay.jetty.Handler">
+ <!-- ======================================================= -->
+ <!-- Configure a context directly - no XML parser required -->
+ <!-- ======================================================= -->
+ <Item>
+ <New id="aContext" class="org.mortbay.jetty.handler.ContextHandler">
+ <Set name="contextPath">/timeline</Set>
+ <Set name="resourceBase">./src/webapp/</Set>
+ <Set name="handler">
+ <New id="javadocServletHandler" class="org.mortbay.jetty.servlet.ServletHandler">
+ <Set name="servlets">
+ <Array type="org.mortbay.jetty.servlet.ServletHolder">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletHolder">
+ <Set name="name">Timeline</Set>
+ <Set name="className">org.mortbay.jetty.servlet.DefaultServlet</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+
+ <Set name="servletMappings">
+ <Array type="org.mortbay.jetty.servlet.ServletMapping">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletMapping">
+ <Set name="pathSpec">/</Set>
+ <Set name="servletName">Timeline</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+ </New>
+ </Item>
+
+ <Item>
+ <New id="aContext" class="org.mortbay.jetty.handler.ContextHandler">
+ <Set name="contextPath">/timeline/api</Set>
+ <Set name="resourceBase">./src/webapp/api/</Set>
+ <Set name="handler">
+ <New id="javadocServletHandler" class="org.mortbay.jetty.servlet.ServletHandler">
+ <Set name="servlets">
+ <Array type="org.mortbay.jetty.servlet.ServletHolder">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletHolder">
+ <Set name="name">Timeline</Set>
+ <Set name="className">org.mortbay.jetty.servlet.DefaultServlet</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+
+ <Set name="servletMappings">
+ <Array type="org.mortbay.jetty.servlet.ServletMapping">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletMapping">
+ <Set name="pathSpec">/</Set>
+ <Set name="servletName">Timeline</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+ </New>
+ </Item>
+
+ <Item>
+ <New id="aContext" class="org.mortbay.jetty.handler.ContextHandler">
+ <Set name="contextPath">/ajax/api</Set>
+ <Set name="resourceBase">./src/ajax/api/</Set>
+ <Set name="handler">
+ <New id="javadocServletHandler" class="org.mortbay.jetty.servlet.ServletHandler">
+ <Set name="servlets">
+ <Array type="org.mortbay.jetty.servlet.ServletHolder">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletHolder">
+ <Set name="name">Ajax</Set>
+ <Set name="className">org.mortbay.jetty.servlet.DefaultServlet</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+
+ <Set name="servletMappings">
+ <Array type="org.mortbay.jetty.servlet.ServletMapping">
+ <Item>
+ <New class="org.mortbay.jetty.servlet.ServletMapping">
+ <Set name="pathSpec">/</Set>
+ <Set name="servletName">Ajax</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
+ </Ref>
+
+ <!-- =========================================================== -->
+ <!-- extra options -->
+ <!-- =========================================================== -->
+ <Set name="stopAtShutdown">true</Set>
+ <!-- ensure/prevent Server: header being sent to browsers -->
+ <Set name="sendServerVersion">true</Set>
+
+</Configure>
+
+
+
+
+
+
+
+
+
diff --git a/run b/run
new file mode 100644
index 0000000..8153dc9
--- /dev/null
+++ b/run
@@ -0,0 +1,2 @@
+#!/bin/sh
+java -jar lib/start.jar jetty.xml
diff --git a/run.bat b/run.bat
new file mode 100644
index 0000000..5810f28
--- /dev/null
+++ b/run.bat
@@ -0,0 +1 @@
+java -jar lib/start.jar jetty.xml \ No newline at end of file
diff --git a/src/ajax/api/content/history.html b/src/ajax/api/content/history.html
new file mode 100644
index 0000000..a30fbd8
--- /dev/null
+++ b/src/ajax/api/content/history.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+ <title>Dummy Page for Keeping Track of History</title>
+</head>
+<body>
+</body>
+</html> \ No newline at end of file
diff --git a/src/ajax/api/images/bubble-arrow-point-down.png b/src/ajax/api/images/bubble-arrow-point-down.png
new file mode 100644
index 0000000..b87e87d
--- /dev/null
+++ b/src/ajax/api/images/bubble-arrow-point-down.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-arrow-point-left.png b/src/ajax/api/images/bubble-arrow-point-left.png
new file mode 100644
index 0000000..192d7f6
--- /dev/null
+++ b/src/ajax/api/images/bubble-arrow-point-left.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-arrow-point-right.png b/src/ajax/api/images/bubble-arrow-point-right.png
new file mode 100644
index 0000000..d09fdc7
--- /dev/null
+++ b/src/ajax/api/images/bubble-arrow-point-right.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-arrow-point-up.png b/src/ajax/api/images/bubble-arrow-point-up.png
new file mode 100644
index 0000000..7036080
--- /dev/null
+++ b/src/ajax/api/images/bubble-arrow-point-up.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-bottom-left.png b/src/ajax/api/images/bubble-bottom-left.png
new file mode 100644
index 0000000..117c29c
--- /dev/null
+++ b/src/ajax/api/images/bubble-bottom-left.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-bottom-right.png b/src/ajax/api/images/bubble-bottom-right.png
new file mode 100644
index 0000000..fa88d28
--- /dev/null
+++ b/src/ajax/api/images/bubble-bottom-right.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-bottom.png b/src/ajax/api/images/bubble-bottom.png
new file mode 100644
index 0000000..9958c3f
--- /dev/null
+++ b/src/ajax/api/images/bubble-bottom.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-left.png b/src/ajax/api/images/bubble-left.png
new file mode 100644
index 0000000..851d2d7
--- /dev/null
+++ b/src/ajax/api/images/bubble-left.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-right.png b/src/ajax/api/images/bubble-right.png
new file mode 100644
index 0000000..7c74abc
--- /dev/null
+++ b/src/ajax/api/images/bubble-right.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-top-left.png b/src/ajax/api/images/bubble-top-left.png
new file mode 100644
index 0000000..00c0773
--- /dev/null
+++ b/src/ajax/api/images/bubble-top-left.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-top-right.png b/src/ajax/api/images/bubble-top-right.png
new file mode 100644
index 0000000..e553363
--- /dev/null
+++ b/src/ajax/api/images/bubble-top-right.png
Binary files differ
diff --git a/src/ajax/api/images/bubble-top.png b/src/ajax/api/images/bubble-top.png
new file mode 100644
index 0000000..ddb6784
--- /dev/null
+++ b/src/ajax/api/images/bubble-top.png
Binary files differ
diff --git a/src/ajax/api/images/close-button.png b/src/ajax/api/images/close-button.png
new file mode 100644
index 0000000..15f31b3
--- /dev/null
+++ b/src/ajax/api/images/close-button.png
Binary files differ
diff --git a/src/ajax/api/images/copy.png b/src/ajax/api/images/copy.png
new file mode 100644
index 0000000..cf7cee4
--- /dev/null
+++ b/src/ajax/api/images/copy.png
Binary files differ
diff --git a/src/ajax/api/images/message-bottom-left.png b/src/ajax/api/images/message-bottom-left.png
new file mode 100644
index 0000000..43a9d61
--- /dev/null
+++ b/src/ajax/api/images/message-bottom-left.png
Binary files differ
diff --git a/src/ajax/api/images/message-bottom-right.png b/src/ajax/api/images/message-bottom-right.png
new file mode 100644
index 0000000..bfa4954
--- /dev/null
+++ b/src/ajax/api/images/message-bottom-right.png
Binary files differ
diff --git a/src/ajax/api/images/message-left.png b/src/ajax/api/images/message-left.png
new file mode 100644
index 0000000..f354376
--- /dev/null
+++ b/src/ajax/api/images/message-left.png
Binary files differ
diff --git a/src/ajax/api/images/message-right.png b/src/ajax/api/images/message-right.png
new file mode 100644
index 0000000..4702c28
--- /dev/null
+++ b/src/ajax/api/images/message-right.png
Binary files differ
diff --git a/src/ajax/api/images/message-top-left.png b/src/ajax/api/images/message-top-left.png
new file mode 100644
index 0000000..b19b0ea
--- /dev/null
+++ b/src/ajax/api/images/message-top-left.png
Binary files differ
diff --git a/src/ajax/api/images/message-top-right.png b/src/ajax/api/images/message-top-right.png
new file mode 100644
index 0000000..c092555
--- /dev/null
+++ b/src/ajax/api/images/message-top-right.png
Binary files differ
diff --git a/src/ajax/api/scripts/ajax.js b/src/ajax/api/scripts/ajax.js
new file mode 100644
index 0000000..7172609
--- /dev/null
+++ b/src/ajax/api/scripts/ajax.js
@@ -0,0 +1,45 @@
+/*==================================================
+ * General, miscellaneous SimileAjax stuff
+ *==================================================
+ */
+
+SimileAjax.ListenerQueue = function(wildcardHandlerName) {
+ this._listeners = [];
+ this._wildcardHandlerName = wildcardHandlerName;
+};
+
+SimileAjax.ListenerQueue.prototype.add = function(listener) {
+ this._listeners.push(listener);
+};
+
+SimileAjax.ListenerQueue.prototype.remove = function(listener) {
+ var listeners = this._listeners;
+ for (var i = 0; i < listeners.length; i++) {
+ if (listeners[i] == listener) {
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+SimileAjax.ListenerQueue.prototype.fire = function(handlerName, args) {
+ var listeners = [].concat(this._listeners);
+ for (var i = 0; i < listeners.length; i++) {
+ var listener = listeners[i];
+ if (handlerName in listener) {
+ try {
+ listener[handlerName].apply(listener, args);
+ } catch (e) {
+ SimileAjax.Debug.exception("Error firing event of name " + handlerName, e);
+ }
+ } else if (this._wildcardHandlerName != null &&
+ this._wildcardHandlerName in listener) {
+ try {
+ listener[this._wildcardHandlerName].apply(listener, [ handlerName ]);
+ } catch (e) {
+ SimileAjax.Debug.exception("Error firing event of name " + handlerName + " to wildcard handler", e);
+ }
+ }
+ }
+};
+
diff --git a/src/ajax/api/scripts/data-structure.js b/src/ajax/api/scripts/data-structure.js
new file mode 100644
index 0000000..e789cb4
--- /dev/null
+++ b/src/ajax/api/scripts/data-structure.js
@@ -0,0 +1,447 @@
+/**
+ * A basic set (in the mathematical sense) data structure
+ *
+ * @constructor
+ * @param {Array or SimileAjax.Set} [a] an initial collection
+ */
+SimileAjax.Set = function(a) {
+ this._hash = {};
+ this._count = 0;
+
+ if (a instanceof Array) {
+ for (var i = 0; i < a.length; i++) {
+ this.add(a[i]);
+ }
+ } else if (a instanceof SimileAjax.Set) {
+ this.addSet(a);
+ }
+}
+
+/**
+ * Adds the given object to this set, assuming there it does not already exist
+ *
+ * @param {Object} o the object to add
+ * @return {Boolean} true if the object was added, false if not
+ */
+SimileAjax.Set.prototype.add = function(o) {
+ if (!(o in this._hash)) {
+ this._hash[o] = true;
+ this._count++;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Adds each element in the given set to this set
+ *
+ * @param {SimileAjax.Set} set the set of elements to add
+ */
+SimileAjax.Set.prototype.addSet = function(set) {
+ for (var o in set._hash) {
+ this.add(o);
+ }
+}
+
+/**
+ * Removes the given element from this set
+ *
+ * @param {Object} o the object to remove
+ * @return {Boolean} true if the object was successfully removed,
+ * false otherwise
+ */
+SimileAjax.Set.prototype.remove = function(o) {
+ if (o in this._hash) {
+ delete this._hash[o];
+ this._count--;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Removes the elements in this set that correspond to the elements in the
+ * given set
+ *
+ * @param {SimileAjax.Set} set the set of elements to remove
+ */
+SimileAjax.Set.prototype.removeSet = function(set) {
+ for (var o in set._hash) {
+ this.remove(o);
+ }
+}
+
+/**
+ * Removes all elements in this set that are not present in the given set, i.e.
+ * modifies this set to the intersection of the two sets
+ *
+ * @param {SimileAjax.Set} set the set to intersect
+ */
+SimileAjax.Set.prototype.retainSet = function(set) {
+ for (var o in this._hash) {
+ if (!set.contains(o)) {
+ delete this._hash[o];
+ this._count--;
+ }
+ }
+}
+
+/**
+ * Returns whether or not the given element exists in this set
+ *
+ * @param {SimileAjax.Set} o the object to test for
+ * @return {Boolean} true if the object is present, false otherwise
+ */
+SimileAjax.Set.prototype.contains = function(o) {
+ return (o in this._hash);
+}
+
+/**
+ * Returns the number of elements in this set
+ *
+ * @return {Number} the number of elements in this set
+ */
+SimileAjax.Set.prototype.size = function() {
+ return this._count;
+}
+
+/**
+ * Returns the elements of this set as an array
+ *
+ * @return {Array} a new array containing the elements of this set
+ */
+SimileAjax.Set.prototype.toArray = function() {
+ var a = [];
+ for (var o in this._hash) {
+ a.push(o);
+ }
+ return a;
+}
+
+/**
+ * Iterates through the elements of this set, order unspecified, executing the
+ * given function on each element until the function returns true
+ *
+ * @param {Function} f a function of form f(element)
+ */
+SimileAjax.Set.prototype.visit = function(f) {
+ for (var o in this._hash) {
+ if (f(o) == true) {
+ break;
+ }
+ }
+}
+
+/**
+ * A sorted array data structure
+ *
+ * @constructor
+ */
+SimileAjax.SortedArray = function(compare, initialArray) {
+ this._a = (initialArray instanceof Array) ? initialArray : [];
+ this._compare = compare;
+};
+
+SimileAjax.SortedArray.prototype.add = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ if (index < this._a.length) {
+ this._a.splice(index, 0, elmt);
+ } else {
+ this._a.push(elmt);
+ }
+};
+
+SimileAjax.SortedArray.prototype.remove = function(elmt) {
+ var sa = this;
+ var index = this.find(function(elmt2) {
+ return sa._compare(elmt2, elmt);
+ });
+
+ while (index < this._a.length && this._compare(this._a[index], elmt) == 0) {
+ if (this._a[index] == elmt) {
+ this._a.splice(index, 1);
+ return true;
+ } else {
+ index++;
+ }
+ }
+ return false;
+};
+
+SimileAjax.SortedArray.prototype.removeAll = function() {
+ this._a = [];
+};
+
+SimileAjax.SortedArray.prototype.elementAt = function(index) {
+ return this._a[index];
+};
+
+SimileAjax.SortedArray.prototype.length = function() {
+ return this._a.length;
+};
+
+SimileAjax.SortedArray.prototype.find = function(compare) {
+ var a = 0;
+ var b = this._a.length;
+
+ while (a < b) {
+ var mid = Math.floor((a + b) / 2);
+ var c = compare(this._a[mid]);
+ if (mid == a) {
+ return c < 0 ? a+1 : a;
+ } else if (c < 0) {
+ a = mid;
+ } else {
+ b = mid;
+ }
+ }
+ return a;
+};
+
+SimileAjax.SortedArray.prototype.getFirst = function() {
+ return (this._a.length > 0) ? this._a[0] : null;
+};
+
+SimileAjax.SortedArray.prototype.getLast = function() {
+ return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
+};
+
+/*==================================================
+ * Event Index
+ *==================================================
+ */
+
+SimileAjax.EventIndex = function(unit) {
+ var eventIndex = this;
+
+ this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
+ this._events = new SimileAjax.SortedArray(
+ function(event1, event2) {
+ return eventIndex._unit.compare(event1.getStart(), event2.getStart());
+ }
+ );
+ this._idToEvent = {};
+ this._indexed = true;
+};
+
+SimileAjax.EventIndex.prototype.getUnit = function() {
+ return this._unit;
+};
+
+SimileAjax.EventIndex.prototype.getEvent = function(id) {
+ return this._idToEvent[id];
+};
+
+SimileAjax.EventIndex.prototype.add = function(evt) {
+ this._events.add(evt);
+ this._idToEvent[evt.getID()] = evt;
+ this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.removeAll = function() {
+ this._events.removeAll();
+ this._idToEvent = {};
+ this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.getCount = function() {
+ return this._events.length();
+};
+
+SimileAjax.EventIndex.prototype.getIterator = function(startDate, endDate) {
+ if (!this._indexed) {
+ this._index();
+ }
+ return new SimileAjax.EventIndex._Iterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getReverseIterator = function(startDate, endDate) {
+ if (!this._indexed) {
+ this._index();
+ }
+ return new SimileAjax.EventIndex._ReverseIterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getAllIterator = function() {
+ return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+
+SimileAjax.EventIndex.prototype.getEarliestDate = function() {
+ var evt = this._events.getFirst();
+ return (evt == null) ? null : evt.getStart();
+};
+
+SimileAjax.EventIndex.prototype.getLatestDate = function() {
+ var evt = this._events.getLast();
+ if (evt == null) {
+ return null;
+ }
+
+ if (!this._indexed) {
+ this._index();
+ }
+
+ var index = evt._earliestOverlapIndex;
+ var date = this._events.elementAt(index).getEnd();
+ for (var i = index + 1; i < this._events.length(); i++) {
+ date = this._unit.later(date, this._events.elementAt(i).getEnd());
+ }
+
+ return date;
+};
+
+SimileAjax.EventIndex.prototype._index = function() {
+ /*
+ * For each event, we want to find the earliest preceding
+ * event that overlaps with it, if any.
+ */
+
+ var l = this._events.length();
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ evt._earliestOverlapIndex = i;
+ }
+
+ var toIndex = 1;
+ for (var i = 0; i < l; i++) {
+ var evt = this._events.elementAt(i);
+ var end = evt.getEnd();
+
+ toIndex = Math.max(toIndex, i + 1);
+ while (toIndex < l) {
+ var evt2 = this._events.elementAt(toIndex);
+ var start2 = evt2.getStart();
+
+ if (this._unit.compare(start2, end) < 0) {
+ evt2._earliestOverlapIndex = i;
+ toIndex++;
+ } else {
+ break;
+ }
+ }
+ }
+ this._indexed = true;
+};
+
+SimileAjax.EventIndex._Iterator = function(events, startDate, endDate, unit) {
+ this._events = events;
+ this._startDate = startDate;
+ this._endDate = endDate;
+ this._unit = unit;
+
+ this._currentIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), startDate);
+ });
+ if (this._currentIndex - 1 >= 0) {
+ this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex;
+ }
+ this._currentIndex--;
+
+ this._maxIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), endDate);
+ });
+
+ this._hasNext = false;
+ this._next = null;
+ this._findNext();
+};
+
+SimileAjax.EventIndex._Iterator.prototype = {
+ hasNext: function() { return this._hasNext; },
+ next: function() {
+ if (this._hasNext) {
+ var next = this._next;
+ this._findNext();
+
+ return next;
+ } else {
+ return null;
+ }
+ },
+ _findNext: function() {
+ var unit = this._unit;
+ while ((++this._currentIndex) < this._maxIndex) {
+ var evt = this._events.elementAt(this._currentIndex);
+ if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+ unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+ this._next = evt;
+ this._hasNext = true;
+ return;
+ }
+ }
+ this._next = null;
+ this._hasNext = false;
+ }
+};
+
+SimileAjax.EventIndex._ReverseIterator = function(events, startDate, endDate, unit) {
+ this._events = events;
+ this._startDate = startDate;
+ this._endDate = endDate;
+ this._unit = unit;
+
+ this._minIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), startDate);
+ });
+ if (this._minIndex - 1 >= 0) {
+ this._minIndex = this._events.elementAt(this._minIndex - 1)._earliestOverlapIndex;
+ }
+
+ this._maxIndex = events.find(function(evt) {
+ return unit.compare(evt.getStart(), endDate);
+ });
+
+ this._currentIndex = this._maxIndex;
+ this._hasNext = false;
+ this._next = null;
+ this._findNext();
+};
+
+SimileAjax.EventIndex._ReverseIterator.prototype = {
+ hasNext: function() { return this._hasNext; },
+ next: function() {
+ if (this._hasNext) {
+ var next = this._next;
+ this._findNext();
+
+ return next;
+ } else {
+ return null;
+ }
+ },
+ _findNext: function() {
+ var unit = this._unit;
+ while ((--this._currentIndex) >= this._minIndex) {
+ var evt = this._events.elementAt(this._currentIndex);
+ if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+ unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+ this._next = evt;
+ this._hasNext = true;
+ return;
+ }
+ }
+ this._next = null;
+ this._hasNext = false;
+ }
+};
+
+SimileAjax.EventIndex._AllIterator = function(events) {
+ this._events = events;
+ this._index = 0;
+};
+
+SimileAjax.EventIndex._AllIterator.prototype = {
+ hasNext: function() {
+ return this._index < this._events.length();
+ },
+ next: function() {
+ return this._index < this._events.length() ?
+ this._events.elementAt(this._index++) : null;
+ }
+}; \ No newline at end of file
diff --git a/src/ajax/api/scripts/date-time.js b/src/ajax/api/scripts/date-time.js
new file mode 100644
index 0000000..d0498bf
--- /dev/null
+++ b/src/ajax/api/scripts/date-time.js
@@ -0,0 +1,452 @@
+/**
+ * @fileOverview A collection of date/time utility functions
+ * @name SimileAjax.DateTime
+ */
+
+SimileAjax.DateTime = new Object();
+
+SimileAjax.DateTime.MILLISECOND = 0;
+SimileAjax.DateTime.SECOND = 1;
+SimileAjax.DateTime.MINUTE = 2;
+SimileAjax.DateTime.HOUR = 3;
+SimileAjax.DateTime.DAY = 4;
+SimileAjax.DateTime.WEEK = 5;
+SimileAjax.DateTime.MONTH = 6;
+SimileAjax.DateTime.YEAR = 7;
+SimileAjax.DateTime.DECADE = 8;
+SimileAjax.DateTime.CENTURY = 9;
+SimileAjax.DateTime.MILLENNIUM = 10;
+
+SimileAjax.DateTime.EPOCH = -1;
+SimileAjax.DateTime.ERA = -2;
+
+/**
+ * An array of unit lengths, expressed in milliseconds, of various lengths of
+ * time. The array indices are predefined and stored as properties of the
+ * SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.
+ * @type Array
+ */
+SimileAjax.DateTime.gregorianUnitLengths = [];
+ (function() {
+ var d = SimileAjax.DateTime;
+ var a = d.gregorianUnitLengths;
+
+ a[d.MILLISECOND] = 1;
+ a[d.SECOND] = 1000;
+ a[d.MINUTE] = a[d.SECOND] * 60;
+ a[d.HOUR] = a[d.MINUTE] * 60;
+ a[d.DAY] = a[d.HOUR] * 24;
+ a[d.WEEK] = a[d.DAY] * 7;
+ a[d.MONTH] = a[d.DAY] * 31;
+ a[d.YEAR] = a[d.DAY] * 365;
+ a[d.DECADE] = a[d.YEAR] * 10;
+ a[d.CENTURY] = a[d.YEAR] * 100;
+ a[d.MILLENNIUM] = a[d.YEAR] * 1000;
+ })();
+
+SimileAjax.DateTime._dateRegexp = new RegExp(
+ "^(-?)([0-9]{4})(" + [
+ "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth
+ "(-?([0-9]{3}))", // -dayOfYear
+ "(-?W([0-9]{2})(-?([1-7]))?)" // -Wweek-dayOfWeek
+ ].join("|") + ")?$"
+);
+SimileAjax.DateTime._timezoneRegexp = new RegExp(
+ "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"
+);
+SimileAjax.DateTime._timeRegexp = new RegExp(
+ "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"
+);
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and sets the
+ * the date using information parsed from the string. Note that this method
+ * does not parse any time information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Date = function(dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var d = string.match(SimileAjax.DateTime._dateRegexp);
+ if(!d) {
+ throw new Error("Invalid date string: " + string);
+ }
+
+ var sign = (d[1] == "-") ? -1 : 1; // BC or AD
+ var year = sign * d[2];
+ var month = d[5];
+ var date = d[7];
+ var dayofyear = d[9];
+ var week = d[11];
+ var dayofweek = (d[13]) ? d[13] : 1;
+
+ dateObject.setUTCFullYear(year);
+ if (dayofyear) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(Number(dayofyear));
+ } else if (week) {
+ dateObject.setUTCMonth(0);
+ dateObject.setUTCDate(1);
+ var gd = dateObject.getUTCDay();
+ var day = (gd) ? gd : 7;
+ var offset = Number(dayofweek) + (7 * Number(week));
+
+ if (day <= 4) {
+ dateObject.setUTCDate(offset + 1 - day);
+ } else {
+ dateObject.setUTCDate(offset + 8 - day);
+ }
+ } else {
+ if (month) {
+ dateObject.setUTCDate(1);
+ dateObject.setUTCMonth(month - 1);
+ }
+ if (date) {
+ dateObject.setUTCDate(date);
+ }
+ }
+
+ return dateObject;
+};
+
+/**
+ * Takes a date object and a string containing an ISO 8601 time and sets the
+ * the time using information parsed from the string. Note that this method
+ * does not parse any date information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Time = function (dateObject, string) {
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var d = string.match(SimileAjax.DateTime._timeRegexp);
+ if(!d) {
+ SimileAjax.Debug.warn("Invalid time string: " + string);
+ return false;
+ }
+ var hours = d[1];
+ var mins = Number((d[3]) ? d[3] : 0);
+ var secs = (d[5]) ? d[5] : 0;
+ var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+ dateObject.setUTCHours(hours);
+ dateObject.setUTCMinutes(mins);
+ dateObject.setUTCSeconds(secs);
+ dateObject.setUTCMilliseconds(ms);
+
+ return dateObject;
+};
+
+/**
+ * The timezone offset in minutes in the user's browser.
+ * @type Number
+ */
+SimileAjax.DateTime.timezoneOffset = new Date().getTimezoneOffset();
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and time and
+ * sets the date object using information parsed from the string.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601 = function (dateObject, string){
+ /*
+ * This function has been adapted from dojo.date, v.0.3.0
+ * http://dojotoolkit.org/.
+ */
+
+ var offset = null;
+ var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
+
+ SimileAjax.DateTime.setIso8601Date(dateObject, comps[0]);
+ if (comps.length == 2) {
+ // first strip timezone info from the end
+ var d = comps[1].match(SimileAjax.DateTime._timezoneRegexp);
+ if (d) {
+ if (d[0] == 'Z') {
+ offset = 0;
+ } else {
+ offset = (Number(d[3]) * 60) + Number(d[5]);
+ offset *= ((d[2] == '-') ? 1 : -1);
+ }
+ comps[1] = comps[1].substr(0, comps[1].length - d[0].length);
+ }
+
+ SimileAjax.DateTime.setIso8601Time(dateObject, comps[1]);
+ }
+ if (offset == null) {
+ offset = dateObject.getTimezoneOffset(); // local time zone if no tz info
+ }
+ dateObject.setTime(dateObject.getTime() + offset * 60000);
+
+ return dateObject;
+};
+
+/**
+ * Takes a string containing an ISO 8601 date and returns a newly instantiated
+ * date object with the parsed date and time information from the string.
+ *
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} a new date object created from the string
+ */
+SimileAjax.DateTime.parseIso8601DateTime = function (string) {
+ try {
+ return SimileAjax.DateTime.setIso8601(new Date(0), string);
+ } catch (e) {
+ return null;
+ }
+};
+
+/**
+ * Takes a string containing a Gregorian date and time and returns a newly
+ * instantiated date object with the parsed date and time information from the
+ * string. If the param is actually an instance of Date instead of a string,
+ * simply returns the given date instead.
+ *
+ * @param {Object} o an object, to either return or parse as a string
+ * @return {Date} the date object
+ */
+SimileAjax.DateTime.parseGregorianDateTime = function(o) {
+ if (o == null) {
+ return null;
+ } else if (o instanceof Date) {
+ return o;
+ }
+
+ var s = o.toString();
+ if (s.length > 0 && s.length < 8) {
+ var space = s.indexOf(" ");
+ if (space > 0) {
+ var year = parseInt(s.substr(0, space));
+ var suffix = s.substr(space + 1);
+ if (suffix.toLowerCase() == "bc") {
+ year = 1 - year;
+ }
+ } else {
+ var year = parseInt(s);
+ }
+
+ var d = new Date(0);
+ d.setUTCFullYear(year);
+
+ return d;
+ }
+
+ try {
+ return new Date(Date.parse(s));
+ } catch (e) {
+ return null;
+ }
+};
+
+/**
+ * Rounds date objects down to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ * week, 0 corresponds to Sunday, 1 to Monday, etc.
+ */
+SimileAjax.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var timeShift = timeZone *
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+ var date2 = new Date(date.getTime() + timeShift);
+ var clearInDay = function(d) {
+ d.setUTCMilliseconds(0);
+ d.setUTCSeconds(0);
+ d.setUTCMinutes(0);
+ d.setUTCHours(0);
+ };
+ var clearInYear = function(d) {
+ clearInDay(d);
+ d.setUTCDate(1);
+ d.setUTCMonth(0);
+ };
+
+ switch(intervalUnit) {
+ case SimileAjax.DateTime.MILLISECOND:
+ var x = date2.getUTCMilliseconds();
+ date2.setUTCMilliseconds(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.SECOND:
+ date2.setUTCMilliseconds(0);
+
+ var x = date2.getUTCSeconds();
+ date2.setUTCSeconds(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.MINUTE:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+
+ var x = date2.getUTCMinutes();
+ date2.setTime(date2.getTime() -
+ (x % multiple) * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+ break;
+ case SimileAjax.DateTime.HOUR:
+ date2.setUTCMilliseconds(0);
+ date2.setUTCSeconds(0);
+ date2.setUTCMinutes(0);
+
+ var x = date2.getUTCHours();
+ date2.setUTCHours(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.DAY:
+ clearInDay(date2);
+ break;
+ case SimileAjax.DateTime.WEEK:
+ clearInDay(date2);
+ var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
+ date2.setTime(date2.getTime() -
+ d * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+ break;
+ case SimileAjax.DateTime.MONTH:
+ clearInDay(date2);
+ date2.setUTCDate(1);
+
+ var x = date2.getUTCMonth();
+ date2.setUTCMonth(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.YEAR:
+ clearInYear(date2);
+
+ var x = date2.getUTCFullYear();
+ date2.setUTCFullYear(x - (x % multiple));
+ break;
+ case SimileAjax.DateTime.DECADE:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
+ break;
+ case SimileAjax.DateTime.CENTURY:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
+ break;
+ case SimileAjax.DateTime.MILLENNIUM:
+ clearInYear(date2);
+ date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
+ break;
+ }
+
+ date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Rounds date objects up to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ * week, 0 corresponds to Sunday, 1 to Monday, etc.
+ * @see SimileAjax.DateTime.roundDownToInterval
+ */
+SimileAjax.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+ var originalTime = date.getTime();
+ SimileAjax.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
+ if (date.getTime() < originalTime) {
+ date.setTime(date.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
+ }
+};
+
+/**
+ * Increments a date object by a specified interval, taking into
+ * consideration the timezone.
+ *
+ * @param {Date} date the date object to increment
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ * interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone the timezone offset in hours
+ */
+SimileAjax.DateTime.incrementByInterval = function(date, intervalUnit, timeZone) {
+ timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone;
+
+ var timeShift = timeZone *
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+ var date2 = new Date(date.getTime() + timeShift);
+
+ switch(intervalUnit) {
+ case SimileAjax.DateTime.MILLISECOND:
+ date2.setTime(date2.getTime() + 1)
+ break;
+ case SimileAjax.DateTime.SECOND:
+ date2.setTime(date2.getTime() + 1000);
+ break;
+ case SimileAjax.DateTime.MINUTE:
+ date2.setTime(date2.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+ break;
+ case SimileAjax.DateTime.HOUR:
+ date2.setTime(date2.getTime() +
+ SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+ break;
+ case SimileAjax.DateTime.DAY:
+ date2.setUTCDate(date2.getUTCDate() + 1);
+ break;
+ case SimileAjax.DateTime.WEEK:
+ date2.setUTCDate(date2.getUTCDate() + 7);
+ break;
+ case SimileAjax.DateTime.MONTH:
+ date2.setUTCMonth(date2.getUTCMonth() + 1);
+ break;
+ case SimileAjax.DateTime.YEAR:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 1);
+ break;
+ case SimileAjax.DateTime.DECADE:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 10);
+ break;
+ case SimileAjax.DateTime.CENTURY:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 100);
+ break;
+ case SimileAjax.DateTime.MILLENNIUM:
+ date2.setUTCFullYear(date2.getUTCFullYear() + 1000);
+ break;
+ }
+
+ date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Returns a new date object with the given time offset removed.
+ *
+ * @param {Date} date the starting date
+ * @param {Number} timeZone a timezone specified in an hour offset to remove
+ * @return {Date} a new date object with the offset removed
+ */
+SimileAjax.DateTime.removeTimeZoneOffset = function(date, timeZone) {
+ return new Date(date.getTime() +
+ timeZone * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+
+/**
+ * Returns the timezone of the user's browser.
+ *
+ * @return {Number} the timezone in the user's locale in hours
+ */
+SimileAjax.DateTime.getTimezone = function() {
+ var d = new Date().getTimezoneOffset();
+ return d / -60;
+};
diff --git a/src/ajax/api/scripts/debug.js b/src/ajax/api/scripts/debug.js
new file mode 100644
index 0000000..3fca6a5
--- /dev/null
+++ b/src/ajax/api/scripts/debug.js
@@ -0,0 +1,94 @@
+/*==================================================
+ * Debug Utility Functions
+ *==================================================
+ */
+
+SimileAjax.Debug = {
+ silent: false
+};
+
+SimileAjax.Debug.log = function(msg) {
+ var f;
+ if ("console" in window && "log" in window.console) { // FireBug installed
+ f = function(msg2) {
+ console.log(msg2);
+ }
+ } else {
+ f = function(msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert(msg2);
+ }
+ }
+ }
+ SimileAjax.Debug.log = f;
+ f(msg);
+};
+
+SimileAjax.Debug.warn = function(msg) {
+ var f;
+ if ("console" in window && "warn" in window.console) { // FireBug installed
+ f = function(msg2) {
+ console.warn(msg2);
+ }
+ } else {
+ f = function(msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert(msg2);
+ }
+ }
+ }
+ SimileAjax.Debug.warn = f;
+ f(msg);
+};
+
+SimileAjax.Debug.exception = function(e, msg) {
+ var f, params = SimileAjax.parseURLParameters();
+ if (params.errors == "throw" || SimileAjax.params.errors == "throw") {
+ f = function(e2, msg2) {
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ } else if ("console" in window && "error" in window.console) { // FireBug installed
+ f = function(e2, msg2) {
+ if (msg2 != null) {
+ console.error(msg2 + " %o", e2);
+ } else {
+ console.error(e2);
+ }
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ } else {
+ f = function(e2, msg2) {
+ if (!SimileAjax.Debug.silent) {
+ alert("Caught exception: " + msg2 + "\n\nDetails: " + ("description" in e2 ? e2.description : e2));
+ }
+ throw(e2); // do not hide from browser's native debugging features
+ };
+ }
+ SimileAjax.Debug.exception = f;
+ f(e, msg);
+};
+
+SimileAjax.Debug.objectToString = function(o) {
+ return SimileAjax.Debug._objectToString(o, "");
+};
+
+SimileAjax.Debug._objectToString = function(o, indent) {
+ var indent2 = indent + " ";
+ if (typeof o == "object") {
+ var s = "{";
+ for (n in o) {
+ s += indent2 + n + ": " + SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+ }
+ s += indent + "}";
+ return s;
+ } else if (typeof o == "array") {
+ var s = "[";
+ for (var n = 0; n < o.length; n++) {
+ s += SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+ }
+ s += indent + "]";
+ return s;
+ } else {
+ return o;
+ }
+};
diff --git a/src/ajax/api/scripts/dom.js b/src/ajax/api/scripts/dom.js
new file mode 100644
index 0000000..c153a32
--- /dev/null
+++ b/src/ajax/api/scripts/dom.js
@@ -0,0 +1,344 @@
+/*==================================================
+ * DOM Utility Functions
+ *==================================================
+ */
+
+SimileAjax.DOM = new Object();
+
+SimileAjax.DOM.registerEventWithObject = function(elmt, eventName, obj, handlerName) {
+ SimileAjax.DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) {
+ return obj[handlerName].call(obj, elmt2, evt, target);
+ });
+};
+
+SimileAjax.DOM.registerEvent = function(elmt, eventName, handler) {
+ var handler2 = function(evt) {
+ evt = (evt) ? evt : ((event) ? event : null);
+ if (evt) {
+ var target = (evt.target) ?
+ evt.target : ((evt.srcElement) ? evt.srcElement : null);
+ if (target) {
+ target = (target.nodeType == 1 || target.nodeType == 9) ?
+ target : target.parentNode;
+ }
+
+ return handler(elmt, evt, target);
+ }
+ return true;
+ }
+
+ if (SimileAjax.Platform.browser.isIE) {
+ elmt.attachEvent("on" + eventName, handler2);
+ } else {
+ elmt.addEventListener(eventName, handler2, false);
+ }
+};
+
+SimileAjax.DOM.getPageCoordinates = function(elmt) {
+ var left = 0;
+ var top = 0;
+
+ if (elmt.nodeType != 1) {
+ elmt = elmt.parentNode;
+ }
+
+ var elmt2 = elmt;
+ while (elmt2 != null) {
+ left += elmt2.offsetLeft;
+ top += elmt2.offsetTop;
+ elmt2 = elmt2.offsetParent;
+ }
+
+ var body = document.body;
+ while (elmt != null && elmt != body) {
+ if ("scrollLeft" in elmt) {
+ left -= elmt.scrollLeft;
+ top -= elmt.scrollTop;
+ }
+ elmt = elmt.parentNode;
+ }
+
+ return { left: left, top: top };
+};
+
+SimileAjax.DOM.getSize = function(elmt) {
+ var w = this.getStyle(elmt,"width");
+ var h = this.getStyle(elmt,"height");
+ if (w.indexOf("px") > -1) w = w.replace("px","");
+ if (h.indexOf("px") > -1) h = h.replace("px","");
+ return {
+ w: w,
+ h: h
+ }
+}
+
+SimileAjax.DOM.getStyle = function(elmt, styleProp) {
+ if (elmt.currentStyle) { // IE
+ var style = elmt.currentStyle[styleProp];
+ } else if (window.getComputedStyle) { // standard DOM
+ var style = document.defaultView.getComputedStyle(elmt, null).getPropertyValue(styleProp);
+ } else {
+ var style = "";
+ }
+ return style;
+}
+
+SimileAjax.DOM.getEventRelativeCoordinates = function(evt, elmt) {
+ if (SimileAjax.Platform.browser.isIE) {
+ if (evt.type == "mousewheel") {
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+ return {
+ x: evt.clientX - coords.left,
+ y: evt.clientY - coords.top
+ };
+ } else {
+ return {
+ x: evt.offsetX,
+ y: evt.offsetY
+ };
+ }
+ } else {
+ var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+
+ if ((evt.type == "DOMMouseScroll") &&
+ SimileAjax.Platform.browser.isFirefox &&
+ (SimileAjax.Platform.browser.majorVersion == 2)) {
+ // Due to: https://bugzilla.mozilla.org/show_bug.cgi?id=352179
+
+ return {
+ x: evt.screenX - coords.left,
+ y: evt.screenY - coords.top
+ };
+ } else {
+ return {
+ x: evt.pageX - coords.left,
+ y: evt.pageY - coords.top
+ };
+ }
+ }
+};
+
+SimileAjax.DOM.getEventPageCoordinates = function(evt) {
+ if (SimileAjax.Platform.browser.isIE) {
+ return {
+ x: evt.clientX + document.body.scrollLeft,
+ y: evt.clientY + document.body.scrollTop
+ };
+ } else {
+ return {
+ x: evt.pageX,
+ y: evt.pageY
+ };
+ }
+};
+
+SimileAjax.DOM.hittest = function(x, y, except) {
+ return SimileAjax.DOM._hittest(document.body, x, y, except);
+};
+
+SimileAjax.DOM._hittest = function(elmt, x, y, except) {
+ var childNodes = elmt.childNodes;
+ outer: for (var i = 0; i < childNodes.length; i++) {
+ var childNode = childNodes[i];
+ for (var j = 0; j < except.length; j++) {
+ if (childNode == except[j]) {
+ continue outer;
+ }
+ }
+
+ if (childNode.offsetWidth == 0 && childNode.offsetHeight == 0) {
+ /*
+ * Sometimes SPAN elements have zero width and height but
+ * they have children like DIVs that cover non-zero areas.
+ */
+ var hitNode = SimileAjax.DOM._hittest(childNode, x, y, except);
+ if (hitNode != childNode) {
+ return hitNode;
+ }
+ } else {
+ var top = 0;
+ var left = 0;
+
+ var node = childNode;
+ while (node) {
+ top += node.offsetTop;
+ left += node.offsetLeft;
+ node = node.offsetParent;
+ }
+
+ if (left <= x && top <= y && (x - left) < childNode.offsetWidth && (y - top) < childNode.offsetHeight) {
+ return SimileAjax.DOM._hittest(childNode, x, y, except);
+ } else if (childNode.nodeType == 1 && childNode.tagName == "TR") {
+ /*
+ * Table row might have cells that span several rows.
+ */
+ var childNode2 = SimileAjax.DOM._hittest(childNode, x, y, except);
+ if (childNode2 != childNode) {
+ return childNode2;
+ }
+ }
+ }
+ }
+ return elmt;
+};
+
+SimileAjax.DOM.cancelEvent = function(evt) {
+ evt.returnValue = false;
+ evt.cancelBubble = true;
+ if ("preventDefault" in evt) {
+ evt.preventDefault();
+ }
+};
+
+SimileAjax.DOM.appendClassName = function(elmt, className) {
+ var classes = elmt.className.split(" ");
+ for (var i = 0; i < classes.length; i++) {
+ if (classes[i] == className) {
+ return;
+ }
+ }
+ classes.push(className);
+ elmt.className = classes.join(" ");
+};
+
+SimileAjax.DOM.createInputElement = function(type) {
+ var div = document.createElement("div");
+ div.innerHTML = "<input type='" + type + "' />";
+
+ return div.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromTemplate = function(template) {
+ var result = {};
+ result.elmt = SimileAjax.DOM._createDOMFromTemplate(template, result, null);
+
+ return result;
+};
+
+SimileAjax.DOM._createDOMFromTemplate = function(templateNode, result, parentElmt) {
+ if (templateNode == null) {
+ /*
+ var node = doc.createTextNode("--null--");
+ if (parentElmt != null) {
+ parentElmt.appendChild(node);
+ }
+ return node;
+ */
+ return null;
+ } else if (typeof templateNode != "object") {
+ var node = document.createTextNode(templateNode);
+ if (parentElmt != null) {
+ parentElmt.appendChild(node);
+ }
+ return node;
+ } else {
+ var elmt = null;
+ if ("tag" in templateNode) {
+ var tag = templateNode.tag;
+ if (parentElmt != null) {
+ if (tag == "tr") {
+ elmt = parentElmt.insertRow(parentElmt.rows.length);
+ } else if (tag == "td") {
+ elmt = parentElmt.insertCell(parentElmt.cells.length);
+ }
+ }
+ if (elmt == null) {
+ elmt = tag == "input" ?
+ SimileAjax.DOM.createInputElement(templateNode.type) :
+ document.createElement(tag);
+
+ if (parentElmt != null) {
+ parentElmt.appendChild(elmt);
+ }
+ }
+ } else {
+ elmt = templateNode.elmt;
+ if (parentElmt != null) {
+ parentElmt.appendChild(elmt);
+ }
+ }
+
+ for (var attribute in templateNode) {
+ var value = templateNode[attribute];
+
+ if (attribute == "field") {
+ result[value] = elmt;
+
+ } else if (attribute == "className") {
+ elmt.className = value;
+ } else if (attribute == "id") {
+ elmt.id = value;
+ } else if (attribute == "title") {
+ elmt.title = value;
+ } else if (attribute == "type" && elmt.tagName == "input") {
+ // do nothing
+ } else if (attribute == "style") {
+ for (n in value) {
+ var v = value[n];
+ if (n == "float") {
+ n = SimileAjax.Platform.browser.isIE ? "styleFloat" : "cssFloat";
+ }
+ elmt.style[n] = v;
+ }
+ } else if (attribute == "children") {
+ for (var i = 0; i < value.length; i++) {
+ SimileAjax.DOM._createDOMFromTemplate(value[i], result, elmt);
+ }
+ } else if (attribute != "tag" && attribute != "elmt") {
+ elmt.setAttribute(attribute, value);
+ }
+ }
+ return elmt;
+ }
+}
+
+SimileAjax.DOM._cachedParent = null;
+SimileAjax.DOM.createElementFromString = function(s) {
+ if (SimileAjax.DOM._cachedParent == null) {
+ SimileAjax.DOM._cachedParent = document.createElement("div");
+ }
+ SimileAjax.DOM._cachedParent.innerHTML = s;
+ return SimileAjax.DOM._cachedParent.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromString = function(root, s, fieldElmts) {
+ var elmt = typeof root == "string" ? document.createElement(root) : root;
+ elmt.innerHTML = s;
+
+ var dom = { elmt: elmt };
+ SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts != null ? fieldElmts : {} );
+
+ return dom;
+};
+
+SimileAjax.DOM._processDOMConstructedFromString = function(dom, elmt, fieldElmts) {
+ var id = elmt.id;
+ if (id != null && id.length > 0) {
+ elmt.removeAttribute("id");
+ if (id in fieldElmts) {
+ var parentElmt = elmt.parentNode;
+ parentElmt.insertBefore(fieldElmts[id], elmt);
+ parentElmt.removeChild(elmt);
+
+ dom[id] = fieldElmts[id];
+ return;
+ } else {
+ dom[id] = elmt;
+ }
+ }
+
+ if (elmt.hasChildNodes()) {
+ SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts);
+ }
+};
+
+SimileAjax.DOM._processDOMChildrenConstructedFromString = function(dom, elmt, fieldElmts) {
+ var node = elmt.firstChild;
+ while (node != null) {
+ var node2 = node.nextSibling;
+ if (node.nodeType == 1) {
+ SimileAjax.DOM._processDOMConstructedFromString(dom, node, fieldElmts);
+ }
+ node = node2;
+ }
+};
diff --git a/src/ajax/api/scripts/graphics.js b/src/ajax/api/scripts/graphics.js
new file mode 100644
index 0000000..5a8499a
--- /dev/null
+++ b/src/ajax/api/scripts/graphics.js
@@ -0,0 +1,653 @@
+/**
+ * @fileOverview Graphics utility functions and constants
+ * @name SimileAjax.Graphics
+ */
+
+SimileAjax.Graphics = new Object();
+
+/**
+ * A boolean value indicating whether PNG translucency is supported on the
+ * user's browser or not.
+ *
+ * @type Boolean
+ */
+SimileAjax.Graphics.pngIsTranslucent = (!SimileAjax.Platform.browser.isIE) || (SimileAjax.Platform.browser.majorVersion > 6);
+if (!SimileAjax.Graphics.pngIsTranslucent) {
+ SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
+}
+
+/*==================================================
+ * Opacity, translucency
+ *==================================================
+ */
+SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
+ var elmt = document.createElement("img");
+ elmt.setAttribute("src", url);
+ if (verticalAlign != null) {
+ elmt.style.verticalAlign = verticalAlign;
+ }
+ return elmt;
+};
+SimileAjax.Graphics._createTranslucentImage2 = function(url, verticalAlign) {
+ var elmt = document.createElement("img");
+ elmt.style.width = "1px"; // just so that IE will calculate the size property
+ elmt.style.height = "1px";
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
+ elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
+ return elmt;
+};
+
+/**
+ * Creates a DOM element for an <code>img</code> tag using the URL given. This
+ * is a convenience method that automatically includes the necessary CSS to
+ * allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {Element} a DOM element containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImage = SimileAjax.Graphics.pngIsTranslucent ?
+ SimileAjax.Graphics._createTranslucentImage1 :
+ SimileAjax.Graphics._createTranslucentImage2;
+
+SimileAjax.Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) {
+ return "<img src=\"" + url + "\"" +
+ (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") +
+ " />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) {
+ var style =
+ "width: 1px; height: 1px; " +
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" +
+ (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : "");
+
+ return "<img src='" + url + "' style=\"" + style + "\" />";
+};
+
+/**
+ * Creates an HTML string for an <code>img</code> tag using the URL given.
+ * This is a convenience method that automatically includes the necessary CSS
+ * to allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {String} a string containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImageHTML = SimileAjax.Graphics.pngIsTranslucent ?
+ SimileAjax.Graphics._createTranslucentImageHTML1 :
+ SimileAjax.Graphics._createTranslucentImageHTML2;
+
+/**
+ * Sets the opacity on the given DOM element.
+ *
+ * @param {Element} elmt the DOM element to set the opacity on
+ * @param {Number} opacity an integer from 0 to 100 specifying the opacity
+ */
+SimileAjax.Graphics.setOpacity = function(elmt, opacity) {
+ if (SimileAjax.Platform.browser.isIE) {
+ elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
+ } else {
+ var o = (opacity / 100).toString();
+ elmt.style.opacity = o;
+ elmt.style.MozOpacity = o;
+ }
+};
+
+/*==================================================
+ * Bubble
+ *==================================================
+ */
+
+SimileAjax.Graphics.bubbleConfig = {
+ containerCSSClass: "simileAjax-bubble-container",
+ innerContainerCSSClass: "simileAjax-bubble-innerContainer",
+ contentContainerCSSClass: "simileAjax-bubble-contentContainer",
+
+ borderGraphicSize: 50,
+ borderGraphicCSSClassPrefix: "simileAjax-bubble-border-",
+
+ arrowGraphicTargetOffset: 33, // from tip of arrow to the side of the graphic that touches the content of the bubble
+ arrowGraphicLength: 100, // dimension of arrow graphic along the direction that the arrow points
+ arrowGraphicWidth: 49, // dimension of arrow graphic perpendicular to the direction that the arrow points
+ arrowGraphicCSSClassPrefix: "simileAjax-bubble-arrow-",
+
+ closeGraphicCSSClass: "simileAjax-bubble-close",
+
+ extraPadding: 20
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given content in a div,
+ * page coordinates and a suggested width. The bubble will point to the
+ * location on the page as described by pageX and pageY. All measurements
+ * should be given in pixels.
+ *
+ * @param {Element} the content div
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth a suggested width of the content
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ * that describes the orientation of the arrow on the bubble
+ * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall.
+ * Default of 0 or null means no maximum
+ */
+SimileAjax.Graphics.createBubbleForContentAndPoint = function(
+ div, pageX, pageY, contentWidth, orientation, maxHeight) {
+ if (typeof contentWidth != "number") {
+ contentWidth = 300;
+ }
+ if (typeof maxHeight != "number") {
+ maxHeight = 0;
+ }
+
+ div.style.position = "absolute";
+ div.style.left = "-5000px";
+ div.style.top = "0px";
+ div.style.width = contentWidth + "px";
+ document.body.appendChild(div);
+
+ window.setTimeout(function() {
+ var width = div.scrollWidth + 10;
+ var height = div.scrollHeight + 10;
+ var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
+ if (maxHeight > 0 && height > maxHeight) {
+ height = maxHeight;
+ scrollDivW = width - 25;
+ }
+
+ var bubble = SimileAjax.Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation);
+
+ document.body.removeChild(div);
+ div.style.position = "static";
+ div.style.left = "";
+ div.style.top = "";
+
+ // create a scroll div if needed
+ if (scrollDivW > 0) {
+ var scrollDiv = document.createElement("div");
+ div.style.width = "";
+ scrollDiv.style.width = scrollDivW + "px";
+ scrollDiv.appendChild(div);
+ bubble.content.appendChild(scrollDiv);
+ } else {
+ div.style.width = width + "px";
+ bubble.content.appendChild(div);
+ }
+ }, 200);
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given page coordinates and
+ * content dimensions. The bubble will point to the location on the page
+ * as described by pageX and pageY. All measurements should be given in
+ * pixels.
+ *
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth the width of the content box in the bubble
+ * @param {Number} contentHeight the height of the content box in the bubble
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ * that describes the orientation of the arrow on the bubble
+ * @return {Element} a DOM element for the newly created bubble
+ */
+SimileAjax.Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) {
+ contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs
+ contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings
+
+ var bubbleConfig = SimileAjax.Graphics.bubbleConfig;
+ var pngTransparencyClassSuffix =
+ SimileAjax.Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent";
+
+ var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
+ var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
+
+ var generatePngSensitiveClass = function(className) {
+ return className + " " + className + "-" + pngTransparencyClassSuffix;
+ };
+
+ /*
+ * Render container divs
+ */
+ var div = document.createElement("div");
+ div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass);
+ div.style.width = contentWidth + "px";
+ div.style.height = contentHeight + "px";
+
+ var divInnerContainer = document.createElement("div");
+ divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
+ div.appendChild(divInnerContainer);
+
+ /*
+ * Create layer for bubble
+ */
+ var close = function() {
+ if (!bubble._closed) {
+ document.body.removeChild(bubble._div);
+ bubble._doc = null;
+ bubble._div = null;
+ bubble._content = null;
+ bubble._closed = true;
+ }
+ }
+ var bubble = { _closed: false };
+ var layer = SimileAjax.WindowManager.pushLayer(close, true, div);
+ bubble._div = div;
+ bubble.close = function() { SimileAjax.WindowManager.popLayer(layer); }
+
+ /*
+ * Render border graphics
+ */
+ var createBorder = function(classNameSuffix) {
+ var divBorderGraphic = document.createElement("div");
+ divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix);
+ divInnerContainer.appendChild(divBorderGraphic);
+ };
+ createBorder("top-left");
+ createBorder("top-right");
+ createBorder("bottom-left");
+ createBorder("bottom-right");
+ createBorder("left");
+ createBorder("right");
+ createBorder("top");
+ createBorder("bottom");
+
+ /*
+ * Render content
+ */
+ var divContentContainer = document.createElement("div");
+ divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
+ divInnerContainer.appendChild(divContentContainer);
+ bubble.content = divContentContainer;
+
+ /*
+ * Render close button
+ */
+ var divClose = document.createElement("div");
+ divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
+ divInnerContainer.appendChild(divClose);
+ SimileAjax.WindowManager.registerEventWithObject(divClose, "click", bubble, "close");
+
+ (function() {
+ var dims = SimileAjax.Graphics.getWindowDimensions();
+ var docWidth = dims.w;
+ var docHeight = dims.h;
+
+ var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
+
+ var createArrow = function(classNameSuffix) {
+ var divArrowGraphic = document.createElement("div");
+ divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix);
+ divInnerContainer.appendChild(divArrowGraphic);
+ return divArrowGraphic;
+ };
+
+ if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
+ pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
+
+ /*
+ * Bubble can be positioned above or below the target point.
+ */
+
+ var left = pageX - Math.round(contentWidth / 2);
+ left = pageX < (docWidth / 2) ?
+ Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+ Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
+
+ if ((orientation && orientation == "top") ||
+ (!orientation &&
+ (pageY
+ - bubbleConfig.arrowGraphicTargetOffset
+ - contentHeight
+ - bubbleConfig.borderGraphicSize
+ - bubbleConfig.extraPadding > 0))) {
+
+ /*
+ * Position bubble above the target point.
+ */
+
+ var divArrow = createArrow("down");
+ divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+ div.style.left = left + "px";
+ div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px";
+
+ return;
+ } else if ((orientation && orientation == "bottom") ||
+ (!orientation &&
+ (pageY
+ + bubbleConfig.arrowGraphicTargetOffset
+ + contentHeight
+ + bubbleConfig.borderGraphicSize
+ + bubbleConfig.extraPadding < docHeight))) {
+
+ /*
+ * Position bubble below the target point.
+ */
+
+ var divArrow = createArrow("up");
+ divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+ div.style.left = left + "px";
+ div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px";
+
+ return;
+ }
+ }
+
+ var top = pageY - Math.round(contentHeight / 2);
+ top = pageY < (docHeight / 2) ?
+ Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+ Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
+
+ if ((orientation && orientation == "left") ||
+ (!orientation &&
+ (pageX
+ - bubbleConfig.arrowGraphicTargetOffset
+ - contentWidth
+ - bubbleConfig.borderGraphicSize
+ - bubbleConfig.extraPadding > 0))) {
+
+ /*
+ * Position bubble left of the target point.
+ */
+
+ var divArrow = createArrow("right");
+ divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+ div.style.top = top + "px";
+ div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px";
+ } else {
+
+ /*
+ * Position bubble right of the target point, as the last resort.
+ */
+
+ var divArrow = createArrow("left");
+ divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+ div.style.top = top + "px";
+ div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px";
+ }
+ })();
+
+ document.body.appendChild(div);
+
+ return bubble;
+};
+
+SimileAjax.Graphics.getWindowDimensions = function() {
+ if (typeof window.innerHeight == 'number') {
+ return { w:window.innerWidth, h:window.innerHeight }; // Non-IE
+ } else if (document.documentElement && document.documentElement.clientHeight) {
+ return { // IE6+, in "standards compliant mode"
+ w:document.documentElement.clientWidth,
+ h:document.documentElement.clientHeight
+ };
+ } else if (document.body && document.body.clientHeight) {
+ return { // IE 4 compatible
+ w:document.body.clientWidth,
+ h:document.body.clientHeight
+ };
+ }
+};
+
+
+/**
+ * Creates a floating, rounded message bubble in the center of the window for
+ * displaying modal information, e.g. "Loading..."
+ *
+ * @param {Document} doc the root document for the page to render on
+ * @param {Object} an object with two properties, contentDiv and containerDiv,
+ * consisting of the newly created DOM elements
+ */
+SimileAjax.Graphics.createMessageBubble = function(doc) {
+ var containerDiv = doc.createElement("div");
+ if (SimileAjax.Graphics.pngIsTranslucent) {
+ var topDiv = doc.createElement("div");
+ topDiv.style.height = "33px";
+ topDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-left.png) top left no-repeat";
+ topDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(topDiv);
+
+ var topRightDiv = doc.createElement("div");
+ topRightDiv.style.height = "33px";
+ topRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-right.png) top right no-repeat";
+ topDiv.appendChild(topRightDiv);
+
+ var middleDiv = doc.createElement("div");
+ middleDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-left.png) top left repeat-y";
+ middleDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(middleDiv);
+
+ var middleRightDiv = doc.createElement("div");
+ middleRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-right.png) top right repeat-y";
+ middleRightDiv.style.paddingRight = "44px";
+ middleDiv.appendChild(middleRightDiv);
+
+ var contentDiv = doc.createElement("div");
+ middleRightDiv.appendChild(contentDiv);
+
+ var bottomDiv = doc.createElement("div");
+ bottomDiv.style.height = "55px";
+ bottomDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
+ bottomDiv.style.paddingLeft = "44px";
+ containerDiv.appendChild(bottomDiv);
+
+ var bottomRightDiv = doc.createElement("div");
+ bottomRightDiv.style.height = "55px";
+ bottomRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
+ bottomDiv.appendChild(bottomRightDiv);
+ } else {
+ containerDiv.style.border = "2px solid #7777AA";
+ containerDiv.style.padding = "20px";
+ containerDiv.style.background = "white";
+ SimileAjax.Graphics.setOpacity(containerDiv, 90);
+
+ var contentDiv = doc.createElement("div");
+ containerDiv.appendChild(contentDiv);
+ }
+
+ return {
+ containerDiv: containerDiv,
+ contentDiv: contentDiv
+ };
+};
+
+/*==================================================
+ * Animation
+ *==================================================
+ */
+
+/**
+ * Creates an animation for a function, and an interval of values. The word
+ * "animation" here is used in the sense of repeatedly calling a function with
+ * a current value from within an interval, and a delta value.
+ *
+ * @param {Function} f a function to be called every 50 milliseconds throughout
+ * the animation duration, of the form f(current, delta), where current is
+ * the current value within the range and delta is the current change.
+ * @param {Number} from a starting value
+ * @param {Number} to an ending value
+ * @param {Number} duration the duration of the animation in milliseconds
+ * @param {Function} [cont] an optional function that is called at the end of
+ * the animation, i.e. a continuation.
+ * @return {SimileAjax.Graphics._Animation} a new animation object
+ */
+SimileAjax.Graphics.createAnimation = function(f, from, to, duration, cont) {
+ return new SimileAjax.Graphics._Animation(f, from, to, duration, cont);
+};
+
+SimileAjax.Graphics._Animation = function(f, from, to, duration, cont) {
+ this.f = f;
+ this.cont = (typeof cont == "function") ? cont : function() {};
+
+ this.from = from;
+ this.to = to;
+ this.current = from;
+
+ this.duration = duration;
+ this.start = new Date().getTime();
+ this.timePassed = 0;
+};
+
+/**
+ * Runs this animation.
+ */
+SimileAjax.Graphics._Animation.prototype.run = function() {
+ var a = this;
+ window.setTimeout(function() { a.step(); }, 50);
+};
+
+/**
+ * Increments this animation by one step, and then continues the animation with
+ * <code>run()</code>.
+ */
+SimileAjax.Graphics._Animation.prototype.step = function() {
+ this.timePassed += 50;
+
+ var timePassedFraction = this.timePassed / this.duration;
+ var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
+ var current = parameterFraction * (this.to - this.from) + this.from;
+
+ try {
+ this.f(current, current - this.current);
+ } catch (e) {
+ }
+ this.current = current;
+
+ if (this.timePassed < this.duration) {
+ this.run();
+ } else {
+ this.f(this.to, 0);
+ this["cont"]();
+ }
+};
+
+/*==================================================
+ * CopyPasteButton
+ *
+ * Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
+ *==================================================
+ */
+
+/**
+ * Creates a button and textarea for displaying structured data and copying it
+ * to the clipboard. The data is dynamically generated by the given
+ * createDataFunction parameter.
+ *
+ * @param {String} image an image URL to use as the background for the
+ * generated box
+ * @param {Number} width the width in pixels of the generated box
+ * @param {Number} height the height in pixels of the generated box
+ * @param {Function} createDataFunction a function that is called with no
+ * arguments to generate the structured data
+ * @return a new DOM element
+ */
+SimileAjax.Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) {
+ var div = document.createElement("div");
+ div.style.position = "relative";
+ div.style.display = "inline";
+ div.style.width = width + "px";
+ div.style.height = height + "px";
+ div.style.overflow = "hidden";
+ div.style.margin = "2px";
+
+ if (SimileAjax.Graphics.pngIsTranslucent) {
+ div.style.background = "url(" + image + ") no-repeat";
+ } else {
+ div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')";
+ }
+
+ var style;
+ if (SimileAjax.Platform.browser.isIE) {
+ style = "filter:alpha(opacity=0)";
+ } else {
+ style = "opacity: 0";
+ }
+ div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />";
+
+ var textarea = div.firstChild;
+ textarea.style.width = width + "px";
+ textarea.style.height = height + "px";
+ textarea.onmousedown = function(evt) {
+ evt = (evt) ? evt : ((event) ? event : null);
+ if (evt.button == 2) {
+ textarea.value = createDataFunction();
+ textarea.select();
+ }
+ };
+
+ return div;
+};
+
+/*==================================================
+ * getWidthHeight
+ *==================================================
+ */
+SimileAjax.Graphics.getWidthHeight = function(el) {
+ // RETURNS hash {width: w, height: h} in pixels
+
+ var w, h;
+ // offsetWidth rounds on FF, so doesn't work for us.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617
+ if (el.getBoundingClientRect == null) {
+ // use offsetWidth
+ w = el.offsetWidth;
+ h = el.offsetHeight;
+ } else {
+ // use getBoundingClientRect
+ var rect = el.getBoundingClientRect();
+ w = Math.ceil(rect.right - rect.left);
+ h = Math.ceil(rect.bottom - rect.top);
+ }
+ return {
+ width: w,
+ height: h
+ };
+};
+
+
+/*==================================================
+ * FontRenderingContext
+ *==================================================
+ */
+SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
+ return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
+};
+
+SimileAjax.Graphics._FontRenderingContext = function(elmt, width) {
+ this._elmt = elmt;
+ this._elmt.style.visibility = "hidden";
+ if (typeof width == "string") {
+ this._elmt.style.width = width;
+ } else if (typeof width == "number") {
+ this._elmt.style.width = width + "px";
+ }
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose = function() {
+ this._elmt = null;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.update = function() {
+ this._elmt.innerHTML = "A";
+ this._lineHeight = this._elmt.offsetHeight;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize = function(text, className) {
+ // className arg is optional
+ var el = this._elmt;
+ el.innerHTML = text;
+ el.className = className === undefined ? '' : className;
+ var wh = SimileAjax.Graphics.getWidthHeight(el);
+ el.className = ''; // reset for the next guy
+
+ return wh;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight = function() {
+ return this._lineHeight;
+};
+
diff --git a/src/ajax/api/scripts/history.js b/src/ajax/api/scripts/history.js
new file mode 100644
index 0000000..678b1ec
--- /dev/null
+++ b/src/ajax/api/scripts/history.js
@@ -0,0 +1,220 @@
+/*======================================================================
+ * History
+ *
+ * This is a singleton that keeps track of undoable user actions and
+ * performs undos and redos in response to the browser's Back and
+ * Forward buttons.
+ *
+ * Call addAction(action) to register an undoable user action. action
+ * must have 4 fields:
+ *
+ * perform: an argument-less function that carries out the action
+ * undo: an argument-less function that undos the action
+ * label: a short, user-friendly string describing the action
+ * uiLayer: the UI layer on which the action takes place
+ *
+ * By default, the history keeps track of upto 10 actions. You can
+ * configure this behavior by setting
+ * SimileAjax.History.maxHistoryLength
+ * to a different number.
+ *
+ * An iframe is inserted into the document's body element to track
+ * onload events.
+ *======================================================================
+ */
+
+SimileAjax.History = {
+ maxHistoryLength: 10,
+ historyFile: "__history__.html",
+ enabled: true,
+
+ _initialized: false,
+ _listeners: new SimileAjax.ListenerQueue(),
+
+ _actions: [],
+ _baseIndex: 0,
+ _currentIndex: 0,
+
+ _plainDocumentTitle: document.title
+};
+
+SimileAjax.History.formatHistoryEntryTitle = function(actionLabel) {
+ return SimileAjax.History._plainDocumentTitle + " {" + actionLabel + "}";
+};
+
+SimileAjax.History.initialize = function() {
+ if (SimileAjax.History._initialized) {
+ return;
+ }
+
+ if (SimileAjax.History.enabled) {
+ var iframe = document.createElement("iframe");
+ iframe.id = "simile-ajax-history";
+ iframe.style.position = "absolute";
+ iframe.style.width = "10px";
+ iframe.style.height = "10px";
+ iframe.style.top = "0px";
+ iframe.style.left = "0px";
+ iframe.style.visibility = "hidden";
+ iframe.src = SimileAjax.History.historyFile + "?0";
+
+ document.body.appendChild(iframe);
+ SimileAjax.DOM.registerEvent(iframe, "load", SimileAjax.History._handleIFrameOnLoad);
+
+ SimileAjax.History._iframe = iframe;
+ }
+ SimileAjax.History._initialized = true;
+};
+
+SimileAjax.History.addListener = function(listener) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.add(listener);
+};
+
+SimileAjax.History.removeListener = function(listener) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.remove(listener);
+};
+
+SimileAjax.History.addAction = function(action) {
+ SimileAjax.History.initialize();
+
+ SimileAjax.History._listeners.fire("onBeforePerform", [ action ]);
+ window.setTimeout(function() {
+ try {
+ action.perform();
+ SimileAjax.History._listeners.fire("onAfterPerform", [ action ]);
+
+ if (SimileAjax.History.enabled) {
+ SimileAjax.History._actions = SimileAjax.History._actions.slice(
+ 0, SimileAjax.History._currentIndex - SimileAjax.History._baseIndex);
+
+ SimileAjax.History._actions.push(action);
+ SimileAjax.History._currentIndex++;
+
+ var diff = SimileAjax.History._actions.length - SimileAjax.History.maxHistoryLength;
+ if (diff > 0) {
+ SimileAjax.History._actions = SimileAjax.History._actions.slice(diff);
+ SimileAjax.History._baseIndex += diff;
+ }
+
+ try {
+ SimileAjax.History._iframe.contentWindow.location.search =
+ "?" + SimileAjax.History._currentIndex;
+ } catch (e) {
+ /*
+ * We can't modify location.search most probably because it's a file:// url.
+ * We'll just going to modify the document's title.
+ */
+ var title = SimileAjax.History.formatHistoryEntryTitle(action.label);
+ document.title = title;
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "Error adding action {" + action.label + "} to history");
+ }
+ }, 0);
+};
+
+SimileAjax.History.addLengthyAction = function(perform, undo, label) {
+ SimileAjax.History.addAction({
+ perform: perform,
+ undo: undo,
+ label: label,
+ uiLayer: SimileAjax.WindowManager.getBaseLayer(),
+ lengthy: true
+ });
+};
+
+SimileAjax.History._handleIFrameOnLoad = function() {
+ /*
+ * This function is invoked when the user herself
+ * navigates backward or forward. We need to adjust
+ * the application's state accordingly.
+ */
+
+ try {
+ var q = SimileAjax.History._iframe.contentWindow.location.search;
+ var c = (q.length == 0) ? 0 : Math.max(0, parseInt(q.substr(1)));
+
+ var finishUp = function() {
+ var diff = c - SimileAjax.History._currentIndex;
+ SimileAjax.History._currentIndex += diff;
+ SimileAjax.History._baseIndex += diff;
+
+ SimileAjax.History._iframe.contentWindow.location.search = "?" + c;
+ };
+
+ if (c < SimileAjax.History._currentIndex) { // need to undo
+ SimileAjax.History._listeners.fire("onBeforeUndoSeveral", []);
+ window.setTimeout(function() {
+ while (SimileAjax.History._currentIndex > c &&
+ SimileAjax.History._currentIndex > SimileAjax.History._baseIndex) {
+
+ SimileAjax.History._currentIndex--;
+
+ var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+ try {
+ action.undo();
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "History: Failed to undo action {" + action.label + "}");
+ }
+ }
+
+ SimileAjax.History._listeners.fire("onAfterUndoSeveral", []);
+ finishUp();
+ }, 0);
+ } else if (c > SimileAjax.History._currentIndex) { // need to redo
+ SimileAjax.History._listeners.fire("onBeforeRedoSeveral", []);
+ window.setTimeout(function() {
+ while (SimileAjax.History._currentIndex < c &&
+ SimileAjax.History._currentIndex - SimileAjax.History._baseIndex < SimileAjax.History._actions.length) {
+
+ var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+ try {
+ action.perform();
+ } catch (e) {
+ SimileAjax.Debug.exception(e, "History: Failed to redo action {" + action.label + "}");
+ }
+
+ SimileAjax.History._currentIndex++;
+ }
+
+ SimileAjax.History._listeners.fire("onAfterRedoSeveral", []);
+ finishUp();
+ }, 0);
+ } else {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+ var title = (index >= 0 && index < SimileAjax.History._actions.length) ?
+ SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[index].label) :
+ SimileAjax.History._plainDocumentTitle;
+
+ SimileAjax.History._iframe.contentWindow.document.title = title;
+ document.title = title;
+ }
+ } catch (e) {
+ // silent
+ }
+};
+
+SimileAjax.History.getNextUndoAction = function() {
+ try {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+ return SimileAjax.History._actions[index];
+ } catch (e) {
+ return null;
+ }
+};
+
+SimileAjax.History.getNextRedoAction = function() {
+ try {
+ var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex;
+ return SimileAjax.History._actions[index];
+ } catch (e) {
+ return null;
+ }
+};
diff --git a/src/ajax/api/scripts/html.js b/src/ajax/api/scripts/html.js
new file mode 100644
index 0000000..cedeb4a
--- /dev/null
+++ b/src/ajax/api/scripts/html.js
@@ -0,0 +1,274 @@
+/*==================================================
+ * HTML Utility Functions
+ *==================================================
+ */
+
+SimileAjax.HTML = new Object();
+
+SimileAjax.HTML._e2uHash = {};
+(function() {
+ var e2uHash = SimileAjax.HTML._e2uHash;
+ e2uHash['nbsp']= '\u00A0[space]';
+ e2uHash['iexcl']= '\u00A1';
+ e2uHash['cent']= '\u00A2';
+ e2uHash['pound']= '\u00A3';
+ e2uHash['curren']= '\u00A4';
+ e2uHash['yen']= '\u00A5';
+ e2uHash['brvbar']= '\u00A6';
+ e2uHash['sect']= '\u00A7';
+ e2uHash['uml']= '\u00A8';
+ e2uHash['copy']= '\u00A9';
+ e2uHash['ordf']= '\u00AA';
+ e2uHash['laquo']= '\u00AB';
+ e2uHash['not']= '\u00AC';
+ e2uHash['shy']= '\u00AD';
+ e2uHash['reg']= '\u00AE';
+ e2uHash['macr']= '\u00AF';
+ e2uHash['deg']= '\u00B0';
+ e2uHash['plusmn']= '\u00B1';
+ e2uHash['sup2']= '\u00B2';
+ e2uHash['sup3']= '\u00B3';
+ e2uHash['acute']= '\u00B4';
+ e2uHash['micro']= '\u00B5';
+ e2uHash['para']= '\u00B6';
+ e2uHash['middot']= '\u00B7';
+ e2uHash['cedil']= '\u00B8';
+ e2uHash['sup1']= '\u00B9';
+ e2uHash['ordm']= '\u00BA';
+ e2uHash['raquo']= '\u00BB';
+ e2uHash['frac14']= '\u00BC';
+ e2uHash['frac12']= '\u00BD';
+ e2uHash['frac34']= '\u00BE';
+ e2uHash['iquest']= '\u00BF';
+ e2uHash['Agrave']= '\u00C0';
+ e2uHash['Aacute']= '\u00C1';
+ e2uHash['Acirc']= '\u00C2';
+ e2uHash['Atilde']= '\u00C3';
+ e2uHash['Auml']= '\u00C4';
+ e2uHash['Aring']= '\u00C5';
+ e2uHash['AElig']= '\u00C6';
+ e2uHash['Ccedil']= '\u00C7';
+ e2uHash['Egrave']= '\u00C8';
+ e2uHash['Eacute']= '\u00C9';
+ e2uHash['Ecirc']= '\u00CA';
+ e2uHash['Euml']= '\u00CB';
+ e2uHash['Igrave']= '\u00CC';
+ e2uHash['Iacute']= '\u00CD';
+ e2uHash['Icirc']= '\u00CE';
+ e2uHash['Iuml']= '\u00CF';
+ e2uHash['ETH']= '\u00D0';
+ e2uHash['Ntilde']= '\u00D1';
+ e2uHash['Ograve']= '\u00D2';
+ e2uHash['Oacute']= '\u00D3';
+ e2uHash['Ocirc']= '\u00D4';
+ e2uHash['Otilde']= '\u00D5';
+ e2uHash['Ouml']= '\u00D6';
+ e2uHash['times']= '\u00D7';
+ e2uHash['Oslash']= '\u00D8';
+ e2uHash['Ugrave']= '\u00D9';
+ e2uHash['Uacute']= '\u00DA';
+ e2uHash['Ucirc']= '\u00DB';
+ e2uHash['Uuml']= '\u00DC';
+ e2uHash['Yacute']= '\u00DD';
+ e2uHash['THORN']= '\u00DE';
+ e2uHash['szlig']= '\u00DF';
+ e2uHash['agrave']= '\u00E0';
+ e2uHash['aacute']= '\u00E1';
+ e2uHash['acirc']= '\u00E2';
+ e2uHash['atilde']= '\u00E3';
+ e2uHash['auml']= '\u00E4';
+ e2uHash['aring']= '\u00E5';
+ e2uHash['aelig']= '\u00E6';
+ e2uHash['ccedil']= '\u00E7';
+ e2uHash['egrave']= '\u00E8';
+ e2uHash['eacute']= '\u00E9';
+ e2uHash['ecirc']= '\u00EA';
+ e2uHash['euml']= '\u00EB';
+ e2uHash['igrave']= '\u00EC';
+ e2uHash['iacute']= '\u00ED';
+ e2uHash['icirc']= '\u00EE';
+ e2uHash['iuml']= '\u00EF';
+ e2uHash['eth']= '\u00F0';
+ e2uHash['ntilde']= '\u00F1';
+ e2uHash['ograve']= '\u00F2';
+ e2uHash['oacute']= '\u00F3';
+ e2uHash['ocirc']= '\u00F4';
+ e2uHash['otilde']= '\u00F5';
+ e2uHash['ouml']= '\u00F6';
+ e2uHash['divide']= '\u00F7';
+ e2uHash['oslash']= '\u00F8';
+ e2uHash['ugrave']= '\u00F9';
+ e2uHash['uacute']= '\u00FA';
+ e2uHash['ucirc']= '\u00FB';
+ e2uHash['uuml']= '\u00FC';
+ e2uHash['yacute']= '\u00FD';
+ e2uHash['thorn']= '\u00FE';
+ e2uHash['yuml']= '\u00FF';
+ e2uHash['quot']= '\u0022';
+ e2uHash['amp']= '\u0026';
+ e2uHash['lt']= '\u003C';
+ e2uHash['gt']= '\u003E';
+ e2uHash['OElig']= '';
+ e2uHash['oelig']= '\u0153';
+ e2uHash['Scaron']= '\u0160';
+ e2uHash['scaron']= '\u0161';
+ e2uHash['Yuml']= '\u0178';
+ e2uHash['circ']= '\u02C6';
+ e2uHash['tilde']= '\u02DC';
+ e2uHash['ensp']= '\u2002';
+ e2uHash['emsp']= '\u2003';
+ e2uHash['thinsp']= '\u2009';
+ e2uHash['zwnj']= '\u200C';
+ e2uHash['zwj']= '\u200D';
+ e2uHash['lrm']= '\u200E';
+ e2uHash['rlm']= '\u200F';
+ e2uHash['ndash']= '\u2013';
+ e2uHash['mdash']= '\u2014';
+ e2uHash['lsquo']= '\u2018';
+ e2uHash['rsquo']= '\u2019';
+ e2uHash['sbquo']= '\u201A';
+ e2uHash['ldquo']= '\u201C';
+ e2uHash['rdquo']= '\u201D';
+ e2uHash['bdquo']= '\u201E';
+ e2uHash['dagger']= '\u2020';
+ e2uHash['Dagger']= '\u2021';
+ e2uHash['permil']= '\u2030';
+ e2uHash['lsaquo']= '\u2039';
+ e2uHash['rsaquo']= '\u203A';
+ e2uHash['euro']= '\u20AC';
+ e2uHash['fnof']= '\u0192';
+ e2uHash['Alpha']= '\u0391';
+ e2uHash['Beta']= '\u0392';
+ e2uHash['Gamma']= '\u0393';
+ e2uHash['Delta']= '\u0394';
+ e2uHash['Epsilon']= '\u0395';
+ e2uHash['Zeta']= '\u0396';
+ e2uHash['Eta']= '\u0397';
+ e2uHash['Theta']= '\u0398';
+ e2uHash['Iota']= '\u0399';
+ e2uHash['Kappa']= '\u039A';
+ e2uHash['Lambda']= '\u039B';
+ e2uHash['Mu']= '\u039C';
+ e2uHash['Nu']= '\u039D';
+ e2uHash['Xi']= '\u039E';
+ e2uHash['Omicron']= '\u039F';
+ e2uHash['Pi']= '\u03A0';
+ e2uHash['Rho']= '\u03A1';
+ e2uHash['Sigma']= '\u03A3';
+ e2uHash['Tau']= '\u03A4';
+ e2uHash['Upsilon']= '\u03A5';
+ e2uHash['Phi']= '\u03A6';
+ e2uHash['Chi']= '\u03A7';
+ e2uHash['Psi']= '\u03A8';
+ e2uHash['Omega']= '\u03A9';
+ e2uHash['alpha']= '\u03B1';
+ e2uHash['beta']= '\u03B2';
+ e2uHash['gamma']= '\u03B3';
+ e2uHash['delta']= '\u03B4';
+ e2uHash['epsilon']= '\u03B5';
+ e2uHash['zeta']= '\u03B6';
+ e2uHash['eta']= '\u03B7';
+ e2uHash['theta']= '\u03B8';
+ e2uHash['iota']= '\u03B9';
+ e2uHash['kappa']= '\u03BA';
+ e2uHash['lambda']= '\u03BB';
+ e2uHash['mu']= '\u03BC';
+ e2uHash['nu']= '\u03BD';
+ e2uHash['xi']= '\u03BE';
+ e2uHash['omicron']= '\u03BF';
+ e2uHash['pi']= '\u03C0';
+ e2uHash['rho']= '\u03C1';
+ e2uHash['sigmaf']= '\u03C2';
+ e2uHash['sigma']= '\u03C3';
+ e2uHash['tau']= '\u03C4';
+ e2uHash['upsilon']= '\u03C5';
+ e2uHash['phi']= '\u03C6';
+ e2uHash['chi']= '\u03C7';
+ e2uHash['psi']= '\u03C8';
+ e2uHash['omega']= '\u03C9';
+ e2uHash['thetasym']= '\u03D1';
+ e2uHash['upsih']= '\u03D2';
+ e2uHash['piv']= '\u03D6';
+ e2uHash['bull']= '\u2022';
+ e2uHash['hellip']= '\u2026';
+ e2uHash['prime']= '\u2032';
+ e2uHash['Prime']= '\u2033';
+ e2uHash['oline']= '\u203E';
+ e2uHash['frasl']= '\u2044';
+ e2uHash['weierp']= '\u2118';
+ e2uHash['image']= '\u2111';
+ e2uHash['real']= '\u211C';
+ e2uHash['trade']= '\u2122';
+ e2uHash['alefsym']= '\u2135';
+ e2uHash['larr']= '\u2190';
+ e2uHash['uarr']= '\u2191';
+ e2uHash['rarr']= '\u2192';
+ e2uHash['darr']= '\u2193';
+ e2uHash['harr']= '\u2194';
+ e2uHash['crarr']= '\u21B5';
+ e2uHash['lArr']= '\u21D0';
+ e2uHash['uArr']= '\u21D1';
+ e2uHash['rArr']= '\u21D2';
+ e2uHash['dArr']= '\u21D3';
+ e2uHash['hArr']= '\u21D4';
+ e2uHash['forall']= '\u2200';
+ e2uHash['part']= '\u2202';
+ e2uHash['exist']= '\u2203';
+ e2uHash['empty']= '\u2205';
+ e2uHash['nabla']= '\u2207';
+ e2uHash['isin']= '\u2208';
+ e2uHash['notin']= '\u2209';
+ e2uHash['ni']= '\u220B';
+ e2uHash['prod']= '\u220F';
+ e2uHash['sum']= '\u2211';
+ e2uHash['minus']= '\u2212';
+ e2uHash['lowast']= '\u2217';
+ e2uHash['radic']= '\u221A';
+ e2uHash['prop']= '\u221D';
+ e2uHash['infin']= '\u221E';
+ e2uHash['ang']= '\u2220';
+ e2uHash['and']= '\u2227';
+ e2uHash['or']= '\u2228';
+ e2uHash['cap']= '\u2229';
+ e2uHash['cup']= '\u222A';
+ e2uHash['int']= '\u222B';
+ e2uHash['there4']= '\u2234';
+ e2uHash['sim']= '\u223C';
+ e2uHash['cong']= '\u2245';
+ e2uHash['asymp']= '\u2248';
+ e2uHash['ne']= '\u2260';
+ e2uHash['equiv']= '\u2261';
+ e2uHash['le']= '\u2264';
+ e2uHash['ge']= '\u2265';
+ e2uHash['sub']= '\u2282';
+ e2uHash['sup']= '\u2283';
+ e2uHash['nsub']= '\u2284';
+ e2uHash['sube']= '\u2286';
+ e2uHash['supe']= '\u2287';
+ e2uHash['oplus']= '\u2295';
+ e2uHash['otimes']= '\u2297';
+ e2uHash['perp']= '\u22A5';
+ e2uHash['sdot']= '\u22C5';
+ e2uHash['lceil']= '\u2308';
+ e2uHash['rceil']= '\u2309';
+ e2uHash['lfloor']= '\u230A';
+ e2uHash['rfloor']= '\u230B';
+ e2uHash['lang']= '\u2329';
+ e2uHash['rang']= '\u232A';
+ e2uHash['loz']= '\u25CA';
+ e2uHash['spades']= '\u2660';
+ e2uHash['clubs']= '\u2663';
+ e2uHash['hearts']= '\u2665';
+ e2uHash['diams']= '\u2666';
+})();
+
+SimileAjax.HTML.deEntify = function(s) {
+ var e2uHash = SimileAjax.HTML._e2uHash;
+
+ var re = /&(\w+?);/;
+ while (re.test(s)) {
+ var m = s.match(re);
+ s = s.replace(re, e2uHash[m[1]]);
+ }
+ return s;
+}; \ No newline at end of file
diff --git a/src/ajax/api/scripts/json.js b/src/ajax/api/scripts/json.js
new file mode 100644
index 0000000..ef6dc30
--- /dev/null
+++ b/src/ajax/api/scripts/json.js
@@ -0,0 +1,129 @@
+/*
+ * Copied directly from http://www.json.org/json.js.
+ */
+
+/*
+ json.js
+ 2006-04-28
+
+ This file adds these methods to JavaScript:
+
+ object.toJSONString()
+
+ This method produces a JSON text from an object. The
+ object must not contain any cyclical references.
+
+ array.toJSONString()
+
+ This method produces a JSON text from an array. The
+ array must not contain any cyclical references.
+
+ string.parseJSON()
+
+ This method parses a JSON text to produce an object or
+ array. It will return false if there is an error.
+*/
+
+SimileAjax.JSON = new Object();
+
+(function () {
+ var m = {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ };
+ var s = {
+ array: function (x) {
+ var a = ['['], b, f, i, l = x.length, v;
+ for (i = 0; i < l; i += 1) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a[a.length] = v;
+ b = true;
+ }
+ }
+ }
+ a[a.length] = ']';
+ return a.join('');
+ },
+ 'boolean': function (x) {
+ return String(x);
+ },
+ 'null': function (x) {
+ return "null";
+ },
+ number: function (x) {
+ return isFinite(x) ? String(x) : 'null';
+ },
+ object: function (x) {
+ if (x) {
+ if (x instanceof Array) {
+ return s.array(x);
+ }
+ var a = ['{'], b, f, i, v;
+ for (i in x) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a.push(s.string(i), ':', v);
+ b = true;
+ }
+ }
+ }
+ a[a.length] = '}';
+ return a.join('');
+ }
+ return 'null';
+ },
+ string: function (x) {
+ if (/["\\\x00-\x1f]/.test(x)) {
+ x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+ var c = m[b];
+ if (c) {
+ return c;
+ }
+ c = b.charCodeAt();
+ return '\\u00' +
+ Math.floor(c / 16).toString(16) +
+ (c % 16).toString(16);
+ });
+ }
+ return '"' + x + '"';
+ }
+ };
+
+ SimileAjax.JSON.toJSONString = function(o) {
+ if (o instanceof Object) {
+ return s.object(o);
+ } else if (o instanceof Array) {
+ return s.array(o);
+ } else {
+ return o.toString();
+ }
+ };
+
+ SimileAjax.JSON.parseJSON = function () {
+ try {
+ return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
+ this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
+ eval('(' + this + ')');
+ } catch (e) {
+ return false;
+ }
+ };
+})();
diff --git a/src/ajax/api/scripts/platform.js b/src/ajax/api/scripts/platform.js
new file mode 100644
index 0000000..cab8d8c
--- /dev/null
+++ b/src/ajax/api/scripts/platform.js
@@ -0,0 +1,114 @@
+/*==================================================
+ * Platform Utility Functions and Constants
+ *==================================================
+ */
+
+/* This must be called after our jQuery has been loaded
+ but before control returns to user-code.
+*/
+
+
+/*==================================================
+ * REMEMBER to update the Version!
+ *==================================================
+ */
+SimileAjax.version = 'pre 2.3.0';
+
+SimileAjax.jQuery = jQuery.noConflict(true);
+if (typeof window["$"] == "undefined") {
+ window.$ = SimileAjax.jQuery;
+}
+
+SimileAjax.Platform.os = {
+ isMac: false,
+ isWin: false,
+ isWin32: false,
+ isUnix: false
+};
+SimileAjax.Platform.browser = {
+ isIE: false,
+ isNetscape: false,
+ isMozilla: false,
+ isFirefox: false,
+ isOpera: false,
+ isSafari: false,
+
+ majorVersion: 0,
+ minorVersion: 0
+};
+
+(function() {
+ var an = navigator.appName.toLowerCase();
+ var ua = navigator.userAgent.toLowerCase();
+
+ /*
+ * Operating system
+ */
+ SimileAjax.Platform.os.isMac = (ua.indexOf('mac') != -1);
+ SimileAjax.Platform.os.isWin = (ua.indexOf('win') != -1);
+ SimileAjax.Platform.os.isWin32 = SimileAjax.Platform.isWin && (
+ ua.indexOf('95') != -1 ||
+ ua.indexOf('98') != -1 ||
+ ua.indexOf('nt') != -1 ||
+ ua.indexOf('win32') != -1 ||
+ ua.indexOf('32bit') != -1
+ );
+ SimileAjax.Platform.os.isUnix = (ua.indexOf('x11') != -1);
+
+ /*
+ * Browser
+ */
+ SimileAjax.Platform.browser.isIE = (an.indexOf("microsoft") != -1);
+ SimileAjax.Platform.browser.isNetscape = (an.indexOf("netscape") != -1);
+ SimileAjax.Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1);
+ SimileAjax.Platform.browser.isFirefox = (ua.indexOf("firefox") != -1);
+ SimileAjax.Platform.browser.isOpera = (an.indexOf("opera") != -1);
+ SimileAjax.Platform.browser.isSafari = (an.indexOf("safari") != -1);
+
+ var parseVersionString = function(s) {
+ var a = s.split(".");
+ SimileAjax.Platform.browser.majorVersion = parseInt(a[0]);
+ SimileAjax.Platform.browser.minorVersion = parseInt(a[1]);
+ };
+ var indexOf = function(s, sub, start) {
+ var i = s.indexOf(sub, start);
+ return i >= 0 ? i : s.length;
+ };
+
+ if (SimileAjax.Platform.browser.isMozilla) {
+ var offset = ua.indexOf("mozilla/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isIE) {
+ var offset = ua.indexOf("msie ");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isNetscape) {
+ var offset = ua.indexOf("rv:");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset)));
+ }
+ }
+ if (SimileAjax.Platform.browser.isFirefox) {
+ var offset = ua.indexOf("firefox/");
+ if (offset >= 0) {
+ parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+ }
+ }
+
+ if (!("localeCompare" in String.prototype)) {
+ String.prototype.localeCompare = function (s) {
+ if (this < s) return -1;
+ else if (this > s) return 1;
+ else return 0;
+ };
+ }
+})();
+
+SimileAjax.Platform.getDefaultLocale = function() {
+ return SimileAjax.Platform.clientLocale;
+}; \ No newline at end of file
diff --git a/src/ajax/api/scripts/signal.js b/src/ajax/api/scripts/signal.js
new file mode 100644
index 0000000..a638fd2
--- /dev/null
+++ b/src/ajax/api/scripts/signal.js
@@ -0,0 +1,43 @@
+/*==================================================
+ * This file is used to detect that all outstanding
+ * javascript files have been loaded. You can put
+ * a function reference into SimileAjax_onLoad
+ * to have it executed once all javascript files
+ * have loaded.
+ *==================================================
+ */
+(function() {
+ var substring = SimileAjax.urlPrefix + "scripts/signal.js";
+ var heads = document.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var node = heads[h].firstChild;
+ while (node != null) {
+ if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
+ var url = node.src;
+ var i = url.indexOf(substring);
+ if (i >= 0) {
+ heads[h].removeChild(node); // remove it so we won't hit it again
+
+ var count = parseInt(url.substr(url.indexOf(substring) + substring.length + 1));
+ SimileAjax.loadingScriptsCount -= count;
+ if (SimileAjax.loadingScriptsCount == 0) {
+ var f = null;
+ if (typeof SimileAjax_onLoad == "string") {
+ f = eval(SimileAjax_onLoad);
+ SimileAjax_onLoad = null;
+ } else if (typeof SimileAjax_onLoad == "function") {
+ f = SimileAjax_onLoad;
+ SimileAjax_onLoad = null;
+ }
+
+ if (f != null) {
+ f();
+ }
+ }
+ return;
+ }
+ }
+ node = node.nextSibling;
+ }
+ }
+})();
diff --git a/src/ajax/api/scripts/string.js b/src/ajax/api/scripts/string.js
new file mode 100644
index 0000000..01466d8
--- /dev/null
+++ b/src/ajax/api/scripts/string.js
@@ -0,0 +1,43 @@
+/*==================================================
+ * String Utility Functions and Constants
+ *==================================================
+ */
+
+String.prototype.trim = function() {
+ return this.replace(/^\s+|\s+$/g, '');
+};
+
+String.prototype.startsWith = function(prefix) {
+ return this.length >= prefix.length && this.substr(0, prefix.length) == prefix;
+};
+
+String.prototype.endsWith = function(suffix) {
+ return this.length >= suffix.length && this.substr(this.length - suffix.length) == suffix;
+};
+
+String.substitute = function(s, objects) {
+ var result = "";
+ var start = 0;
+ while (start < s.length - 1) {
+ var percent = s.indexOf("%", start);
+ if (percent < 0 || percent == s.length - 1) {
+ break;
+ } else if (percent > start && s.charAt(percent - 1) == "\\") {
+ result += s.substring(start, percent - 1) + "%";
+ start = percent + 1;
+ } else {
+ var n = parseInt(s.charAt(percent + 1));
+ if (isNaN(n) || n >= objects.length) {
+ result += s.substring(start, percent + 2);
+ } else {
+ result += s.substring(start, percent) + objects[n].toString();
+ }
+ start = percent + 2;
+ }
+ }
+
+ if (start < s.length) {
+ result += s.substring(start);
+ }
+ return result;
+};
diff --git a/src/ajax/api/scripts/units.js b/src/ajax/api/scripts/units.js
new file mode 100644
index 0000000..54f2a5b
--- /dev/null
+++ b/src/ajax/api/scripts/units.js
@@ -0,0 +1,64 @@
+/*==================================================
+ * Default Unit
+ *==================================================
+ */
+
+SimileAjax.NativeDateUnit = new Object();
+
+SimileAjax.NativeDateUnit.makeDefaultValue = function() {
+ return new Date();
+};
+
+SimileAjax.NativeDateUnit.cloneValue = function(v) {
+ return new Date(v.getTime());
+};
+
+SimileAjax.NativeDateUnit.getParser = function(format) {
+ if (typeof format == "string") {
+ format = format.toLowerCase();
+ }
+ return (format == "iso8601" || format == "iso 8601") ?
+ SimileAjax.DateTime.parseIso8601DateTime :
+ SimileAjax.DateTime.parseGregorianDateTime;
+};
+
+SimileAjax.NativeDateUnit.parseFromObject = function(o) {
+ return SimileAjax.DateTime.parseGregorianDateTime(o);
+};
+
+SimileAjax.NativeDateUnit.toNumber = function(v) {
+ return v.getTime();
+};
+
+SimileAjax.NativeDateUnit.fromNumber = function(n) {
+ return new Date(n);
+};
+
+SimileAjax.NativeDateUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1.getTime();
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2.getTime();
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n1 - n2;
+};
+
+SimileAjax.NativeDateUnit.earlier = function(v1, v2) {
+ return SimileAjax.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.later = function(v1, v2) {
+ return SimileAjax.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.change = function(v, n) {
+ return new Date(v.getTime() + n);
+};
+
diff --git a/src/ajax/api/scripts/window-manager.js b/src/ajax/api/scripts/window-manager.js
new file mode 100644
index 0000000..0da5970
--- /dev/null
+++ b/src/ajax/api/scripts/window-manager.js
@@ -0,0 +1,414 @@
+/**
+ * @fileOverview UI layers and window-wide dragging
+ * @name SimileAjax.WindowManager
+ */
+
+/**
+ * This is a singleton that keeps track of UI layers (modal and
+ * modeless) and enables/disables UI elements based on which layers
+ * they belong to. It also provides window-wide dragging
+ * implementation.
+ */
+SimileAjax.WindowManager = {
+ _initialized: false,
+ _listeners: [],
+
+ _draggedElement: null,
+ _draggedElementCallback: null,
+ _dropTargetHighlightElement: null,
+ _lastCoords: null,
+ _ghostCoords: null,
+ _draggingMode: "",
+ _dragging: false,
+
+ _layers: []
+};
+
+SimileAjax.WindowManager.initialize = function() {
+ if (SimileAjax.WindowManager._initialized) {
+ return;
+ }
+
+ SimileAjax.DOM.registerEvent(document.body, "mousedown", SimileAjax.WindowManager._onBodyMouseDown);
+ SimileAjax.DOM.registerEvent(document.body, "mousemove", SimileAjax.WindowManager._onBodyMouseMove);
+ SimileAjax.DOM.registerEvent(document.body, "mouseup", SimileAjax.WindowManager._onBodyMouseUp);
+ SimileAjax.DOM.registerEvent(document, "keydown", SimileAjax.WindowManager._onBodyKeyDown);
+ SimileAjax.DOM.registerEvent(document, "keyup", SimileAjax.WindowManager._onBodyKeyUp);
+
+ SimileAjax.WindowManager._layers.push({index: 0});
+
+ SimileAjax.WindowManager._historyListener = {
+ onBeforeUndoSeveral: function() {},
+ onAfterUndoSeveral: function() {},
+ onBeforeUndo: function() {},
+ onAfterUndo: function() {},
+
+ onBeforeRedoSeveral: function() {},
+ onAfterRedoSeveral: function() {},
+ onBeforeRedo: function() {},
+ onAfterRedo: function() {}
+ };
+ SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+
+ SimileAjax.WindowManager._initialized = true;
+};
+
+SimileAjax.WindowManager.getBaseLayer = function() {
+ SimileAjax.WindowManager.initialize();
+ return SimileAjax.WindowManager._layers[0];
+};
+
+SimileAjax.WindowManager.getHighestLayer = function() {
+ SimileAjax.WindowManager.initialize();
+ return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length - 1];
+};
+
+SimileAjax.WindowManager.registerEventWithObject = function(elmt, eventName, obj, handlerName, layer) {
+ SimileAjax.WindowManager.registerEvent(
+ elmt,
+ eventName,
+ function(elmt2, evt, target) {
+ return obj[handlerName].call(obj, elmt2, evt, target);
+ },
+ layer
+ );
+};
+
+SimileAjax.WindowManager.registerEvent = function(elmt, eventName, handler, layer) {
+ if (layer == null) {
+ layer = SimileAjax.WindowManager.getHighestLayer();
+ }
+
+ var handler2 = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._canProcessEventAtLayer(layer)) {
+ SimileAjax.WindowManager._popToLayer(layer.index);
+ try {
+ handler(elmt, evt, target);
+ } catch (e) {
+ SimileAjax.Debug.exception(e);
+ }
+ }
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+
+ SimileAjax.DOM.registerEvent(elmt, eventName, handler2);
+};
+
+SimileAjax.WindowManager.pushLayer = function(f, ephemeral, elmt) {
+ var layer = { onPop: f, index: SimileAjax.WindowManager._layers.length, ephemeral: (ephemeral), elmt: elmt };
+ SimileAjax.WindowManager._layers.push(layer);
+
+ return layer;
+};
+
+SimileAjax.WindowManager.popLayer = function(layer) {
+ for (var i = 1; i < SimileAjax.WindowManager._layers.length; i++) {
+ if (SimileAjax.WindowManager._layers[i] == layer) {
+ SimileAjax.WindowManager._popToLayer(i - 1);
+ break;
+ }
+ }
+};
+
+SimileAjax.WindowManager.popAllLayers = function() {
+ SimileAjax.WindowManager._popToLayer(0);
+};
+
+SimileAjax.WindowManager.registerForDragging = function(elmt, callback, layer) {
+ SimileAjax.WindowManager.registerEvent(
+ elmt,
+ "mousedown",
+ function(elmt, evt, target) {
+ SimileAjax.WindowManager._handleMouseDown(elmt, evt, callback);
+ },
+ layer
+ );
+};
+
+SimileAjax.WindowManager._popToLayer = function(level) {
+ while (level+1 < SimileAjax.WindowManager._layers.length) {
+ try {
+ var layer = SimileAjax.WindowManager._layers.pop();
+ if (layer.onPop != null) {
+ layer.onPop();
+ }
+ } catch (e) {
+ }
+ }
+};
+
+SimileAjax.WindowManager._canProcessEventAtLayer = function(layer) {
+ if (layer.index == (SimileAjax.WindowManager._layers.length - 1)) {
+ return true;
+ }
+ for (var i = layer.index + 1; i < SimileAjax.WindowManager._layers.length; i++) {
+ if (!SimileAjax.WindowManager._layers[i].ephemeral) {
+ return false;
+ }
+ }
+ return true;
+};
+
+SimileAjax.WindowManager.cancelPopups = function(evt) {
+ var evtCoords = (evt) ? SimileAjax.DOM.getEventPageCoordinates(evt) : { x: -1, y: -1 };
+
+ var i = SimileAjax.WindowManager._layers.length - 1;
+ while (i > 0 && SimileAjax.WindowManager._layers[i].ephemeral) {
+ var layer = SimileAjax.WindowManager._layers[i];
+ if (layer.elmt != null) { // if event falls within main element of layer then don't cancel
+ var elmt = layer.elmt;
+ var elmtCoords = SimileAjax.DOM.getPageCoordinates(elmt);
+ if (evtCoords.x >= elmtCoords.left && evtCoords.x < (elmtCoords.left + elmt.offsetWidth) &&
+ evtCoords.y >= elmtCoords.top && evtCoords.y < (elmtCoords.top + elmt.offsetHeight)) {
+ break;
+ }
+ }
+ i--;
+ }
+ SimileAjax.WindowManager._popToLayer(i);
+};
+
+SimileAjax.WindowManager._onBodyMouseDown = function(elmt, evt, target) {
+ if (!("eventPhase" in evt) || evt.eventPhase == evt.BUBBLING_PHASE) {
+ SimileAjax.WindowManager.cancelPopups(evt);
+ }
+};
+
+SimileAjax.WindowManager._handleMouseDown = function(elmt, evt, callback) {
+ SimileAjax.WindowManager._draggedElement = elmt;
+ SimileAjax.WindowManager._draggedElementCallback = callback;
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+};
+
+SimileAjax.WindowManager._onBodyKeyDown = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._dragging) {
+ if (evt.keyCode == 27) { // esc
+ SimileAjax.WindowManager._cancelDragging();
+ } else if ((evt.keyCode == 17 || evt.keyCode == 16) && SimileAjax.WindowManager._draggingMode != "copy") {
+ SimileAjax.WindowManager._draggingMode = "copy";
+
+ var img = SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix + "images/copy.png");
+ img.style.position = "absolute";
+ img.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+ img.style.top = (SimileAjax.WindowManager._ghostCoords.top) + "px";
+ document.body.appendChild(img);
+
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = img;
+ }
+ }
+};
+
+SimileAjax.WindowManager._onBodyKeyUp = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._dragging) {
+ if (evt.keyCode == 17 || evt.keyCode == 16) {
+ SimileAjax.WindowManager._draggingMode = "";
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+ }
+ }
+ }
+};
+
+SimileAjax.WindowManager._onBodyMouseMove = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._draggedElement != null) {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+
+ var lastCoords = SimileAjax.WindowManager._lastCoords;
+ var diffX = evt.clientX - lastCoords.x;
+ var diffY = evt.clientY - lastCoords.y;
+
+ if (!SimileAjax.WindowManager._dragging) {
+ if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
+ try {
+ if ("onDragStart" in callback) {
+ callback.onDragStart();
+ }
+
+ if ("ghost" in callback && callback.ghost) {
+ var draggedElmt = SimileAjax.WindowManager._draggedElement;
+
+ SimileAjax.WindowManager._ghostCoords = SimileAjax.DOM.getPageCoordinates(draggedElmt);
+ SimileAjax.WindowManager._ghostCoords.left += diffX;
+ SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+ var ghostElmt = draggedElmt.cloneNode(true);
+ ghostElmt.style.position = "absolute";
+ ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+ ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ ghostElmt.style.zIndex = 1000;
+ SimileAjax.Graphics.setOpacity(ghostElmt, 50);
+
+ document.body.appendChild(ghostElmt);
+ callback._ghostElmt = ghostElmt;
+ }
+
+ SimileAjax.WindowManager._dragging = true;
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ document.body.focus();
+ } catch (e) {
+ SimileAjax.Debug.exception("WindowManager: Error handling mouse down", e);
+ SimileAjax.WindowManager._cancelDragging();
+ }
+ }
+ } else {
+ try {
+ SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+ if ("onDragBy" in callback) {
+ callback.onDragBy(diffX, diffY);
+ }
+
+ if ("_ghostElmt" in callback) {
+ var ghostElmt = callback._ghostElmt;
+
+ SimileAjax.WindowManager._ghostCoords.left += diffX;
+ SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+ ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+ ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ var indicatorElmt = SimileAjax.WindowManager._draggingModeIndicatorElmt;
+
+ indicatorElmt.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+ indicatorElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+ }
+
+ if ("droppable" in callback && callback.droppable) {
+ var coords = SimileAjax.DOM.getEventPageCoordinates(evt);
+ var target = SimileAjax.DOM.hittest(
+ coords.x, coords.y,
+ [ SimileAjax.WindowManager._ghostElmt,
+ SimileAjax.WindowManager._dropTargetHighlightElement
+ ]
+ );
+ target = SimileAjax.WindowManager._findDropTarget(target);
+
+ if (target != SimileAjax.WindowManager._potentialDropTarget) {
+ if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+ document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ SimileAjax.WindowManager._potentialDropTarget = null;
+ }
+
+ var droppable = false;
+ if (target != null) {
+ if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+ (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+ droppable = true;
+ }
+ }
+
+ if (droppable) {
+ var border = 4;
+ var targetCoords = SimileAjax.DOM.getPageCoordinates(target);
+ var highlight = document.createElement("div");
+ highlight.style.border = border + "px solid yellow";
+ highlight.style.backgroundColor = "yellow";
+ highlight.style.position = "absolute";
+ highlight.style.left = targetCoords.left + "px";
+ highlight.style.top = targetCoords.top + "px";
+ highlight.style.width = (target.offsetWidth - border * 2) + "px";
+ highlight.style.height = (target.offsetHeight - border * 2) + "px";
+ SimileAjax.Graphics.setOpacity(highlight, 30);
+ document.body.appendChild(highlight);
+
+ SimileAjax.WindowManager._potentialDropTarget = target;
+ SimileAjax.WindowManager._dropTargetHighlightElement = highlight;
+ }
+ }
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception("WindowManager: Error handling mouse move", e);
+ SimileAjax.WindowManager._cancelDragging();
+ }
+ }
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+};
+
+SimileAjax.WindowManager._onBodyMouseUp = function(elmt, evt, target) {
+ if (SimileAjax.WindowManager._draggedElement != null) {
+ try {
+ if (SimileAjax.WindowManager._dragging) {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+ if ("onDragEnd" in callback) {
+ callback.onDragEnd();
+ }
+ if ("droppable" in callback && callback.droppable) {
+ var dropped = false;
+
+ var target = SimileAjax.WindowManager._potentialDropTarget;
+ if (target != null) {
+ if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+ (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+ if ("onDropOn" in callback) {
+ callback.onDropOn(target);
+ }
+ target.ondrop(SimileAjax.WindowManager._draggedElement, SimileAjax.WindowManager._draggingMode);
+
+ dropped = true;
+ }
+ }
+
+ if (!dropped) {
+ // TODO: do holywood explosion here
+ }
+ }
+ }
+ } finally {
+ SimileAjax.WindowManager._cancelDragging();
+ }
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+};
+
+SimileAjax.WindowManager._cancelDragging = function() {
+ var callback = SimileAjax.WindowManager._draggedElementCallback;
+ if ("_ghostElmt" in callback) {
+ var ghostElmt = callback._ghostElmt;
+ document.body.removeChild(ghostElmt);
+
+ delete callback._ghostElmt;
+ }
+ if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+ document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ }
+ if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+ document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+ SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+ }
+
+ SimileAjax.WindowManager._draggedElement = null;
+ SimileAjax.WindowManager._draggedElementCallback = null;
+ SimileAjax.WindowManager._potentialDropTarget = null;
+ SimileAjax.WindowManager._dropTargetHighlightElement = null;
+ SimileAjax.WindowManager._lastCoords = null;
+ SimileAjax.WindowManager._ghostCoords = null;
+ SimileAjax.WindowManager._draggingMode = "";
+ SimileAjax.WindowManager._dragging = false;
+};
+
+SimileAjax.WindowManager._findDropTarget = function(elmt) {
+ while (elmt != null) {
+ if ("ondrop" in elmt && (typeof elmt.ondrop) == "function") {
+ break;
+ }
+ elmt = elmt.parentNode;
+ }
+ return elmt;
+};
diff --git a/src/ajax/api/scripts/xmlhttp.js b/src/ajax/api/scripts/xmlhttp.js
new file mode 100644
index 0000000..b6d2c0a
--- /dev/null
+++ b/src/ajax/api/scripts/xmlhttp.js
@@ -0,0 +1,137 @@
+/**
+ * @fileOverview XmlHttp utility functions
+ * @name SimileAjax.XmlHttp
+ */
+
+SimileAjax.XmlHttp = new Object();
+
+/**
+ * Callback for XMLHttp onRequestStateChange.
+ */
+SimileAjax.XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) {
+ switch (xmlhttp.readyState) {
+ // 1: Request not yet made
+ // 2: Contact established with server but nothing downloaded yet
+ // 3: Called multiple while downloading in progress
+
+ // Download complete
+ case 4:
+ try {
+ if (xmlhttp.status == 0 // file:// urls, works on Firefox
+ || xmlhttp.status == 200 // http:// urls
+ ) {
+ if (fDone) {
+ fDone(xmlhttp);
+ }
+ } else {
+ if (fError) {
+ fError(
+ xmlhttp.statusText,
+ xmlhttp.status,
+ xmlhttp
+ );
+ }
+ }
+ } catch (e) {
+ SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange", e);
+ }
+ break;
+ }
+};
+
+/**
+ * Creates an XMLHttpRequest object. On the first run, this
+ * function creates a platform-specific function for
+ * instantiating an XMLHttpRequest object and then replaces
+ * itself with that function.
+ */
+SimileAjax.XmlHttp._createRequest = function() {
+ if (SimileAjax.Platform.browser.isIE) {
+ var programIDs = [
+ "Msxml2.XMLHTTP",
+ "Microsoft.XMLHTTP",
+ "Msxml2.XMLHTTP.4.0"
+ ];
+ for (var i = 0; i < programIDs.length; i++) {
+ try {
+ var programID = programIDs[i];
+ var f = function() {
+ return new ActiveXObject(programID);
+ };
+ var o = f();
+
+ // We are replacing the SimileAjax._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ SimileAjax.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ // silent
+ }
+ }
+ // fall through to try new XMLHttpRequest();
+ }
+
+ try {
+ var f = function() {
+ return new XMLHttpRequest();
+ };
+ var o = f();
+
+ // We are replacing the SimileAjax._createXmlHttpRequest
+ // function with this inner function as we've
+ // found out that it works. This is so that we
+ // don't have to do all the testing over again
+ // on subsequent calls.
+ SimileAjax.XmlHttp._createRequest = f;
+
+ return o;
+ } catch (e) {
+ throw new Error("Failed to create an XMLHttpRequest object");
+ }
+};
+
+/**
+ * Performs an asynchronous HTTP GET.
+ *
+ * @param {Function} fError a function of the form
+ function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.get = function(url, fError, fDone) {
+ var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+ xmlhttp.open("GET", url, true);
+ xmlhttp.onreadystatechange = function() {
+ SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(null);
+};
+
+/**
+ * Performs an asynchronous HTTP POST.
+ *
+ * @param {Function} fError a function of the form
+ function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.post = function(url, body, fError, fDone) {
+ var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+ xmlhttp.open("POST", url, true);
+ xmlhttp.onreadystatechange = function() {
+ SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+ };
+ xmlhttp.send(body);
+};
+
+SimileAjax.XmlHttp._forceXML = function(xmlhttp) {
+ try {
+ xmlhttp.overrideMimeType("text/xml");
+ } catch (e) {
+ xmlhttp.setrequestheader("Content-Type", "text/xml");
+ }
+}; \ No newline at end of file
diff --git a/src/ajax/api/simile-ajax-api.js b/src/ajax/api/simile-ajax-api.js
new file mode 100644
index 0000000..e858af4
--- /dev/null
+++ b/src/ajax/api/simile-ajax-api.js
@@ -0,0 +1,212 @@
+/*==================================================
+ * Simile Ajax API
+ *
+ * Include this file in your HTML file as follows:
+ *
+ * <script src="http://simile.mit.edu/ajax/api/simile-ajax-api.js" type="text/javascript"></script>
+ *
+ *==================================================
+ */
+
+if (typeof SimileAjax == "undefined") {
+ var SimileAjax = {
+ loaded: false,
+ loadingScriptsCount: 0,
+ error: null,
+ params: { bundle:"true" }
+ };
+
+ SimileAjax.Platform = new Object();
+ /*
+ HACK: We need these 2 things here because we cannot simply append
+ a <script> element containing code that accesses SimileAjax.Platform
+ to initialize it because IE executes that <script> code first
+ before it loads ajax.js and platform.js.
+ */
+
+ var getHead = function(doc) {
+ return doc.getElementsByTagName("head")[0];
+ };
+
+ SimileAjax.findScript = function(doc, substring) {
+ var heads = doc.documentElement.getElementsByTagName("head");
+ for (var h = 0; h < heads.length; h++) {
+ var node = heads[h].firstChild;
+ while (node != null) {
+ if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
+ var url = node.src;
+ var i = url.indexOf(substring);
+ if (i >= 0) {
+ return url;
+ }
+ }
+ node = node.nextSibling;
+ }
+ }
+ return null;
+ };
+ SimileAjax.includeJavascriptFile = function(doc, url, onerror, charset) {
+ onerror = onerror || "";
+ if (doc.body == null) {
+ try {
+ var q = "'" + onerror.replace( /'/g, '&apos' ) + "'"; // "
+ doc.write("<script src='" + url + "' onerror="+ q +
+ (charset ? " charset='"+ charset +"'" : "") +
+ " type='text/javascript'>"+ onerror + "</script>");
+ return;
+ } catch (e) {
+ // fall through
+ }
+ }
+
+ var script = doc.createElement("script");
+ if (onerror) {
+ try { script.innerHTML = onerror; } catch(e) {}
+ script.setAttribute("onerror", onerror);
+ }
+ if (charset) {
+ script.setAttribute("charset", charset);
+ }
+ script.type = "text/javascript";
+ script.language = "JavaScript";
+ script.src = url;
+ return getHead(doc).appendChild(script);
+ };
+ SimileAjax.includeJavascriptFiles = function(doc, urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ SimileAjax.includeJavascriptFile(doc, urlPrefix + filenames[i]);
+ }
+ SimileAjax.loadingScriptsCount += filenames.length;
+ SimileAjax.includeJavascriptFile(doc, SimileAjax.urlPrefix + "scripts/signal.js?" + filenames.length);
+ };
+ SimileAjax.includeCssFile = function(doc, url) {
+ if (doc.body == null) {
+ try {
+ doc.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>");
+ return;
+ } catch (e) {
+ // fall through
+ }
+ }
+
+ var link = doc.createElement("link");
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("type", "text/css");
+ link.setAttribute("href", url);
+ getHead(doc).appendChild(link);
+ };
+ SimileAjax.includeCssFiles = function(doc, urlPrefix, filenames) {
+ for (var i = 0; i < filenames.length; i++) {
+ SimileAjax.includeCssFile(doc, urlPrefix + filenames[i]);
+ }
+ };
+
+ /**
+ * Append into urls each string in suffixes after prefixing it with urlPrefix.
+ * @param {Array} urls
+ * @param {String} urlPrefix
+ * @param {Array} suffixes
+ */
+ SimileAjax.prefixURLs = function(urls, urlPrefix, suffixes) {
+ for (var i = 0; i < suffixes.length; i++) {
+ urls.push(urlPrefix + suffixes[i]);
+ }
+ };
+
+ /**
+ * Parse out the query parameters from a URL
+ * @param {String} url the url to parse, or location.href if undefined
+ * @param {Object} to optional object to extend with the parameters
+ * @param {Object} types optional object mapping keys to value types
+ * (String, Number, Boolean or Array, String by default)
+ * @return a key/value Object whose keys are the query parameter names
+ * @type Object
+ */
+ SimileAjax.parseURLParameters = function(url, to, types) {
+ to = to || {};
+ types = types || {};
+
+ if (typeof url == "undefined") {
+ url = location.href;
+ }
+ var q = url.indexOf("?");
+ if (q < 0) {
+ return to;
+ }
+ url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
+
+ var params = url.split("&"), param, parsed = {};
+ var decode = window.decodeURIComponent || unescape;
+ for (var i = 0; param = params[i]; i++) {
+ var eq = param.indexOf("=");
+ var name = decode(param.slice(0,eq));
+ var old = parsed[name];
+ if (typeof old == "undefined") {
+ old = [];
+ } else if (!(old instanceof Array)) {
+ old = [old];
+ }
+ parsed[name] = old.concat(decode(param.slice(eq+1)));
+ }
+ for (var i in parsed) {
+ if (!parsed.hasOwnProperty(i)) continue;
+ var type = types[i] || String;
+ var data = parsed[i];
+ if (!(data instanceof Array)) {
+ data = [data];
+ }
+ if (type === Boolean && data[0] == "false") {
+ to[i] = false; // because Boolean("false") === true
+ } else {
+ to[i] = type.apply(this, data);
+ }
+ }
+ return to;
+ };
+
+ (function() {
+ var javascriptFiles = [
+ "jquery-1.2.6.min.js",
+ "platform.js",
+ "debug.js",
+ "xmlhttp.js",
+ "json.js",
+ "dom.js",
+ "graphics.js",
+ "date-time.js",
+ "string.js",
+ "html.js",
+ "data-structure.js",
+ "units.js",
+
+ "ajax.js",
+ "history.js",
+ "window-manager.js"
+ ];
+ var cssFiles = [
+ "graphics.css"
+ ];
+
+ if (typeof SimileAjax_urlPrefix == "string") {
+ SimileAjax.urlPrefix = SimileAjax_urlPrefix;
+ } else {
+ var url = SimileAjax.findScript(document, "simile-ajax-api.js");
+ if (url == null) {
+ SimileAjax.error = new Error("Failed to derive URL prefix for Simile Ajax API code files");
+ return;
+ }
+
+ SimileAjax.urlPrefix = url.substr(0, url.indexOf("simile-ajax-api.js"));
+ }
+
+ SimileAjax.parseURLParameters(url, SimileAjax.params, {bundle:Boolean});
+ if (SimileAjax.params.bundle) {
+ SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix, [ "simile-ajax-bundle.js" ]);
+ } else {
+ SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix + "scripts/", javascriptFiles);
+ }
+ SimileAjax.includeCssFiles(document, SimileAjax.urlPrefix + "styles/", cssFiles);
+
+ SimileAjax.loaded = true;
+ })();
+}
diff --git a/src/ajax/api/simile-ajax-bundle.js b/src/ajax/api/simile-ajax-bundle.js
new file mode 100644
index 0000000..4eae2d8
--- /dev/null
+++ b/src/ajax/api/simile-ajax-bundle.js
@@ -0,0 +1,2623 @@
+´╗┐
+
+/* jquery-1.2.6.min.js */
+(function(){var _jQuery=window.jQuery,_$=window.$;
+var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);
+};
+var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;
+jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;
+if(selector.nodeType){this[0]=selector;
+this.length=1;
+return this;
+}if(typeof selector=="string"){var match=quickExpr.exec(selector);
+if(match&&(match[1]||!context)){if(match[1]){selector=jQuery.clean([match[1]],context);
+}else{var elem=document.getElementById(match[3]);
+if(elem){if(elem.id!=match[3]){return jQuery().find(selector);
+}return jQuery(elem);
+}selector=[];
+}}else{return jQuery(context).find(selector);
+}}else{if(jQuery.isFunction(selector)){return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);
+}}return this.setArray(jQuery.makeArray(selector));
+},jquery:"1.2.6",size:function(){return this.length;
+},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];
+},pushStack:function(elems){var ret=jQuery(elems);
+ret.prevObject=this;
+return ret;
+},setArray:function(elems){this.length=0;
+Array.prototype.push.apply(this,elems);
+return this;
+},each:function(callback,args){return jQuery.each(this,callback,args);
+},index:function(elem){var ret=-1;
+return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);
+},attr:function(name,value,type){var options=name;
+if(name.constructor==String){if(value===undefined){return this[0]&&jQuery[type||"attr"](this[0],name);
+}else{options={};
+options[name]=value;
+}}return this.each(function(i){for(name in options){jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));
+}});
+},css:function(key,value){if((key=="width"||key=="height")&&parseFloat(value)<0){value=undefined;
+}return this.attr(key,value,"curCSS");
+},text:function(text){if(typeof text!="object"&&text!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));
+}var ret="";
+jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8){ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);
+}});
+});
+return ret;
+},wrapAll:function(html){if(this[0]){jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;
+while(elem.firstChild){elem=elem.firstChild;
+}return elem;
+}).append(this);
+}return this;
+},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);
+});
+},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);
+});
+},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1){this.appendChild(elem);
+}});
+},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1){this.insertBefore(elem,this.firstChild);
+}});
+},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);
+});
+},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);
+});
+},end:function(){return this.prevObject||jQuery([]);
+},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);
+});
+return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);
+},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");
+container.appendChild(clone);
+return jQuery.clean([container.innerHTML])[0];
+}else{return this.cloneNode(true);
+}});
+var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined){this[expando]=null;
+}});
+if(events===true){this.find("*").andSelf().each(function(i){if(this.nodeType==3){return ;
+}var events=jQuery.data(this,"events");
+for(var type in events){for(var handler in events[type]){jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);
+}}});
+}return ret;
+},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);
+})||jQuery.multiFilter(selector,this));
+},not:function(selector){if(selector.constructor==String){if(isSimple.test(selector)){return this.pushStack(jQuery.multiFilter(selector,this,true));
+}else{selector=jQuery.multiFilter(selector,this);
+}}var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;
+return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;
+});
+},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=="string"?jQuery(selector):jQuery.makeArray(selector))));
+},is:function(selector){return !!selector&&jQuery.multiFilter(selector,this).length>0;
+},hasClass:function(selector){return this.is("."+selector);
+},val:function(value){if(value==undefined){if(this.length){var elem=this[0];
+if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";
+if(index<0){return null;
+}for(var i=one?index:0,max=one?index+1:options.length;
+i<max;
+i++){var option=options[i];
+if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;
+if(one){return value;
+}values.push(value);
+}}return values;
+}else{return(this[0].value||"").replace(/\r/g,"");
+}}return undefined;
+}if(value.constructor==Number){value+="";
+}return this.each(function(){if(this.nodeType!=1){return ;
+}if(value.constructor==Array&&/radio|checkbox/.test(this.type)){this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);
+}else{if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);
+jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);
+});
+if(!values.length){this.selectedIndex=-1;
+}}else{this.value=value;
+}}});
+},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);
+},replaceWith:function(value){return this.after(value).remove();
+},eq:function(i){return this.slice(i,i+1);
+},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));
+},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);
+}));
+},andSelf:function(){return this.add(this.prevObject);
+},data:function(key,value){var parts=key.split(".");
+parts[1]=parts[1]?"."+parts[1]:"";
+if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);
+if(data===undefined&&this.length){data=jQuery.data(this[0],key);
+}return data===undefined&&parts[1]?this.data(parts[0]):data;
+}else{return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);
+});
+}},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);
+});
+},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;
+return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);
+if(reverse){elems.reverse();
+}}var obj=this;
+if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr")){obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));
+}var scripts=jQuery([]);
+jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;
+if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem);
+}else{if(elem.nodeType==1){scripts=scripts.add(jQuery("script",elem).remove());
+}callback.call(obj,elem);
+}});
+scripts.each(evalScript);
+});
+}};
+jQuery.fn.init.prototype=jQuery.fn;
+function evalScript(i,elem){if(elem.src){jQuery.ajax({url:elem.src,async:false,dataType:"script"});
+}else{jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");
+}if(elem.parentNode){elem.parentNode.removeChild(elem);
+}}function now(){return +new Date;
+}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;
+if(target.constructor==Boolean){deep=target;
+target=arguments[1]||{};
+i=2;
+}if(typeof target!="object"&&typeof target!="function"){target={};
+}if(length==i){target=this;
+--i;
+}for(;
+i<length;
+i++){if((options=arguments[i])!=null){for(var name in options){var src=target[name],copy=options[name];
+if(target===copy){continue;
+}if(deep&&copy&&typeof copy=="object"&&!copy.nodeType){target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);
+}else{if(copy!==undefined){target[name]=copy;
+}}}}}return target;
+};
+var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};
+jQuery.extend({noConflict:function(deep){window.$=_$;
+if(deep){window.jQuery=_jQuery;
+}return jQuery;
+},isFunction:function(fn){return !!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");
+},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;
+},globalEval:function(data){data=jQuery.trim(data);
+if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");
+script.type="text/javascript";
+if(jQuery.browser.msie){script.text=data;
+}else{script.appendChild(document.createTextNode(data));
+}head.insertBefore(script,head.firstChild);
+head.removeChild(script);
+}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();
+},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;
+var id=elem[expando];
+if(!id){id=elem[expando]=++uuid;
+}if(name&&!jQuery.cache[id]){jQuery.cache[id]={};
+}if(data!==undefined){jQuery.cache[id][name]=data;
+}return name?jQuery.cache[id][name]:id;
+},removeData:function(elem,name){elem=elem==window?windowData:elem;
+var id=elem[expando];
+if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];
+name="";
+for(name in jQuery.cache[id]){break;
+}if(!name){jQuery.removeData(elem);
+}}}else{try{delete elem[expando];
+}catch(e){if(elem.removeAttribute){elem.removeAttribute(expando);
+}}delete jQuery.cache[id];
+}},each:function(object,callback,args){var name,i=0,length=object.length;
+if(args){if(length==undefined){for(name in object){if(callback.apply(object[name],args)===false){break;
+}}}else{for(;
+i<length;
+){if(callback.apply(object[i++],args)===false){break;
+}}}}else{if(length==undefined){for(name in object){if(callback.call(object[name],name,object[name])===false){break;
+}}}else{for(var value=object[0];
+i<length&&callback.call(value,i,value)!==false;
+value=object[++i]){}}}return object;
+},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value)){value=value.call(elem,i);
+}return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;
+},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className)){elem.className+=(elem.className?" ":"")+className;
+}});
+},remove:function(elem,classNames){if(elem.nodeType==1){elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return !jQuery.className.has(classNames,className);
+}).join(" "):"";
+}},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;
+}},swap:function(elem,options,callback){var old={};
+for(var name in options){old[name]=elem.style[name];
+elem.style[name]=options[name];
+}callback.call(elem);
+for(var name in options){elem.style[name]=old[name];
+}},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];
+function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;
+var padding=0,border=0;
+jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;
+border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;
+});
+val-=Math.round(padding+border);
+}if(jQuery(elem).is(":visible")){getWH();
+}else{jQuery.swap(elem,props,getWH);
+}return Math.max(0,val);
+}return jQuery.curCSS(elem,name,force);
+},curCSS:function(elem,name,force){var ret,style=elem.style;
+function color(elem){if(!jQuery.browser.safari){return false;
+}var ret=defaultView.getComputedStyle(elem,null);
+return !ret||ret.getPropertyValue("color")=="";
+}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");
+return ret==""?"1":ret;
+}if(jQuery.browser.opera&&name=="display"){var save=style.outline;
+style.outline="0 solid black";
+style.outline=save;
+}if(name.match(/float/i)){name=styleFloat;
+}if(!force&&style&&style[name]){ret=style[name];
+}else{if(defaultView.getComputedStyle){if(name.match(/float/i)){name="float";
+}name=name.replace(/([A-Z])/g,"-$1").toLowerCase();
+var computedStyle=defaultView.getComputedStyle(elem,null);
+if(computedStyle&&!color(elem)){ret=computedStyle.getPropertyValue(name);
+}else{var swap=[],stack=[],a=elem,i=0;
+for(;
+a&&color(a);
+a=a.parentNode){stack.unshift(a);
+}for(;
+i<stack.length;
+i++){if(color(stack[i])){swap[i]=stack[i].style.display;
+stack[i].style.display="block";
+}}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";
+for(i=0;
+i<swap.length;
+i++){if(swap[i]!=null){stack[i].style.display=swap[i];
+}}}if(name=="opacity"&&ret==""){ret="1";
+}}else{if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();
+});
+ret=elem.currentStyle[name]||elem.currentStyle[camelCase];
+if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;
+elem.runtimeStyle.left=elem.currentStyle.left;
+style.left=ret||0;
+ret=style.pixelLeft+"px";
+style.left=left;
+elem.runtimeStyle.left=rsLeft;
+}}}}return ret;
+},clean:function(elems,context){var ret=[];
+context=context||document;
+if(typeof context.createElement=="undefined"){context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;
+}jQuery.each(elems,function(i,elem){if(!elem){return ;
+}if(elem.constructor==Number){elem+="";
+}if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";
+});
+var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");
+var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];
+div.innerHTML=wrap[1]+elem+wrap[2];
+while(wrap[0]--){div=div.lastChild;
+}if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];
+for(var j=tbody.length-1;
+j>=0;
+--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j]);
+}}if(/^\s/.test(elem)){div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);
+}}elem=jQuery.makeArray(div.childNodes);
+}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select"))){return ;
+}if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options){ret.push(elem);
+}else{ret=jQuery.merge(ret,elem);
+}});
+return ret;
+},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8){return undefined;
+}var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;
+name=notxml&&jQuery.props[name]||name;
+if(elem.tagName){var special=/href|src|style/.test(name);
+if(name=="selected"&&jQuery.browser.safari){elem.parentNode.selectedIndex;
+}if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode){throw"type property can't be changed";
+}elem[name]=value;
+}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name)){return elem.getAttributeNode(name).nodeValue;
+}return elem[name];
+}if(msie&&notxml&&name=="style"){return jQuery.attr(elem.style,"cssText",value);
+}if(set){elem.setAttribute(name,""+value);
+}var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);
+return attr===null?undefined:attr;
+}if(msie&&name=="opacity"){if(set){elem.zoom=1;
+elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+""=="NaN"?"":"alpha(opacity="+value*100+")");
+}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+"":"";
+}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();
+});
+if(set){elem[name]=value;
+}return elem[name];
+},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");
+},makeArray:function(array){var ret=[];
+if(array!=null){var i=array.length;
+if(i==null||array.split||array.setInterval||array.call){ret[0]=array;
+}else{while(i){ret[--i]=array[i];
+}}}return ret;
+},inArray:function(elem,array){for(var i=0,length=array.length;
+i<length;
+i++){if(array[i]===elem){return i;
+}}return -1;
+},merge:function(first,second){var i=0,elem,pos=first.length;
+if(jQuery.browser.msie){while(elem=second[i++]){if(elem.nodeType!=8){first[pos++]=elem;
+}}}else{while(elem=second[i++]){first[pos++]=elem;
+}}return first;
+},unique:function(array){var ret=[],done={};
+try{for(var i=0,length=array.length;
+i<length;
+i++){var id=jQuery.data(array[i]);
+if(!done[id]){done[id]=true;
+ret.push(array[i]);
+}}}catch(e){ret=array;
+}return ret;
+},grep:function(elems,callback,inv){var ret=[];
+for(var i=0,length=elems.length;
+i<length;
+i++){if(!inv!=!callback(elems[i],i)){ret.push(elems[i]);
+}}return ret;
+},map:function(elems,callback){var ret=[];
+for(var i=0,length=elems.length;
+i<length;
+i++){var value=callback(elems[i],i);
+if(value!=null){ret[ret.length]=value;
+}}return ret.concat.apply([],ret);
+}});
+var userAgent=navigator.userAgent.toLowerCase();
+jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};
+var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";
+jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});
+jQuery.each({parent:function(elem){return elem.parentNode;
+},parents:function(elem){return jQuery.dir(elem,"parentNode");
+},next:function(elem){return jQuery.nth(elem,2,"nextSibling");
+},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");
+},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");
+},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");
+},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);
+},children:function(elem){return jQuery.sibling(elem.firstChild);
+},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);
+}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);
+if(selector&&typeof selector=="string"){ret=jQuery.multiFilter(selector,ret);
+}return this.pushStack(jQuery.unique(ret));
+};
+});
+jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;
+return this.each(function(){for(var i=0,length=args.length;
+i<length;
+i++){jQuery(args[i])[original](this);
+}});
+};
+});
+jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");
+if(this.nodeType==1){this.removeAttribute(name);
+}},addClass:function(classNames){jQuery.className.add(this,classNames);
+},removeClass:function(classNames){jQuery.className.remove(this,classNames);
+},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);
+},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);
+jQuery.removeData(this);
+});
+if(this.parentNode){this.parentNode.removeChild(this);
+}}},empty:function(){jQuery(">*",this).remove();
+while(this.firstChild){this.removeChild(this.firstChild);
+}}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);
+};
+});
+jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();
+jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");
+};
+});
+function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;
+}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");
+jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);
+},"#":function(a,i,m){return a.getAttribute("id")==m[2];
+},":":{lt:function(a,i,m){return i<m[3]-0;
+},gt:function(a,i,m){return i>m[3]-0;
+},nth:function(a,i,m){return m[3]-0==i;
+},eq:function(a,i,m){return m[3]-0==i;
+},first:function(a,i){return i==0;
+},last:function(a,i,m,r){return i==r.length-1;
+},even:function(a,i){return i%2==0;
+},odd:function(a,i){return i%2;
+},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;
+},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;
+},"only-child":function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");
+},parent:function(a){return a.firstChild;
+},empty:function(a){return !a.firstChild;
+},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;
+},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";
+},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";
+},enabled:function(a){return !a.disabled;
+},disabled:function(a){return a.disabled;
+},checked:function(a){return a.checked;
+},selected:function(a){return a.selected||jQuery.attr(a,"selected");
+},text:function(a){return"text"==a.type;
+},radio:function(a){return"radio"==a.type;
+},checkbox:function(a){return"checkbox"==a.type;
+},file:function(a){return"file"==a.type;
+},password:function(a){return"password"==a.type;
+},submit:function(a){return"submit"==a.type;
+},image:function(a){return"image"==a.type;
+},reset:function(a){return"reset"==a.type;
+},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");
+},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);
+},has:function(a,i,m){return jQuery.find(m[3],a).length;
+},header:function(a){return/h\d/i.test(a.nodeName);
+},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;
+}).length;
+}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];
+while(expr&&expr!=old){old=expr;
+var f=jQuery.filter(expr,elems,not);
+expr=f.t.replace(/^\s*,\s*/,"");
+cur=not?elems=f.r:jQuery.merge(cur,f.r);
+}return cur;
+},find:function(t,context){if(typeof t!="string"){return[t];
+}if(context&&context.nodeType!=1&&context.nodeType!=9){return[];
+}context=context||document;
+var ret=[context],done=[],last,nodeName;
+while(t&&last!=t){var r=[];
+last=t;
+t=jQuery.trim(t);
+var foundToken=false,re=quickChild,m=re.exec(t);
+if(m){nodeName=m[1].toUpperCase();
+for(var i=0;
+ret[i];
+i++){for(var c=ret[i].firstChild;
+c;
+c=c.nextSibling){if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName)){r.push(c);
+}}}ret=r;
+t=t.replace(re,"");
+if(t.indexOf(" ")==0){continue;
+}foundToken=true;
+}else{re=/^([>+~])\s*(\w*)/i;
+if((m=re.exec(t))!=null){r=[];
+var merge={};
+nodeName=m[2].toUpperCase();
+m=m[1];
+for(var j=0,rl=ret.length;
+j<rl;
+j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;
+for(;
+n;
+n=n.nextSibling){if(n.nodeType==1){var id=jQuery.data(n);
+if(m=="~"&&merge[id]){break;
+}if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~"){merge[id]=true;
+}r.push(n);
+}if(m=="+"){break;
+}}}}ret=r;
+t=jQuery.trim(t.replace(re,""));
+foundToken=true;
+}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0]){ret.shift();
+}done=jQuery.merge(done,ret);
+r=ret=[context];
+t=" "+t.substr(1,t.length);
+}else{var re2=quickID;
+var m=re2.exec(t);
+if(m){m=[0,m[2],m[3],m[1]];
+}else{re2=quickClass;
+m=re2.exec(t);
+}m[2]=m[2].replace(/\\/g,"");
+var elem=ret[ret.length-1];
+if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);
+if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2]){oid=jQuery('[@id="'+m[2]+'"]',elem)[0];
+}ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];
+}else{for(var i=0;
+ret[i];
+i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];
+if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object"){tag="param";
+}r=jQuery.merge(r,ret[i].getElementsByTagName(tag));
+}if(m[1]=="."){r=jQuery.classFilter(r,m[2]);
+}if(m[1]=="#"){var tmp=[];
+for(var i=0;
+r[i];
+i++){if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];
+break;
+}}r=tmp;
+}ret=r;
+}t=t.replace(re2,"");
+}}if(t){var val=jQuery.filter(t,r);
+ret=r=val.r;
+t=jQuery.trim(val.t);
+}}if(t){ret=[];
+}if(ret&&context==ret[0]){ret.shift();
+}done=jQuery.merge(done,ret);
+return done;
+},classFilter:function(r,m,not){m=" "+m+" ";
+var tmp=[];
+for(var i=0;
+r[i];
+i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;
+if(!not&&pass||not&&!pass){tmp.push(r[i]);
+}}return tmp;
+},filter:function(t,r,not){var last;
+while(t&&t!=last){last=t;
+var p=jQuery.parse,m;
+for(var i=0;
+p[i];
+i++){m=p[i].exec(t);
+if(m){t=t.substring(m[0].length);
+m[2]=m[2].replace(/\\/g,"");
+break;
+}}if(!m){break;
+}if(m[1]==":"&&m[2]=="not"){r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);
+}else{if(m[1]=="."){r=jQuery.classFilter(r,m[2],not);
+}else{if(m[1]=="["){var tmp=[],type=m[3];
+for(var i=0,rl=r.length;
+i<rl;
+i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];
+if(z==null||/href|src|selected/.test(m[2])){z=jQuery.attr(a,m[2])||"";
+}if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not){tmp.push(a);
+}}r=tmp;
+}else{if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;
+for(var i=0,rl=r.length;
+i<rl;
+i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);
+if(!merge[id]){var c=1;
+for(var n=parentNode.firstChild;
+n;
+n=n.nextSibling){if(n.nodeType==1){n.nodeIndex=c++;
+}}merge[id]=true;
+}var add=false;
+if(first==0){if(node.nodeIndex==last){add=true;
+}}else{if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0){add=true;
+}}if(add^not){tmp.push(node);
+}}r=tmp;
+}else{var fn=jQuery.expr[m[1]];
+if(typeof fn=="object"){fn=fn[m[2]];
+}if(typeof fn=="string"){fn=eval("false||function(a,i){return "+fn+";}");
+}r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);
+},not);
+}}}}}return{r:r,t:t};
+},dir:function(elem,dir){var matched=[],cur=elem[dir];
+while(cur&&cur!=document){if(cur.nodeType==1){matched.push(cur);
+}cur=cur[dir];
+}return matched;
+},nth:function(cur,result,dir,elem){result=result||1;
+var num=0;
+for(;
+cur;
+cur=cur[dir]){if(cur.nodeType==1&&++num==result){break;
+}}return cur;
+},sibling:function(n,elem){var r=[];
+for(;
+n;
+n=n.nextSibling){if(n.nodeType==1&&n!=elem){r.push(n);
+}}return r;
+}});
+jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8){return ;
+}if(jQuery.browser.msie&&elem.setInterval){elem=window;
+}if(!handler.guid){handler.guid=this.guid++;
+}if(data!=undefined){var fn=handler;
+handler=this.proxy(fn,function(){return fn.apply(this,arguments);
+});
+handler.data=data;
+}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered){return jQuery.event.handle.apply(arguments.callee.elem,arguments);
+}});
+handle.elem=elem;
+jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");
+type=parts[0];
+handler.type=parts[1];
+var handlers=events[type];
+if(!handlers){handlers=events[type]={};
+if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener){elem.addEventListener(type,handle,false);
+}else{if(elem.attachEvent){elem.attachEvent("on"+type,handle);
+}}}}handlers[handler.guid]=handler;
+jQuery.event.global[type]=true;
+});
+elem=null;
+},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8){return ;
+}var events=jQuery.data(elem,"events"),ret,index;
+if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)==".")){for(var type in events){this.remove(elem,type+(types||""));
+}}else{if(types.type){handler=types.handler;
+types=types.type;
+}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");
+type=parts[0];
+if(events[type]){if(handler){delete events[type][handler.guid];
+}else{for(handler in events[type]){if(!parts[1]||events[type][handler].type==parts[1]){delete events[type][handler];
+}}}for(ret in events[type]){break;
+}if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener){elem.removeEventListener(type,jQuery.data(elem,"handle"),false);
+}else{if(elem.detachEvent){elem.detachEvent("on"+type,jQuery.data(elem,"handle"));
+}}}ret=null;
+delete events[type];
+}}});
+}for(ret in events){break;
+}if(!ret){var handle=jQuery.data(elem,"handle");
+if(handle){handle.elem=null;
+}jQuery.removeData(elem,"events");
+jQuery.removeData(elem,"handle");
+}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);
+if(type.indexOf("!")>=0){type=type.slice(0,-1);
+var exclusive=true;
+}if(!elem){if(this.global[type]){jQuery("*").add([window,document]).trigger(type,data);
+}}else{if(elem.nodeType==3||elem.nodeType==8){return undefined;
+}var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;
+if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});
+data[0][expando]=true;
+}data[0].type=type;
+if(exclusive){data[0].exclusive=true;
+}var handle=jQuery.data(elem,"handle");
+if(handle){val=handle.apply(elem,data);
+}if((!fn||(jQuery.nodeName(elem,"a")&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false){val=false;
+}if(event){data.shift();
+}if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));
+if(ret!==undefined){val=ret;
+}}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,"a")&&type=="click")){this.triggered=true;
+try{elem[type]();
+}catch(e){}}this.triggered=false;
+}return val;
+},handle:function(event){var val,ret,namespace,all,handlers;
+event=arguments[0]=jQuery.event.fix(event||window.event);
+namespace=event.type.split(".");
+event.type=namespace[0];
+namespace=namespace[1];
+all=!namespace&&!event.exclusive;
+handlers=(jQuery.data(this,"events")||{})[event.type];
+for(var j in handlers){var handler=handlers[j];
+if(all||handler.type==namespace){event.handler=handler;
+event.data=handler.data;
+ret=handler.apply(this,arguments);
+if(val!==false){val=ret;
+}if(ret===false){event.preventDefault();
+event.stopPropagation();
+}}}return val;
+},fix:function(event){if(event[expando]==true){return event;
+}var originalEvent=event;
+event={originalEvent:originalEvent};
+var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
+for(var i=props.length;
+i;
+i--){event[props[i]]=originalEvent[props[i]];
+}event[expando]=true;
+event.preventDefault=function(){if(originalEvent.preventDefault){originalEvent.preventDefault();
+}originalEvent.returnValue=false;
+};
+event.stopPropagation=function(){if(originalEvent.stopPropagation){originalEvent.stopPropagation();
+}originalEvent.cancelBubble=true;
+};
+event.timeStamp=event.timeStamp||now();
+if(!event.target){event.target=event.srcElement||document;
+}if(event.target.nodeType==3){event.target=event.target.parentNode;
+}if(!event.relatedTarget&&event.fromElement){event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;
+}if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;
+event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);
+event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);
+}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode)){event.which=event.charCode||event.keyCode;
+}if(!event.metaKey&&event.ctrlKey){event.metaKey=event.ctrlKey;
+}if(!event.which&&event.button){event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));
+}return event;
+},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;
+return proxy;
+},special:{ready:{setup:function(){bindReady();
+return ;
+},teardown:function(){return ;
+}},mouseenter:{setup:function(){if(jQuery.browser.msie){return false;
+}jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);
+return true;
+},teardown:function(){if(jQuery.browser.msie){return false;
+}jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);
+return true;
+},handler:function(event){if(withinElement(event,this)){return true;
+}event.type="mouseenter";
+return jQuery.event.handle.apply(this,arguments);
+}},mouseleave:{setup:function(){if(jQuery.browser.msie){return false;
+}jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);
+return true;
+},teardown:function(){if(jQuery.browser.msie){return false;
+}jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);
+return true;
+},handler:function(event){if(withinElement(event,this)){return true;
+}event.type="mouseleave";
+return jQuery.event.handle.apply(this,arguments);
+}}}};
+jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);
+});
+},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);
+return(fn||data).apply(this,arguments);
+});
+return this.each(function(){jQuery.event.add(this,type,one,fn&&data);
+});
+},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);
+});
+},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);
+});
+},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);
+},toggle:function(fn){var args=arguments,i=1;
+while(i<args.length){jQuery.event.proxy(fn,args[i++]);
+}return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;
+event.preventDefault();
+return args[this.lastToggle++].apply(this,arguments)||false;
+}));
+},hover:function(fnOver,fnOut){return this.bind("mouseenter",fnOver).bind("mouseleave",fnOut);
+},ready:function(fn){bindReady();
+if(jQuery.isReady){fn.call(document,jQuery);
+}else{jQuery.readyList.push(function(){return fn.call(this,jQuery);
+});
+}return this;
+}});
+jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;
+if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);
+});
+jQuery.readyList=null;
+}jQuery(document).triggerHandler("ready");
+}}});
+var readyBound=false;
+function bindReady(){if(readyBound){return ;
+}readyBound=true;
+if(document.addEventListener&&!jQuery.browser.opera){document.addEventListener("DOMContentLoaded",jQuery.ready,false);
+}if(jQuery.browser.msie&&window==top){(function(){if(jQuery.isReady){return ;
+}try{document.documentElement.doScroll("left");
+}catch(error){setTimeout(arguments.callee,0);
+return ;
+}jQuery.ready();
+})();
+}if(jQuery.browser.opera){document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady){return ;
+}for(var i=0;
+i<document.styleSheets.length;
+i++){if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);
+return ;
+}}jQuery.ready();
+},false);
+}if(jQuery.browser.safari){var numStyles;
+(function(){if(jQuery.isReady){return ;
+}if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);
+return ;
+}if(numStyles===undefined){numStyles=jQuery("style, link[rel=stylesheet]").length;
+}if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);
+return ;
+}jQuery.ready();
+})();
+}jQuery.event.add(window,"load",jQuery.ready);
+}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,change,select,submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);
+};
+});
+var withinElement=function(event,elem){var parent=event.relatedTarget;
+while(parent&&parent!=elem){try{parent=parent.parentNode;
+}catch(error){parent=elem;
+}}return parent==elem;
+};
+jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();
+});
+jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!="string"){return this._load(url);
+}var off=url.indexOf(" ");
+if(off>=0){var selector=url.slice(off,url.length);
+url=url.slice(0,off);
+}callback=callback||function(){};
+var type="GET";
+if(params){if(jQuery.isFunction(params)){callback=params;
+params=null;
+}else{params=jQuery.param(params);
+type="POST";
+}}var self=this;
+jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified"){self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);
+}self.each(callback,[res.responseText,status,res]);
+}});
+return this;
+},serialize:function(){return jQuery.param(this.serializeArray());
+},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;
+}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));
+}).map(function(i,elem){var val=jQuery(this).val();
+return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};
+}):{name:elem.name,value:val};
+}).get();
+}});
+jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);
+};
+});
+var jsc=now();
+jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;
+data=null;
+}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});
+},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");
+},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");
+},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;
+data={};
+}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});
+},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);
+},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));
+var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();
+if(s.data&&s.processData&&typeof s.data!="string"){s.data=jQuery.param(s.data);
+}if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre)){s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";
+}}else{if(!s.data||!s.data.match(jsre)){s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";
+}}s.dataType="json";
+}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;
+if(s.data){s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");
+}s.url=s.url.replace(jsre,"="+jsonp+"$1");
+s.dataType="script";
+window[jsonp]=function(tmp){data=tmp;
+success();
+complete();
+window[jsonp]=undefined;
+try{delete window[jsonp];
+}catch(e){}if(head){head.removeChild(script);
+}};
+}if(s.dataType=="script"&&s.cache==null){s.cache=false;
+}if(s.cache===false&&type=="GET"){var ts=now();
+var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");
+s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");
+}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;
+s.data=null;
+}if(s.global&&!jQuery.active++){jQuery.event.trigger("ajaxStart");
+}var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;
+if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];
+var script=document.createElement("script");
+script.src=s.url;
+if(s.scriptCharset){script.charset=s.scriptCharset;
+}if(!jsonp){var done=false;
+script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;
+success();
+complete();
+head.removeChild(script);
+}};
+}head.appendChild(script);
+return undefined;
+}var requestDone=false;
+var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();
+if(s.username){xhr.open(type,s.url,s.async,s.username,s.password);
+}else{xhr.open(type,s.url,s.async);
+}try{if(s.data){xhr.setRequestHeader("Content-Type",s.contentType);
+}if(s.ifModified){xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");
+}xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");
+xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);
+}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;
+xhr.abort();
+return false;
+}if(s.global){jQuery.event.trigger("ajaxSend",[xhr,s]);
+}var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;
+if(ival){clearInterval(ival);
+ival=null;
+}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";
+if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);
+}catch(e){status="parsererror";
+}}if(status=="success"){var modRes;
+try{modRes=xhr.getResponseHeader("Last-Modified");
+}catch(e){}if(s.ifModified&&modRes){jQuery.lastModified[s.url]=modRes;
+}if(!jsonp){success();
+}}else{jQuery.handleError(s,xhr,status);
+}complete();
+if(s.async){xhr=null;
+}}};
+if(s.async){var ival=setInterval(onreadystatechange,13);
+if(s.timeout>0){setTimeout(function(){if(xhr){xhr.abort();
+if(!requestDone){onreadystatechange("timeout");
+}}},s.timeout);
+}}try{xhr.send(s.data);
+}catch(e){jQuery.handleError(s,xhr,null,e);
+}if(!s.async){onreadystatechange();
+}function success(){if(s.success){s.success(data,status);
+}if(s.global){jQuery.event.trigger("ajaxSuccess",[xhr,s]);
+}}function complete(){if(s.complete){s.complete(xhr,status);
+}if(s.global){jQuery.event.trigger("ajaxComplete",[xhr,s]);
+}if(s.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop");
+}}return xhr;
+},handleError:function(s,xhr,status,e){if(s.error){s.error(xhr,status,e);
+}if(s.global){jQuery.event.trigger("ajaxError",[xhr,s,e]);
+}},active:0,httpSuccess:function(xhr){try{return !xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;
+}catch(e){}return false;
+},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");
+return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;
+}catch(e){}return false;
+},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;
+if(xml&&data.documentElement.tagName=="parsererror"){throw"parsererror";
+}if(filter){data=filter(data,type);
+}if(type=="script"){jQuery.globalEval(data);
+}if(type=="json"){data=eval("("+data+")");
+}return data;
+},param:function(a){var s=[];
+if(a.constructor==Array||a.jquery){jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));
+});
+}else{for(var j in a){if(a[j]&&a[j].constructor==Array){jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));
+});
+}else{s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));
+}}}return s.join("&").replace(/%20/g,"+");
+}});
+jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";
+if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");
+this.style.display=elem.css("display");
+if(this.style.display=="none"){this.style.display="block";
+}elem.remove();
+}}).end();
+},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");
+this.style.display="none";
+}).end();
+},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();
+});
+},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);
+},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);
+},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);
+},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);
+},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);
+},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);
+},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);
+return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1){return false;
+}var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;
+for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden){return opt.complete.call(this);
+}if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");
+opt.overflow=this.style.overflow;
+}}if(opt.overflow!=null){this.style.overflow="hidden";
+}opt.curAnim=jQuery.extend({},prop);
+jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);
+if(/toggle|show|hide/.test(val)){e[val=="toggle"?hidden?"show":"hide":val](prop);
+}else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;
+if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";
+if(unit!="px"){self.style[name]=(end||1)+unit;
+start=((end||1)/e.cur(true))*start;
+self.style[name]=start+unit;
+}if(parts[1]){end=((parts[1]=="-="?-1:1)*end)+start;
+}e.custom(start,end,unit);
+}else{e.custom(start,val,"");
+}}});
+return true;
+});
+},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;
+type="fx";
+}if(!type||(typeof type=="string"&&!fn)){return queue(this[0],type);
+}return this.each(function(){if(fn.constructor==Array){queue(this,type,fn);
+}else{queue(this,type).push(fn);
+if(queue(this,type).length==1){fn.call(this);
+}}});
+},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;
+if(clearQueue){this.queue([]);
+}this.each(function(){for(var i=timers.length-1;
+i>=0;
+i--){if(timers[i].elem==this){if(gotoEnd){timers[i](true);
+}timers.splice(i,1);
+}}});
+if(!gotoEnd){this.dequeue();
+}return this;
+}});
+var queue=function(elem,type,array){if(elem){type=type||"fx";
+var q=jQuery.data(elem,type+"queue");
+if(!q||array){q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));
+}}return q;
+};
+jQuery.fn.dequeue=function(type){type=type||"fx";
+return this.each(function(){var q=queue(this,type);
+q.shift();
+if(q.length){q[0].call(this);
+}});
+};
+jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};
+opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;
+opt.old=opt.complete;
+opt.complete=function(){if(opt.queue!==false){jQuery(this).dequeue();
+}if(jQuery.isFunction(opt.old)){opt.old.call(this);
+}};
+return opt;
+},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;
+},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;
+}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;
+this.elem=elem;
+this.prop=prop;
+if(!options.orig){options.orig={};
+}}});
+jQuery.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this);
+}(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);
+if(this.prop=="height"||this.prop=="width"){this.elem.style.display="block";
+}},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null){return this.elem[this.prop];
+}var r=parseFloat(jQuery.css(this.elem,this.prop,force));
+return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;
+},custom:function(from,to,unit){this.startTime=now();
+this.start=from;
+this.end=to;
+this.unit=unit||this.unit||"px";
+this.now=this.start;
+this.pos=this.state=0;
+this.update();
+var self=this;
+function t(gotoEnd){return self.step(gotoEnd);
+}t.elem=this.elem;
+jQuery.timers.push(t);
+if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;
+for(var i=0;
+i<timers.length;
+i++){if(!timers[i]()){timers.splice(i--,1);
+}}if(!timers.length){clearInterval(jQuery.timerId);
+jQuery.timerId=null;
+}},13);
+}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);
+this.options.show=true;
+this.custom(0,this.cur());
+if(this.prop=="width"||this.prop=="height"){this.elem.style[this.prop]="1px";
+}jQuery(this.elem).show();
+},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);
+this.options.hide=true;
+this.custom(this.cur(),0);
+},step:function(gotoEnd){var t=now();
+if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;
+this.pos=this.state=1;
+this.update();
+this.options.curAnim[this.prop]=true;
+var done=true;
+for(var i in this.options.curAnim){if(this.options.curAnim[i]!==true){done=false;
+}}if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;
+this.elem.style.display=this.options.display;
+if(jQuery.css(this.elem,"display")=="none"){this.elem.style.display="block";
+}}if(this.options.hide){this.elem.style.display="none";
+}if(this.options.hide||this.options.show){for(var p in this.options.curAnim){jQuery.attr(this.elem.style,p,this.options.orig[p]);
+}}}if(done){this.options.complete.call(this.elem);
+}return false;
+}else{var n=t-this.startTime;
+this.state=n/this.options.duration;
+this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);
+this.now=this.start+((this.end-this.start)*this.pos);
+this.update();
+}return true;
+}};
+jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;
+},scrollTop:function(fx){fx.elem.scrollTop=fx.now;
+},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);
+},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;
+}}});
+jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;
+if(elem){with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";
+if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();
+add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));
+add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);
+}else{add(elem.offsetLeft,elem.offsetTop);
+while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);
+if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2){border(offsetParent);
+}if(!fixed&&css(offsetParent,"position")=="fixed"){fixed=true;
+}offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;
+offsetParent=offsetParent.offsetParent;
+}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display"))){add(-parent.scrollLeft,-parent.scrollTop);
+}if(mozilla&&css(parent,"overflow")!="visible"){border(parent);
+}parent=parent.parentNode;
+}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute")){add(-doc.body.offsetLeft,-doc.body.offsetTop);
+}if(fixed){add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));
+}}results={top:top,left:left};
+}}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));
+}function add(l,t){left+=parseInt(l,10)||0;
+top+=parseInt(t,10)||0;
+}return results;
+};
+jQuery.fn.extend({position:function(){var left=0,top=0,results;
+if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();
+offset.top-=num(this,"marginTop");
+offset.left-=num(this,"marginLeft");
+parentOffset.top+=num(offsetParent,"borderTopWidth");
+parentOffset.left+=num(offsetParent,"borderLeftWidth");
+results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};
+}return results;
+},offsetParent:function(){var offsetParent=this[0].offsetParent;
+while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,"position")=="static")){offsetParent=offsetParent.offsetParent;
+}return jQuery(offsetParent);
+}});
+jQuery.each(["Left","Top"],function(i,name){var method="scroll"+name;
+jQuery.fn[method]=function(val){if(!this[0]){return ;
+}return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;
+}):this[0]==window||this[0]==document?self[i?"pageYOffset":"pageXOffset"]||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];
+};
+});
+jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";
+jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);
+};
+jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);
+};
+});
+})();
+
+
+/* platform.js */
+SimileAjax.version="pre 2.3.0";
+SimileAjax.jQuery=jQuery.noConflict(true);
+if(typeof window["$"]=="undefined"){window.$=SimileAjax.jQuery;
+}SimileAjax.Platform.os={isMac:false,isWin:false,isWin32:false,isUnix:false};
+SimileAjax.Platform.browser={isIE:false,isNetscape:false,isMozilla:false,isFirefox:false,isOpera:false,isSafari:false,majorVersion:0,minorVersion:0};
+(function(){var C=navigator.appName.toLowerCase();
+var A=navigator.userAgent.toLowerCase();
+SimileAjax.Platform.os.isMac=(A.indexOf("mac")!=-1);
+SimileAjax.Platform.os.isWin=(A.indexOf("win")!=-1);
+SimileAjax.Platform.os.isWin32=SimileAjax.Platform.isWin&&(A.indexOf("95")!=-1||A.indexOf("98")!=-1||A.indexOf("nt")!=-1||A.indexOf("win32")!=-1||A.indexOf("32bit")!=-1);
+SimileAjax.Platform.os.isUnix=(A.indexOf("x11")!=-1);
+SimileAjax.Platform.browser.isIE=(C.indexOf("microsoft")!=-1);
+SimileAjax.Platform.browser.isNetscape=(C.indexOf("netscape")!=-1);
+SimileAjax.Platform.browser.isMozilla=(A.indexOf("mozilla")!=-1);
+SimileAjax.Platform.browser.isFirefox=(A.indexOf("firefox")!=-1);
+SimileAjax.Platform.browser.isOpera=(C.indexOf("opera")!=-1);
+SimileAjax.Platform.browser.isSafari=(C.indexOf("safari")!=-1);
+var E=function(G){var F=G.split(".");
+SimileAjax.Platform.browser.majorVersion=parseInt(F[0]);
+SimileAjax.Platform.browser.minorVersion=parseInt(F[1]);
+};
+var B=function(H,G,I){var F=H.indexOf(G,I);
+return F>=0?F:H.length;
+};
+if(SimileAjax.Platform.browser.isMozilla){var D=A.indexOf("mozilla/");
+if(D>=0){E(A.substring(D+8,B(A," ",D)));
+}}if(SimileAjax.Platform.browser.isIE){var D=A.indexOf("msie ");
+if(D>=0){E(A.substring(D+5,B(A,";",D)));
+}}if(SimileAjax.Platform.browser.isNetscape){var D=A.indexOf("rv:");
+if(D>=0){E(A.substring(D+3,B(A,")",D)));
+}}if(SimileAjax.Platform.browser.isFirefox){var D=A.indexOf("firefox/");
+if(D>=0){E(A.substring(D+8,B(A," ",D)));
+}}if(!("localeCompare" in String.prototype)){String.prototype.localeCompare=function(F){if(this<F){return -1;
+}else{if(this>F){return 1;
+}else{return 0;
+}}};
+}})();
+SimileAjax.Platform.getDefaultLocale=function(){return SimileAjax.Platform.clientLocale;
+};
+
+
+/* ajax.js */
+SimileAjax.ListenerQueue=function(A){this._listeners=[];
+this._wildcardHandlerName=A;
+};
+SimileAjax.ListenerQueue.prototype.add=function(A){this._listeners.push(A);
+};
+SimileAjax.ListenerQueue.prototype.remove=function(C){var A=this._listeners;
+for(var B=0;
+B<A.length;
+B++){if(A[B]==C){A.splice(B,1);
+break;
+}}};
+SimileAjax.ListenerQueue.prototype.fire=function(C,B){var A=[].concat(this._listeners);
+for(var D=0;
+D<A.length;
+D++){var E=A[D];
+if(C in E){try{E[C].apply(E,B);
+}catch(F){SimileAjax.Debug.exception("Error firing event of name "+C,F);
+}}else{if(this._wildcardHandlerName!=null&&this._wildcardHandlerName in E){try{E[this._wildcardHandlerName].apply(E,[C]);
+}catch(F){SimileAjax.Debug.exception("Error firing event of name "+C+" to wildcard handler",F);
+}}}}};
+
+
+/* data-structure.js */
+SimileAjax.Set=function(A){this._hash={};
+this._count=0;
+if(A instanceof Array){for(var B=0;
+B<A.length;
+B++){this.add(A[B]);
+}}else{if(A instanceof SimileAjax.Set){this.addSet(A);
+}}};
+SimileAjax.Set.prototype.add=function(A){if(!(A in this._hash)){this._hash[A]=true;
+this._count++;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.addSet=function(B){for(var A in B._hash){this.add(A);
+}};
+SimileAjax.Set.prototype.remove=function(A){if(A in this._hash){delete this._hash[A];
+this._count--;
+return true;
+}return false;
+};
+SimileAjax.Set.prototype.removeSet=function(B){for(var A in B._hash){this.remove(A);
+}};
+SimileAjax.Set.prototype.retainSet=function(B){for(var A in this._hash){if(!B.contains(A)){delete this._hash[A];
+this._count--;
+}}};
+SimileAjax.Set.prototype.contains=function(A){return(A in this._hash);
+};
+SimileAjax.Set.prototype.size=function(){return this._count;
+};
+SimileAjax.Set.prototype.toArray=function(){var A=[];
+for(var B in this._hash){A.push(B);
+}return A;
+};
+SimileAjax.Set.prototype.visit=function(A){for(var B in this._hash){if(A(B)==true){break;
+}}};
+SimileAjax.SortedArray=function(B,A){this._a=(A instanceof Array)?A:[];
+this._compare=B;
+};
+SimileAjax.SortedArray.prototype.add=function(C){var A=this;
+var B=this.find(function(D){return A._compare(D,C);
+});
+if(B<this._a.length){this._a.splice(B,0,C);
+}else{this._a.push(C);
+}};
+SimileAjax.SortedArray.prototype.remove=function(C){var A=this;
+var B=this.find(function(D){return A._compare(D,C);
+});
+while(B<this._a.length&&this._compare(this._a[B],C)==0){if(this._a[B]==C){this._a.splice(B,1);
+return true;
+}else{B++;
+}}return false;
+};
+SimileAjax.SortedArray.prototype.removeAll=function(){this._a=[];
+};
+SimileAjax.SortedArray.prototype.elementAt=function(A){return this._a[A];
+};
+SimileAjax.SortedArray.prototype.length=function(){return this._a.length;
+};
+SimileAjax.SortedArray.prototype.find=function(D){var B=0;
+var A=this._a.length;
+while(B<A){var C=Math.floor((B+A)/2);
+var E=D(this._a[C]);
+if(C==B){return E<0?B+1:B;
+}else{if(E<0){B=C;
+}else{A=C;
+}}}return B;
+};
+SimileAjax.SortedArray.prototype.getFirst=function(){return(this._a.length>0)?this._a[0]:null;
+};
+SimileAjax.SortedArray.prototype.getLast=function(){return(this._a.length>0)?this._a[this._a.length-1]:null;
+};
+SimileAjax.EventIndex=function(B){var A=this;
+this._unit=(B!=null)?B:SimileAjax.NativeDateUnit;
+this._events=new SimileAjax.SortedArray(function(C,D){return A._unit.compare(C.getStart(),D.getStart());
+});
+this._idToEvent={};
+this._indexed=true;
+};
+SimileAjax.EventIndex.prototype.getUnit=function(){return this._unit;
+};
+SimileAjax.EventIndex.prototype.getEvent=function(A){return this._idToEvent[A];
+};
+SimileAjax.EventIndex.prototype.add=function(A){this._events.add(A);
+this._idToEvent[A.getID()]=A;
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.removeAll=function(){this._events.removeAll();
+this._idToEvent={};
+this._indexed=false;
+};
+SimileAjax.EventIndex.prototype.getCount=function(){return this._events.length();
+};
+SimileAjax.EventIndex.prototype.getIterator=function(A,B){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._Iterator(this._events,A,B,this._unit);
+};
+SimileAjax.EventIndex.prototype.getReverseIterator=function(A,B){if(!this._indexed){this._index();
+}return new SimileAjax.EventIndex._ReverseIterator(this._events,A,B,this._unit);
+};
+SimileAjax.EventIndex.prototype.getAllIterator=function(){return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+SimileAjax.EventIndex.prototype.getEarliestDate=function(){var A=this._events.getFirst();
+return(A==null)?null:A.getStart();
+};
+SimileAjax.EventIndex.prototype.getLatestDate=function(){var A=this._events.getLast();
+if(A==null){return null;
+}if(!this._indexed){this._index();
+}var C=A._earliestOverlapIndex;
+var B=this._events.elementAt(C).getEnd();
+for(var D=C+1;
+D<this._events.length();
+D++){B=this._unit.later(B,this._events.elementAt(D).getEnd());
+}return B;
+};
+SimileAjax.EventIndex.prototype._index=function(){var E=this._events.length();
+for(var F=0;
+F<E;
+F++){var D=this._events.elementAt(F);
+D._earliestOverlapIndex=F;
+}var G=1;
+for(var F=0;
+F<E;
+F++){var D=this._events.elementAt(F);
+var C=D.getEnd();
+G=Math.max(G,F+1);
+while(G<E){var A=this._events.elementAt(G);
+var B=A.getStart();
+if(this._unit.compare(B,C)<0){A._earliestOverlapIndex=F;
+G++;
+}else{break;
+}}}this._indexed=true;
+};
+SimileAjax.EventIndex._Iterator=function(A,C,D,B){this._events=A;
+this._startDate=C;
+this._endDate=D;
+this._unit=B;
+this._currentIndex=A.find(function(E){return B.compare(E.getStart(),C);
+});
+if(this._currentIndex-1>=0){this._currentIndex=this._events.elementAt(this._currentIndex-1)._earliestOverlapIndex;
+}this._currentIndex--;
+this._maxIndex=A.find(function(E){return B.compare(E.getStart(),D);
+});
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._Iterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var A=this._next;
+this._findNext();
+return A;
+}else{return null;
+}},_findNext:function(){var B=this._unit;
+while((++this._currentIndex)<this._maxIndex){var A=this._events.elementAt(this._currentIndex);
+if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._ReverseIterator=function(A,C,D,B){this._events=A;
+this._startDate=C;
+this._endDate=D;
+this._unit=B;
+this._minIndex=A.find(function(E){return B.compare(E.getStart(),C);
+});
+if(this._minIndex-1>=0){this._minIndex=this._events.elementAt(this._minIndex-1)._earliestOverlapIndex;
+}this._maxIndex=A.find(function(E){return B.compare(E.getStart(),D);
+});
+this._currentIndex=this._maxIndex;
+this._hasNext=false;
+this._next=null;
+this._findNext();
+};
+SimileAjax.EventIndex._ReverseIterator.prototype={hasNext:function(){return this._hasNext;
+},next:function(){if(this._hasNext){var A=this._next;
+this._findNext();
+return A;
+}else{return null;
+}},_findNext:function(){var B=this._unit;
+while((--this._currentIndex)>=this._minIndex){var A=this._events.elementAt(this._currentIndex);
+if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
+this._hasNext=true;
+return ;
+}}this._next=null;
+this._hasNext=false;
+}};
+SimileAjax.EventIndex._AllIterator=function(A){this._events=A;
+this._index=0;
+};
+SimileAjax.EventIndex._AllIterator.prototype={hasNext:function(){return this._index<this._events.length();
+},next:function(){return this._index<this._events.length()?this._events.elementAt(this._index++):null;
+}};
+
+
+/* date-time.js */
+SimileAjax.DateTime=new Object();
+SimileAjax.DateTime.MILLISECOND=0;
+SimileAjax.DateTime.SECOND=1;
+SimileAjax.DateTime.MINUTE=2;
+SimileAjax.DateTime.HOUR=3;
+SimileAjax.DateTime.DAY=4;
+SimileAjax.DateTime.WEEK=5;
+SimileAjax.DateTime.MONTH=6;
+SimileAjax.DateTime.YEAR=7;
+SimileAjax.DateTime.DECADE=8;
+SimileAjax.DateTime.CENTURY=9;
+SimileAjax.DateTime.MILLENNIUM=10;
+SimileAjax.DateTime.EPOCH=-1;
+SimileAjax.DateTime.ERA=-2;
+SimileAjax.DateTime.gregorianUnitLengths=[];
+(function(){var B=SimileAjax.DateTime;
+var A=B.gregorianUnitLengths;
+A[B.MILLISECOND]=1;
+A[B.SECOND]=1000;
+A[B.MINUTE]=A[B.SECOND]*60;
+A[B.HOUR]=A[B.MINUTE]*60;
+A[B.DAY]=A[B.HOUR]*24;
+A[B.WEEK]=A[B.DAY]*7;
+A[B.MONTH]=A[B.DAY]*31;
+A[B.YEAR]=A[B.DAY]*365;
+A[B.DECADE]=A[B.YEAR]*10;
+A[B.CENTURY]=A[B.YEAR]*100;
+A[B.MILLENNIUM]=A[B.YEAR]*1000;
+})();
+SimileAjax.DateTime._dateRegexp=new RegExp("^(-?)([0-9]{4})("+["(-?([0-9]{2})(-?([0-9]{2}))?)","(-?([0-9]{3}))","(-?W([0-9]{2})(-?([1-7]))?)"].join("|")+")?$");
+SimileAjax.DateTime._timezoneRegexp=new RegExp("Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$");
+SimileAjax.DateTime._timeRegexp=new RegExp("^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$");
+SimileAjax.DateTime.setIso8601Date=function(G,C){var I=C.match(SimileAjax.DateTime._dateRegexp);
+if(!I){throw new Error("Invalid date string: "+C);
+}var B=(I[1]=="-")?-1:1;
+var J=B*I[2];
+var H=I[5];
+var D=I[7];
+var F=I[9];
+var A=I[11];
+var M=(I[13])?I[13]:1;
+G.setUTCFullYear(J);
+if(F){G.setUTCMonth(0);
+G.setUTCDate(Number(F));
+}else{if(A){G.setUTCMonth(0);
+G.setUTCDate(1);
+var L=G.getUTCDay();
+var K=(L)?L:7;
+var E=Number(M)+(7*Number(A));
+if(K<=4){G.setUTCDate(E+1-K);
+}else{G.setUTCDate(E+8-K);
+}}else{if(H){G.setUTCDate(1);
+G.setUTCMonth(H-1);
+}if(D){G.setUTCDate(D);
+}}}return G;
+};
+SimileAjax.DateTime.setIso8601Time=function(F,D){var G=D.match(SimileAjax.DateTime._timeRegexp);
+if(!G){SimileAjax.Debug.warn("Invalid time string: "+D);
+return false;
+}var A=G[1];
+var E=Number((G[3])?G[3]:0);
+var C=(G[5])?G[5]:0;
+var B=G[7]?(Number("0."+G[7])*1000):0;
+F.setUTCHours(A);
+F.setUTCMinutes(E);
+F.setUTCSeconds(C);
+F.setUTCMilliseconds(B);
+return F;
+};
+SimileAjax.DateTime.timezoneOffset=new Date().getTimezoneOffset();
+SimileAjax.DateTime.setIso8601=function(B,A){var D=null;
+var E=(A.indexOf("T")==-1)?A.split(" "):A.split("T");
+SimileAjax.DateTime.setIso8601Date(B,E[0]);
+if(E.length==2){var C=E[1].match(SimileAjax.DateTime._timezoneRegexp);
+if(C){if(C[0]=="Z"){D=0;
+}else{D=(Number(C[3])*60)+Number(C[5]);
+D*=((C[2]=="-")?1:-1);
+}E[1]=E[1].substr(0,E[1].length-C[0].length);
+}SimileAjax.DateTime.setIso8601Time(B,E[1]);
+}if(D==null){D=B.getTimezoneOffset();
+}B.setTime(B.getTime()+D*60000);
+return B;
+};
+SimileAjax.DateTime.parseIso8601DateTime=function(A){try{return SimileAjax.DateTime.setIso8601(new Date(0),A);
+}catch(B){return null;
+}};
+SimileAjax.DateTime.parseGregorianDateTime=function(F){if(F==null){return null;
+}else{if(F instanceof Date){return F;
+}}var B=F.toString();
+if(B.length>0&&B.length<8){var C=B.indexOf(" ");
+if(C>0){var A=parseInt(B.substr(0,C));
+var G=B.substr(C+1);
+if(G.toLowerCase()=="bc"){A=1-A;
+}}else{var A=parseInt(B);
+}var E=new Date(0);
+E.setUTCFullYear(A);
+return E;
+}try{return new Date(Date.parse(B));
+}catch(D){return null;
+}};
+SimileAjax.DateTime.roundDownToInterval=function(E,B,I,K,A){var F=I*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var J=new Date(E.getTime()+F);
+var C=function(L){L.setUTCMilliseconds(0);
+L.setUTCSeconds(0);
+L.setUTCMinutes(0);
+L.setUTCHours(0);
+};
+var D=function(L){C(L);
+L.setUTCDate(1);
+L.setUTCMonth(0);
+};
+switch(B){case SimileAjax.DateTime.MILLISECOND:var H=J.getUTCMilliseconds();
+J.setUTCMilliseconds(H-(H%K));
+break;
+case SimileAjax.DateTime.SECOND:J.setUTCMilliseconds(0);
+var H=J.getUTCSeconds();
+J.setUTCSeconds(H-(H%K));
+break;
+case SimileAjax.DateTime.MINUTE:J.setUTCMilliseconds(0);
+J.setUTCSeconds(0);
+var H=J.getUTCMinutes();
+J.setTime(J.getTime()-(H%K)*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:J.setUTCMilliseconds(0);
+J.setUTCSeconds(0);
+J.setUTCMinutes(0);
+var H=J.getUTCHours();
+J.setUTCHours(H-(H%K));
+break;
+case SimileAjax.DateTime.DAY:C(J);
+break;
+case SimileAjax.DateTime.WEEK:C(J);
+var G=(J.getUTCDay()+7-A)%7;
+J.setTime(J.getTime()-G*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+break;
+case SimileAjax.DateTime.MONTH:C(J);
+J.setUTCDate(1);
+var H=J.getUTCMonth();
+J.setUTCMonth(H-(H%K));
+break;
+case SimileAjax.DateTime.YEAR:D(J);
+var H=J.getUTCFullYear();
+J.setUTCFullYear(H-(H%K));
+break;
+case SimileAjax.DateTime.DECADE:D(J);
+J.setUTCFullYear(Math.floor(J.getUTCFullYear()/10)*10);
+break;
+case SimileAjax.DateTime.CENTURY:D(J);
+J.setUTCFullYear(Math.floor(J.getUTCFullYear()/100)*100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:D(J);
+J.setUTCFullYear(Math.floor(J.getUTCFullYear()/1000)*1000);
+break;
+}E.setTime(J.getTime()-F);
+};
+SimileAjax.DateTime.roundUpToInterval=function(C,F,D,A,B){var E=C.getTime();
+SimileAjax.DateTime.roundDownToInterval(C,F,D,A,B);
+if(C.getTime()<E){C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[F]*A);
+}};
+SimileAjax.DateTime.incrementByInterval=function(A,D,B){B=(typeof B=="undefined")?0:B;
+var E=B*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+var C=new Date(A.getTime()+E);
+switch(D){case SimileAjax.DateTime.MILLISECOND:C.setTime(C.getTime()+1);
+break;
+case SimileAjax.DateTime.SECOND:C.setTime(C.getTime()+1000);
+break;
+case SimileAjax.DateTime.MINUTE:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+break;
+case SimileAjax.DateTime.HOUR:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+break;
+case SimileAjax.DateTime.DAY:C.setUTCDate(C.getUTCDate()+1);
+break;
+case SimileAjax.DateTime.WEEK:C.setUTCDate(C.getUTCDate()+7);
+break;
+case SimileAjax.DateTime.MONTH:C.setUTCMonth(C.getUTCMonth()+1);
+break;
+case SimileAjax.DateTime.YEAR:C.setUTCFullYear(C.getUTCFullYear()+1);
+break;
+case SimileAjax.DateTime.DECADE:C.setUTCFullYear(C.getUTCFullYear()+10);
+break;
+case SimileAjax.DateTime.CENTURY:C.setUTCFullYear(C.getUTCFullYear()+100);
+break;
+case SimileAjax.DateTime.MILLENNIUM:C.setUTCFullYear(C.getUTCFullYear()+1000);
+break;
+}A.setTime(C.getTime()-E);
+};
+SimileAjax.DateTime.removeTimeZoneOffset=function(A,B){return new Date(A.getTime()+B*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+SimileAjax.DateTime.getTimezone=function(){var A=new Date().getTimezoneOffset();
+return A/-60;
+};
+
+
+/* debug.js */
+SimileAjax.Debug={silent:false};
+SimileAjax.Debug.log=function(B){var A;
+if("console" in window&&"log" in window.console){A=function(C){console.log(C);
+};
+}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
+}};
+}SimileAjax.Debug.log=A;
+A(B);
+};
+SimileAjax.Debug.warn=function(B){var A;
+if("console" in window&&"warn" in window.console){A=function(C){console.warn(C);
+};
+}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
+}};
+}SimileAjax.Debug.warn=A;
+A(B);
+};
+SimileAjax.Debug.exception=function(B,D){var A,C=SimileAjax.parseURLParameters();
+if(C.errors=="throw"||SimileAjax.params.errors=="throw"){A=function(F,E){throw (F);
+};
+}else{if("console" in window&&"error" in window.console){A=function(F,E){if(E!=null){console.error(E+" %o",F);
+}else{console.error(F);
+}throw (F);
+};
+}else{A=function(F,E){if(!SimileAjax.Debug.silent){alert("Caught exception: "+E+"\n\nDetails: "+("description" in F?F.description:F));
+}throw (F);
+};
+}}SimileAjax.Debug.exception=A;
+A(B,D);
+};
+SimileAjax.Debug.objectToString=function(A){return SimileAjax.Debug._objectToString(A,"");
+};
+SimileAjax.Debug._objectToString=function(D,C){var B=C+" ";
+if(typeof D=="object"){var A="{";
+for(E in D){A+=B+E+": "+SimileAjax.Debug._objectToString(D[E],B)+"\n";
+}A+=C+"}";
+return A;
+}else{if(typeof D=="array"){var A="[";
+for(var E=0;
+E<D.length;
+E++){A+=SimileAjax.Debug._objectToString(D[E],B)+"\n";
+}A+=C+"]";
+return A;
+}else{return D;
+}}};
+
+
+/* dom.js */
+SimileAjax.DOM=new Object();
+SimileAjax.DOM.registerEventWithObject=function(C,A,D,B){SimileAjax.DOM.registerEvent(C,A,function(F,E,G){return D[B].call(D,F,E,G);
+});
+};
+SimileAjax.DOM.registerEvent=function(C,B,D){var A=function(E){E=(E)?E:((event)?event:null);
+if(E){var F=(E.target)?E.target:((E.srcElement)?E.srcElement:null);
+if(F){F=(F.nodeType==1||F.nodeType==9)?F:F.parentNode;
+}return D(C,E,F);
+}return true;
+};
+if(SimileAjax.Platform.browser.isIE){C.attachEvent("on"+B,A);
+}else{C.addEventListener(B,A,false);
+}};
+SimileAjax.DOM.getPageCoordinates=function(B){var E=0;
+var D=0;
+if(B.nodeType!=1){B=B.parentNode;
+}var C=B;
+while(C!=null){E+=C.offsetLeft;
+D+=C.offsetTop;
+C=C.offsetParent;
+}var A=document.body;
+while(B!=null&&B!=A){if("scrollLeft" in B){E-=B.scrollLeft;
+D-=B.scrollTop;
+}B=B.parentNode;
+}return{left:E,top:D};
+};
+SimileAjax.DOM.getSize=function(B){var A=this.getStyle(B,"width");
+var C=this.getStyle(B,"height");
+if(A.indexOf("px")>-1){A=A.replace("px","");
+}if(C.indexOf("px")>-1){C=C.replace("px","");
+}return{w:A,h:C};
+};
+SimileAjax.DOM.getStyle=function(B,A){if(B.currentStyle){var C=B.currentStyle[A];
+}else{if(window.getComputedStyle){var C=document.defaultView.getComputedStyle(B,null).getPropertyValue(A);
+}else{var C="";
+}}return C;
+};
+SimileAjax.DOM.getEventRelativeCoordinates=function(B,C){if(SimileAjax.Platform.browser.isIE){if(B.type=="mousewheel"){var A=SimileAjax.DOM.getPageCoordinates(C);
+return{x:B.clientX-A.left,y:B.clientY-A.top};
+}else{return{x:B.offsetX,y:B.offsetY};
+}}else{var A=SimileAjax.DOM.getPageCoordinates(C);
+if((B.type=="DOMMouseScroll")&&SimileAjax.Platform.browser.isFirefox&&(SimileAjax.Platform.browser.majorVersion==2)){return{x:B.screenX-A.left,y:B.screenY-A.top};
+}else{return{x:B.pageX-A.left,y:B.pageY-A.top};
+}}};
+SimileAjax.DOM.getEventPageCoordinates=function(A){if(SimileAjax.Platform.browser.isIE){return{x:A.clientX+document.body.scrollLeft,y:A.clientY+document.body.scrollTop};
+}else{return{x:A.pageX,y:A.pageY};
+}};
+SimileAjax.DOM.hittest=function(A,C,B){return SimileAjax.DOM._hittest(document.body,A,C,B);
+};
+SimileAjax.DOM._hittest=function(C,L,K,A){var M=C.childNodes;
+outer:for(var G=0;
+G<M.length;
+G++){var H=M[G];
+for(var F=0;
+F<A.length;
+F++){if(H==A[F]){continue outer;
+}}if(H.offsetWidth==0&&H.offsetHeight==0){var B=SimileAjax.DOM._hittest(H,L,K,A);
+if(B!=H){return B;
+}}else{var J=0;
+var E=0;
+var D=H;
+while(D){J+=D.offsetTop;
+E+=D.offsetLeft;
+D=D.offsetParent;
+}if(E<=L&&J<=K&&(L-E)<H.offsetWidth&&(K-J)<H.offsetHeight){return SimileAjax.DOM._hittest(H,L,K,A);
+}else{if(H.nodeType==1&&H.tagName=="TR"){var I=SimileAjax.DOM._hittest(H,L,K,A);
+if(I!=H){return I;
+}}}}}return C;
+};
+SimileAjax.DOM.cancelEvent=function(A){A.returnValue=false;
+A.cancelBubble=true;
+if("preventDefault" in A){A.preventDefault();
+}};
+SimileAjax.DOM.appendClassName=function(D,A){var C=D.className.split(" ");
+for(var B=0;
+B<C.length;
+B++){if(C[B]==A){return ;
+}}C.push(A);
+D.className=C.join(" ");
+};
+SimileAjax.DOM.createInputElement=function(A){var B=document.createElement("div");
+B.innerHTML="<input type='"+A+"' />";
+return B.firstChild;
+};
+SimileAjax.DOM.createDOMFromTemplate=function(A){var B={};
+B.elmt=SimileAjax.DOM._createDOMFromTemplate(A,B,null);
+return B;
+};
+SimileAjax.DOM._createDOMFromTemplate=function(F,G,D){if(F==null){return null;
+}else{if(typeof F!="object"){var C=document.createTextNode(F);
+if(D!=null){D.appendChild(C);
+}return C;
+}else{var A=null;
+if("tag" in F){var J=F.tag;
+if(D!=null){if(J=="tr"){A=D.insertRow(D.rows.length);
+}else{if(J=="td"){A=D.insertCell(D.cells.length);
+}}}if(A==null){A=J=="input"?SimileAjax.DOM.createInputElement(F.type):document.createElement(J);
+if(D!=null){D.appendChild(A);
+}}}else{A=F.elmt;
+if(D!=null){D.appendChild(A);
+}}for(var B in F){var H=F[B];
+if(B=="field"){G[H]=A;
+}else{if(B=="className"){A.className=H;
+}else{if(B=="id"){A.id=H;
+}else{if(B=="title"){A.title=H;
+}else{if(B=="type"&&A.tagName=="input"){}else{if(B=="style"){for(n in H){var I=H[n];
+if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
+}A.style[n]=I;
+}}else{if(B=="children"){for(var E=0;
+E<H.length;
+E++){SimileAjax.DOM._createDOMFromTemplate(H[E],G,A);
+}}else{if(B!="tag"&&B!="elmt"){A.setAttribute(B,H);
+}}}}}}}}}return A;
+}}};
+SimileAjax.DOM._cachedParent=null;
+SimileAjax.DOM.createElementFromString=function(A){if(SimileAjax.DOM._cachedParent==null){SimileAjax.DOM._cachedParent=document.createElement("div");
+}SimileAjax.DOM._cachedParent.innerHTML=A;
+return SimileAjax.DOM._cachedParent.firstChild;
+};
+SimileAjax.DOM.createDOMFromString=function(A,C,D){var B=typeof A=="string"?document.createElement(A):A;
+B.innerHTML=C;
+var E={elmt:B};
+SimileAjax.DOM._processDOMChildrenConstructedFromString(E,B,D!=null?D:{});
+return E;
+};
+SimileAjax.DOM._processDOMConstructedFromString=function(D,A,B){var E=A.id;
+if(E!=null&&E.length>0){A.removeAttribute("id");
+if(E in B){var C=A.parentNode;
+C.insertBefore(B[E],A);
+C.removeChild(A);
+D[E]=B[E];
+return ;
+}else{D[E]=A;
+}}if(A.hasChildNodes()){SimileAjax.DOM._processDOMChildrenConstructedFromString(D,A,B);
+}};
+SimileAjax.DOM._processDOMChildrenConstructedFromString=function(E,B,D){var C=B.firstChild;
+while(C!=null){var A=C.nextSibling;
+if(C.nodeType==1){SimileAjax.DOM._processDOMConstructedFromString(E,C,D);
+}C=A;
+}};
+
+
+/* graphics.js */
+SimileAjax.Graphics=new Object();
+SimileAjax.Graphics.pngIsTranslucent=(!SimileAjax.Platform.browser.isIE)||(SimileAjax.Platform.browser.majorVersion>6);
+if(!SimileAjax.Graphics.pngIsTranslucent){SimileAjax.includeCssFile(document,SimileAjax.urlPrefix+"styles/graphics-ie6.css");
+}SimileAjax.Graphics._createTranslucentImage1=function(A,C){var B=document.createElement("img");
+B.setAttribute("src",A);
+if(C!=null){B.style.verticalAlign=C;
+}return B;
+};
+SimileAjax.Graphics._createTranslucentImage2=function(A,C){var B=document.createElement("img");
+B.style.width="1px";
+B.style.height="1px";
+B.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image')";
+B.style.verticalAlign=(C!=null)?C:"middle";
+return B;
+};
+SimileAjax.Graphics.createTranslucentImage=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImage1:SimileAjax.Graphics._createTranslucentImage2;
+SimileAjax.Graphics._createTranslucentImageHTML1=function(A,B){return'<img src="'+A+'"'+(B!=null?' style="vertical-align: '+B+';"':"")+" />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2=function(A,C){var B="width: 1px; height: 1px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image');"+(C!=null?" vertical-align: "+C+";":"");
+return"<img src='"+A+"' style=\""+B+'" />';
+};
+SimileAjax.Graphics.createTranslucentImageHTML=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImageHTML1:SimileAjax.Graphics._createTranslucentImageHTML2;
+SimileAjax.Graphics.setOpacity=function(B,A){if(SimileAjax.Platform.browser.isIE){B.style.filter="progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity="+A+")";
+}else{var C=(A/100).toString();
+B.style.opacity=C;
+B.style.MozOpacity=C;
+}};
+SimileAjax.Graphics.bubbleConfig={containerCSSClass:"simileAjax-bubble-container",innerContainerCSSClass:"simileAjax-bubble-innerContainer",contentContainerCSSClass:"simileAjax-bubble-contentContainer",borderGraphicSize:50,borderGraphicCSSClassPrefix:"simileAjax-bubble-border-",arrowGraphicTargetOffset:33,arrowGraphicLength:100,arrowGraphicWidth:49,arrowGraphicCSSClassPrefix:"simileAjax-bubble-arrow-",closeGraphicCSSClass:"simileAjax-bubble-close",extraPadding:20};
+SimileAjax.Graphics.createBubbleForContentAndPoint=function(F,E,C,B,D,A){if(typeof B!="number"){B=300;
+}if(typeof A!="number"){A=0;
+}F.style.position="absolute";
+F.style.left="-5000px";
+F.style.top="0px";
+F.style.width=B+"px";
+document.body.appendChild(F);
+window.setTimeout(function(){var H=F.scrollWidth+10;
+var J=F.scrollHeight+10;
+var G=0;
+if(A>0&&J>A){J=A;
+G=H-25;
+}var I=SimileAjax.Graphics.createBubbleForPoint(E,C,H,J,D);
+document.body.removeChild(F);
+F.style.position="static";
+F.style.left="";
+F.style.top="";
+if(G>0){var K=document.createElement("div");
+F.style.width="";
+K.style.width=G+"px";
+K.appendChild(F);
+I.content.appendChild(K);
+}else{F.style.width=H+"px";
+I.content.appendChild(F);
+}},200);
+};
+SimileAjax.Graphics.createBubbleForPoint=function(B,A,J,N,F){J=parseInt(J,10);
+N=parseInt(N,10);
+var E=SimileAjax.Graphics.bubbleConfig;
+var M=SimileAjax.Graphics.pngIsTranslucent?"pngTranslucent":"pngNotTranslucent";
+var L=J+2*E.borderGraphicSize;
+var O=N+2*E.borderGraphicSize;
+var K=function(S){return S+" "+S+"-"+M;
+};
+var H=document.createElement("div");
+H.className=K(E.containerCSSClass);
+H.style.width=J+"px";
+H.style.height=N+"px";
+var D=document.createElement("div");
+D.className=K(E.innerContainerCSSClass);
+H.appendChild(D);
+var I=function(){if(!Q._closed){document.body.removeChild(Q._div);
+Q._doc=null;
+Q._div=null;
+Q._content=null;
+Q._closed=true;
+}};
+var Q={_closed:false};
+var R=SimileAjax.WindowManager.pushLayer(I,true,H);
+Q._div=H;
+Q.close=function(){SimileAjax.WindowManager.popLayer(R);
+};
+var G=function(T){var S=document.createElement("div");
+S.className=K(E.borderGraphicCSSClassPrefix+T);
+D.appendChild(S);
+};
+G("top-left");
+G("top-right");
+G("bottom-left");
+G("bottom-right");
+G("left");
+G("right");
+G("top");
+G("bottom");
+var C=document.createElement("div");
+C.className=K(E.contentContainerCSSClass);
+D.appendChild(C);
+Q.content=C;
+var P=document.createElement("div");
+P.className=K(E.closeGraphicCSSClass);
+D.appendChild(P);
+SimileAjax.WindowManager.registerEventWithObject(P,"click",Q,"close");
+(function(){var Y=SimileAjax.Graphics.getWindowDimensions();
+var T=Y.w;
+var U=Y.h;
+var V=Math.ceil(E.arrowGraphicWidth/2);
+var Z=function(b){var a=document.createElement("div");
+a.className=K(E.arrowGraphicCSSClassPrefix+"point-"+b);
+D.appendChild(a);
+return a;
+};
+if(B-V-E.borderGraphicSize-E.extraPadding>0&&B+V+E.borderGraphicSize+E.extraPadding<T){var X=B-Math.round(J/2);
+X=B<(T/2)?Math.max(X,E.extraPadding+E.borderGraphicSize):Math.min(X,T-E.extraPadding-E.borderGraphicSize-J);
+if((F&&F=="top")||(!F&&(A-E.arrowGraphicTargetOffset-N-E.borderGraphicSize-E.extraPadding>0))){var S=Z("down");
+S.style.left=(B-V-X)+"px";
+H.style.left=X+"px";
+H.style.top=(A-E.arrowGraphicTargetOffset-N)+"px";
+return ;
+}else{if((F&&F=="bottom")||(!F&&(A+E.arrowGraphicTargetOffset+N+E.borderGraphicSize+E.extraPadding<U))){var S=Z("up");
+S.style.left=(B-V-X)+"px";
+H.style.left=X+"px";
+H.style.top=(A+E.arrowGraphicTargetOffset)+"px";
+return ;
+}}}var W=A-Math.round(N/2);
+W=A<(U/2)?Math.max(W,E.extraPadding+E.borderGraphicSize):Math.min(W,U-E.extraPadding-E.borderGraphicSize-N);
+if((F&&F=="left")||(!F&&(B-E.arrowGraphicTargetOffset-J-E.borderGraphicSize-E.extraPadding>0))){var S=Z("right");
+S.style.top=(A-V-W)+"px";
+H.style.top=W+"px";
+H.style.left=(B-E.arrowGraphicTargetOffset-J)+"px";
+}else{var S=Z("left");
+S.style.top=(A-V-W)+"px";
+H.style.top=W+"px";
+H.style.left=(B+E.arrowGraphicTargetOffset)+"px";
+}})();
+document.body.appendChild(H);
+return Q;
+};
+SimileAjax.Graphics.getWindowDimensions=function(){if(typeof window.innerHeight=="number"){return{w:window.innerWidth,h:window.innerHeight};
+}else{if(document.documentElement&&document.documentElement.clientHeight){return{w:document.documentElement.clientWidth,h:document.documentElement.clientHeight};
+}else{if(document.body&&document.body.clientHeight){return{w:document.body.clientWidth,h:document.body.clientHeight};
+}}}};
+SimileAjax.Graphics.createMessageBubble=function(H){var G=H.createElement("div");
+if(SimileAjax.Graphics.pngIsTranslucent){var I=H.createElement("div");
+I.style.height="33px";
+I.style.background="url("+SimileAjax.urlPrefix+"images/message-top-left.png) top left no-repeat";
+I.style.paddingLeft="44px";
+G.appendChild(I);
+var D=H.createElement("div");
+D.style.height="33px";
+D.style.background="url("+SimileAjax.urlPrefix+"images/message-top-right.png) top right no-repeat";
+I.appendChild(D);
+var F=H.createElement("div");
+F.style.background="url("+SimileAjax.urlPrefix+"images/message-left.png) top left repeat-y";
+F.style.paddingLeft="44px";
+G.appendChild(F);
+var B=H.createElement("div");
+B.style.background="url("+SimileAjax.urlPrefix+"images/message-right.png) top right repeat-y";
+B.style.paddingRight="44px";
+F.appendChild(B);
+var C=H.createElement("div");
+B.appendChild(C);
+var E=H.createElement("div");
+E.style.height="55px";
+E.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-left.png) bottom left no-repeat";
+E.style.paddingLeft="44px";
+G.appendChild(E);
+var A=H.createElement("div");
+A.style.height="55px";
+A.style.background="url("+SimileAjax.urlPrefix+"images/message-bottom-right.png) bottom right no-repeat";
+E.appendChild(A);
+}else{G.style.border="2px solid #7777AA";
+G.style.padding="20px";
+G.style.background="white";
+SimileAjax.Graphics.setOpacity(G,90);
+var C=H.createElement("div");
+G.appendChild(C);
+}return{containerDiv:G,contentDiv:C};
+};
+SimileAjax.Graphics.createAnimation=function(B,E,D,C,A){return new SimileAjax.Graphics._Animation(B,E,D,C,A);
+};
+SimileAjax.Graphics._Animation=function(B,E,D,C,A){this.f=B;
+this.cont=(typeof A=="function")?A:function(){};
+this.from=E;
+this.to=D;
+this.current=E;
+this.duration=C;
+this.start=new Date().getTime();
+this.timePassed=0;
+};
+SimileAjax.Graphics._Animation.prototype.run=function(){var A=this;
+window.setTimeout(function(){A.step();
+},50);
+};
+SimileAjax.Graphics._Animation.prototype.step=function(){this.timePassed+=50;
+var A=this.timePassed/this.duration;
+var B=-Math.cos(A*Math.PI)/2+0.5;
+var D=B*(this.to-this.from)+this.from;
+try{this.f(D,D-this.current);
+}catch(C){}this.current=D;
+if(this.timePassed<this.duration){this.run();
+}else{this.f(this.to,0);
+this["cont"]();
+}};
+SimileAjax.Graphics.createStructuredDataCopyButton=function(F,B,D,E){var G=document.createElement("div");
+G.style.position="relative";
+G.style.display="inline";
+G.style.width=B+"px";
+G.style.height=D+"px";
+G.style.overflow="hidden";
+G.style.margin="2px";
+if(SimileAjax.Graphics.pngIsTranslucent){G.style.background="url("+F+") no-repeat";
+}else{G.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+F+"', sizingMethod='image')";
+}var A;
+if(SimileAjax.Platform.browser.isIE){A="filter:alpha(opacity=0)";
+}else{A="opacity: 0";
+}G.innerHTML="<textarea rows='1' autocomplete='off' value='none' style='"+A+"' />";
+var C=G.firstChild;
+C.style.width=B+"px";
+C.style.height=D+"px";
+C.onmousedown=function(H){H=(H)?H:((event)?event:null);
+if(H.button==2){C.value=E();
+C.select();
+}};
+return G;
+};
+SimileAjax.Graphics.getWidthHeight=function(C){var A,B;
+if(C.getBoundingClientRect==null){A=C.offsetWidth;
+B=C.offsetHeight;
+}else{var D=C.getBoundingClientRect();
+A=Math.ceil(D.right-D.left);
+B=Math.ceil(D.bottom-D.top);
+}return{width:A,height:B};
+};
+SimileAjax.Graphics.getFontRenderingContext=function(A,B){return new SimileAjax.Graphics._FontRenderingContext(A,B);
+};
+SimileAjax.Graphics._FontRenderingContext=function(A,B){this._elmt=A;
+this._elmt.style.visibility="hidden";
+if(typeof B=="string"){this._elmt.style.width=B;
+}else{if(typeof B=="number"){this._elmt.style.width=B+"px";
+}}};
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose=function(){this._elmt=null;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.update=function(){this._elmt.innerHTML="A";
+this._lineHeight=this._elmt.offsetHeight;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize=function(D,B){var C=this._elmt;
+C.innerHTML=D;
+C.className=B===undefined?"":B;
+var A=SimileAjax.Graphics.getWidthHeight(C);
+C.className="";
+return A;
+};
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight=function(){return this._lineHeight;
+};
+
+
+/* history.js */
+SimileAjax.History={maxHistoryLength:10,historyFile:"__history__.html",enabled:true,_initialized:false,_listeners:new SimileAjax.ListenerQueue(),_actions:[],_baseIndex:0,_currentIndex:0,_plainDocumentTitle:document.title};
+SimileAjax.History.formatHistoryEntryTitle=function(A){return SimileAjax.History._plainDocumentTitle+" {"+A+"}";
+};
+SimileAjax.History.initialize=function(){if(SimileAjax.History._initialized){return ;
+}if(SimileAjax.History.enabled){var A=document.createElement("iframe");
+A.id="simile-ajax-history";
+A.style.position="absolute";
+A.style.width="10px";
+A.style.height="10px";
+A.style.top="0px";
+A.style.left="0px";
+A.style.visibility="hidden";
+A.src=SimileAjax.History.historyFile+"?0";
+document.body.appendChild(A);
+SimileAjax.DOM.registerEvent(A,"load",SimileAjax.History._handleIFrameOnLoad);
+SimileAjax.History._iframe=A;
+}SimileAjax.History._initialized=true;
+};
+SimileAjax.History.addListener=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.add(A);
+};
+SimileAjax.History.removeListener=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.remove(A);
+};
+SimileAjax.History.addAction=function(A){SimileAjax.History.initialize();
+SimileAjax.History._listeners.fire("onBeforePerform",[A]);
+window.setTimeout(function(){try{A.perform();
+SimileAjax.History._listeners.fire("onAfterPerform",[A]);
+if(SimileAjax.History.enabled){SimileAjax.History._actions=SimileAjax.History._actions.slice(0,SimileAjax.History._currentIndex-SimileAjax.History._baseIndex);
+SimileAjax.History._actions.push(A);
+SimileAjax.History._currentIndex++;
+var C=SimileAjax.History._actions.length-SimileAjax.History.maxHistoryLength;
+if(C>0){SimileAjax.History._actions=SimileAjax.History._actions.slice(C);
+SimileAjax.History._baseIndex+=C;
+}try{SimileAjax.History._iframe.contentWindow.location.search="?"+SimileAjax.History._currentIndex;
+}catch(B){var D=SimileAjax.History.formatHistoryEntryTitle(A.label);
+document.title=D;
+}}}catch(B){SimileAjax.Debug.exception(B,"Error adding action {"+A.label+"} to history");
+}},0);
+};
+SimileAjax.History.addLengthyAction=function(B,A,C){SimileAjax.History.addAction({perform:B,undo:A,label:C,uiLayer:SimileAjax.WindowManager.getBaseLayer(),lengthy:true});
+};
+SimileAjax.History._handleIFrameOnLoad=function(){try{var B=SimileAjax.History._iframe.contentWindow.location.search;
+var F=(B.length==0)?0:Math.max(0,parseInt(B.substr(1)));
+var D=function(){var G=F-SimileAjax.History._currentIndex;
+SimileAjax.History._currentIndex+=G;
+SimileAjax.History._baseIndex+=G;
+SimileAjax.History._iframe.contentWindow.location.search="?"+F;
+};
+if(F<SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeUndoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex>F&&SimileAjax.History._currentIndex>SimileAjax.History._baseIndex){SimileAjax.History._currentIndex--;
+var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{G.undo();
+}catch(H){SimileAjax.Debug.exception(H,"History: Failed to undo action {"+G.label+"}");
+}}SimileAjax.History._listeners.fire("onAfterUndoSeveral",[]);
+D();
+},0);
+}else{if(F>SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeRedoSeveral",[]);
+window.setTimeout(function(){while(SimileAjax.History._currentIndex<F&&SimileAjax.History._currentIndex-SimileAjax.History._baseIndex<SimileAjax.History._actions.length){var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
+try{G.perform();
+}catch(H){SimileAjax.Debug.exception(H,"History: Failed to redo action {"+G.label+"}");
+}SimileAjax.History._currentIndex++;
+}SimileAjax.History._listeners.fire("onAfterRedoSeveral",[]);
+D();
+},0);
+}else{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+var E=(A>=0&&A<SimileAjax.History._actions.length)?SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[A].label):SimileAjax.History._plainDocumentTitle;
+SimileAjax.History._iframe.contentWindow.document.title=E;
+document.title=E;
+}}}catch(C){}};
+SimileAjax.History.getNextUndoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
+return SimileAjax.History._actions[A];
+}catch(B){return null;
+}};
+SimileAjax.History.getNextRedoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex;
+return SimileAjax.History._actions[A];
+}catch(B){return null;
+}};
+
+
+/* html.js */
+SimileAjax.HTML=new Object();
+SimileAjax.HTML._e2uHash={};
+(function(){var A=SimileAjax.HTML._e2uHash;
+A["nbsp"]="\u00A0[space]";
+A["iexcl"]="\u00A1";
+A["cent"]="\u00A2";
+A["pound"]="\u00A3";
+A["curren"]="\u00A4";
+A["yen"]="\u00A5";
+A["brvbar"]="\u00A6";
+A["sect"]="\u00A7";
+A["uml"]="\u00A8";
+A["copy"]="\u00A9";
+A["ordf"]="\u00AA";
+A["laquo"]="\u00AB";
+A["not"]="\u00AC";
+A["shy"]="\u00AD";
+A["reg"]="\u00AE";
+A["macr"]="\u00AF";
+A["deg"]="\u00B0";
+A["plusmn"]="\u00B1";
+A["sup2"]="\u00B2";
+A["sup3"]="\u00B3";
+A["acute"]="\u00B4";
+A["micro"]="\u00B5";
+A["para"]="\u00B6";
+A["middot"]="\u00B7";
+A["cedil"]="\u00B8";
+A["sup1"]="\u00B9";
+A["ordm"]="\u00BA";
+A["raquo"]="\u00BB";
+A["frac14"]="\u00BC";
+A["frac12"]="\u00BD";
+A["frac34"]="\u00BE";
+A["iquest"]="\u00BF";
+A["Agrave"]="\u00C0";
+A["Aacute"]="\u00C1";
+A["Acirc"]="\u00C2";
+A["Atilde"]="\u00C3";
+A["Auml"]="\u00C4";
+A["Aring"]="\u00C5";
+A["AElig"]="\u00C6";
+A["Ccedil"]="\u00C7";
+A["Egrave"]="\u00C8";
+A["Eacute"]="\u00C9";
+A["Ecirc"]="\u00CA";
+A["Euml"]="\u00CB";
+A["Igrave"]="\u00CC";
+A["Iacute"]="\u00CD";
+A["Icirc"]="\u00CE";
+A["Iuml"]="\u00CF";
+A["ETH"]="\u00D0";
+A["Ntilde"]="\u00D1";
+A["Ograve"]="\u00D2";
+A["Oacute"]="\u00D3";
+A["Ocirc"]="\u00D4";
+A["Otilde"]="\u00D5";
+A["Ouml"]="\u00D6";
+A["times"]="\u00D7";
+A["Oslash"]="\u00D8";
+A["Ugrave"]="\u00D9";
+A["Uacute"]="\u00DA";
+A["Ucirc"]="\u00DB";
+A["Uuml"]="\u00DC";
+A["Yacute"]="\u00DD";
+A["THORN"]="\u00DE";
+A["szlig"]="\u00DF";
+A["agrave"]="\u00E0";
+A["aacute"]="\u00E1";
+A["acirc"]="\u00E2";
+A["atilde"]="\u00E3";
+A["auml"]="\u00E4";
+A["aring"]="\u00E5";
+A["aelig"]="\u00E6";
+A["ccedil"]="\u00E7";
+A["egrave"]="\u00E8";
+A["eacute"]="\u00E9";
+A["ecirc"]="\u00EA";
+A["euml"]="\u00EB";
+A["igrave"]="\u00EC";
+A["iacute"]="\u00ED";
+A["icirc"]="\u00EE";
+A["iuml"]="\u00EF";
+A["eth"]="\u00F0";
+A["ntilde"]="\u00F1";
+A["ograve"]="\u00F2";
+A["oacute"]="\u00F3";
+A["ocirc"]="\u00F4";
+A["otilde"]="\u00F5";
+A["ouml"]="\u00F6";
+A["divide"]="\u00F7";
+A["oslash"]="\u00F8";
+A["ugrave"]="\u00F9";
+A["uacute"]="\u00FA";
+A["ucirc"]="\u00FB";
+A["uuml"]="\u00FC";
+A["yacute"]="\u00FD";
+A["thorn"]="\u00FE";
+A["yuml"]="\u00FF";
+A["quot"]="\u0022";
+A["amp"]="\u0026";
+A["lt"]="\u003C";
+A["gt"]="\u003E";
+A["OElig"]="";
+A["oelig"]="\u0153";
+A["Scaron"]="\u0160";
+A["scaron"]="\u0161";
+A["Yuml"]="\u0178";
+A["circ"]="\u02C6";
+A["tilde"]="\u02DC";
+A["ensp"]="\u2002";
+A["emsp"]="\u2003";
+A["thinsp"]="\u2009";
+A["zwnj"]="\u200C";
+A["zwj"]="\u200D";
+A["lrm"]="\u200E";
+A["rlm"]="\u200F";
+A["ndash"]="\u2013";
+A["mdash"]="\u2014";
+A["lsquo"]="\u2018";
+A["rsquo"]="\u2019";
+A["sbquo"]="\u201A";
+A["ldquo"]="\u201C";
+A["rdquo"]="\u201D";
+A["bdquo"]="\u201E";
+A["dagger"]="\u2020";
+A["Dagger"]="\u2021";
+A["permil"]="\u2030";
+A["lsaquo"]="\u2039";
+A["rsaquo"]="\u203A";
+A["euro"]="\u20AC";
+A["fnof"]="\u0192";
+A["Alpha"]="\u0391";
+A["Beta"]="\u0392";
+A["Gamma"]="\u0393";
+A["Delta"]="\u0394";
+A["Epsilon"]="\u0395";
+A["Zeta"]="\u0396";
+A["Eta"]="\u0397";
+A["Theta"]="\u0398";
+A["Iota"]="\u0399";
+A["Kappa"]="\u039A";
+A["Lambda"]="\u039B";
+A["Mu"]="\u039C";
+A["Nu"]="\u039D";
+A["Xi"]="\u039E";
+A["Omicron"]="\u039F";
+A["Pi"]="\u03A0";
+A["Rho"]="\u03A1";
+A["Sigma"]="\u03A3";
+A["Tau"]="\u03A4";
+A["Upsilon"]="\u03A5";
+A["Phi"]="\u03A6";
+A["Chi"]="\u03A7";
+A["Psi"]="\u03A8";
+A["Omega"]="\u03A9";
+A["alpha"]="\u03B1";
+A["beta"]="\u03B2";
+A["gamma"]="\u03B3";
+A["delta"]="\u03B4";
+A["epsilon"]="\u03B5";
+A["zeta"]="\u03B6";
+A["eta"]="\u03B7";
+A["theta"]="\u03B8";
+A["iota"]="\u03B9";
+A["kappa"]="\u03BA";
+A["lambda"]="\u03BB";
+A["mu"]="\u03BC";
+A["nu"]="\u03BD";
+A["xi"]="\u03BE";
+A["omicron"]="\u03BF";
+A["pi"]="\u03C0";
+A["rho"]="\u03C1";
+A["sigmaf"]="\u03C2";
+A["sigma"]="\u03C3";
+A["tau"]="\u03C4";
+A["upsilon"]="\u03C5";
+A["phi"]="\u03C6";
+A["chi"]="\u03C7";
+A["psi"]="\u03C8";
+A["omega"]="\u03C9";
+A["thetasym"]="\u03D1";
+A["upsih"]="\u03D2";
+A["piv"]="\u03D6";
+A["bull"]="\u2022";
+A["hellip"]="\u2026";
+A["prime"]="\u2032";
+A["Prime"]="\u2033";
+A["oline"]="\u203E";
+A["frasl"]="\u2044";
+A["weierp"]="\u2118";
+A["image"]="\u2111";
+A["real"]="\u211C";
+A["trade"]="\u2122";
+A["alefsym"]="\u2135";
+A["larr"]="\u2190";
+A["uarr"]="\u2191";
+A["rarr"]="\u2192";
+A["darr"]="\u2193";
+A["harr"]="\u2194";
+A["crarr"]="\u21B5";
+A["lArr"]="\u21D0";
+A["uArr"]="\u21D1";
+A["rArr"]="\u21D2";
+A["dArr"]="\u21D3";
+A["hArr"]="\u21D4";
+A["forall"]="\u2200";
+A["part"]="\u2202";
+A["exist"]="\u2203";
+A["empty"]="\u2205";
+A["nabla"]="\u2207";
+A["isin"]="\u2208";
+A["notin"]="\u2209";
+A["ni"]="\u220B";
+A["prod"]="\u220F";
+A["sum"]="\u2211";
+A["minus"]="\u2212";
+A["lowast"]="\u2217";
+A["radic"]="\u221A";
+A["prop"]="\u221D";
+A["infin"]="\u221E";
+A["ang"]="\u2220";
+A["and"]="\u2227";
+A["or"]="\u2228";
+A["cap"]="\u2229";
+A["cup"]="\u222A";
+A["int"]="\u222B";
+A["there4"]="\u2234";
+A["sim"]="\u223C";
+A["cong"]="\u2245";
+A["asymp"]="\u2248";
+A["ne"]="\u2260";
+A["equiv"]="\u2261";
+A["le"]="\u2264";
+A["ge"]="\u2265";
+A["sub"]="\u2282";
+A["sup"]="\u2283";
+A["nsub"]="\u2284";
+A["sube"]="\u2286";
+A["supe"]="\u2287";
+A["oplus"]="\u2295";
+A["otimes"]="\u2297";
+A["perp"]="\u22A5";
+A["sdot"]="\u22C5";
+A["lceil"]="\u2308";
+A["rceil"]="\u2309";
+A["lfloor"]="\u230A";
+A["rfloor"]="\u230B";
+A["lang"]="\u2329";
+A["rang"]="\u232A";
+A["loz"]="\u25CA";
+A["spades"]="\u2660";
+A["clubs"]="\u2663";
+A["hearts"]="\u2665";
+A["diams"]="\u2666";
+})();
+SimileAjax.HTML.deEntify=function(C){var D=SimileAjax.HTML._e2uHash;
+var B=/&(\w+?);/;
+while(B.test(C)){var A=C.match(B);
+C=C.replace(B,D[A[1]]);
+}return C;
+};
+
+
+/* json.js */
+SimileAjax.JSON=new Object();
+(function(){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};
+var s={array:function(x){var a=["["],b,f,i,l=x.length,v;
+for(i=0;
+i<l;
+i+=1){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a[a.length]=v;
+b=true;
+}}}a[a.length]="]";
+return a.join("");
+},"boolean":function(x){return String(x);
+},"null":function(x){return"null";
+},number:function(x){return isFinite(x)?String(x):"null";
+},object:function(x){if(x){if(x instanceof Array){return s.array(x);
+}var a=["{"],b,f,i,v;
+for(i in x){v=x[i];
+f=s[typeof v];
+if(f){v=f(v);
+if(typeof v=="string"){if(b){a[a.length]=",";
+}a.push(s.string(i),":",v);
+b=true;
+}}}a[a.length]="}";
+return a.join("");
+}return"null";
+},string:function(x){if(/["\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];
+if(c){return c;
+}c=b.charCodeAt();
+return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);
+});
+}return'"'+x+'"';
+}};
+SimileAjax.JSON.toJSONString=function(o){if(o instanceof Object){return s.object(o);
+}else{if(o instanceof Array){return s.array(o);
+}else{return o.toString();
+}}};
+SimileAjax.JSON.parseJSON=function(){try{return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g,"")))&&eval("("+this+")");
+}catch(e){return false;
+}};
+})();
+
+
+/* string.js */
+String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
+};
+String.prototype.startsWith=function(A){return this.length>=A.length&&this.substr(0,A.length)==A;
+};
+String.prototype.endsWith=function(A){return this.length>=A.length&&this.substr(this.length-A.length)==A;
+};
+String.substitute=function(C,A){var D="";
+var F=0;
+while(F<C.length-1){var B=C.indexOf("%",F);
+if(B<0||B==C.length-1){break;
+}else{if(B>F&&C.charAt(B-1)=="\\"){D+=C.substring(F,B-1)+"%";
+F=B+1;
+}else{var E=parseInt(C.charAt(B+1));
+if(isNaN(E)||E>=A.length){D+=C.substring(F,B+2);
+}else{D+=C.substring(F,B)+A[E].toString();
+}F=B+2;
+}}}if(F<C.length){D+=C.substring(F);
+}return D;
+};
+
+
+/* units.js */
+SimileAjax.NativeDateUnit=new Object();
+SimileAjax.NativeDateUnit.makeDefaultValue=function(){return new Date();
+};
+SimileAjax.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
+};
+SimileAjax.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
+}return(A=="iso8601"||A=="iso 8601")?SimileAjax.DateTime.parseIso8601DateTime:SimileAjax.DateTime.parseGregorianDateTime;
+};
+SimileAjax.NativeDateUnit.parseFromObject=function(A){return SimileAjax.DateTime.parseGregorianDateTime(A);
+};
+SimileAjax.NativeDateUnit.toNumber=function(A){return A.getTime();
+};
+SimileAjax.NativeDateUnit.fromNumber=function(A){return new Date(A);
+};
+SimileAjax.NativeDateUnit.compare=function(D,C){var B,A;
+if(typeof D=="object"){B=D.getTime();
+}else{B=Number(D);
+}if(typeof C=="object"){A=C.getTime();
+}else{A=Number(C);
+}return B-A;
+};
+SimileAjax.NativeDateUnit.earlier=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)<0?B:A;
+};
+SimileAjax.NativeDateUnit.later=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)>0?B:A;
+};
+SimileAjax.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
+};
+
+
+/* window-manager.js */
+SimileAjax.WindowManager={_initialized:false,_listeners:[],_draggedElement:null,_draggedElementCallback:null,_dropTargetHighlightElement:null,_lastCoords:null,_ghostCoords:null,_draggingMode:"",_dragging:false,_layers:[]};
+SimileAjax.WindowManager.initialize=function(){if(SimileAjax.WindowManager._initialized){return ;
+}SimileAjax.DOM.registerEvent(document.body,"mousedown",SimileAjax.WindowManager._onBodyMouseDown);
+SimileAjax.DOM.registerEvent(document.body,"mousemove",SimileAjax.WindowManager._onBodyMouseMove);
+SimileAjax.DOM.registerEvent(document.body,"mouseup",SimileAjax.WindowManager._onBodyMouseUp);
+SimileAjax.DOM.registerEvent(document,"keydown",SimileAjax.WindowManager._onBodyKeyDown);
+SimileAjax.DOM.registerEvent(document,"keyup",SimileAjax.WindowManager._onBodyKeyUp);
+SimileAjax.WindowManager._layers.push({index:0});
+SimileAjax.WindowManager._historyListener={onBeforeUndoSeveral:function(){},onAfterUndoSeveral:function(){},onBeforeUndo:function(){},onAfterUndo:function(){},onBeforeRedoSeveral:function(){},onAfterRedoSeveral:function(){},onBeforeRedo:function(){},onAfterRedo:function(){}};
+SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+SimileAjax.WindowManager._initialized=true;
+};
+SimileAjax.WindowManager.getBaseLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[0];
+};
+SimileAjax.WindowManager.getHighestLayer=function(){SimileAjax.WindowManager.initialize();
+return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length-1];
+};
+SimileAjax.WindowManager.registerEventWithObject=function(D,A,E,B,C){SimileAjax.WindowManager.registerEvent(D,A,function(G,F,H){return E[B].call(E,G,F,H);
+},C);
+};
+SimileAjax.WindowManager.registerEvent=function(D,B,E,C){if(C==null){C=SimileAjax.WindowManager.getHighestLayer();
+}var A=function(G,F,I){if(SimileAjax.WindowManager._canProcessEventAtLayer(C)){SimileAjax.WindowManager._popToLayer(C.index);
+try{E(G,F,I);
+}catch(H){SimileAjax.Debug.exception(H);
+}}SimileAjax.DOM.cancelEvent(F);
+return false;
+};
+SimileAjax.DOM.registerEvent(D,B,A);
+};
+SimileAjax.WindowManager.pushLayer=function(C,D,B){var A={onPop:C,index:SimileAjax.WindowManager._layers.length,ephemeral:(D),elmt:B};
+SimileAjax.WindowManager._layers.push(A);
+return A;
+};
+SimileAjax.WindowManager.popLayer=function(B){for(var A=1;
+A<SimileAjax.WindowManager._layers.length;
+A++){if(SimileAjax.WindowManager._layers[A]==B){SimileAjax.WindowManager._popToLayer(A-1);
+break;
+}}};
+SimileAjax.WindowManager.popAllLayers=function(){SimileAjax.WindowManager._popToLayer(0);
+};
+SimileAjax.WindowManager.registerForDragging=function(B,C,A){SimileAjax.WindowManager.registerEvent(B,"mousedown",function(E,D,F){SimileAjax.WindowManager._handleMouseDown(E,D,C);
+},A);
+};
+SimileAjax.WindowManager._popToLayer=function(C){while(C+1<SimileAjax.WindowManager._layers.length){try{var A=SimileAjax.WindowManager._layers.pop();
+if(A.onPop!=null){A.onPop();
+}}catch(B){}}};
+SimileAjax.WindowManager._canProcessEventAtLayer=function(B){if(B.index==(SimileAjax.WindowManager._layers.length-1)){return true;
+}for(var A=B.index+1;
+A<SimileAjax.WindowManager._layers.length;
+A++){if(!SimileAjax.WindowManager._layers[A].ephemeral){return false;
+}}return true;
+};
+SimileAjax.WindowManager.cancelPopups=function(A){var F=(A)?SimileAjax.DOM.getEventPageCoordinates(A):{x:-1,y:-1};
+var E=SimileAjax.WindowManager._layers.length-1;
+while(E>0&&SimileAjax.WindowManager._layers[E].ephemeral){var D=SimileAjax.WindowManager._layers[E];
+if(D.elmt!=null){var C=D.elmt;
+var B=SimileAjax.DOM.getPageCoordinates(C);
+if(F.x>=B.left&&F.x<(B.left+C.offsetWidth)&&F.y>=B.top&&F.y<(B.top+C.offsetHeight)){break;
+}}E--;
+}SimileAjax.WindowManager._popToLayer(E);
+};
+SimileAjax.WindowManager._onBodyMouseDown=function(B,A,C){if(!("eventPhase" in A)||A.eventPhase==A.BUBBLING_PHASE){SimileAjax.WindowManager.cancelPopups(A);
+}};
+SimileAjax.WindowManager._handleMouseDown=function(B,A,C){SimileAjax.WindowManager._draggedElement=B;
+SimileAjax.WindowManager._draggedElementCallback=C;
+SimileAjax.WindowManager._lastCoords={x:A.clientX,y:A.clientY};
+SimileAjax.DOM.cancelEvent(A);
+return false;
+};
+SimileAjax.WindowManager._onBodyKeyDown=function(C,A,D){if(SimileAjax.WindowManager._dragging){if(A.keyCode==27){SimileAjax.WindowManager._cancelDragging();
+}else{if((A.keyCode==17||A.keyCode==16)&&SimileAjax.WindowManager._draggingMode!="copy"){SimileAjax.WindowManager._draggingMode="copy";
+var B=SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix+"images/copy.png");
+B.style.position="absolute";
+B.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+B.style.top=(SimileAjax.WindowManager._ghostCoords.top)+"px";
+document.body.appendChild(B);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=B;
+}}}};
+SimileAjax.WindowManager._onBodyKeyUp=function(B,A,C){if(SimileAjax.WindowManager._dragging){if(A.keyCode==17||A.keyCode==16){SimileAjax.WindowManager._draggingMode="";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}}}};
+SimileAjax.WindowManager._onBodyMouseMove=function(C,M,B){if(SimileAjax.WindowManager._draggedElement!=null){var L=SimileAjax.WindowManager._draggedElementCallback;
+var G=SimileAjax.WindowManager._lastCoords;
+var J=M.clientX-G.x;
+var I=M.clientY-G.y;
+if(!SimileAjax.WindowManager._dragging){if(Math.abs(J)>5||Math.abs(I)>5){try{if("onDragStart" in L){L.onDragStart();
+}if("ghost" in L&&L.ghost){var P=SimileAjax.WindowManager._draggedElement;
+SimileAjax.WindowManager._ghostCoords=SimileAjax.DOM.getPageCoordinates(P);
+SimileAjax.WindowManager._ghostCoords.left+=J;
+SimileAjax.WindowManager._ghostCoords.top+=I;
+var K=P.cloneNode(true);
+K.style.position="absolute";
+K.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+K.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+K.style.zIndex=1000;
+SimileAjax.Graphics.setOpacity(K,50);
+document.body.appendChild(K);
+L._ghostElmt=K;
+}SimileAjax.WindowManager._dragging=true;
+SimileAjax.WindowManager._lastCoords={x:M.clientX,y:M.clientY};
+document.body.focus();
+}catch(H){SimileAjax.Debug.exception("WindowManager: Error handling mouse down",H);
+SimileAjax.WindowManager._cancelDragging();
+}}}else{try{SimileAjax.WindowManager._lastCoords={x:M.clientX,y:M.clientY};
+if("onDragBy" in L){L.onDragBy(J,I);
+}if("_ghostElmt" in L){var K=L._ghostElmt;
+SimileAjax.WindowManager._ghostCoords.left+=J;
+SimileAjax.WindowManager._ghostCoords.top+=I;
+K.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
+K.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){var O=SimileAjax.WindowManager._draggingModeIndicatorElmt;
+O.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
+O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
+}if("droppable" in L&&L.droppable){var N=SimileAjax.DOM.getEventPageCoordinates(M);
+var B=SimileAjax.DOM.hittest(N.x,N.y,[SimileAjax.WindowManager._ghostElmt,SimileAjax.WindowManager._dropTargetHighlightElement]);
+B=SimileAjax.WindowManager._findDropTarget(B);
+if(B!=SimileAjax.WindowManager._potentialDropTarget){if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+}var A=false;
+if(B!=null){if((!("canDropOn" in L)||L.canDropOn(B))&&(!("canDrop" in B)||B.canDrop(SimileAjax.WindowManager._draggedElement))){A=true;
+}}if(A){var E=4;
+var D=SimileAjax.DOM.getPageCoordinates(B);
+var F=document.createElement("div");
+F.style.border=E+"px solid yellow";
+F.style.backgroundColor="yellow";
+F.style.position="absolute";
+F.style.left=D.left+"px";
+F.style.top=D.top+"px";
+F.style.width=(B.offsetWidth-E*2)+"px";
+F.style.height=(B.offsetHeight-E*2)+"px";
+SimileAjax.Graphics.setOpacity(F,30);
+document.body.appendChild(F);
+SimileAjax.WindowManager._potentialDropTarget=B;
+SimileAjax.WindowManager._dropTargetHighlightElement=F;
+}}}}}catch(H){SimileAjax.Debug.exception("WindowManager: Error handling mouse move",H);
+SimileAjax.WindowManager._cancelDragging();
+}}SimileAjax.DOM.cancelEvent(M);
+return false;
+}};
+SimileAjax.WindowManager._onBodyMouseUp=function(B,A,E){if(SimileAjax.WindowManager._draggedElement!=null){try{if(SimileAjax.WindowManager._dragging){var C=SimileAjax.WindowManager._draggedElementCallback;
+if("onDragEnd" in C){C.onDragEnd();
+}if("droppable" in C&&C.droppable){var D=false;
+var E=SimileAjax.WindowManager._potentialDropTarget;
+if(E!=null){if((!("canDropOn" in C)||C.canDropOn(E))&&(!("canDrop" in E)||E.canDrop(SimileAjax.WindowManager._draggedElement))){if("onDropOn" in C){C.onDropOn(E);
+}E.ondrop(SimileAjax.WindowManager._draggedElement,SimileAjax.WindowManager._draggingMode);
+D=true;
+}}if(!D){}}}}finally{SimileAjax.WindowManager._cancelDragging();
+}SimileAjax.DOM.cancelEvent(A);
+return false;
+}};
+SimileAjax.WindowManager._cancelDragging=function(){var A=SimileAjax.WindowManager._draggedElementCallback;
+if("_ghostElmt" in A){var B=A._ghostElmt;
+document.body.removeChild(B);
+delete A._ghostElmt;
+}if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+}if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
+}SimileAjax.WindowManager._draggedElement=null;
+SimileAjax.WindowManager._draggedElementCallback=null;
+SimileAjax.WindowManager._potentialDropTarget=null;
+SimileAjax.WindowManager._dropTargetHighlightElement=null;
+SimileAjax.WindowManager._lastCoords=null;
+SimileAjax.WindowManager._ghostCoords=null;
+SimileAjax.WindowManager._draggingMode="";
+SimileAjax.WindowManager._dragging=false;
+};
+SimileAjax.WindowManager._findDropTarget=function(A){while(A!=null){if("ondrop" in A&&(typeof A.ondrop)=="function"){break;
+}A=A.parentNode;
+}return A;
+};
+
+
+/* xmlhttp.js */
+SimileAjax.XmlHttp=new Object();
+SimileAjax.XmlHttp._onReadyStateChange=function(A,D,B){switch(A.readyState){case 4:try{if(A.status==0||A.status==200){if(B){B(A);
+}}else{if(D){D(A.statusText,A.status,A);
+}}}catch(C){SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange",C);
+}break;
+}};
+SimileAjax.XmlHttp._createRequest=function(){if(SimileAjax.Platform.browser.isIE){var B=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
+for(var C=0;
+C<B.length;
+C++){try{var A=B[C];
+var D=function(){return new ActiveXObject(A);
+};
+var F=D();
+SimileAjax.XmlHttp._createRequest=D;
+return F;
+}catch(E){}}}try{var D=function(){return new XMLHttpRequest();
+};
+var F=D();
+SimileAjax.XmlHttp._createRequest=D;
+return F;
+}catch(E){throw new Error("Failed to create an XMLHttpRequest object");
+}};
+SimileAjax.XmlHttp.get=function(B,D,C){var A=SimileAjax.XmlHttp._createRequest();
+A.open("GET",B,true);
+A.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(A,D,C);
+};
+A.send(null);
+};
+SimileAjax.XmlHttp.post=function(C,A,E,D){var B=SimileAjax.XmlHttp._createRequest();
+B.open("POST",C,true);
+B.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(B,E,D);
+};
+B.send(A);
+};
+SimileAjax.XmlHttp._forceXML=function(A){try{A.overrideMimeType("text/xml");
+}catch(B){A.setrequestheader("Content-Type","text/xml");
+}};
diff --git a/src/ajax/api/styles/graphics-ie6.css b/src/ajax/api/styles/graphics-ie6.css
new file mode 100644
index 0000000..4fc9382
--- /dev/null
+++ b/src/ajax/api/styles/graphics-ie6.css
@@ -0,0 +1,77 @@
+.simileAjax-bubble-border-left-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-left.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-right-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-right.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-top-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-top.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-bottom-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-bottom.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-top-left-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-top-left.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-top-right-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-top-right.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-bottom-left-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-bottom-left.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-border-bottom-right-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-bottom-right.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-arrow-point-left-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-arrow-point-left.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-arrow-point-right-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-arrow-point-right.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-arrow-point-up-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-arrow-point-up.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-arrow-point-down-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/bubble-arrow-point-down.png', sizingMethod='crop')"
+ );
+}
+
+.simileAjax-bubble-close-pngNotTranslucent {
+ filter: expression(
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + SimileAjax.urlPrefix + "images/close-button.png', sizingMethod='crop')"
+ );
+}
diff --git a/src/ajax/api/styles/graphics.css b/src/ajax/api/styles/graphics.css
new file mode 100644
index 0000000..3377b2b
--- /dev/null
+++ b/src/ajax/api/styles/graphics.css
@@ -0,0 +1,171 @@
+div.simileAjax-bubble-container {
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ position: absolute;
+ z-index: 1000;
+}
+
+div.simileAjax-bubble-innerContainer {
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: visible;
+}
+
+div.simileAjax-bubble-contentContainer {
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background: white;
+}
+
+div.simileAjax-bubble-border-left {
+ position: absolute;
+ left: -50px;
+ top: 0px;
+ width: 50px;
+ height: 100%;
+}
+div.simileAjax-bubble-border-left-pngTranslucent {
+ background: url(../images/bubble-left.png) top right repeat-y;
+}
+
+div.simileAjax-bubble-border-right {
+ position: absolute;
+ right: -50px;
+ top: 0px;
+ width: 50px;
+ height: 100%;
+}
+.simileAjax-bubble-border-right-pngTranslucent {
+ background: url(../images/bubble-right.png) top left repeat-y;
+}
+
+div.simileAjax-bubble-border-top {
+ position: absolute;
+ top: -50px;
+ left: 0px;
+ width: 100%;
+ height: 50px;
+}
+.simileAjax-bubble-border-top-pngTranslucent {
+ background: url(../images/bubble-top.png) bottom left repeat-x;
+}
+
+div.simileAjax-bubble-border-bottom {
+ position: absolute;
+ bottom: -50px;
+ left: 0px;
+ width: 100%;
+ height: 50px;
+}
+.simileAjax-bubble-border-bottom-pngTranslucent {
+ background: url(../images/bubble-bottom.png) top left repeat-x;
+}
+
+div.simileAjax-bubble-border-top-left {
+ position: absolute;
+ top: -50px;
+ left: -50px;
+ width: 50px;
+ height: 50px;
+}
+.simileAjax-bubble-border-top-left-pngTranslucent {
+ background: url(../images/bubble-top-left.png) bottom right no-repeat;
+}
+
+div.simileAjax-bubble-border-top-right {
+ position: absolute;
+ top: -50px;
+ right: -50px;
+ width: 50px;
+ height: 50px;
+}
+.simileAjax-bubble-border-top-right-pngTranslucent {
+ background: url(../images/bubble-top-right.png) bottom left no-repeat;
+}
+
+div.simileAjax-bubble-border-bottom-left {
+ position: absolute;
+ bottom: -50px;
+ left: -50px;
+ width: 50px;
+ height: 50px;
+}
+.simileAjax-bubble-border-bottom-left-pngTranslucent {
+ background: url(../images/bubble-bottom-left.png) top right no-repeat;
+}
+
+div.simileAjax-bubble-border-bottom-right {
+ position: absolute;
+ bottom: -50px;
+ right: -50px;
+ width: 50px;
+ height: 50px;
+}
+.simileAjax-bubble-border-bottom-right-pngTranslucent {
+ background: url(../images/bubble-bottom-right.png) top left no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-left {
+ position: absolute;
+ left: -100px;
+ width: 100px;
+ height: 49px;
+}
+.simileAjax-bubble-arrow-point-left-pngTranslucent {
+ background: url(../images/bubble-arrow-point-left.png) center right no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-right {
+ position: absolute;
+ right: -100px;
+ width: 100px;
+ height: 49px;
+}
+.simileAjax-bubble-arrow-point-right-pngTranslucent {
+ background: url(../images/bubble-arrow-point-right.png) center left no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-up {
+ position: absolute;
+ top: -100px;
+ width: 49px;
+ height: 100px;
+}
+.simileAjax-bubble-arrow-point-up-pngTranslucent {
+ background: url(../images/bubble-arrow-point-up.png) bottom center no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-down {
+ position: absolute;
+ bottom: -100px;
+ width: 49px;
+ height: 100px;
+}
+.simileAjax-bubble-arrow-point-down-pngTranslucent {
+ background: url(../images/bubble-arrow-point-down.png) bottom center no-repeat;
+}
+
+
+div.simileAjax-bubble-close {
+ position: absolute;
+ right: -10px;
+ top: -12px;
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+}
+.simileAjax-bubble-close-pngTranslucent {
+ background: url(../images/close-button.png) no-repeat;
+}
diff --git a/src/ajax/site/docs/_01.html b/src/ajax/site/docs/_01.html
new file mode 100644
index 0000000..effc47f
--- /dev/null
+++ b/src/ajax/site/docs/_01.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: ajax.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: ajax.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:47 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_02.html b/src/ajax/site/docs/_02.html
new file mode 100644
index 0000000..1a1d586
--- /dev/null
+++ b/src/ajax/site/docs/_02.html
@@ -0,0 +1,643 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: data-structure.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: data-structure.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="section constructor">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set"></a>
+
+
+ SimileAjax.Set(<span class="signature">a</span>)
+
+ </div>
+
+
+ <div class="desc">A basic set (in the mathematical sense) data structure</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Array or SimileAjax.Set
+ </td>
+ <td>
+ a
+ </td>
+ <td>
+ an initial collection
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">methods</div>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.add">add</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.addSet">addSet</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.remove">remove</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.removeSet">removeSet</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.retainSet">retainSet</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.contains">contains</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.size">size</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.toArray">toArray</a></li>
+ </ul>
+
+ <ul class="details">
+ <li><a href="#SimileAjax.Set.visit">visit</a></li>
+ </ul>
+
+
+
+
+
+
+ </div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <div class="section constructor">
+ <div class="itemTitle">
+ <a name="SimileAjax.SortedArray"></a>
+
+
+ SimileAjax.SortedArray(<span class="signature">compare, initialArray</span>)
+
+ </div>
+
+
+ <div class="desc">A sorted array data structure</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ compare
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ initialArray
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+
+
+ </div>
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.add"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>add(<span class="signature">o</span>)
+
+
+ </div>
+
+
+ <div class="desc">Adds the given object to this set, assuming there it does not already exist</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ o
+ </td>
+ <td>
+ the object to add
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Boolean
+ </td>
+ <td>
+ true if the object was added, false if not
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.addSet"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>addSet(<span class="signature">set</span>)
+
+
+ </div>
+
+
+ <div class="desc">Adds each element in the given set to this set</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ SimileAjax.Set
+ </td>
+ <td>
+ set
+ </td>
+ <td>
+ the set of elements to add
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.remove"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>remove(<span class="signature">o</span>)
+
+
+ </div>
+
+
+ <div class="desc">Removes the given element from this set</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ o
+ </td>
+ <td>
+ the object to remove
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Boolean
+ </td>
+ <td>
+ true if the object was successfully removed,
+ false otherwise
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.removeSet"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>removeSet(<span class="signature">set</span>)
+
+
+ </div>
+
+
+ <div class="desc">Removes the elements in this set that correspond to the elements in the
+given set</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ SimileAjax.Set
+ </td>
+ <td>
+ set
+ </td>
+ <td>
+ the set of elements to remove
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.retainSet"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>retainSet(<span class="signature">set</span>)
+
+
+ </div>
+
+
+ <div class="desc">Removes all elements in this set that are not present in the given set, i.e.
+modifies this set to the intersection of the two sets</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ SimileAjax.Set
+ </td>
+ <td>
+ set
+ </td>
+ <td>
+ the set to intersect
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.contains"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>contains(<span class="signature">o</span>)
+
+
+ </div>
+
+
+ <div class="desc">Returns whether or not the given element exists in this set</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ SimileAjax.Set
+ </td>
+ <td>
+ o
+ </td>
+ <td>
+ the object to test for
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Boolean
+ </td>
+ <td>
+ true if the object is present, false otherwise
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.size"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>size(<span class="signature"></span>)
+
+
+ </div>
+
+
+ <div class="desc">Returns the number of elements in this set</div>
+
+
+
+
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ the number of elements in this set
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.toArray"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>toArray(<span class="signature"></span>)
+
+
+ </div>
+
+
+ <div class="desc">Returns the elements of this set as an array</div>
+
+
+
+
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Array
+ </td>
+ <td>
+ a new array containing the elements of this set
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Set.visit"></a>
+
+ <i><a href="#SimileAjax.Set" class="type">SimileAjax.Set.</a></i>visit(<span class="signature">f</span>)
+
+
+ </div>
+
+
+ <div class="desc">Iterates through the elements of this set, order unspecified, executing the
+given function on each element until the function returns true</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ f
+ </td>
+ <td>
+ a function of form f(element)
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:47 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_03.html b/src/ajax/site/docs/_03.html
new file mode 100644
index 0000000..dfee170
--- /dev/null
+++ b/src/ajax/site/docs/_03.html
@@ -0,0 +1,811 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: SimileAjax.DateTime</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: SimileAjax.DateTime</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">A collection of date/time utility functions</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.setIso8601Date"></a>
+
+
+ SimileAjax.DateTime.setIso8601Date(<span class="signature">dateObject, string</span>)
+
+ </div>
+
+
+ <div class="desc">Takes a date object and a string containing an ISO 8601 date and sets the
+the date using information parsed from the string. Note that this method
+does not parse any time information.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ dateObject
+ </td>
+ <td>
+ the date object to modify
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ string
+ </td>
+ <td>
+ an ISO 8601 string to parse
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ the modified date object
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.setIso8601Time"></a>
+
+
+ SimileAjax.DateTime.setIso8601Time(<span class="signature">dateObject, string</span>)
+
+ </div>
+
+
+ <div class="desc">Takes a date object and a string containing an ISO 8601 time and sets the
+the time using information parsed from the string. Note that this method
+does not parse any date information.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ dateObject
+ </td>
+ <td>
+ the date object to modify
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ string
+ </td>
+ <td>
+ an ISO 8601 string to parse
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ the modified date object
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.setIso8601"></a>
+
+
+ SimileAjax.DateTime.setIso8601(<span class="signature">dateObject, string</span>)
+
+ </div>
+
+
+ <div class="desc">Takes a date object and a string containing an ISO 8601 date and time and
+sets the date object using information parsed from the string.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ dateObject
+ </td>
+ <td>
+ the date object to modify
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ string
+ </td>
+ <td>
+ an ISO 8601 string to parse
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ the modified date object
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.parseIso8601DateTime"></a>
+
+
+ SimileAjax.DateTime.parseIso8601DateTime(<span class="signature">string</span>)
+
+ </div>
+
+
+ <div class="desc">Takes a string containing an ISO 8601 date and returns a newly instantiated
+date object with the parsed date and time information from the string.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ string
+ </td>
+ <td>
+ an ISO 8601 string to parse
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ a new date object created from the string
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.parseGregorianDateTime"></a>
+
+
+ SimileAjax.DateTime.parseGregorianDateTime(<span class="signature">o</span>)
+
+ </div>
+
+
+ <div class="desc">Takes a string containing a Gregorian date and time and returns a newly
+instantiated date object with the parsed date and time information from the
+string. If the param is actually an instance of Date instead of a string,
+simply returns the given date instead.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ o
+ </td>
+ <td>
+ an object, to either return or parse as a string
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ the date object
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.roundDownToInterval"></a>
+
+
+ SimileAjax.DateTime.roundDownToInterval(<span class="signature">date, intervalUnit, timeZone, multiple, firstDayOfWeek</span>)
+
+ </div>
+
+
+ <div class="desc">Rounds date objects down to the nearest interval or multiple of an interval.
+This method modifies the given date object, converting it to the given
+timezone if specified.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ date
+ </td>
+ <td>
+ the date object to round
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ intervalUnit
+ </td>
+ <td>
+ a constant, integer index specifying an
+ interval, e.g. SimileAjax.DateTime.HOUR
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ timeZone
+ </td>
+ <td>
+ a timezone shift, given in hours
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ multiple
+ </td>
+ <td>
+ a multiple of the interval to round by
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ firstDayOfWeek
+ </td>
+ <td>
+ an integer specifying the first day of the
+ week, 0 corresponds to Sunday, 1 to Monday, etc.
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.roundUpToInterval"></a>
+
+
+ SimileAjax.DateTime.roundUpToInterval(<span class="signature">date, intervalUnit, timeZone, multiple, firstDayOfWeek</span>)
+
+ </div>
+
+
+ <div class="desc">Rounds date objects up to the nearest interval or multiple of an interval.
+This method modifies the given date object, converting it to the given
+timezone if specified.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ date
+ </td>
+ <td>
+ the date object to round
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ intervalUnit
+ </td>
+ <td>
+ a constant, integer index specifying an
+ interval, e.g. SimileAjax.DateTime.HOUR
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ timeZone
+ </td>
+ <td>
+ a timezone shift, given in hours
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ multiple
+ </td>
+ <td>
+ a multiple of the interval to round by
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ firstDayOfWeek
+ </td>
+ <td>
+ an integer specifying the first day of the
+ week, 0 corresponds to Sunday, 1 to Monday, etc.
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.incrementByInterval"></a>
+
+
+ SimileAjax.DateTime.incrementByInterval(<span class="signature">date, intervalUnit</span>)
+
+ </div>
+
+
+ <div class="desc">Increments a date object by a specified interval.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ date
+ </td>
+ <td>
+ the date object to increment
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ intervalUnit
+ </td>
+ <td>
+ a constant, integer index specifying an
+ interval, e.g. SimileAjax.DateTime.HOUR
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.removeTimeZoneOffset"></a>
+
+
+ SimileAjax.DateTime.removeTimeZoneOffset(<span class="signature">date, timeZone</span>)
+
+ </div>
+
+
+ <div class="desc">Returns a new date object with the given time offset removed.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ date
+ </td>
+ <td>
+ the starting date
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ timeZone
+ </td>
+ <td>
+ a timezone specified in an hour offset to remove
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Date
+ </td>
+ <td>
+ a new date object with the offset removed
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.getTimezone"></a>
+
+
+ SimileAjax.DateTime.getTimezone(<span class="signature"></span>)
+
+ </div>
+
+
+ <div class="desc">Returns the timezone offset of the user's browser.</div>
+
+
+
+
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ the timezone offset in the user's locale in hours
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+ <div class="section object">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.gregorianUnitLengths"></a>
+
+ <span class="type">Array</span>
+
+
+
+ SimileAjax.DateTime.gregorianUnitLengths
+
+ </div>
+
+
+ <div class="desc">An array of unit lengths, expressed in milliseconds, of various lengths of
+time. The array indices are predefined and stored as properties of the
+SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.</div>
+
+
+
+ </div>
+
+
+
+
+
+
+
+
+
+
+ <div class="section object">
+ <div class="itemTitle">
+ <a name="SimileAjax.DateTime.timezoneOffset"></a>
+
+ <span class="type">Number</span>
+
+
+
+ SimileAjax.DateTime.timezoneOffset
+
+ </div>
+
+
+ <div class="desc">The timezone offset in minutes in the user's browser.</div>
+
+
+
+ </div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:47 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_04.html b/src/ajax/site/docs/_04.html
new file mode 100644
index 0000000..53c3a86
--- /dev/null
+++ b/src/ajax/site/docs/_04.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: debug.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: debug.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:47 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_05.html b/src/ajax/site/docs/_05.html
new file mode 100644
index 0000000..48ceac5
--- /dev/null
+++ b/src/ajax/site/docs/_05.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: dom.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: dom.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:47 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_06.html b/src/ajax/site/docs/_06.html
new file mode 100644
index 0000000..72ccbb3
--- /dev/null
+++ b/src/ajax/site/docs/_06.html
@@ -0,0 +1,719 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: SimileAjax.Graphics</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: SimileAjax.Graphics</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">Graphics utility functions and constants</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createTranslucentImage"></a>
+
+
+ SimileAjax.Graphics.createTranslucentImage(<span class="signature">url, verticalAlign</span>)
+
+ </div>
+
+
+ <div class="desc">Creates a DOM element for an <code>img</code> tag using the URL given. This
+is a convenience method that automatically includes the necessary CSS to
+allow for translucency, even on IE.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ url
+ </td>
+ <td>
+ the URL to the image
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ verticalAlign
+ </td>
+ <td>
+ the CSS value for the image's vertical-align
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Element
+ </td>
+ <td>
+ a DOM element containing the <code>img</code> tag
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createTranslucentImageHTML"></a>
+
+
+ SimileAjax.Graphics.createTranslucentImageHTML(<span class="signature">url, verticalAlign</span>)
+
+ </div>
+
+
+ <div class="desc">Creates an HTML string for an <code>img</code> tag using the URL given.
+This is a convenience method that automatically includes the necessary CSS
+to allow for translucency, even on IE.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ url
+ </td>
+ <td>
+ the URL to the image
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ verticalAlign
+ </td>
+ <td>
+ the CSS value for the image's vertical-align
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ a string containing the <code>img</code> tag
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.setOpacity"></a>
+
+
+ SimileAjax.Graphics.setOpacity(<span class="signature">elmt, opacity</span>)
+
+ </div>
+
+
+ <div class="desc">Sets the opacity on the given DOM element.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Element
+ </td>
+ <td>
+ elmt
+ </td>
+ <td>
+ the DOM element to set the opacity on
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ opacity
+ </td>
+ <td>
+ an integer from 0 to 100 specifying the opacity
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createBubbleForPoint"></a>
+
+
+ SimileAjax.Graphics.createBubbleForPoint(<span class="signature">pageX, pageY, contentWidth, contentHeight, orientation</span>)
+
+ </div>
+
+
+ <div class="desc">Creates a nice, rounded bubble popup with the given page coordinates and
+content dimensions. The bubble will point to the location on the page
+as described by pageX and pageY. All measurements should be given in
+pixels.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ pageX
+ </td>
+ <td>
+ the x coordinate of the point to point to
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ pageY
+ </td>
+ <td>
+ the y coordinate of the point to point to
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ contentWidth
+ </td>
+ <td>
+ the width of the content box in the bubble
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ contentHeight
+ </td>
+ <td>
+ the height of the content box in the bubble
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ orientation
+ </td>
+ <td>
+ a string ("top", "bottom", "left", or "right")
+ that describes the orientation of the arrow on the bubble
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Element
+ </td>
+ <td>
+ a DOM element for the newly created bubble
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createMessageBubble"></a>
+
+
+ SimileAjax.Graphics.createMessageBubble(<span class="signature">doc, an</span>)
+
+ </div>
+
+
+ <div class="desc">Creates a floating, rounded message bubble in the center of the window for
+displaying modal information, e.g. "Loading..."</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Document
+ </td>
+ <td>
+ doc
+ </td>
+ <td>
+ the root document for the page to render on
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ an
+ </td>
+ <td>
+ object with two properties, contentDiv and containerDiv,
+ consisting of the newly created DOM elements
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createAnimation"></a>
+
+
+ SimileAjax.Graphics.createAnimation(<span class="signature">f, from, to, duration, cont</span>)
+
+ </div>
+
+
+ <div class="desc">Creates an animation for a function, and an interval of values. The word
+"animation" here is used in the sense of repeatedly calling a function with
+a current value from within an interval, and a delta value.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ f
+ </td>
+ <td>
+ a function to be called every 50 milliseconds throughout
+ the animation duration, of the form f(current, delta), where current is
+ the current value within the range and delta is the current change.
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ from
+ </td>
+ <td>
+ a starting value
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ to
+ </td>
+ <td>
+ an ending value
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ duration
+ </td>
+ <td>
+ the duration of the animation in milliseconds
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ cont
+ </td>
+ <td>
+ an optional function that is called at the end of
+ the animation, i.e. a continuation.
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ SimileAjax.Graphics._Animation
+ </td>
+ <td>
+ a new animation object
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics._Animation.run"></a>
+
+ <i><a href="#SimileAjax.Graphics._Animation" class="type">SimileAjax.Graphics._Animation.</a></i>run(<span class="signature"></span>)
+
+
+ </div>
+
+
+ <div class="desc">Runs this animation.</div>
+
+
+
+
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics._Animation.step"></a>
+
+ <i><a href="#SimileAjax.Graphics._Animation" class="type">SimileAjax.Graphics._Animation.</a></i>step(<span class="signature"></span>)
+
+
+ </div>
+
+
+ <div class="desc">Increments this animation by one step, and then continues the animation with
+<code>run()</code>.</div>
+
+
+
+
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.createStructuredDataCopyButton"></a>
+
+
+ SimileAjax.Graphics.createStructuredDataCopyButton(<span class="signature">image, width, height, createDataFunction</span>)
+
+ </div>
+
+
+ <div class="desc">Creates a button and textarea for displaying structured data and copying it
+to the clipboard. The data is dynamically generated by the given
+createDataFunction parameter.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ image
+ </td>
+ <td>
+ an image URL to use as the background for the
+ generated box
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ width
+ </td>
+ <td>
+ the width in pixels of the generated box
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Number
+ </td>
+ <td>
+ height
+ </td>
+ <td>
+ the height in pixels of the generated box
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ createDataFunction
+ </td>
+ <td>
+ a function that is called with no
+ arguments to generate the structured data
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ a new DOM element
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+ <div class="section object">
+ <div class="itemTitle">
+ <a name="SimileAjax.Graphics.pngIsTranslucent"></a>
+
+ <span class="type">Boolean</span>
+
+
+
+ SimileAjax.Graphics.pngIsTranslucent
+
+ </div>
+
+
+ <div class="desc">A boolean value indicating whether PNG translucency is supported on the
+user's browser or not.</div>
+
+
+
+ </div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_07.html b/src/ajax/site/docs/_07.html
new file mode 100644
index 0000000..db74c84
--- /dev/null
+++ b/src/ajax/site/docs/_07.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: history.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: history.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_08.html b/src/ajax/site/docs/_08.html
new file mode 100644
index 0000000..71f4a20
--- /dev/null
+++ b/src/ajax/site/docs/_08.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: html.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: html.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_09.html b/src/ajax/site/docs/_09.html
new file mode 100644
index 0000000..2a855a8
--- /dev/null
+++ b/src/ajax/site/docs/_09.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: jquery-1.1.3.1.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: jquery-1.1.3.1.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_10.html b/src/ajax/site/docs/_10.html
new file mode 100644
index 0000000..9cf2957
--- /dev/null
+++ b/src/ajax/site/docs/_10.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: json.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: json.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_11.html b/src/ajax/site/docs/_11.html
new file mode 100644
index 0000000..b801fb4
--- /dev/null
+++ b/src/ajax/site/docs/_11.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: platform.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: platform.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_12.html b/src/ajax/site/docs/_12.html
new file mode 100644
index 0000000..debf2b5
--- /dev/null
+++ b/src/ajax/site/docs/_12.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: signal.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: signal.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_13.html b/src/ajax/site/docs/_13.html
new file mode 100644
index 0000000..f20fdef
--- /dev/null
+++ b/src/ajax/site/docs/_13.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: string.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: string.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_14.html b/src/ajax/site/docs/_14.html
new file mode 100644
index 0000000..805209a
--- /dev/null
+++ b/src/ajax/site/docs/_14.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: units.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: units.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_15.html b/src/ajax/site/docs/_15.html
new file mode 100644
index 0000000..6d3161f
--- /dev/null
+++ b/src/ajax/site/docs/_15.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: SimileAjax.WindowManager</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: SimileAjax.WindowManager</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">UI layers and window-wide dragging</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+ <div class="section object">
+ <div class="itemTitle">
+ <a name="SimileAjax.WindowManager"></a>
+
+
+
+ SimileAjax.WindowManager
+
+ </div>
+
+
+ <div class="desc">This is a singleton that keeps track of UI layers (modal and
+ modeless) and enables/disables UI elements based on which layers
+ they belong to. It also provides window-wide dragging
+ implementation.</div>
+
+
+
+ </div>
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_16.html b/src/ajax/site/docs/_16.html
new file mode 100644
index 0000000..9042d3d
--- /dev/null
+++ b/src/ajax/site/docs/_16.html
@@ -0,0 +1,262 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: SimileAjax.XmlHttp</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: SimileAjax.XmlHttp</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">XmlHttp utility functions</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+
+
+
+
+
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.XmlHttp._onReadyStateChange"></a>
+
+
+ SimileAjax.XmlHttp._onReadyStateChange(<span class="signature">xmlhttp, fError, fDone</span>)
+
+ </div>
+
+
+ <div class="desc">Callback for XMLHttp onRequestStateChange.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ xmlhttp
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ fError
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ fDone
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.XmlHttp._createRequest"></a>
+
+
+ SimileAjax.XmlHttp._createRequest(<span class="signature"></span>)
+
+ </div>
+
+
+ <div class="desc">Creates an XMLHttpRequest object. On the first run, this
+ function creates a platform-specific function for
+ instantiating an XMLHttpRequest object and then replaces
+ itself with that function.</div>
+
+
+
+
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.XmlHttp.get"></a>
+
+
+ SimileAjax.XmlHttp.get(<span class="signature">fError, fDone</span>)
+
+ </div>
+
+
+ <div class="desc">Performs an asynchronous HTTP GET.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ fError
+ </td>
+ <td>
+ a function of the form
+ function(statusText, statusCode, xmlhttp)
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ fDone
+ </td>
+ <td>
+ a function of the form function(xmlhttp)
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.XmlHttp.post"></a>
+
+
+ SimileAjax.XmlHttp.post(<span class="signature">fError, fDone</span>)
+
+ </div>
+
+
+ <div class="desc">Performs an asynchronous HTTP POST.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ fError
+ </td>
+ <td>
+ a function of the form
+ function(statusText, statusCode, xmlhttp)
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Function
+ </td>
+ <td>
+ fDone
+ </td>
+ <td>
+ a function of the form function(xmlhttp)
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_17.html b/src/ajax/site/docs/_17.html
new file mode 100644
index 0000000..202632d
--- /dev/null
+++ b/src/ajax/site/docs/_17.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: simile-ajax-api.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: simile-ajax-api.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+
+
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.prefixURLs"></a>
+
+
+ SimileAjax.prefixURLs(<span class="signature">urls, urlPrefix, suffixes</span>)
+
+ </div>
+
+
+ <div class="desc">Append into urls each string in suffixes after prefixing it with urlPrefix.</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ Array
+ </td>
+ <td>
+ urls
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ urlPrefix
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Array
+ </td>
+ <td>
+ suffixes
+ </td>
+ <td>
+
+ </td>
+ </tr>
+
+ </table>
+
+
+
+
+
+ </div>
+
+
+
+ <div class="section function">
+ <div class="itemTitle">
+ <a name="SimileAjax.parseURLParameters"></a>
+
+
+ SimileAjax.parseURLParameters(<span class="signature">url, to, types</span>)
+
+ </div>
+
+
+ <div class="desc">Parse out the query parameters from a URL</div>
+
+
+
+
+
+ <div class="detailHead">parameters</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+ String
+ </td>
+ <td>
+ url
+ </td>
+ <td>
+ the url to parse, or location.href if undefined
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ to
+ </td>
+ <td>
+ optional object to extend with the parameters
+ </td>
+ </tr>
+
+ <tr>
+ <td class="type">
+ Object
+ </td>
+ <td>
+ types
+ </td>
+ <td>
+ optional object mapping keys to value types
+ (String, Number, Boolean or Array, String by default)
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ <div class="detailHead">returns</div>
+ <table class="params">
+
+ <tr>
+ <td class="type">
+
+ </td>
+ <td>
+ a key/value Object whose keys are the query parameter names
+ </td>
+ </tr>
+
+ </table>
+
+
+
+ </div>
+
+
+
+ <div class="sectionHead">Objects</div>
+
+
+
+
+
+
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/_18.html b/src/ajax/site/docs/_18.html
new file mode 100644
index 0000000..bfa83c6
--- /dev/null
+++ b/src/ajax/site/docs/_18.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ <title>JsDoc: simile-ajax-bundle.js</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+</head>
+
+<body>
+ <div class="content">
+ <div class="docs">
+
+ <div class="sectionHead">Library: simile-ajax-bundle.js</div>
+ <div class="section overview">
+ <div class="itemTitle">
+ Overview
+ </div>
+ <div>
+ <div class="desc">No overview provided.</div>
+ <div class="itemTags">
+
+ </div>
+ </div>
+ </div>
+
+ <div class="sectionHead">Constructors</div>
+
+
+ <div class="sectionHead">Functions</div>
+
+
+ <div class="sectionHead">Objects</div>
+
+ </div>
+ </div>
+ <div class="finePrint">
+ Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> on Tue, 07 Aug 2007 20:53:48 GMT
+ </div>
+</body>
+</html>
diff --git a/src/ajax/site/docs/constructor.gif b/src/ajax/site/docs/constructor.gif
new file mode 100644
index 0000000..ba77997
--- /dev/null
+++ b/src/ajax/site/docs/constructor.gif
Binary files differ
diff --git a/src/ajax/site/docs/default.css b/src/ajax/site/docs/default.css
new file mode 100644
index 0000000..cfe837b
--- /dev/null
+++ b/src/ajax/site/docs/default.css
@@ -0,0 +1,116 @@
+body,a
+{
+ color: #000;
+ font: 12px verdana;
+}
+
+ul
+{
+ list-style-type: none;
+ margin-left: 10px;
+ padding-left: 10px;
+}
+
+.content { }
+.docs { }
+.signature { font-weight: normal; }
+.code {
+ font: 11px monaco,monospace;
+ padding: 4px;
+ margin-left: 18px;
+ border: 1px dashed #ccc;
+}
+
+.itemTitle
+{
+ font-size: 12px;
+ font-weight: bold;
+ height: 16px;
+}
+
+.item { }
+
+.sectionHead
+{
+ font-size: 18px;
+ font-weight: bold;
+ background-color: #C0C1DE;
+ color: #fff;
+ margin-top: 18px;
+ padding: 2px 4px 2px 4px;
+}
+
+.section
+{
+ padding: 8px;
+ border: 1px #8A92BC solid;
+ margin: 4px;
+}
+
+.detailHead
+{
+ border-bottom: 1px #8FB685 dotted;
+ font-size: 12px;
+ font-weight: bold;
+ color: #798E73;
+ margin-top: 18px;
+}
+
+.desc { padding: 8px; }
+
+.fileHead
+{
+ background-image: url(file.gif);
+ background-repeat: no-repeat;
+ padding-left: 20px;
+ font-weight: bold;
+ font-size: 14px;
+ line-height: 20px;
+}
+
+.overview .itemTitle
+{
+ background-image: url(overview.gif);
+ background-repeat: no-repeat;
+ padding-left: 20px;
+}
+
+.constructor .itemTitle
+{
+ background-image: url(constructor.gif);
+ background-repeat: no-repeat;
+ padding-left: 20px;
+}
+
+.function .itemTitle
+{
+ background-image: url(function.gif);
+ background-repeat: no-repeat;
+ padding-left: 20px;
+}
+
+.object .itemTitle
+{
+ background-image: url(object.gif);
+ background-repeat: no-repeat;
+ padding-left: 20px;
+}
+
+.type
+{
+ font-style: italic;
+ color: #999;
+ font-weight: normal;
+}
+
+.itemTitle a.type { font-weight: bold; }
+
+.finePrint
+{
+ color: #878787;
+ font-family: verdana;
+ font-size: 10px;
+ text-align: right;
+}
+
+.params td { padding-right: 10px; } \ No newline at end of file
diff --git a/src/ajax/site/docs/file.gif b/src/ajax/site/docs/file.gif
new file mode 100644
index 0000000..9c7446e
--- /dev/null
+++ b/src/ajax/site/docs/file.gif
Binary files differ
diff --git a/src/ajax/site/docs/file_list.html b/src/ajax/site/docs/file_list.html
new file mode 100644
index 0000000..d52d175
--- /dev/null
+++ b/src/ajax/site/docs/file_list.html
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>JsDoc</title>
+ <link rel=stylesheet href="default.css" type="text/css" media=screen>
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+</head>
+<body>
+<div class="sectionHead">File Index</div>
+<ul>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_01.html" target="main" class="fileHead">ajax.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_02.html" target="main" class="fileHead">data-structure.js</a>
+ <ul>
+
+ <li><a href="_02.html#SimileAjax.Set" target="main">SimileAjax.Set</a></li>
+
+ <li><a href="_02.html#SimileAjax.SortedArray" target="main">SimileAjax.SortedArray</a></li>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_03.html" target="main" class="fileHead">SimileAjax.DateTime</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_04.html" target="main" class="fileHead">debug.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_05.html" target="main" class="fileHead">dom.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_06.html" target="main" class="fileHead">SimileAjax.Graphics</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_07.html" target="main" class="fileHead">history.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_08.html" target="main" class="fileHead">html.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_09.html" target="main" class="fileHead">jquery-1.1.3.1.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_10.html" target="main" class="fileHead">json.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_11.html" target="main" class="fileHead">platform.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_12.html" target="main" class="fileHead">signal.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_13.html" target="main" class="fileHead">string.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_14.html" target="main" class="fileHead">units.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_15.html" target="main" class="fileHead">SimileAjax.WindowManager</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_16.html" target="main" class="fileHead">SimileAjax.XmlHttp</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_17.html" target="main" class="fileHead">simile-ajax-api.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+ <li style="margin-bottom: 16px;">
+ <a href="_18.html" target="main" class="fileHead">simile-ajax-bundle.js</a>
+ <ul>
+
+ </ul>
+ </li>
+
+</ul>
+</body>
+</html> \ No newline at end of file
diff --git a/src/ajax/site/docs/function.gif b/src/ajax/site/docs/function.gif
new file mode 100644
index 0000000..be00b96
--- /dev/null
+++ b/src/ajax/site/docs/function.gif
Binary files differ
diff --git a/src/ajax/site/docs/index.html b/src/ajax/site/docs/index.html
new file mode 100644
index 0000000..3df8e5b
--- /dev/null
+++ b/src/ajax/site/docs/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
+"http://www.w3.org/TR/html4/frameset.dtd">
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>JsDoc</title>
+ <meta name="generator" content="JsDoc Toolkit 1.0">
+ </head>
+ <frameset cols="200,*">
+ <frame name="menu" src="file_list.html">
+ <frame name="main" src="splash.html">
+ </frameset>
+</html> \ No newline at end of file
diff --git a/src/ajax/site/docs/object.gif b/src/ajax/site/docs/object.gif
new file mode 100644
index 0000000..409b58e
--- /dev/null
+++ b/src/ajax/site/docs/object.gif
Binary files differ
diff --git a/src/ajax/site/docs/overview.gif b/src/ajax/site/docs/overview.gif
new file mode 100644
index 0000000..241c257
--- /dev/null
+++ b/src/ajax/site/docs/overview.gif
Binary files differ
diff --git a/src/ajax/site/docs/splash.html b/src/ajax/site/docs/splash.html
new file mode 100644
index 0000000..8c74951
--- /dev/null
+++ b/src/ajax/site/docs/splash.html
@@ -0,0 +1,7 @@
+´╗┐<html>
+ <head>
+ <title>JsDoc</title>
+ </head>
+ <body>
+ </body>
+</html> \ No newline at end of file
diff --git a/src/ajax/site/styles.css b/src/ajax/site/styles.css
new file mode 100644
index 0000000..58ac51c
--- /dev/null
+++ b/src/ajax/site/styles.css
@@ -0,0 +1,9 @@
+@import url("http://simile.mit.edu/styles/default.css");
+
+body {
+ margin-bottom: 20em;
+}
+
+table {
+ font-size: 100%;
+}
diff --git a/src/ajax/site/test.html b/src/ajax/site/test.html
new file mode 100644
index 0000000..b67b0c2
--- /dev/null
+++ b/src/ajax/site/test.html
@@ -0,0 +1,57 @@
+<html>
+<head>
+ <title>SIMILE | Ajax | Test</title>
+ <link rel='stylesheet' href='styles.css' type='text/css' />
+ <link rel="alternate" type="application/rdf+xml" href="doap.rdf" />
+ <style>
+ .result {
+ background: #eee;
+ border: 2px solid #aaa;
+ margin: 2em 0;
+ padding: 2em;
+ text-align: center;
+ font-size: 200%;
+ color: #800;
+ }
+ </style>
+
+ <script src="api/simile-ajax-api.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ function onLoad() {
+ var div = document.createElement("div");
+ div.className = "result";
+ div.innerHTML = (SimileAjax.loaded) ?
+ "Your browser seems to be supported." :
+ "Your browser is NOT supported";
+
+ document.getElementById("body").appendChild(div);
+ }
+ </script>
+</head>
+<body onload="onLoad();">
+<ul id="path">
+ <li><a href="http://simile.mit.edu/" title="Home">SIMILE</a></li>
+ <li><span>Ajax</span></li>
+</ul>
+
+<div id="body">
+ <h1>SIMILE Ajax Library</h1>
+ <p>This is a library that various Simile client-side software components
+ are or will be based on. The official homepage for this project is
+ <a href="http://simile.mit.edu/wiki/Ajax">here</a>.
+ </p>
+
+ <p>This page is a test for this library. Load it up in your browser and
+ see if there is any error reported. Check your browser's Javascript
+ console if it has one.
+ </p>
+
+ <noscript>
+ <div class="result">
+ Your browser does not support Javascript currently.
+ Please turn on Javascript support or use a different
+ browser.
+ </div>
+ </noscript>
+</body>
+</html>
diff --git a/src/graphics/blue-circle.psd b/src/graphics/blue-circle.psd
new file mode 100644
index 0000000..d897116
--- /dev/null
+++ b/src/graphics/blue-circle.psd
Binary files differ
diff --git a/src/graphics/bubble-arrows.png b/src/graphics/bubble-arrows.png
new file mode 100644
index 0000000..0093b52
--- /dev/null
+++ b/src/graphics/bubble-arrows.png
Binary files differ
diff --git a/src/graphics/bubble-body-and-arrows.png b/src/graphics/bubble-body-and-arrows.png
new file mode 100644
index 0000000..c276adc
--- /dev/null
+++ b/src/graphics/bubble-body-and-arrows.png
Binary files differ
diff --git a/src/graphics/bubble-body.png b/src/graphics/bubble-body.png
new file mode 100644
index 0000000..75819df
--- /dev/null
+++ b/src/graphics/bubble-body.png
Binary files differ
diff --git a/src/graphics/bubble-bottom-arrow.png b/src/graphics/bubble-bottom-arrow.png
new file mode 100644
index 0000000..f6ae809
--- /dev/null
+++ b/src/graphics/bubble-bottom-arrow.png
Binary files differ
diff --git a/src/graphics/bubble-bottom-left.png b/src/graphics/bubble-bottom-left.png
new file mode 100644
index 0000000..6d32026
--- /dev/null
+++ b/src/graphics/bubble-bottom-left.png
Binary files differ
diff --git a/src/graphics/bubble-bottom-right.png b/src/graphics/bubble-bottom-right.png
new file mode 100644
index 0000000..e5dc136
--- /dev/null
+++ b/src/graphics/bubble-bottom-right.png
Binary files differ
diff --git a/src/graphics/bubble-bottom.png b/src/graphics/bubble-bottom.png
new file mode 100644
index 0000000..166b057
--- /dev/null
+++ b/src/graphics/bubble-bottom.png
Binary files differ
diff --git a/src/graphics/bubble-left-arrow.png b/src/graphics/bubble-left-arrow.png
new file mode 100644
index 0000000..8c31f1d
--- /dev/null
+++ b/src/graphics/bubble-left-arrow.png
Binary files differ
diff --git a/src/graphics/bubble-left.png b/src/graphics/bubble-left.png
new file mode 100644
index 0000000..3826722
--- /dev/null
+++ b/src/graphics/bubble-left.png
Binary files differ
diff --git a/src/graphics/bubble-right-arrow.png b/src/graphics/bubble-right-arrow.png
new file mode 100644
index 0000000..11e2873
--- /dev/null
+++ b/src/graphics/bubble-right-arrow.png
Binary files differ
diff --git a/src/graphics/bubble-right.png b/src/graphics/bubble-right.png
new file mode 100644
index 0000000..f66f879
--- /dev/null
+++ b/src/graphics/bubble-right.png
Binary files differ
diff --git a/src/graphics/bubble-top-arrow.png b/src/graphics/bubble-top-arrow.png
new file mode 100644
index 0000000..e10e4a9
--- /dev/null
+++ b/src/graphics/bubble-top-arrow.png
Binary files differ
diff --git a/src/graphics/bubble-top-left.png b/src/graphics/bubble-top-left.png
new file mode 100644
index 0000000..d69841f
--- /dev/null
+++ b/src/graphics/bubble-top-left.png
Binary files differ
diff --git a/src/graphics/bubble-top-right.png b/src/graphics/bubble-top-right.png
new file mode 100644
index 0000000..9ab219a
--- /dev/null
+++ b/src/graphics/bubble-top-right.png
Binary files differ
diff --git a/src/graphics/bubble-top.png b/src/graphics/bubble-top.png
new file mode 100644
index 0000000..917defa
--- /dev/null
+++ b/src/graphics/bubble-top.png
Binary files differ
diff --git a/src/graphics/bubble.psd b/src/graphics/bubble.psd
new file mode 100644
index 0000000..dd143fc
--- /dev/null
+++ b/src/graphics/bubble.psd
Binary files differ
diff --git a/src/graphics/close-button.psd b/src/graphics/close-button.psd
new file mode 100644
index 0000000..ab98a01
--- /dev/null
+++ b/src/graphics/close-button.psd
Binary files differ
diff --git a/src/graphics/copyright.psd b/src/graphics/copyright.psd
new file mode 100644
index 0000000..fa062dd
--- /dev/null
+++ b/src/graphics/copyright.psd
Binary files differ
diff --git a/src/graphics/ether.indd b/src/graphics/ether.indd
new file mode 100644
index 0000000..511f48b
--- /dev/null
+++ b/src/graphics/ether.indd
Binary files differ
diff --git a/src/graphics/gray-circle.psd b/src/graphics/gray-circle.psd
new file mode 100644
index 0000000..b2eb83f
--- /dev/null
+++ b/src/graphics/gray-circle.psd
Binary files differ
diff --git a/src/graphics/green-circle.psd b/src/graphics/green-circle.psd
new file mode 100644
index 0000000..8672408
--- /dev/null
+++ b/src/graphics/green-circle.psd
Binary files differ
diff --git a/src/graphics/message.png b/src/graphics/message.png
new file mode 100644
index 0000000..1026b11
--- /dev/null
+++ b/src/graphics/message.png
Binary files differ
diff --git a/src/graphics/message.psd b/src/graphics/message.psd
new file mode 100644
index 0000000..95dcfcf
--- /dev/null
+++ b/src/graphics/message.psd
Binary files differ
diff --git a/src/graphics/red-circle.psd b/src/graphics/red-circle.psd
new file mode 100644
index 0000000..6bb4c28
--- /dev/null
+++ b/src/graphics/red-circle.psd
Binary files differ
diff --git a/src/graphics/red-pin.psd b/src/graphics/red-pin.psd
new file mode 100644
index 0000000..19a0b65
--- /dev/null
+++ b/src/graphics/red-pin.psd
Binary files differ
diff --git a/src/graphics/sundial-simile.psd b/src/graphics/sundial-simile.psd
new file mode 100644
index 0000000..21f14a4
--- /dev/null
+++ b/src/graphics/sundial-simile.psd
Binary files differ
diff --git a/src/graphics/sundial.png b/src/graphics/sundial.png
new file mode 100644
index 0000000..d6de5e8
--- /dev/null
+++ b/src/graphics/sundial.png
Binary files differ
diff --git a/src/graphics/sundial.psd b/src/graphics/sundial.psd
new file mode 100644
index 0000000..4883590
--- /dev/null
+++ b/src/graphics/sundial.psd
Binary files differ
diff --git a/src/graphics/sundial.skb b/src/graphics/sundial.skb
new file mode 100644
index 0000000..777ab63
--- /dev/null
+++ b/src/graphics/sundial.skb
Binary files differ
diff --git a/src/graphics/sundial.skp b/src/graphics/sundial.skp
new file mode 100644
index 0000000..0b0c44a
--- /dev/null
+++ b/src/graphics/sundial.skp
Binary files differ
diff --git a/src/graphics/timeline.indd b/src/graphics/timeline.indd
new file mode 100644
index 0000000..41adca6
--- /dev/null
+++ b/src/graphics/timeline.indd
Binary files differ
diff --git a/src/misc/fix_svn_props.txt b/src/misc/fix_svn_props.txt
new file mode 100644
index 0000000..282442a
--- /dev/null
+++ b/src/misc/fix_svn_props.txt
@@ -0,0 +1,43 @@
+
+
+# set the properties of the test files so they will be served properly from the svn repo
+#
+# designed to be copy/pasted into your shell terminal
+
+cd src/webapp/examples
+svn propdel svn:executable index.html
+svn propset svn:mime-type text/html index.html
+
+svn propdel svn:executable compact-painter/compact-painter.html
+svn propset svn:mime-type text/html compact-painter/compact-painter.html
+svn propdel svn:executable cubism/cubism.html
+svn propset svn:mime-type text/html cubism/cubism.html
+svn propdel svn:executable dinosaurs/dinosaurs.html
+svn propset svn:mime-type text/html dinosaurs/dinosaurs2.html
+svn propdel svn:executable jfk/jfk.html
+svn propset svn:mime-type text/html jfk/jfk.html
+svn propdel svn:executable jfk_i18n/jfk.html
+svn propset svn:mime-type text/html jfk_i18n/jfk.html
+svn propdel svn:executable monet/monet.html
+svn propset svn:mime-type text/html monet/monet.html
+svn propdel svn:executable religions/christianity.html
+svn propset svn:mime-type text/html religions/christianity.html
+svn propdel svn:executable religions/jewish-history.html
+svn propset svn:mime-type text/html religions/jewish-history.html
+svn propdel svn:executable religions/religions.html
+svn propset svn:mime-type text/html religions/religions.html
+svn propdel svn:executable test_example/test.html
+svn propset svn:mime-type text/html test_example/test.html
+svn propdel svn:executable test_example/firefox_mac_test_case.html
+svn propset svn:mime-type text/html test_example/firefox_mac_test_case.html
+svn propdel svn:executable test_example2/test_example2.html
+svn propset svn:mime-type text/html test_example2/test_example2.html
+
+# set mime type to be text/xml for xml files
+
+svn propset svn:mime-type text/xml dinosaurs/dinosaurs.xml
+svn propset svn:mime-type text/xml jfk_i18n/jfk.xml
+svn propset svn:mime-type text/xml jfk/jfk.xml
+svn propset svn:mime-type text/xml monet/monet.xml
+svn propset svn:mime-type text/xml religions/christianity.xml
+svn propset svn:mime-type text/xml religions/jewish.xml
diff --git a/src/misc/japanese-eras.xls b/src/misc/japanese-eras.xls
new file mode 100644
index 0000000..0f1af17
--- /dev/null
+++ b/src/misc/japanese-eras.xls
Binary files differ
diff --git a/src/webapp/api/ext/geochrono/geochrono-api.js b/src/webapp/api/ext/geochrono/geochrono-api.js
new file mode 100644
index 0000000..b16a2c3
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/geochrono-api.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Geochrono Extension
+ *
+ * This file will load all the Javascript files
+ * necessary to make the extension work.
+ *
+ *==================================================
+ */
+
+(function() {
+ var javascriptFiles = [
+ "geochrono.js",
+ "units.js",
+ "ether-painters.js",
+ "labellers.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var localizedJavascriptFiles = [
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en" // English
+ ];
+
+ try {
+ var includeJavascriptFile = function(filename) {
+ document.write("<script src='" + Timeline.urlPrefix + "ext/geochrono/scripts/" + filename + "' type='text/javascript'></script>");
+ };
+ var includeCssFile = function(filename) {
+ document.write("<link rel='stylesheet' href='" + Timeline.urlPrefix + "ext/geochrono/styles/" + filename + "' type='text/css'/>");
+ }
+
+ /*
+ * Include non-localized files
+ */
+ for (var i = 0; i < javascriptFiles.length; i++) {
+ includeJavascriptFile(javascriptFiles[i]);
+ }
+ for (var i = 0; i < cssFiles.length; i++) {
+ includeCssFile(cssFiles[i]);
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ tryLocale(Timeline.serverLocale);
+ tryLocale(Timeline.clientLocale);
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ for (var i = 0; i < localizedJavascriptFiles.length; i++) {
+ includeJavascriptFile("l10n/" + locale + "/" + localizedJavascriptFiles[i]);
+ }
+ for (var i = 0; i < localizedCssFiles.length; i++) {
+ includeCssFile("l10n/" + locale + "/" + localizedCssFiles[i]);
+ }
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/src/webapp/api/ext/geochrono/scripts/ether-painters.js b/src/webapp/api/ext/geochrono/scripts/ether-painters.js
new file mode 100644
index 0000000..c9c0453
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/scripts/ether-painters.js
@@ -0,0 +1,204 @@
+´╗┐/*==================================================
+ * Geochrono Ether Painter
+ *==================================================
+ */
+
+Timeline.GeochronoEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._intervalUnit = params.intervalUnit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+ this._theme = params.theme;
+};
+
+Timeline.GeochronoEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && typeof this._params.align == "string") ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.GeochronoEtherMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GeochronoEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.GeochronoEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = Math.ceil(Timeline.GeochronoUnit.toNumber(this._band.getMinDate()));
+ var maxDate = Math.floor(Timeline.GeochronoUnit.toNumber(this._band.getMaxDate()));
+
+ var increment;
+ var hasMore;
+ (function(intervalUnit, multiple) {
+ var dates;
+
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons; break;
+ default:
+ hasMore = function() {
+ return minDate > 0 && minDate > maxDate;
+ }
+ increment = function() {
+ minDate -= multiple;
+ };
+ return;
+ }
+
+ var startIndex = dates.length - 1;
+ while (startIndex > 0) {
+ if (minDate <= dates[startIndex].start) {
+ break;
+ }
+ startIndex--;
+ }
+
+ minDate = dates[startIndex].start;
+ hasMore = function() {
+ return startIndex < (dates.length - 1) && minDate > maxDate;
+ };
+ increment = function() {
+ startIndex++;
+ minDate = dates[startIndex].start;
+ };
+ })(this._intervalUnit, this._multiple);
+
+ var labeller = this._band.getLabeller();
+ while (true) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ Timeline.GeochronoUnit.fromNumber(minDate),
+ labeller,
+ this._intervalUnit,
+ this._markerLayer,
+ this._lineLayer
+ );
+ if (hasMore()) {
+ increment();
+ } else {
+ break;
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GeochronoEtherPainter.prototype.softPaint = function() {
+};
+
+
+/*==================================================
+ * Geochrono Ether Marker Layout
+ *==================================================
+ */
+
+Timeline.GeochronoEtherMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ (label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+}; \ No newline at end of file
diff --git a/src/webapp/api/ext/geochrono/scripts/geochrono.js b/src/webapp/api/ext/geochrono/scripts/geochrono.js
new file mode 100644
index 0000000..dc9716a
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/scripts/geochrono.js
@@ -0,0 +1,518 @@
+/*==================================================
+ * Geochrono
+ *==================================================
+ */
+Timeline.Geochrono = new Object();
+Timeline.Geochrono.eons = [
+ { name: "Proterozoic",
+ start: 2500.000
+ },
+ { name: "Phanerozoic",
+ start: 542.000
+ }
+];
+Timeline.Geochrono.eras = [
+ { name: "Paleoarchean",
+ start: 3600.000
+ },
+ { name: "Mesoarchean",
+ start: 3200.000
+ },
+ { name: "Neoarchean",
+ start: 2800.000
+ },
+ { name: "Paleoproterozoic",
+ start: 2500.000
+ },
+ { name: "Mesoproterozoic",
+ start: 1600.000
+ },
+ { name: "Neoproterozoic",
+ start: 1000.000
+ },
+ { name: "Paleozoic",
+ start: 542.000
+ },
+ { name: "Mesozoic",
+ start: 251.000
+ },
+ { name: "Cenozoic",
+ start: 65.500
+ }
+];
+Timeline.Geochrono.periods = [
+ { name: "Siderian",
+ start: 2500.000
+ },
+ { name: "Rhyacian",
+ start: 2300.000
+ },
+ { name: "Orosirian",
+ start: 2050.000
+ },
+ { name: "Statherian",
+ start: 1800.000
+ },
+ { name: "Calymmian",
+ start: 1600.000
+ },
+ { name: "Ectasian",
+ start: 1400.000
+ },
+ { name: "Stenian",
+ start: 1200.000
+ },
+ { name: "Tonian",
+ start: 1000.000
+ },
+ { name: "Cryogenian",
+ start: 850.000
+ },
+ { name: "Ediacaran",
+ start: 600.000
+ },
+ { name: "Cambrian",
+ start: 542.000
+ },
+ { name: "Ordovician",
+ start: 488.300
+ },
+ { name: "Silurian",
+ start: 443.700
+ },
+ { name: "Devonian",
+ start: 416.000
+ },
+ { name: "Carboniferous",
+ start: 359.200
+ },
+ { name: "Permian",
+ start: 299.000
+ },
+ { name: "Triassic",
+ start: 251.000
+ },
+ { name: "Jurassic",
+ start: 199.600
+ },
+ { name: "Cretaceous",
+ start: 145.500
+ },
+ { name: "Paleogene",
+ start: 65.500
+ },
+ { name: "Neogene",
+ start: 23.030
+ }
+];
+Timeline.Geochrono.epoches = [
+ { name: "Lower Cambrian",
+ start: 542.000
+ },
+ { name: "Middle Cambrian",
+ start: 513.000
+ },
+ { name: "Furongian",
+ start: 501.000
+ },
+ { name: "Lower Ordovician",
+ start: 488.300
+ },
+ { name: "Middle Ordovician",
+ start: 471.800
+ },
+ { name: "Upper Ordovician",
+ start: 460.900
+ },
+ { name: "Llandovery",
+ start: 443.700
+ },
+ { name: "Wenlock",
+ start: 428.200
+ },
+ { name: "Ludlow",
+ start: 422.900
+ },
+ { name: "Pridoli",
+ start: 418.700
+ },
+ { name: "Lower Devonian",
+ start: 416.000
+ },
+ { name: "Middle Devonian",
+ start: 397.500
+ },
+ { name: "Upper Devonian",
+ start: 385.300
+ },
+ { name: "Mississippian",
+ start: 359.200
+ },
+ { name: "Pennsylvanian",
+ start: 318.100
+ },
+ { name: "Cisuralian",
+ start: 299.000
+ },
+ { name: "Guadalupian",
+ start: 270.600
+ },
+ { name: "Lopingian",
+ start: 260.400
+ },
+ { name: "Lower Triassic",
+ start: 251.000
+ },
+ { name: "Middle Triassic",
+ start: 245.000
+ },
+ { name: "Upper Triassic",
+ start: 228.000
+ },
+ { name: "Lower Jurassic",
+ start: 199.600
+ },
+ { name: "Middle Jurassic",
+ start: 175.600
+ },
+ { name: "Upper Jurassic",
+ start: 161.200
+ },
+ { name: "Lower Cretaceous",
+ start: 145.500
+ },
+ { name: "Upper Cretaceous",
+ start: 99.600
+ },
+ { name: "Paleocene",
+ start: 65.500
+ },
+ { name: "Eocene",
+ start: 55.800
+ },
+ { name: "Oligocene",
+ start: 33.900
+ },
+ { name: "Miocene",
+ start: 23.030
+ },
+ { name: "Pliocene",
+ start: 5.332
+ },
+ { name: "Pleistocene",
+ start: 1.806
+ },
+ { name: "Holocene",
+ start: 0.012
+ }
+];
+Timeline.Geochrono.ages = [
+ { name: "-",
+ start: 542.000
+ },
+ { name: "-",
+ start: 513.000
+ },
+ { name: "Paibian",
+ start: 501.000
+ },
+ { name: "Tremadocian",
+ start: 488.300
+ },
+ { name: "-",
+ start: 478.600
+ },
+ { name: "-",
+ start: 471.800
+ },
+ { name: "Darriwilian",
+ start: 468.100
+ },
+ { name: "-",
+ start: 460.900
+ },
+ { name: "-",
+ start: 455.800
+ },
+ { name: "Hirnantian",
+ start: 445.600
+ },
+ { name: "Rhuddanian",
+ start: 443.700
+ },
+ { name: "Aeronian",
+ start: 439.000
+ },
+ { name: "Telychian",
+ start: 436.100
+ },
+ { name: "Sheinwoodian",
+ start: 428.200
+ },
+ { name: "Homerian",
+ start: 426.200
+ },
+ { name: "Gorstian",
+ start: 422.900
+ },
+ { name: "Ludfordian",
+ start: 421.300
+ },
+ { name: "-",
+ start: 418.700
+ },
+ { name: "Lochkovian",
+ start: 416.000
+ },
+ { name: "Pragian",
+ start: 411.200
+ },
+ { name: "Emsian",
+ start: 407.000
+ },
+ { name: "Eifelian",
+ start: 397.500
+ },
+ { name: "Givetian",
+ start: 391.800
+ },
+ { name: "Frasnian",
+ start: 385.300
+ },
+ { name: "Famennian",
+ start: 374.500
+ },
+ { name: "Tournaisian",
+ start: 359.200
+ },
+ { name: "Visean",
+ start: 345.300
+ },
+ { name: "Serpukhovian",
+ start: 326.400
+ },
+ { name: "Bashkirian",
+ start: 318.100
+ },
+ { name: "Moscovian",
+ start: 311.700
+ },
+ { name: "Kazimovian",
+ start: 306.500
+ },
+ { name: "Gzhelian",
+ start: 303.900
+ },
+ { name: "Asselian",
+ start: 299.000
+ },
+ { name: "Sakmarian",
+ start: 294.600
+ },
+ { name: "Artinskian",
+ start: 284.400
+ },
+ { name: "Kungurian",
+ start: 275.600
+ },
+ { name: "Roadian",
+ start: 270.600
+ },
+ { name: "Wordian",
+ start: 268.000
+ },
+ { name: "Capitanian",
+ start: 265.800
+ },
+ { name: "Wuchiapingian",
+ start: 260.400
+ },
+ { name: "Changhsingian",
+ start: 253.800
+ },
+ { name: "Induan",
+ start: 251.000
+ },
+ { name: "Olenekian",
+ start: 249.700
+ },
+ { name: "Anisian",
+ start: 245.000
+ },
+ { name: "Ladinian",
+ start: 237.000
+ },
+ { name: "Carnian",
+ start: 228.000
+ },
+ { name: "Norian",
+ start: 216.500
+ },
+ { name: "Rhaetian",
+ start: 203.600
+ },
+ { name: "Hettangian",
+ start: 199.600
+ },
+ { name: "Sinemurian",
+ start: 196.500
+ },
+ { name: "Pliensbachian",
+ start: 189.600
+ },
+ { name: "Toarcian",
+ start: 183.000
+ },
+ { name: "Aalenian",
+ start: 175.600
+ },
+ { name: "Bajocian",
+ start: 171.600
+ },
+ { name: "Bathonian",
+ start: 167.700
+ },
+ { name: "Callovian",
+ start: 164.700
+ },
+ { name: "Oxfordian",
+ start: 161.200
+ },
+ { name: "Kimmeridgian",
+ start: 155.000
+ },
+ { name: "Tithonian",
+ start: 150.800
+ },
+ { name: "Berriasian",
+ start: 145.500
+ },
+ { name: "Valanginian",
+ start: 140.200
+ },
+ { name: "Hauterivian",
+ start: 136.400
+ },
+ { name: "Barremian",
+ start: 130.000
+ },
+ { name: "Aptian",
+ start: 125.000
+ },
+ { name: "Albian",
+ start: 112.000
+ },
+ { name: "Cenomanian",
+ start: 99.600
+ },
+ { name: "Turonian",
+ start: 93.500
+ },
+ { name: "Coniacian",
+ start: 89.300
+ },
+ { name: "Santonian",
+ start: 85.800
+ },
+ { name: "Campanian",
+ start: 83.500
+ },
+ { name: "Maastrichtian",
+ start: 70.600
+ },
+ { name: "Danian",
+ start: 65.500
+ },
+ { name: "Selandian",
+ start: 61.700
+ },
+ { name: "Thanetian",
+ start: 58.700
+ },
+ { name: "Ypresian",
+ start: 55.800
+ },
+ { name: "Lutetian",
+ start: 48.600
+ },
+ { name: "Bartonian",
+ start: 40.400
+ },
+ { name: "Priabonian",
+ start: 37.200
+ },
+ { name: "Rupelian",
+ start: 33.900
+ },
+ { name: "Chattian",
+ start: 28.400
+ },
+ { name: "Aquitanian",
+ start: 23.030
+ },
+ { name: "Burdigalian",
+ start: 20.430
+ },
+ { name: "Langhian",
+ start: 15.970
+ },
+ { name: "Serravallian",
+ start: 13.650
+ },
+ { name: "Tortonian",
+ start: 11.608
+ },
+ { name: "Messinian",
+ start: 7.246
+ },
+ { name: "Zanclean",
+ start: 5.332
+ },
+ { name: "Piacenzian",
+ start: 3.600
+ },
+ { name: "Gelasian",
+ start: 2.588
+ }
+];
+
+Timeline.Geochrono.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : Timeline.GeochronoUnit.makeDefaultValue(),
+ interval: 1,
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.GeochronoEtherPainter({
+ intervalUnit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ align: params.align,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = ("overview" in params && params.overview) ?
+ new Timeline.OverviewEventPainter(eventPainterParams) :
+ new Timeline.DetailedEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+}; \ No newline at end of file
diff --git a/src/webapp/api/ext/geochrono/scripts/l10n/en/labellers.js b/src/webapp/api/ext/geochrono/scripts/l10n/en/labellers.js
new file mode 100644
index 0000000..7e66701
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/scripts/l10n/en/labellers.js
@@ -0,0 +1,10 @@
+/*==================================================
+ * Localization of Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller.eonNames["en"] = Timeline.Geochrono.eons;
+Timeline.GeochronoLabeller.eraNames["en"] = Timeline.Geochrono.eras;
+Timeline.GeochronoLabeller.periodNames["en"] = Timeline.Geochrono.periods;
+Timeline.GeochronoLabeller.epochNames["en"] = Timeline.Geochrono.epoches;
+Timeline.GeochronoLabeller.ageNames["en"] = Timeline.Geochrono.ages;
diff --git a/src/webapp/api/ext/geochrono/scripts/labellers.js b/src/webapp/api/ext/geochrono/scripts/labellers.js
new file mode 100644
index 0000000..3aabd15
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/scripts/labellers.js
@@ -0,0 +1,52 @@
+/*==================================================
+ * Geochrono Labeller
+ *==================================================
+ */
+
+Timeline.GeochronoLabeller = function(locale) {
+ this._locale = locale;
+};
+
+Timeline.GeochronoLabeller.eonNames = [];
+Timeline.GeochronoLabeller.eraNames = [];
+Timeline.GeochronoLabeller.periodNames = [];
+Timeline.GeochronoLabeller.epochNames = [];
+Timeline.GeochronoLabeller.ageNames = [];
+
+Timeline.GeochronoLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var n = Timeline.GeochronoUnit.toNumber(date);
+ var dates, names;
+ switch (intervalUnit) {
+ case Timeline.GeochronoUnit.AGE:
+ dates = Timeline.Geochrono.ages;
+ names = Timeline.GeochronoLabeller.ageNames; break;
+ case Timeline.GeochronoUnit.EPOCH:
+ dates = Timeline.Geochrono.epoches;
+ names = Timeline.GeochronoLabeller.epochNames; break;
+ case Timeline.GeochronoUnit.PERIOD:
+ dates = Timeline.Geochrono.periods;
+ names = Timeline.GeochronoLabeller.periodNames; break;
+ case Timeline.GeochronoUnit.ERA:
+ dates = Timeline.Geochrono.eras;
+ names = Timeline.GeochronoLabeller.eraNames; break;
+ case Timeline.GeochronoUnit.EON:
+ dates = Timeline.Geochrono.eons;
+ names = Timeline.GeochronoLabeller.eonNames; break;
+ default:
+ return { text: n, emphasized: false };
+ }
+
+ for (var i = dates.length - 1; i >= 0; i--) {
+ if (n <= dates[i].start) {
+ return {
+ text: names[this._locale][i].name,
+ emphasized: n == dates[i].start
+ }
+ }
+ }
+ return { text: n, emphasized: false };
+};
+
+Timeline.GeochronoLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.GeochronoUnit.toNumber(date) + "ma";
+};
diff --git a/src/webapp/api/ext/geochrono/scripts/units.js b/src/webapp/api/ext/geochrono/scripts/units.js
new file mode 100644
index 0000000..86182ff
--- /dev/null
+++ b/src/webapp/api/ext/geochrono/scripts/units.js
@@ -0,0 +1,86 @@
+/*==================================================
+ * Geochrono Unit
+ *==================================================
+ */
+
+Timeline.GeochronoUnit = new Object();
+
+Timeline.GeochronoUnit.MA = 0;
+Timeline.GeochronoUnit.AGE = 1;
+Timeline.GeochronoUnit.EPOCH = 2;
+Timeline.GeochronoUnit.PERIOD = 3;
+Timeline.GeochronoUnit.ERA = 4;
+Timeline.GeochronoUnit.EON = 5;
+
+Timeline.GeochronoUnit.getParser = function(format) {
+ return Timeline.GeochronoUnit.parseFromObject;
+};
+
+Timeline.GeochronoUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.GeochronoLabeller(locale);
+};
+
+Timeline.GeochronoUnit.wrapMA = function (n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.makeDefaultValue = function () {
+ return Timeline.GeochronoUnit.wrapMA(0);
+};
+
+Timeline.GeochronoUnit.cloneValue = function (v) {
+ return new Timeline.GeochronoUnit._MA(v._n);
+};
+
+Timeline.GeochronoUnit.parseFromObject = function(o) {
+ if (o instanceof Timeline.GeochronoUnit._MA) {
+ return o;
+ } else if (typeof o == "number") {
+ return Timeline.GeochronoUnit.wrapMA(o);
+ } else if (typeof o == "string" && o.length > 0) {
+ return Timeline.GeochronoUnit.wrapMA(Number(o));
+ } else {
+ return null;
+ }
+};
+
+Timeline.GeochronoUnit.toNumber = function(v) {
+ return v._n;
+};
+
+Timeline.GeochronoUnit.fromNumber = function(n) {
+ return new Timeline.GeochronoUnit._MA(n);
+};
+
+Timeline.GeochronoUnit.compare = function(v1, v2) {
+ var n1, n2;
+ if (typeof v1 == "object") {
+ n1 = v1._n;
+ } else {
+ n1 = Number(v1);
+ }
+ if (typeof v2 == "object") {
+ n2 = v2._n;
+ } else {
+ n2 = Number(v2);
+ }
+
+ return n2 - n1;
+};
+
+Timeline.GeochronoUnit.earlier = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.later = function(v1, v2) {
+ return Timeline.GeochronoUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.GeochronoUnit.change = function(v, n) {
+ return new Timeline.GeochronoUnit._MA(v._n - n);
+};
+
+Timeline.GeochronoUnit._MA = function(n) {
+ this._n = n;
+};
+
diff --git a/src/webapp/api/ext/planning/planning-api.js b/src/webapp/api/ext/planning/planning-api.js
new file mode 100644
index 0000000..9d92681
--- /dev/null
+++ b/src/webapp/api/ext/planning/planning-api.js
@@ -0,0 +1,92 @@
+/*==================================================
+ * Planning Extension
+ *
+ * This file will load all the Javascript files
+ * necessary to make the extension work.
+ *
+ *==================================================
+ */
+
+(function() {
+ var javascriptFiles = [
+ "planning.js",
+ "units.js",
+ "ether-painters.js",
+ "labellers.js"
+ ];
+ var cssFiles = [
+ ];
+
+ var localizedJavascriptFiles = [
+ "labellers.js"
+ ];
+ var localizedCssFiles = [
+ ];
+
+ // ISO-639 language codes, ISO-3166 country codes (2 characters)
+ var supportedLocales = [
+ "en" // English
+ ];
+
+ try {
+ var includeJavascriptFile = function(filename) {
+ document.write("<script src='" + Timeline.urlPrefix + "ext/planning/scripts/" + filename + "' type='text/javascript'></script>");
+ };
+ var includeCssFile = function(filename) {
+ document.write("<link rel='stylesheet' href='" + Timeline.urlPrefix + "ext/planning/styles/" + filename + "' type='text/css'/>");
+ }
+
+ /*
+ * Include non-localized files
+ */
+ for (var i = 0; i < javascriptFiles.length; i++) {
+ includeJavascriptFile(javascriptFiles[i]);
+ }
+ for (var i = 0; i < cssFiles.length; i++) {
+ includeCssFile(cssFiles[i]);
+ }
+
+ /*
+ * Include localized files
+ */
+ var loadLocale = [];
+ var tryExactLocale = function(locale) {
+ for (var l = 0; l < supportedLocales.length; l++) {
+ if (locale == supportedLocales[l]) {
+ loadLocale[locale] = true;
+ return true;
+ }
+ }
+ return false;
+ }
+ var tryLocale = function(locale) {
+ if (tryExactLocale(locale)) {
+ return locale;
+ }
+
+ var dash = locale.indexOf("-");
+ if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+ return locale.substr(0, dash);
+ }
+
+ return null;
+ }
+
+ tryLocale(Timeline.serverLocale);
+ tryLocale(Timeline.clientLocale);
+
+ for (var l = 0; l < supportedLocales.length; l++) {
+ var locale = supportedLocales[l];
+ if (loadLocale[locale]) {
+ for (var i = 0; i < localizedJavascriptFiles.length; i++) {
+ includeJavascriptFile("l10n/" + locale + "/" + localizedJavascriptFiles[i]);
+ }
+ for (var i = 0; i < localizedCssFiles.length; i++) {
+ includeCssFile("l10n/" + locale + "/" + localizedCssFiles[i]);
+ }
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+})(); \ No newline at end of file
diff --git a/src/webapp/api/ext/planning/scripts/ether-painters.js b/src/webapp/api/ext/planning/scripts/ether-painters.js
new file mode 100644
index 0000000..75c2a62
--- /dev/null
+++ b/src/webapp/api/ext/planning/scripts/ether-painters.js
@@ -0,0 +1,176 @@
+/*==================================================
+ * Planning Ether Painter
+ *==================================================
+ */
+
+Timeline.PlanningEtherPainter = function(params, band, timeline) {
+ this._params = params;
+ this._intervalUnit = params.intervalUnit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+ this._theme = params.theme;
+};
+
+Timeline.PlanningEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && typeof this._params.align == "string") ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.PlanningEtherMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.PlanningEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.PlanningEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = Math.max(0, Math.ceil(Timeline.PlanningUnit.toNumber(this._band.getMinDate())));
+ var maxDate = Math.floor(Timeline.PlanningUnit.toNumber(this._band.getMaxDate()));
+
+ var hasMore = function() {
+ return minDate < maxDate;
+ };
+ var change = 1;
+ var multiple = this._multiple;
+ switch (this._intervalUnit) {
+ case Timeline.PlanningUnit.DAY: change = 1; break;
+ case Timeline.PlanningUnit.WEEK: change = 7; break;
+ case Timeline.PlanningUnit.MONTH: change = 28; break;
+ case Timeline.PlanningUnit.QUARTER: change = 28 * 3; break;
+ case Timeline.PlanningUnit.YEAR: change = 28 * 12; break;
+ }
+ var increment = function() {
+ minDate += change * multiple;
+ };
+
+ var labeller = this._band.getLabeller();
+ while (true) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ Timeline.PlanningUnit.fromNumber(minDate),
+ labeller,
+ this._intervalUnit,
+ this._markerLayer,
+ this._lineLayer
+ );
+ if (hasMore()) {
+ increment();
+ } else {
+ break;
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.PlanningEtherPainter.prototype.softPaint = function() {
+};
+
+
+/*==================================================
+ * Planning Ether Marker Layout
+ *==================================================
+ */
+
+Timeline.PlanningEtherMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.style.position = "absolute";
+
+ if (lineTheme.opacity < 100) {
+ Timeline.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ divLine.style.borderLeft = "1px solid " + lineTheme.color;
+ divLine.style.left = offset + "px";
+ divLine.style.width = "1px";
+ divLine.style.top = "0px";
+ divLine.style.height = "100%";
+ } else {
+ divLine.style.borderTop = "1px solid " + lineTheme.color;
+ divLine.style.top = offset + "px";
+ divLine.style.height = "1px";
+ divLine.style.left = "0px";
+ divLine.style.width = "100%";
+ }
+ lineDiv.appendChild(divLine);
+ }
+
+ var label = labeller.labelInterval(date, unit);
+
+ var div = timeline.getDocument().createElement("div");
+ div.innerHTML = label.text;
+ div.style.position = "absolute";
+ (label.emphasized ? emphasizedLabelStyler : labelStyler)(div);
+
+ this.positionDiv(div, offset);
+ markerDiv.appendChild(div);
+
+ return div;
+ };
+}; \ No newline at end of file
diff --git a/src/webapp/api/ext/planning/scripts/l10n/en/labellers.js b/src/webapp/api/ext/planning/scripts/l10n/en/labellers.js
new file mode 100644
index 0000000..cdbac8c
--- /dev/null
+++ b/src/webapp/api/ext/planning/scripts/l10n/en/labellers.js
@@ -0,0 +1,12 @@
+/*==================================================
+ * Localization of Planning Labeller
+ *==================================================
+ */
+
+Timeline.PlanningLabeller.labels["en"] = {
+ dayPrefix: "d",
+ weekPrefix: "w",
+ monthPrefix: "m",
+ quarterPrefix: "q",
+ yearPrefix: "y"
+}; \ No newline at end of file
diff --git a/src/webapp/api/ext/planning/scripts/labellers.js b/src/webapp/api/ext/planning/scripts/labellers.js
new file mode 100644
index 0000000..46e5a69
--- /dev/null
+++ b/src/webapp/api/ext/planning/scripts/labellers.js
@@ -0,0 +1,33 @@
+/*==================================================
+ * Planning Labeller
+ *==================================================
+ */
+
+Timeline.PlanningLabeller = function(locale) {
+ this._locale = locale;
+};
+
+Timeline.PlanningLabeller.labels = [];
+
+Timeline.PlanningLabeller.prototype.labelInterval = function(date, intervalUnit) {
+ var n = Timeline.PlanningUnit.toNumber(date);
+
+ var prefix = "";
+ var divider = 1;
+ var divider2 = 7;
+ var labels = Timeline.PlanningLabeller.labels[this._locale];
+
+ switch (intervalUnit) {
+ case Timeline.PlanningUnit.DAY: prefix = labels.dayPrefix; break;
+ case Timeline.PlanningUnit.WEEK: prefix = labels.weekPrefix; divider = 7; divider2 = divider * 4; break;
+ case Timeline.PlanningUnit.MONTH: prefix = labels.monthPrefix; divider = 28; divider2 = divider * 3; break;
+ case Timeline.PlanningUnit.QUARTER: prefix = labels.quarterPrefix; divider = 28 * 3; divider2 = divider * 4; break;
+ case Timeline.PlanningUnit.YEAR: prefix = labels.yearPrefix; divider = 28 * 12; divider2 = divider * 5; break;
+ }
+ return { text: prefix + Math.floor(n / divider), emphasized: (n % divider2) == 0 };
+};
+
+Timeline.PlanningLabeller.prototype.labelPrecise = function(date) {
+ return Timeline.PlanningLabeller.labels[this._locale].dayPrefix +
+ Timeline.PlanningUnit.toNumber(date);
+};
diff --git a/src/webapp/api/ext/planning/scripts/planning.js b/src/webapp/api/ext/planning/scripts/planning.js
new file mode 100644
index 0000000..4201f92
--- /dev/null
+++ b/src/webapp/api/ext/planning/scripts/planning.js
@@ -0,0 +1,47 @@
+/*==================================================
+ * Planning
+ *==================================================
+ */
+
+Timeline.Planning = new Object();
+
+Timeline.Planning.createBandInfo = function(params) {
+ var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+ var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+ var ether = new Timeline.LinearEther({
+ centersOn: ("date" in params) ? params.date : Timeline.PlanningUnit.makeDefaultValue(),
+ interval: 1,
+ pixelsPerInterval: params.intervalPixels
+ });
+
+ var etherPainter = new Timeline.PlanningEtherPainter({
+ intervalUnit: params.intervalUnit,
+ multiple: ("multiple" in params) ? params.multiple : 1,
+ align: params.align,
+ theme: theme
+ });
+
+ var eventPainterParams = {
+ theme: theme
+ };
+ if ("trackHeight" in params) {
+ eventPainterParams.trackHeight = params.trackHeight;
+ }
+ if ("trackGap" in params) {
+ eventPainterParams.trackGap = params.trackGap;
+ }
+ var eventPainter = ("overview" in params && params.overview) ?
+ new Timeline.OverviewEventPainter(eventPainterParams) :
+ new Timeline.DetailedEventPainter(eventPainterParams);
+
+ return {
+ width: params.width,
+ eventSource: eventSource,
+ timeZone: ("timeZone" in params) ? params.timeZone : 0,
+ ether: ether,
+ etherPainter: etherPainter,
+ eventPainter: eventPainter
+ };
+}; \ No newline at end of file
diff --git a/src/webapp/api/ext/planning/scripts/units.js b/src/webapp/api/ext/planning/scripts/units.js
new file mode 100644
index 0000000..13c31c1
--- /dev/null
+++ b/src/webapp/api/ext/planning/scripts/units.js
@@ -0,0 +1,66 @@
+/*==================================================
+ * Planning Unit
+ *==================================================
+ */
+
+Timeline.PlanningUnit = new Object();
+
+Timeline.PlanningUnit.DAY = 0;
+Timeline.PlanningUnit.WEEK = 1;
+Timeline.PlanningUnit.MONTH = 2;
+Timeline.PlanningUnit.QUARTER = 3;
+Timeline.PlanningUnit.YEAR = 4;
+
+Timeline.PlanningUnit.getParser = function(format) {
+ return Timeline.PlanningUnit.parseFromObject;
+};
+
+Timeline.PlanningUnit.createLabeller = function(locale, timeZone) {
+ return new Timeline.PlanningLabeller(locale);
+};
+
+Timeline.PlanningUnit.makeDefaultValue = function () {
+ return 0;
+};
+
+Timeline.PlanningUnit.cloneValue = function (v) {
+ return v;
+};
+
+Timeline.PlanningUnit.parseFromObject = function(o) {
+ if (o == null) {
+ return null;
+ } else if (typeof o == "number") {
+ return o;
+ } else {
+ try {
+ return parseInt(o);
+ } catch (e) {
+ return null;
+ }
+ }
+};
+
+Timeline.PlanningUnit.toNumber = function(v) {
+ return v
+};
+
+Timeline.PlanningUnit.fromNumber = function(n) {
+ return n;
+};
+
+Timeline.PlanningUnit.compare = function(v1, v2) {
+ return v1 - v2;
+};
+
+Timeline.PlanningUnit.earlier = function(v1, v2) {
+ return Timeline.PlanningUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.PlanningUnit.later = function(v1, v2) {
+ return Timeline.PlanningUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.PlanningUnit.change = function(v, n) {
+ return v + n;
+};
diff --git a/src/webapp/api/images/blue-circle.png b/src/webapp/api/images/blue-circle.png
new file mode 100644
index 0000000..9ef045c
--- /dev/null
+++ b/src/webapp/api/images/blue-circle.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-bottom-arrow.png b/src/webapp/api/images/bubble-bottom-arrow.png
new file mode 100644
index 0000000..38c3917
--- /dev/null
+++ b/src/webapp/api/images/bubble-bottom-arrow.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-bottom-left.png b/src/webapp/api/images/bubble-bottom-left.png
new file mode 100644
index 0000000..6d32026
--- /dev/null
+++ b/src/webapp/api/images/bubble-bottom-left.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-bottom-right.png b/src/webapp/api/images/bubble-bottom-right.png
new file mode 100644
index 0000000..e5dc136
--- /dev/null
+++ b/src/webapp/api/images/bubble-bottom-right.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-bottom.png b/src/webapp/api/images/bubble-bottom.png
new file mode 100644
index 0000000..166b057
--- /dev/null
+++ b/src/webapp/api/images/bubble-bottom.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-left-arrow.png b/src/webapp/api/images/bubble-left-arrow.png
new file mode 100644
index 0000000..5b173cd
--- /dev/null
+++ b/src/webapp/api/images/bubble-left-arrow.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-left.png b/src/webapp/api/images/bubble-left.png
new file mode 100644
index 0000000..3826722
--- /dev/null
+++ b/src/webapp/api/images/bubble-left.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-right-arrow.png b/src/webapp/api/images/bubble-right-arrow.png
new file mode 100644
index 0000000..11e2873
--- /dev/null
+++ b/src/webapp/api/images/bubble-right-arrow.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-right.png b/src/webapp/api/images/bubble-right.png
new file mode 100644
index 0000000..f66f879
--- /dev/null
+++ b/src/webapp/api/images/bubble-right.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-top-arrow.png b/src/webapp/api/images/bubble-top-arrow.png
new file mode 100644
index 0000000..524c46e
--- /dev/null
+++ b/src/webapp/api/images/bubble-top-arrow.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-top-left.png b/src/webapp/api/images/bubble-top-left.png
new file mode 100644
index 0000000..d69841f
--- /dev/null
+++ b/src/webapp/api/images/bubble-top-left.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-top-right.png b/src/webapp/api/images/bubble-top-right.png
new file mode 100644
index 0000000..9ab219a
--- /dev/null
+++ b/src/webapp/api/images/bubble-top-right.png
Binary files differ
diff --git a/src/webapp/api/images/bubble-top.png b/src/webapp/api/images/bubble-top.png
new file mode 100644
index 0000000..917defa
--- /dev/null
+++ b/src/webapp/api/images/bubble-top.png
Binary files differ
diff --git a/src/webapp/api/images/close-button.png b/src/webapp/api/images/close-button.png
new file mode 100644
index 0000000..15f31b3
--- /dev/null
+++ b/src/webapp/api/images/close-button.png
Binary files differ
diff --git a/src/webapp/api/images/copyright-vertical.png b/src/webapp/api/images/copyright-vertical.png
new file mode 100644
index 0000000..b15197b
--- /dev/null
+++ b/src/webapp/api/images/copyright-vertical.png
Binary files differ
diff --git a/src/webapp/api/images/copyright.png b/src/webapp/api/images/copyright.png
new file mode 100644
index 0000000..bcf69c6
--- /dev/null
+++ b/src/webapp/api/images/copyright.png
Binary files differ
diff --git a/src/webapp/api/images/dark-blue-circle.png b/src/webapp/api/images/dark-blue-circle.png
new file mode 100644
index 0000000..2747397
--- /dev/null
+++ b/src/webapp/api/images/dark-blue-circle.png
Binary files differ
diff --git a/src/webapp/api/images/dark-green-circle.png b/src/webapp/api/images/dark-green-circle.png
new file mode 100644
index 0000000..903f9fd
--- /dev/null
+++ b/src/webapp/api/images/dark-green-circle.png
Binary files differ
diff --git a/src/webapp/api/images/dark-red-circle.png b/src/webapp/api/images/dark-red-circle.png
new file mode 100644
index 0000000..5cbb085
--- /dev/null
+++ b/src/webapp/api/images/dark-red-circle.png
Binary files differ
diff --git a/src/webapp/api/images/dull-blue-circle.png b/src/webapp/api/images/dull-blue-circle.png
new file mode 100644
index 0000000..19dd0da
--- /dev/null
+++ b/src/webapp/api/images/dull-blue-circle.png
Binary files differ
diff --git a/src/webapp/api/images/dull-green-circle.png b/src/webapp/api/images/dull-green-circle.png
new file mode 100644
index 0000000..eecf665
--- /dev/null
+++ b/src/webapp/api/images/dull-green-circle.png
Binary files differ
diff --git a/src/webapp/api/images/dull-red-circle.png b/src/webapp/api/images/dull-red-circle.png
new file mode 100644
index 0000000..2ff0111
--- /dev/null
+++ b/src/webapp/api/images/dull-red-circle.png
Binary files differ
diff --git a/src/webapp/api/images/gray-circle.png b/src/webapp/api/images/gray-circle.png
new file mode 100644
index 0000000..39360d7
--- /dev/null
+++ b/src/webapp/api/images/gray-circle.png
Binary files differ
diff --git a/src/webapp/api/images/green-circle.png b/src/webapp/api/images/green-circle.png
new file mode 100644
index 0000000..a5fc15c
--- /dev/null
+++ b/src/webapp/api/images/green-circle.png
Binary files differ
diff --git a/src/webapp/api/images/message-bottom-left.png b/src/webapp/api/images/message-bottom-left.png
new file mode 100644
index 0000000..43a9d61
--- /dev/null
+++ b/src/webapp/api/images/message-bottom-left.png
Binary files differ
diff --git a/src/webapp/api/images/message-bottom-right.png b/src/webapp/api/images/message-bottom-right.png
new file mode 100644
index 0000000..bfa4954
--- /dev/null
+++ b/src/webapp/api/images/message-bottom-right.png
Binary files differ
diff --git a/src/webapp/api/images/message-left.png b/src/webapp/api/images/message-left.png
new file mode 100644
index 0000000..f354376
--- /dev/null
+++ b/src/webapp/api/images/message-left.png
Binary files differ
diff --git a/src/webapp/api/images/message-right.png b/src/webapp/api/images/message-right.png
new file mode 100644
index 0000000..4702c28
--- /dev/null
+++ b/src/webapp/api/images/message-right.png
Binary files differ
diff --git a/src/webapp/api/images/message-top-left.png b/src/webapp/api/images/message-top-left.png
new file mode 100644
index 0000000..b19b0ea
--- /dev/null
+++ b/src/webapp/api/images/message-top-left.png
Binary files differ
diff --git a/src/webapp/api/images/message-top-right.png b/src/webapp/api/images/message-top-right.png
new file mode 100644
index 0000000..c092555
--- /dev/null
+++ b/src/webapp/api/images/message-top-right.png
Binary files differ
diff --git a/src/webapp/api/images/progress-running.gif b/src/webapp/api/images/progress-running.gif
new file mode 100644
index 0000000..f7429eb
--- /dev/null
+++ b/src/webapp/api/images/progress-running.gif
Binary files differ
diff --git a/src/webapp/api/images/red-circle.png b/src/webapp/api/images/red-circle.png
new file mode 100644
index 0000000..d56e734
--- /dev/null
+++ b/src/webapp/api/images/red-circle.png
Binary files differ
diff --git a/src/webapp/api/images/top-bubble.png b/src/webapp/api/images/top-bubble.png
new file mode 100644
index 0000000..db6c93d
--- /dev/null
+++ b/src/webapp/api/images/top-bubble.png
Binary files differ
diff --git a/src/webapp/api/scripts/band.js b/src/webapp/api/scripts/band.js
new file mode 100644
index 0000000..02c75e6
--- /dev/null
+++ b/src/webapp/api/scripts/band.js
@@ -0,0 +1,733 @@
+/*=================================================
+ *
+ * Coding standards:
+ *
+ * We aim towards Douglas Crockford's Javascript conventions.
+ * See: http://javascript.crockford.com/code.html
+ * See also: http://www.crockford.com/javascript/javascript.html
+ *
+ * That said, this JS code was written before some recent JS
+ * support libraries became widely used or available.
+ * In particular, the _ character is used to indicate a class function or
+ * variable that should be considered private to the class.
+ *
+ * The code mostly uses accessor methods for getting/setting the private
+ * class variables.
+ *
+ * Over time, we'd like to formalize the convention by using support libraries
+ * which enforce privacy in objects.
+ *
+ * We also want to use jslint: http://www.jslint.com/
+ *
+ *
+ *==================================================
+ */
+
+
+
+/*==================================================
+ * Band
+ *==================================================
+ */
+Timeline._Band = function(timeline, bandInfo, index) {
+ // Set up the band's object
+
+ // Munge params: If autoWidth is on for the Timeline, then ensure that
+ // bandInfo.width is an integer
+ if (timeline.autoWidth && typeof bandInfo.width == 'string') {
+ bandInfo.width = bandInfo.width.indexOf("%") > -1 ? 0 : parseInt(bandInfo.width);
+ }
+
+ this._timeline = timeline;
+ this._bandInfo = bandInfo;
+
+ this._index = index;
+
+ this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.getDefaultLocale();
+ this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0;
+ this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller :
+ (("createLabeller" in timeline.getUnit()) ?
+ timeline.getUnit().createLabeller(this._locale, this._timeZone) :
+ new Timeline.GregorianDateLabeller(this._locale, this._timeZone));
+ this._theme = bandInfo.theme;
+ this._zoomIndex = ("zoomIndex" in bandInfo) ? bandInfo.zoomIndex : 0;
+ this._zoomSteps = ("zoomSteps" in bandInfo) ? bandInfo.zoomSteps : null;
+
+ this._dragging = false;
+ this._changing = false;
+ this._originalScrollSpeed = 5; // pixels
+ this._scrollSpeed = this._originalScrollSpeed;
+ this._onScrollListeners = [];
+
+ var b = this;
+ this._syncWithBand = null;
+ this._syncWithBandHandler = function(band) {
+ b._onHighlightBandScroll();
+ };
+ this._selectorListener = function(band) {
+ b._onHighlightBandScroll();
+ };
+
+ /*
+ * Install a textbox to capture keyboard events
+ */
+ var inputDiv = this._timeline.getDocument().createElement("div");
+ inputDiv.className = "timeline-band-input";
+ this._timeline.addDiv(inputDiv);
+
+ this._keyboardInput = document.createElement("input");
+ this._keyboardInput.type = "text";
+ inputDiv.appendChild(this._keyboardInput);
+ SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, "_onKeyDown");
+ SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, "_onKeyUp");
+
+ /*
+ * The band's outer most div that slides with respect to the timeline's div
+ */
+ this._div = this._timeline.getDocument().createElement("div");
+ this._div.id = "timeline-band-" + index;
+ this._div.className = "timeline-band timeline-band-" + index;
+ this._timeline.addDiv(this._div);
+
+ SimileAjax.DOM.registerEventWithObject(this._div, "mousedown", this, "_onMouseDown");
+ SimileAjax.DOM.registerEventWithObject(this._div, "mousemove", this, "_onMouseMove");
+ SimileAjax.DOM.registerEventWithObject(this._div, "mouseup", this, "_onMouseUp");
+ SimileAjax.DOM.registerEventWithObject(this._div, "mouseout", this, "_onMouseOut");
+ SimileAjax.DOM.registerEventWithObject(this._div, "dblclick", this, "_onDblClick");
+
+ var mouseWheel = this._theme!= null ? this._theme.mouseWheel : 'scroll'; // theme is not always defined
+ if (mouseWheel === 'zoom' || mouseWheel === 'scroll' || this._zoomSteps) {
+ // capture mouse scroll
+ if (SimileAjax.Platform.browser.isFirefox) {
+ SimileAjax.DOM.registerEventWithObject(this._div, "DOMMouseScroll", this, "_onMouseScroll");
+ } else {
+ SimileAjax.DOM.registerEventWithObject(this._div, "mousewheel", this, "_onMouseScroll");
+ }
+ }
+
+ /*
+ * The inner div that contains layers
+ */
+ this._innerDiv = this._timeline.getDocument().createElement("div");
+ this._innerDiv.className = "timeline-band-inner";
+ this._div.appendChild(this._innerDiv);
+
+ /*
+ * Initialize parts of the band
+ */
+ this._ether = bandInfo.ether;
+ bandInfo.ether.initialize(this, timeline);
+
+ this._etherPainter = bandInfo.etherPainter;
+ bandInfo.etherPainter.initialize(this, timeline);
+
+ this._eventSource = bandInfo.eventSource;
+ if (this._eventSource) {
+ this._eventListener = {
+ onAddMany: function() { b._onAddMany(); },
+ onClear: function() { b._onClear(); }
+ }
+ this._eventSource.addListener(this._eventListener);
+ }
+
+ this._eventPainter = bandInfo.eventPainter;
+ this._eventTracksNeeded = 0; // set by painter via updateEventTrackInfo
+ this._eventTrackIncrement = 0;
+ bandInfo.eventPainter.initialize(this, timeline);
+
+ this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : [];
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].initialize(this, timeline);
+ }
+};
+
+Timeline._Band.SCROLL_MULTIPLES = 5;
+
+Timeline._Band.prototype.dispose = function() {
+ this.closeBubble();
+
+ if (this._eventSource) {
+ this._eventSource.removeListener(this._eventListener);
+ this._eventListener = null;
+ this._eventSource = null;
+ }
+
+ this._timeline = null;
+ this._bandInfo = null;
+
+ this._labeller = null;
+ this._ether = null;
+ this._etherPainter = null;
+ this._eventPainter = null;
+ this._decorators = null;
+
+ this._onScrollListeners = null;
+ this._syncWithBandHandler = null;
+ this._selectorListener = null;
+
+ this._div = null;
+ this._innerDiv = null;
+ this._keyboardInput = null;
+};
+
+Timeline._Band.prototype.addOnScrollListener = function(listener) {
+ this._onScrollListeners.push(listener);
+};
+
+Timeline._Band.prototype.removeOnScrollListener = function(listener) {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ if (this._onScrollListeners[i] == listener) {
+ this._onScrollListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline._Band.prototype.setSyncWithBand = function(band, highlight) {
+ if (this._syncWithBand) {
+ this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+ }
+
+ this._syncWithBand = band;
+ this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+ this._highlight = highlight;
+ this._positionHighlight();
+};
+
+Timeline._Band.prototype.getLocale = function() {
+ return this._locale;
+};
+
+Timeline._Band.prototype.getTimeZone = function() {
+ return this._timeZone;
+};
+
+Timeline._Band.prototype.getLabeller = function() {
+ return this._labeller;
+};
+
+Timeline._Band.prototype.getIndex = function() {
+ return this._index;
+};
+
+Timeline._Band.prototype.getEther = function() {
+ return this._ether;
+};
+
+Timeline._Band.prototype.getEtherPainter = function() {
+ return this._etherPainter;
+};
+
+Timeline._Band.prototype.getEventSource = function() {
+ return this._eventSource;
+};
+
+Timeline._Band.prototype.getEventPainter = function() {
+ return this._eventPainter;
+};
+
+Timeline._Band.prototype.getTimeline = function() {
+ return this._timeline;
+};
+
+// Autowidth support
+Timeline._Band.prototype.updateEventTrackInfo = function(tracks, increment) {
+ this._eventTrackIncrement = increment; // doesn't vary for a specific band
+
+ if (tracks > this._eventTracksNeeded) {
+ this._eventTracksNeeded = tracks;
+ }
+};
+
+// Autowidth support
+Timeline._Band.prototype.checkAutoWidth = function() {
+ // if a new (larger) width is needed by the band
+ // then: a) updates the band's bandInfo.width
+ //
+ // desiredWidth for the band is
+ // (number of tracks + margin) * track increment
+ if (! this._timeline.autoWidth) {
+ return; // early return
+ }
+
+ var overviewBand = this._eventPainter.getType() == 'overview';
+ var margin = overviewBand ?
+ this._theme.event.overviewTrack.autoWidthMargin :
+ this._theme.event.track.autoWidthMargin;
+ var desiredWidth = Math.ceil((this._eventTracksNeeded + margin) *
+ this._eventTrackIncrement);
+ // add offset amount (additional margin)
+ desiredWidth += overviewBand ? this._theme.event.overviewTrack.offset :
+ this._theme.event.track.offset;
+ var bandInfo = this._bandInfo;
+
+ if (desiredWidth != bandInfo.width) {
+ bandInfo.width = desiredWidth;
+ }
+};
+
+Timeline._Band.prototype.layout = function() {
+ this.paint();
+};
+
+Timeline._Band.prototype.paint = function() {
+ this._etherPainter.paint();
+ this._paintDecorators();
+ this._paintEvents();
+};
+
+Timeline._Band.prototype.softLayout = function() {
+ this.softPaint();
+};
+
+Timeline._Band.prototype.softPaint = function() {
+ this._etherPainter.softPaint();
+ this._softPaintDecorators();
+ this._softPaintEvents();
+};
+
+Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) {
+ var inputDiv = this._keyboardInput.parentNode;
+ var middle = shift + Math.floor(width / 2);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.top = shift + "px";
+ this._div.style.height = width + "px";
+
+ inputDiv.style.top = middle + "px";
+ inputDiv.style.left = "-1em";
+ } else {
+ this._div.style.left = shift + "px";
+ this._div.style.width = width + "px";
+
+ inputDiv.style.left = middle + "px";
+ inputDiv.style.top = "-1em";
+ }
+};
+
+Timeline._Band.prototype.getViewWidth = function() {
+ if (this._timeline.isHorizontal()) {
+ return this._div.offsetHeight;
+ } else {
+ return this._div.offsetWidth;
+ }
+};
+
+Timeline._Band.prototype.setViewLength = function(length) {
+ this._viewLength = length;
+ this._recenterDiv();
+ this._onChanging();
+};
+
+Timeline._Band.prototype.getViewLength = function() {
+ return this._viewLength;
+};
+
+Timeline._Band.prototype.getTotalViewLength = function() {
+ return Timeline._Band.SCROLL_MULTIPLES * this._viewLength;
+};
+
+Timeline._Band.prototype.getViewOffset = function() {
+ return this._viewOffset;
+};
+
+Timeline._Band.prototype.getMinDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+
+Timeline._Band.prototype.getMaxDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength);
+};
+
+Timeline._Band.prototype.getMinVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(0);
+};
+
+Timeline._Band.prototype.getMinVisibleDateAfterDelta = function(delta) {
+ return this._ether.pixelOffsetToDate(delta);
+};
+
+Timeline._Band.prototype.getMaxVisibleDate = function() {
+ // Max date currently visible on band
+ return this._ether.pixelOffsetToDate(this._viewLength);
+};
+
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta = function(delta) {
+ // Max date visible on band after delta px view change is applied
+ return this._ether.pixelOffsetToDate(this._viewLength + delta);
+};
+
+Timeline._Band.prototype.getCenterVisibleDate = function() {
+ return this._ether.pixelOffsetToDate(this._viewLength / 2);
+};
+
+Timeline._Band.prototype.setMinVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setMaxVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.setCenterVisibleDate = function(date) {
+ if (!this._changing) {
+ this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
+ }
+};
+
+Timeline._Band.prototype.dateToPixelOffset = function(date) {
+ return this._ether.dateToPixelOffset(date) - this._viewOffset;
+};
+
+Timeline._Band.prototype.pixelOffsetToDate = function(pixels) {
+ return this._ether.pixelOffsetToDate(pixels + this._viewOffset);
+};
+
+Timeline._Band.prototype.createLayerDiv = function(zIndex, className) {
+ var div = this._timeline.getDocument().createElement("div");
+ div.className = "timeline-band-layer" + (typeof className == "string" ? (" " + className) : "");
+ div.style.zIndex = zIndex;
+ this._innerDiv.appendChild(div);
+
+ var innerDiv = this._timeline.getDocument().createElement("div");
+ innerDiv.className = "timeline-band-layer-inner";
+ if (SimileAjax.Platform.browser.isIE) {
+ innerDiv.style.cursor = "move";
+ } else {
+ innerDiv.style.cursor = "-moz-grab";
+ }
+ div.appendChild(innerDiv);
+
+ return innerDiv;
+};
+
+Timeline._Band.prototype.removeLayerDiv = function(div) {
+ this._innerDiv.removeChild(div.parentNode);
+};
+
+Timeline._Band.prototype.scrollToCenter = function(date, f) {
+ var pixelOffset = this._ether.dateToPixelOffset(date);
+ if (pixelOffset < -this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength));
+ } else if (pixelOffset > 3 * this._viewLength / 2) {
+ this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength));
+ }
+ this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)), f);
+};
+
+Timeline._Band.prototype.showBubbleForEvent = function(eventID) {
+ var evt = this.getEventSource().getEvent(eventID);
+ if (evt) {
+ var self = this;
+ this.scrollToCenter(evt.getStart(), function() {
+ self._eventPainter.showBubble(evt);
+ });
+ }
+};
+
+Timeline._Band.prototype.zoom = function(zoomIn, x, y, target) {
+ if (!this._zoomSteps) {
+ // zoom disabled
+ return;
+ }
+
+ // shift the x value by our offset
+ x += this._viewOffset;
+
+ var zoomDate = this._ether.pixelOffsetToDate(x);
+ var netIntervalChange = this._ether.zoom(zoomIn);
+ this._etherPainter.zoom(netIntervalChange);
+
+ // shift our zoom date to the far left
+ this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
+ // then shift it back to where the mouse was
+ this._moveEther(x);
+};
+
+Timeline._Band.prototype._onMouseDown = function(innerFrame, evt, target) {
+ this.closeBubble();
+
+ this._dragging = true;
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+};
+
+Timeline._Band.prototype._onMouseMove = function(innerFrame, evt, target) {
+ if (this._dragging) {
+ var diffX = evt.clientX - this._dragX;
+ var diffY = evt.clientY - this._dragY;
+
+ this._dragX = evt.clientX;
+ this._dragY = evt.clientY;
+
+ this._moveEther(this._timeline.isHorizontal() ? diffX : diffY);
+ this._positionHighlight();
+ }
+};
+
+Timeline._Band.prototype._onMouseUp = function(innerFrame, evt, target) {
+ this._dragging = false;
+ this._keyboardInput.focus();
+};
+
+Timeline._Band.prototype._onMouseOut = function(innerFrame, evt, target) {
+ var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ coords.x += this._viewOffset;
+ if (coords.x < 0 || coords.x > innerFrame.offsetWidth ||
+ coords.y < 0 || coords.y > innerFrame.offsetHeight) {
+ this._dragging = false;
+ }
+};
+
+Timeline._Band.prototype._onMouseScroll = function(innerFrame, evt, target) {
+ var now = new Date();
+ now = now.getTime();
+
+ if (!this._lastScrollTime || ((now - this._lastScrollTime) > 50)) {
+ // limit 1 scroll per 200ms due to FF3 sending multiple events back to back
+ this._lastScrollTime = now;
+
+ var delta = 0;
+ if (evt.wheelDelta) {
+ delta = evt.wheelDelta/120;
+ } else if (evt.detail) {
+ delta = -evt.detail/3;
+ }
+
+ // either scroll or zoom
+ var mouseWheel = this._theme.mouseWheel;
+
+ if (this._zoomSteps || mouseWheel === 'zoom') {
+ var loc = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ if (delta != 0) {
+ var zoomIn;
+ if (delta > 0)
+ zoomIn = true;
+ if (delta < 0)
+ zoomIn = false;
+ // call zoom on the timeline so we could zoom multiple bands if desired
+ this._timeline.zoom(zoomIn, loc.x, loc.y, innerFrame);
+ }
+ }
+ else if (mouseWheel === 'scroll') {
+ var move_amt = 50 * (delta < 0 ? -1 : 1);
+ this._moveEther(move_amt);
+ }
+ }
+
+ // prevent bubble
+ if (evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ evt.cancelBubble = true;
+
+ // prevent the default action
+ if (evt.preventDefault) {
+ evt.preventDefault();
+ }
+ evt.returnValue = false;
+};
+
+Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) {
+ var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+ var distance = coords.x - (this._viewLength / 2 - this._viewOffset);
+
+ this._autoScroll(-distance);
+};
+
+Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ switch (evt.keyCode) {
+ case 27: // ESC
+ break;
+ case 37: // left arrow
+ case 38: // up arrow
+ this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ case 39: // right arrow
+ case 40: // down arrow
+ this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+ this._moveEther(this._scrollSpeed);
+ break;
+ default:
+ return true;
+ }
+ this.closeBubble();
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) {
+ if (!this._dragging) {
+ this._scrollSpeed = this._originalScrollSpeed;
+
+ switch (evt.keyCode) {
+ case 35: // end
+ this.setCenterVisibleDate(this._eventSource.getLatestDate());
+ break;
+ case 36: // home
+ this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+ break;
+ case 33: // page up
+ this._autoScroll(this._timeline.getPixelLength());
+ break;
+ case 34: // page down
+ this._autoScroll(-this._timeline.getPixelLength());
+ break;
+ default:
+ return true;
+ }
+
+ this.closeBubble();
+
+ SimileAjax.DOM.cancelEvent(evt);
+ return false;
+ }
+ return true;
+};
+
+Timeline._Band.prototype._autoScroll = function(distance, f) {
+ var b = this;
+ var a = SimileAjax.Graphics.createAnimation(
+ function(abs, diff) {
+ b._moveEther(diff);
+ },
+ 0,
+ distance,
+ 1000,
+ f
+ );
+ a.run();
+};
+
+Timeline._Band.prototype._moveEther = function(shift) {
+ this.closeBubble();
+
+ // A positive shift means back in time
+ // Check that we're not moving beyond Timeline's limits
+ if (!this._timeline.shiftOK(this._index, shift)) {
+ return; // early return
+ }
+
+ this._viewOffset += shift;
+ this._ether.shiftPixels(-shift);
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ }
+
+ if (this._viewOffset > -this._viewLength * 0.5 ||
+ this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) {
+
+ this._recenterDiv();
+ } else {
+ this.softLayout();
+ }
+
+ this._onChanging();
+}
+
+Timeline._Band.prototype._onChanging = function() {
+ this._changing = true;
+
+ this._fireOnScroll();
+ this._setSyncWithBandDate();
+
+ this._changing = false;
+};
+
+Timeline._Band.prototype.busy = function() {
+ // Is this band busy changing other bands?
+ return(this._changing);
+};
+
+Timeline._Band.prototype._fireOnScroll = function() {
+ for (var i = 0; i < this._onScrollListeners.length; i++) {
+ this._onScrollListeners[i](this);
+ }
+};
+
+Timeline._Band.prototype._setSyncWithBandDate = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2);
+ this._syncWithBand.setCenterVisibleDate(centerDate);
+ }
+};
+
+Timeline._Band.prototype._onHighlightBandScroll = function() {
+ if (this._syncWithBand) {
+ var centerDate = this._syncWithBand.getCenterVisibleDate();
+ var centerPixelOffset = this._ether.dateToPixelOffset(centerDate);
+
+ this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset));
+
+ if (this._highlight) {
+ this._etherPainter.setHighlight(
+ this._syncWithBand.getMinVisibleDate(),
+ this._syncWithBand.getMaxVisibleDate());
+ }
+ }
+};
+
+Timeline._Band.prototype._onAddMany = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._onClear = function() {
+ this._paintEvents();
+};
+
+Timeline._Band.prototype._positionHighlight = function() {
+ if (this._syncWithBand) {
+ var startDate = this._syncWithBand.getMinVisibleDate();
+ var endDate = this._syncWithBand.getMaxVisibleDate();
+
+ if (this._highlight) {
+ this._etherPainter.setHighlight(startDate, endDate);
+ }
+ }
+};
+
+Timeline._Band.prototype._recenterDiv = function() {
+ this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2;
+ if (this._timeline.isHorizontal()) {
+ this._div.style.left = this._viewOffset + "px";
+ this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ } else {
+ this._div.style.top = this._viewOffset + "px";
+ this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+ }
+ this.layout();
+};
+
+Timeline._Band.prototype._paintEvents = function() {
+ this._eventPainter.paint();
+};
+
+Timeline._Band.prototype._softPaintEvents = function() {
+ this._eventPainter.softPaint();
+};
+
+Timeline._Band.prototype._paintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].paint();
+ }
+};
+
+Timeline._Band.prototype._softPaintDecorators = function() {
+ for (var i = 0; i < this._decorators.length; i++) {
+ this._decorators[i].softPaint();
+ }
+};
+
+Timeline._Band.prototype.closeBubble = function() {
+ SimileAjax.WindowManager.cancelPopups();
+};
diff --git a/src/webapp/api/scripts/compact-painter.js b/src/webapp/api/scripts/compact-painter.js
new file mode 100644
index 0000000..14ba1cd
--- /dev/null
+++ b/src/webapp/api/scripts/compact-painter.js
@@ -0,0 +1,1041 @@
+/*==================================================
+ * Original Event Painter
+ *==================================================
+ */
+
+Timeline.CompactEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
+
+ this._eventIdToElmt = {};
+};
+
+Timeline.CompactEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backLayer = null;
+ this._eventLayer = null;
+ this._lineLayer = null;
+ this._highlightLayer = null;
+
+ this._eventIdToElmt = null;
+};
+
+Timeline.CompactEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.CompactEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.CompactEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._eventIdToElmt = {};
+ this._prepareForPainting();
+
+ var theme = this._params.theme;
+ var eventTheme = theme.event;
+
+ var metrics = {
+ trackOffset: "trackOffset" in this._params ? this._params.trackOffset : 10,
+ trackHeight: "trackHeight" in this._params ? this._params.trackHeight : 10,
+
+ tapeHeight: theme.event.tape.height,
+ tapeBottomMargin: "tapeBottomMargin" in this._params ? this._params.tapeBottomMargin : 2,
+
+ labelBottomMargin: "labelBottomMargin" in this._params ? this._params.labelBottomMargin : 5,
+ labelRightMargin: "labelRightMargin" in this._params ? this._params.labelRightMargin : 5,
+
+ defaultIcon: eventTheme.instant.icon,
+ defaultIconWidth: eventTheme.instant.iconWidth,
+ defaultIconHeight: eventTheme.instant.iconHeight,
+
+ customIconWidth: "iconWidth" in this._params ? this._params.iconWidth : eventTheme.instant.iconWidth,
+ customIconHeight: "iconHeight" in this._params ? this._params.iconHeight : eventTheme.instant.iconHeight,
+
+ iconLabelGap: "iconLabelGap" in this._params ? this._params.iconLabelGap : 2,
+ iconBottomMargin: "iconBottomMargin" in this._params ? this._params.iconBottomMargin : 2
+ };
+ if ("compositeIcon" in this._params) {
+ metrics.compositeIcon = this._params.compositeIcon;
+ metrics.compositeIconWidth = this._params.compositeIconWidth || metrics.customIconWidth;
+ metrics.compositeIconHeight = this._params.compositeIconHeight || metrics.customIconHeight;
+ } else {
+ metrics.compositeIcon = metrics.defaultIcon;
+ metrics.compositeIconWidth = metrics.defaultIconWidth;
+ metrics.compositeIconHeight = metrics.defaultIconHeight;
+ }
+ metrics.defaultStackIcon = "icon" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.icon : metrics.defaultIcon;
+ metrics.defaultStackIconWidth = "iconWidth" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.iconWidth : metrics.defaultIconWidth;
+ metrics.defaultStackIconHeight = "iconHeight" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.iconHeight : metrics.defaultIconHeight;
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventIterator(minDate, maxDate);
+
+ var stackConcurrentPreciseInstantEvents = "stackConcurrentPreciseInstantEvents" in this._params && typeof this._params.stackConcurrentPreciseInstantEvents == "object";
+ var collapseConcurrentPreciseInstantEvents = "collapseConcurrentPreciseInstantEvents" in this._params && this._params.collapseConcurrentPreciseInstantEvents;
+ if (collapseConcurrentPreciseInstantEvents || stackConcurrentPreciseInstantEvents) {
+ var bufferedEvents = [];
+ var previousInstantEvent = null;
+
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ if (!evt.isInstant() || evt.isImprecise()) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ } else if (previousInstantEvent != null &&
+ previousInstantEvent.getStart().getTime() == evt.getStart().getTime()) {
+ bufferedEvents[bufferedEvents.length - 1].push(evt);
+ } else {
+ bufferedEvents.push([ evt ]);
+ previousInstantEvent = evt;
+ }
+ }
+ }
+
+ for (var i = 0; i < bufferedEvents.length; i++) {
+ var compositeEvents = bufferedEvents[i];
+ if (compositeEvents.length == 1) {
+ this.paintEvent(compositeEvents[0], metrics, this._params.theme, highlightMatcher(evt));
+ } else {
+ var match = -1;
+ for (var j = 0; match < 0 && j < compositeEvents.length; j++) {
+ match = highlightMatcher(compositeEvents[j]);
+ }
+
+ if (stackConcurrentPreciseInstantEvents) {
+ this.paintStackedPreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+ } else {
+ this.paintCompositePreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+ }
+ }
+ }
+ } else {
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+};
+
+Timeline.CompactEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.CompactEventPainter.prototype._prepareForPainting = function() {
+ var band = this._band;
+
+ if (this._backLayer == null) {
+ this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+ this._backLayer.style.visibility = "hidden";
+
+ var eventLabelPrototype = document.createElement("span");
+ eventLabelPrototype.className = "timeline-event-label";
+ this._backLayer.appendChild(eventLabelPrototype);
+ this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+ }
+ this._frc.update();
+ this._tracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._lineLayer != null) {
+ band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+ this._lineLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.CompactEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.CompactEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData.url = metrics.defaultIcon;
+ iconData.width = metrics.defaultIconWidth;
+ iconData.height = metrics.defaultIconHeight;
+ iconData.className = "timeline-event-icon-default";
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ null, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+};
+
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+ var evt = events[0];
+
+ var tooltips = [];
+ for (var i = 0; i < events.length; i++) {
+ tooltips.push(events[i].getProperty("tooltip") || events[i].getText());
+ }
+ var commonData = {
+ tooltip: tooltips.join("; ")
+ };
+
+ var iconData = {
+ url: metrics.compositeIcon,
+ width: metrics.compositeIconWidth,
+ height: metrics.compositeIconHeight,
+ className: "timeline-event-icon-composite"
+ };
+
+ var labelData = {
+ text: String.substitute(this._params.compositeEventLabelTemplate, [ events.length ])
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ null, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt, domEvt, events);
+ };
+
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+ for (var i = 0; i < events.length; i++) {
+ this._eventIdToElmt[events[i].getID()] = result.iconElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+ var limit = "limit" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.limit : 10;
+ var moreMessageTemplate = "moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents ?
+ this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate : "%0 More Events";
+ var showMoreMessage = limit <= events.length - 2; // We want at least 2 more events above the limit.
+ // Otherwise we'd need the singular case of "1 More Event"
+
+ var band = this._band;
+ var getPixelOffset = function(date) {
+ return Math.round(band.dateToPixelOffset(date));
+ };
+ var getIconData = function(evt) {
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData.url = metrics.defaultStackIcon;
+ iconData.width = metrics.defaultStackIconWidth;
+ iconData.height = metrics.defaultStackIconHeight;
+ iconData.className = "timeline-event-icon-stack timeline-event-icon-default";
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ iconData.className = "timeline-event-icon-stack";
+ }
+ return iconData;
+ };
+
+ var firstIconData = getIconData(events[0]);
+ var horizontalIncrement = 5;
+ var leftIconEdge = 0;
+ var totalLabelWidth = 0;
+ var totalLabelHeight = 0;
+ var totalIconHeight = 0;
+
+ var records = [];
+ for (var i = 0; i < events.length && (!showMoreMessage || i < limit); i++) {
+ var evt = events[i];
+ var text = evt.getText();
+ var iconData = getIconData(evt);
+ var labelSize = this._frc.computeSize(text);
+ var record = {
+ text: text,
+ iconData: iconData,
+ labelSize: labelSize,
+ iconLeft: firstIconData.width + i * horizontalIncrement - iconData.width
+ };
+ record.labelLeft = firstIconData.width + i * horizontalIncrement + metrics.iconLabelGap;
+ record.top = totalLabelHeight;
+ records.push(record);
+
+ leftIconEdge = Math.min(leftIconEdge, record.iconLeft);
+ totalLabelHeight += labelSize.height;
+ totalLabelWidth = Math.max(totalLabelWidth, record.labelLeft + labelSize.width);
+ totalIconHeight = Math.max(totalIconHeight, record.top + iconData.height);
+ }
+ if (showMoreMessage) {
+ var moreMessage = String.substitute(moreMessageTemplate, [ events.length - limit ]);
+
+ var moreMessageLabelSize = this._frc.computeSize(moreMessage);
+ var moreMessageLabelLeft = firstIconData.width + (limit - 1) * horizontalIncrement + metrics.iconLabelGap;
+ var moreMessageLabelTop = totalLabelHeight;
+
+ totalLabelHeight += moreMessageLabelSize.height;
+ totalLabelWidth = Math.max(totalLabelWidth, moreMessageLabelLeft + moreMessageLabelSize.width);
+ }
+ totalLabelWidth += metrics.labelRightMargin;
+ totalLabelHeight += metrics.labelBottomMargin;
+ totalIconHeight += metrics.iconBottomMargin;
+
+ var anchorPixel = getPixelOffset(events[0].getStart());
+ var newTracks = [];
+
+ var trackCount = Math.ceil(Math.max(totalIconHeight, totalLabelHeight) / metrics.trackHeight);
+ var rightIconEdge = firstIconData.width + (events.length - 1) * horizontalIncrement;
+ for (var i = 0; i < trackCount; i++) {
+ newTracks.push({ start: leftIconEdge, end: rightIconEdge });
+ }
+ var labelTrackCount = Math.ceil(totalLabelHeight / metrics.trackHeight);
+ for (var i = 0; i < labelTrackCount; i++) {
+ var track = newTracks[i];
+ track.end = Math.max(track.end, totalLabelWidth);
+ }
+
+ var firstTrack = this._fitTracks(anchorPixel, newTracks);
+ var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+
+ var iconStackDiv = this._timeline.getDocument().createElement("div");
+ iconStackDiv.className = 'timeline-event-icon-stack';
+ iconStackDiv.style.position = "absolute";
+ iconStackDiv.style.overflow = "visible";
+ iconStackDiv.style.left = anchorPixel + "px";
+ iconStackDiv.style.top = verticalPixelOffset + "px";
+ iconStackDiv.style.width = rightIconEdge + "px";
+ iconStackDiv.style.height = totalIconHeight + "px";
+ iconStackDiv.innerHTML = "<div style='position: relative'></div>";
+ this._eventLayer.appendChild(iconStackDiv);
+
+ var self = this;
+ var onMouseOver = function(domEvt) {
+ try {
+ var n = parseInt(this.getAttribute("index"));
+ var childNodes = iconStackDiv.firstChild.childNodes;
+ for (var i = 0; i < childNodes.length; i++) {
+ var child = childNodes[i];
+ if (i == n) {
+ child.style.zIndex = childNodes.length;
+ } else {
+ child.style.zIndex = childNodes.length - i;
+ }
+ }
+ } catch (e) {
+ }
+ };
+ var paintEvent = function(index) {
+ var record = records[index];
+ var evt = events[index];
+ var tooltip = evt.getProperty("tooltip") || evt.getText();
+
+ var labelElmtData = self._paintEventLabel(
+ { tooltip: tooltip },
+ { text: record.text },
+ anchorPixel + record.labelLeft,
+ verticalPixelOffset + record.top,
+ record.labelSize.width,
+ record.labelSize.height,
+ theme
+ );
+ labelElmtData.elmt.setAttribute("index", index);
+ labelElmtData.elmt.onmouseover = onMouseOver;
+
+ var img = SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
+ var iconDiv = self._timeline.getDocument().createElement("div");
+ iconDiv.className = 'timeline-event-icon' + ("className" in record.iconData ? (" " + record.iconData.className) : "");
+ iconDiv.style.left = record.iconLeft + "px";
+ iconDiv.style.top = record.top + "px";
+ iconDiv.style.zIndex = (records.length - index);
+ iconDiv.appendChild(img);
+ iconDiv.setAttribute("index", index);
+ iconDiv.onmouseover = onMouseOver;
+
+ iconStackDiv.firstChild.appendChild(iconDiv);
+
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(iconDiv, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ self._eventIdToElmt[evt.getID()] = iconDiv;
+ };
+ for (var i = 0; i < records.length; i++) {
+ paintEvent(i);
+ }
+
+ if (showMoreMessage) {
+ var moreEvents = events.slice(limit);
+ var moreMessageLabelElmtData = this._paintEventLabel(
+ { tooltip: moreMessage },
+ { text: moreMessage },
+ anchorPixel + moreMessageLabelLeft,
+ verticalPixelOffset + moreMessageLabelTop,
+ moreMessageLabelSize.width,
+ moreMessageLabelSize.height,
+ theme
+ );
+
+ var moreMessageClickHandler = function(elmt, domEvt, target) {
+ return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt, domEvt, moreEvents);
+ };
+ SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt, "mousedown", moreMessageClickHandler);
+
+ for (var i = 0; i < moreEvents.length; i++) {
+ this._eventIdToElmt[moreEvents[i].getID()] = moreMessageLabelElmtData.elmt;
+ }
+ }
+ //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ latestStart: evt.getLatestStart(),
+ earliestEnd: evt.getEarliestEnd(),
+ isInstant: true
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getStart(),
+ commonData,
+ tapeData, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ isInstant: false
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getLatestStart(),
+ commonData,
+ tapeData, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var commonData = {
+ tooltip: evt.getProperty("tooltip") || evt.getText()
+ };
+
+ var tapeData = {
+ start: evt.getStart(),
+ end: evt.getEnd(),
+ latestStart: evt.getLatestStart(),
+ earliestEnd: evt.getEarliestEnd(),
+ isInstant: false
+ };
+
+ var iconData = {
+ url: evt.getIcon()
+ };
+ if (iconData.url == null) {
+ iconData = null;
+ } else {
+ iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+ iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+ }
+
+ var labelData = {
+ text: evt.getText(),
+ color: evt.getTextColor() || evt.getColor(),
+ className: evt.getClassName()
+ };
+
+ var result = this.paintTapeIconLabel(
+ evt.getLatestStart(),
+ commonData,
+ tapeData, // no tape data
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+ );
+
+ var self = this;
+ var clickHandler = iconData != null ?
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+ } :
+ function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+ };
+
+ SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+ if (iconData != null) {
+ SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+ this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+ } else {
+ this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+ }
+};
+
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel = function(
+ anchorDate,
+ commonData,
+ tapeData,
+ iconData,
+ labelData,
+ metrics,
+ theme,
+ highlightIndex
+) {
+ var band = this._band;
+ var getPixelOffset = function(date) {
+ return Math.round(band.dateToPixelOffset(date));
+ };
+
+ var anchorPixel = getPixelOffset(anchorDate);
+ var newTracks = [];
+
+ var tapeHeightOccupied = 0; // how many pixels (vertically) the tape occupies, including bottom margin
+ var tapeTrackCount = 0; // how many tracks the tape takes up, usually just 1
+ var tapeLastTrackExtraSpace = 0; // on the last track that the tape occupies, how many pixels are left (for icon and label to occupy as well)
+ if (tapeData != null) {
+ tapeHeightOccupied = metrics.tapeHeight + metrics.tapeBottomMargin;
+ tapeTrackCount = Math.ceil(metrics.tapeHeight / metrics.trackHeight);
+
+ var tapeEndPixelOffset = getPixelOffset(tapeData.end) - anchorPixel;
+ var tapeStartPixelOffset = getPixelOffset(tapeData.start) - anchorPixel;
+
+ for (var t = 0; t < tapeTrackCount; t++) {
+ newTracks.push({ start: tapeStartPixelOffset, end: tapeEndPixelOffset });
+ }
+
+ tapeLastTrackExtraSpace = metrics.trackHeight - (tapeHeightOccupied % metrics.tapeHeight);
+ }
+
+ var iconStartPixelOffset = 0; // where the icon starts compared to the anchor pixel;
+ // this can be negative if the icon is center-aligned around the anchor
+ var iconHorizontalSpaceOccupied = 0; // how many pixels the icon take up from the anchor pixel,
+ // including the gap between the icon and the label
+ if (iconData != null) {
+ if ("iconAlign" in iconData && iconData.iconAlign == "center") {
+ iconStartPixelOffset = -Math.floor(iconData.width / 2);
+ }
+ iconHorizontalSpaceOccupied = iconStartPixelOffset + iconData.width + metrics.iconLabelGap;
+
+ if (tapeTrackCount > 0) {
+ newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, iconHorizontalSpaceOccupied);
+ }
+
+ var iconHeight = iconData.height + metrics.iconBottomMargin + tapeLastTrackExtraSpace;
+ while (iconHeight > 0) {
+ newTracks.push({ start: iconStartPixelOffset, end: iconHorizontalSpaceOccupied });
+ iconHeight -= metrics.trackHeight;
+ }
+ }
+
+ var text = labelData.text;
+ var labelSize = this._frc.computeSize(text);
+ var labelHeight = labelSize.height + metrics.labelBottomMargin + tapeLastTrackExtraSpace;
+ var labelEndPixelOffset = iconHorizontalSpaceOccupied + labelSize.width + metrics.labelRightMargin;
+ if (tapeTrackCount > 0) {
+ newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, labelEndPixelOffset);
+ }
+ for (var i = 0; labelHeight > 0; i++) {
+ if (tapeTrackCount + i < newTracks.length) {
+ var track = newTracks[tapeTrackCount + i];
+ track.end = labelEndPixelOffset;
+ } else {
+ newTracks.push({ start: 0, end: labelEndPixelOffset });
+ }
+ labelHeight -= metrics.trackHeight;
+ }
+
+ /*
+ * Try to fit the new track on top of the existing tracks, then
+ * render the various elements.
+ */
+ var firstTrack = this._fitTracks(anchorPixel, newTracks);
+ var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+ var result = {};
+
+ result.labelElmtData = this._paintEventLabel(
+ commonData,
+ labelData,
+ anchorPixel + iconHorizontalSpaceOccupied,
+ verticalPixelOffset + tapeHeightOccupied,
+ labelSize.width,
+ labelSize.height,
+ theme
+ );
+
+ if (tapeData != null) {
+ if ("latestStart" in tapeData || "earliestEnd" in tapeData) {
+ result.impreciseTapeElmtData = this._paintEventTape(
+ commonData,
+ tapeData,
+ metrics.tapeHeight,
+ verticalPixelOffset,
+ getPixelOffset(tapeData.start),
+ getPixelOffset(tapeData.end),
+ theme.event.duration.impreciseColor,
+ theme.event.duration.impreciseOpacity,
+ metrics,
+ theme
+ );
+ }
+ if (!tapeData.isInstant && "start" in tapeData && "end" in tapeData) {
+ result.tapeElmtData = this._paintEventTape(
+ commonData,
+ tapeData,
+ metrics.tapeHeight,
+ verticalPixelOffset,
+ anchorPixel,
+ getPixelOffset("earliestEnd" in tapeData ? tapeData.earliestEnd : tapeData.end),
+ tapeData.color,
+ 100,
+ metrics,
+ theme
+ );
+ }
+ }
+
+ if (iconData != null) {
+ result.iconElmtData = this._paintEventIcon(
+ commonData,
+ iconData,
+ verticalPixelOffset + tapeHeightOccupied,
+ anchorPixel + iconStartPixelOffset,
+ metrics,
+ theme
+ );
+ }
+ //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ return result;
+};
+
+Timeline.CompactEventPainter.prototype._fitTracks = function(anchorPixel, newTracks) {
+ var firstTrack;
+ for (firstTrack = 0; firstTrack < this._tracks.length; firstTrack++) {
+ var fit = true;
+ for (var j = 0; j < newTracks.length && (firstTrack + j) < this._tracks.length; j++) {
+ var existingTrack = this._tracks[firstTrack + j];
+ var newTrack = newTracks[j];
+ if (anchorPixel + newTrack.start < existingTrack) {
+ fit = false;
+ break;
+ }
+ }
+
+ if (fit) {
+ break;
+ }
+ }
+ for (var i = 0; i < newTracks.length; i++) {
+ this._tracks[firstTrack + i] = anchorPixel + newTracks[i].end;
+ }
+
+ return firstTrack;
+};
+
+
+Timeline.CompactEventPainter.prototype._paintEventIcon = function(commonData, iconData, top, left, metrics, theme) {
+ var img = SimileAjax.Graphics.createTranslucentImage(iconData.url);
+ var iconDiv = this._timeline.getDocument().createElement("div");
+ iconDiv.className = 'timeline-event-icon' + ("className" in iconData ? (" " + iconData.className) : "");
+ iconDiv.style.left = left + "px";
+ iconDiv.style.top = top + "px";
+ iconDiv.appendChild(img);
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ iconDiv.title = commonData.tooltip;
+ }
+
+ this._eventLayer.appendChild(iconDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: metrics.iconWidth,
+ height: metrics.iconHeight,
+ elmt: iconDiv
+ };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventLabel = function(commonData, labelData, left, top, width, height, theme) {
+ var doc = this._timeline.getDocument();
+
+ var labelDiv = doc.createElement("div");
+ labelDiv.className = 'timeline-event-label';
+
+ labelDiv.style.left = left + "px";
+ labelDiv.style.width = (width + 1) + "px";
+ labelDiv.style.top = top + "px";
+ labelDiv.innerHTML = labelData.text;
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ labelDiv.title = commonData.tooltip;
+ }
+ if ("color" in labelData && typeof labelData.color == "string") {
+ labelDiv.style.color = labelData.color;
+ }
+ if ("className" in labelData && typeof labelData.className == "string") {
+ labelDiv.className += ' ' + labelData.className;
+ }
+
+ this._eventLayer.appendChild(labelDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: labelDiv
+ };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventTape = function(
+ commonData, tapeData, height, top, startPixel, endPixel, color, opacity, metrics, theme) {
+
+ var width = endPixel - startPixel;
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.className = "timeline-event-tape"
+
+ tapeDiv.style.left = startPixel + "px";
+ tapeDiv.style.top = top + "px";
+ tapeDiv.style.width = width + "px";
+ tapeDiv.style.height = height + "px";
+
+ if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+ tapeDiv.title = commonData.tooltip;
+ }
+ if (color != null && typeof tapeData.color == "string") {
+ tapeDiv.style.backgroundColor = color;
+ }
+
+ if ("backgroundImage" in tapeData && typeof tapeData.backgroundImage == "string") {
+ tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
+ tapeDiv.style.backgroundRepeat =
+ ("backgroundRepeat" in tapeData && typeof tapeData.backgroundRepeat == "string")
+ ? tapeData.backgroundRepeat : 'repeat';
+ }
+
+ SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ if ("className" in tapeData && typeof tapeData.className == "string") {
+ tapeDiv.className += ' ' + tapeData.className;
+ }
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: startPixel,
+ top: top,
+ width: width,
+ height: height,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.CompactEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var eventTheme = theme.event;
+
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 2) + "px";
+ div.style.width = (dimensions.width + 4) + "px";
+ div.style.top = (dimensions.top - 2) + "px";
+ div.style.height = (dimensions.height + 4) + "px";
+// div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+};
+
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent = function(icon, domEvt, events) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ events
+ );
+
+ var ids = [];
+ for (var i = 0; i < events.length; i++) {
+ ids.push(events[i].getID());
+ }
+ this._fireOnSelect(ids);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ [evt]
+ );
+ this._fireOnSelect([evt.getID()]);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = SimileAjax.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, [evt]);
+ this._fireOnSelect([evt.getID()]);
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.CompactEventPainter.prototype.showBubble = function(evt) {
+ var elmt = this._eventIdToElmt[evt.getID()];
+ if (elmt) {
+ var c = SimileAjax.DOM.getPageCoordinates(elmt);
+ this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, [evt]);
+ }
+};
+
+Timeline.CompactEventPainter.prototype._showBubble = function(x, y, evts) {
+ var div = document.createElement("div");
+
+ evts = ("fillInfoBubble" in evts) ? [evts] : evts;
+ for (var i = 0; i < evts.length; i++) {
+ var div2 = document.createElement("div");
+ div.appendChild(div2);
+
+ evts[i].fillInfoBubble(div2, this._params.theme, this._band.getLabeller());
+ }
+
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, this._params.theme.event.bubble.width);
+};
+
+Timeline.CompactEventPainter.prototype._fireOnSelect = function(eventIDs) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ this._onSelectListeners[i](eventIDs);
+ }
+};
diff --git a/src/webapp/api/scripts/decorators.js b/src/webapp/api/scripts/decorators.js
new file mode 100644
index 0000000..0174de1
--- /dev/null
+++ b/src/webapp/api/scripts/decorators.js
@@ -0,0 +1,184 @@
+/*==================================================
+ * Span Highlight Decorator
+ *==================================================
+ */
+
+Timeline.SpanHighlightDecorator = function(params) {
+ // When evaluating params, test against null. Not "p in params". Testing against
+ // null enables caller to explicitly request the default. Testing against "in" means
+ // that the param has to be ommitted to get the default.
+ this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+ this._startDate = (typeof params.startDate == "string") ?
+ this._unit.parseFromObject(params.startDate) : params.startDate;
+ this._endDate = (typeof params.endDate == "string") ?
+ this._unit.parseFromObject(params.endDate) : params.endDate;
+ this._startLabel = params.startLabel != null ? params.startLabel : ""; // not null!
+ this._endLabel = params.endLabel != null ? params.endLabel : ""; // not null!
+ this._color = params.color;
+ this._cssClass = params.cssClass != null ? params.cssClass : null;
+ this._opacity = params.opacity != null ? params.opacity : 100;
+ // Default z is 10, behind everything but background grid.
+ // If inFront, then place just behind events, in front of everything else
+ this._zIndex = (params.inFront != null && params.inFront) ? 113 : 10;
+};
+
+Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._layerDiv = null;
+};
+
+Timeline.SpanHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(this._zIndex);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._unit.compare(this._startDate, maxDate) < 0 &&
+ this._unit.compare(this._endDate, minDate) > 0) {
+
+ minDate = this._unit.later(minDate, this._startDate);
+ maxDate = this._unit.earlier(maxDate, this._endDate);
+
+ var minPixel = this._band.dateToPixelOffset(minDate);
+ var maxPixel = this._band.dateToPixelOffset(maxDate);
+
+ var doc = this._timeline.getDocument();
+
+ var createTable = function() {
+ var table = doc.createElement("table");
+ table.insertRow(0).insertCell(0);
+ return table;
+ };
+
+ var div = doc.createElement("div");
+ div.className='timeline-highlight-decorator'
+ if(this._cssClass) {
+ div.className += ' ' + this._cssClass;
+ }
+ if(this._color != null) {
+ div.style.backgroundColor = this._color;
+ }
+ if (this._opacity < 100) {
+ SimileAjax.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ var tableStartLabel = createTable();
+ tableStartLabel.className = 'timeline-highlight-label timeline-highlight-label-start'
+ var tdStart = tableStartLabel.rows[0].cells[0]
+ tdStart.innerHTML = this._startLabel;
+ if (this._cssClass) {
+ tdStart.className = 'label_' + this._cssClass;
+ }
+ this._layerDiv.appendChild(tableStartLabel);
+
+ var tableEndLabel = createTable();
+ tableEndLabel.className = 'timeline-highlight-label timeline-highlight-label-end'
+ var tdEnd = tableEndLabel.rows[0].cells[0]
+ tdEnd.innerHTML = this._endLabel;
+ if (this._cssClass) {
+ tdEnd.className = 'label_' + this._cssClass;
+ }
+ this._layerDiv.appendChild(tableEndLabel);
+
+ if (this._timeline.isHorizontal()){
+ div.style.left = minPixel + "px";
+ div.style.width = (maxPixel - minPixel) + "px";
+
+ tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px";
+ tableStartLabel.style.width = (this._startLabel.length) + "em";
+
+ tableEndLabel.style.left = maxPixel + "px";
+ tableEndLabel.style.width = (this._endLabel.length) + "em";
+
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = (maxPixel - minPixel) + "px";
+
+ tableStartLabel.style.bottom = minPixel + "px";
+ tableStartLabel.style.height = "1.5px";
+
+ tableEndLabel.style.top = maxPixel + "px";
+ tableEndLabel.style.height = "1.5px";
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Point Highlight Decorator
+ *==================================================
+ */
+
+Timeline.PointHighlightDecorator = function(params) {
+ this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+ this._date = (typeof params.date == "string") ?
+ this._unit.parseFromObject(params.date) : params.date;
+ this._width = params.width != null ? params.width : 10;
+ // Since the width is used to calculate placements (see minPixel, below), we
+ // specify width here, not in css.
+ this._color = params.color;
+ this._cssClass = params.cssClass != null ? params.cssClass : '';
+ this._opacity = params.opacity != null ? params.opacity : 100;
+};
+
+Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+ this._layerDiv = null;
+};
+
+Timeline.PointHighlightDecorator.prototype.paint = function() {
+ if (this._layerDiv != null) {
+ this._band.removeLayerDiv(this._layerDiv);
+ }
+ this._layerDiv = this._band.createLayerDiv(10);
+ this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+ this._layerDiv.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ if (this._unit.compare(this._date, maxDate) < 0 &&
+ this._unit.compare(this._date, minDate) > 0) {
+
+ var pixel = this._band.dateToPixelOffset(this._date);
+ var minPixel = pixel - Math.round(this._width / 2);
+
+ var doc = this._timeline.getDocument();
+
+ var div = doc.createElement("div");
+ div.className='timeline-highlight-point-decorator';
+ div.className += ' ' + this._cssClass;
+
+ if(this._color != null) {
+ div.style.backgroundColor = this._color;
+ }
+ if (this._opacity < 100) {
+ SimileAjax.Graphics.setOpacity(div, this._opacity);
+ }
+ this._layerDiv.appendChild(div);
+
+ if (this._timeline.isHorizontal()) {
+ div.style.left = minPixel + "px";
+ div.style.width = this._width;
+ } else {
+ div.style.top = minPixel + "px";
+ div.style.height = this._width;
+ }
+ }
+ this._layerDiv.style.display = "block";
+};
+
+Timeline.PointHighlightDecorator.prototype.softPaint = function() {
+};
diff --git a/src/webapp/api/scripts/detailed-painter.js b/src/webapp/api/scripts/detailed-painter.js
new file mode 100644
index 0000000..a0a2c56
--- /dev/null
+++ b/src/webapp/api/scripts/detailed-painter.js
@@ -0,0 +1,691 @@
+/*==================================================
+ * Detailed Event Painter
+ *==================================================
+ */
+
+// Note: a number of features from original-painter
+// are not yet implemented in detailed painter.
+// Eg classname, id attributes for icons, labels, tapes
+
+Timeline.DetailedEventPainter = function(params) {
+ this._params = params;
+ this._onSelectListeners = [];
+
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
+
+ this._eventIdToElmt = {};
+};
+
+Timeline.DetailedEventPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backLayer = null;
+ this._eventLayer = null;
+ this._lineLayer = null;
+ this._highlightLayer = null;
+
+ this._eventIdToElmt = null;
+};
+
+Timeline.DetailedEventPainter.prototype.getType = function() {
+ return 'detailed';
+};
+
+Timeline.DetailedEventPainter.prototype.addOnSelectListener = function(listener) {
+ this._onSelectListeners.push(listener);
+};
+
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener = function(listener) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ if (this._onSelectListeners[i] == listener) {
+ this._onSelectListeners.splice(i, 1);
+ break;
+ }
+ }
+};
+
+Timeline.DetailedEventPainter.prototype.getFilterMatcher = function() {
+ return this._filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+ this._filterMatcher = filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher = function() {
+ return this._highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+ this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.paint = function() {
+ var eventSource = this._band.getEventSource();
+ if (eventSource == null) {
+ return;
+ }
+
+ this._eventIdToElmt = {};
+ this._prepareForPainting();
+
+ var eventTheme = this._params.theme.event;
+ var trackHeight = Math.max(eventTheme.track.height, this._frc.getLineHeight());
+ var metrics = {
+ trackOffset: Math.round(this._band.getViewWidth() / 2 - trackHeight / 2),
+ trackHeight: trackHeight,
+ trackGap: eventTheme.track.gap,
+ trackIncrement: trackHeight + eventTheme.track.gap,
+ icon: eventTheme.instant.icon,
+ iconWidth: eventTheme.instant.iconWidth,
+ iconHeight: eventTheme.instant.iconHeight,
+ labelWidth: eventTheme.label.width
+ }
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var filterMatcher = (this._filterMatcher != null) ?
+ this._filterMatcher :
+ function(evt) { return true; };
+ var highlightMatcher = (this._highlightMatcher != null) ?
+ this._highlightMatcher :
+ function(evt) { return -1; };
+
+ var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+ while (iterator.hasNext()) {
+ var evt = iterator.next();
+ if (filterMatcher(evt)) {
+ this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+ }
+ }
+
+ this._highlightLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+ this._eventLayer.style.display = "block";
+ // update the band object for max number of tracks in this section of the ether
+ this._band.updateEventTrackInfo(this._lowerTracks.length + this._upperTracks.length,
+ metrics.trackIncrement);
+};
+
+Timeline.DetailedEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.DetailedEventPainter.prototype._prepareForPainting = function() {
+ var band = this._band;
+
+ if (this._backLayer == null) {
+ this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+ this._backLayer.style.visibility = "hidden";
+
+ var eventLabelPrototype = document.createElement("span");
+ eventLabelPrototype.className = "timeline-event-label";
+ this._backLayer.appendChild(eventLabelPrototype);
+ this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+ }
+ this._frc.update();
+ this._lowerTracks = [];
+ this._upperTracks = [];
+
+ if (this._highlightLayer != null) {
+ band.removeLayerDiv(this._highlightLayer);
+ }
+ this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+ this._highlightLayer.style.display = "none";
+
+ if (this._lineLayer != null) {
+ band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+ this._lineLayer.style.display = "none";
+
+ if (this._eventLayer != null) {
+ band.removeLayerDiv(this._eventLayer);
+ }
+ this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
+ this._eventLayer.style.display = "none";
+};
+
+Timeline.DetailedEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isInstant()) {
+ this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.DetailedEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ if (evt.isImprecise()) {
+ this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ } else {
+ this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+ }
+}
+
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelSize = this._frc.computeSize(text);
+ var iconTrack = this._findFreeTrackForSolid(iconRightEdge, startPixel);
+ var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelTrack = iconTrack;
+
+ var iconTrackData = this._getTrackData(iconTrack);
+ if (Math.min(iconTrackData.solid, iconTrackData.text) >= labelLeft + labelSize.width) { // label on the same track, to the right of icon
+ iconTrackData.solid = iconLeftEdge;
+ iconTrackData.text = labelLeft;
+ } else { // label on a different track, below icon
+ iconTrackData.solid = iconLeftEdge;
+
+ labelLeft = startPixel + theme.event.label.offsetFromLine;
+ labelTrack = this._findFreeTrackForText(iconTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = iconLeftEdge;
+
+ this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+ }
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+ var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+ var labelSize = this._frc.computeSize(text);
+ var iconTrack = this._findFreeTrackForSolid(endPixel, startPixel);
+
+ var tapeElmtData = this._paintEventTape(evt, iconTrack, startPixel, endPixel,
+ theme.event.instant.impreciseColor, theme.event.instant.impreciseOpacity, metrics, theme);
+ var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+ var iconTrackData = this._getTrackData(iconTrack);
+ iconTrackData.solid = iconLeftEdge;
+
+ var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+ var labelRight = labelLeft + labelSize.width;
+ var labelTrack;
+ if (labelRight < endPixel) {
+ labelTrack = iconTrack;
+ } else {
+ labelLeft = startPixel + theme.event.label.offsetFromLine;
+ labelRight = labelLeft + labelSize.width;
+
+ labelTrack = this._findFreeTrackForText(iconTrack, labelRight, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = iconLeftEdge;
+
+ this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+ }
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var endDate = evt.getEnd();
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+ var labelSize = this._frc.computeSize(text);
+ var tapeTrack = this._findFreeTrackForSolid(endPixel);
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ var tapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel, color, 100, metrics, theme);
+
+ var tapeTrackData = this._getTrackData(tapeTrack);
+ tapeTrackData.solid = startPixel;
+
+ var labelLeft = startPixel + theme.event.label.offsetFromLine;
+ var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+ this._getTrackData(labelTrack).text = startPixel - 2;
+
+ this._paintEventLine(evt, startPixel, tapeTrack, labelTrack, metrics, theme);
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+ var doc = this._timeline.getDocument();
+ var text = evt.getText();
+
+ var startDate = evt.getStart();
+ var latestStartDate = evt.getLatestStart();
+ var endDate = evt.getEnd();
+ var earliestEndDate = evt.getEarliestEnd();
+
+ var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+ var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+ var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+ var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+ var labelSize = this._frc.computeSize(text);
+ var tapeTrack = this._findFreeTrackForSolid(endPixel);
+ var color = evt.getColor();
+ color = color != null ? color : theme.event.duration.color;
+
+ var impreciseTapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel,
+ theme.event.duration.impreciseColor, theme.event.duration.impreciseOpacity, metrics, theme);
+ var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel, color, 100, metrics, theme);
+
+ var tapeTrackData = this._getTrackData(tapeTrack);
+ tapeTrackData.solid = startPixel;
+
+ var labelLeft = latestStartPixel + theme.event.label.offsetFromLine;
+ var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = latestStartPixel - 2; });
+ this._getTrackData(labelTrack).text = latestStartPixel - 2;
+
+ this._paintEventLine(evt, latestStartPixel, tapeTrack, labelTrack, metrics, theme);
+
+ var labelTop = Math.round(
+ metrics.trackOffset + labelTrack * metrics.trackIncrement +
+ metrics.trackHeight / 2 - labelSize.height / 2);
+
+ var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+ var self = this;
+ var clickHandler = function(elmt, domEvt, target) {
+ return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+ };
+ SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+ SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+ this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+ this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid = function(solidEdge, softEdge) {
+ for (var i = 0; true; i++) {
+ if (i < this._lowerTracks.length) {
+ var t = this._lowerTracks[i];
+ if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+ return i;
+ }
+ } else {
+ this._lowerTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+
+ return i;
+ }
+
+ if (i < this._upperTracks.length) {
+ var t = this._upperTracks[i];
+ if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+ return -1 - i;
+ }
+ } else {
+ this._upperTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+
+ return -1 - i;
+ }
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText = function(fromTrack, edge, occupiedTrackVisitor) {
+ var extendUp;
+ var index;
+ var firstIndex;
+ var result;
+
+ if (fromTrack < 0) {
+ extendUp = true;
+ firstIndex = -fromTrack;
+
+ index = this._findFreeUpperTrackForText(firstIndex, edge);
+ result = -1 - index;
+ } else if (fromTrack > 0) {
+ extendUp = false;
+ firstIndex = fromTrack + 1;
+
+ index = this._findFreeLowerTrackForText(firstIndex, edge);
+ result = index;
+ } else {
+ var upIndex = this._findFreeUpperTrackForText(0, edge);
+ var downIndex = this._findFreeLowerTrackForText(1, edge);
+
+ if (downIndex - 1 <= upIndex) {
+ extendUp = false;
+ firstIndex = 1;
+ index = downIndex;
+ result = index;
+ } else {
+ extendUp = true;
+ firstIndex = 0;
+ index = upIndex;
+ result = -1 - index;
+ }
+ }
+
+ if (extendUp) {
+ if (index == this._upperTracks.length) {
+ this._upperTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+ }
+ for (var i = firstIndex; i < index; i++) {
+ occupiedTrackVisitor(this._upperTracks[i]);
+ }
+ } else {
+ if (index == this._lowerTracks.length) {
+ this._lowerTracks.push({
+ solid: Number.POSITIVE_INFINITY,
+ text: Number.POSITIVE_INFINITY,
+ line: Number.POSITIVE_INFINITY
+ });
+ }
+ for (var i = firstIndex; i < index; i++) {
+ occupiedTrackVisitor(this._lowerTracks[i]);
+ }
+ }
+ return result;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText = function(index, edge) {
+ for (; index < this._lowerTracks.length; index++) {
+ var t = this._lowerTracks[index];
+ if (Math.min(t.solid, t.text) >= edge) {
+ break;
+ }
+ }
+ return index;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText = function(index, edge) {
+ for (; index < this._upperTracks.length; index++) {
+ var t = this._upperTracks[index];
+ if (Math.min(t.solid, t.text) >= edge) {
+ break;
+ }
+ }
+ return index;
+};
+
+Timeline.DetailedEventPainter.prototype._getTrackData = function(index) {
+ return (index < 0) ? this._upperTracks[-index - 1] : this._lowerTracks[index];
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLine = function(evt, left, startTrack, endTrack, metrics, theme) {
+ var top = Math.round(metrics.trackOffset + startTrack * metrics.trackIncrement + metrics.trackHeight / 2);
+ var height = Math.round(Math.abs(endTrack - startTrack) * metrics.trackIncrement);
+
+ var lineStyle = "1px solid " + theme.event.label.lineColor;
+ var lineDiv = this._timeline.getDocument().createElement("div");
+ lineDiv.style.position = "absolute";
+ lineDiv.style.left = left + "px";
+ lineDiv.style.width = theme.event.label.offsetFromLine + "px";
+ lineDiv.style.height = height + "px";
+ if (startTrack > endTrack) {
+ lineDiv.style.top = (top - height) + "px";
+ lineDiv.style.borderTop = lineStyle;
+ } else {
+ lineDiv.style.top = top + "px";
+ lineDiv.style.borderBottom = lineStyle;
+ }
+ lineDiv.style.borderLeft = lineStyle;
+ this._lineLayer.appendChild(lineDiv);
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme) {
+ var icon = evt.getIcon();
+ icon = icon != null ? icon : metrics.icon;
+
+ var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+ var top = Math.round(middle - metrics.iconHeight / 2);
+
+ var img = SimileAjax.Graphics.createTranslucentImage(icon);
+ var iconDiv = this._timeline.getDocument().createElement("div");
+ iconDiv.style.position = "absolute";
+ iconDiv.style.left = left + "px";
+ iconDiv.style.top = top + "px";
+ iconDiv.appendChild(img);
+ iconDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ iconDiv.title = evt._title
+
+ this._eventLayer.appendChild(iconDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: metrics.iconWidth,
+ height: metrics.iconHeight,
+ elmt: iconDiv
+ };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width, height, theme) {
+ var doc = this._timeline.getDocument();
+
+ var labelBackgroundDiv = doc.createElement("div");
+ labelBackgroundDiv.style.position = "absolute";
+ labelBackgroundDiv.style.left = left + "px";
+ labelBackgroundDiv.style.width = width + "px";
+ labelBackgroundDiv.style.top = top + "px";
+ labelBackgroundDiv.style.height = height + "px";
+ labelBackgroundDiv.style.backgroundColor = theme.event.label.backgroundColor;
+ SimileAjax.Graphics.setOpacity(labelBackgroundDiv, theme.event.label.backgroundOpacity);
+ this._eventLayer.appendChild(labelBackgroundDiv);
+
+ var labelDiv = doc.createElement("div");
+ labelDiv.style.position = "absolute";
+ labelDiv.style.left = left + "px";
+ labelDiv.style.width = width + "px";
+ labelDiv.style.top = top + "px";
+ labelDiv.innerHTML = text;
+ labelDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ labelDiv.title = evt._title;
+
+ var color = evt.getTextColor();
+ if (color == null) {
+ color = evt.getColor();
+ }
+ if (color != null) {
+ labelDiv.style.color = color;
+ }
+
+ this._eventLayer.appendChild(labelDiv);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ elmt: labelDiv
+ };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventTape = function(
+ evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme) {
+
+ var tapeWidth = endPixel - startPixel;
+ var tapeHeight = theme.event.tape.height;
+ var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+ var top = Math.round(middle - tapeHeight / 2);
+
+ var tapeDiv = this._timeline.getDocument().createElement("div");
+ tapeDiv.style.position = "absolute";
+ tapeDiv.style.left = startPixel + "px";
+ tapeDiv.style.width = tapeWidth + "px";
+ tapeDiv.style.top = top + "px";
+ tapeDiv.style.height = tapeHeight + "px";
+ tapeDiv.style.backgroundColor = color;
+ tapeDiv.style.overflow = "hidden";
+ tapeDiv.style.cursor = "pointer";
+
+ if(evt._title != null)
+ tapeDiv.title = evt._title;
+
+ SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+ this._eventLayer.appendChild(tapeDiv);
+
+ return {
+ left: startPixel,
+ top: top,
+ width: tapeWidth,
+ height: tapeHeight,
+ elmt: tapeDiv
+ };
+}
+
+Timeline.DetailedEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+ if (highlightIndex >= 0) {
+ var doc = this._timeline.getDocument();
+ var eventTheme = theme.event;
+
+ var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+ var div = doc.createElement("div");
+ div.style.position = "absolute";
+ div.style.overflow = "hidden";
+ div.style.left = (dimensions.left - 2) + "px";
+ div.style.width = (dimensions.width + 4) + "px";
+ div.style.top = (dimensions.top - 2) + "px";
+ div.style.height = (dimensions.height + 4) + "px";
+ div.style.background = color;
+
+ this._highlightLayer.appendChild(div);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+ var c = SimileAjax.DOM.getPageCoordinates(icon);
+ this._showBubble(
+ c.left + Math.ceil(icon.offsetWidth / 2),
+ c.top + Math.ceil(icon.offsetHeight / 2),
+ evt
+ );
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+ if ("pageX" in domEvt) {
+ var x = domEvt.pageX;
+ var y = domEvt.pageY;
+ } else {
+ var c = SimileAjax.DOM.getPageCoordinates(target);
+ var x = domEvt.offsetX + c.left;
+ var y = domEvt.offsetY + c.top;
+ }
+ this._showBubble(x, y, evt);
+ this._fireOnSelect(evt.getID());
+
+ domEvt.cancelBubble = true;
+ SimileAjax.DOM.cancelEvent(domEvt);
+ return false;
+};
+
+Timeline.DetailedEventPainter.prototype.showBubble = function(evt) {
+ var elmt = this._eventIdToElmt[evt.getID()];
+ if (elmt) {
+ var c = SimileAjax.DOM.getPageCoordinates(elmt);
+ this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
+ }
+};
+
+Timeline.DetailedEventPainter.prototype._showBubble = function(x, y, evt) {
+ var div = document.createElement("div");
+ var themeBubble = this._params.theme.event.bubble;
+ evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
+ themeBubble.width, null, themeBubble.maxHeight);
+};
+
+Timeline.DetailedEventPainter.prototype._fireOnSelect = function(eventID) {
+ for (var i = 0; i < this._onSelectListeners.length; i++) {
+ this._onSelectListeners[i](eventID);
+ }
+};
diff --git a/src/webapp/api/scripts/ether-painters.js b/src/webapp/api/scripts/ether-painters.js
new file mode 100644
index 0000000..51a0d5c
--- /dev/null
+++ b/src/webapp/api/scripts/ether-painters.js
@@ -0,0 +1,576 @@
+/*==================================================
+ * Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.GregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._unit = params.unit;
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.GregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.GregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ SimileAjax.DateTime.roundDownToInterval(minDate, this._unit, timeZone, this._multiple, this._theme.firstDayOfWeek);
+
+ var p = this;
+ var incrementDate = function(date) {
+ for (var i = 0; i < p._multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, p._unit);
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, this._unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.GregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.GregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+ if (netIntervalChange != 0) {
+ this._unit += netIntervalChange;
+ }
+};
+
+
+/*==================================================
+ * Hot Zone Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.HotZoneGregorianEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+
+ this._zones = [{
+ startTime: Number.NEGATIVE_INFINITY,
+ endTime: Number.POSITIVE_INFINITY,
+ unit: params.unit,
+ multiple: 1
+ }];
+ for (var i = 0; i < params.zones.length; i++) {
+ var zone = params.zones[i];
+ var zoneStart = SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
+ var zoneEnd = SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
+
+ for (var j = 0; j < this._zones.length && zoneEnd > zoneStart; j++) {
+ var zone2 = this._zones[j];
+
+ if (zoneStart < zone2.endTime) {
+ if (zoneStart > zone2.startTime) {
+ this._zones.splice(j, 0, {
+ startTime: zone2.startTime,
+ endTime: zoneStart,
+ unit: zone2.unit,
+ multiple: zone2.multiple
+ });
+ j++;
+
+ zone2.startTime = zoneStart;
+ }
+
+ if (zoneEnd < zone2.endTime) {
+ this._zones.splice(j, 0, {
+ startTime: zoneStart,
+ endTime: zoneEnd,
+ unit: zone.unit,
+ multiple: (zone.multiple) ? zone.multiple : 1
+ });
+ j++;
+
+ zone2.startTime = zoneEnd;
+ zoneStart = zoneEnd;
+ } else {
+ zone2.multiple = zone.multiple;
+ zone2.unit = zone.unit;
+ zoneStart = zone2.endTime;
+ }
+ } // else, try the next existing zone
+ }
+ }
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className ='timeline-ether-bg';
+ //this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = this._band.getMinDate();
+ var maxDate = this._band.getMaxDate();
+
+ var timeZone = this._band.getTimeZone();
+ var labeller = this._band.getLabeller();
+
+ var p = this;
+ var incrementDate = function(date, zone) {
+ for (var i = 0; i < zone.multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, zone.unit);
+ }
+ };
+
+ var zStart = 0;
+ while (zStart < this._zones.length) {
+ if (minDate.getTime() < this._zones[zStart].endTime) {
+ break;
+ }
+ zStart++;
+ }
+ var zEnd = this._zones.length - 1;
+ while (zEnd >= 0) {
+ if (maxDate.getTime() > this._zones[zEnd].startTime) {
+ break;
+ }
+ zEnd--;
+ }
+
+ for (var z = zStart; z <= zEnd; z++) {
+ var zone = this._zones[z];
+
+ var minDate2 = new Date(Math.max(minDate.getTime(), zone.startTime));
+ var maxDate2 = new Date(Math.min(maxDate.getTime(), zone.endTime));
+
+ SimileAjax.DateTime.roundDownToInterval(minDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+ SimileAjax.DateTime.roundUpToInterval(maxDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+
+ while (minDate2.getTime() < maxDate2.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate2, labeller, zone.unit, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate2, zone);
+ }
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+ if (netIntervalChange != 0) {
+ for (var i = 0; i < this._zones.length; ++i) {
+ if (this._zones[i]) {
+ this._zones[i].unit += netIntervalChange;
+ }
+ }
+ }
+};
+
+/*==================================================
+ * Year Count Ether Painter
+ *==================================================
+ */
+
+Timeline.YearCountEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+ this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.YearCountEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.YearCountEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.YearCountEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(this._startDate.getTime());
+ var maxDate = this._band.getMaxDate();
+ var yearDiff = this._band.getMinDate().getUTCFullYear() - this._startDate.getUTCFullYear();
+ minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear() - yearDiff % this._multiple);
+
+ var p = this;
+ var incrementDate = function(date) {
+ for (var i = 0; i < p._multiple; i++) {
+ SimileAjax.DateTime.incrementByInterval(date, SimileAjax.DateTime.YEAR);
+ }
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var diff = date.getUTCFullYear() - p._startDate.getUTCFullYear();
+ return {
+ text: diff,
+ emphasized: diff == 0
+ };
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.YearCountEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Quarterly Ether Painter
+ *==================================================
+ */
+
+Timeline.QuarterlyEtherPainter = function(params) {
+ this._params = params;
+ this._theme = params.theme;
+ this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.initialize = function(band, timeline) {
+ this._band = band;
+ this._timeline = timeline;
+
+ this._backgroundLayer = band.createLayerDiv(0);
+ this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+ this._backgroundLayer.className = 'timeline-ether-bg';
+ // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+ this._markerLayer = null;
+ this._lineLayer = null;
+
+ var align = ("align" in this._params) ? this._params.align :
+ this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+ var showLine = ("showLine" in this._params) ? this._params.showLine :
+ this._theme.ether.interval.line.show;
+
+ this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+ this._timeline, this._band, this._theme, align, showLine);
+
+ this._highlight = new Timeline.EtherHighlight(
+ this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+ this._highlight.position(startDate, endDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.paint = function() {
+ if (this._markerLayer) {
+ this._band.removeLayerDiv(this._markerLayer);
+ }
+ this._markerLayer = this._band.createLayerDiv(100);
+ this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+ this._markerLayer.style.display = "none";
+
+ if (this._lineLayer) {
+ this._band.removeLayerDiv(this._lineLayer);
+ }
+ this._lineLayer = this._band.createLayerDiv(1);
+ this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+ this._lineLayer.style.display = "none";
+
+ var minDate = new Date(0);
+ var maxDate = this._band.getMaxDate();
+
+ minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(), this._band.getMinDate().getUTCFullYear()));
+ minDate.setUTCMonth(this._startDate.getUTCMonth());
+
+ var p = this;
+ var incrementDate = function(date) {
+ date.setUTCMonth(date.getUTCMonth() + 3);
+ };
+ var labeller = {
+ labelInterval: function(date, intervalUnit) {
+ var quarters = (4 + (date.getUTCMonth() - p._startDate.getUTCMonth()) / 3) % 4;
+ if (quarters != 0) {
+ return { text: "Q" + (quarters + 1), emphasized: false };
+ } else {
+ return { text: "Y" + (date.getUTCFullYear() - p._startDate.getUTCFullYear() + 1), emphasized: true };
+ }
+ }
+ };
+
+ while (minDate.getTime() < maxDate.getTime()) {
+ this._intervalMarkerLayout.createIntervalMarker(
+ minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+ incrementDate(minDate);
+ }
+ this._markerLayer.style.display = "block";
+ this._lineLayer.style.display = "block";
+};
+
+Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ * Ether Interval Marker Layout
+ *==================================================
+ */
+
+Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
+ var horizontal = timeline.isHorizontal();
+ if (horizontal) {
+ if (align == "Top") {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.top = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.left = offset + "px";
+ div.style.bottom = "0px";
+ };
+ }
+ } else {
+ if (align == "Left") {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.left = "0px";
+ };
+ } else {
+ this.positionDiv = function(div, offset) {
+ div.style.top = offset + "px";
+ div.style.right = "0px";
+ };
+ }
+ }
+
+ var markerTheme = theme.ether.interval.marker;
+ var lineTheme = theme.ether.interval.line;
+ var weekendTheme = theme.ether.interval.weekend;
+
+ var stylePrefix = (horizontal ? "h" : "v") + align;
+ var labelStyler = markerTheme[stylePrefix + "Styler"];
+ var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+ var day = SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+
+ this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+ var offset = Math.round(band.dateToPixelOffset(date));
+
+ if (showLine && unit != SimileAjax.DateTime.WEEK) {
+ var divLine = timeline.getDocument().createElement("div");
+ divLine.className = "timeline-ether-lines";
+
+ if (lineTheme.opacity < 100) {
+ SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
+ }
+
+ if (horizontal) {
+ //divLine.className += " timeline-ether-lines-vertical";
+ divLine.style.left = offset + "px";
+ } else {
+ //divLine.className += " timeline-ether-lines-horizontal";
+ divLine.style.top = offset + "px";
+ }
+ lineDiv.appendChild(divLine);