From c5d0cd2824e3c3bb2f6f3834177a71c1d7b78519 Mon Sep 17 00:00:00 2001 From: xue <> Date: Tue, 27 Mar 2007 00:47:38 +0000 Subject: merge from 3.0 branch till 1779. --- framework/3rdParty/readme.html | 14 +- .../Web/Javascripts/colorpicker/background.png | Bin 14501 -> 0 bytes framework/Web/Javascripts/colorpicker/button.gif | Bin 58 -> 0 bytes .../Web/Javascripts/colorpicker/colorpicker.js | 532 --- framework/Web/Javascripts/colorpicker/default.css | 258 -- framework/Web/Javascripts/colorpicker/hue.gif | Bin 2793 -> 0 bytes framework/Web/Javascripts/colorpicker/slider.gif | Bin 81 -> 0 bytes framework/Web/Javascripts/colorpicker/spacer.gif | Bin 43 -> 0 bytes .../Web/Javascripts/colorpicker/target_black.gif | Bin 56 -> 0 bytes .../Web/Javascripts/colorpicker/target_white.gif | Bin 56 -> 0 bytes framework/Web/Javascripts/datepicker/calendar.png | Bin 775 -> 0 bytes framework/Web/Javascripts/datepicker/datepicker.js | 696 ---- framework/Web/Javascripts/datepicker/default.css | 98 - framework/Web/Javascripts/datepicker/spacer.gif | Bin 43 -> 0 bytes framework/Web/Javascripts/effects/CHANGELOG | 980 ------ framework/Web/Javascripts/effects/MIT-LICENSE | 20 - framework/Web/Javascripts/effects/README | 57 - framework/Web/Javascripts/effects/builder.js | 131 - framework/Web/Javascripts/effects/controls.js | 835 ----- framework/Web/Javascripts/effects/dragdrop.js | 944 ------ framework/Web/Javascripts/effects/effects.js | 1090 ------ framework/Web/Javascripts/effects/slider.js | 278 -- framework/Web/Javascripts/extended/base.js | 332 -- framework/Web/Javascripts/extended/builder.js | 24 - framework/Web/Javascripts/extended/date.js | 151 - framework/Web/Javascripts/extended/effects.js | 7 - framework/Web/Javascripts/extended/event.js | 110 - framework/Web/Javascripts/extended/string.js | 172 - framework/Web/Javascripts/extra/json.js | 340 -- framework/Web/Javascripts/extra/logger.js | 753 ----- framework/Web/Javascripts/js/compressed/ajax.js | 363 -- .../Javascripts/js/compressed/clientscripts.php | 2 +- framework/Web/Javascripts/js/compressed/prado.js | 222 +- framework/Web/Javascripts/js/compressed/rico.js | 265 -- .../Web/Javascripts/js/compressed/validator.js | 53 +- framework/Web/Javascripts/js/debug/ajax.js | 2889 ---------------- .../Web/Javascripts/js/debug/clientscripts.php | 2 +- framework/Web/Javascripts/js/debug/colorpicker.js | 118 +- framework/Web/Javascripts/js/debug/prado.js | 1662 +++------- framework/Web/Javascripts/js/debug/rico.js | 3503 -------------------- framework/Web/Javascripts/js/debug/validator.js | 156 +- .../Javascripts/prado/colorpicker/background.png | Bin 0 -> 14501 bytes .../Web/Javascripts/prado/colorpicker/button.gif | Bin 0 -> 58 bytes .../Javascripts/prado/colorpicker/colorpicker.js | 776 +++++ .../Web/Javascripts/prado/colorpicker/default.css | 258 ++ .../Web/Javascripts/prado/colorpicker/hue.gif | Bin 0 -> 2793 bytes .../Web/Javascripts/prado/colorpicker/slider.gif | Bin 0 -> 81 bytes .../Web/Javascripts/prado/colorpicker/spacer.gif | Bin 0 -> 43 bytes .../Javascripts/prado/colorpicker/target_black.gif | Bin 0 -> 56 bytes .../Javascripts/prado/colorpicker/target_white.gif | Bin 0 -> 56 bytes framework/Web/Javascripts/prado/controls.js | 290 -- .../Web/Javascripts/prado/controls/controls.js | 290 ++ .../Web/Javascripts/prado/datepicker/calendar.png | Bin 0 -> 775 bytes .../Web/Javascripts/prado/datepicker/datepicker.js | 696 ++++ .../Web/Javascripts/prado/datepicker/default.css | 98 + .../Web/Javascripts/prado/datepicker/spacer.gif | Bin 0 -> 43 bytes framework/Web/Javascripts/prado/element.js | 326 -- framework/Web/Javascripts/prado/form.js | 209 -- framework/Web/Javascripts/prado/logger/logger.js | 753 +++++ framework/Web/Javascripts/prado/ratings/blocks.css | 29 + framework/Web/Javascripts/prado/ratings/blocks.png | Bin 0 -> 29885 bytes .../Web/Javascripts/prado/ratings/blocks_blank.gif | Bin 0 -> 72 bytes .../Web/Javascripts/prado/ratings/blocks_half.gif | Bin 0 -> 94 bytes .../Web/Javascripts/prado/ratings/blocks_hover.gif | Bin 0 -> 75 bytes .../Javascripts/prado/ratings/blocks_selected.gif | Bin 0 -> 75 bytes .../Web/Javascripts/prado/ratings/default.css | 29 + .../Javascripts/prado/ratings/default_blank.gif | Bin 0 -> 271 bytes .../Web/Javascripts/prado/ratings/default_half.gif | Bin 0 -> 619 bytes .../Javascripts/prado/ratings/default_hover.gif | Bin 0 -> 618 bytes .../Javascripts/prado/ratings/default_selected.gif | Bin 0 -> 614 bytes framework/Web/Javascripts/prado/ratings/ratings.js | 60 + framework/Web/Javascripts/prado/ratings/stars1.png | Bin 0 -> 53016 bytes .../Web/Javascripts/prado/scriptaculous-adapter.js | 811 +++++ framework/Web/Javascripts/prado/validation3.js | 1366 -------- .../Web/Javascripts/prado/validator/validation3.js | 1276 +++++++ framework/Web/Javascripts/ratings/blocks.css | 42 - framework/Web/Javascripts/ratings/blocks.png | Bin 28700 -> 0 bytes framework/Web/Javascripts/ratings/blocks_blank.gif | Bin 72 -> 0 bytes .../Web/Javascripts/ratings/blocks_combined.gif | Bin 289 -> 0 bytes framework/Web/Javascripts/ratings/blocks_half.gif | Bin 94 -> 0 bytes .../Web/Javascripts/ratings/blocks_selected.gif | Bin 75 -> 0 bytes framework/Web/Javascripts/ratings/default.css | 43 - framework/Web/Javascripts/ratings/default.png | Bin 51492 -> 0 bytes .../Web/Javascripts/ratings/default_blank.gif | Bin 158 -> 0 bytes .../Web/Javascripts/ratings/default_combined.gif | Bin 1201 -> 0 bytes framework/Web/Javascripts/ratings/default_half.gif | Bin 610 -> 0 bytes .../Web/Javascripts/ratings/default_selected.gif | Bin 603 -> 0 bytes framework/Web/Javascripts/ratings/ratings.js | 178 - framework/Web/Javascripts/rico/colors.js | 242 -- framework/Web/Javascripts/rico/extension.js | 175 - framework/Web/Javascripts/rico/rico.js | 3326 ------------------- framework/Web/Javascripts/scriptaculous/CHANGELOG | 980 ++++++ .../Web/Javascripts/scriptaculous/MIT-LICENSE | 20 + framework/Web/Javascripts/scriptaculous/README | 57 + framework/Web/Javascripts/scriptaculous/builder.js | 131 + .../Web/Javascripts/scriptaculous/controls.js | 835 +++++ .../Web/Javascripts/scriptaculous/dragdrop.js | 944 ++++++ framework/Web/Javascripts/scriptaculous/effects.js | 1090 ++++++ framework/Web/Javascripts/scriptaculous/slider.js | 278 ++ framework/Web/UI/TClientScriptManager.php | 2 - framework/Web/UI/WebControls/TColorPicker.php | 4 +- framework/Web/UI/WebControls/TDatePicker.php | 6 +- 102 files changed, 10082 insertions(+), 22595 deletions(-) delete mode 100644 framework/Web/Javascripts/colorpicker/background.png delete mode 100644 framework/Web/Javascripts/colorpicker/button.gif delete mode 100644 framework/Web/Javascripts/colorpicker/colorpicker.js delete mode 100644 framework/Web/Javascripts/colorpicker/default.css delete mode 100644 framework/Web/Javascripts/colorpicker/hue.gif delete mode 100644 framework/Web/Javascripts/colorpicker/slider.gif delete mode 100755 framework/Web/Javascripts/colorpicker/spacer.gif delete mode 100644 framework/Web/Javascripts/colorpicker/target_black.gif delete mode 100644 framework/Web/Javascripts/colorpicker/target_white.gif delete mode 100644 framework/Web/Javascripts/datepicker/calendar.png delete mode 100644 framework/Web/Javascripts/datepicker/datepicker.js delete mode 100644 framework/Web/Javascripts/datepicker/default.css delete mode 100755 framework/Web/Javascripts/datepicker/spacer.gif delete mode 100644 framework/Web/Javascripts/effects/CHANGELOG delete mode 100644 framework/Web/Javascripts/effects/MIT-LICENSE delete mode 100644 framework/Web/Javascripts/effects/README delete mode 100644 framework/Web/Javascripts/effects/builder.js delete mode 100644 framework/Web/Javascripts/effects/controls.js delete mode 100644 framework/Web/Javascripts/effects/dragdrop.js delete mode 100644 framework/Web/Javascripts/effects/effects.js delete mode 100644 framework/Web/Javascripts/effects/slider.js delete mode 100644 framework/Web/Javascripts/extended/base.js delete mode 100644 framework/Web/Javascripts/extended/builder.js delete mode 100644 framework/Web/Javascripts/extended/date.js delete mode 100644 framework/Web/Javascripts/extended/effects.js delete mode 100644 framework/Web/Javascripts/extended/event.js delete mode 100644 framework/Web/Javascripts/extended/string.js delete mode 100644 framework/Web/Javascripts/extra/json.js delete mode 100644 framework/Web/Javascripts/extra/logger.js delete mode 100644 framework/Web/Javascripts/js/compressed/ajax.js delete mode 100644 framework/Web/Javascripts/js/compressed/rico.js delete mode 100644 framework/Web/Javascripts/js/debug/ajax.js delete mode 100644 framework/Web/Javascripts/js/debug/rico.js create mode 100644 framework/Web/Javascripts/prado/colorpicker/background.png create mode 100644 framework/Web/Javascripts/prado/colorpicker/button.gif create mode 100644 framework/Web/Javascripts/prado/colorpicker/colorpicker.js create mode 100644 framework/Web/Javascripts/prado/colorpicker/default.css create mode 100644 framework/Web/Javascripts/prado/colorpicker/hue.gif create mode 100644 framework/Web/Javascripts/prado/colorpicker/slider.gif create mode 100755 framework/Web/Javascripts/prado/colorpicker/spacer.gif create mode 100644 framework/Web/Javascripts/prado/colorpicker/target_black.gif create mode 100644 framework/Web/Javascripts/prado/colorpicker/target_white.gif delete mode 100644 framework/Web/Javascripts/prado/controls.js create mode 100644 framework/Web/Javascripts/prado/controls/controls.js create mode 100644 framework/Web/Javascripts/prado/datepicker/calendar.png create mode 100644 framework/Web/Javascripts/prado/datepicker/datepicker.js create mode 100644 framework/Web/Javascripts/prado/datepicker/default.css create mode 100755 framework/Web/Javascripts/prado/datepicker/spacer.gif delete mode 100644 framework/Web/Javascripts/prado/element.js delete mode 100644 framework/Web/Javascripts/prado/form.js create mode 100644 framework/Web/Javascripts/prado/logger/logger.js create mode 100644 framework/Web/Javascripts/prado/ratings/blocks.css create mode 100644 framework/Web/Javascripts/prado/ratings/blocks.png create mode 100644 framework/Web/Javascripts/prado/ratings/blocks_blank.gif create mode 100644 framework/Web/Javascripts/prado/ratings/blocks_half.gif create mode 100644 framework/Web/Javascripts/prado/ratings/blocks_hover.gif create mode 100644 framework/Web/Javascripts/prado/ratings/blocks_selected.gif create mode 100644 framework/Web/Javascripts/prado/ratings/default.css create mode 100644 framework/Web/Javascripts/prado/ratings/default_blank.gif create mode 100644 framework/Web/Javascripts/prado/ratings/default_half.gif create mode 100644 framework/Web/Javascripts/prado/ratings/default_hover.gif create mode 100644 framework/Web/Javascripts/prado/ratings/default_selected.gif create mode 100644 framework/Web/Javascripts/prado/ratings/ratings.js create mode 100644 framework/Web/Javascripts/prado/ratings/stars1.png create mode 100644 framework/Web/Javascripts/prado/scriptaculous-adapter.js delete mode 100644 framework/Web/Javascripts/prado/validation3.js create mode 100644 framework/Web/Javascripts/prado/validator/validation3.js delete mode 100644 framework/Web/Javascripts/ratings/blocks.css delete mode 100644 framework/Web/Javascripts/ratings/blocks.png delete mode 100644 framework/Web/Javascripts/ratings/blocks_blank.gif delete mode 100644 framework/Web/Javascripts/ratings/blocks_combined.gif delete mode 100644 framework/Web/Javascripts/ratings/blocks_half.gif delete mode 100644 framework/Web/Javascripts/ratings/blocks_selected.gif delete mode 100644 framework/Web/Javascripts/ratings/default.css delete mode 100644 framework/Web/Javascripts/ratings/default.png delete mode 100644 framework/Web/Javascripts/ratings/default_blank.gif delete mode 100644 framework/Web/Javascripts/ratings/default_combined.gif delete mode 100644 framework/Web/Javascripts/ratings/default_half.gif delete mode 100644 framework/Web/Javascripts/ratings/default_selected.gif delete mode 100644 framework/Web/Javascripts/ratings/ratings.js delete mode 100644 framework/Web/Javascripts/rico/colors.js delete mode 100644 framework/Web/Javascripts/rico/extension.js delete mode 100644 framework/Web/Javascripts/rico/rico.js create mode 100644 framework/Web/Javascripts/scriptaculous/CHANGELOG create mode 100644 framework/Web/Javascripts/scriptaculous/MIT-LICENSE create mode 100644 framework/Web/Javascripts/scriptaculous/README create mode 100644 framework/Web/Javascripts/scriptaculous/builder.js create mode 100644 framework/Web/Javascripts/scriptaculous/controls.js create mode 100644 framework/Web/Javascripts/scriptaculous/dragdrop.js create mode 100644 framework/Web/Javascripts/scriptaculous/effects.js create mode 100644 framework/Web/Javascripts/scriptaculous/slider.js (limited to 'framework') diff --git a/framework/3rdParty/readme.html b/framework/3rdParty/readme.html index 6b79f694..4da09643 100644 --- a/framework/3rdParty/readme.html +++ b/framework/3rdParty/readme.html @@ -37,7 +37,7 @@ projects.
this is neat!
"); - -* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo] - - For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses. - -* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin] - -* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd] - -*V1.6.4* (September 6, 2006) - -* Hotfix IE issues with patched Prototype V1.5.0_rc1 - -*V1.6.3* (September 5, 2006) - -* Update Prototype to V1.5.0_rc1 - -* Merge assertElementsMatch and assertElementMatches from Prototype's [4986] unittest.js [Sam Stephenson] - -* Update Prototype to revision [4930] - -* Fix various issues with IE detection and Opera, and setOpacity, fixes #3886, #5973 - -* Make Sortable.serialize handle DOM IDs like "some_element_1" correctly, fixes #5324 - -* Add assertRespondsTo and shouldRespondTo assertions - -* Add experimental alternate syntax for unit tests (Behaviour Driven Development-style) - -* Add support for onStart, onDrag and onEnd events directly on Draggables (invoked from the Draggables.notify), fixes #4747 [thx scriptkitchen] - -* Add element shortcuts to Builder that can be activated by calling Builder.dump() (see the unit test), fixes #4260 [thx napalm] - -* Fix selection of correct option in SELECT element generated by InPlaceCollectionEditor for indexed option arrays, fixes #4789 [thx steve] - -* Add autoSelect option to Autocompleters to auto select an entry if only one is returned, fixes #5183 [thx cassiano dandrea] - -* Added delay option to Draggables and Sortables, see test/functional/dragdrop_delay_test.html for usage, implements #3325 [thx lsimon, tomg] - -* Remove revert cache code obsoleted by #4706, fixes #3436 (again) [thx tomg] - -* Fix autoscrolling inside scrollable containers when window is scrolled too, fixes #5200 [thx wseitz] - -* Make Effect.Puff work correctly for floating elements, fixes #3777 [thx michael hartl] - -* Add version and timestamp to indvidual library files for easier identification (the files are preprocessed by the Rake fresh_scriptaculous task), fixes #3015 [thx Tobie] - -* Add assertIndentical and assertNotIdentical unit test assertions, which test for equality and common type, fixes #5822 [thx glazedginger] - -* Add integration test for Ajax autocompleter for results with no linebreaks, #4149 - -* Fix an issue with redrawing ghosted draggables that are inside a scrolled container, fixes #3860 [thx gkupps, tsukue] - -* Added a custom exception to all base effects when used on non-existing DOM elements, added a assertRaise method to unit tests - -* Fix autoscrolling when dragging an element unto a scrollable container, fixes #5017 [thx tomg] - -* Fix a condition where overriding the endeffect on Draggables without overriding the starteffect too leads to a Javascript error [thx Javier Martinez] - -* Fix a possible error with the drag/drop logic (affects the solution to #4706) - -*V1.6.2* - -* Fix a problem in the drag and drop logic if an reverting/drag ending draggable was initialized for a new drag (for example by clicking repeatedly) for all cases where the default start/revert/end-effects are used, fixes #4706 [thx tecM0] - -* Fix possible memory leaks with Draggables, fixes #3436 [thx aal] - -* Throw nicer errors when requires script.aculo.us libraries are not loaded, fixes #5339 - -* Make slider handles work when not displayed initially by using CSS width/height, fixes #4011 [thx foysavas] - -* Update sortable functional test with onUpdate counter - -* Make more Element extensions unit tests work on Safari - -* Add the assertMatch unit test assertion for asserts with RegExps [thx Ian Tyndall] - -* Fix a problem with Effect.Move causing "jumping" elements because of very low float numbers in some situations - -* Fix a missing semicolon in dragdrop.js, fixes #5569 [thx mackalicious] - -* Fix a slight inaccuracy with Effect.Scale that could lead the scaling to be one pixel off - -* Be more prototypish with Effect.Transitions.linear - -* Make Effect.Scale recognize font sizes that use the pt unit, fixes #4136 [thx aljoscha] - -* Fix IE hack in Effect.Opacity, fixes #5444 [thx nicholas] - -* Fix IFRAME layout fix for IE and Autocompleter, fixes #5192 [thx tommy skaue] - -* Fix only option in onEmptyHover, fiex #5348 [thx glenn nilsson] - -* Fix Effect.BlindDown and SwitchOff handling of supplied callbacks, fixes #5089 [thx martinstrom] - -* Fix a problem with field focus on Ajax.InPlaceEditor and loading external text, fixes #4988, #5244 [thx rob] - -* Do not attempt to scroll if scrollspeed is 0/0, fixes #5035 [thx tomg] - -* Fix a problem with Sortable Tree serialization, fixes #4939, #4688, #4767 [thx Sammi Williams] - -* Fix an endless loop with sliders, fixes #3226, #4051, #4765 [thx jeff] - -* Make autocompleter work with update DIVs that have scrollbars, fixes #4782 [thx Tommy Skaue] - -* Corrected options parsing on switchoff effect, fixes #4710 [thx haldini] - -*V1.6.1* - -* Update to Prototype 1.5.0_rc0 - -* Add Draggable object as third parameter to snap, fixes #4074 [thx mdaines] - -* Fix an IE flicker with SlideUp/SlideDown, fixes #3774, [thx sbbowers] - -* Add parsing/setting of any currently set opacity CSS rule to default opacity effect on draggables, fixes #3682 [thx Mike A. Owens] - -* Added prototype $() performance patch from #4477 and updated effects.js to new Element.addMethods() syntax - -* Sortable trees [thx Sammi Williams, sammi@oriontransfer.co.nz] - - Added functional test (test/functional/sortable_tree_test.html) - - removed greedy option - - modified the way Droppables.show works - added affected list - - added Droppables.findDeepestChild - - modified Sortable.options to work for trees - - modified Sortable.onEmptyHover with additional logic to insert - the element at a certain place according to the overlap - - modified Sortable.onHover to avoid DOM Exceptions - - modified Sortable.create to support the creation of Sortable trees - - added two convenience functions - Sortable.findElements and - Sortable.findTreeElements - - Added Sortable.tree (and a number of private functions to facilitate it) - Returns a tree structure: - var root = { - id: null, - parent: null, - children:/gi, "");
- },
- createEditField: function() {
- var text;
- if(this.options.loadTextURL) {
- text = this.options.loadingText;
- } else {
- text = this.getText();
- }
-
- var obj = this;
-
- if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
- this.options.textarea = false;
- var textField = document.createElement("input");
- textField.obj = this;
- textField.type = "text";
- textField.name = this.options.paramName;
- textField.value = text;
- textField.style.backgroundColor = this.options.highlightcolor;
- textField.className = 'editor_field';
- var size = this.options.size || this.options.cols || 0;
- if (size != 0) textField.size = size;
- if (this.options.submitOnBlur)
- textField.onblur = this.onSubmit.bind(this);
- this.editField = textField;
- } else {
- this.options.textarea = true;
- var textArea = document.createElement("textarea");
- textArea.obj = this;
- textArea.name = this.options.paramName;
- textArea.value = this.convertHTMLLineBreaks(text);
- textArea.rows = this.options.rows;
- textArea.cols = this.options.cols || 40;
- textArea.className = 'editor_field';
- if (this.options.submitOnBlur)
- textArea.onblur = this.onSubmit.bind(this);
- this.editField = textArea;
- }
-
- if(this.options.loadTextURL) {
- this.loadExternalText();
- }
- this.form.appendChild(this.editField);
- },
- getText: function() {
- return this.element.innerHTML;
- },
- loadExternalText: function() {
- Element.addClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = true;
- new Ajax.Request(
- this.options.loadTextURL,
- Object.extend({
- asynchronous: true,
- onComplete: this.onLoadedExternalText.bind(this)
- }, this.options.ajaxOptions)
- );
- },
- onLoadedExternalText: function(transport) {
- Element.removeClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = false;
- this.editField.value = transport.responseText.stripTags();
- Field.scrollFreeActivate(this.editField);
- },
- onclickCancel: function() {
- this.onComplete();
- this.leaveEditMode();
- return false;
- },
- onFailure: function(transport) {
- this.options.onFailure(transport);
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- this.oldInnerHTML = null;
- }
- return false;
- },
- onSubmit: function() {
- // onLoading resets these so we need to save them away for the Ajax call
- var form = this.form;
- var value = this.editField.value;
-
- // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
- // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
- // to be displayed indefinitely
- this.onLoading();
-
- if (this.options.evalScripts) {
- new Ajax.Request(
- this.url, Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this),
- asynchronous:true,
- evalScripts:true
- }, this.options.ajaxOptions));
- } else {
- new Ajax.Updater(
- { success: this.element,
- // don't update on failure (this could be an option)
- failure: null },
- this.url, Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this)
- }, this.options.ajaxOptions));
- }
- // stop the event to avoid a page refresh in Safari
- if (arguments.length > 1) {
- Event.stop(arguments[0]);
- }
- return false;
- },
- onLoading: function() {
- this.saving = true;
- this.removeForm();
- this.leaveHover();
- this.showSaving();
- },
- showSaving: function() {
- this.oldInnerHTML = this.element.innerHTML;
- this.element.innerHTML = this.options.savingText;
- Element.addClassName(this.element, this.options.savingClassName);
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
- },
- removeForm: function() {
- if(this.form) {
- if (this.form.parentNode) Element.remove(this.form);
- this.form = null;
- }
- },
- enterHover: function() {
- if (this.saving) return;
- this.element.style.backgroundColor = this.options.highlightcolor;
- if (this.effect) {
- this.effect.cancel();
- }
- Element.addClassName(this.element, this.options.hoverClassName)
- },
- leaveHover: function() {
- if (this.options.backgroundColor) {
- this.element.style.backgroundColor = this.oldBackground;
- }
- Element.removeClassName(this.element, this.options.hoverClassName)
- if (this.saving) return;
- this.effect = new Effect.Highlight(this.element, {
- startcolor: this.options.highlightcolor,
- endcolor: this.options.highlightendcolor,
- restorecolor: this.originalBackground
- });
- },
- leaveEditMode: function() {
- Element.removeClassName(this.element, this.options.savingClassName);
- this.removeForm();
- this.leaveHover();
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
- if (this.options.externalControl) {
- Element.show(this.options.externalControl);
- }
- this.editing = false;
- this.saving = false;
- this.oldInnerHTML = null;
- this.onLeaveEditMode();
- },
- onComplete: function(transport) {
- this.leaveEditMode();
- this.options.onComplete.bind(this)(transport, this.element);
- },
- onEnterEditMode: function() {},
- onLeaveEditMode: function() {},
- dispose: function() {
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- }
- this.leaveEditMode();
- Event.stopObserving(this.element, 'click', this.onclickListener);
- Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
- if (this.options.externalControl) {
- Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
- Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
- }
- }
-};
-
-Ajax.InPlaceCollectionEditor = Class.create();
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
- createEditField: function() {
- if (!this.cached_selectTag) {
- var selectTag = document.createElement("select");
- var collection = this.options.collection || [];
- var optionTag;
- collection.each(function(e,i) {
- optionTag = document.createElement("option");
- optionTag.value = (e instanceof Array) ? e[0] : e;
- if((typeof this.options.value == 'undefined') &&
- ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
- if(this.options.value==optionTag.value) optionTag.selected = true;
- optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
- selectTag.appendChild(optionTag);
- }.bind(this));
- this.cached_selectTag = selectTag;
- }
-
- this.editField = this.cached_selectTag;
- if(this.options.loadTextURL) this.loadExternalText();
- this.form.appendChild(this.editField);
- this.options.callback = function(form, value) {
- return "value=" + encodeURIComponent(value);
- }
- }
-});
-
-// Delayed observer, like Form.Element.Observer,
-// but waits for delay after last key input
-// Ideal for live-search fields
-
-Form.Element.DelayedObserver = Class.create();
-Form.Element.DelayedObserver.prototype = {
- initialize: function(element, delay, callback) {
- this.delay = delay || 0.5;
- this.element = $(element);
- this.callback = callback;
- this.timer = null;
- this.lastValue = $F(this.element);
- Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
- },
- delayedListener: function(event) {
- if(this.lastValue == $F(this.element)) return;
- if(this.timer) clearTimeout(this.timer);
- this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
- this.lastValue = $F(this.element);
- },
- onTimerEvent: function() {
- this.timer = null;
- this.callback(this.element, $F(this.element));
- }
-};
diff --git a/framework/Web/Javascripts/effects/dragdrop.js b/framework/Web/Javascripts/effects/dragdrop.js
deleted file mode 100644
index 32c91bc3..00000000
--- a/framework/Web/Javascripts/effects/dragdrop.js
+++ /dev/null
@@ -1,944 +0,0 @@
-// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-if(typeof Effect == 'undefined')
- throw("dragdrop.js requires including script.aculo.us' effects.js library");
-
-var Droppables = {
- drops: [],
-
- remove: function(element) {
- this.drops = this.drops.reject(function(d) { return d.element==$(element) });
- },
-
- add: function(element) {
- element = $(element);
- var options = Object.extend({
- greedy: true,
- hoverclass: null,
- tree: false
- }, arguments[1] || {});
-
- // cache containers
- if(options.containment) {
- options._containers = [];
- var containment = options.containment;
- if((typeof containment == 'object') &&
- (containment.constructor == Array)) {
- containment.each( function(c) { options._containers.push($(c)) });
- } else {
- options._containers.push($(containment));
- }
- }
-
- if(options.accept) options.accept = [options.accept].flatten();
-
- Element.makePositioned(element); // fix IE
- options.element = element;
-
- this.drops.push(options);
- },
-
- findDeepestChild: function(drops) {
- deepest = drops[0];
-
- for (i = 1; i < drops.length; ++i)
- if (Element.isParent(drops[i].element, deepest.element))
- deepest = drops[i];
-
- return deepest;
- },
-
- isContained: function(element, drop) {
- var containmentNode;
- if(drop.tree) {
- containmentNode = element.treeNode;
- } else {
- containmentNode = element.parentNode;
- }
- return drop._containers.detect(function(c) { return containmentNode == c });
- },
-
- isAffected: function(point, element, drop) {
- return (
- (drop.element!=element) &&
- ((!drop._containers) ||
- this.isContained(element, drop)) &&
- ((!drop.accept) ||
- (Element.classNames(element).detect(
- function(v) { return drop.accept.include(v) } ) )) &&
- Position.within(drop.element, point[0], point[1]) );
- },
-
- deactivate: function(drop) {
- if(drop.hoverclass)
- Element.removeClassName(drop.element, drop.hoverclass);
- this.last_active = null;
- },
-
- activate: function(drop) {
- if(drop.hoverclass)
- Element.addClassName(drop.element, drop.hoverclass);
- this.last_active = drop;
- },
-
- show: function(point, element) {
- if(!this.drops.length) return;
- var affected = [];
-
- if(this.last_active) this.deactivate(this.last_active);
- this.drops.each( function(drop) {
- if(Droppables.isAffected(point, element, drop))
- affected.push(drop);
- });
-
- if(affected.length>0) {
- drop = Droppables.findDeepestChild(affected);
- Position.within(drop.element, point[0], point[1]);
- if(drop.onHover)
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
-
- Droppables.activate(drop);
- }
- },
-
- fire: function(event, element) {
- if(!this.last_active) return;
- Position.prepare();
-
- if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
- if (this.last_active.onDrop)
- this.last_active.onDrop(element, this.last_active.element, event);
- },
-
- reset: function() {
- if(this.last_active)
- this.deactivate(this.last_active);
- }
-}
-
-var Draggables = {
- drags: [],
- observers: [],
-
- register: function(draggable) {
- if(this.drags.length == 0) {
- this.eventMouseUp = this.endDrag.bindAsEventListener(this);
- this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
- this.eventKeypress = this.keyPress.bindAsEventListener(this);
-
- Event.observe(document, "mouseup", this.eventMouseUp);
- Event.observe(document, "mousemove", this.eventMouseMove);
- Event.observe(document, "keypress", this.eventKeypress);
- }
- this.drags.push(draggable);
- },
-
- unregister: function(draggable) {
- this.drags = this.drags.reject(function(d) { return d==draggable });
- if(this.drags.length == 0) {
- Event.stopObserving(document, "mouseup", this.eventMouseUp);
- Event.stopObserving(document, "mousemove", this.eventMouseMove);
- Event.stopObserving(document, "keypress", this.eventKeypress);
- }
- },
-
- activate: function(draggable) {
- if(draggable.options.delay) {
- this._timeout = setTimeout(function() {
- Draggables._timeout = null;
- window.focus();
- Draggables.activeDraggable = draggable;
- }.bind(this), draggable.options.delay);
- } else {
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
- this.activeDraggable = draggable;
- }
- },
-
- deactivate: function() {
- this.activeDraggable = null;
- },
-
- updateDrag: function(event) {
- if(!this.activeDraggable) return;
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- // Mozilla-based browsers fire successive mousemove events with
- // the same coordinates, prevent needless redrawing (moz bug?)
- if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
- this._lastPointer = pointer;
-
- this.activeDraggable.updateDrag(event, pointer);
- },
-
- endDrag: function(event) {
- if(this._timeout) {
- clearTimeout(this._timeout);
- this._timeout = null;
- }
- if(!this.activeDraggable) return;
- this._lastPointer = null;
- this.activeDraggable.endDrag(event);
- this.activeDraggable = null;
- },
-
- keyPress: function(event) {
- if(this.activeDraggable)
- this.activeDraggable.keyPress(event);
- },
-
- addObserver: function(observer) {
- this.observers.push(observer);
- this._cacheObserverCallbacks();
- },
-
- removeObserver: function(element) { // element instead of observer fixes mem leaks
- this.observers = this.observers.reject( function(o) { return o.element==element });
- this._cacheObserverCallbacks();
- },
-
- notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
- if(this[eventName+'Count'] > 0)
- this.observers.each( function(o) {
- if(o[eventName]) o[eventName](eventName, draggable, event);
- });
- if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
- },
-
- _cacheObserverCallbacks: function() {
- ['onStart','onEnd','onDrag'].each( function(eventName) {
- Draggables[eventName+'Count'] = Draggables.observers.select(
- function(o) { return o[eventName]; }
- ).length;
- });
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Draggable = Class.create();
-Draggable._dragging = {};
-
-Draggable.prototype = {
- initialize: function(element) {
- var defaults = {
- handle: false,
- reverteffect: function(element, top_offset, left_offset) {
- var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
- new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
- queue: {scope:'_draggable', position:'end'}
- });
- },
- endeffect: function(element) {
- var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
- queue: {scope:'_draggable', position:'end'},
- afterFinish: function(){
- Draggable._dragging[element] = false
- }
- });
- },
- zindex: 1000,
- revert: false,
- scroll: false,
- scrollSensitivity: 20,
- scrollSpeed: 15,
- snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
- delay: 0
- };
-
- if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
- Object.extend(defaults, {
- starteffect: function(element) {
- element._opacity = Element.getOpacity(element);
- Draggable._dragging[element] = true;
- new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
- }
- });
-
- var options = Object.extend(defaults, arguments[1] || {});
-
- this.element = $(element);
-
- if(options.handle && (typeof options.handle == 'string'))
- this.handle = this.element.down('.'+options.handle, 0);
-
- if(!this.handle) this.handle = $(options.handle);
- if(!this.handle) this.handle = this.element;
-
- if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
- options.scroll = $(options.scroll);
- this._isScrollChild = Element.childOf(this.element, options.scroll);
- }
-
- Element.makePositioned(this.element); // fix IE
-
- this.delta = this.currentDelta();
- this.options = options;
- this.dragging = false;
-
- this.eventMouseDown = this.initDrag.bindAsEventListener(this);
- Event.observe(this.handle, "mousedown", this.eventMouseDown);
-
- Draggables.register(this);
- },
-
- destroy: function() {
- Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
- Draggables.unregister(this);
- },
-
- currentDelta: function() {
- return([
- parseInt(Element.getStyle(this.element,'left') || '0'),
- parseInt(Element.getStyle(this.element,'top') || '0')]);
- },
-
- initDrag: function(event) {
- if(typeof Draggable._dragging[this.element] != 'undefined' &&
- Draggable._dragging[this.element]) return;
- if(Event.isLeftClick(event)) {
- // abort on form elements, fixes a Firefox issue
- var src = Event.element(event);
- if((tag_name = src.tagName.toUpperCase()) && (
- tag_name=='INPUT' ||
- tag_name=='SELECT' ||
- tag_name=='OPTION' ||
- tag_name=='BUTTON' ||
- tag_name=='TEXTAREA')) return;
-
- var pointer = [Event.pointerX(event), Event.pointerY(event)];
- var pos = Position.cumulativeOffset(this.element);
- this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
-
- Draggables.activate(this);
- Event.stop(event);
- }
- },
-
- startDrag: function(event) {
- this.dragging = true;
-
- if(this.options.zindex) {
- this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
- this.element.style.zIndex = this.options.zindex;
- }
-
- if(this.options.ghosting) {
- this._clone = this.element.cloneNode(true);
- Position.absolutize(this.element);
- this.element.parentNode.insertBefore(this._clone, this.element);
- }
-
- if(this.options.scroll) {
- if (this.options.scroll == window) {
- var where = this._getWindowScroll(this.options.scroll);
- this.originalScrollLeft = where.left;
- this.originalScrollTop = where.top;
- } else {
- this.originalScrollLeft = this.options.scroll.scrollLeft;
- this.originalScrollTop = this.options.scroll.scrollTop;
- }
- }
-
- Draggables.notify('onStart', this, event);
-
- if(this.options.starteffect) this.options.starteffect(this.element);
- },
-
- updateDrag: function(event, pointer) {
- if(!this.dragging) this.startDrag(event);
- Position.prepare();
- Droppables.show(pointer, this.element);
- Draggables.notify('onDrag', this, event);
-
- this.draw(pointer);
- if(this.options.change) this.options.change(this);
-
- if(this.options.scroll) {
- this.stopScrolling();
-
- var p;
- if (this.options.scroll == window) {
- with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
- } else {
- p = Position.page(this.options.scroll);
- p[0] += this.options.scroll.scrollLeft + Position.deltaX;
- p[1] += this.options.scroll.scrollTop + Position.deltaY;
- p.push(p[0]+this.options.scroll.offsetWidth);
- p.push(p[1]+this.options.scroll.offsetHeight);
- }
- var speed = [0,0];
- if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
- if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
- if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
- if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
- this.startScrolling(speed);
- }
-
- // fix AppleWebKit rendering
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-
- Event.stop(event);
- },
-
- finishDrag: function(event, success) {
- this.dragging = false;
-
- if(this.options.ghosting) {
- Position.relativize(this.element);
- Element.remove(this._clone);
- this._clone = null;
- }
-
- if(success) Droppables.fire(event, this.element);
- Draggables.notify('onEnd', this, event);
-
- var revert = this.options.revert;
- if(revert && typeof revert == 'function') revert = revert(this.element);
-
- var d = this.currentDelta();
- if(revert && this.options.reverteffect) {
- this.options.reverteffect(this.element,
- d[1]-this.delta[1], d[0]-this.delta[0]);
- } else {
- this.delta = d;
- }
-
- if(this.options.zindex)
- this.element.style.zIndex = this.originalZ;
-
- if(this.options.endeffect)
- this.options.endeffect(this.element);
-
- Draggables.deactivate(this);
- Droppables.reset();
- },
-
- keyPress: function(event) {
- if(event.keyCode!=Event.KEY_ESC) return;
- this.finishDrag(event, false);
- Event.stop(event);
- },
-
- endDrag: function(event) {
- if(!this.dragging) return;
- this.stopScrolling();
- this.finishDrag(event, true);
- Event.stop(event);
- },
-
- draw: function(point) {
- var pos = Position.cumulativeOffset(this.element);
- if(this.options.ghosting) {
- var r = Position.realOffset(this.element);
- pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
- }
-
- var d = this.currentDelta();
- pos[0] -= d[0]; pos[1] -= d[1];
-
- if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
- pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
- pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
- }
-
- var p = [0,1].map(function(i){
- return (point[i]-pos[i]-this.offset[i])
- }.bind(this));
-
- if(this.options.snap) {
- if(typeof this.options.snap == 'function') {
- p = this.options.snap(p[0],p[1],this);
- } else {
- if(this.options.snap instanceof Array) {
- p = p.map( function(v, i) {
- return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
- } else {
- p = p.map( function(v) {
- return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
- }
- }}
-
- var style = this.element.style;
- if((!this.options.constraint) || (this.options.constraint=='horizontal'))
- style.left = p[0] + "px";
- if((!this.options.constraint) || (this.options.constraint=='vertical'))
- style.top = p[1] + "px";
-
- if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
- },
-
- stopScrolling: function() {
- if(this.scrollInterval) {
- clearInterval(this.scrollInterval);
- this.scrollInterval = null;
- Draggables._lastScrollPointer = null;
- }
- },
-
- startScrolling: function(speed) {
- if(!(speed[0] || speed[1])) return;
- this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
- this.lastScrolled = new Date();
- this.scrollInterval = setInterval(this.scroll.bind(this), 10);
- },
-
- scroll: function() {
- var current = new Date();
- var delta = current - this.lastScrolled;
- this.lastScrolled = current;
- if(this.options.scroll == window) {
- with (this._getWindowScroll(this.options.scroll)) {
- if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
- var d = delta / 1000;
- this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
- }
- }
- } else {
- this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
- this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
- }
-
- Position.prepare();
- Droppables.show(Draggables._lastPointer, this.element);
- Draggables.notify('onDrag', this);
- if (this._isScrollChild) {
- Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
- Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
- Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
- if (Draggables._lastScrollPointer[0] < 0)
- Draggables._lastScrollPointer[0] = 0;
- if (Draggables._lastScrollPointer[1] < 0)
- Draggables._lastScrollPointer[1] = 0;
- this.draw(Draggables._lastScrollPointer);
- }
-
- if(this.options.change) this.options.change(this);
- },
-
- _getWindowScroll: function(w) {
- var T, L, W, H;
- with (w.document) {
- if (w.document.documentElement && documentElement.scrollTop) {
- T = documentElement.scrollTop;
- L = documentElement.scrollLeft;
- } else if (w.document.body) {
- T = body.scrollTop;
- L = body.scrollLeft;
- }
- if (w.innerWidth) {
- W = w.innerWidth;
- H = w.innerHeight;
- } else if (w.document.documentElement && documentElement.clientWidth) {
- W = documentElement.clientWidth;
- H = documentElement.clientHeight;
- } else {
- W = body.offsetWidth;
- H = body.offsetHeight
- }
- }
- return { top: T, left: L, width: W, height: H };
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var SortableObserver = Class.create();
-SortableObserver.prototype = {
- initialize: function(element, observer) {
- this.element = $(element);
- this.observer = observer;
- this.lastValue = Sortable.serialize(this.element);
- },
-
- onStart: function() {
- this.lastValue = Sortable.serialize(this.element);
- },
-
- onEnd: function() {
- Sortable.unmark();
- if(this.lastValue != Sortable.serialize(this.element))
- this.observer(this.element)
- }
-}
-
-var Sortable = {
- SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
-
- sortables: {},
-
- _findRootElement: function(element) {
- while (element.tagName.toUpperCase() != "BODY") {
- if(element.id && Sortable.sortables[element.id]) return element;
- element = element.parentNode;
- }
- },
-
- options: function(element) {
- element = Sortable._findRootElement($(element));
- if(!element) return;
- return Sortable.sortables[element.id];
- },
-
- destroy: function(element){
- var s = Sortable.options(element);
-
- if(s) {
- Draggables.removeObserver(s.element);
- s.droppables.each(function(d){ Droppables.remove(d) });
- s.draggables.invoke('destroy');
-
- delete Sortable.sortables[s.element.id];
- }
- },
-
- create: function(element) {
- element = $(element);
- var options = Object.extend({
- element: element,
- tag: 'li', // assumes li children, override with tag: 'tagname'
- dropOnEmpty: false,
- tree: false,
- treeTag: 'ul',
- overlap: 'vertical', // one of 'vertical', 'horizontal'
- constraint: 'vertical', // one of 'vertical', 'horizontal', false
- containment: element, // also takes array of elements (or id's); or false
- handle: false, // or a CSS class
- only: false,
- delay: 0,
- hoverclass: null,
- ghosting: false,
- scroll: false,
- scrollSensitivity: 20,
- scrollSpeed: 15,
- format: this.SERIALIZE_RULE,
- onChange: Prototype.emptyFunction,
- onUpdate: Prototype.emptyFunction
- }, arguments[1] || {});
-
- // clear any old sortable with same element
- this.destroy(element);
-
- // build options for the draggables
- var options_for_draggable = {
- revert: true,
- scroll: options.scroll,
- scrollSpeed: options.scrollSpeed,
- scrollSensitivity: options.scrollSensitivity,
- delay: options.delay,
- ghosting: options.ghosting,
- constraint: options.constraint,
- handle: options.handle };
-
- if(options.starteffect)
- options_for_draggable.starteffect = options.starteffect;
-
- if(options.reverteffect)
- options_for_draggable.reverteffect = options.reverteffect;
- else
- if(options.ghosting) options_for_draggable.reverteffect = function(element) {
- element.style.top = 0;
- element.style.left = 0;
- };
-
- if(options.endeffect)
- options_for_draggable.endeffect = options.endeffect;
-
- if(options.zindex)
- options_for_draggable.zindex = options.zindex;
-
- // build options for the droppables
- var options_for_droppable = {
- overlap: options.overlap,
- containment: options.containment,
- tree: options.tree,
- hoverclass: options.hoverclass,
- onHover: Sortable.onHover
- }
-
- var options_for_tree = {
- onHover: Sortable.onEmptyHover,
- overlap: options.overlap,
- containment: options.containment,
- hoverclass: options.hoverclass
- }
-
- // fix for gecko engine
- Element.cleanWhitespace(element);
-
- options.draggables = [];
- options.droppables = [];
-
- // drop on empty handling
- if(options.dropOnEmpty || options.tree) {
- Droppables.add(element, options_for_tree);
- options.droppables.push(element);
- }
-
- (this.findElements(element, options) || []).each( function(e) {
- // handles are per-draggable
- var handle = options.handle ?
- $(e).down('.'+options.handle,0) : e;
- options.draggables.push(
- new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
- Droppables.add(e, options_for_droppable);
- if(options.tree) e.treeNode = element;
- options.droppables.push(e);
- });
-
- if(options.tree) {
- (Sortable.findTreeElements(element, options) || []).each( function(e) {
- Droppables.add(e, options_for_tree);
- e.treeNode = element;
- options.droppables.push(e);
- });
- }
-
- // keep reference
- this.sortables[element.id] = options;
-
- // for onupdate
- Draggables.addObserver(new SortableObserver(element, options.onUpdate));
-
- },
-
- // return all suitable-for-sortable elements in a guaranteed order
- findElements: function(element, options) {
- return Element.findChildren(
- element, options.only, options.tree ? true : false, options.tag);
- },
-
- findTreeElements: function(element, options) {
- return Element.findChildren(
- element, options.only, options.tree ? true : false, options.treeTag);
- },
-
- onHover: function(element, dropon, overlap) {
- if(Element.isParent(dropon, element)) return;
-
- if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
- return;
- } else if(overlap>0.5) {
- Sortable.mark(dropon, 'before');
- if(dropon.previousSibling != element) {
- var oldParentNode = element.parentNode;
- element.style.visibility = "hidden"; // fix gecko rendering
- dropon.parentNode.insertBefore(element, dropon);
- if(dropon.parentNode!=oldParentNode)
- Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon.parentNode).onChange(element);
- }
- } else {
- Sortable.mark(dropon, 'after');
- var nextElement = dropon.nextSibling || null;
- if(nextElement != element) {
- var oldParentNode = element.parentNode;
- element.style.visibility = "hidden"; // fix gecko rendering
- dropon.parentNode.insertBefore(element, nextElement);
- if(dropon.parentNode!=oldParentNode)
- Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon.parentNode).onChange(element);
- }
- }
- },
-
- onEmptyHover: function(element, dropon, overlap) {
- var oldParentNode = element.parentNode;
- var droponOptions = Sortable.options(dropon);
-
- if(!Element.isParent(dropon, element)) {
- var index;
-
- var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
- var child = null;
-
- if(children) {
- var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
-
- for (index = 0; index < children.length; index += 1) {
- if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
- offset -= Element.offsetSize (children[index], droponOptions.overlap);
- } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
- child = index + 1 < children.length ? children[index + 1] : null;
- break;
- } else {
- child = children[index];
- break;
- }
- }
- }
-
- dropon.insertBefore(element, child);
-
- Sortable.options(oldParentNode).onChange(element);
- droponOptions.onChange(element);
- }
- },
-
- unmark: function() {
- if(Sortable._marker) Sortable._marker.hide();
- },
-
- mark: function(dropon, position) {
- // mark on ghosting only
- var sortable = Sortable.options(dropon.parentNode);
- if(sortable && !sortable.ghosting) return;
-
- if(!Sortable._marker) {
- Sortable._marker =
- ($('dropmarker') || Element.extend(document.createElement('DIV'))).
- hide().addClassName('dropmarker').setStyle({position:'absolute'});
- document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
- }
- var offsets = Position.cumulativeOffset(dropon);
- Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
-
- if(position=='after')
- if(sortable.overlap == 'horizontal')
- Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
- else
- Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
-
- Sortable._marker.show();
- },
-
- _tree: function(element, options, parent) {
- var children = Sortable.findElements(element, options) || [];
-
- for (var i = 0; i < children.length; ++i) {
- var match = children[i].id.match(options.format);
-
- if (!match) continue;
-
- var child = {
- id: encodeURIComponent(match ? match[1] : null),
- element: element,
- parent: parent,
- children: [],
- position: parent.children.length,
- container: $(children[i]).down(options.treeTag)
- }
-
- /* Get the element containing the children and recurse over it */
- if (child.container)
- this._tree(child.container, options, child)
-
- parent.children.push (child);
- }
-
- return parent;
- },
-
- tree: function(element) {
- element = $(element);
- var sortableOptions = this.options(element);
- var options = Object.extend({
- tag: sortableOptions.tag,
- treeTag: sortableOptions.treeTag,
- only: sortableOptions.only,
- name: element.id,
- format: sortableOptions.format
- }, arguments[1] || {});
-
- var root = {
- id: null,
- parent: null,
- children: [],
- container: element,
- position: 0
- }
-
- return Sortable._tree(element, options, root);
- },
-
- /* Construct a [i] index for a particular node */
- _constructIndex: function(node) {
- var index = '';
- do {
- if (node.id) index = '[' + node.position + ']' + index;
- } while ((node = node.parent) != null);
- return index;
- },
-
- sequence: function(element) {
- element = $(element);
- var options = Object.extend(this.options(element), arguments[1] || {});
-
- return $(this.findElements(element, options) || []).map( function(item) {
- return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
- });
- },
-
- setSequence: function(element, new_sequence) {
- element = $(element);
- var options = Object.extend(this.options(element), arguments[2] || {});
-
- var nodeMap = {};
- this.findElements(element, options).each( function(n) {
- if (n.id.match(options.format))
- nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
- n.parentNode.removeChild(n);
- });
-
- new_sequence.each(function(ident) {
- var n = nodeMap[ident];
- if (n) {
- n[1].appendChild(n[0]);
- delete nodeMap[ident];
- }
- });
- },
-
- serialize: function(element) {
- element = $(element);
- var options = Object.extend(Sortable.options(element), arguments[1] || {});
- var name = encodeURIComponent(
- (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
-
- if (options.tree) {
- return Sortable.tree(element, arguments[1]).children.map( function (item) {
- return [name + Sortable._constructIndex(item) + "[id]=" +
- encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
- }).flatten().join('&');
- } else {
- return Sortable.sequence(element, arguments[1]).map( function(item) {
- return name + "[]=" + encodeURIComponent(item);
- }).join('&');
- }
- }
-}
-
-// Returns true if child is contained within element
-Element.isParent = function(child, element) {
- if (!child.parentNode || child == element) return false;
- if (child.parentNode == element) return true;
- return Element.isParent(child.parentNode, element);
-}
-
-Element.findChildren = function(element, only, recursive, tagName) {
- if(!element.hasChildNodes()) return null;
- tagName = tagName.toUpperCase();
- if(only) only = [only].flatten();
- var elements = [];
- $A(element.childNodes).each( function(e) {
- if(e.tagName && e.tagName.toUpperCase()==tagName &&
- (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
- elements.push(e);
- if(recursive) {
- var grandchildren = Element.findChildren(e, only, recursive, tagName);
- if(grandchildren) elements.push(grandchildren);
- }
- });
-
- return (elements.length>0 ? elements.flatten() : []);
-}
-
-Element.offsetSize = function (element, type) {
- return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
-}
diff --git a/framework/Web/Javascripts/effects/effects.js b/framework/Web/Javascripts/effects/effects.js
deleted file mode 100644
index 06f59b47..00000000
--- a/framework/Web/Javascripts/effects/effects.js
+++ /dev/null
@@ -1,1090 +0,0 @@
-// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// Contributors:
-// Justin Palmer (http://encytemedia.com/)
-// Mark Pilgrim (http://diveintomark.org/)
-// Martin Bialasinki
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-// converts rgb() and #xxx to #xxxxxx format,
-// returns self (or first argument) if not convertable
-String.prototype.parseColor = function() {
- var color = '#';
- if(this.slice(0,4) == 'rgb(') {
- var cols = this.slice(4,this.length-1).split(',');
- var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
- } else {
- if(this.slice(0,1) == '#') {
- if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
- if(this.length==7) color = this.toLowerCase();
- }
- }
- return(color.length==7 ? color : (arguments[0] || this));
-}
-
-/*--------------------------------------------------------------------------*/
-
-Element.collectTextNodes = function(element) {
- return $A($(element).childNodes).collect( function(node) {
- return (node.nodeType==3 ? node.nodeValue :
- (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
- }).flatten().join('');
-}
-
-Element.collectTextNodesIgnoreClass = function(element, className) {
- return $A($(element).childNodes).collect( function(node) {
- return (node.nodeType==3 ? node.nodeValue :
- ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
- Element.collectTextNodesIgnoreClass(node, className) : ''));
- }).flatten().join('');
-}
-
-Element.setContentZoom = function(element, percent) {
- element = $(element);
- element.setStyle({fontSize: (percent/100) + 'em'});
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
- return element;
-}
-
-Element.getOpacity = function(element){
- return $(element).getStyle('opacity');
-}
-
-Element.setOpacity = function(element, value){
- return $(element).setStyle({opacity:value});
-}
-
-Element.getInlineOpacity = function(element){
- return $(element).style.opacity || '';
-}
-
-Element.forceRerendering = function(element) {
- try {
- element = $(element);
- var n = document.createTextNode(' ');
- element.appendChild(n);
- element.removeChild(n);
- } catch(e) { }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Array.prototype.call = function() {
- var args = arguments;
- this.each(function(f){ f.apply(this, args) });
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Effect = {
- _elementDoesNotExistError: {
- name: 'ElementDoesNotExistError',
- message: 'The specified DOM element does not exist, but is required for this effect to operate'
- },
- tagifyText: function(element) {
- if(typeof Builder == 'undefined')
- throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
-
- var tagifyStyle = 'position:relative';
- if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
-
- element = $(element);
- $A(element.childNodes).each( function(child) {
- if(child.nodeType==3) {
- child.nodeValue.toArray().each( function(character) {
- element.insertBefore(
- Builder.node('span',{style: tagifyStyle},
- character == ' ' ? String.fromCharCode(160) : character),
- child);
- });
- Element.remove(child);
- }
- });
- },
- multiple: function(element, effect) {
- var elements;
- if(((typeof element == 'object') ||
- (typeof element == 'function')) &&
- (element.length))
- elements = element;
- else
- elements = $(element).childNodes;
-
- var options = Object.extend({
- speed: 0.1,
- delay: 0.0
- }, arguments[2] || {});
- var masterDelay = options.delay;
-
- $A(elements).each( function(element, index) {
- new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
- });
- },
- PAIRS: {
- 'slide': ['SlideDown','SlideUp'],
- 'blind': ['BlindDown','BlindUp'],
- 'appear': ['Appear','Fade']
- },
- toggle: function(element, effect) {
- element = $(element);
- effect = (effect || 'appear').toLowerCase();
- var options = Object.extend({
- queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
- }, arguments[2] || {});
- Effect[element.visible() ?
- Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
- }
-};
-
-var Effect2 = Effect; // deprecated
-
-/* ------------- transitions ------------- */
-
-Effect.Transitions = {
- linear: Prototype.K,
- sinoidal: function(pos) {
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
- },
- reverse: function(pos) {
- return 1-pos;
- },
- flicker: function(pos) {
- return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
- },
- wobble: function(pos) {
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
- },
- pulse: function(pos, pulses) {
- pulses = pulses || 5;
- return (
- Math.round((pos % (1/pulses)) * pulses) == 0 ?
- ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
- 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
- );
- },
- none: function(pos) {
- return 0;
- },
- full: function(pos) {
- return 1;
- }
-};
-
-/* ------------- core effects ------------- */
-
-Effect.ScopedQueue = Class.create();
-Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
- initialize: function() {
- this.effects = [];
- this.interval = null;
- },
- _each: function(iterator) {
- this.effects._each(iterator);
- },
- add: function(effect) {
- var timestamp = new Date().getTime();
-
- var position = (typeof effect.options.queue == 'string') ?
- effect.options.queue : effect.options.queue.position;
-
- switch(position) {
- case 'front':
- // move unstarted effects after this effect
- this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
- e.startOn += effect.finishOn;
- e.finishOn += effect.finishOn;
- });
- break;
- case 'with-last':
- timestamp = this.effects.pluck('startOn').max() || timestamp;
- break;
- case 'end':
- // start effect after last queued effect has finished
- timestamp = this.effects.pluck('finishOn').max() || timestamp;
- break;
- }
-
- effect.startOn += timestamp;
- effect.finishOn += timestamp;
-
- if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
- this.effects.push(effect);
-
- if(!this.interval)
- this.interval = setInterval(this.loop.bind(this), 15);
- },
- remove: function(effect) {
- this.effects = this.effects.reject(function(e) { return e==effect });
- if(this.effects.length == 0) {
- clearInterval(this.interval);
- this.interval = null;
- }
- },
- loop: function() {
- var timePos = new Date().getTime();
- for(var i=0, len=this.effects.length;i /gi,"");},createEditField:function(){var text;if(this.options.loadTextURL){text=this.options.loadingText;}else{text=this.getText();}
-var obj=this;if(this.options.rows==1&&!this.hasHTMLLineBreaks(text)){this.options.textarea=false;var textField=document.createElement("input");textField.obj=this;textField.type="text";textField.name="value";textField.value=text;textField.style.backgroundColor=this.options.highlightcolor;textField.className='editor_field';var size=this.options.size||this.options.cols||0;if(size!=0)textField.size=size;if(this.options.submitOnBlur)
-textField.onblur=this.onSubmit.bind(this);this.editField=textField;}else{this.options.textarea=true;var textArea=document.createElement("textarea");textArea.obj=this;textArea.name="value";textArea.value=this.convertHTMLLineBreaks(text);textArea.rows=this.options.rows;textArea.cols=this.options.cols||40;textArea.className='editor_field';if(this.options.submitOnBlur)
-textArea.onblur=this.onSubmit.bind(this);this.editField=textArea;}
-if(this.options.loadTextURL){this.loadExternalText();}
-this.form.appendChild(this.editField);},getText:function(){return this.element.innerHTML;},loadExternalText:function(){Element.addClassName(this.form,this.options.loadingClassName);this.editField.disabled=true;new Ajax.Request(this.options.loadTextURL,Object.extend({asynchronous:true,onComplete:this.onLoadedExternalText.bind(this)},this.options.ajaxOptions));},onLoadedExternalText:function(transport){Element.removeClassName(this.form,this.options.loadingClassName);this.editField.disabled=false;this.editField.value=transport.responseText.stripTags();Field.scrollFreeActivate(this.editField);},onclickCancel:function(){this.onComplete();this.leaveEditMode();return false;},onFailure:function(transport){this.options.onFailure(transport);if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;this.oldInnerHTML=null;}
-return false;},onSubmit:function(){var form=this.form;var value=this.editField.value;this.onLoading();if(this.options.evalScripts){new Ajax.Request(this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this),asynchronous:true,evalScripts:true},this.options.ajaxOptions));}else{new Ajax.Updater({success:this.element,failure:null},this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this)},this.options.ajaxOptions));}
-if(arguments.length>1){Event.stop(arguments[0]);}
-return false;},onLoading:function(){this.saving=true;this.removeForm();this.leaveHover();this.showSaving();},showSaving:function(){this.oldInnerHTML=this.element.innerHTML;this.element.innerHTML=this.options.savingText;Element.addClassName(this.element,this.options.savingClassName);this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);},removeForm:function(){if(this.form){if(this.form.parentNode)Element.remove(this.form);this.form=null;}},enterHover:function(){if(this.saving)return;this.element.style.backgroundColor=this.options.highlightcolor;if(this.effect){this.effect.cancel();}
-Element.addClassName(this.element,this.options.hoverClassName)},leaveHover:function(){if(this.options.backgroundColor){this.element.style.backgroundColor=this.oldBackground;}
-Element.removeClassName(this.element,this.options.hoverClassName)
-if(this.saving)return;this.effect=new Effect.Highlight(this.element,{startcolor:this.options.highlightcolor,endcolor:this.options.highlightendcolor,restorecolor:this.originalBackground});},leaveEditMode:function(){Element.removeClassName(this.element,this.options.savingClassName);this.removeForm();this.leaveHover();this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);if(this.options.externalControl){Element.show(this.options.externalControl);}
-this.editing=false;this.saving=false;this.oldInnerHTML=null;this.onLeaveEditMode();},onComplete:function(transport){this.leaveEditMode();this.options.onComplete.bind(this)(transport,this.element);},onEnterEditMode:function(){},onLeaveEditMode:function(){},dispose:function(){if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;}
-this.leaveEditMode();Event.stopObserving(this.element,'click',this.onclickListener);Event.stopObserving(this.element,'mouseover',this.mouseoverListener);Event.stopObserving(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.stopObserving(this.options.externalControl,'click',this.onclickListener);Event.stopObserving(this.options.externalControl,'mouseover',this.mouseoverListener);Event.stopObserving(this.options.externalControl,'mouseout',this.mouseoutListener);}}};Ajax.InPlaceCollectionEditor=Class.create();Object.extend(Ajax.InPlaceCollectionEditor.prototype,Ajax.InPlaceEditor.prototype);Object.extend(Ajax.InPlaceCollectionEditor.prototype,{createEditField:function(){if(!this.cached_selectTag){var selectTag=document.createElement("select");var collection=this.options.collection||[];var optionTag;collection.each(function(e,i){optionTag=document.createElement("option");optionTag.value=(e instanceof Array)?e[0]:e;if(this.options.value==optionTag.value)optionTag.selected=true;optionTag.appendChild(document.createTextNode((e instanceof Array)?e[1]:e));selectTag.appendChild(optionTag);}.bind(this));this.cached_selectTag=selectTag;}
-this.editField=this.cached_selectTag;if(this.options.loadTextURL)this.loadExternalText();this.form.appendChild(this.editField);this.options.callback=function(form,value){return"value="+encodeURIComponent(value);}}});Form.Element.DelayedObserver=Class.create();Form.Element.DelayedObserver.prototype={initialize:function(element,delay,callback){this.delay=delay||0.5;this.element=$(element);this.callback=callback;this.timer=null;this.lastValue=$F(this.element);Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));},delayedListener:function(event){if(this.lastValue==$F(this.element))return;if(this.timer)clearTimeout(this.timer);this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);this.lastValue=$F(this.element);},onTimerEvent:function(){this.timer=null;this.callback(this.element,$F(this.element));}};Prado.WebUI.CallbackControl=Class.extend(Prado.WebUI.PostBackControl,{onPostBack:function(event,options)
-{var request=new Prado.CallbackRequest(options.EventTarget,options);request.dispatch();Event.stop(event);}});Prado.WebUI.TActiveButton=Class.extend(Prado.WebUI.CallbackControl);Prado.WebUI.TActiveLinkButton=Class.extend(Prado.WebUI.CallbackControl);Prado.WebUI.TActiveImageButton=Class.extend(Prado.WebUI.TImageButton,{onPostBack:function(event,options)
-{this.addXYInput(event,options);var request=new Prado.CallbackRequest(options.EventTarget,options);request.dispatch();Event.stop(event);}});Prado.WebUI.TActiveCheckBox=Class.extend(Prado.WebUI.CallbackControl,{onPostBack:function(event,options)
-{var request=new Prado.CallbackRequest(options.EventTarget,options);if(request.dispatch()==false)
-Event.stop(event);}});Prado.WebUI.TActiveRadioButton=Class.extend(Prado.WebUI.TActiveCheckBox);Prado.WebUI.TActiveCheckBoxList=Base.extend({constructor:function(options)
-{for(var i=0;i /gi, "");
- },
- createEditField: function() {
- var text;
- if(this.options.loadTextURL) {
- text = this.options.loadingText;
- } else {
- text = this.getText();
- }
-
- var obj = this;
-
- if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
- this.options.textarea = false;
- var textField = document.createElement("input");
- textField.obj = this;
- textField.type = "text";
- textField.name = "value";
- textField.value = text;
- textField.style.backgroundColor = this.options.highlightcolor;
- textField.className = 'editor_field';
- var size = this.options.size || this.options.cols || 0;
- if (size != 0) textField.size = size;
- if (this.options.submitOnBlur)
- textField.onblur = this.onSubmit.bind(this);
- this.editField = textField;
- } else {
- this.options.textarea = true;
- var textArea = document.createElement("textarea");
- textArea.obj = this;
- textArea.name = "value";
- textArea.value = this.convertHTMLLineBreaks(text);
- textArea.rows = this.options.rows;
- textArea.cols = this.options.cols || 40;
- textArea.className = 'editor_field';
- if (this.options.submitOnBlur)
- textArea.onblur = this.onSubmit.bind(this);
- this.editField = textArea;
- }
-
- if(this.options.loadTextURL) {
- this.loadExternalText();
- }
- this.form.appendChild(this.editField);
- },
- getText: function() {
- return this.element.innerHTML;
- },
- loadExternalText: function() {
- Element.addClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = true;
- new Ajax.Request(
- this.options.loadTextURL,
- Object.extend({
- asynchronous: true,
- onComplete: this.onLoadedExternalText.bind(this)
- }, this.options.ajaxOptions)
- );
- },
- onLoadedExternalText: function(transport) {
- Element.removeClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = false;
- this.editField.value = transport.responseText.stripTags();
- Field.scrollFreeActivate(this.editField);
- },
- onclickCancel: function() {
- this.onComplete();
- this.leaveEditMode();
- return false;
- },
- onFailure: function(transport) {
- this.options.onFailure(transport);
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- this.oldInnerHTML = null;
- }
- return false;
- },
- onSubmit: function() {
- // onLoading resets these so we need to save them away for the Ajax call
- var form = this.form;
- var value = this.editField.value;
-
- // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
- // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
- // to be displayed indefinitely
- this.onLoading();
-
- if (this.options.evalScripts) {
- new Ajax.Request(
- this.url, Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this),
- asynchronous:true,
- evalScripts:true
- }, this.options.ajaxOptions));
- } else {
- new Ajax.Updater(
- { success: this.element,
- // don't update on failure (this could be an option)
- failure: null },
- this.url, Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this)
- }, this.options.ajaxOptions));
- }
- // stop the event to avoid a page refresh in Safari
- if (arguments.length > 1) {
- Event.stop(arguments[0]);
- }
- return false;
- },
- onLoading: function() {
- this.saving = true;
- this.removeForm();
- this.leaveHover();
- this.showSaving();
- },
- showSaving: function() {
- this.oldInnerHTML = this.element.innerHTML;
- this.element.innerHTML = this.options.savingText;
- Element.addClassName(this.element, this.options.savingClassName);
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
- },
- removeForm: function() {
- if(this.form) {
- if (this.form.parentNode) Element.remove(this.form);
- this.form = null;
- }
- },
- enterHover: function() {
- if (this.saving) return;
- this.element.style.backgroundColor = this.options.highlightcolor;
- if (this.effect) {
- this.effect.cancel();
- }
- Element.addClassName(this.element, this.options.hoverClassName)
- },
- leaveHover: function() {
- if (this.options.backgroundColor) {
- this.element.style.backgroundColor = this.oldBackground;
- }
- Element.removeClassName(this.element, this.options.hoverClassName)
- if (this.saving) return;
- this.effect = new Effect.Highlight(this.element, {
- startcolor: this.options.highlightcolor,
- endcolor: this.options.highlightendcolor,
- restorecolor: this.originalBackground
- });
- },
- leaveEditMode: function() {
- Element.removeClassName(this.element, this.options.savingClassName);
- this.removeForm();
- this.leaveHover();
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
- if (this.options.externalControl) {
- Element.show(this.options.externalControl);
- }
- this.editing = false;
- this.saving = false;
- this.oldInnerHTML = null;
- this.onLeaveEditMode();
- },
- onComplete: function(transport) {
- this.leaveEditMode();
- this.options.onComplete.bind(this)(transport, this.element);
- },
- onEnterEditMode: function() {},
- onLeaveEditMode: function() {},
- dispose: function() {
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- }
- this.leaveEditMode();
- Event.stopObserving(this.element, 'click', this.onclickListener);
- Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
- if (this.options.externalControl) {
- Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
- Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
- }
- }
-};
-
-Ajax.InPlaceCollectionEditor = Class.create();
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
- createEditField: function() {
- if (!this.cached_selectTag) {
- var selectTag = document.createElement("select");
- var collection = this.options.collection || [];
- var optionTag;
- collection.each(function(e,i) {
- optionTag = document.createElement("option");
- optionTag.value = (e instanceof Array) ? e[0] : e;
- if(this.options.value==optionTag.value) optionTag.selected = true;
- optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
- selectTag.appendChild(optionTag);
- }.bind(this));
- this.cached_selectTag = selectTag;
- }
-
- this.editField = this.cached_selectTag;
- if(this.options.loadTextURL) this.loadExternalText();
- this.form.appendChild(this.editField);
- this.options.callback = function(form, value) {
- return "value=" + encodeURIComponent(value);
- }
- }
-});
-
-// Delayed observer, like Form.Element.Observer,
-// but waits for delay after last key input
-// Ideal for live-search fields
-
-Form.Element.DelayedObserver = Class.create();
-Form.Element.DelayedObserver.prototype = {
- initialize: function(element, delay, callback) {
- this.delay = delay || 0.5;
- this.element = $(element);
- this.callback = callback;
- this.timer = null;
- this.lastValue = $F(this.element);
- Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
- },
- delayedListener: function(event) {
- if(this.lastValue == $F(this.element)) return;
- if(this.timer) clearTimeout(this.timer);
- this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
- this.lastValue = $F(this.element);
- },
- onTimerEvent: function() {
- this.timer = null;
- this.callback(this.element, $F(this.element));
- }
-};
-
-
-/**
- * Generic postback control.
- */
-Prado.WebUI.CallbackControl = Class.extend(Prado.WebUI.PostBackControl,
-{
- onPostBack : function(event, options)
- {
- var request = new Prado.CallbackRequest(options.EventTarget, options);
- request.dispatch();
- Event.stop(event);
- }
-});
-
-/**
- * TActiveButton control.
- */
-Prado.WebUI.TActiveButton = Class.extend(Prado.WebUI.CallbackControl);
-/**
- * TActiveLinkButton control.
- */
-Prado.WebUI.TActiveLinkButton = Class.extend(Prado.WebUI.CallbackControl);
-
-Prado.WebUI.TActiveImageButton = Class.extend(Prado.WebUI.TImageButton,
-{
- onPostBack : function(event, options)
- {
- this.addXYInput(event,options);
- var request = new Prado.CallbackRequest(options.EventTarget, options);
- request.dispatch();
- Event.stop(event);
- }
-});
-/**
- * Active check box.
- */
-Prado.WebUI.TActiveCheckBox = Class.extend(Prado.WebUI.CallbackControl,
-{
- onPostBack : function(event, options)
- {
- var request = new Prado.CallbackRequest(options.EventTarget, options);
- if(request.dispatch()==false)
- Event.stop(event);
- }
-});
-
-/**
- * TActiveRadioButton control.
- */
-Prado.WebUI.TActiveRadioButton = Class.extend(Prado.WebUI.TActiveCheckBox);
-
-
-Prado.WebUI.TActiveCheckBoxList = Base.extend(
-{
- constructor : function(options)
- {
- for(var i = 0; i /gi, "");
+ },
+ createEditField: function() {
+ var text;
+ if(this.options.loadTextURL) {
+ text = this.options.loadingText;
+ } else {
+ text = this.getText();
+ }
+
+ var obj = this;
+
+ if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
+ this.options.textarea = false;
+ var textField = document.createElement("input");
+ textField.obj = this;
+ textField.type = "text";
+ textField.name = this.options.paramName;
+ textField.value = text;
+ textField.style.backgroundColor = this.options.highlightcolor;
+ textField.className = 'editor_field';
+ var size = this.options.size || this.options.cols || 0;
+ if (size != 0) textField.size = size;
+ if (this.options.submitOnBlur)
+ textField.onblur = this.onSubmit.bind(this);
+ this.editField = textField;
+ } else {
+ this.options.textarea = true;
+ var textArea = document.createElement("textarea");
+ textArea.obj = this;
+ textArea.name = this.options.paramName;
+ textArea.value = this.convertHTMLLineBreaks(text);
+ textArea.rows = this.options.rows;
+ textArea.cols = this.options.cols || 40;
+ textArea.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ textArea.onblur = this.onSubmit.bind(this);
+ this.editField = textArea;
+ }
+
+ if(this.options.loadTextURL) {
+ this.loadExternalText();
+ }
+ this.form.appendChild(this.editField);
+ },
+ getText: function() {
+ return this.element.innerHTML;
+ },
+ loadExternalText: function() {
+ Element.addClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = true;
+ new Ajax.Request(
+ this.options.loadTextURL,
+ Object.extend({
+ asynchronous: true,
+ onComplete: this.onLoadedExternalText.bind(this)
+ }, this.options.ajaxOptions)
+ );
+ },
+ onLoadedExternalText: function(transport) {
+ Element.removeClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = false;
+ this.editField.value = transport.responseText.stripTags();
+ Field.scrollFreeActivate(this.editField);
+ },
+ onclickCancel: function() {
+ this.onComplete();
+ this.leaveEditMode();
+ return false;
+ },
+ onFailure: function(transport) {
+ this.options.onFailure(transport);
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ this.oldInnerHTML = null;
+ }
+ return false;
+ },
+ onSubmit: function() {
+ // onLoading resets these so we need to save them away for the Ajax call
+ var form = this.form;
+ var value = this.editField.value;
+
+ // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
+ // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
+ // to be displayed indefinitely
+ this.onLoading();
+
+ if (this.options.evalScripts) {
+ new Ajax.Request(
+ this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this),
+ asynchronous:true,
+ evalScripts:true
+ }, this.options.ajaxOptions));
+ } else {
+ new Ajax.Updater(
+ { success: this.element,
+ // don't update on failure (this could be an option)
+ failure: null },
+ this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this)
+ }, this.options.ajaxOptions));
+ }
+ // stop the event to avoid a page refresh in Safari
+ if (arguments.length > 1) {
+ Event.stop(arguments[0]);
+ }
+ return false;
+ },
+ onLoading: function() {
+ this.saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ showSaving: function() {
+ this.oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ Element.addClassName(this.element, this.options.savingClassName);
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ },
+ removeForm: function() {
+ if(this.form) {
+ if (this.form.parentNode) Element.remove(this.form);
+ this.form = null;
+ }
+ },
+ enterHover: function() {
+ if (this.saving) return;
+ this.element.style.backgroundColor = this.options.highlightcolor;
+ if (this.effect) {
+ this.effect.cancel();
+ }
+ Element.addClassName(this.element, this.options.hoverClassName)
+ },
+ leaveHover: function() {
+ if (this.options.backgroundColor) {
+ this.element.style.backgroundColor = this.oldBackground;
+ }
+ Element.removeClassName(this.element, this.options.hoverClassName)
+ if (this.saving) return;
+ this.effect = new Effect.Highlight(this.element, {
+ startcolor: this.options.highlightcolor,
+ endcolor: this.options.highlightendcolor,
+ restorecolor: this.originalBackground
+ });
+ },
+ leaveEditMode: function() {
+ Element.removeClassName(this.element, this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ if (this.options.externalControl) {
+ Element.show(this.options.externalControl);
+ }
+ this.editing = false;
+ this.saving = false;
+ this.oldInnerHTML = null;
+ this.onLeaveEditMode();
+ },
+ onComplete: function(transport) {
+ this.leaveEditMode();
+ this.options.onComplete.bind(this)(transport, this.element);
+ },
+ onEnterEditMode: function() {},
+ onLeaveEditMode: function() {},
+ dispose: function() {
+ if (this.oldInnerHTML) {
+ this.element.innerHTML = this.oldInnerHTML;
+ }
+ this.leaveEditMode();
+ Event.stopObserving(this.element, 'click', this.onclickListener);
+ Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+ Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ }
+};
+
+Ajax.InPlaceCollectionEditor = Class.create();
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
+ createEditField: function() {
+ if (!this.cached_selectTag) {
+ var selectTag = document.createElement("select");
+ var collection = this.options.collection || [];
+ var optionTag;
+ collection.each(function(e,i) {
+ optionTag = document.createElement("option");
+ optionTag.value = (e instanceof Array) ? e[0] : e;
+ if((typeof this.options.value == 'undefined') &&
+ ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
+ if(this.options.value==optionTag.value) optionTag.selected = true;
+ optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
+ selectTag.appendChild(optionTag);
+ }.bind(this));
+ this.cached_selectTag = selectTag;
+ }
+
+ this.editField = this.cached_selectTag;
+ if(this.options.loadTextURL) this.loadExternalText();
+ this.form.appendChild(this.editField);
+ this.options.callback = function(form, value) {
+ return "value=" + encodeURIComponent(value);
+ }
+ }
+});
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+};
diff --git a/framework/Web/Javascripts/scriptaculous/dragdrop.js b/framework/Web/Javascripts/scriptaculous/dragdrop.js
new file mode 100644
index 00000000..32c91bc3
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/dragdrop.js
@@ -0,0 +1,944 @@
+// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(typeof Effect == 'undefined')
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || {});
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if((typeof containment == 'object') &&
+ (containment.constructor == Array)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ if(options.accept) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
+
+ isContained: function(element, drop) {
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
+ },
+
+ isAffected: function(point, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(drop.hoverclass)
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(point, element) {
+ if(!this.drops.length) return;
+ var affected = [];
+
+ if(this.last_active) this.deactivate(this.last_active);
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
+ });
+
+ if(affected.length>0) {
+ drop = Droppables.findDeepestChild(affected);
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ Droppables.activate(drop);
+ }
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+ if (this.last_active.onDrop)
+ this.last_active.onDrop(element, this.last_active.element, event);
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+}
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ } else {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
+ },
+
+ deactivate: function() {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+ },
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create();
+Draggable._dragging = {};
+
+Draggable.prototype = {
+ initialize: function(element) {
+ var defaults = {
+ handle: false,
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ },
+ endeffect: function(element) {
+ var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function(){
+ Draggable._dragging[element] = false
+ }
+ });
+ },
+ zindex: 1000,
+ revert: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
+ Object.extend(defaults, {
+ starteffect: function(element) {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || {});
+
+ this.element = $(element);
+
+ if(options.handle && (typeof options.handle == 'string'))
+ this.handle = this.element.down('.'+options.handle, 0);
+
+ if(!this.handle) this.handle = $(options.handle);
+ if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.delta = this.currentDelta();
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function() {
+ return([
+ parseInt(Element.getStyle(this.element,'left') || '0'),
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
+ },
+
+ initDrag: function(event) {
+ if(typeof Draggable._dragging[this.element] != 'undefined' &&
+ Draggable._dragging[this.element]) return;
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function(event) {
+ this.dragging = true;
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ Draggables.notify('onDrag', this, event);
+
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+
+ Event.stop(event);
+ },
+
+ finishDrag: function(event, success) {
+ this.dragging = false;
+
+ if(this.options.ghosting) {
+ Position.relativize(this.element);
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ if(success) Droppables.fire(event, this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && typeof revert == 'function') revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function(event) {
+ if(event.keyCode!=Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function(event) {
+ if(!this.dragging) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(typeof this.options.snap == 'function') {
+ p = this.options.snap(p[0],p[1],this);
+ } else {
+ if(this.options.snap instanceof Array) {
+ p = p.map( function(v, i) {
+ return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+ } else {
+ p = p.map( function(v) {
+ return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+ }
+ }}
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ if(!(speed[0] || speed[1])) return;
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+ }
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if (this._isScrollChild) {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+}
+
+var Sortable = {
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+
+ sortables: {},
+
+ _findRootElement: function(element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
+ },
+
+ destroy: function(element){
+ var s = Sortable.options(element);
+
+ if(s) {
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+
+ delete Sortable.sortables[s.element.id];
+ }
+ },
+
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false,
+ treeTag: 'ul',
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ delay: 0,
+ hoverclass: null,
+ ghosting: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || {});
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ tree: options.tree,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover
+ }
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
+ }
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
+ options.droppables.push(element);
+ }
+
+ (this.findElements(element, options) || []).each( function(e) {
+ // handles are per-draggable
+ var handle = options.handle ?
+ $(e).down('.'+options.handle,0) : e;
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
+ options.droppables.push(e);
+ });
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
+
+ // keep reference
+ this.sortables[element.id] = options;
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ Sortable.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Sortable._marker.hide();
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker =
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = Position.cumulativeOffset(dropon);
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+ else
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+
+ Sortable._marker.show();
+ },
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: $(children[i]).down(options.treeTag)
+ }
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child)
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ tree: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, arguments[1] || {});
+
+ var root = {
+ id: null,
+ parent: null,
+ children: [],
+ container: element,
+ position: 0
+ }
+
+ return Sortable._tree(element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || {});
+
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || {});
+
+ var nodeMap = {};
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || {});
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
+ }
+}
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+ if (child.parentNode == element) return true;
+ return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}
diff --git a/framework/Web/Javascripts/scriptaculous/effects.js b/framework/Web/Javascripts/scriptaculous/effects.js
new file mode 100644
index 00000000..06f59b47
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/effects.js
@@ -0,0 +1,1090 @@
+// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if(this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if(this.slice(0,1) == '#') {
+ if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if(this.length==7) color = this.toLowerCase();
+ }
+ }
+ return(color.length==7 ? color : (arguments[0] || this));
+}
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+}
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+}
+
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+ return element;
+}
+
+Element.getOpacity = function(element){
+ return $(element).getStyle('opacity');
+}
+
+Element.setOpacity = function(element, value){
+ return $(element).setStyle({opacity:value});
+}
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+}
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Array.prototype.call = function() {
+ var args = arguments;
+ this.each(function(f){ f.apply(this, args) });
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ tagifyText: function(element) {
+ if(typeof Builder == 'undefined')
+ throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
+
+ var tagifyStyle = 'position:relative';
+ if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
+
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if(child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ Builder.node('span',{style: tagifyStyle},
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if(((typeof element == 'object') ||
+ (typeof element == 'function')) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || {});
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+ var options = Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || {});
+ Effect[element.visible() ?
+ Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+ }
+};
+
+var Effect2 = Effect; // deprecated
+
+/* ------------- transitions ------------- */
+
+Effect.Transitions = {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+ },
+ pulse: function(pos, pulses) {
+ pulses = pulses || 5;
+ return (
+ Math.round((pos % (1/pulses)) * pulses) == 0 ?
+ ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
+ 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
+ );
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+};
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create();
+Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ var position = (typeof effect.options.queue == 'string') ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if(!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if(this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ for(var i=0, len=this.effects.length;i
- * Event.OnLoad(function(){ alert("Page Loaded!"); });
- *
- *
- * @param {Function} function to execute when page is loaded.
- */
- OnLoad : function (fn)
- {
- // opera onload is in document, not window
- var w = document.addEventListener &&
- !window.addEventListener ? document : window;
- Event.observe(w,'load',fn);
- },
-
- /**
- * @param {Event} a keyboard event
- * @return {Number} the Unicode character code generated by the key
- * that was struck.
- */
- keyCode : function(e)
- {
- return e.keyCode != null ? e.keyCode : e.charCode
- },
-
- /**
- * @param {String} event type or event name.
- * @return {Boolean} true if event type is of HTMLEvent, false
- * otherwise
- */
- isHTMLEvent : function(type)
- {
- var events = ['abort', 'blur', 'change', 'error', 'focus',
- 'load', 'reset', 'resize', 'scroll', 'select',
- 'submit', 'unload'];
- return events.include(type);
- },
-
- /**
- * @param {String} event type or event name
- * @return {Boolean} true if event type is of MouseEvent,
- * false otherwise
- */
- isMouseEvent : function(type)
- {
- var events = ['click', 'mousedown', 'mousemove', 'mouseout',
- 'mouseover', 'mouseup'];
- return events.include(type);
- },
-
- /**
- * Dispatch the DOM event of a given type on a DOM
- * element. Only HTMLEvent and MouseEvent can be
- * dispatched, keyboard events or UIEvent can not be dispatch
- * via javascript consistently.
- * For the "submit" event the submit() method is called.
- * @param {Object} element id string or a DOM element.
- * @param {String} event type to dispatch.
- */
- fireEvent : function(element,type,canBubble)
- {
- canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
- element = $(element);
- if(type == "submit")
- return element.submit();
- if(document.createEvent)
- {
- if(Event.isHTMLEvent(type))
- {
- var event = document.createEvent('HTMLEvents');
- event.initEvent(type, canBubble, true);
- }
- else if(Event.isMouseEvent(type))
- {
- var event = document.createEvent('MouseEvents');
- if (event.initMouseEvent)
- {
- event.initMouseEvent(type,canBubble,true,
- document.defaultView, 1, 0, 0, 0, 0, false,
- false, false, false, 0, null);
- }
- else
- {
- // Safari
- // TODO we should be initialising other mouse-event related attributes here
- event.initEvent(type, canBubble, true);
- }
- }
- element.dispatchEvent(event);
- }
- else if(document.createEventObject)
- {
- var evObj = document.createEventObject();
- element.fireEvent('on'+type, evObj);
- }
- else if(typeof(element['on'+type]) == "function")
- element['on'+type]();
- }
-});
\ No newline at end of file
diff --git a/framework/Web/Javascripts/extended/string.js b/framework/Web/Javascripts/extended/string.js
deleted file mode 100644
index 2bb40759..00000000
--- a/framework/Web/Javascripts/extended/string.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * @class String extensions
- */
-Object.extend(String.prototype,
-{
- /**
- * @param {String} "left" to pad the string on the left, "right" to pad right.
- * @param {Number} minimum string length.
- * @param {String} character(s) to pad
- * @return {String} padded character(s) on the left or right to satisfy minimum string length
- */
-
- pad : function(side, len, chr) {
- if (!chr) chr = ' ';
- var s = this;
- var left = side.toLowerCase()=='left';
- while (s.length" + message + "
"
-
- if (shouldScroll) {
- this.outputElement.scrollTop = this.outputElement.scrollHeight
- }
- },
-
- updateTags : function() {
- var pattern = this.tagFilterElement.value
-
- if (this.tagPattern == pattern) return
-
- try {
- new RegExp(pattern)
- }
- catch (e) {
- return
- }
-
- this.tagPattern = pattern
- Cookie.set('tagPattern', this.tagPattern)
-
- this.outputElement.innerHTML = ""
-
- // Go through each log entry again
- this.outputCount = 0;
- for (var i = 0; i < Logger.logEntries.length; i++) {
- this.logUpdate(Logger.logEntries[i])
- }
- },
-
- repositionWindow : function() {
- var offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
- var pageHeight = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
- this.logElement.style.top = (offset + pageHeight - Element.getHeight(this.logElement)) + "px"
- },
-
- // Event Handlers
- // --------------
-
- logUpdate : function(logEntry) {
- if (logEntry.tag.search(new RegExp(this.tagPattern, 'igm')) == -1) return
- var style = ''
- if (logEntry.tag.search(/error/) != -1) style += 'color:red'
- else if (logEntry.tag.search(/warning/) != -1) style += 'color:orange'
- else if (logEntry.tag.search(/debug/) != -1) style += 'color:green'
- else if (logEntry.tag.search(/info/) != -1) style += 'color:white'
- else style += 'color:yellow'
-
- this.output(logEntry.message, style)
- },
-
- clear : function(e) {
- this.outputElement.innerHTML = ""
- },
-
- handleInput : function(e) {
- if (e.keyCode == Event.KEY_RETURN ) {
- var command = this.inputElement.value
-
- switch(command) {
- case "clear":
- Logger.clear()
- break
-
- default:
- var consoleOutput = ""
-
- try {
- consoleOutput = eval(this.inputElement.value)
- }
- catch (e) {
- Logger.error("Problem parsing input <" + command + ">", e)
- break
- }
-
- Logger.log(consoleOutput)
- break
- }
-
- if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
- this.commandHistory.unshift(this.inputElement.value)
- }
-
- this.commandIndex = 0
- this.inputElement.value = ""
- }
- else if (e.keyCode == Event.KEY_UP && this.commandHistory.length > 0) {
- this.inputElement.value = this.commandHistory[this.commandIndex]
-
- if (this.commandIndex < this.commandHistory.length - 1) {
- this.commandIndex += 1
- }
- }
- else if (e.keyCode == Event.KEY_DOWN && this.commandHistory.length > 0) {
- if (this.commandIndex > 0) {
- this.commandIndex -= 1
- }
-
- this.inputElement.value = this.commandHistory[this.commandIndex]
- }
- else {
- this.commandIndex = 0
- }
- }
-}
-
-
-// -------------------------
-// Helper Functions And Junk
-// -------------------------
-function inspect(o)
-{
- var objtype = typeof(o);
- if (objtype == "undefined") {
- return "undefined";
- } else if (objtype == "number" || objtype == "boolean") {
- return o + "";
- } else if (o === null) {
- return "null";
- }
-
- try {
- var ostring = (o + "");
- } catch (e) {
- return "[" + typeof(o) + "]";
- }
-
- if (typeof(o) == "function")
- {
- o = ostring.replace(/^\s+/, "");
- var idx = o.indexOf("{");
- if (idx != -1) {
- o = o.substr(0, idx) + "{...}";
- }
- return o;
- }
-
- var reprString = function (o)
- {
- return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
- ).replace(/[\f]/g, "\\f"
- ).replace(/[\b]/g, "\\b"
- ).replace(/[\n]/g, "\\n"
- ).replace(/[\t]/g, "\\t"
- ).replace(/[\r]/g, "\\r");
- };
-
- if (objtype == "string") {
- return reprString(o);
- }
- // recurse
- var me = arguments.callee;
- // short-circuit for objects that support "json" serialization
- // if they return "self" then just pass-through...
- var newObj;
- if (typeof(o.__json__) == "function") {
- newObj = o.__json__();
- if (o !== newObj) {
- return me(newObj);
- }
- }
- if (typeof(o.json) == "function") {
- newObj = o.json();
- if (o !== newObj) {
- return me(newObj);
- }
- }
- // array
- if (objtype != "function" && typeof(o.length) == "number") {
- var res = [];
- for (var i = 0; i < o.length; i++) {
- var val = me(o[i]);
- if (typeof(val) != "string") {
- val = "undefined";
- }
- res.push(val);
- }
- return "[" + res.join(", ") + "]";
- }
-
- // generic object code path
- res = [];
- for (var k in o) {
- var useKey;
- if (typeof(k) == "number") {
- useKey = '"' + k + '"';
- } else if (typeof(k) == "string") {
- useKey = reprString(k);
- } else {
- // skip non-string or number keys
- continue;
- }
- val = me(o[k]);
- if (typeof(val) != "string") {
- // skip non-serializable values
- continue;
- }
- res.push(useKey + ":" + val);
- }
- return "{" + res.join(", ") + "}";
-}
-
-Array.prototype.contains = function(object) {
- for(var i = 0; i < this.length; i++) {
- if (object == this[i]) return true
- }
-
- return false
-}
-
-// Helper Alias for simple logging
-var puts = function() {return Logger.log(arguments[0], arguments[1])}
-
-/*************************************
-
- Javascript Object Tree
- version 1.0
- last revision:04.11.2004
- steve@slayeroffice.com
- http://slayeroffice.com
-
- (c)2004 S.G. Chipman
-
- Please notify me of any modifications
- you make to this code so that I can
- update the version hosted on slayeroffice.com
-
-
-************************************/
-if(typeof Prado == "undefined")
- var Prado = {};
-Prado.Inspector =
-{
- d : document,
- types : new Array(),
- objs : new Array(),
- hidden : new Array(),
- opera : window.opera,
- displaying : '',
- nameList : new Array(),
-
- format : function(str) {
- if(typeof(str) != "string") return str;
- str=str.replace(//g,">");
- return str;
- },
-
- parseJS : function(obj) {
- var name;
- if(typeof obj == "string") { name = obj; obj = eval(obj); }
- win= typeof obj == 'undefined' ? window : obj;
- this.displaying = name ? name : win.toString();
- for(js in win) {
- try {
- if(win[js] && js.toString().indexOf("Inspector")==-1 && (win[js]+"").indexOf("[native code]")==-1) {
-
- t=typeof(win[js]);
- if(!this.objs[t.toString()]) {
- this.types[this.types.length]=t;
- this.objs[t]={};
- this.nameList[t] = new Array();
- }
- this.nameList[t].push(js);
- this.objs[t][js] = this.format(win[js]+"");
- }
- } catch(err) { }
- }
-
- for(i=0;i";
- this.types.sort();
- var so_objIndex=0;
- for(i=0;i
";
- this.d.getElementById("so_mContainer").innerHTML =mHTML;
- },
-
- handleKeyEvent : function(e) {
- keyCode=document.all?window.event.keyCode:e.keyCode;
- if(keyCode==27) {
- this.cleanUp();
- }
- },
-
- cleanUp : function()
- {
- if(this.d.getElementById("so_mContainer"))
- {
- this.d.body.removeChild(this.d.getElementById("so_mContainer"));
- this.d.body.removeChild(this.d.getElementById("so_mStyle"));
- if(typeof Event != "undefined")
- Event.stopObserving(this.d, "keydown", this.dKeyDownEvent);
- this.types = new Array();
- this.objs = new Array();
- this.hidden = new Array();
- }
- },
-
- disabled : document.all && !this.opera,
-
- inspect : function(obj)
- {
- if(this.disabled)return alert("Sorry, this only works in Mozilla and Firefox currently.");
- this.cleanUp();
- mObj=this.d.body.appendChild(this.d.createElement("div"));
- mObj.id="so_mContainer";
- sObj=this.d.body.appendChild(this.d.createElement("style"));
- sObj.id="so_mStyle";
- sObj.type="text/css";
- sObj.innerHTML = this.style;
- this.dKeyDownEvent = this.handleKeyEvent.bind(this);
- if(typeof Event != "undefined")
- Event.observe(this.d, "keydown", this.dKeyDownEvent);
-
- this.parseJS(obj);
- this.buildTree();
-
- cObj=mObj.appendChild(this.d.createElement("div"));
- cObj.className="credits";
- cObj.innerHTML = "[esc] to close
Javascript Object Tree V2.0.";
-
- window.scrollTo(0,0);
- },
-
- style : "#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000; color:#000; } " +
- "#so_mContainer ul { padding-left:20px; } " +
- "#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } " +
- "#so_mContainer li:hover { background-color:#E3EBED; } " +
- "#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } " +
- "#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } " +
- "#so_mContainer .topLevel { margin:0; padding:0; } " +
- "#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } " +
- "#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"
-}
-
-//similar function to var_dump in PHP, brings up the javascript object tree UI.
-function var_dump(obj)
-{
- Prado.Inspector.inspect(obj);
-}
-
-//similar function to print_r for PHP
-var print_r = inspect;
-
diff --git a/framework/Web/Javascripts/js/compressed/ajax.js b/framework/Web/Javascripts/js/compressed/ajax.js
deleted file mode 100644
index 5bf062d9..00000000
--- a/framework/Web/Javascripts/js/compressed/ajax.js
+++ /dev/null
@@ -1,363 +0,0 @@
-
-var Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest()},function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')})||false;},activeRequestCount:0}
-Ajax.Responders={responders:[],_each:function(iterator){this.responders._each(iterator);},register:function(responderToAdd){if(!this.include(responderToAdd))
-this.responders.push(responderToAdd);},unregister:function(responderToRemove){this.responders=this.responders.without(responderToRemove);},dispatch:function(callback,request,transport,json){this.each(function(responder){if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}});}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++;},onComplete:function(){Ajax.activeRequestCount--;}});Ajax.Base=function(){};Ajax.Base.prototype={setOptions:function(options){this.options={method:'post',asynchronous:true,contentType:'application/x-www-form-urlencoded',parameters:''}
-Object.extend(this.options,options||{});},responseIsSuccess:function(){return this.transport.status==undefined||this.transport.status==0||(this.transport.status>=200&&this.transport.status<300);},responseIsFailure:function(){return!this.responseIsSuccess();}}
-Ajax.Request=Class.create();Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];Ajax.Request.prototype=Object.extend(new Ajax.Base(),{initialize:function(url,options){this.transport=Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){var parameters=this.options.parameters||'';if(parameters.length>0)parameters+='&_=';try{this.url=url;if(this.options.method=='get'&¶meters.length>0)
-this.url+=(this.url.match(/\?/)?'&':'?')+parameters;Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.options.method,this.url,this.options.asynchronous);if(this.options.asynchronous){this.transport.onreadystatechange=this.onStateChange.bind(this);setTimeout((function(){this.respondToReadyState(1)}).bind(this),10);}
-this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version',Prototype.Version,'Accept','text/javascript, text/html, application/xml, text/xml'];if(this.options.method=='post'){requestHeaders.push('Content-type',this.options.contentType);if(this.transport.overrideMimeType)
-requestHeaders.push('Connection','close');}
-if(this.options.requestHeaders)
-requestHeaders.push.apply(requestHeaders,this.options.requestHeaders);for(var i=0;i"+ret.join('')+"
";}},options||{});}});Field.scrollFreeActivate=function(field){setTimeout(function(){Field.activate(field);},1);}
-Ajax.InPlaceEditor=Class.create();Ajax.InPlaceEditor.defaultHighlightColor="#FFFF99";Ajax.InPlaceEditor.prototype={initialize:function(element,url,options){this.url=url;this.element=$(element);this.options=Object.extend({okButton:true,okText:"ok",cancelLink:true,cancelText:"cancel",savingText:"Saving...",clickToEditText:"Click to edit",okText:"ok",rows:1,onComplete:function(transport,element){new Effect.Highlight(element,{startcolor:this.options.highlightcolor});},onFailure:function(transport){alert("Error communicating with the server: "+transport.responseText.stripTags());},callback:function(form){return Form.serialize(form);},handleLineBreaks:true,loadingText:'Loading...',savingClassName:'inplaceeditor-saving',loadingClassName:'inplaceeditor-loading',formClassName:'inplaceeditor-form',highlightcolor:Ajax.InPlaceEditor.defaultHighlightColor,highlightendcolor:"#FFFFFF",externalControl:null,submitOnBlur:false,ajaxOptions:{},evalScripts:false},options||{});if(!this.options.formId&&this.element.id){this.options.formId=this.element.id+"-inplaceeditor";if($(this.options.formId)){this.options.formId=null;}}
-if(this.options.externalControl){this.options.externalControl=$(this.options.externalControl);}
-this.originalBackground=Element.getStyle(this.element,'background-color');if(!this.originalBackground){this.originalBackground="transparent";}
-this.element.title=this.options.clickToEditText;this.onclickListener=this.enterEditMode.bindAsEventListener(this);this.mouseoverListener=this.enterHover.bindAsEventListener(this);this.mouseoutListener=this.leaveHover.bindAsEventListener(this);Event.observe(this.element,'click',this.onclickListener);Event.observe(this.element,'mouseover',this.mouseoverListener);Event.observe(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.observe(this.options.externalControl,'click',this.onclickListener);Event.observe(this.options.externalControl,'mouseover',this.mouseoverListener);Event.observe(this.options.externalControl,'mouseout',this.mouseoutListener);}},enterEditMode:function(evt){if(this.saving)return;if(this.editing)return;this.editing=true;this.onEnterEditMode();if(this.options.externalControl){Element.hide(this.options.externalControl);}
-Element.hide(this.element);this.createForm();this.element.parentNode.insertBefore(this.form,this.element);if(!this.options.loadTextURL)Field.scrollFreeActivate(this.editField);if(evt){Event.stop(evt);}
-return false;},createForm:function(){this.form=document.createElement("form");this.form.id=this.options.formId;Element.addClassName(this.form,this.options.formClassName)
-this.form.onsubmit=this.onSubmit.bind(this);this.createEditField();if(this.options.textarea){var br=document.createElement("br");this.form.appendChild(br);}
-if(this.options.okButton){okButton=document.createElement("input");okButton.type="submit";okButton.value=this.options.okText;okButton.className='editor_ok_button';this.form.appendChild(okButton);}
-if(this.options.cancelLink){cancelLink=document.createElement("a");cancelLink.href="#";cancelLink.appendChild(document.createTextNode(this.options.cancelText));cancelLink.onclick=this.onclickCancel.bind(this);cancelLink.className='editor_cancel';this.form.appendChild(cancelLink);}},hasHTMLLineBreaks:function(string){if(!this.options.handleLineBreaks)return false;return string.match(/
/i);},convertHTMLLineBreaks:function(string){return string.replace(/
/gi,"\n").replace(/
/gi,"\n").replace(/<\/p>/gi,"\n").replace(/
- * request = new Prado.CallbackRequest(UniqueID, callback);
- * request.dispatch();
- *
- */
-Prado.CallbackRequest.prototype =
-{
-
- /**
- * Prepare and inititate a callback request.
- */
- initialize : function(id, options)
- {
- /**
- * Callback URL, same url as the current page.
- */
- this.url = this.getCallbackUrl();
-
- /**
- * Current callback request.
- */
- this.request = null;
-
- this.Enabled = true;
-
- this.id = id;
- if(typeof(id)=="string")
- Prado.CallbackRequest.requests[id] = this;
-
- this.options = Object.extend(
- {
- RequestTimeOut : 30000, // 30 second timeout.
- EnablePageStateUpdate : true,
- HasPriority : true,
- CausesValidation : true,
- ValidationGroup : null,
- PostInputs : true
- }, options || {});
- },
-
- /**
- * Gets the url from the forms that contains the PRADO_PAGESTATE
- * @return {String} callback url.
- */
- getCallbackUrl : function()
- {
- return $('PRADO_PAGESTATE').form.action;
- },
-
- /**
- * Sets the request parameter
- * @param {Object} parameter value
- */
- setCallbackParameter : function(value)
- {
- this.options['params'] = value;
- },
-
- /**
- * @return {Object} request paramater value.
- */
- getCallbackParameter : function()
- {
- return this.options['params'];
- },
-
- /**
- * Sets the callback request timeout.
- * @param {integer} timeout in milliseconds
- */
- setRequestTimeOut : function(timeout)
- {
- this.options['RequestTimeOut'] = timeout;
- },
-
- /**
- * @return {integer} request timeout in milliseconds
- */
- getRequestTimeOut : function()
- {
- return this.options['RequestTimeOut'];
- },
-
- /**
- * Set true to enable validation on callback dispatch.
- * @param {boolean} true to validate
- */
- setCausesValidation : function(validate)
- {
- this.options['CausesValidation'] = validate;
- },
-
- /**
- * @return {boolean} validate on request dispatch
- */
- getCausesValidation : function()
- {
- return this.options['CausesValidation'];
- },
-
- /**
- * Sets the validation group to validate during request dispatch.
- * @param {string} validation group name
- */
- setValidationGroup : function(group)
- {
- this.options['ValidationGroup'] = group;
- },
-
- /**
- * @return {string} validation group name.
- */
- getValidationGroup : function()
- {
- return this.options['ValidationGroup'];
- },
-
- /**
- * Dispatch the callback request.
- */
- dispatch : function()
- {
- //Logger.info("dispatching request");
- //trigger tinyMCE to save data.
- if(typeof tinyMCE != "undefined")
- tinyMCE.triggerSave();
-
- //override parameter and postBody options.
- Object.extend(this.options,
- {
-// postBody : this._getPostData(),
- parameters : ''
- });
-
- if(this.options.CausesValidation && typeof(Prado.Validation) != "undefined")
- {
- var form = this.options.Form || Prado.Validation.getForm();
- if(Prado.Validation.validate(form,this.options.ValidationGroup,this) == false)
- return false;
- }
-
- if(this.options.onPreDispatch)
- this.options.onPreDispatch(this,null);
-
- if(!this.Enabled)
- return;
-
- if(this.options.HasPriority)
- {
- return Prado.CallbackRequest.enqueue(this);
- //return Prado.CallbackRequest.dispatchPriorityRequest(this);
- }
- else
- return Prado.CallbackRequest.dispatchNormalRequest(this);
- },
-
- abort : function()
- {
- return Prado.CallbackRequest.abortRequest(this.id);
- },
-
- /**
- * Collects the form inputs, encode the parameters, and sets the callback
- * target id. The resulting string is the request content body.
- * @return string request body content containing post data.
- */
- _getPostData : function()
- {
- var data = {};
- var callback = Prado.CallbackRequest;
- if(this.options.PostInputs != false)
- {
- callback.PostDataLoaders.each(function(name)
- {
- $A(document.getElementsByName(name)).each(function(element)
- {
- //IE will try to get elements with ID == name as well.
- if(element.type && element.name == name)
- {
- value = $F(element);
- if(typeof(value) != "undefined")
- data[name] = value;
- }
- })
- })
- }
- if(typeof(this.options.params) != "undefined")
- data[callback.FIELD_CALLBACK_PARAMETER] = callback.encode(this.options.params);
- var pageState = $F(callback.FIELD_CALLBACK_PAGESTATE);
- if(typeof(pageState) != "undefined")
- data[callback.FIELD_CALLBACK_PAGESTATE] = pageState;
- data[callback.FIELD_CALLBACK_TARGET] = this.id;
- if(this.options.EventTarget)
- data[callback.FIELD_POSTBACK_TARGET] = this.options.EventTarget;
- if(this.options.EventParameter)
- data[callback.FIELD_POSTBACK_PARAMETER] = this.options.EventParameter;
- return $H(data).toQueryString();
- }
-}
-
-/**
- * Create a new callback request using default settings.
- * @param string callback handler unique ID.
- * @param mixed parameter to pass to callback handler on the server side.
- * @param function client side onSuccess event handler.
- * @param object additional request options.
- * @return boolean always false.
- */
-Prado.Callback = function(UniqueID, parameter, onSuccess, options)
-{
- var callback =
- {
- 'params' : parameter || '',
- 'onSuccess' : onSuccess || Prototype.emptyFunction
- };
-
- Object.extend(callback, options || {});
-
- request = new Prado.CallbackRequest(UniqueID, callback);
- request.dispatch();
- return false;
-}
-
-
-/*
-Copyright (c) 2005 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-Array.prototype.______array = '______array';
-
-Prado.JSON = {
- org: 'http://www.JSON.org',
- copyright: '(c)2005 JSON.org',
- license: 'http://www.crockford.com/JSON/license.html',
-
- stringify: function (arg) {
- var c, i, l, s = '', v;
-
- switch (typeof arg) {
- case 'object':
- if (arg) {
- if (arg.______array == '______array') {
- for (i = 0; i < arg.length; ++i) {
- v = this.stringify(arg[i]);
- if (s) {
- s += ',';
- }
- s += v;
- }
- return '[' + s + ']';
- } else if (typeof arg.toString != 'undefined') {
- for (i in arg) {
- v = arg[i];
- if (typeof v != 'undefined' && typeof v != 'function') {
- v = this.stringify(v);
- if (s) {
- s += ',';
- }
- s += this.stringify(i) + ':' + v;
- }
- }
- return '{' + s + '}';
- }
- }
- return 'null';
- case 'number':
- return isFinite(arg) ? String(arg) : 'null';
- case 'string':
- l = arg.length;
- s = '"';
- for (i = 0; i < l; i += 1) {
- c = arg.charAt(i);
- if (c >= ' ') {
- if (c == '\\' || c == '"') {
- s += '\\';
- }
- s += c;
- } else {
- switch (c) {
- case '\b':
- s += '\\b';
- break;
- case '\f':
- s += '\\f';
- break;
- case '\n':
- s += '\\n';
- break;
- case '\r':
- s += '\\r';
- break;
- case '\t':
- s += '\\t';
- break;
- default:
- c = c.charCodeAt();
- s += '\\u00' + Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }
- }
- }
- return s + '"';
- case 'boolean':
- return String(arg);
- default:
- return 'null';
- }
- },
- parse: function (text) {
- var at = 0;
- var ch = ' ';
-
- function error(m) {
- throw {
- name: 'JSONError',
- message: m,
- at: at - 1,
- text: text
- };
- }
-
- function next() {
- ch = text.charAt(at);
- at += 1;
- return ch;
- }
-
- function white() {
- while (ch) {
- if (ch <= ' ') {
- next();
- } else if (ch == '/') {
- switch (next()) {
- case '/':
- while (next() && ch != '\n' && ch != '\r') {}
- break;
- case '*':
- next();
- for (;;) {
- if (ch) {
- if (ch == '*') {
- if (next() == '/') {
- next();
- break;
- }
- } else {
- next();
- }
- } else {
- error("Unterminated comment");
- }
- }
- break;
- default:
- error("Syntax error");
- }
- } else {
- break;
- }
- }
- }
-
- function string() {
- var i, s = '', t, u;
-
- if (ch == '"') {
-outer: while (next()) {
- if (ch == '"') {
- next();
- return s;
- } else if (ch == '\\') {
- switch (next()) {
- case 'b':
- s += '\b';
- break;
- case 'f':
- s += '\f';
- break;
- case 'n':
- s += '\n';
- break;
- case 'r':
- s += '\r';
- break;
- case 't':
- s += '\t';
- break;
- case 'u':
- u = 0;
- for (i = 0; i < 4; i += 1) {
- t = parseInt(next(), 16);
- if (!isFinite(t)) {
- break outer;
- }
- u = u * 16 + t;
- }
- s += String.fromCharCode(u);
- break;
- default:
- s += ch;
- }
- } else {
- s += ch;
- }
- }
- }
- error("Bad string");
- }
-
- function array() {
- var a = [];
-
- if (ch == '[') {
- next();
- white();
- if (ch == ']') {
- next();
- return a;
- }
- while (ch) {
- a.push(value());
- white();
- if (ch == ']') {
- next();
- return a;
- } else if (ch != ',') {
- break;
- }
- next();
- white();
- }
- }
- error("Bad array");
- }
-
- function object() {
- var k, o = {};
-
- if (ch == '{') {
- next();
- white();
- if (ch == '}') {
- next();
- return o;
- }
- while (ch) {
- k = string();
- white();
- if (ch != ':') {
- break;
- }
- next();
- o[k] = value();
- white();
- if (ch == '}') {
- next();
- return o;
- } else if (ch != ',') {
- break;
- }
- next();
- white();
- }
- }
- error("Bad object");
- }
-
- function number() {
- var n = '', v;
- if (ch == '-') {
- n = '-';
- next();
- }
- while (ch >= '0' && ch <= '9') {
- n += ch;
- next();
- }
- if (ch == '.') {
- n += '.';
- while (next() && ch >= '0' && ch <= '9') {
- n += ch;
- }
- }
- if (ch == 'e' || ch == 'E') {
- n += 'e';
- next();
- if (ch == '-' || ch == '+') {
- n += ch;
- next();
- }
- while (ch >= '0' && ch <= '9') {
- n += ch;
- next();
- }
- }
- v = +n;
- if (!isFinite(v)) {
- ////error("Bad number");
- } else {
- return v;
- }
- }
-
- function word() {
- switch (ch) {
- case 't':
- if (next() == 'r' && next() == 'u' && next() == 'e') {
- next();
- return true;
- }
- break;
- case 'f':
- if (next() == 'a' && next() == 'l' && next() == 's' &&
- next() == 'e') {
- next();
- return false;
- }
- break;
- case 'n':
- if (next() == 'u' && next() == 'l' && next() == 'l') {
- next();
- return null;
- }
- break;
- }
- error("Syntax error");
- }
-
- function value() {
- white();
- switch (ch) {
- case '{':
- return object();
- case '[':
- return array();
- case '"':
- return string();
- case '-':
- return number();
- default:
- return ch >= '0' && ch <= '9' ? number() : word();
- }
- }
-
- return value();
- }
-};
-
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
-// (c) 2005 Jon Tirsen (http://www.tirsen.com)
-// Contributors:
-// Richard Livsey
-// Rahul Bhargava
-// Rob Wills
-//
-// See scriptaculous.js for full license.
-
-// Autocompleter.Base handles all the autocompletion functionality
-// that's independent of the data source for autocompletion. This
-// includes drawing the autocompletion menu, observing keyboard
-// and mouse events, and similar.
-//
-// Specific autocompleters need to provide, at the very least,
-// a getUpdatedChoices function that will be invoked every time
-// the text inside the monitored textbox changes. This method
-// should get the text for which to provide autocompletion by
-// invoking this.getToken(), NOT by directly accessing
-// this.element.value. This is to allow incremental tokenized
-// autocompletion. Specific auto-completion logic (AJAX, etc)
-// belongs in getUpdatedChoices.
-//
-// Tokenized incremental autocompletion is enabled automatically
-// when an autocompleter is instantiated with the 'tokens' option
-// in the options parameter, e.g.:
-// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
-// will incrementally autocomplete with a comma as the token.
-// Additionally, ',' in the above example can be replaced with
-// a token array, e.g. { tokens: [',', '\n'] } which
-// enables autocompletion on multiple tokens. This is most
-// useful when one of the tokens is \n (a newline), as it
-// allows smart autocompletion after linebreaks.
-
-if(typeof Effect == 'undefined')
- throw("controls.js requires including script.aculo.us' effects.js library");
-
-var Autocompleter = {}
-Autocompleter.Base = function() {};
-Autocompleter.Base.prototype = {
- baseInitialize: function(element, update, options) {
- this.element = $(element);
- this.update = $(update);
- this.hasFocus = false;
- this.changed = false;
- this.active = false;
- this.index = 0;
- this.entryCount = 0;
-
- if (this.setOptions)
- this.setOptions(options);
- else
- this.options = options || {};
-
- this.options.paramName = this.options.paramName || this.element.name;
- this.options.tokens = this.options.tokens || [];
- this.options.frequency = this.options.frequency || 0.4;
- this.options.minChars = this.options.minChars || 1;
- this.options.onShow = this.options.onShow ||
- function(element, update){
- if(!update.style.position || update.style.position=='absolute') {
- update.style.position = 'absolute';
- Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
- }
- Effect.Appear(update,{duration:0.15});
- };
- this.options.onHide = this.options.onHide ||
- function(element, update){ new Effect.Fade(update,{duration:0.15}) };
-
- if (typeof(this.options.tokens) == 'string')
- this.options.tokens = new Array(this.options.tokens);
-
- this.observer = null;
-
- this.element.setAttribute('autocomplete','off');
-
- Element.hide(this.update);
-
- Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
- Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
- },
-
- show: function() {
- if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
- if(!this.iefix &&
- (navigator.appVersion.indexOf('MSIE')>0) &&
- (navigator.userAgent.indexOf('Opera')<0) &&
- (Element.getStyle(this.update, 'position')=='absolute')) {
- new Insertion.After(this.update,
- '');
- this.iefix = $(this.update.id+'_iefix');
- }
- if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
- },
-
- fixIEOverlapping: function() {
- Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
- this.iefix.style.zIndex = 1;
- this.update.style.zIndex = 2;
- Element.show(this.iefix);
- },
-
- hide: function() {
- this.stopIndicator();
- if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
- if(this.iefix) Element.hide(this.iefix);
- },
-
- startIndicator: function() {
- if(this.options.indicator) Element.show(this.options.indicator);
- },
-
- stopIndicator: function() {
- if(this.options.indicator) Element.hide(this.options.indicator);
- },
-
- onKeyPress: function(event) {
- if(this.active)
- switch(event.keyCode) {
- case Event.KEY_TAB:
- case Event.KEY_RETURN:
- this.selectEntry();
- Event.stop(event);
- case Event.KEY_ESC:
- this.hide();
- this.active = false;
- Event.stop(event);
- return;
- case Event.KEY_LEFT:
- case Event.KEY_RIGHT:
- return;
- case Event.KEY_UP:
- this.markPrevious();
- this.render();
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
- return;
- case Event.KEY_DOWN:
- this.markNext();
- this.render();
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
- return;
- }
- else
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
- (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
-
- this.changed = true;
- this.hasFocus = true;
-
- if(this.observer) clearTimeout(this.observer);
- this.observer =
- setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
- },
-
- activate: function() {
- this.changed = false;
- this.hasFocus = true;
- this.getUpdatedChoices();
- },
-
- onHover: function(event) {
- var element = Event.findElement(event, 'LI');
- if(this.index != element.autocompleteIndex)
- {
- this.index = element.autocompleteIndex;
- this.render();
- }
- Event.stop(event);
- },
-
- onClick: function(event) {
- var element = Event.findElement(event, 'LI');
- this.index = element.autocompleteIndex;
- this.selectEntry();
- this.hide();
- },
-
- onBlur: function(event) {
- // needed to make click events working
- setTimeout(this.hide.bind(this), 250);
- this.hasFocus = false;
- this.active = false;
- },
-
- render: function() {
- if(this.entryCount > 0) {
- for (var i = 0; i < this.entryCount; i++)
- this.index==i ?
- Element.addClassName(this.getEntry(i),"selected") :
- Element.removeClassName(this.getEntry(i),"selected");
-
- if(this.hasFocus) {
- this.show();
- this.active = true;
- }
- } else {
- this.active = false;
- this.hide();
- }
- },
-
- markPrevious: function() {
- if(this.index > 0) this.index--
- else this.index = this.entryCount-1;
- this.getEntry(this.index).scrollIntoView(true);
- },
-
- markNext: function() {
- if(this.index < this.entryCount-1) this.index++
- else this.index = 0;
- this.getEntry(this.index).scrollIntoView(false);
- },
-
- getEntry: function(index) {
- return this.update.firstChild.childNodes[index];
- },
-
- getCurrentEntry: function() {
- return this.getEntry(this.index);
- },
-
- selectEntry: function() {
- this.active = false;
- this.updateElement(this.getCurrentEntry());
- },
-
- updateElement: function(selectedElement) {
- if (this.options.updateElement) {
- this.options.updateElement(selectedElement);
- return;
- }
- var value = '';
- if (this.options.select) {
- var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
- if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
- } else
- value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
-
- var lastTokenPos = this.findLastToken();
- if (lastTokenPos != -1) {
- var newValue = this.element.value.substr(0, lastTokenPos + 1);
- var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
- if (whitespace)
- newValue += whitespace[0];
- this.element.value = newValue + value;
- } else {
- this.element.value = value;
- }
- this.element.focus();
-
- if (this.options.afterUpdateElement)
- this.options.afterUpdateElement(this.element, selectedElement);
- },
-
- updateChoices: function(choices) {
- if(!this.changed && this.hasFocus) {
- this.update.innerHTML = choices;
- Element.cleanWhitespace(this.update);
- Element.cleanWhitespace(this.update.firstChild);
-
- if(this.update.firstChild && this.update.firstChild.childNodes) {
- this.entryCount =
- this.update.firstChild.childNodes.length;
- for (var i = 0; i < this.entryCount; i++) {
- var entry = this.getEntry(i);
- entry.autocompleteIndex = i;
- this.addObservers(entry);
- }
- } else {
- this.entryCount = 0;
- }
-
- this.stopIndicator();
-
- this.index = 0;
- this.render();
- }
- },
-
- addObservers: function(element) {
- Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
- Event.observe(element, "click", this.onClick.bindAsEventListener(this));
- },
-
- onObserverEvent: function() {
- this.changed = false;
- if(this.getToken().length>=this.options.minChars) {
- this.startIndicator();
- this.getUpdatedChoices();
- } else {
- this.active = false;
- this.hide();
- }
- },
-
- getToken: function() {
- var tokenPos = this.findLastToken();
- if (tokenPos != -1)
- var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
- else
- var ret = this.element.value;
-
- return /\n/.test(ret) ? '' : ret;
- },
-
- findLastToken: function() {
- var lastTokenPos = -1;
-
- for (var i=0; i" + ret.join('') + "
";
- }
- }, options || {});
- }
-});
-
-// AJAX in-place editor
-//
-// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
-
-// Use this if you notice weird scrolling problems on some browsers,
-// the DOM might be a bit confused when this gets called so do this
-// waits 1 ms (with setTimeout) until it does the activation
-Field.scrollFreeActivate = function(field) {
- setTimeout(function() {
- Field.activate(field);
- }, 1);
-}
-
-Ajax.InPlaceEditor = Class.create();
-Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
-Ajax.InPlaceEditor.prototype = {
- initialize: function(element, url, options) {
- this.url = url;
- this.element = $(element);
-
- this.options = Object.extend({
- okButton: true,
- okText: "ok",
- cancelLink: true,
- cancelText: "cancel",
- savingText: "Saving...",
- clickToEditText: "Click to edit",
- okText: "ok",
- rows: 1,
- onComplete: function(transport, element) {
- new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
- },
- onFailure: function(transport) {
- alert("Error communicating with the server: " + transport.responseText.stripTags());
- },
- callback: function(form) {
- return Form.serialize(form);
- },
- handleLineBreaks: true,
- loadingText: 'Loading...',
- savingClassName: 'inplaceeditor-saving',
- loadingClassName: 'inplaceeditor-loading',
- formClassName: 'inplaceeditor-form',
- highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
- highlightendcolor: "#FFFFFF",
- externalControl: null,
- submitOnBlur: false,
- ajaxOptions: {},
- evalScripts: false
- }, options || {});
-
- if(!this.options.formId && this.element.id) {
- this.options.formId = this.element.id + "-inplaceeditor";
- if ($(this.options.formId)) {
- // there's already a form with that name, don't specify an id
- this.options.formId = null;
- }
- }
-
- if (this.options.externalControl) {
- this.options.externalControl = $(this.options.externalControl);
- }
-
- this.originalBackground = Element.getStyle(this.element, 'background-color');
- if (!this.originalBackground) {
- this.originalBackground = "transparent";
- }
-
- this.element.title = this.options.clickToEditText;
-
- this.onclickListener = this.enterEditMode.bindAsEventListener(this);
- this.mouseoverListener = this.enterHover.bindAsEventListener(this);
- this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
- Event.observe(this.element, 'click', this.onclickListener);
- Event.observe(this.element, 'mouseover', this.mouseoverListener);
- Event.observe(this.element, 'mouseout', this.mouseoutListener);
- if (this.options.externalControl) {
- Event.observe(this.options.externalControl, 'click', this.onclickListener);
- Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
- Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
- }
- },
- enterEditMode: function(evt) {
- if (this.saving) return;
- if (this.editing) return;
- this.editing = true;
- this.onEnterEditMode();
- if (this.options.externalControl) {
- Element.hide(this.options.externalControl);
- }
- Element.hide(this.element);
- this.createForm();
- this.element.parentNode.insertBefore(this.form, this.element);
- if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
- // stop the event to avoid a page refresh in Safari
- if (evt) {
- Event.stop(evt);
- }
- return false;
- },
- createForm: function() {
- this.form = document.createElement("form");
- this.form.id = this.options.formId;
- Element.addClassName(this.form, this.options.formClassName)
- this.form.onsubmit = this.onSubmit.bind(this);
-
- this.createEditField();
-
- if (this.options.textarea) {
- var br = document.createElement("br");
- this.form.appendChild(br);
- }
-
- if (this.options.okButton) {
- okButton = document.createElement("input");
- okButton.type = "submit";
- okButton.value = this.options.okText;
- okButton.className = 'editor_ok_button';
- this.form.appendChild(okButton);
- }
-
- if (this.options.cancelLink) {
- cancelLink = document.createElement("a");
- cancelLink.href = "#";
- cancelLink.appendChild(document.createTextNode(this.options.cancelText));
- cancelLink.onclick = this.onclickCancel.bind(this);
- cancelLink.className = 'editor_cancel';
- this.form.appendChild(cancelLink);
- }
- },
- hasHTMLLineBreaks: function(string) {
- if (!this.options.handleLineBreaks) return false;
- return string.match(/
/i);
- },
- convertHTMLLineBreaks: function(string) {
- return string.replace(/
/gi, "\n").replace(/
/gi, "\n").replace(/<\/p>/gi, "\n").replace(/
+ * var browser = Prado.Browser();
+ * alert(browser.ie); //should ouput true if IE, false otherwise
+ *
+ * @param ${parameter}
+ * @return ${return}
+ */
+ Browser : function()
+ {
+ var info = { Version : "1.0" };
+ var is_major = parseInt( navigator.appVersion );
+ info.nver = is_major;
+ info.ver = navigator.appVersion;
+ info.agent = navigator.userAgent;
+ info.dom = document.getElementById ? 1 : 0;
+ info.opera = window.opera ? 1 : 0;
+ info.ie5 = ( info.ver.indexOf( "MSIE 5" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
+ info.ie6 = ( info.ver.indexOf( "MSIE 6" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
+ info.ie4 = ( document.all && !info.dom && !info.opera ) ? 1 : 0;
+ info.ie = info.ie4 || info.ie5 || info.ie6;
+ info.mac = info.agent.indexOf( "Mac" ) > -1;
+ info.ns6 = ( info.dom && parseInt( info.ver ) >= 5 ) ? 1 : 0;
+ info.ie3 = ( info.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
+ info.hotjava = ( info.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
+ info.ns4 = ( document.layers && !info.dom && !info.hotjava ) ? 1 : 0;
+ info.bw = ( info.ie6 || info.ie5 || info.ie4 || info.ns4 || info.ns6 || info.opera );
+ info.ver3 = ( info.hotjava || info.ie3 );
+ info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
+ info.operaOld = info.opera && !info.opera7;
+ return info;
+ },
+
+ ImportCss : function(doc, css_file)
+ {
+ if (Prado.Browser().ie)
+ var styleSheet = doc.createStyleSheet(css_file);
+ else
+ {
+ var elm = doc.createElement("link");
+
+ elm.rel = "stylesheet";
+ elm.href = css_file;
+
+ if (headArr = doc.getElementsByTagName("head"))
+ headArr[0].appendChild(elm);
+ }
+ }
+};
+
+
+
/**
* Similar to bindAsEventLister, but takes additional arguments.
*/
@@ -3485,297 +3542,339 @@ Base.implement = function(_interface) {
this.prototype.extend(_interface);
};
-/*
- * Signals and Slots for Prototype: Easy custom javascript events
- * http://tetlaw.id.au/view/blog/signals-and-slots-for-prototype-easy-custom-javascript-events
- * Andrew Tetlaw
- * Version 1.2 (2006-06-19)
- *
- * http://creativecommons.org/licenses/by-sa/2.5/
+/**
+ * Performs a post-back using javascript
*
-Signal = {
- throwErrors : true,
- MT : function(){ return true },
- connect : function(obj1, func1, obj2, func2, options) {
- var options = Object.extend({
- connectOnce : false,
- before : false,
- mutate : function() {return arguments;}
- }, options || {});
- if(typeof func1 != 'string' || typeof func2 != 'string') return;
+ */
+Prado.PostBack = function(event,options)
+{
+ var form = $(options['FormID']);
+ var canSubmit = true;
- var sigObj = obj1 || window;
- var slotObj = obj2 || window;
- var signame = func1+'__signal_';
- var slotsname = func1+'__slots_';
- if(!sigObj[signame]) {
- // having the slotFunc in a var and setting it by using an anonymous function in this way
- // is apparently a good way to prevent memory leaks in IE if the objects are DOM nodes.
- var slotFunc = function() {
- var args = [];
- for(var x = 0; x < arguments.length; x++){
- args.push(arguments[x]);
- }
- args = options.mutate.apply(null,args)
- var result;
- if(!options.before) result = sigObj[signame].apply(sigObj,arguments); //default: call sign before slot
- sigObj[slotsname].each(function(slot){
- try {
- if(slot && slot[0]) { // testing for null, a disconnect may have nulled this slot
- slot[0][slot[1]].apply(slot[0],args); //[0] = obj, [1] = func name
- }
- } catch(e) {
- if(Signal.throwErrors) throw e;
- }
- });
- if(options.before) result = sigObj[signame].apply(sigObj,arguments); //call slot before sig
- return result; //return sig result
- };
- (function() {
- sigObj[slotsname] = $A([]);
- sigObj[signame] = sigObj[func1] || Signal.MT;
- sigObj[func1] = slotFunc;
- })();
- }
- var con = (sigObj[slotsname].length > 0) ?
- (options.connectOnce ? !sigObj[slotsname].any(function(slot) { return (slot[0] == slotObj && slot[1] == func2) }) : true) :
- true;
- if(con) {
- sigObj[slotsname].push([slotObj,func2]);
- }
- },
- connectOnce : function(obj1, func1, obj2, func2, options) {
- Signal.connect(obj1, func1, obj2, func2, Object.extend(options || {}, {connectOnce : true}))
- },
- disconnect : function(obj1, func1, obj2, func2, options) {
- var options = Object.extend({
- disconnectAll : false
- }, options || {});
- if(typeof func1 != 'string' || typeof func2 != 'string') return;
+ if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
+ {
+ if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
+ return Event.stop(event);
+ }
- var sigObj = obj1 || window;
- var slotObj = obj2 || window;
- var signame = func1+'__signal_';
- var slotsname = func1+'__slots_';
+ if(options['PostBackUrl'] && options['PostBackUrl'].length > 0)
+ form.action = options['PostBackUrl'];
- // I null them in this way so that any currectly active signal will read a null slot,
- // otherwise the slot will be applied even though it's been disconnected
- if(sigObj[slotsname]) {
- if(options.disconnectAll) {
- sigObj[slotsname] = sigObj[slotsname].collect(function(slot) {
- if(slot[0] == slotObj && slot[1] == func2) {
- slot[0] = null;
- return null;
- } else {
- return slot;
- }
- }).compact();
- } else {
- var idx = -1;
- sigObj[slotsname] = sigObj[slotsname].collect(function(slot, index) {
- if(slot[0] == slotObj && slot[1] == func2 && idx < 0) { //disconnect first match
- idx = index;
- slot[0] = null;
- return null;
- } else {
- return slot;
- }
- }).compact();
- }
+ if(options['TrackFocus'])
+ {
+ var lastFocus = $('PRADO_LASTFOCUS');
+ if(lastFocus)
+ {
+ var active = document.activeElement; //where did this come from
+ if(active)
+ lastFocus.value = active.id;
+ else
+ lastFocus.value = options['EventTarget'];
}
- },
- disconnectAll : function(obj1, func1, obj2, func2, options) {
- Signal.disconnect(obj1, func1, obj2, func2, Object.extend(options || {}, {disconnectAll : true}))
}
-}
-*/
-
-/*
- Tests
-
-// 1. Simple Test 1 "hello Fred" should trigger "Fred is a stupid head"
-
-
- sayHello = function(n) {
- alert("Hello! " + n);
- }
- moron = function(n) {
- alert(n + " is a stupid head");
- }
- Signal.connect(null,'sayHello',null,'moron');
-
- onclick="sayHello('Fred')"
-
-
-// 2. Simple Test 2 repeated insults about Fred
-
-
- Signal.connect(null,'sayHello2',null,'moron2');
- Signal.connect(null,'sayHello2',null,'moron2');
- Signal.connect(null,'sayHello2',null,'moron2');
-
-
-// 3. Simple Test 3 multiple insults about Fred
-
-
- Signal.connect(null,'sayHello3',null,'moron3');
- Signal.connect(null,'sayHello3',null,'bonehead3');
- Signal.connect(null,'sayHello3',null,'idiot3');
-
-
-// 4. Simple Test 4 3 insults about Fred first - 3 then none
-
-
- Signal.connect(null,'sayHello4',null,'moron4');
- Signal.connect(null,'sayHello4',null,'moron4');
- Signal.connect(null,'sayHello4',null,'moron4');
- Signal.disconnect(null,'sayHello4',null,'moron4');
- Signal.disconnect(null,'sayHello4',null,'moron4');
- Signal.disconnect(null,'sayHello4',null,'moron4');
-
-
-// 5. Simple Test 5 connect 3 insults about Fred first - only one, then none
-
-
- Signal.connect(null,'sayHello5',null,'moron5');
- Signal.connect(null,'sayHello5',null,'moron5');
- Signal.connect(null,'sayHello5',null,'moron5');
- Signal.disconnectAll(null,'sayHello5',null,'moron5');
-
-
-// 6. Simple Test 6 connect 3 insults but only one comes out
-
-
- Signal.connectOnce(null,'sayHello6',null,'moron6');
- Signal.connectOnce(null,'sayHello6',null,'moron6');
- Signal.connectOnce(null,'sayHello6',null,'moron6');
-
-
-// 7. Simple Test 7 connect via objects
-
-
- var o = {};
- o.sayHello = function(n) {
- alert("Hello! " + n + " (from object o)");
- }
- var m = {};
- m.moron = function(n) {
- alert(n + " is a stupid head (from object m)");
- }
-
- Signal.connect(o,'sayHello',m,'moron');
-
- onclick="o.sayHello('Fred')"
-
-// 8. Simple Test 8 connect but the insult comes first using {before:true}
-
-
- Signal.connect(null,'sayHello8',null,'moron8', {before:true});
-
-
-// 9. Simple Test 9 connect but the insult is mutated
-
-
- Signal.connect(null,'sayHello9',null,'moron9', {mutate:function() { return ['smelly ' + arguments[0]] }});
+ $('PRADO_POSTBACK_TARGET').value = options['EventTarget'];
+ $('PRADO_POSTBACK_PARAMETER').value = options['EventParameter'];
+ /**
+ * Since google toolbar prevents browser default action,
+ * we will always disable default client-side browser action
+ */
+ /*if(options['StopEvent']) */
+ Event.stop(event);
+ Event.fireEvent(form,"submit");
+}
- */
-
-
/**
- * @class String extensions
+ * Additional element utilities.
*/
-Object.extend(String.prototype,
+Prado.Element =
{
/**
- * @param {String} "left" to pad the string on the left, "right" to pad right.
- * @param {Number} minimum string length.
- * @param {String} character(s) to pad
- * @return {String} padded character(s) on the left or right to satisfy minimum string length
+ * Set the value of a particular element.
+ * @param string element id
+ * @param string new element value.
*/
-
- pad : function(side, len, chr) {
- if (!chr) chr = ' ';
- var s = this;
- var left = side.toLowerCase()=='left';
- while (s.length
- * var browser = Prado.Browser();
- * alert(browser.ie); //should ouput true if IE, false otherwise
- *
- * @param ${parameter}
- * @return ${return}
- */
- Browser : function()
- {
- var info = { Version : "1.0" };
- var is_major = parseInt( navigator.appVersion );
- info.nver = is_major;
- info.ver = navigator.appVersion;
- info.agent = navigator.userAgent;
- info.dom = document.getElementById ? 1 : 0;
- info.opera = window.opera ? 1 : 0;
- info.ie5 = ( info.ver.indexOf( "MSIE 5" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
- info.ie6 = ( info.ver.indexOf( "MSIE 6" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
- info.ie4 = ( document.all && !info.dom && !info.opera ) ? 1 : 0;
- info.ie = info.ie4 || info.ie5 || info.ie6;
- info.mac = info.agent.indexOf( "Mac" ) > -1;
- info.ns6 = ( info.dom && parseInt( info.ver ) >= 5 ) ? 1 : 0;
- info.ie3 = ( info.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
- info.hotjava = ( info.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
- info.ns4 = ( document.layers && !info.dom && !info.hotjava ) ? 1 : 0;
- info.bw = ( info.ie6 || info.ie5 || info.ie4 || info.ns4 || info.ns6 || info.opera );
- info.ver3 = ( info.hotjava || info.ie3 );
- info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
- info.operaOld = info.opera && !info.opera7;
- return info;
- },
-
- ImportCss : function(doc, css_file)
- {
- if (Prado.Browser().ie)
- var styleSheet = doc.createStyleSheet(css_file);
- else
- {
- var elm = doc.createElement("link");
-
- elm.rel = "stylesheet";
- elm.href = css_file;
-
- if (headArr = doc.getElementsByTagName("head"))
- headArr[0].appendChild(elm);
- }
- }
-};
-
-
-/*Prado.Focus = Class.create();
-
-Prado.Focus.setFocus = function(id)
-{
- var target = document.getElementById ? document.getElementById(id) : document.all[id];
- if(target && !Prado.Focus.canFocusOn(target))
- {
- target = Prado.Focus.findTarget(target);
- }
- if(target)
- {
- try
- {
- target.focus();
- target.scrollIntoView(false);
- if (window.__smartNav)
- {
- window.__smartNav.ae = target.id;
- }
- }
- catch (e)
- {
- }
- }
-}
-
-Prado.Focus.canFocusOn = function(element)
-{
- if(!element || !(element.tagName))
- return false;
- var tagName = element.tagName.toLowerCase();
- return !element.disabled && (!element.type || element.type.toLowerCase() != "hidden") && Prado.Focus.isFocusableTag(tagName) && Prado.Focus.isVisible(element);
-}
-
-Prado.Focus.isFocusableTag = function(tagName)
-{
- return (tagName == "input" || tagName == "textarea" || tagName == "select" || tagName == "button" || tagName == "a");
-}
-
-
-Prado.Focus.findTarget = function(element)
-{
- if(!element || !(element.tagName))
- {
- return null;
- }
- var tagName = element.tagName.toLowerCase();
- if (tagName == "undefined")
- {
- return null;
- }
- var children = element.childNodes;
- if (children)
- {
- for(var i=0;i
* options['FormID']* The ID of HTML form to manage.
@@ -175,11 +156,6 @@ Prado.ValidationManager.prototype =
*/
initialize : function(options)
{
- this.validators = []; // list of validators
- this.summaries = []; // validation summaries
- this.groups = []; // validation groups
- this.options = {};
-
this.options = options;
Prado.Validation.managers[options.FormID] = this;
},
@@ -357,6 +333,11 @@ Prado.ValidationManager.prototype =
Prado.WebUI.TValidationSummary = Class.create();
Prado.WebUI.TValidationSummary.prototype =
{
+ group : null,
+ options : {},
+ visible : false,
+ messages : null,
+
/**
*
* options['ID']* Validation summary ID, i.e., an HTML element ID
@@ -376,12 +357,9 @@ Prado.WebUI.TValidationSummary.prototype =
this.options = options;
this.group = options.ValidationGroup;
this.messages = $(options.ID);
- if(this.messages)
- {
- this.visible = this.messages.style.visibility != "hidden"
- this.visible = this.visible && this.messages.style.display != "none";
- Prado.Validation.addSummary(options.FormID, this);
- }
+ this.visible = this.messages.style.visibility != "hidden"
+ this.visible = this.visible && this.messages.style.display != "none";
+ Prado.Validation.addSummary(options.FormID, this);
},
/**
@@ -562,6 +540,15 @@ Prado.WebUI.TValidationSummary.prototype =
Prado.WebUI.TBaseValidator = Class.create();
Prado.WebUI.TBaseValidator.prototype =
{
+ enabled : true,
+ visible : false,
+ isValid : true,
+ options : {},
+ _isObserving : {},
+ group : null,
+ manager : null,
+ message : null,
+
/**
*
* options['ID']* Validator ID, e.g. span with message
@@ -574,8 +561,8 @@ Prado.WebUI.TBaseValidator.prototype =
* options['ValidationGroup'] Validation group
* options['ControlCssClass'] Css class to use on the input upon error
* options['OnValidate'] Function to call immediately after validation
- * options['OnValidationSuccess'] Function to call upon after successful validation
- * options['OnValidationError'] Function to call upon after error in validation.
+ * options['OnSuccess'] Function to call upon after successful validation
+ * options['OnError'] Function to call upon after error in validation.
* options['ObserveChanges'] True to observe changes in input
*
*/
@@ -585,23 +572,12 @@ Prado.WebUI.TBaseValidator.prototype =
options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
options.OnError = options.OnError || Prototype.emptyFunction;
*/
-
- this.enabled = true;
- this.visible = false;
- this.isValid = true;
- this._isObserving = {};
- this.group = null;
- this.requestDispatched = false;
-
this.options = options;
this.control = $(options.ControlToValidate);
this.message = $(options.ID);
- if(this.control && this.message)
- {
- this.group = options.ValidationGroup;
+ this.group = options.ValidationGroup;
- this.manager = Prado.Validation.addValidator(options.FormID, this);
- }
+ this.manager = Prado.Validation.addValidator(options.FormID, this);
},
/**
@@ -623,8 +599,6 @@ Prado.WebUI.TBaseValidator.prototype =
if(this.options.FocusOnError && !this.isValid )
Prado.Element.focus(this.options.FocusElementID);
-
- this.visible = true;
},
refreshControlAndMessage : function()
@@ -676,21 +650,8 @@ Prado.WebUI.TBaseValidator.prototype =
*/
validate : function(invoker)
{
- //try to find the control.
- if(!this.control)
- this.control = $(this.options.ControlToValidate);
-
- if(!this.control)
- {
- this.isValid = true;
- return this.isValid;
- }
-
if(typeof(this.options.OnValidate) == "function")
- {
- if(this.requestDispatched == false)
- this.options.OnValidate(this, invoker);
- }
+ this.options.OnValidate(this, invoker);
if(this.enabled)
this.isValid = this.evaluateIsValid();
@@ -699,26 +660,20 @@ Prado.WebUI.TBaseValidator.prototype =
if(this.isValid)
{
- if(typeof(this.options.OnValidationSuccess) == "function")
+ if(typeof(this.options.OnSuccess) == "function")
{
- if(this.requestDispatched == false)
- {
- this.refreshControlAndMessage();
- this.options.OnValidationSuccess(this, invoker);
- }
+ this.refreshControlAndMessage();
+ this.options.OnSuccess(this, invoker);
}
else
this.updateControl();
}
else
{
- if(typeof(this.options.OnValidationError) == "function")
+ if(typeof(this.options.OnError) == "function")
{
- if(this.requestDispatched == false)
- {
- this.refreshControlAndMessage();
- this.options.OnValidationError(this, invoker)
- }
+ this.refreshControlAndMessage();
+ this.options.OnError(this, invoker);
}
else
this.updateControl();
@@ -1125,51 +1080,6 @@ Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
}
});
-/**
- * Uses callback request to perform validation.
- */
-Prado.WebUI.TActiveCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- validatingValue : null,
-
- /**
- * Calls custom validation function.
- */
- evaluateIsValid : function()
- {
- value = this.getValidationValue();
- if(!this.requestDispatched && value != this.validatingValue)
- {
- this.validatingValue = value;
- request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
- request.setCallbackParameter(value);
- request.setCausesValidation(false);
- request.options.onSuccess = this.callbackOnSuccess.bind(this);
- request.options.onFailure = this.callbackOnFailure.bind(this);
- request.dispatch();
- this.requestDispatched = true;
- return false;
- }
- return this.isValid;
- },
-
- callbackOnSuccess : function(request, data)
- {
- this.isValid = data;
- this.requestDispatched = false;
- if(typeof(this.options.onSuccess) == "function")
- this.options.onSuccess(request,data);
- Prado.Validation.validate(this.options.FormID, this.group,null);
- },
-
- callbackOnFailure : function(request, data)
- {
- this.requestDispatched = false;
- if(typeof(this.options.onFailure) == "function")
- this.options.onFailure(request,data);
- }
-});
-
/**
* TRangeValidator tests whether an input value is within a specified range.
*
diff --git a/framework/Web/Javascripts/prado/colorpicker/background.png b/framework/Web/Javascripts/prado/colorpicker/background.png
new file mode 100644
index 00000000..91798cf5
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/background.png differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/button.gif b/framework/Web/Javascripts/prado/colorpicker/button.gif
new file mode 100644
index 00000000..67f17975
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/button.gif differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/colorpicker.js b/framework/Web/Javascripts/prado/colorpicker/colorpicker.js
new file mode 100644
index 00000000..423338e0
--- /dev/null
+++ b/framework/Web/Javascripts/prado/colorpicker/colorpicker.js
@@ -0,0 +1,776 @@
+//-------------------- ricoColor.js
+if(typeof(Rico) == "undefined") Rico = {};
+
+Rico.Color = Class.create();
+
+Rico.Color.prototype = {
+
+ initialize: function(red, green, blue) {
+ this.rgb = { r: red, g : green, b : blue };
+ },
+
+ setRed: function(r) {
+ this.rgb.r = r;
+ },
+
+ setGreen: function(g) {
+ this.rgb.g = g;
+ },
+
+ setBlue: function(b) {
+ this.rgb.b = b;
+ },
+
+ setHue: function(h) {
+
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.h = h;
+
+ // convert back to RGB...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setSaturation: function(s) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.s = s;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setBrightness: function(b) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.b = b;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+ },
+
+ darken: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+ },
+
+ brighten: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+ },
+
+ blend: function(other) {
+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+ },
+
+ isBright: function() {
+ var hsb = this.asHSB();
+ return this.asHSB().b > 0.5;
+ },
+
+ isDark: function() {
+ return ! this.isBright();
+ },
+
+ asRGB: function() {
+ return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+ },
+
+ asHex: function() {
+ return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
+ },
+
+ asHSB: function() {
+ return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+ },
+
+ toString: function() {
+ return this.asHex();
+ }
+
+};
+
+Rico.Color.createFromHex = function(hexCode) {
+
+ if ( hexCode.indexOf('#') == 0 )
+ hexCode = hexCode.substring(1);
+
+ var red = "ff", green = "ff", blue="ff";
+ if(hexCode.length > 4)
+ {
+ red = hexCode.substring(0,2);
+ green = hexCode.substring(2,4);
+ blue = hexCode.substring(4,6);
+ }
+ else if(hexCode.length > 0 & hexCode.length < 4)
+ {
+ var r = hexCode.substring(0,1);
+ var g = hexCode.substring(1,2);
+ var b = hexCode.substring(2);
+ red = r+r;
+ green = g+g;
+ blue = b+b;
+ }
+ return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+}
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+ var actualColor = Element.getStyle($(elem), "background-color");
+ if ( actualColor == "transparent" && elem.parent )
+ return Rico.Color.createColorFromBackground(elem.parent);
+
+ if ( actualColor == null )
+ return new Rico.Color(255,255,255);
+
+ if ( actualColor.indexOf("rgb(") == 0 ) {
+ var colors = actualColor.substring(4, actualColor.length - 1 );
+ var colorArray = colors.split(",");
+ return new Rico.Color( parseInt( colorArray[0] ),
+ parseInt( colorArray[1] ),
+ parseInt( colorArray[2] ) );
+
+ }
+ else if ( actualColor.indexOf("#") == 0 ) {
+ return Rico.Color.createFromHex(actualColor);
+ }
+ else
+ return new Rico.Color(255,255,255);
+}
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ if (saturation == 0) {
+ red = parseInt(brightness * 255.0 + 0.5);
+ green = red;
+ blue = red;
+ }
+ else {
+ var h = (hue - Math.floor(hue)) * 6.0;
+ var f = h - Math.floor(h);
+ var p = brightness * (1.0 - saturation);
+ var q = brightness * (1.0 - saturation * f);
+ var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+ switch (parseInt(h)) {
+ case 0:
+ red = (brightness * 255.0 + 0.5);
+ green = (t * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 1:
+ red = (q * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 2:
+ red = (p * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (t * 255.0 + 0.5);
+ break;
+ case 3:
+ red = (p * 255.0 + 0.5);
+ green = (q * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 4:
+ red = (t * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 5:
+ red = (brightness * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (q * 255.0 + 0.5);
+ break;
+ }
+ }
+
+ return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+}
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+ var hue;
+ var saturaton;
+ var brightness;
+
+ var cmax = (r > g) ? r : g;
+ if (b > cmax)
+ cmax = b;
+
+ var cmin = (r < g) ? r : g;
+ if (b < cmin)
+ cmin = b;
+
+ brightness = cmax / 255.0;
+ if (cmax != 0)
+ saturation = (cmax - cmin)/cmax;
+ else
+ saturation = 0;
+
+ if (saturation == 0)
+ hue = 0;
+ else {
+ var redc = (cmax - r)/(cmax - cmin);
+ var greenc = (cmax - g)/(cmax - cmin);
+ var bluec = (cmax - b)/(cmax - cmin);
+
+ if (r == cmax)
+ hue = bluec - greenc;
+ else if (g == cmax)
+ hue = 2.0 + redc - bluec;
+ else
+ hue = 4.0 + greenc - redc;
+
+ hue = hue / 6.0;
+ if (hue < 0)
+ hue = hue + 1.0;
+ }
+
+ return { h : hue, s : saturation, b : brightness };
+}
+
+
+Prado.WebUI.TColorPicker = Class.create();
+
+Object.extend(Prado.WebUI.TColorPicker,
+{
+ palettes:
+ {
+ Small : [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"],
+ ["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"],
+ ["c0c0c0", "f00", "f90", "fc6", "ff0", "3f3", "6cc", "3cf", "66c", "c6c"],
+ ["999", "c00", "f60", "fc3", "fc0", "3c0", "0cc", "36f", "63f", "c3c"],
+ ["666", "900", "c60", "c93", "990", "090", "399", "33f", "60c", "939"],
+ ["333", "600", "930", "963", "660", "060", "366", "009", "339", "636"],
+ ["000", "300", "630", "633", "330", "030", "033", "006", "309", "303"]],
+
+ Tiny : [["ffffff"/*white*/, "00ff00"/*lime*/, "008000"/*green*/, "0000ff"/*blue*/],
+ ["c0c0c0"/*silver*/, "ffff00"/*yellow*/, "ff00ff"/*fuchsia*/, "000080"/*navy*/],
+ ["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]]
+ },
+
+ UIImages :
+ {
+ 'button.gif' : 'button.gif',
+// 'target_black.gif' : 'target_black.gif',
+// 'target_white.gif' : 'target_white.gif',
+ 'background.png' : 'background.png'
+// 'slider.gif' : 'slider.gif',
+// 'hue.gif' : 'hue.gif'
+ }
+});
+
+Object.extend(Prado.WebUI.TColorPicker.prototype,
+{
+ initialize : function(options)
+ {
+ var basics =
+ {
+ Palette : 'Small',
+ ClassName : 'TColorPicker',
+ Mode : 'Basic',
+ OKButtonText : 'OK',
+ CancelButtonText : 'Cancel',
+ ShowColorPicker : true
+ }
+
+ this.element = null;
+ this.showing = false;
+
+ options = Object.extend(basics, options);
+ this.options = options;
+ this.input = $(options['ID']);
+ this.button = $(options['ID']+'_button');
+ this._buttonOnClick = this.buttonOnClick.bind(this);
+ if(options['ShowColorPicker'])
+ Event.observe(this.button, "click", this._buttonOnClick);
+ Event.observe(this.input, "change", this.updatePicker.bind(this));
+ },
+
+ updatePicker : function(e)
+ {
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.button.style.backgroundColor = color.toString();
+ },
+
+ buttonOnClick : function(event)
+ {
+ var mode = this.options['Mode'];
+ if(this.element == null)
+ {
+ var constructor = mode == "Basic" ? "getBasicPickerContainer": "getFullPickerContainer"
+ this.element = this[constructor](this.options['ID'], this.options['Palette'])
+ this.input.parentNode.appendChild(this.element);
+ this.element.style.display = "none";
+
+ if(Prado.Browser().ie)
+ {
+ this.iePopUp = document.createElement('iframe');
+ this.iePopUp.src = Prado.WebUI.TColorPicker.UIImages['button.gif'];
+ this.iePopUp.style.position = "absolute"
+ this.iePopUp.scrolling="no"
+ this.iePopUp.frameBorder="0"
+ this.input.parentNode.appendChild(this.iePopUp);
+ }
+ if(mode == "Full")
+ this.initializeFullPicker();
+ }
+ this.show(mode);
+ },
+
+ show : function(type)
+ {
+ if(!this.showing)
+ {
+ var pos = Position.positionedOffset(this.input);
+ pos[1] += this.input.offsetHeight;
+
+ this.element.style.top = (pos[1]-1) + "px";
+ this.element.style.left = pos[0] + "px";
+ this.element.style.display = "block";
+
+ this.ieHack(type);
+
+ //observe for clicks on the document body
+ this._documentClickEvent = this.hideOnClick.bindEvent(this, type);
+ this._documentKeyDownEvent = this.keyPressed.bindEvent(this, type);
+ Event.observe(document.body, "click", this._documentClickEvent);
+ Event.observe(document,"keydown", this._documentKeyDownEvent);
+ this.showing = true;
+
+ if(type == "Full")
+ {
+ this.observeMouseMovement();
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.setColor(color,true);
+ }
+ }
+ },
+
+ hide : function(event)
+ {
+ if(this.showing)
+ {
+ if(this.iePopUp)
+ this.iePopUp.style.display = "none";
+
+ this.element.style.display = "none";
+ this.showing = false;
+ Event.stopObserving(document.body, "click", this._documentClickEvent);
+ Event.stopObserving(document,"keydown", this._documentKeyDownEvent);
+
+ if(this._observingMouseMove)
+ {
+ Event.stopObserving(document.body, "mousemove", this._onMouseMove);
+ this._observingMouseMove = false;
+ }
+ }
+ },
+
+ keyPressed : function(event,type)
+ {
+ if(Event.keyCode(event) == Event.KEY_ESC)
+ this.hide(event,type);
+ },
+
+ hideOnClick : function(ev)
+ {
+ if(!this.showing) return;
+ var el = Event.element(ev);
+ var within = false;
+ do
+ { within = within || String(el.className).indexOf('FullColorPicker') > -1
+ within = within || el == this.button;
+ within = within || el == this.input;
+ if(within) break;
+ el = el.parentNode;
+ }
+ while(el);
+ if(!within) this.hide(ev);
+ },
+
+ ieHack : function()
+ {
+ // IE hack
+ if(this.iePopUp)
+ {
+ this.iePopUp.style.display = "block";
+ this.iePopUp.style.top = (this.element.offsetTop) + "px";
+ this.iePopUp.style.left = (this.element.offsetLeft)+ "px";
+ this.iePopUp.style.width = Math.abs(this.element.offsetWidth)+ "px";
+ this.iePopUp.style.height = (this.element.offsetHeight + 1)+ "px";
+ }
+ },
+
+ getBasicPickerContainer : function(pickerID, palette)
+ {
+ var table = TABLE({className:'basic_colors palette_'+palette},TBODY());
+ var colors = Prado.WebUI.TColorPicker.palettes[palette];
+ var pickerOnClick = this.cellOnClick.bind(this);
+ colors.each(function(color)
+ {
+ var row = document.createElement("tr");
+ color.each(function(c)
+ {
+ var td = document.createElement("td");
+ var img = IMG({src:Prado.WebUI.TColorPicker.UIImages['button.gif'],width:16,height:16});
+ img.style.backgroundColor = "#"+c;
+ Event.observe(img,"click", pickerOnClick);
+ Event.observe(img,"mouseover", function(e)
+ {
+ Element.addClassName(Event.element(e), "pickerhover");
+ });
+ Event.observe(img,"mouseout", function(e)
+ {
+ Element.removeClassName(Event.element(e), "pickerhover");
+ });
+ td.appendChild(img);
+ row.appendChild(td);
+ });
+ table.childNodes[0].appendChild(row);
+ });
+ return DIV({className:this.options['ClassName']+" BasicColorPicker",
+ id:pickerID+"_picker"}, table);
+ },
+
+ cellOnClick : function(e)
+ {
+ var el = Event.element(e);
+ if(el.tagName.toLowerCase() != "img")
+ return;
+ var color = Rico.Color.createColorFromBackground(el);
+ this.updateColor(color);
+ },
+
+ updateColor : function(color)
+ {
+ this.input.value = color.toString().toUpperCase();
+ this.button.style.backgroundColor = color.toString();
+ if(typeof(this.onChange) == "function")
+ this.onChange(color);
+ },
+
+ getFullPickerContainer : function(pickerID)
+ {
+ //create the 3 buttons
+ this.buttons =
+ {
+ //Less : INPUT({value:'Less Colors', className:'button', type:'button'}),
+ OK : INPUT({value:this.options.OKButtonText, className:'button', type:'button'}),
+ Cancel : INPUT({value:this.options.CancelButtonText, className:'button', type:'button'})
+ };
+
+ //create the 6 inputs
+ var inputs = {};
+ ['H','S','V','R','G','B'].each(function(type)
+ {
+ inputs[type] = INPUT({type:'text',size:'3',maxlength:'3'});
+ });
+
+ //create the HEX input
+ inputs['HEX'] = INPUT({className:'hex',type:'text',size:'6',maxlength:'6'});
+ this.inputs = inputs;
+
+ var images = Prado.WebUI.TColorPicker.UIImages;
+
+ this.inputs['currentColor'] = SPAN({className:'currentColor'});
+ this.inputs['oldColor'] = SPAN({className:'oldColor'});
+
+ var inputsTable =
+ TABLE({className:'inputs'}, TBODY(null,
+ TR(null,
+ TD({className:'currentcolor',colSpan:2},
+ this.inputs['currentColor'], this.inputs['oldColor'])),
+
+ TR(null,
+ TD(null,'H:'),
+ TD(null,this.inputs['H'], '??')),
+
+ TR(null,
+ TD(null,'S:'),
+ TD(null,this.inputs['S'], '%')),
+
+ TR(null,
+ TD(null,'V:'),
+ TD(null,this.inputs['V'], '%')),
+
+ TR(null,
+ TD({className:'gap'},'R:'),
+ TD({className:'gap'},this.inputs['R'])),
+
+ TR(null,
+ TD(null,'G:'),
+ TD(null, this.inputs['G'])),
+
+ TR(null,
+ TD(null,'B:'),
+ TD(null, this.inputs['B'])),
+
+ TR(null,
+ TD({className:'gap'},'#'),
+ TD({className:'gap'},this.inputs['HEX']))
+ ));
+
+ var UIimages =
+ {
+ selector : SPAN({className:'selector'}),
+ background : SPAN({className:'colorpanel'}),
+ slider : SPAN({className:'slider'}),
+ hue : SPAN({className:'strip'})
+ }
+
+ //png alpha channels for IE
+ if(Prado.Browser().ie)
+ {
+ var filter = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader";
+ UIimages['background'] = SPAN({className:'colorpanel',style:filter+"(src='"+images['background.png']+"' sizingMethod=scale);"})
+ }
+
+ this.inputs = Object.extend(this.inputs, UIimages);
+
+ var pickerTable =
+ TABLE(null,TBODY(null,
+ TR({className:'selection'},
+ TD({className:'colors'},UIimages['selector'],UIimages['background']),
+ TD({className:'hue'},UIimages['slider'],UIimages['hue']),
+ TD({className:'inputs'}, inputsTable)
+ ),
+ TR({className:'options'},
+ TD({colSpan:3},
+ this.buttons['OK'],
+ this.buttons['Cancel'])
+ )
+ ));
+
+ return DIV({className:this.options['ClassName']+" FullColorPicker",
+ id:pickerID+"_picker"},pickerTable);
+ },
+
+ initializeFullPicker : function()
+ {
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.setColor(color,true);
+
+ var i = 0;
+ for(var type in this.inputs)
+ {
+ Event.observe(this.inputs[type], "change",
+ this.onInputChanged.bindEvent(this,type));
+ i++;
+
+ if(i > 6) break;
+ }
+
+ this.isMouseDownOnColor = false;
+ this.isMouseDownOnHue = false;
+
+ this._onColorMouseDown = this.onColorMouseDown.bind(this);
+ this._onHueMouseDown = this.onHueMouseDown.bind(this);
+ this._onMouseUp = this.onMouseUp.bind(this);
+ this._onMouseMove = this.onMouseMove.bind(this);
+
+ Event.observe(this.inputs.background, "mousedown", this._onColorMouseDown);
+ Event.observe(this.inputs.selector, "mousedown", this._onColorMouseDown);
+ Event.observe(this.inputs.hue, "mousedown", this._onHueMouseDown);
+ Event.observe(this.inputs.slider, "mousedown", this._onHueMouseDown);
+
+ Event.observe(document.body, "mouseup", this._onMouseUp);
+
+ this.observeMouseMovement();
+
+ Event.observe(this.buttons.Cancel, "click", this.hide.bindEvent(this,this.options['Mode']));
+ Event.observe(this.buttons.OK, "click", this.onOKClicked.bind(this));
+ },
+
+ observeMouseMovement : function()
+ {
+ if(!this._observingMouseMove)
+ {
+ Event.observe(document.body, "mousemove", this._onMouseMove);
+ this._observingMouseMove = true;
+ }
+ },
+
+ onColorMouseDown : function(ev)
+ {
+ this.isMouseDownOnColor = true;
+ this.onMouseMove(ev);
+ Event.stop(ev);
+ },
+
+ onHueMouseDown : function(ev)
+ {
+ this.isMouseDownOnHue = true;
+ this.onMouseMove(ev);
+ Event.stop(ev);
+ },
+
+ onMouseUp : function(ev)
+ {
+ this.isMouseDownOnColor = false;
+ this.isMouseDownOnHue = false;
+ Event.stop(ev);
+ },
+
+ onMouseMove : function(ev)
+ {
+ if(this.isMouseDownOnColor)
+ this.changeSV(ev);
+ if(this.isMouseDownOnHue)
+ this.changeH(ev);
+ Event.stop(ev);
+ },
+
+ changeSV : function(ev)
+ {
+ var px = Event.pointerX(ev);
+ var py = Event.pointerY(ev);
+ var pos = Position.cumulativeOffset(this.inputs.background);
+
+ var x = this.truncate(px - pos[0],0,255);
+ var y = this.truncate(py - pos[1],0,255);
+
+
+ var s = x/255;
+ var b = (255-y)/255;
+
+ var current_s = parseInt(this.inputs.S.value);
+ var current_b = parseInt(this.inputs.V.value);
+
+ if(current_s == parseInt(s*100) && current_b == parseInt(b*100)) return;
+
+ var h = this.truncate(this.inputs.H.value,0,360)/360;
+
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+
+
+ this.inputs.selector.style.left = x+"px";
+ this.inputs.selector.style.top = y+"px";
+
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+
+ return this.setColor(color);
+ },
+
+ changeH : function(ev)
+ {
+ var py = Event.pointerY(ev);
+ var pos = Position.cumulativeOffset(this.inputs.background);
+ var y = this.truncate(py - pos[1],0,255);
+
+ var h = (255-y)/255;
+ var current_h = this.truncate(this.inputs.H.value,0,360);
+ current_h = current_h == 0 ? 360 : current_h;
+ if(current_h == parseInt(h*360)) return;
+
+ var s = parseInt(this.inputs.S.value)/100;
+ var b = parseInt(this.inputs.V.value)/100;
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+
+ var hue = new Rico.Color(color.rgb.r,color.rgb.g,color.rgb.b);
+ hue.setSaturation(1); hue.setBrightness(1);
+
+ this.inputs.background.style.backgroundColor = hue.asHex();
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+
+ this.inputs.slider.style.top = this.truncate(y,0,255)+"px";
+ return this.setColor(color);
+
+ },
+
+ onOKClicked : function(ev)
+ {
+ var r = this.truncate(this.inputs.R.value,0,255);///255;
+ var g = this.truncate(this.inputs.G.value,0,255);///255;
+ var b = this.truncate(this.inputs.B.value,0,255);///255;
+ var color = new Rico.Color(r,g,b);
+ this.updateColor(color);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.hide(ev);
+ },
+
+ onInputChanged : function(ev, type)
+ {
+ if(this.isMouseDownOnColor || isMouseDownOnHue)
+ return;
+
+
+ switch(type)
+ {
+ case "H": case "S": case "V":
+ var h = this.truncate(this.inputs.H.value,0,360)/360;
+ var s = this.truncate(this.inputs.S.value,0,100)/100;
+ var b = this.truncate(this.inputs.V.value,0,100)/100;
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+ return this.setColor(color,true);
+ case "R": case "G": case "B":
+ var r = this.truncate(this.inputs.R.value,0,255);///255;
+ var g = this.truncate(this.inputs.G.value,0,255);///255;
+ var b = this.truncate(this.inputs.B.value,0,255);///255;
+ var color = new Rico.Color(r,g,b);
+ return this.setColor(color,true);
+ case "HEX":
+ var color = Rico.Color.createFromHex(this.inputs.HEX.value);
+ return this.setColor(color,true);
+ }
+ },
+
+ setColor : function(color, update)
+ {
+ var hsb = color.asHSB();
+
+ this.inputs.H.value = parseInt(hsb.h*360);
+ this.inputs.S.value = parseInt(hsb.s*100);
+ this.inputs.V.value = parseInt(hsb.b*100);
+ this.inputs.R.value = color.rgb.r;
+ this.inputs.G.value = color.rgb.g;
+ this.inputs.B.value = color.rgb.b;
+ this.inputs.HEX.value = color.asHex().substring(1).toUpperCase();
+
+ var images = Prado.WebUI.TColorPicker.UIImages;
+
+ var changeCss = color.isBright() ? 'removeClassName' : 'addClassName';
+ Element[changeCss](this.inputs.selector, 'target_white');
+
+ if(update)
+ this.updateSelectors(color);
+ },
+
+ updateSelectors : function(color)
+ {
+ var hsb = color.asHSB();
+ var pos = [hsb.s*255, hsb.b*255, hsb.h*255];
+
+ this.inputs.selector.style.left = this.truncate(pos[0],0,255)+"px";
+ this.inputs.selector.style.top = this.truncate(255-pos[1],0,255)+"px";
+ this.inputs.slider.style.top = this.truncate(255-pos[2],0,255)+"px";
+
+ var hue = new Rico.Color(color.rgb.r,color.rgb.g,color.rgb.b);
+ hue.setSaturation(1); hue.setBrightness(1);
+ this.inputs.background.style.backgroundColor = hue.asHex();
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+ },
+
+ truncate : function(value, min, max)
+ {
+ value = parseInt(value);
+ return value < min ? min : value > max ? max : value;
+ }
+});
diff --git a/framework/Web/Javascripts/prado/colorpicker/default.css b/framework/Web/Javascripts/prado/colorpicker/default.css
new file mode 100644
index 00000000..67235c08
--- /dev/null
+++ b/framework/Web/Javascripts/prado/colorpicker/default.css
@@ -0,0 +1,258 @@
+
+/** Colors **/
+
+.TColorPicker_button
+{
+ border: 1px solid #919EA9;
+ background-color: #fff;
+}
+
+.TColorPicker
+{
+ background-color: white;
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker
+{
+ width: 388px;
+}
+
+.BasicColorPicker .basic_colors td img
+{
+ border: 1px solid #919EA9;
+}
+
+.BasicColorPicker .basic_colors .pickerhover
+{
+ border-color: white;
+}
+
+.FullColorPicker .colors .colorpanel
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .hue .strip
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .inputs .currentcolor span
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .options td
+{
+ border-top: 1px solid #919EA9;
+}
+
+/** UI **/
+.TColorPicker_button
+{
+ position: absolute;
+ font-size: 0;
+ padding: 1px;
+ margin-left: 1px;
+}
+
+.TColorPicker_button img
+{
+ width: 18px;
+ height: 18px;
+}
+
+* html .TColorPicker_button
+{
+ margin-top: 1px;
+}
+
+.TColorPicker
+{
+ position: absolute;
+}
+
+.BasicColorPicker .palette_Tiny img
+{
+ width: 30px;
+ height: 30px;
+}
+.BasicColorPicker .basic_colors
+{
+ border-collapse: separate;
+ border-spacing: 2px;
+}
+
+.BasicColorPicker .basic_colors td
+{
+ padding: 0;
+ font-size: 0;
+}
+
+.FullColorPicker table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.FullColorPicker .colors .colorpanel
+{
+ margin-left: 7px;
+ margin-top: -9px;
+ display: block;
+ width:256px;
+ height:256px;
+ background-image: url(background.png);
+}
+
+* html .FullColorPicker .colors .colorpanel
+{
+ background-image: none;
+ margin-top: -10px;
+}
+
+.FullColorPicker .colors
+{
+ padding-bottom: 10px;
+ padding-top: 17px;
+}
+
+* html .FullColorPicker .colors
+{
+ margin-top: 10px;
+}
+
+.FullColorPicker .colors .selector
+{
+ position: relative;
+ top: 0px;
+ left: 0px;
+ border: 0 none;
+ float: left;
+ margin-left: 2px;
+ margin-top: -12px;
+ display: block;
+ background-image: url(target_black.gif);
+ background-repeat: no-repeat;
+ width: 8px;
+ height:8px;
+ background-position: 50%
+}
+
+* html .FullColorPicker .colors .selector
+{
+ margin-top: -16px;
+}
+
+.FullColorPicker .colors span.target_white
+{
+ background-image: url(target_white.gif);
+}
+
+.FullColorPicker .hue
+{
+ text-align: center;
+ width: 50px;
+}
+
+.FullColorPicker .hue .strip
+{
+ margin-top: -5px;
+ margin-left: 9px;
+ display: block;
+ background-image: url(hue.gif);
+ width:19px;
+ height:256px;
+}
+
+* html .FullColorPicker .hue .strip
+{
+ margin-left: 10px;
+}
+
+.FullColorPicker .slider
+{
+ position: relative;
+ top: 0px;
+ margin-top: -5px;
+ background-image: url(slider.gif);
+ width: 40px;
+ height: 9px;
+ font-size: 0;
+ display: block;
+}
+
+* html .FullColorPicker .slider
+{
+ margin-left: 10px;
+}
+
+.FullColorPicker .inputs
+{
+ font-family: Tahoma;
+ font-size: 10pt;
+}
+
+.FullColorPicker .inputs input
+{
+ width: 30px;
+ text-align: center;
+ height: 16px;
+ margin-right: 2px;
+}
+
+.FullColorPicker .currentcolor
+{
+ text-align: center;
+}
+
+.FullColorPicker .inputs .currentcolor span
+{
+ display: block;
+ width: 60px;
+ height: 30px;
+}
+
+.FullColorPicker .inputs .currentcolor span.currentColor
+{
+ margin: 5px 5px 0 2px;
+ border-bottom: 0 none;
+}
+
+.FullColorPicker .inputs .currentcolor span.oldColor
+{
+ margin: 0px 5px 5px 2px;
+ border-top: 0 none;
+}
+
+.FullColorPicker input.hex
+{
+ width: 50px;
+ margin-right: 5px;
+}
+
+.FullColorPicker input.button
+{
+ width: 90px;
+ margin: 3px;
+ font-size: 10px;
+}
+
+.FullColorPicker .inputs .gap
+{
+ padding-top: 8px;
+}
+
+.FullColorPicker .customs
+{
+ width: 100%;
+ border-collapse: separate;
+}
+
+.FullColorPicker .options td
+{
+ height: 0px;
+ text-align: right;
+ padding: 7px 10px 7px 0px;
+}
\ No newline at end of file
diff --git a/framework/Web/Javascripts/prado/colorpicker/hue.gif b/framework/Web/Javascripts/prado/colorpicker/hue.gif
new file mode 100644
index 00000000..901e409c
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/hue.gif differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/slider.gif b/framework/Web/Javascripts/prado/colorpicker/slider.gif
new file mode 100644
index 00000000..92f9d744
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/slider.gif differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/spacer.gif b/framework/Web/Javascripts/prado/colorpicker/spacer.gif
new file mode 100755
index 00000000..fc256098
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/spacer.gif differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/target_black.gif b/framework/Web/Javascripts/prado/colorpicker/target_black.gif
new file mode 100644
index 00000000..ebb89f58
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/target_black.gif differ
diff --git a/framework/Web/Javascripts/prado/colorpicker/target_white.gif b/framework/Web/Javascripts/prado/colorpicker/target_white.gif
new file mode 100644
index 00000000..c3527c86
Binary files /dev/null and b/framework/Web/Javascripts/prado/colorpicker/target_white.gif differ
diff --git a/framework/Web/Javascripts/prado/controls.js b/framework/Web/Javascripts/prado/controls.js
deleted file mode 100644
index 64fb1a30..00000000
--- a/framework/Web/Javascripts/prado/controls.js
+++ /dev/null
@@ -1,290 +0,0 @@
-Prado.WebUI = Class.create();
-
-Prado.WebUI.PostBackControl = Class.create();
-
-Prado.WebUI.PostBackControl.prototype =
-{
- initialize : function(options)
- {
- this._elementOnClick = null, //capture the element's onclick function
-
- this.element = $(options.ID);
- if(this.element)
- {
- if(this.onInit)
- this.onInit(options);
- }
- },
-
- onInit : function(options)
- {
- if(typeof(this.element.onclick)=="function")
- {
- this._elementOnClick = this.element.onclick;
- this.element.onclick = null;
- }
- Event.observe(this.element, "click", this.elementClicked.bindEvent(this,options));
- },
-
- elementClicked : function(event, options)
- {
- var src = Event.element(event);
- var doPostBack = true;
- var onclicked = null;
-
- if(this._elementOnClick)
- {
- var onclicked = this._elementOnClick(event);
- if(typeof(onclicked) == "boolean")
- doPostBack = onclicked;
- }
- if(doPostBack)
- this.onPostBack(event,options);
- if(typeof(onclicked) == "boolean" && !onclicked)
- Event.stop(event);
- },
-
- onPostBack : function(event, options)
- {
- Prado.PostBack(event,options);
- }
-};
-
-Prado.WebUI.TButton = Class.extend(Prado.WebUI.PostBackControl);
-Prado.WebUI.TLinkButton = Class.extend(Prado.WebUI.PostBackControl);
-Prado.WebUI.TCheckBox = Class.extend(Prado.WebUI.PostBackControl);
-Prado.WebUI.TBulletedList = Class.extend(Prado.WebUI.PostBackControl);
-Prado.WebUI.TImageMap = Class.extend(Prado.WebUI.PostBackControl);
-
-/**
- * TImageButton client-side behaviour. With validation, Firefox needs
- * to capture the x,y point of the clicked image in hidden form fields.
- */
-Prado.WebUI.TImageButton = Class.extend(Prado.WebUI.PostBackControl);
-Object.extend(Prado.WebUI.TImageButton.prototype,
-{
- /**
- * Override parent onPostBack function, tried to add hidden forms
- * inputs to capture x,y clicked point.
- */
- onPostBack : function(event, options)
- {
- if(!this.hasXYInput)
- {
- this.addXYInput(event,options);
- this.hasXYInput = true;
- }
- Prado.PostBack(event, options);
- },
-
- /**
- * Add hidden inputs to capture the x,y point clicked on the image.
- * @param event DOM click event.
- * @param array image button options.
- */
- addXYInput : function(event,options)
- {
- imagePos = Position.cumulativeOffset(this.element);
- clickedPos = [event.clientX, event.clientY];
- x = clickedPos[0]-imagePos[0]+1;
- y = clickedPos[1]-imagePos[1]+1;
- x = x < 0 ? 0 : x;
- y = y < 0 ? 0 : y;
- id = options['EventTarget'];
- x_input = $(id+"_x");
- y_input = $(id+"_y");
- if(x_input)
- {
- x_input.value = x;
- }
- else
- {
- x_input = INPUT({type:'hidden',name:id+'_x','id':id+'_x',value:x});
- this.element.parentNode.appendChild(x_input);
- }
- if(y_input)
- {
- y_input.value = y;
- }
- else
- {
- y_input = INPUT({type:'hidden',name:id+'_y','id':id+'_y',value:y});
- this.element.parentNode.appendChild(y_input);
- }
- }
-});
-
-
-/**
- * Radio button, only initialize if not already checked.
- */
-Prado.WebUI.TRadioButton = Class.extend(Prado.WebUI.PostBackControl);
-Prado.WebUI.TRadioButton.prototype.onRadioButtonInitialize = Prado.WebUI.TRadioButton.prototype.initialize;
-Object.extend(Prado.WebUI.TRadioButton.prototype,
-{
- initialize : function(options)
- {
- this.element = $(options['ID']);
- if(this.element)
- {
- if(!this.element.checked)
- this.onRadioButtonInitialize(options);
- }
- }
-});
-
-
-Prado.WebUI.TTextBox = Class.extend(Prado.WebUI.PostBackControl,
-{
- onInit : function(options)
- {
- this.options=options;
- if(options['TextMode'] != 'MultiLine')
- Event.observe(this.element, "keydown", this.handleReturnKey.bind(this));
- if(this.options['AutoPostBack']==true)
- Event.observe(this.element, "change", Prado.PostBack.bindEvent(this,options));
- },
-
- handleReturnKey : function(e)
- {
- if(Event.keyCode(e) == Event.KEY_RETURN)
- {
- var target = Event.element(e);
- if(target)
- {
- if(this.options['AutoPostBack']==true)
- {
- Event.fireEvent(target, "change");
- Event.stop(e);
- }
- else
- {
- if(this.options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
- {
- if(!Prado.Validation.validate(this.options['FormID'], this.options['ValidationGroup'], $(this.options['ID'])))
- return Event.stop(e);
- }
- }
- }
- }
- }
-});
-
-Prado.WebUI.TListControl = Class.extend(Prado.WebUI.PostBackControl,
-{
- onInit : function(options)
- {
- Event.observe(this.element, "change", Prado.PostBack.bindEvent(this,options));
- }
-});
-
-Prado.WebUI.TListBox = Class.extend(Prado.WebUI.TListControl);
-Prado.WebUI.TDropDownList = Class.extend(Prado.WebUI.TListControl);
-
-Prado.WebUI.DefaultButton = Class.create();
-Prado.WebUI.DefaultButton.prototype =
-{
- initialize : function(options)
- {
- this.options = options;
- this._event = this.triggerEvent.bindEvent(this);
- Event.observe(options['Panel'], 'keydown', this._event);
- },
-
- triggerEvent : function(ev, target)
- {
- var enterPressed = Event.keyCode(ev) == Event.KEY_RETURN;
- var isTextArea = Event.element(ev).tagName.toLowerCase() == "textarea";
- if(enterPressed && !isTextArea)
- {
- var defaultButton = $(this.options['Target']);
- if(defaultButton)
- {
- this.triggered = true;
- $('PRADO_POSTBACK_TARGET').value = this.options.EventTarget;
- Event.fireEvent(defaultButton, this.options['Event']);
- Event.stop(ev);
- }
- }
- }
-};
-
-Prado.WebUI.TTextHighlighter=Class.create();
-Prado.WebUI.TTextHighlighter.prototype=
-{
- initialize:function(id)
- {
- if(!window.clipboardData) return;
- var options =
- {
- href : 'javascript:;/'+'/copy code to clipboard',
- onclick : 'Prado.WebUI.TTextHighlighter.copy(this)',
- onmouseover : 'Prado.WebUI.TTextHighlighter.hover(this)',
- onmouseout : 'Prado.WebUI.TTextHighlighter.out(this)'
- }
- var div = DIV({className:'copycode'}, A(options, 'Copy Code'));
- document.write(DIV(null,div).innerHTML);
- }
-};
-
-Object.extend(Prado.WebUI.TTextHighlighter,
-{
- copy : function(obj)
- {
- var parent = obj.parentNode.parentNode.parentNode;
- var text = '';
- for(var i = 0; i < parent.childNodes.length; i++)
- {
- var node = parent.childNodes[i];
- if(node.innerText)
- text += node.innerText == 'Copy Code' ? '' : node.innerText;
- else
- text += node.nodeValue;
- }
- if(text.length > 0)
- window.clipboardData.setData("Text", text);
- },
-
- hover : function(obj)
- {
- obj.parentNode.className = "copycode copycode_hover";
- },
-
- out : function(obj)
- {
- obj.parentNode.className = "copycode";
- }
-});
-
-
-Prado.WebUI.TCheckBoxList = Base.extend(
-{
- constructor : function(options)
- {
- for(var i = 0; i" + message + "
"
+
+ if (shouldScroll) {
+ this.outputElement.scrollTop = this.outputElement.scrollHeight
+ }
+ },
+
+ updateTags : function() {
+ var pattern = this.tagFilterElement.value
+
+ if (this.tagPattern == pattern) return
+
+ try {
+ new RegExp(pattern)
+ }
+ catch (e) {
+ return
+ }
+
+ this.tagPattern = pattern
+ Cookie.set('tagPattern', this.tagPattern)
+
+ this.outputElement.innerHTML = ""
+
+ // Go through each log entry again
+ this.outputCount = 0;
+ for (var i = 0; i < Logger.logEntries.length; i++) {
+ this.logUpdate(Logger.logEntries[i])
+ }
+ },
+
+ repositionWindow : function() {
+ var offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
+ var pageHeight = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+ this.logElement.style.top = (offset + pageHeight - Element.getHeight(this.logElement)) + "px"
+ },
+
+ // Event Handlers
+ // --------------
+
+ logUpdate : function(logEntry) {
+ if (logEntry.tag.search(new RegExp(this.tagPattern, 'igm')) == -1) return
+ var style = ''
+ if (logEntry.tag.search(/error/) != -1) style += 'color:red'
+ else if (logEntry.tag.search(/warning/) != -1) style += 'color:orange'
+ else if (logEntry.tag.search(/debug/) != -1) style += 'color:green'
+ else if (logEntry.tag.search(/info/) != -1) style += 'color:white'
+ else style += 'color:yellow'
+
+ this.output(logEntry.message, style)
+ },
+
+ clear : function(e) {
+ this.outputElement.innerHTML = ""
+ },
+
+ handleInput : function(e) {
+ if (e.keyCode == Event.KEY_RETURN ) {
+ var command = this.inputElement.value
+
+ switch(command) {
+ case "clear":
+ Logger.clear()
+ break
+
+ default:
+ var consoleOutput = ""
+
+ try {
+ consoleOutput = eval(this.inputElement.value)
+ }
+ catch (e) {
+ Logger.error("Problem parsing input <" + command + ">", e)
+ break
+ }
+
+ Logger.log(consoleOutput)
+ break
+ }
+
+ if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
+ this.commandHistory.unshift(this.inputElement.value)
+ }
+
+ this.commandIndex = 0
+ this.inputElement.value = ""
+ }
+ else if (e.keyCode == Event.KEY_UP && this.commandHistory.length > 0) {
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+
+ if (this.commandIndex < this.commandHistory.length - 1) {
+ this.commandIndex += 1
+ }
+ }
+ else if (e.keyCode == Event.KEY_DOWN && this.commandHistory.length > 0) {
+ if (this.commandIndex > 0) {
+ this.commandIndex -= 1
+ }
+
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+ }
+ else {
+ this.commandIndex = 0
+ }
+ }
+}
+
+
+// -------------------------
+// Helper Functions And Junk
+// -------------------------
+function inspect(o)
+{
+ var objtype = typeof(o);
+ if (objtype == "undefined") {
+ return "undefined";
+ } else if (objtype == "number" || objtype == "boolean") {
+ return o + "";
+ } else if (o === null) {
+ return "null";
+ }
+
+ try {
+ var ostring = (o + "");
+ } catch (e) {
+ return "[" + typeof(o) + "]";
+ }
+
+ if (typeof(o) == "function")
+ {
+ o = ostring.replace(/^\s+/, "");
+ var idx = o.indexOf("{");
+ if (idx != -1) {
+ o = o.substr(0, idx) + "{...}";
+ }
+ return o;
+ }
+
+ var reprString = function (o)
+ {
+ return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
+ ).replace(/[\f]/g, "\\f"
+ ).replace(/[\b]/g, "\\b"
+ ).replace(/[\n]/g, "\\n"
+ ).replace(/[\t]/g, "\\t"
+ ).replace(/[\r]/g, "\\r");
+ };
+
+ if (objtype == "string") {
+ return reprString(o);
+ }
+ // recurse
+ var me = arguments.callee;
+ // short-circuit for objects that support "json" serialization
+ // if they return "self" then just pass-through...
+ var newObj;
+ if (typeof(o.__json__) == "function") {
+ newObj = o.__json__();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ if (typeof(o.json) == "function") {
+ newObj = o.json();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ // array
+ if (objtype != "function" && typeof(o.length) == "number") {
+ var res = [];
+ for (var i = 0; i < o.length; i++) {
+ var val = me(o[i]);
+ if (typeof(val) != "string") {
+ val = "undefined";
+ }
+ res.push(val);
+ }
+ return "[" + res.join(", ") + "]";
+ }
+
+ // generic object code path
+ res = [];
+ for (var k in o) {
+ var useKey;
+ if (typeof(k) == "number") {
+ useKey = '"' + k + '"';
+ } else if (typeof(k) == "string") {
+ useKey = reprString(k);
+ } else {
+ // skip non-string or number keys
+ continue;
+ }
+ val = me(o[k]);
+ if (typeof(val) != "string") {
+ // skip non-serializable values
+ continue;
+ }
+ res.push(useKey + ":" + val);
+ }
+ return "{" + res.join(", ") + "}";
+}
+
+Array.prototype.contains = function(object) {
+ for(var i = 0; i < this.length; i++) {
+ if (object == this[i]) return true
+ }
+
+ return false
+}
+
+// Helper Alias for simple logging
+var puts = function() {return Logger.log(arguments[0], arguments[1])}
+
+/*************************************
+
+ Javascript Object Tree
+ version 1.0
+ last revision:04.11.2004
+ steve@slayeroffice.com
+ http://slayeroffice.com
+
+ (c)2004 S.G. Chipman
+
+ Please notify me of any modifications
+ you make to this code so that I can
+ update the version hosted on slayeroffice.com
+
+
+************************************/
+if(typeof Prado == "undefined")
+ var Prado = {};
+Prado.Inspector =
+{
+ d : document,
+ types : new Array(),
+ objs : new Array(),
+ hidden : new Array(),
+ opera : window.opera,
+ displaying : '',
+ nameList : new Array(),
+
+ format : function(str) {
+ if(typeof(str) != "string") return str;
+ str=str.replace(//g,">");
+ return str;
+ },
+
+ parseJS : function(obj) {
+ var name;
+ if(typeof obj == "string") { name = obj; obj = eval(obj); }
+ win= typeof obj == 'undefined' ? window : obj;
+ this.displaying = name ? name : win.toString();
+ for(js in win) {
+ try {
+ if(win[js] && js.toString().indexOf("Inspector")==-1 && (win[js]+"").indexOf("[native code]")==-1) {
+
+ t=typeof(win[js]);
+ if(!this.objs[t.toString()]) {
+ this.types[this.types.length]=t;
+ this.objs[t]={};
+ this.nameList[t] = new Array();
+ }
+ this.nameList[t].push(js);
+ this.objs[t][js] = this.format(win[js]+"");
+ }
+ } catch(err) { }
+ }
+
+ for(i=0;i";
+ this.types.sort();
+ var so_objIndex=0;
+ for(i=0;i
";
+ this.d.getElementById("so_mContainer").innerHTML =mHTML;
+ },
+
+ handleKeyEvent : function(e) {
+ keyCode=document.all?window.event.keyCode:e.keyCode;
+ if(keyCode==27) {
+ this.cleanUp();
+ }
+ },
+
+ cleanUp : function()
+ {
+ if(this.d.getElementById("so_mContainer"))
+ {
+ this.d.body.removeChild(this.d.getElementById("so_mContainer"));
+ this.d.body.removeChild(this.d.getElementById("so_mStyle"));
+ if(typeof Event != "undefined")
+ Event.stopObserving(this.d, "keydown", this.dKeyDownEvent);
+ this.types = new Array();
+ this.objs = new Array();
+ this.hidden = new Array();
+ }
+ },
+
+ disabled : document.all && !this.opera,
+
+ inspect : function(obj)
+ {
+ if(this.disabled)return alert("Sorry, this only works in Mozilla and Firefox currently.");
+ this.cleanUp();
+ mObj=this.d.body.appendChild(this.d.createElement("div"));
+ mObj.id="so_mContainer";
+ sObj=this.d.body.appendChild(this.d.createElement("style"));
+ sObj.id="so_mStyle";
+ sObj.type="text/css";
+ sObj.innerHTML = this.style;
+ this.dKeyDownEvent = this.handleKeyEvent.bind(this);
+ if(typeof Event != "undefined")
+ Event.observe(this.d, "keydown", this.dKeyDownEvent);
+
+ this.parseJS(obj);
+ this.buildTree();
+
+ cObj=mObj.appendChild(this.d.createElement("div"));
+ cObj.className="credits";
+ cObj.innerHTML = "[esc] to close
Javascript Object Tree V2.0.";
+
+ window.scrollTo(0,0);
+ },
+
+ style : "#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000; color:#000; } " +
+ "#so_mContainer ul { padding-left:20px; } " +
+ "#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } " +
+ "#so_mContainer li:hover { background-color:#E3EBED; } " +
+ "#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } " +
+ "#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } " +
+ "#so_mContainer .topLevel { margin:0; padding:0; } " +
+ "#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } " +
+ "#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"
+}
+
+//similar function to var_dump in PHP, brings up the javascript object tree UI.
+function var_dump(obj)
+{
+ Prado.Inspector.inspect(obj);
+}
+
+//similar function to print_r for PHP
+var print_r = inspect;
+
diff --git a/framework/Web/Javascripts/prado/ratings/blocks.css b/framework/Web/Javascripts/prado/ratings/blocks.css
new file mode 100644
index 00000000..2bf2e904
--- /dev/null
+++ b/framework/Web/Javascripts/prado/ratings/blocks.css
@@ -0,0 +1,29 @@
+.TRatingList_blocks
+{
+ border-collapse: collapse;
+}
+.TRatingList_blocks input, .TRatingList_blocks label
+{
+ display: none;
+}
+.TRatingList_blocks td
+{
+ width: 17px;
+ height: 18px;
+ background-image: url(blocks_blank.gif);
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+.TRatingList_blocks td.rating_selected
+{
+ background-image: url(blocks_selected.gif);
+}
+
+.TRatingList_blocks td.rating_hover
+{
+ background-image: url(blocks_hover.gif);
+}
+.TRatingList_blocks td.rating_half
+{
+ background-image: url(blocks_half.gif);
+}
diff --git a/framework/Web/Javascripts/prado/ratings/blocks.png b/framework/Web/Javascripts/prado/ratings/blocks.png
new file mode 100644
index 00000000..16a2b249
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/blocks.png differ
diff --git a/framework/Web/Javascripts/prado/ratings/blocks_blank.gif b/framework/Web/Javascripts/prado/ratings/blocks_blank.gif
new file mode 100644
index 00000000..a68d0e94
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/blocks_blank.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/blocks_half.gif b/framework/Web/Javascripts/prado/ratings/blocks_half.gif
new file mode 100644
index 00000000..4cff0148
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/blocks_half.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/blocks_hover.gif b/framework/Web/Javascripts/prado/ratings/blocks_hover.gif
new file mode 100644
index 00000000..58ad7495
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/blocks_hover.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/blocks_selected.gif b/framework/Web/Javascripts/prado/ratings/blocks_selected.gif
new file mode 100644
index 00000000..f91873e2
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/blocks_selected.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/default.css b/framework/Web/Javascripts/prado/ratings/default.css
new file mode 100644
index 00000000..c15a36bd
--- /dev/null
+++ b/framework/Web/Javascripts/prado/ratings/default.css
@@ -0,0 +1,29 @@
+.TRatingList_default
+{
+ border-collapse: collapse;
+}
+.TRatingList_default input, .TRatingList_default label
+{
+ display: none;
+}
+.TRatingList_default td
+{
+ width: 17px;
+ height: 18px;
+ background-image: url(default_blank.gif);
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+.TRatingList_default td.rating_selected
+{
+ background-image: url(default_selected.gif);
+}
+
+.TRatingList_default td.rating_hover
+{
+ background-image: url(default_hover.gif);
+}
+.TRatingList_default td.rating_half
+{
+ background-image: url(default_half.gif);
+}
diff --git a/framework/Web/Javascripts/prado/ratings/default_blank.gif b/framework/Web/Javascripts/prado/ratings/default_blank.gif
new file mode 100644
index 00000000..4e6fda3c
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/default_blank.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/default_half.gif b/framework/Web/Javascripts/prado/ratings/default_half.gif
new file mode 100644
index 00000000..7cecf0ec
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/default_half.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/default_hover.gif b/framework/Web/Javascripts/prado/ratings/default_hover.gif
new file mode 100644
index 00000000..ad0cd28a
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/default_hover.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/default_selected.gif b/framework/Web/Javascripts/prado/ratings/default_selected.gif
new file mode 100644
index 00000000..a19ab39f
Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/default_selected.gif differ
diff --git a/framework/Web/Javascripts/prado/ratings/ratings.js b/framework/Web/Javascripts/prado/ratings/ratings.js
new file mode 100644
index 00000000..e6fd97ba
--- /dev/null
+++ b/framework/Web/Javascripts/prado/ratings/ratings.js
@@ -0,0 +1,60 @@
+Prado.WebUI.TRatingList = Class.create();
+Prado.WebUI.TRatingList.prototype =
+{
+ selectedIndex : -1,
+
+ initialize : function(options)
+ {
+ this.options = options;
+ this.element = $(options['ID']);
+ Element.addClassName(this.element,options.cssClass);
+ this.radios = document.getElementsByName(options.field);
+ for(var i = 0; i
+ * Event.OnLoad(function(){ alert("Page Loaded!"); });
+ *
+ *
+ * @param {Function} function to execute when page is loaded.
+ */
+ OnLoad : function (fn)
+ {
+ // opera onload is in document, not window
+ var w = document.addEventListener &&
+ !window.addEventListener ? document : window;
+ Event.observe(w,'load',fn);
+ },
+
+ /**
+ * @param {Event} a keyboard event
+ * @return {Number} the Unicode character code generated by the key
+ * that was struck.
+ */
+ keyCode : function(e)
+ {
+ return e.keyCode != null ? e.keyCode : e.charCode
+ },
+
+ /**
+ * @param {String} event type or event name.
+ * @return {Boolean} true if event type is of HTMLEvent, false
+ * otherwise
+ */
+ isHTMLEvent : function(type)
+ {
+ var events = ['abort', 'blur', 'change', 'error', 'focus',
+ 'load', 'reset', 'resize', 'scroll', 'select',
+ 'submit', 'unload'];
+ return events.include(type);
+ },
+
+ /**
+ * @param {String} event type or event name
+ * @return {Boolean} true if event type is of MouseEvent,
+ * false otherwise
+ */
+ isMouseEvent : function(type)
+ {
+ var events = ['click', 'mousedown', 'mousemove', 'mouseout',
+ 'mouseover', 'mouseup'];
+ return events.include(type);
+ },
+
+ /**
+ * Dispatch the DOM event of a given type on a DOM
+ * element. Only HTMLEvent and MouseEvent can be
+ * dispatched, keyboard events or UIEvent can not be dispatch
+ * via javascript consistently.
+ * For the "submit" event the submit() method is called.
+ * @param {Object} element id string or a DOM element.
+ * @param {String} event type to dispatch.
+ */
+ fireEvent : function(element,type)
+ {
+ element = $(element);
+ if(type == "submit")
+ return element.submit();
+ if(document.createEvent)
+ {
+ if(Event.isHTMLEvent(type))
+ {
+ var event = document.createEvent('HTMLEvents');
+ event.initEvent(type, true, true);
+ }
+ else if(Event.isMouseEvent(type))
+ {
+ var event = document.createEvent('MouseEvents');
+ if (event.initMouseEvent)
+ {
+ event.initMouseEvent(type,true,true,
+ document.defaultView, 1, 0, 0, 0, 0, false,
+ false, false, false, 0, null);
+ }
+ else
+ {
+ // Safari
+ // TODO we should be initialising other mouse-event related attributes here
+ event.initEvent(type, true, true);
+ }
+ }
+ element.dispatchEvent(event);
+ }
+ else if(document.createEventObject)
+ {
+ var evObj = document.createEventObject();
+ element.fireEvent('on'+type, evObj);
+ }
+ else if(typeof(element['on'+type]) == "function")
+ element['on'+type]();
+ }
+});
+
+
+
+Object.extend(Date.prototype,
+{
+ SimpleFormat: function(format, data)
+ {
+ data = data || {};
+ var bits = new Array();
+ bits['d'] = this.getDate();
+ bits['dd'] = String(this.getDate()).zerofill(2);
+
+ bits['M'] = this.getMonth()+1;
+ bits['MM'] = String(this.getMonth()+1).zerofill(2);
+ if(data.AbbreviatedMonthNames)
+ bits['MMM'] = data.AbbreviatedMonthNames[this.getMonth()];
+ if(data.MonthNames)
+ bits['MMMM'] = data.MonthNames[this.getMonth()];
+ var yearStr = "" + this.getFullYear();
+ yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
+ bits['yyyy'] = yearStr;
+ bits['yy'] = bits['yyyy'].toString().substr(2,2);
+
+ // do some funky regexs to replace the format string
+ // with the real values
+ var frm = new String(format);
+ for (var sect in bits)
+ {
+ var reg = new RegExp("\\b"+sect+"\\b" ,"g");
+ frm = frm.replace(reg, bits[sect]);
+ }
+ return frm;
+ },
+
+ toISODate : function()
+ {
+ var y = this.getFullYear();
+ var m = String(this.getMonth() + 1).zerofill(2);
+ var d = String(this.getDate()).zerofill(2);
+ return String(y) + String(m) + String(d);
+ }
+});
+
+Object.extend(Date,
+{
+ SimpleParse: function(value, format)
+ {
+ val=String(value);
+ format=String(format);
+
+ if(val.length <= 0) return null;
+
+ if(format.length <= 0) return new Date(value);
+
+ var isInteger = function (val)
+ {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++)
+ {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ };
+
+ var getInt = function(str,i,minlength,maxlength)
+ {
+ for (var x=maxlength; x>=minlength; x--)
+ {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (isInteger(token)) { return token; }
+ }
+ return null;
+ };
+
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getFullYear();
+ var month=now.getMonth()+1;
+ var date=1;
+
+ while (i_format < format.length)
+ {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length))
+ {
+ token += format.charAt(i_format++);
+ }
+
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y")
+ {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=getInt(val,i_val,x,y);
+ if (year==null) { return null; }
+ i_val += year.length;
+ if (year.length==2)
+ {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+
+ else if (token=="MM"||token=="M")
+ {
+ month=getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return null;}
+ i_val+=month.length;
+ }
+ else if (token=="dd"||token=="d")
+ {
+ date=getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return null;}
+ i_val+=date.length;
+ }
+ else
+ {
+ if (val.substring(i_val,i_val+token.length)!=token) {return null;}
+ else {i_val+=token.length;}
+ }
+ }
+
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return null; }
+
+ // Is date valid for month?
+ if (month==2)
+ {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return null; }
+ }
+ else { if (date > 28) { return null; } }
+ }
+
+ if ((month==4)||(month==6)||(month==9)||(month==11))
+ {
+ if (date > 30) { return null; }
+ }
+
+ var newdate=new Date(year,month-1,date, 0, 0, 0);
+ return newdate;
+ }
+});
\ No newline at end of file
diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js
deleted file mode 100644
index 4158369f..00000000
--- a/framework/Web/Javascripts/prado/validation3.js
+++ /dev/null
@@ -1,1366 +0,0 @@
-
-/**
- * Prado client-side javascript validation fascade.
- *
- * There are 4 basic classes, Validation, ValidationManager, ValidationSummary
- * and TBaseValidator, that interact together to perform validation.
- * The Prado.Validation class co-ordinates together the
- * validation scheme and is responsible for maintaining references
- * to ValidationManagers.
- *
- * The ValidationManager class is responsible for maintaining refereneces
- * to individual validators, validation summaries and their associated
- * groupings.
- *
- * The ValidationSummary take cares of display the validator error messages
- * as html output or an alert output.
- *
- * The TBaseValidator is the base class for all validators and contains
- * methods to interact with the actual inputs, data type conversion.
- *
- * An instance of ValidationManager must be instantiated first for a
- * particular form before instantiating validators and summaries.
- *
- * Usage example: adding a required field to a text box input with
- * ID "input1" in a form with ID "form1".
- *
- *
- *
- *
- *
- */
-Prado.Validation = Class.create();
-
-/**
- * A global validation manager.
- * To validate the inputs of a particular form, call
- * Prado.Validation.validate(formID, groupID)
- * where formID is the HTML form ID, and the optional
- * groupID if present will only validate the validators
- * in a particular group.
- */
-Object.extend(Prado.Validation,
-{
- managers : {},
-
- /**
- * Validate the validators (those that DO NOT
- * belong to a particular group) the form specified by the
- * formID parameter. If groupID is specified
- * then only validators belonging to that group will be validated.
- * @param string ID of the form to validate
- * @param string ID of the group to validate.
- * @param HTMLElement element that calls for validation
- */
- validate : function(formID, groupID, invoker)
- {
- if(this.managers[formID])
- {
- return this.managers[formID].validate(groupID, invoker);
- }
- else
- {
- throw new Error("Form '"+form+"' is not registered with Prado.Validation");
- }
- },
-
- /**
- * @return string first form ID.
- */
- getForm : function()
- {
- var keys = $H(this.managers).keys();
- return keys[0];
- },
-
- /**
- * Check if the validators are valid for a particular form (and group).
- * The validators states will not be changed.
- * The validate function should be called first.
- * @param string ID of the form to validate
- * @param string ID of the group to validate.
- */
- isValid : function(formID, groupID)
- {
- if(this.managers[formID])
- return this.managers[formID].isValid(groupID);
- return true;
- },
-
- /**
- * Add a new validator to a particular form.
- * @param string the form that the validator belongs.
- * @param object a validator
- * @return object the manager
- */
- addValidator : function(formID, validator)
- {
- if(this.managers[formID])
- this.managers[formID].addValidator(validator);
- else
- throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
- return this.managers[formID];
- },
-
- /**
- * Add a new validation summary.
- * @param string the form that the validation summary belongs.
- * @param object a validation summary
- * @return object manager
- */
- addSummary : function(formID, validator)
- {
- if(this.managers[formID])
- this.managers[formID].addSummary(validator);
- else
- throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
- return this.managers[formID];
- },
-
- setErrorMessage : function(validatorID, message)
- {
- $H(Prado.Validation.managers).each(function(manager)
- {
- manager[1].validators.each(function(validator)
- {
- if(validator.options.ID == validatorID)
- {
- validator.options.ErrorMessage = message;
- $(validatorID).innerHTML = message;
- }
- });
- });
- }
-});
-
-Prado.ValidationManager = Class.create();
-/**
- * Validation manager instances. Manages validators for a particular
- * HTML form. The manager contains references to all the validators
- * summaries, and their groupings for a particular form.
- * Generally, Prado.Validation methods should be called rather
- * than calling directly the ValidationManager.
- */
-Prado.ValidationManager.prototype =
-{
- /**
- *
- * options['FormID']* The ID of HTML form to manage.
- *
- */
- initialize : function(options)
- {
- this.validators = []; // list of validators
- this.summaries = []; // validation summaries
- this.groups = []; // validation groups
- this.options = {};
-
- this.options = options;
- Prado.Validation.managers[options.FormID] = this;
- },
-
- /**
- * Validate the validators managed by this validation manager.
- * @param string only validate validators belonging to a group (optional)
- * @param HTMLElement element that calls for validation
- * @return boolean true if all validators are valid, false otherwise.
- */
- validate : function(group, invoker)
- {
- if(group)
- return this._validateGroup(group, invoker);
- else
- return this._validateNonGroup(invoker);
- },
-
- /**
- * Validate a particular group of validators.
- * @param string ID of the form
- * @param HTMLElement element that calls for validation
- * @return boolean false if group is not valid, true otherwise.
- */
- _validateGroup: function(groupID, invoker)
- {
- var valid = true;
- if(this.groups.include(groupID))
- {
- this.validators.each(function(validator)
- {
- if(validator.group == groupID)
- valid = valid & validator.validate(invoker);
- else
- validator.hide();
- });
- }
- this.updateSummary(groupID, true);
- return valid;
- },
-
- /**
- * Validate validators that doesn't belong to any group.
- * @return boolean false if not valid, true otherwise.
- * @param HTMLElement element that calls for validation
- */
- _validateNonGroup : function(invoker)
- {
- var valid = true;
- this.validators.each(function(validator)
- {
- if(!validator.group)
- valid = valid & validator.validate(invoker);
- else
- validator.hide();
- });
- this.updateSummary(null, true);
- return valid;
- },
-
- /**
- * Gets the state of all the validators, true if they are all valid.
- * @return boolean true if the validators are valid.
- */
- isValid : function(group)
- {
- if(group)
- return this._isValidGroup(group);
- else
- return this._isValidNonGroup();
- },
-
- /**
- * @return boolean true if all validators not belonging to a group are valid.
- */
- _isValidNonGroup : function()
- {
- var valid = true;
- this.validators.each(function(validator)
- {
- if(!validator.group)
- valid = valid & validator.isValid;
- });
- return valid;
- },
-
- /**
- * @return boolean true if all validators belonging to the group are valid.
- */
- _isValidGroup : function(groupID)
- {
- var valid = true;
- if(this.groups.include(groupID))
- {
- this.validators.each(function(validator)
- {
- if(validator.group == groupID)
- valid = valid & validator.isValid;
- });
- }
- return valid;
- },
-
- /**
- * Add a validator to this manager.
- * @param Prado.WebUI.TBaseValidator a new validator
- */
- addValidator : function(validator)
- {
- this.validators.push(validator);
- if(validator.group && !this.groups.include(validator.group))
- this.groups.push(validator.group);
- },
-
- /**
- * Add a validation summary.
- * @param Prado.WebUI.TValidationSummary validation summary.
- */
- addSummary : function(summary)
- {
- this.summaries.push(summary);
- },
-
- /**
- * Gets all validators that belong to a group or that the validator
- * group is null and the validator validation was false.
- * @return array list of validators with error.
- */
- getValidatorsWithError : function(group)
- {
- var validators = this.validators.findAll(function(validator)
- {
- var notValid = !validator.isValid;
- var inGroup = group && validator.group == group;
- var noGroup = validator.group == null;
- return notValid && (inGroup || noGroup);
- });
- return validators;
- },
-
- /**
- * Update the summary of a particular group.
- * @param string validation group to update.
- */
- updateSummary : function(group, refresh)
- {
- var validators = this.getValidatorsWithError(group);
- this.summaries.each(function(summary)
- {
- var inGroup = group && summary.group == group;
- var noGroup = !group && !summary.group;
- if(inGroup || noGroup)
- summary.updateSummary(validators, refresh);
- else
- summary.hideSummary(true);
- });
- }
-};
-
-/**
- * TValidationSummary displays a summary of validation errors inline on a Web page,
- * in a message box, or both. By default, a validation summary will collect
- * ErrorMessage of all failed validators on the page. If
- * ValidationGroup is not empty, only those validators who belong
- * to the group will show their error messages in the summary.
- *
- * The summary can be displayed as a list, as a bulleted list, or as a single
- * paragraph based on the DisplayMode option.
- * The messages shown can be prefixed with HeaderText.
- *
- * The summary can be displayed on the Web page and in a message box by setting
- * the ShowSummary and ShowMessageBox
- * options, respectively.
- */
-Prado.WebUI.TValidationSummary = Class.create();
-Prado.WebUI.TValidationSummary.prototype =
-{
- /**
- *
- * options['ID']* Validation summary ID, i.e., an HTML element ID
- * options['FormID']* HTML form that this summary belongs.
- * options['ShowMessageBox'] True to show the summary in an alert box.
- * options['ShowSummary'] True to show the inline summary.
- * options['HeaderText'] Summary header text
- * options['DisplayMode'] Summary display style, 'BulletList', 'List', 'SingleParagraph'
- * options['Refresh'] True to update the summary upon validator state change.
- * options['ValidationGroup'] Validation summary group
- * options['Display'] Display mode, 'None', 'Fixed', 'Dynamic'.
- * options['ScrollToSummary'] True to scroll to the validation summary upon refresh.
- *
- */
- initialize : function(options)
- {
- this.options = options;
- this.group = options.ValidationGroup;
- this.messages = $(options.ID);
- if(this.messages)
- {
- this.visible = this.messages.style.visibility != "hidden"
- this.visible = this.visible && this.messages.style.display != "none";
- Prado.Validation.addSummary(options.FormID, this);
- }
- },
-
- /**
- * Update the validation summary to show the error message from
- * validators that failed validation.
- * @param array list of validators that failed validation.
- * @param boolean update the summary;
- */
- updateSummary : function(validators, update)
- {
- if(validators.length <= 0)
- {
- if(update || this.options.Refresh != false)
- {
- return this.hideSummary(validators);
- }
- return;
- }
-
- var refresh = update || this.visible == false || this.options.Refresh != false;
-
- if(this.options.ShowSummary != false && refresh)
- {
- this.updateHTMLMessages(this.getMessages(validators));
- this.showSummary(validators);
- }
-
- if(this.options.ScrollToSummary != false && refresh)
- window.scrollTo(this.messages.offsetLeft-20, this.messages.offsetTop-20);
-
- if(this.options.ShowMessageBox == true && refresh)
- {
- this.alertMessages(this.getMessages(validators));
- this.visible = true;
- }
- },
-
- /**
- * Display the validator error messages as inline HTML.
- */
- updateHTMLMessages : function(messages)
- {
- while(this.messages.childNodes.length > 0)
- this.messages.removeChild(this.messages.lastChild);
- new Insertion.Bottom(this.messages, this.formatSummary(messages));
- },
-
- /**
- * Display the validator error messages as an alert box.
- */
- alertMessages : function(messages)
- {
- var text = this.formatMessageBox(messages);
- setTimeout(function(){ alert(text); },20);
- },
-
- /**
- * @return array list of validator error messages.
- */
- getMessages : function(validators)
- {
- var messages = [];
- validators.each(function(validator)
- {
- var message = validator.getErrorMessage();
- if(typeof(message) == 'string' && message.length > 0)
- messages.push(message);
- })
- return messages;
- },
-
- /**
- * Hides the validation summary.
- */
- hideSummary : function(validators)
- { if(typeof(this.options.OnHideSummary) == "function")
- {
- this.messages.style.visibility="visible";
- this.options.OnHideSummary(this,validators)
- }
- else
- {
- this.messages.style.visibility="hidden";
- if(this.options.Display == "None" || this.options.Display == "Dynamic")
- this.messages.hide();
- }
- this.visible = false;
- },
-
- /**
- * Shows the validation summary.
- */
- showSummary : function(validators)
- {
- this.messages.style.visibility="visible";
- if(typeof(this.options.OnShowSummary) == "function")
- this.options.OnShowSummary(this,validators);
- else
- this.messages.show();
- this.visible = true;
- },
-
- /**
- * Return the format parameters for the summary.
- * @param string format type, "List", "SingleParagraph" or "BulletList"
- * @type array formatting parameters
- */
- formats : function(type)
- {
- switch(type)
- {
- case "List":
- return { header : "
", first : "", pre : "", post : "
", last : ""};
- case "SingleParagraph":
- return { header : " ", first : "", pre : "", post : " ", last : "
"};
- case "BulletList":
- default:
- return { header : "", first : "", pre : "
"};
- }
- },
-
- /**
- * Format the message summary.
- * @param array list of error messages.
- * @type string formatted message
- */
- formatSummary : function(messages)
- {
- var format = this.formats(this.options.DisplayMode);
- var output = this.options.HeaderText ? this.options.HeaderText + format.header : "";
- output += format.first;
- messages.each(function(message)
- {
- output += message.length > 0 ? format.pre + message + format.post : "";
- });
-// for(var i = 0; i < messages.length; i++)
- // output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
- output += format.last;
- return output;
- },
- /**
- * Format the message alert box.
- * @param array a list of error messages.
- * @type string format message for alert.
- */
- formatMessageBox : function(messages)
- {
- var output = this.options.HeaderText ? this.options.HeaderText + "\n" : "";
- for(var i = 0; i < messages.length; i++)
- {
- switch(this.options.DisplayMode)
- {
- case "List":
- output += messages[i] + "\n";
- break;
- case "BulletList":
- default:
- output += " - " + messages[i] + "\n";
- break;
- case "SingleParagraph":
- output += messages[i] + " ";
- break;
- }
- }
- return output;
- }
-};
-
-/**
- * TBaseValidator serves as the base class for validator controls.
- *
- * Validation is performed when a postback control, such as a TButton,
- * a TLinkButton or a TTextBox (under AutoPostBack mode) is submitting
- * the page and its CausesValidation option is true.
- * The input control to be validated is specified by ControlToValidate
- * option.
- */
-Prado.WebUI.TBaseValidator = Class.create();
-Prado.WebUI.TBaseValidator.prototype =
-{
- /**
- *
- * options['ID']* Validator ID, e.g. span with message
- * options['FormID']* HTML form that the validator belongs
- * options['ControlToValidate']*HTML form input to validate
- * options['Display'] Display mode, 'None', 'Fixed', 'Dynamic'
- * options['ErrorMessage'] Validation error message
- * options['FocusOnError'] True to focus on validation error
- * options['FocusElementID'] Element to focus on error
- * options['ValidationGroup'] Validation group
- * options['ControlCssClass'] Css class to use on the input upon error
- * options['OnValidate'] Function to call immediately after validation
- * options['OnValidationSuccess'] Function to call upon after successful validation
- * options['OnValidationError'] Function to call upon after error in validation.
- * options['ObserveChanges'] True to observe changes in input
- *
- */
- initialize : function(options)
- {
- /* options.OnValidate = options.OnValidate || Prototype.emptyFunction;
- options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
- options.OnError = options.OnError || Prototype.emptyFunction;
- */
-
- this.enabled = true;
- this.visible = false;
- this.isValid = true;
- this._isObserving = {};
- this.group = null;
- this.requestDispatched = false;
-
- this.options = options;
- this.control = $(options.ControlToValidate);
- this.message = $(options.ID);
- if(this.control && this.message)
- {
- this.group = options.ValidationGroup;
-
- this.manager = Prado.Validation.addValidator(options.FormID, this);
- }
- },
-
- /**
- * @return string validation error message.
- */
- getErrorMessage : function()
- {
- return this.options.ErrorMessage;
- },
-
- /**
- * Update the validator span, input CSS class, and focus particular
- * element. Updating the validator control will set the validator
- * visible property to true.
- */
- updateControl: function(focus)
- {
- this.refreshControlAndMessage();
-
- if(this.options.FocusOnError && !this.isValid )
- Prado.Element.focus(this.options.FocusElementID);
-
- this.visible = true;
- },
-
- refreshControlAndMessage : function()
- {
- this.visible = true;
- if(this.message)
- {
- if(this.options.Display == "Dynamic")
- this.isValid ? this.message.hide() : this.message.show();
- this.message.style.visibility = this.isValid ? "hidden" : "visible";
- }
- if(this.control)
- this.updateControlCssClass(this.control, this.isValid);
- },
-
- /**
- * Add a css class to the input control if validator is invalid,
- * removes the css class if valid.
- * @param object html control element
- * @param boolean true to remove the css class, false to add.
- */
- updateControlCssClass : function(control, valid)
- {
- var CssClass = this.options.ControlCssClass;
- if(typeof(CssClass) == "string" && CssClass.length > 0)
- {
- if(valid)
- control.removeClassName(CssClass);
- else
- control.addClassName(CssClass);
- }
- },
-
- /**
- * Hides the validator messages and remove any validation changes.
- */
- hide : function()
- {
- this.isValid = true;
- this.updateControl();
- this.visible = false;
- },
-
- /**
- * Calls evaluateIsValid() function to set the value of isValid property.
- * Triggers onValidate event and onSuccess or onError event.
- * @param HTMLElement element that calls for validation
- * @return boolean true if valid.
- */
- validate : function(invoker)
- {
- //try to find the control.
- if(!this.control)
- this.control = $(this.options.ControlToValidate);
-
- if(!this.control)
- {
- this.isValid = true;
- return this.isValid;
- }
-
- if(typeof(this.options.OnValidate) == "function")
- {
- if(this.requestDispatched == false)
- this.options.OnValidate(this, invoker);
- }
-
- if(this.enabled)
- this.isValid = this.evaluateIsValid();
- else
- this.isValid = true;
-
- if(this.isValid)
- {
- if(typeof(this.options.OnValidationSuccess) == "function")
- {
- if(this.requestDispatched == false)
- {
- this.refreshControlAndMessage();
- this.options.OnValidationSuccess(this, invoker);
- }
- }
- else
- this.updateControl();
- }
- else
- {
- if(typeof(this.options.OnValidationError) == "function")
- {
- if(this.requestDispatched == false)
- {
- this.refreshControlAndMessage();
- this.options.OnValidationError(this, invoker)
- }
- }
- else
- this.updateControl();
- }
-
- this.observeChanges(this.control);
-
- return this.isValid;
- },
-
- /**
- * Observe changes to the control input, re-validate upon change. If
- * the validator is not visible, no updates are propagated.
- * @param HTMLElement element that calls for validation
- */
- observeChanges : function(control)
- {
- if(!control) return;
-
- var canObserveChanges = this.options.ObserveChanges != false;
- var currentlyObserving = this._isObserving[control.id+this.options.ID];
-
- if(canObserveChanges && !currentlyObserving)
- {
- var validator = this;
-
- Event.observe(control, 'change', function()
- {
- if(validator.visible)
- {
- validator.validate();
- validator.manager.updateSummary(validator.group);
- }
- });
- this._isObserving[control.id+this.options.ID] = true;
- }
- },
-
- /**
- * @return string trims the string value, empty string if value is not string.
- */
- trim : function(value)
- {
- return typeof(value) == "string" ? value.trim() : "";
- },
-
- /**
- * Convert the value to a specific data type.
- * @param {string} the data type, "Integer", "Double", "Date" or "String"
- * @param {string} the value to convert.
- * @type {mixed|null} the converted data value.
- */
- convert : function(dataType, value)
- {
- if(typeof(value) == "undefined")
- value = this.getValidationValue();
- var string = new String(value);
- switch(dataType)
- {
- case "Integer":
- return string.toInteger();
- case "Double" :
- case "Float" :
- return string.toDouble(this.options.DecimalChar);
- case "Date":
- if(typeof(value) != "string")
- return value;
- else
- {
- var value = string.toDate(this.options.DateFormat);
- if(value && typeof(value.getTime) == "function")
- return value.getTime();
- else
- return null;
- }
- case "String":
- return string.toString();
- }
- return value;
- },
-
- /**
- * The ControlType property comes from TBaseValidator::getClientControlClass()
- * Be sure to update the TBaseValidator::$_clientClass if new cases are added.
- * @return mixed control value to validate
- */
- getValidationValue : function(control)
- {
- if(!control)
- control = this.control
- switch(this.options.ControlType)
- {
- case 'TDatePicker':
- if(control.type == "text")
- {
- value = this.trim($F(control));
-
- if(this.options.DateFormat)
- {
- date = value.toDate(this.options.DateFormat);
- return date == null ? value : date;
- }
- else
- return value;
- }
- else
- {
- this.observeDatePickerChanges();
-
- return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
- }
- case 'THtmlArea':
- if(typeof tinyMCE != "undefined")
- tinyMCE.triggerSave();
- return this.trim($F(control));
- case 'TRadioButton':
- if(this.options.GroupName)
- return this.getRadioButtonGroupValue();
- default:
- if(this.isListControlType())
- return this.getFirstSelectedListValue();
- else
- return this.trim($F(control));
- }
- },
-
- getRadioButtonGroupValue : function()
- {
- name = this.control.name;
- value = "";
- $A(document.getElementsByName(name)).each(function(el)
- {
- if(el.checked)
- value = el.value;
- });
- return value;
- },
-
- /**
- * Observe changes in the drop down list date picker, IE only.
- */
- observeDatePickerChanges : function()
- {
- if(Prado.Browser().ie)
- {
- var DatePicker = Prado.WebUI.TDatePicker;
- this.observeChanges(DatePicker.getDayListControl(this.control));
- this.observeChanges(DatePicker.getMonthListControl(this.control));
- this.observeChanges(DatePicker.getYearListControl(this.control));
- }
- },
-
- /**
- * Gets numeber selections and their values.
- * @return object returns selected values in values property
- * and number of selections in checks property.
- */
- getSelectedValuesAndChecks : function(elements, initialValue)
- {
- var checked = 0;
- var values = [];
- var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
- elements.each(function(element)
- {
- if(element[isSelected] && element.value != initialValue)
- {
- checked++;
- values.push(element.value);
- }
- });
- return {'checks' : checked, 'values' : values};
- },
-
- /**
- * Gets an array of the list control item input elements, for TCheckBoxList
- * checkbox inputs are returned, for TListBox HTML option elements are returned.
- * @return array list control option elements.
- */
- getListElements : function()
- {
- switch(this.options.ControlType)
- {
- case 'TCheckBoxList': case 'TRadioButtonList':
- var elements = [];
- for(var i = 0; i < this.options.TotalItems; i++)
- {
- var element = $(this.options.ControlToValidate+"_c"+i);
- if(this.isCheckBoxType(element))
- elements.push(element);
- }
- return elements;
- case 'TListBox':
- var elements = [];
- var element = $(this.options.ControlToValidate);
- if(element && (type = element.type.toLowerCase()))
- {
- if(type == "select-one" || type == "select-multiple")
- elements = $A(element.options);
- }
- return elements;
- default:
- return [];
- }
- },
-
- /**
- * @return boolean true if element is of checkbox or radio type.
- */
- isCheckBoxType : function(element)
- {
- if(element && element.type)
- {
- var type = element.type.toLowerCase();
- return type == "checkbox" || type == "radio";
- }
- return false;
- },
-
- /**
- * @return boolean true if control to validate is of some of the TListControl type.
- */
- isListControlType : function()
- {
- var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
- return list.include(this.options.ControlType);
- },
-
- /**
- * @return string gets the first selected list value, initial value if none found.
- */
- getFirstSelectedListValue : function()
- {
- var initial = "";
- if(typeof(this.options.InitialValue) != "undefined")
- initial = this.options.InitialValue;
- var elements = this.getListElements();
- var selection = this.getSelectedValuesAndChecks(elements, initial);
- return selection.values.length > 0 ? selection.values[0] : initial;
- }
-}
-
-
-/**
- * TRequiredFieldValidator makes the associated input control a required field.
- * The input control fails validation if its value does not change from
- * the InitialValue option upon losing focus.
- *
- * options['InitialValue'] Validation fails if control input equals initial value.
- *
- */
-Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- /**
- * @return boolean true if the input value is not empty nor equal to the initial value.
- */
- evaluateIsValid : function()
- {
- var inputType = this.control.getAttribute("type");
- if(inputType == 'file')
- {
- return true;
- }
- else
- {
- var a = this.getValidationValue();
- var b = this.trim(this.options.InitialValue);
- return(a != b);
- }
- }
-});
-
-
-/**
- * TCompareValidator compares the value entered by the user into an input
- * control with the value entered into another input control or a constant value.
- * To compare the associated input control with another input control,
- * set the ControlToCompare option to the ID path
- * of the control to compare with. To compare the associated input control with
- * a constant value, specify the constant value to compare with by setting the
- * ValueToCompare option.
- *
- * The DataType property is used to specify the data type
- * of both comparison values. Both values are automatically converted to this data
- * type before the comparison operation is performed. The following value types are supported:
- * - Integer A 32-bit signed integer data type.
- * - Float A double-precision floating point number data type.
- * - Date A date data type. The format can be by the DateFormat option.
- * - String A string data type.
- *
- * Use the Operator property to specify the type of comparison
- * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
- * LessThan and LessThanEqual.
- *
- * options['ControlToCompare']
- * options['ValueToCompare']
- * options['Operator']
- * options['Type']
- * options['DateFormat']
- *
- */
-Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- //_observingComparee : false,
-
- /**
- * Compares the input to another input or a given value.
- */
- evaluateIsValid : function()
- {
- var value = this.getValidationValue();
- if (value.length <= 0)
- return true;
-
- var comparee = $(this.options.ControlToCompare);
-
- if(comparee)
- var compareTo = this.getValidationValue(comparee);
- else
- var compareTo = this.options.ValueToCompare || "";
-
- var isValid = this.compare(value, compareTo);
-
- if(comparee)
- {
- this.updateControlCssClass(comparee, isValid);
- this.observeChanges(comparee);
- }
- return isValid;
- },
-
- /**
- * Compares two values, their values are casted to type defined
- * by DataType option. False is returned if the first
- * operand converts to null. Returns true if the second operand
- * converts to null. The comparision is done based on the
- * Operator option.
- */
- compare : function(operand1, operand2)
- {
- var op1, op2;
- if((op1 = this.convert(this.options.DataType, operand1)) == null)
- return false;
- if ((op2 = this.convert(this.options.DataType, operand2)) == null)
- return true;
- switch (this.options.Operator)
- {
- case "NotEqual":
- return (op1 != op2);
- case "GreaterThan":
- return (op1 > op2);
- case "GreaterThanEqual":
- return (op1 >= op2);
- case "LessThan":
- return (op1 < op2);
- case "LessThanEqual":
- return (op1 <= op2);
- default:
- return (op1 == op2);
- }
- }
-});
-
-/**
- * TCustomValidator performs user-defined client-side validation on an
- * input component.
- *
- * To create a client-side validation function, add the client-side
- * validation javascript function to the page template.
- * The function should have the following signature:
- *
- *
- *
- * Use the ClientValidationFunction option
- * to specify the name of the client-side validation script function associated
- * with the TCustomValidator.
- *
- * options['ClientValidationFunction'] custom validation function.
- *
- */
-Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- /**
- * Calls custom validation function.
- */
- evaluateIsValid : function()
- {
- var value = this.getValidationValue();
- var clientFunction = this.options.ClientValidationFunction;
- if(typeof(clientFunction) == "string" && clientFunction.length > 0)
- {
- validate = clientFunction.toFunction();
- return validate(this, value);
- }
- return true;
- }
-});
-
-/**
- * Uses callback request to perform validation.
- */
-Prado.WebUI.TActiveCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- validatingValue : null,
-
- /**
- * Calls custom validation function.
- */
- evaluateIsValid : function()
- {
- value = this.getValidationValue();
- if(!this.requestDispatched && value != this.validatingValue)
- {
- this.validatingValue = value;
- request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
- request.setCallbackParameter(value);
- request.setCausesValidation(false);
- request.options.onSuccess = this.callbackOnSuccess.bind(this);
- request.options.onFailure = this.callbackOnFailure.bind(this);
- request.dispatch();
- this.requestDispatched = true;
- return false;
- }
- return this.isValid;
- },
-
- callbackOnSuccess : function(request, data)
- {
- this.isValid = data;
- this.requestDispatched = false;
- if(typeof(this.options.onSuccess) == "function")
- this.options.onSuccess(request,data);
- Prado.Validation.validate(this.options.FormID, this.group,null);
- },
-
- callbackOnFailure : function(request, data)
- {
- this.requestDispatched = false;
- if(typeof(this.options.onFailure) == "function")
- this.options.onFailure(request,data);
- }
-});
-
-/**
- * TRangeValidator tests whether an input value is within a specified range.
- *
- * TRangeValidator uses three key properties to perform its validation.
- * The MinValue and MaxValue options specify the minimum
- * and maximum values of the valid range. The DataType option is
- * used to specify the data type of the value and the minimum and maximum range values.
- * These values are converted to this data type before the validation
- * operation is performed. The following value types are supported:
- * - Integer A 32-bit signed integer data type.
- * - Float A double-precision floating point number data type.
- * - Date A date data type. The date format can be specified by
- * setting DateFormat option, which must be recognizable
- * by Date.SimpleParse javascript function.
- * - String A string data type.
- *
- * options['MinValue'] Minimum range value
- * options['MaxValue'] Maximum range value
- * options['DataType'] Value data type
- * options['DateFormat'] Date format for date data type.
- *
- */
-Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- /**
- * Compares the input value with a minimum and/or maximum value.
- * @return boolean true if the value is empty, returns false if conversion fails.
- */
- evaluateIsValid : function()
- {
- var value = this.getValidationValue();
- if(value.length <= 0)
- return true;
- if(typeof(this.options.DataType) == "undefined")
- this.options.DataType = "String";
-
- if(this.options.DataType != "StringLength")
- {
- var min = this.convert(this.options.DataType, this.options.MinValue || null);
- var max = this.convert(this.options.DataType, this.options.MaxValue || null);
- value = this.convert(this.options.DataType, value);
- }
- else
- {
- var min = this.options.MinValue || 0;
- var max = this.options.MaxValue || Number.POSITIVE_INFINITY;
- value = value.length;
- }
-
- if(value == null)
- return false;
-
- var valid = true;
-
- if(min != null)
- valid = valid && value >= min;
- if(max != null)
- valid = valid && value <= max;
- return valid;
- }
-});
-
-/**
- * TRegularExpressionValidator validates whether the value of an associated
- * input component matches the pattern specified by a regular expression.
- *
- * options['ValidationExpression'] regular expression to match against.
- *
- */
-Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- /**
- * Compare the control input against a regular expression.
- */
- evaluateIsValid : function()
- {
- var value = this.getValidationValue();
- if (value.length <= 0)
- return true;
-
- var rx = new RegExp(this.options.ValidationExpression);
- var matches = rx.exec(value);
- return (matches != null && value == matches[0]);
- }
-});
-
-/**
- * TEmailAddressValidator validates whether the value of an associated
- * input component is a valid email address.
- */
-Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator;
-
-
-/**
- * TListControlValidator checks the number of selection and their values
- * for a TListControl that allows multiple selections.
- */
-Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- /**
- * @return true if the number of selections and/or their values
- * match the requirements.
- */
- evaluateIsValid : function()
- {
- var elements = this.getListElements();
- if(elements && elements.length <= 0)
- return true;
-
- this.observeListElements(elements);
-
- var selection = this.getSelectedValuesAndChecks(elements);
- return this.isValidList(selection.checks, selection.values);
- },
-
- /**
- * Observe list elements for IE browsers of changes
- */
- observeListElements : function(elements)
- {
- if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
- {
- var validator = this;
- elements.each(function(element)
- {
- validator.observeChanges(element);
- });
- }
- },
-
- /**
- * Determine if the number of checked and the checked values
- * satisfy the required number of checks and/or the checked values
- * equal to the required values.
- * @return boolean true if checked values and number of checks are satisfied.
- */
- isValidList : function(checked, values)
- {
- var exists = true;
-
- //check the required values
- var required = this.getRequiredValues();
- if(required.length > 0)
- {
- if(values.length < required.length)
- return false;
- required.each(function(requiredValue)
- {
- exists = exists && values.include(requiredValue);
- });
- }
-
- var min = typeof(this.options.Min) == "undefined" ?
- Number.NEGATIVE_INFINITY : this.options.Min;
- var max = typeof(this.options.Max) == "undefined" ?
- Number.POSITIVE_INFINITY : this.options.Max;
- return exists && checked >= min && checked <= max;
- },
-
- /**
- * @return array list of required options that must be selected.
- */
- getRequiredValues : function()
- {
- var required = [];
- if(this.options.Required && this.options.Required.length > 0)
- required = this.options.Required.split(/,\s*/);
- return required;
- }
-});
-
-
-/**
- * TDataTypeValidator verifies if the input data is of the type specified
- * by DataType option.
- * The following data types are supported:
- * - Integer A 32-bit signed integer data type.
- * - Float A double-precision floating point number data type.
- * - Date A date data type.
- * - String A string data type.
- * For Date type, the option DateFormat
- * will be used to determine how to parse the date string.
- */
-Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
- evaluateIsValid : function()
- {
- value = this.getValidationValue();
- if(value.length <= 0)
- return true;
- return this.convert(this.options.DataType, value) != null;
- }
-});
-
diff --git a/framework/Web/Javascripts/prado/validator/validation3.js b/framework/Web/Javascripts/prado/validator/validation3.js
new file mode 100644
index 00000000..714aa93f
--- /dev/null
+++ b/framework/Web/Javascripts/prado/validator/validation3.js
@@ -0,0 +1,1276 @@
+
+/**
+ * Prado client-side javascript validation fascade.
+ *
+ * There are 4 basic classes, Validation, ValidationManager, ValidationSummary
+ * and TBaseValidator, that interact together to perform validation.
+ * The Prado.Validation class co-ordinates together the
+ * validation scheme and is responsible for maintaining references
+ * to ValidationManagers.
+ *
+ * The ValidationManager class is responsible for maintaining refereneces
+ * to individual validators, validation summaries and their associated
+ * groupings.
+ *
+ * The ValidationSummary take cares of display the validator error messages
+ * as html output or an alert output.
+ *
+ * The TBaseValidator is the base class for all validators and contains
+ * methods to interact with the actual inputs, data type conversion.
+ *
+ * An instance of ValidationManager must be instantiated first for a
+ * particular form before instantiating validators and summaries.
+ *
+ * Usage example: adding a required field to a text box input with
+ * ID "input1" in a form with ID "form1".
+ *
+ *
+ *
+ *
+ *
+ */
+Prado.Validation = Class.create();
+
+/**
+ * A global validation manager.
+ * To validate the inputs of a particular form, call
+ * Prado.Validation.validate(formID, groupID)
+ * where formID is the HTML form ID, and the optional
+ * groupID if present will only validate the validators
+ * in a particular group.
+ */
+Object.extend(Prado.Validation,
+{
+ managers : {},
+
+ /**
+ * Validate the validators (those that DO NOT
+ * belong to a particular group) the form specified by the
+ * formID parameter. If groupID is specified
+ * then only validators belonging to that group will be validated.
+ * @param string ID of the form to validate
+ * @param string ID of the group to validate.
+ * @param HTMLElement element that calls for validation
+ */
+ validate : function(formID, groupID, invoker)
+ {
+ if(this.managers[formID])
+ {
+ return this.managers[formID].validate(groupID, invoker);
+ }
+ else
+ {
+ throw new Error("Form '"+form+"' is not registered with Prado.Validation");
+ }
+ },
+
+ /**
+ * Check if the validators are valid for a particular form (and group).
+ * The validators states will not be changed.
+ * The validate function should be called first.
+ * @param string ID of the form to validate
+ * @param string ID of the group to validate.
+ */
+ isValid : function(formID, groupID)
+ {
+ if(this.managers[formID])
+ return this.managers[formID].isValid(groupID);
+ return true;
+ },
+
+ /**
+ * Add a new validator to a particular form.
+ * @param string the form that the validator belongs.
+ * @param object a validator
+ * @return object the manager
+ */
+ addValidator : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addValidator(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ return this.managers[formID];
+ },
+
+ /**
+ * Add a new validation summary.
+ * @param string the form that the validation summary belongs.
+ * @param object a validation summary
+ * @return object manager
+ */
+ addSummary : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addSummary(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ return this.managers[formID];
+ }
+});
+
+Prado.ValidationManager = Class.create();
+/**
+ * Validation manager instances. Manages validators for a particular
+ * HTML form. The manager contains references to all the validators
+ * summaries, and their groupings for a particular form.
+ * Generally, Prado.Validation methods should be called rather
+ * than calling directly the ValidationManager.
+ */
+Prado.ValidationManager.prototype =
+{
+ validators : [], // list of validators
+ summaries : [], // validation summaries
+ groups : [], // validation groups
+ options : {},
+
+ /**
+ *
+ * options['FormID']* The ID of HTML form to manage.
+ *
+ */
+ initialize : function(options)
+ {
+ this.options = options;
+ Prado.Validation.managers[options.FormID] = this;
+ },
+
+ /**
+ * Validate the validators managed by this validation manager.
+ * @param string only validate validators belonging to a group (optional)
+ * @param HTMLElement element that calls for validation
+ * @return boolean true if all validators are valid, false otherwise.
+ */
+ validate : function(group, invoker)
+ {
+ if(group)
+ return this._validateGroup(group, invoker);
+ else
+ return this._validateNonGroup(invoker);
+ },
+
+ /**
+ * Validate a particular group of validators.
+ * @param string ID of the form
+ * @param HTMLElement element that calls for validation
+ * @return boolean false if group is not valid, true otherwise.
+ */
+ _validateGroup: function(groupID, invoker)
+ {
+ var valid = true;
+ if(this.groups.include(groupID))
+ {
+ this.validators.each(function(validator)
+ {
+ if(validator.group == groupID)
+ valid = valid & validator.validate(invoker);
+ else
+ validator.hide();
+ });
+ }
+ this.updateSummary(groupID, true);
+ return valid;
+ },
+
+ /**
+ * Validate validators that doesn't belong to any group.
+ * @return boolean false if not valid, true otherwise.
+ * @param HTMLElement element that calls for validation
+ */
+ _validateNonGroup : function(invoker)
+ {
+ var valid = true;
+ this.validators.each(function(validator)
+ {
+ if(!validator.group)
+ valid = valid & validator.validate(invoker);
+ else
+ validator.hide();
+ });
+ this.updateSummary(null, true);
+ return valid;
+ },
+
+ /**
+ * Gets the state of all the validators, true if they are all valid.
+ * @return boolean true if the validators are valid.
+ */
+ isValid : function(group)
+ {
+ if(group)
+ return this._isValidGroup(group);
+ else
+ return this._isValidNonGroup();
+ },
+
+ /**
+ * @return boolean true if all validators not belonging to a group are valid.
+ */
+ _isValidNonGroup : function()
+ {
+ var valid = true;
+ this.validators.each(function(validator)
+ {
+ if(!validator.group)
+ valid = valid & validator.isValid;
+ });
+ return valid;
+ },
+
+ /**
+ * @return boolean true if all validators belonging to the group are valid.
+ */
+ _isValidGroup : function(groupID)
+ {
+ var valid = true;
+ if(this.groups.include(groupID))
+ {
+ this.validators.each(function(validator)
+ {
+ if(validator.group == groupID)
+ valid = valid & validator.isValid;
+ });
+ }
+ return valid;
+ },
+
+ /**
+ * Add a validator to this manager.
+ * @param Prado.WebUI.TBaseValidator a new validator
+ */
+ addValidator : function(validator)
+ {
+ this.validators.push(validator);
+ if(validator.group && !this.groups.include(validator.group))
+ this.groups.push(validator.group);
+ },
+
+ /**
+ * Add a validation summary.
+ * @param Prado.WebUI.TValidationSummary validation summary.
+ */
+ addSummary : function(summary)
+ {
+ this.summaries.push(summary);
+ },
+
+ /**
+ * Gets all validators that belong to a group or that the validator
+ * group is null and the validator validation was false.
+ * @return array list of validators with error.
+ */
+ getValidatorsWithError : function(group)
+ {
+ var validators = this.validators.findAll(function(validator)
+ {
+ var notValid = !validator.isValid;
+ var inGroup = group && validator.group == group;
+ var noGroup = validator.group == null;
+ return notValid && (inGroup || noGroup);
+ });
+ return validators;
+ },
+
+ /**
+ * Update the summary of a particular group.
+ * @param string validation group to update.
+ */
+ updateSummary : function(group, refresh)
+ {
+ var validators = this.getValidatorsWithError(group);
+ this.summaries.each(function(summary)
+ {
+ var inGroup = group && summary.group == group;
+ var noGroup = !group && !summary.group;
+ if(inGroup || noGroup)
+ summary.updateSummary(validators, refresh);
+ else
+ summary.hideSummary(true);
+ });
+ }
+};
+
+/**
+ * TValidationSummary displays a summary of validation errors inline on a Web page,
+ * in a message box, or both. By default, a validation summary will collect
+ * ErrorMessage of all failed validators on the page. If
+ * ValidationGroup is not empty, only those validators who belong
+ * to the group will show their error messages in the summary.
+ *
+ * The summary can be displayed as a list, as a bulleted list, or as a single
+ * paragraph based on the DisplayMode option.
+ * The messages shown can be prefixed with HeaderText.
+ *
+ * The summary can be displayed on the Web page and in a message box by setting
+ * the ShowSummary and ShowMessageBox
+ * options, respectively.
+ */
+Prado.WebUI.TValidationSummary = Class.create();
+Prado.WebUI.TValidationSummary.prototype =
+{
+ group : null,
+ options : {},
+ visible : false,
+ messages : null,
+
+ /**
+ *
+ * options['ID']* Validation summary ID, i.e., an HTML element ID
+ * options['FormID']* HTML form that this summary belongs.
+ * options['ShowMessageBox'] True to show the summary in an alert box.
+ * options['ShowSummary'] True to show the inline summary.
+ * options['HeaderText'] Summary header text
+ * options['DisplayMode'] Summary display style, 'BulletList', 'List', 'SingleParagraph'
+ * options['Refresh'] True to update the summary upon validator state change.
+ * options['ValidationGroup'] Validation summary group
+ * options['Display'] Display mode, 'None', 'Fixed', 'Dynamic'.
+ * options['ScrollToSummary'] True to scroll to the validation summary upon refresh.
+ *
+ */
+ initialize : function(options)
+ {
+ this.options = options;
+ this.group = options.ValidationGroup;
+ this.messages = $(options.ID);
+ this.visible = this.messages.style.visibility != "hidden"
+ this.visible = this.visible && this.messages.style.display != "none";
+ Prado.Validation.addSummary(options.FormID, this);
+ },
+
+ /**
+ * Update the validation summary to show the error message from
+ * validators that failed validation.
+ * @param array list of validators that failed validation.
+ * @param boolean update the summary;
+ */
+ updateSummary : function(validators, update)
+ {
+ if(validators.length <= 0)
+ {
+ if(update || this.options.Refresh != false)
+ {
+ return this.hideSummary(validators);
+ }
+ return;
+ }
+
+ var refresh = update || this.visible == false || this.options.Refresh != false;
+
+ if(this.options.ShowSummary != false && refresh)
+ {
+ this.updateHTMLMessages(this.getMessages(validators));
+ this.showSummary(validators);
+ }
+
+ if(this.options.ScrollToSummary != false && refresh)
+ window.scrollTo(this.messages.offsetLeft-20, this.messages.offsetTop-20);
+
+ if(this.options.ShowMessageBox == true && refresh)
+ {
+ this.alertMessages(this.getMessages(validators));
+ this.visible = true;
+ }
+ },
+
+ /**
+ * Display the validator error messages as inline HTML.
+ */
+ updateHTMLMessages : function(messages)
+ {
+ while(this.messages.childNodes.length > 0)
+ this.messages.removeChild(this.messages.lastChild);
+ new Insertion.Bottom(this.messages, this.formatSummary(messages));
+ },
+
+ /**
+ * Display the validator error messages as an alert box.
+ */
+ alertMessages : function(messages)
+ {
+ var text = this.formatMessageBox(messages);
+ setTimeout(function(){ alert(text); },20);
+ },
+
+ /**
+ * @return array list of validator error messages.
+ */
+ getMessages : function(validators)
+ {
+ var messages = [];
+ validators.each(function(validator)
+ {
+ var message = validator.getErrorMessage();
+ if(typeof(message) == 'string' && message.length > 0)
+ messages.push(message);
+ })
+ return messages;
+ },
+
+ /**
+ * Hides the validation summary.
+ */
+ hideSummary : function(validators)
+ { if(typeof(this.options.OnHideSummary) == "function")
+ {
+ this.messages.style.visibility="visible";
+ this.options.OnHideSummary(this,validators)
+ }
+ else
+ {
+ this.messages.style.visibility="hidden";
+ if(this.options.Display == "None" || this.options.Display == "Dynamic")
+ this.messages.hide();
+ }
+ this.visible = false;
+ },
+
+ /**
+ * Shows the validation summary.
+ */
+ showSummary : function(validators)
+ {
+ this.messages.style.visibility="visible";
+ if(typeof(this.options.OnShowSummary) == "function")
+ this.options.OnShowSummary(this,validators);
+ else
+ this.messages.show();
+ this.visible = true;
+ },
+
+ /**
+ * Return the format parameters for the summary.
+ * @param string format type, "List", "SingleParagraph" or "BulletList"
+ * @type array formatting parameters
+ */
+ formats : function(type)
+ {
+ switch(type)
+ {
+ case "List":
+ return { header : "
", first : "", pre : "", post : "
", last : ""};
+ case "SingleParagraph":
+ return { header : " ", first : "", pre : "", post : " ", last : "
"};
+ case "BulletList":
+ default:
+ return { header : "", first : "", pre : "
"};
+ }
+ },
+
+ /**
+ * Format the message summary.
+ * @param array list of error messages.
+ * @type string formatted message
+ */
+ formatSummary : function(messages)
+ {
+ var format = this.formats(this.options.DisplayMode);
+ var output = this.options.HeaderText ? this.options.HeaderText + format.header : "";
+ output += format.first;
+ messages.each(function(message)
+ {
+ output += message.length > 0 ? format.pre + message + format.post : "";
+ });
+// for(var i = 0; i < messages.length; i++)
+ // output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
+ output += format.last;
+ return output;
+ },
+ /**
+ * Format the message alert box.
+ * @param array a list of error messages.
+ * @type string format message for alert.
+ */
+ formatMessageBox : function(messages)
+ {
+ var output = this.options.HeaderText ? this.options.HeaderText + "\n" : "";
+ for(var i = 0; i < messages.length; i++)
+ {
+ switch(this.options.DisplayMode)
+ {
+ case "List":
+ output += messages[i] + "\n";
+ break;
+ case "BulletList":
+ default:
+ output += " - " + messages[i] + "\n";
+ break;
+ case "SingleParagraph":
+ output += messages[i] + " ";
+ break;
+ }
+ }
+ return output;
+ }
+};
+
+/**
+ * TBaseValidator serves as the base class for validator controls.
+ *
+ * Validation is performed when a postback control, such as a TButton,
+ * a TLinkButton or a TTextBox (under AutoPostBack mode) is submitting
+ * the page and its CausesValidation option is true.
+ * The input control to be validated is specified by ControlToValidate
+ * option.
+ */
+Prado.WebUI.TBaseValidator = Class.create();
+Prado.WebUI.TBaseValidator.prototype =
+{
+ enabled : true,
+ visible : false,
+ isValid : true,
+ options : {},
+ _isObserving : {},
+ group : null,
+ manager : null,
+ message : null,
+
+ /**
+ *
+ * options['ID']* Validator ID, e.g. span with message
+ * options['FormID']* HTML form that the validator belongs
+ * options['ControlToValidate']*HTML form input to validate
+ * options['Display'] Display mode, 'None', 'Fixed', 'Dynamic'
+ * options['ErrorMessage'] Validation error message
+ * options['FocusOnError'] True to focus on validation error
+ * options['FocusElementID'] Element to focus on error
+ * options['ValidationGroup'] Validation group
+ * options['ControlCssClass'] Css class to use on the input upon error
+ * options['OnValidate'] Function to call immediately after validation
+ * options['OnSuccess'] Function to call upon after successful validation
+ * options['OnError'] Function to call upon after error in validation.
+ * options['ObserveChanges'] True to observe changes in input
+ *
+ */
+ initialize : function(options)
+ {
+ /* options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+ options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
+ options.OnError = options.OnError || Prototype.emptyFunction;
+ */
+ this.options = options;
+ this.control = $(options.ControlToValidate);
+ this.message = $(options.ID);
+ this.group = options.ValidationGroup;
+
+ this.manager = Prado.Validation.addValidator(options.FormID, this);
+ },
+
+ /**
+ * @return string validation error message.
+ */
+ getErrorMessage : function()
+ {
+ return this.options.ErrorMessage;
+ },
+
+ /**
+ * Update the validator span, input CSS class, and focus particular
+ * element. Updating the validator control will set the validator
+ * visible property to true.
+ */
+ updateControl: function(focus)
+ {
+ this.refreshControlAndMessage();
+
+ if(this.options.FocusOnError && !this.isValid )
+ Prado.Element.focus(this.options.FocusElementID);
+ },
+
+ refreshControlAndMessage : function()
+ {
+ this.visible = true;
+ if(this.message)
+ {
+ if(this.options.Display == "Dynamic")
+ this.isValid ? this.message.hide() : this.message.show();
+ this.message.style.visibility = this.isValid ? "hidden" : "visible";
+ }
+ if(this.control)
+ this.updateControlCssClass(this.control, this.isValid);
+ },
+
+ /**
+ * Add a css class to the input control if validator is invalid,
+ * removes the css class if valid.
+ * @param object html control element
+ * @param boolean true to remove the css class, false to add.
+ */
+ updateControlCssClass : function(control, valid)
+ {
+ var CssClass = this.options.ControlCssClass;
+ if(typeof(CssClass) == "string" && CssClass.length > 0)
+ {
+ if(valid)
+ control.removeClassName(CssClass);
+ else
+ control.addClassName(CssClass);
+ }
+ },
+
+ /**
+ * Hides the validator messages and remove any validation changes.
+ */
+ hide : function()
+ {
+ this.isValid = true;
+ this.updateControl();
+ this.visible = false;
+ },
+
+ /**
+ * Calls evaluateIsValid() function to set the value of isValid property.
+ * Triggers onValidate event and onSuccess or onError event.
+ * @param HTMLElement element that calls for validation
+ * @return boolean true if valid.
+ */
+ validate : function(invoker)
+ {
+ if(typeof(this.options.OnValidate) == "function")
+ this.options.OnValidate(this, invoker);
+
+ if(this.enabled)
+ this.isValid = this.evaluateIsValid();
+ else
+ this.isValid = true;
+
+ if(this.isValid)
+ {
+ if(typeof(this.options.OnSuccess) == "function")
+ {
+ this.refreshControlAndMessage();
+ this.options.OnSuccess(this, invoker);
+ }
+ else
+ this.updateControl();
+ }
+ else
+ {
+ if(typeof(this.options.OnError) == "function")
+ {
+ this.refreshControlAndMessage();
+ this.options.OnError(this, invoker);
+ }
+ else
+ this.updateControl();
+ }
+
+ this.observeChanges(this.control);
+
+ return this.isValid;
+ },
+
+ /**
+ * Observe changes to the control input, re-validate upon change. If
+ * the validator is not visible, no updates are propagated.
+ * @param HTMLElement element that calls for validation
+ */
+ observeChanges : function(control)
+ {
+ if(!control) return;
+
+ var canObserveChanges = this.options.ObserveChanges != false;
+ var currentlyObserving = this._isObserving[control.id+this.options.ID];
+
+ if(canObserveChanges && !currentlyObserving)
+ {
+ var validator = this;
+
+ Event.observe(control, 'change', function()
+ {
+ if(validator.visible)
+ {
+ validator.validate();
+ validator.manager.updateSummary(validator.group);
+ }
+ });
+ this._isObserving[control.id+this.options.ID] = true;
+ }
+ },
+
+ /**
+ * @return string trims the string value, empty string if value is not string.
+ */
+ trim : function(value)
+ {
+ return typeof(value) == "string" ? value.trim() : "";
+ },
+
+ /**
+ * Convert the value to a specific data type.
+ * @param {string} the data type, "Integer", "Double", "Date" or "String"
+ * @param {string} the value to convert.
+ * @type {mixed|null} the converted data value.
+ */
+ convert : function(dataType, value)
+ {
+ if(typeof(value) == "undefined")
+ value = this.getValidationValue();
+ var string = new String(value);
+ switch(dataType)
+ {
+ case "Integer":
+ return string.toInteger();
+ case "Double" :
+ case "Float" :
+ return string.toDouble(this.options.DecimalChar);
+ case "Date":
+ if(typeof(value) != "string")
+ return value;
+ else
+ {
+ var value = string.toDate(this.options.DateFormat);
+ if(value && typeof(value.getTime) == "function")
+ return value.getTime();
+ else
+ return null;
+ }
+ case "String":
+ return string.toString();
+ }
+ return value;
+ },
+
+ /**
+ * The ControlType property comes from TBaseValidator::getClientControlClass()
+ * Be sure to update the TBaseValidator::$_clientClass if new cases are added.
+ * @return mixed control value to validate
+ */
+ getValidationValue : function(control)
+ {
+ if(!control)
+ control = this.control
+ switch(this.options.ControlType)
+ {
+ case 'TDatePicker':
+ if(control.type == "text")
+ {
+ value = this.trim($F(control));
+
+ if(this.options.DateFormat)
+ {
+ date = value.toDate(this.options.DateFormat);
+ return date == null ? value : date;
+ }
+ else
+ return value;
+ }
+ else
+ {
+ this.observeDatePickerChanges();
+
+ return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
+ }
+ case 'THtmlArea':
+ if(typeof tinyMCE != "undefined")
+ tinyMCE.triggerSave();
+ return this.trim($F(control));
+ case 'TRadioButton':
+ if(this.options.GroupName)
+ return this.getRadioButtonGroupValue();
+ default:
+ if(this.isListControlType())
+ return this.getFirstSelectedListValue();
+ else
+ return this.trim($F(control));
+ }
+ },
+
+ getRadioButtonGroupValue : function()
+ {
+ name = this.control.name;
+ value = "";
+ $A(document.getElementsByName(name)).each(function(el)
+ {
+ if(el.checked)
+ value = el.value;
+ });
+ return value;
+ },
+
+ /**
+ * Observe changes in the drop down list date picker, IE only.
+ */
+ observeDatePickerChanges : function()
+ {
+ if(Prado.Browser().ie)
+ {
+ var DatePicker = Prado.WebUI.TDatePicker;
+ this.observeChanges(DatePicker.getDayListControl(this.control));
+ this.observeChanges(DatePicker.getMonthListControl(this.control));
+ this.observeChanges(DatePicker.getYearListControl(this.control));
+ }
+ },
+
+ /**
+ * Gets numeber selections and their values.
+ * @return object returns selected values in values property
+ * and number of selections in checks property.
+ */
+ getSelectedValuesAndChecks : function(elements, initialValue)
+ {
+ var checked = 0;
+ var values = [];
+ var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+ elements.each(function(element)
+ {
+ if(element[isSelected] && element.value != initialValue)
+ {
+ checked++;
+ values.push(element.value);
+ }
+ });
+ return {'checks' : checked, 'values' : values};
+ },
+
+ /**
+ * Gets an array of the list control item input elements, for TCheckBoxList
+ * checkbox inputs are returned, for TListBox HTML option elements are returned.
+ * @return array list control option elements.
+ */
+ getListElements : function()
+ {
+ switch(this.options.ControlType)
+ {
+ case 'TCheckBoxList': case 'TRadioButtonList':
+ var elements = [];
+ for(var i = 0; i < this.options.TotalItems; i++)
+ {
+ var element = $(this.options.ControlToValidate+"_c"+i);
+ if(this.isCheckBoxType(element))
+ elements.push(element);
+ }
+ return elements;
+ case 'TListBox':
+ var elements = [];
+ var element = $(this.options.ControlToValidate);
+ if(element && (type = element.type.toLowerCase()))
+ {
+ if(type == "select-one" || type == "select-multiple")
+ elements = $A(element.options);
+ }
+ return elements;
+ default:
+ return [];
+ }
+ },
+
+ /**
+ * @return boolean true if element is of checkbox or radio type.
+ */
+ isCheckBoxType : function(element)
+ {
+ if(element && element.type)
+ {
+ var type = element.type.toLowerCase();
+ return type == "checkbox" || type == "radio";
+ }
+ return false;
+ },
+
+ /**
+ * @return boolean true if control to validate is of some of the TListControl type.
+ */
+ isListControlType : function()
+ {
+ var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
+ return list.include(this.options.ControlType);
+ },
+
+ /**
+ * @return string gets the first selected list value, initial value if none found.
+ */
+ getFirstSelectedListValue : function()
+ {
+ var initial = "";
+ if(typeof(this.options.InitialValue) != "undefined")
+ initial = this.options.InitialValue;
+ var elements = this.getListElements();
+ var selection = this.getSelectedValuesAndChecks(elements, initial);
+ return selection.values.length > 0 ? selection.values[0] : initial;
+ }
+}
+
+
+/**
+ * TRequiredFieldValidator makes the associated input control a required field.
+ * The input control fails validation if its value does not change from
+ * the InitialValue option upon losing focus.
+ *
+ * options['InitialValue'] Validation fails if control input equals initial value.
+ *
+ */
+Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * @return boolean true if the input value is not empty nor equal to the initial value.
+ */
+ evaluateIsValid : function()
+ {
+ var inputType = this.control.getAttribute("type");
+ if(inputType == 'file')
+ {
+ return true;
+ }
+ else
+ {
+ var a = this.getValidationValue();
+ var b = this.trim(this.options.InitialValue);
+ return(a != b);
+ }
+ }
+});
+
+
+/**
+ * TCompareValidator compares the value entered by the user into an input
+ * control with the value entered into another input control or a constant value.
+ * To compare the associated input control with another input control,
+ * set the ControlToCompare option to the ID path
+ * of the control to compare with. To compare the associated input control with
+ * a constant value, specify the constant value to compare with by setting the
+ * ValueToCompare option.
+ *
+ * The DataType property is used to specify the data type
+ * of both comparison values. Both values are automatically converted to this data
+ * type before the comparison operation is performed. The following value types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Date A date data type. The format can be by the DateFormat option.
+ * - String A string data type.
+ *
+ * Use the Operator property to specify the type of comparison
+ * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
+ * LessThan and LessThanEqual.
+ *
+ * options['ControlToCompare']
+ * options['ValueToCompare']
+ * options['Operator']
+ * options['Type']
+ * options['DateFormat']
+ *
+ */
+Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ //_observingComparee : false,
+
+ /**
+ * Compares the input to another input or a given value.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if (value.length <= 0)
+ return true;
+
+ var comparee = $(this.options.ControlToCompare);
+
+ if(comparee)
+ var compareTo = this.getValidationValue(comparee);
+ else
+ var compareTo = this.options.ValueToCompare || "";
+
+ var isValid = this.compare(value, compareTo);
+
+ if(comparee)
+ {
+ this.updateControlCssClass(comparee, isValid);
+ this.observeChanges(comparee);
+ }
+ return isValid;
+ },
+
+ /**
+ * Compares two values, their values are casted to type defined
+ * by DataType option. False is returned if the first
+ * operand converts to null. Returns true if the second operand
+ * converts to null. The comparision is done based on the
+ * Operator option.
+ */
+ compare : function(operand1, operand2)
+ {
+ var op1, op2;
+ if((op1 = this.convert(this.options.DataType, operand1)) == null)
+ return false;
+ if ((op2 = this.convert(this.options.DataType, operand2)) == null)
+ return true;
+ switch (this.options.Operator)
+ {
+ case "NotEqual":
+ return (op1 != op2);
+ case "GreaterThan":
+ return (op1 > op2);
+ case "GreaterThanEqual":
+ return (op1 >= op2);
+ case "LessThan":
+ return (op1 < op2);
+ case "LessThanEqual":
+ return (op1 <= op2);
+ default:
+ return (op1 == op2);
+ }
+ }
+});
+
+/**
+ * TCustomValidator performs user-defined client-side validation on an
+ * input component.
+ *
+ * To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:
+ *
+ *
+ *
+ * Use the ClientValidationFunction option
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.
+ *
+ * options['ClientValidationFunction'] custom validation function.
+ *
+ */
+Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Calls custom validation function.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ var clientFunction = this.options.ClientValidationFunction;
+ if(typeof(clientFunction) == "string" && clientFunction.length > 0)
+ {
+ validate = clientFunction.toFunction();
+ return validate(this, value);
+ }
+ return true;
+ }
+});
+
+/**
+ * TRangeValidator tests whether an input value is within a specified range.
+ *
+ * TRangeValidator uses three key properties to perform its validation.
+ * The MinValue and MaxValue options specify the minimum
+ * and maximum values of the valid range. The DataType option is
+ * used to specify the data type of the value and the minimum and maximum range values.
+ * These values are converted to this data type before the validation
+ * operation is performed. The following value types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Date A date data type. The date format can be specified by
+ * setting DateFormat option, which must be recognizable
+ * by Date.SimpleParse javascript function.
+ * - String A string data type.
+ *
+ * options['MinValue'] Minimum range value
+ * options['MaxValue'] Maximum range value
+ * options['DataType'] Value data type
+ * options['DateFormat'] Date format for date data type.
+ *
+ */
+Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Compares the input value with a minimum and/or maximum value.
+ * @return boolean true if the value is empty, returns false if conversion fails.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if(value.length <= 0)
+ return true;
+ if(typeof(this.options.DataType) == "undefined")
+ this.options.DataType = "String";
+
+ if(this.options.DataType != "StringLength")
+ {
+ var min = this.convert(this.options.DataType, this.options.MinValue || null);
+ var max = this.convert(this.options.DataType, this.options.MaxValue || null);
+ value = this.convert(this.options.DataType, value);
+ }
+ else
+ {
+ var min = this.options.MinValue || 0;
+ var max = this.options.MaxValue || Number.POSITIVE_INFINITY;
+ value = value.length;
+ }
+
+ if(value == null)
+ return false;
+
+ var valid = true;
+
+ if(min != null)
+ valid = valid && value >= min;
+ if(max != null)
+ valid = valid && value <= max;
+ return valid;
+ }
+});
+
+/**
+ * TRegularExpressionValidator validates whether the value of an associated
+ * input component matches the pattern specified by a regular expression.
+ *
+ * options['ValidationExpression'] regular expression to match against.
+ *
+ */
+Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Compare the control input against a regular expression.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if (value.length <= 0)
+ return true;
+
+ var rx = new RegExp(this.options.ValidationExpression);
+ var matches = rx.exec(value);
+ return (matches != null && value == matches[0]);
+ }
+});
+
+/**
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address.
+ */
+Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator;
+
+
+/**
+ * TListControlValidator checks the number of selection and their values
+ * for a TListControl that allows multiple selections.
+ */
+Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * @return true if the number of selections and/or their values
+ * match the requirements.
+ */
+ evaluateIsValid : function()
+ {
+ var elements = this.getListElements();
+ if(elements && elements.length <= 0)
+ return true;
+
+ this.observeListElements(elements);
+
+ var selection = this.getSelectedValuesAndChecks(elements);
+ return this.isValidList(selection.checks, selection.values);
+ },
+
+ /**
+ * Observe list elements for IE browsers of changes
+ */
+ observeListElements : function(elements)
+ {
+ if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
+ {
+ var validator = this;
+ elements.each(function(element)
+ {
+ validator.observeChanges(element);
+ });
+ }
+ },
+
+ /**
+ * Determine if the number of checked and the checked values
+ * satisfy the required number of checks and/or the checked values
+ * equal to the required values.
+ * @return boolean true if checked values and number of checks are satisfied.
+ */
+ isValidList : function(checked, values)
+ {
+ var exists = true;
+
+ //check the required values
+ var required = this.getRequiredValues();
+ if(required.length > 0)
+ {
+ if(values.length < required.length)
+ return false;
+ required.each(function(requiredValue)
+ {
+ exists = exists && values.include(requiredValue);
+ });
+ }
+
+ var min = typeof(this.options.Min) == "undefined" ?
+ Number.NEGATIVE_INFINITY : this.options.Min;
+ var max = typeof(this.options.Max) == "undefined" ?
+ Number.POSITIVE_INFINITY : this.options.Max;
+ return exists && checked >= min && checked <= max;
+ },
+
+ /**
+ * @return array list of required options that must be selected.
+ */
+ getRequiredValues : function()
+ {
+ var required = [];
+ if(this.options.Required && this.options.Required.length > 0)
+ required = this.options.Required.split(/,\s*/);
+ return required;
+ }
+});
+
+
+/**
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by DataType option.
+ * The following data types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Date A date data type.
+ * - String A string data type.
+ * For Date type, the option DateFormat
+ * will be used to determine how to parse the date string.
+ */
+Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
+{
+ evaluateIsValid : function()
+ {
+ value = this.getValidationValue();
+ if(value.length <= 0)
+ return true;
+ return this.convert(this.options.DataType, value) != null;
+ }
+});
+
diff --git a/framework/Web/Javascripts/ratings/blocks.css b/framework/Web/Javascripts/ratings/blocks.css
deleted file mode 100644
index b05d9eb6..00000000
--- a/framework/Web/Javascripts/ratings/blocks.css
+++ /dev/null
@@ -1,42 +0,0 @@
-.TRatingList_blocks
-{
- border-collapse: collapse;
-}
-.TRatingList_blocks input, .TRatingList_blocks label
-{
- display: none;
-}
-
-.TRatingList_blocks td
-{
- width: 18px;
- height: 9px;
- padding: 1px;
-}
-
-.TRatingList_blocks td.rating
-{
- background-image: url(blocks_combined.gif);
- background-repeat: no-repeat;
- cursor: pointer;
- background-position: 1px 0px;
-}
-.TRatingList_blocks td.rating_selected
-{
- background-position: 1px -100px;
-}
-
-.TRatingList_blocks td.rating_half
-{
- background-position: 1px -200px;
-}
-
-.TRatingList_blocks td.rating_hover
-{
- background-position: 1px -300px;
-}
-
-.TRatingList_blocks td.rating_disabled
-{
- cursor: default !important;
-}
diff --git a/framework/Web/Javascripts/ratings/blocks.png b/framework/Web/Javascripts/ratings/blocks.png
deleted file mode 100644
index 93a5333e..00000000
Binary files a/framework/Web/Javascripts/ratings/blocks.png and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/blocks_blank.gif b/framework/Web/Javascripts/ratings/blocks_blank.gif
deleted file mode 100644
index c0db17c2..00000000
Binary files a/framework/Web/Javascripts/ratings/blocks_blank.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/blocks_combined.gif b/framework/Web/Javascripts/ratings/blocks_combined.gif
deleted file mode 100644
index dfe9da8d..00000000
Binary files a/framework/Web/Javascripts/ratings/blocks_combined.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/blocks_half.gif b/framework/Web/Javascripts/ratings/blocks_half.gif
deleted file mode 100644
index a9e23d7c..00000000
Binary files a/framework/Web/Javascripts/ratings/blocks_half.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/blocks_selected.gif b/framework/Web/Javascripts/ratings/blocks_selected.gif
deleted file mode 100644
index f743d27e..00000000
Binary files a/framework/Web/Javascripts/ratings/blocks_selected.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/default.css b/framework/Web/Javascripts/ratings/default.css
deleted file mode 100644
index d404f843..00000000
--- a/framework/Web/Javascripts/ratings/default.css
+++ /dev/null
@@ -1,43 +0,0 @@
-.TRatingList_default
-{
- border-collapse: collapse;
-}
-.TRatingList_default input, .TRatingList_default label
-{
- display: none;
-}
-
-.TRatingList_default td
-{
- width: 18px;
- height: 18px;
- padding: 0;
-}
-
-.TRatingList_default td.rating
-{
- background-image: url(default_combined.gif);
- background-repeat: no-repeat;
- cursor: pointer;
- background-position: 0px 0px;
-}
-
-.TRatingList_default td.rating_selected
-{
- background-position: 0px -100px;
-}
-
-.TRatingList_default td.rating_half
-{
- background-position: 0px -200px;
-}
-
-.TRatingList_default td.rating_hover
-{
- background-position: 0px -300px;
-}
-
-.TRatingList_default td.rating_disabled
-{
- cursor: default !important;
-}
\ No newline at end of file
diff --git a/framework/Web/Javascripts/ratings/default.png b/framework/Web/Javascripts/ratings/default.png
deleted file mode 100644
index a3148ff4..00000000
Binary files a/framework/Web/Javascripts/ratings/default.png and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/default_blank.gif b/framework/Web/Javascripts/ratings/default_blank.gif
deleted file mode 100644
index 0337ad16..00000000
Binary files a/framework/Web/Javascripts/ratings/default_blank.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/default_combined.gif b/framework/Web/Javascripts/ratings/default_combined.gif
deleted file mode 100644
index ddab2e8b..00000000
Binary files a/framework/Web/Javascripts/ratings/default_combined.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/default_half.gif b/framework/Web/Javascripts/ratings/default_half.gif
deleted file mode 100644
index ed214acd..00000000
Binary files a/framework/Web/Javascripts/ratings/default_half.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/default_selected.gif b/framework/Web/Javascripts/ratings/default_selected.gif
deleted file mode 100644
index 98704fad..00000000
Binary files a/framework/Web/Javascripts/ratings/default_selected.gif and /dev/null differ
diff --git a/framework/Web/Javascripts/ratings/ratings.js b/framework/Web/Javascripts/ratings/ratings.js
deleted file mode 100644
index c8b19511..00000000
--- a/framework/Web/Javascripts/ratings/ratings.js
+++ /dev/null
@@ -1,178 +0,0 @@
-Prado.WebUI.TRatingList = Base.extend(
-{
- selectedIndex : -1,
- rating: -1,
- enabled : true,
- readOnly : false,
-
- constructor : function(options)
- {
- var cap = $(options.CaptionID);
- this.options = Object.extend(
- {
- caption : cap ? cap.innerHTML : ''
- }, options || {});
-
- Prado.WebUI.TRatingList.register(this);
- this._init();
- this.selectedIndex = options.SelectedIndex;
- this.rating = options.Rating;
- if(options.Rating <= 0 && options.SelectedIndex >= 0)
- this.rating = options.SelectedIndex+1;
- this.showRating(this.rating);
- },
-
- _init: function(options)
- {
- Element.addClassName($(this.options.ListID),this.options.Style);
- this.radios = new Array();
- var index=0;
- for(var i = 0; i
s into linebreaks. [Jon Tirsen]
+
+* New Control.Slider() for horizontal and vertical sliders [Marty Haught]
+
+* Fixed autoapplying a 'layout' on IE with Effect.Opacity not working for elements given as id string
+
+* Make Effect.Parallel render final frames and call beforeFinish/afterFinish on included effects
+
+* Make Element.setOpacity work correctly again (browser-specific extensions, except for IE, are disabled at this time)
+
+* Added focusing the text field or text area created when using Ajax.InPlaceEditor #2126 [thx to Lee Mallabone]
+
+* Fixed Element.Class.childrenWith not returning the correct elements #2120 [cmees AT rogers DOT com]
+
+* Added MIT-LICENSE header to scriptaculous.js, cut back on license info in other libs to keep files smaller
+
+* Fix issues with form elements inside draggables not clickable with Firefox #2129
+
+* Fixed an error in dragdrop.js with Draggables when no Droppables are defined
+
+* Fixed an issue with Element.makePositioned causing Effect.SlideDown to fail on Safari
+
+* Make effects "stateless" by cleaning up element.style after finish of effect #2133 [agr30 AT uni-koeln DOT de]
+
+* Add "internal" events to effects, to make them more easily extendable [Martin Bialasinski]
+
+* Set container element height to auto on finishing Effect.BlindDown und Effect.SlideDown #2123 [Tony Arnold]
+
+* Fixed a weird char in dragdrop.js
+
+* Controls.js Autocompleter.Base.updateElement() hook #2116 [Rob Wills]
+
+* Refactoring to use the Prototype enumerable extensions
+
+* Update to Prototype 1.4.0_pre4
+
+*V1.5.0_pre4*
+
+* Added a queue option to effects for easy stacking and simple timeline building. Valid values are "front", "end" and "parallel" (default), see for test/functional/effects_queue_test.html for usage
+
+* Added a setup function to the core effects that gets called by Effect.Base when first entering into running state, which allows them to query the current state of an element or other page properties when queuing and/or delays are used
+
+* Added a state instance variable to Effect.Base that indicates whether a effect that uses the queue is idle, running or finished
+
+* Fixed a flicker with Effect.Puff
+
+* General code cleaning to get rid of (legitimate) Mozilla strict javascript warnings
+
+* Changes to assertVisible in unittest.js
+
+* Slight refactoring of Effect.Text, now known as Effect.multiple(), change first parameter to also accept an array of strings or elements, or a NodeList of elements (if a single element or a string is given, defaults to $('element').childNodes)
+
+* Made tagifyText work with IE. defaults to a style of "position: relative; zoom:1;" for the created SPAN wrappers. It also replaces spaces with non-breakable spaces. These sit-ups are required to work around problems with rendering elements with the proprietary IE "layout" and non-quirksmode documents.
+
+* Add a break to scriptaculous.js when the includes are done [thx to Danilo Celic]
+
+* Fixed a problem with the Autocompleter when hitting ESC would select the entry in IE and redisplay the entries box in Safari
+
+* Fixed that the onDrop callback on Droppables didn't receive the dopped element as second parameter
+
+* Make check for correct Prototype version on loading script.aculo.us
+
+* Changed implementation of Builder to an innerHTML-based approach to make it work with IE6 (note: removed special "style" handling for now)
+
+* Changed non-sync Effects to use a common setInterval call for better timing and page update speeds. See the new Effect.Queue object.
+
+* Fixed a problem with setting opacity in Effect.Opacity to very small values
+
+* Changed the implemention of Effect.Base to use setInterval
+
+* Set version number to 1.5_pre4_trunk
+
+* Added experimental Effect.Text function that allows to start delayed text effects, see test/functional/texteffects_test.html.
+
+* Added experimental Effect.tagifyText(element) which wraps an elements text nodes characters in relatively positioned span elements
+
+* Added "delay" option to Effect.Base to start an effect only after a specified delay
+
+* Finetuning unittest.js + even more unit tests
+
+* Added support for Firefox and Konqueror automatic unit testing on Linux [Michael Schuerig]
+
+* Added basic unit test files for Effects, updated unit testing tests
+
+* Fix typo in lib/prototype.js fix in R2069 (whoops)
+
+* Added unit test for Position.clone
+
+* Made the Postition.cumulative override recognize KHTML and AppleWebKit
+
+* Fix the "hide form controls" iframe fix on the Autocompleter on Internet Explorer
+
+*V1.5.0_pre3*
+
+* More positioning fixes, expanded Element.clone [thx to Michael Schuerig]
+
+* Fixed some JavaScript warnings about redeclared vars [Courtenay]
+
+* Fixed a problem with autocompleting update divs not correctly positioned inside positioned elements [thx to Jonathan Feinberg]
+
+* Workaround for a Safari bug on absolutely positioned children of the BODY element
+
+* Added test/run_functional_test.html to more easily find your way around in the functional tests
+
+* Fixed some missing var declarations in effects.js
+
+* Support for automatic unit testing on IE/Win [Jon Tirsen]
+
+* Added loading the text for the Ajax.InPlaceEditor from the server, more CSS support [Richard Livsey, Jon Tirsen]
+
+* Made builder_test.html unit test work with Safari, fixed (one of two) caching issues with javascripttest.rb, added ajax_autocompleter_test.html to Rakefile unittests
+
+* Fixed Element.Class getting false matches on class names like classA-foobar, added unit tests [Martin Bialasinski]
+
+* Added a test to evluate the Fade/Appear effects across browsers and elements (test/functional/effects6_test.html)
+
+* Framework for completely self-running in-browser unit tests on Mac OS X (try "rake unittest") [Jon Tirsen]
+
+* Updates to Ajax.InPlaceEditor (Highlighting, Ajax options, more) [Jon Tirsen]
+
+* Made event registering on Draggables happen per drag for improved performance [thx to Cathy]
+
+* Moved Element.collectTextNodesIgnoreClass to util.js (preparation for refactoring)
+
+* Made sortable onChange option work again
+
+* Fixed a bug with Sortables resulting in wrong result when using Sortable.serialize with onUpdate on ghostly Sortables [thx Richard Livsey, Caleb Buxton]
+
+* Changed version number in scriptaculous.js to 1.5_pre3
+
+* Moved setting focus in Autocompleter to updateElement function to make it overridable [Brian Palmer]
+
+* Added special handling for style attributes to Builder [Michael Schuerig]
+
+* Changed opacity=1.0 check back to be inline with its original (pre 1.5) implementation to prevent flickering in Firefox < 1.1 on opacity-based effects (this also fixes flickering with drag-and-drop, sortable lists and autocompleting text fields). Note that this potentially breaks correct colors in some situations. [thx to David Zülke]
+
+* Automatically deactivate browser built-in autocompletion on autocompleting textfields, fixes part of Rails #1824.
+
+* Fixed a problem with Ajax.InPlaceEditor causing a JavaScript exception on Safari [thx to Patrick Lenz]
+
+*V1.5.0_pre2*
+
+* Fixed a weird character in dragdrop.js, added check to allow empty containers on Sortables (useful with dropOnEmpty option) [thx to Dave Strus]
+
+* Added unit test runner file test/run_unit_tests.html, new unit test files must be listed in test/unit/index.html
+
+* Added unit tests for Prototype string functions
+
+*V1.5.0_pre1*
+
+* Prepared README for V1.5.0_pre1
+
+* Added a main scriptaculous.js file to load in the other libraries transparently:
+
+
+
+
+ in the HEAD section of an HTML file is now all that's needed to include all of the script.aculo.us libraries,
+ given that they all can be accessed by the same path as scriptaculous.js is.
+
+* Fixed possible problem with greedy Droppables when using the dropOnEmpty option on Sortable.create
+
+* Added new CSS/background color features to Ajax.InPlaceEditor [Jon Tirsen]
+
+* Added unit test for Autocompleter, first Version
+
+* Added Event.simulateKey/s to unittest.js. Note that due to a bug in Firefox this will only work with Firefox up to v1.0.4 (see https://bugzilla.mozilla.org/show_bug.cgi?id=289940)
+
+* Fixed a condition where standard a href=xxx links wouldn't work in autocomplete results. These do now, the onclick event is not cancelled. [thx to Jasper Slits]
+
+* Fix showing ghosting marker only on ghosting Sortables
+
+* Some more Builder stuff, expanded builder unit tests
+
+* Moved stuff that didn't belong into specific libs into util.js; util.js is now required for all script.aculo.us libs
+
+* Corrected weirdness in unittest.js
+
+* Added dropOnEmpty option to Sortables to allow dropping on empty lists (see test/functional/sortable3_test.html)
+
+* Changed algoritm for drag/drop position setting
+
+* Changed workaround for class attributes (fixes a Firefox 1.0 error) from klass to className to be more Javascriptesque [thx to Martin Bialasinski]
+
+* Fixed a typo in ajax_inplaceeditor_test.html
+
+* Updated Rakefile to add unittest.js and util.js to the package
+
+* Added util.js which contains various utlity functions and extensions to Prototype
+
+* Major restructuring
+
+* Added TEXTAREA support to Ajax.InPlaceEditor [Sanford Barr]
+
+* Added Ghost Train alpha 0.1.0. See ghosttrain/test.html.
+
+* More features for Ajax.InPlaceEditor [Jon Tirsen]
+
+* Tweaks to unittest.css [Thomas Fuchs]
+
+* Refactoring and new features in unittest.js [Thomas Fuchs] [Jon Tirsen]
+
+* Fixed a wrong variable reference in Effect.Scale
+
+* Fix Element.makePositioned to recognize the 'static' position
+
+* Allow to choose the parameter name for Ajax.Autocompleter [Cameron Braid]
+
+* Changed resolving indicator DOM element more flexibility [Cameron Braid]
+
+* Fixed a reference in Ajax.InPlaceEditor
+
+* Added contributors to unittest.js
+
+* Souped-up Ajax.InPlaceEditor, added support for a form id and specifying all the texts through options [Jon Tirsen]
+
+* Make unit testing look good [Michael Schuerig]
+
+* Changed default revert duration for Draggables to distance-dependent algorithm [suggested by San]
+
+* Fix double unescaping in Autocompleter
+
+* Refactoring auf Autocompleter classes to use camelCase (note: changes the syntax of some of the options)
+
+* Add updateElement option to Autocompleter [Rob Sharp]
+
+* Updated Ajax.InPlaceEditor, refactoring of unit testing [Jon Tirsen]
+
+* Added preliminary version of Ajax.InPlaceEditor to controls.js; added experimental Firefox only functional testing for it (inplaceeditor_result.html) [Jon Tirsen]
+
+* Added some addtional test files.
+
+* Fixes a bug with Droppables not recognizing a drop if no hoverclass is given [thanks drewie]
+
+* Fixes to ghosting marker, allow a predefined marker (element with id "dropmarker").
+
+* Changed Effect.Opacity to better handle 100% opacity
+
+* Various fixes to ghosting, improves compatiblity with Safari and IE. [thanks to David Zülke]
+
+* Added experimental ghosting option to Sortables. See sortable_functional_ghosting.html for usage.
+
+* Renamed the clone option on Draggables to "ghosting".
+
+* Added experimental "clone" option to Draggable to so that a "clone" stays in place while dragging a translucent version of the draggable element. Currently, this requires relatively positioned elements, and doesn't work with sortable lists (but should after some tweaking). See dragdrop_function_4.html test file for details.
+
+* Added Element.getStyle to find computed CSS styles of an element. Note: doesn't work in all cases in Safari, see my bug report at http://bugzilla.opendarwin.org/show_bug.cgi?id=4125
+
+*1.1beta1*
+
+* Fixed rendering of last frame of animation when from/to is not 0.0/1.0. [thanks to David Zülke]
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2 (patched w/ workaround for Ajax.Updater init bug)
+
+* Some refactoring of controls.js to get rid of "dirty" implementation detail (dont' ask)
+
+* Added returning the generated combined effects to allow for .cancel() on all effects
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2
+
+*Rails 0.13.1*
+
+* Updated Ajax.Autocompleter to deal with parameters options correctly [Martin Marinschek]
+
+* Updated controls.js to allow multple matches in local localcompletion [Ivan Krstic]
+
+* Make version of prototype.js in lib have a nicer Event object [David Zülke]
+
+* Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
+
+* Experimental: make version of prototype.js in lib destroy events on page unload to prevent browser memory leaks
+
+* Fixed a possible memory leak in dragdrop.js
+
+* Make version of prototype.js in lib compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() for testing [David Zülke]
+
+* Make effects.js, dragdrop.js and controls.js compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() [David Zülke]
+
+* Changed some tests to work better
+
+* Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
+
+* Removed a possible memory leaks with IE with sortables and droppables (removed references from elements)
+
+* Changes to class extension in effects.js
+
+* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with set CSS classes)
+
+* Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js
+
+* Added Effect.ScrollTo to smoothly scroll the page to an element
+
+* Better Firefox flickering handling on SlideUp/SlideDown
+
+* Some cleaning up in effects.js
+
+* Removed a possible memory leak in IE with draggables
+
+* Added support for cancelling dragging my hitting ESC
+
+* Changed logic of drag-and-drop to only include the last referenced droppable when firing a drop event. This change also offers slight performance gains. [Dominik Wagner]
+
+* Added addtional effects test page, added tests for scriptfragment matching
+
+*1.0.0*
+
+* Changed auto-hiding update div in Ajax.Autocompleter
+
+* Changed default serialization on Ajax.Autocompleter to use Form.Element.serialize
+
+* Added test file for drag/drop inside scrolled elements
+
+* Fixed dragging of unpositioned elements in Internet Explorer
+
+* Change default behaviour of Ajax.Autocompleter to do automatic overlapping, sizing and appear/fade effects
+
+* Fixed Internet Explorer hide-windowed-controls iframe handling
+
+* Changed Ajax.Autocompleter event handling
+
+* Added onShow/onHide callbacks to Ajax.Autocompleter to allow for customized handling/effects
+
+* Fixed SlideUp/SlideDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed BlindUp/BlindDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed draggables with revert:false on repeated drags behaving badly
+
+* Expanded the revert option on draggables to optionally take a function and revert only if it returns true
+
+* Added the dragged element as a parameter to the Draggables.notify callbacks [Michael Sokolov]
+
+* Removed a deprecated reference to Effect2 om Effect.Fold
+
+* Make the percentage on Element.setContentZoom absolute
+
+* Corrected rendering of Ajax.AutoCompleter when focus is lost while updating
+
+* Added (crude) functional tests
+
+* Some slight refactoring in controls.js
+
+* Changed dragdrop.js to use the Effect namespace for its effects
+
+* Updated to Prototype 1.3.0: removal of prototype-ext.js; refactoring.
+
+* Fixed behaviour of cursor keys in Safari on autocomplete script
+
+* Fixed Position.within_including_scrolloffsets
+
+* Fixed sortables that are absolutely positioned
+
+* Fixed unhandled whitespace in Ajax.Autocompleter
+
+* Updated prototype-ext.js to include additions for Ajax.Autocompleter
+
+* Added controls.js, contains AJAX autocompleting text fields from #960
+
+* Refactored Event object
+
+* Renamed effects2.js to effects.js
+
+* Fixed draggables on pages with no droppables
+
+* Moved Event, Position and Element.Class to prototype-ext.js in preparation to Rails 0.13
+
+* Added Effect.Transitions.pulse
+
+* Added Effect.Pulsate and Effect.Fold effect by Justin Palmer
+
+* Added transitions by Mark Pilgrim: .full, .none
+
+* Added effects by Mark Pilgrim: Effect.Grow, Effect.Shrink
+
+* Changed effects namespace to Effect. (Effect2 is deprecated, but works too)
+
+* Changed old Effect.ContentZoom class to Element.setContentZoom() function
+
+* Greatly expanded Effect.Highlight to have user-defined colors and autodetecting the background color
+
+* Converted remaining effects (Squish, Highlight) to new format
+
+* Sortable.create now passes the zindex, starteffect, reverteffect and endeffect options to the underlying Draggables
+
+* Sortable.serialize now honors the only option on Sortable.create
+
+* New overridable options on Draggables: zindex, starteffect, reverteffect, endeffect
+
+* Fix a Gecko engine flicker on Sortables in dragdrop.js
+
+* Fixed event.isLeftClick
+
+* Some small changes in effects2.js
+
+* Refactoring of dragdrop.js
+
+* Added an Object.prototype.inspect() and more verbose messages for js unit testing
+
+* Added test/unittest.js and initial tests in test/html.
+
+* Cleaning up of effects2.js (convert tabs to spaces)
+
+* Added Rakefile for distribution packaging (default task = make distribution, rake clean for cleaning up)
+
+* Initial check-in and directory layout for the script.aculo.us JavaScripts
diff --git a/framework/Web/Javascripts/scriptaculous/MIT-LICENSE b/framework/Web/Javascripts/scriptaculous/MIT-LICENSE
new file mode 100644
index 00000000..30ff1248
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/framework/Web/Javascripts/scriptaculous/README b/framework/Web/Javascripts/scriptaculous/README
new file mode 100644
index 00000000..94ff1307
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/README
@@ -0,0 +1,57 @@
+== script.aculo.us web 2.0 javascript
+
+The Web is changing. The 30-year-old terminal-like technology it was originally
+is gradually giving way to new ways of doing things. The power of AJAX allows
+for rich user interaction without the trouble that has bugged traditional
+web applications.
+
+Building upon the wonderful Prototype JavaScript library, script.aculo.us
+provides you with some great additional ingredients to mix in.
+
+For more information, see http://script.aculo.us/
+
+== What's new in this release?
+
+See the CHANGELOG file for information on what's new.
+
+== Installation/Usage
+
+script.aculo.us includes the Prototype JavaScript Framework
+V1.5.0. You can use later versions, as they become available
+(see http://prototype.conio.net).
+
+Put prototype.js, and the six files scriptaculous.js,
+builder.js, effects.js, dragdrop.js, controls.js and slider.js
+in a directory of your website, e.g. /javascripts.
+
+(The unittest.js file is optional and is only needed if you
+want to do unit testing on your own javascripts).
+
+Now, you can include the scripts by adding the following
+tags to the HEAD section of your HTML pages:
+
+
+
+
+scriptaculous.js will automatically load the other files of the
+script.aculo.us distribution in, provided they are accessible
+via the same path.
+
+See http://wiki.script.aculo.us/scriptaculous/show/Usage for detailed
+usage instructions.
+
+== The distribution
+
+Besides the script.aculo.us files in src, there's a complete
+test tree included which holds functional and unit tests for
+script.aculo.us.
+
+If you need examples on how to implement things, the best place to
+start is by opening test/run_functional_tests.html or
+test/run_unit_tests.html in your browser, and looking at
+the sources of the examples provided.
+
+== License
+
+script.aculo.us is licensed under the terms of the MIT License,
+see the included MIT-LICENSE file.
\ No newline at end of file
diff --git a/framework/Web/Javascripts/scriptaculous/builder.js b/framework/Web/Javascripts/scriptaculous/builder.js
new file mode 100644
index 00000000..199afc12
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/builder.js
@@ -0,0 +1,131 @@
+// script.aculo.us builder.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+ NODEMAP: {
+ AREA: 'map',
+ CAPTION: 'table',
+ COL: 'table',
+ COLGROUP: 'table',
+ LEGEND: 'fieldset',
+ OPTGROUP: 'select',
+ OPTION: 'select',
+ PARAM: 'object',
+ TBODY: 'table',
+ TD: 'table',
+ TFOOT: 'table',
+ TH: 'table',
+ THEAD: 'table',
+ TR: 'table'
+ },
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+ // due to a Firefox bug
+ node: function(elementName) {
+ elementName = elementName.toUpperCase();
+
+ // try innerHTML approach
+ var parentTag = this.NODEMAP[elementName] || 'div';
+ var parentElement = document.createElement(parentTag);
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + ">" + elementName + ">";
+ } catch(e) {}
+ var element = parentElement.firstChild || null;
+
+ // see if browser added wrapping tags
+ if(element && (element.tagName.toUpperCase() != elementName))
+ element = element.getElementsByTagName(elementName)[0];
+
+ // fallback to createElement approach
+ if(!element) element = document.createElement(elementName);
+
+ // abort if nothing could be created
+ if(!element) return;
+
+ // attributes (or text)
+ if(arguments[1])
+ if(this._isStringOrNumber(arguments[1]) ||
+ (arguments[1] instanceof Array)) {
+ this._children(element, arguments[1]);
+ } else {
+ var attrs = this._attributes(arguments[1]);
+ if(attrs.length) {
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" +elementName + " " +
+ attrs + ">" + elementName + ">";
+ } catch(e) {}
+ element = parentElement.firstChild || null;
+ // workaround firefox 1.0.X bug
+ if(!element) {
+ element = document.createElement(elementName);
+ for(attr in arguments[1])
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+ }
+ if(element.tagName.toUpperCase() != elementName)
+ element = parentElement.getElementsByTagName(elementName)[0];
+ }
+ }
+
+ // text, or array of children
+ if(arguments[2])
+ this._children(element, arguments[2]);
+
+ return element;
+ },
+ _text: function(text) {
+ return document.createTextNode(text);
+ },
+
+ ATTR_MAP: {
+ 'className': 'class',
+ 'htmlFor': 'for'
+ },
+
+ _attributes: function(attributes) {
+ var attrs = [];
+ for(attribute in attributes)
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+ '="' + attributes[attribute].toString().escapeHTML() + '"');
+ return attrs.join(" ");
+ },
+ _children: function(element, children) {
+ if(typeof children=='object') { // array can hold nodes and text
+ children.flatten().each( function(e) {
+ if(typeof e=='object')
+ element.appendChild(e)
+ else
+ if(Builder._isStringOrNumber(e))
+ element.appendChild(Builder._text(e));
+ });
+ } else
+ if(Builder._isStringOrNumber(children))
+ element.appendChild(Builder._text(children));
+ },
+ _isStringOrNumber: function(param) {
+ return(typeof param=='string' || typeof param=='number');
+ },
+ build: function(html) {
+ var element = this.node('div');
+ $(element).update(html.strip());
+ return element.down();
+ },
+ dump: function(scope) {
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each( function(tag){
+ scope[tag] = function() {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ }
+ });
+ }
+}
diff --git a/framework/Web/Javascripts/scriptaculous/controls.js b/framework/Web/Javascripts/scriptaculous/controls.js
new file mode 100644
index 00000000..46f2cc18
--- /dev/null
+++ b/framework/Web/Javascripts/scriptaculous/controls.js
@@ -0,0 +1,835 @@
+// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = {}
+Autocompleter.Base = function() {};
+Autocompleter.Base.prototype = {
+ baseInitialize: function(element, update, options) {
+ this.element = $(element);
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+
+ if(this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || {};
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if(typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix &&
+ (navigator.appVersion.indexOf('MSIE')>0) &&
+ (navigator.userAgent.indexOf('Opera')<0) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function() {
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function() {
+ this.stopIndicator();
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--
+ else this.index = this.entryCount-1;
+ this.getEntry(this.index).scrollIntoView(true);
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++
+ else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+ var value = '';
+ if (this.options.select) {
+ var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+ } else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+ var lastTokenPos = this.findLastToken();
+ if (lastTokenPos != -1) {
+ var newValue = this.element.value.substr(0, lastTokenPos + 1);
+ var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value;
+ } else {
+ this.element.value = value;
+ }
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.down());
+
+ if(this.update.firstChild && this.update.down().childNodes) {
+ this.entryCount =
+ this.update.down().childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if(this.entryCount==1 && this.options.autoSelect) {
+ this.selectEntry();
+ this.hide();
+ } else {
+ this.render();
+ }
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ if(this.getToken().length>=this.options.minChars) {
+ this.startIndicator();
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ getToken: function() {
+ var tokenPos = this.findLastToken();
+ if (tokenPos != -1)
+ var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
+ else
+ var ret = this.element.value;
+
+ return /\n/.test(ret) ? '' : ret;
+ },
+
+ findLastToken: function() {
+ var lastTokenPos = -1;
+
+ for (var i=0; i" + ret.join('') + "
";
+ }
+ }, options || {});
+ }
+});
+
+// AJAX in-place editor
+//
+// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+ setTimeout(function() {
+ Field.activate(field);
+ }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create();
+Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
+Ajax.InPlaceEditor.prototype = {
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = $(element);
+
+ this.options = Object.extend({
+ paramName: "value",
+ okButton: true,
+ okText: "ok",
+ cancelLink: true,
+ cancelText: "cancel",
+ savingText: "Saving...",
+ clickToEditText: "Click to edit",
+ okText: "ok",
+ rows: 1,
+ onComplete: function(transport, element) {
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
+ },
+ onFailure: function(transport) {
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
+ },
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ handleLineBreaks: true,
+ loadingText: 'Loading...',
+ savingClassName: 'inplaceeditor-saving',
+ loadingClassName: 'inplaceeditor-loading',
+ formClassName: 'inplaceeditor-form',
+ highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
+ highlightendcolor: "#FFFFFF",
+ externalControl: null,
+ submitOnBlur: false,
+ ajaxOptions: {},
+ evalScripts: false
+ }, options || {});
+
+ if(!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + "-inplaceeditor";
+ if ($(this.options.formId)) {
+ // there's already a form with that name, don't specify an id
+ this.options.formId = null;
+ }
+ }
+
+ if (this.options.externalControl) {
+ this.options.externalControl = $(this.options.externalControl);
+ }
+
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
+ if (!this.originalBackground) {
+ this.originalBackground = "transparent";
+ }
+
+ this.element.title = this.options.clickToEditText;
+
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+ this.mouseoverListener = this.enterHover.bindAsEventListener(this);
+ this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
+ Event.observe(this.element, 'click', this.onclickListener);
+ Event.observe(this.element, 'mouseover', this.mouseoverListener);
+ Event.observe(this.element, 'mouseout', this.mouseoutListener);
+ if (this.options.externalControl) {
+ Event.observe(this.options.externalControl, 'click', this.onclickListener);
+ Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ },
+ enterEditMode: function(evt) {
+ if (this.saving) return;
+ if (this.editing) return;
+ this.editing = true;
+ this.onEnterEditMode();
+ if (this.options.externalControl) {
+ Element.hide(this.options.externalControl);
+ }
+ Element.hide(this.element);
+ this.createForm();
+ this.element.parentNode.insertBefore(this.form, this.element);
+ if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
+ // stop the event to avoid a page refresh in Safari
+ if (evt) {
+ Event.stop(evt);
+ }
+ return false;
+ },
+ createForm: function() {
+ this.form = document.createElement("form");
+ this.form.id = this.options.formId;
+ Element.addClassName(this.form, this.options.formClassName)
+ this.form.onsubmit = this.onSubmit.bind(this);
+
+ this.createEditField();
+
+ if (this.options.textarea) {
+ var br = document.createElement("br");
+ this.form.appendChild(br);
+ }
+
+ if (this.options.okButton) {
+ okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = this.options.okText;
+ okButton.className = 'editor_ok_button';
+ this.form.appendChild(okButton);
+ }
+
+ if (this.options.cancelLink) {
+ cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+ cancelLink.onclick = this.onclickCancel.bind(this);
+ cancelLink.className = 'editor_cancel';
+ this.form.appendChild(cancelLink);
+ }
+ },
+ hasHTMLLineBreaks: function(string) {
+ if (!this.options.handleLineBreaks) return false;
+ return string.match(/
/i);
+ },
+ convertHTMLLineBreaks: function(string) {
+ return string.replace(/
/gi, "\n").replace(/
/gi, "\n").replace(/<\/p>/gi, "\n").replace(/