From b9b1105224ef72a45a384e51333b9cfe191be84e Mon Sep 17 00:00:00 2001 From: wei <> Date: Mon, 26 Mar 2007 07:06:21 +0000 Subject: rearrange javascript library --- .../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 | 136 - framework/Web/Javascripts/extended/builder.js | 24 - framework/Web/Javascripts/extended/date.js | 151 - framework/Web/Javascripts/extended/event.js | 109 - framework/Web/Javascripts/extended/string.js | 171 - framework/Web/Javascripts/extra/behaviour.js | 68 - .../Web/Javascripts/extra/getElementsBySelector.js | 176 -- framework/Web/Javascripts/extra/json.js | 340 -- framework/Web/Javascripts/extra/logger.js | 753 ----- framework/Web/Javascripts/js/compressed/prado.js | 184 +- framework/Web/Javascripts/js/debug/colorpicker.js | 119 +- framework/Web/Javascripts/js/debug/prado.js | 1423 ++++----- framework/Web/Javascripts/prado/activecontrols.js | 196 -- framework/Web/Javascripts/prado/ajax.js | 427 --- .../Javascripts/prado/colorpicker/background.png | Bin 0 -> 14501 bytes .../Web/Javascripts/prado/colorpicker/button.gif | Bin 0 -> 58 bytes .../Javascripts/prado/colorpicker/colorpicker.js | 532 ++++ .../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 | 253 -- .../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 | 163 - 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 | 1276 -------- .../Web/Javascripts/prado/validator/validation3.js | 1276 ++++++++ framework/Web/Javascripts/ratings/blocks.css | 29 - framework/Web/Javascripts/ratings/blocks.png | Bin 29885 -> 0 bytes framework/Web/Javascripts/ratings/blocks_blank.gif | Bin 72 -> 0 bytes framework/Web/Javascripts/ratings/blocks_half.gif | Bin 94 -> 0 bytes framework/Web/Javascripts/ratings/blocks_hover.gif | Bin 75 -> 0 bytes .../Web/Javascripts/ratings/blocks_selected.gif | Bin 75 -> 0 bytes framework/Web/Javascripts/ratings/default.css | 29 - .../Web/Javascripts/ratings/default_blank.gif | Bin 271 -> 0 bytes framework/Web/Javascripts/ratings/default_half.gif | Bin 619 -> 0 bytes .../Web/Javascripts/ratings/default_hover.gif | Bin 618 -> 0 bytes .../Web/Javascripts/ratings/default_selected.gif | Bin 614 -> 0 bytes framework/Web/Javascripts/ratings/ratings.js | 60 - framework/Web/Javascripts/ratings/stars1.png | Bin 53016 -> 0 bytes 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 ++ 93 files changed, 9941 insertions(+), 15184 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/event.js delete mode 100644 framework/Web/Javascripts/extended/string.js delete mode 100644 framework/Web/Javascripts/extra/behaviour.js delete mode 100644 framework/Web/Javascripts/extra/getElementsBySelector.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/prado/activecontrols.js delete mode 100644 framework/Web/Javascripts/prado/ajax.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_half.gif delete mode 100644 framework/Web/Javascripts/ratings/blocks_hover.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_blank.gif delete mode 100644 framework/Web/Javascripts/ratings/default_half.gif delete mode 100644 framework/Web/Javascripts/ratings/default_hover.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/ratings/stars1.png 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/Web') diff --git a/framework/Web/Javascripts/colorpicker/background.png b/framework/Web/Javascripts/colorpicker/background.png deleted file mode 100644 index 91798cf5..00000000 Binary files a/framework/Web/Javascripts/colorpicker/background.png and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/button.gif b/framework/Web/Javascripts/colorpicker/button.gif deleted file mode 100644 index 67f17975..00000000 Binary files a/framework/Web/Javascripts/colorpicker/button.gif and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/colorpicker.js b/framework/Web/Javascripts/colorpicker/colorpicker.js deleted file mode 100644 index acf5531c..00000000 --- a/framework/Web/Javascripts/colorpicker/colorpicker.js +++ /dev/null @@ -1,532 +0,0 @@ -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/colorpicker/default.css b/framework/Web/Javascripts/colorpicker/default.css deleted file mode 100644 index 67235c08..00000000 --- a/framework/Web/Javascripts/colorpicker/default.css +++ /dev/null @@ -1,258 +0,0 @@ - -/** 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/colorpicker/hue.gif b/framework/Web/Javascripts/colorpicker/hue.gif deleted file mode 100644 index 901e409c..00000000 Binary files a/framework/Web/Javascripts/colorpicker/hue.gif and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/slider.gif b/framework/Web/Javascripts/colorpicker/slider.gif deleted file mode 100644 index 92f9d744..00000000 Binary files a/framework/Web/Javascripts/colorpicker/slider.gif and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/spacer.gif b/framework/Web/Javascripts/colorpicker/spacer.gif deleted file mode 100755 index fc256098..00000000 Binary files a/framework/Web/Javascripts/colorpicker/spacer.gif and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/target_black.gif b/framework/Web/Javascripts/colorpicker/target_black.gif deleted file mode 100644 index ebb89f58..00000000 Binary files a/framework/Web/Javascripts/colorpicker/target_black.gif and /dev/null differ diff --git a/framework/Web/Javascripts/colorpicker/target_white.gif b/framework/Web/Javascripts/colorpicker/target_white.gif deleted file mode 100644 index c3527c86..00000000 Binary files a/framework/Web/Javascripts/colorpicker/target_white.gif and /dev/null differ diff --git a/framework/Web/Javascripts/datepicker/calendar.png b/framework/Web/Javascripts/datepicker/calendar.png deleted file mode 100644 index c245f1b4..00000000 Binary files a/framework/Web/Javascripts/datepicker/calendar.png and /dev/null differ diff --git a/framework/Web/Javascripts/datepicker/datepicker.js b/framework/Web/Javascripts/datepicker/datepicker.js deleted file mode 100644 index 2f1e8261..00000000 --- a/framework/Web/Javascripts/datepicker/datepicker.js +++ /dev/null @@ -1,696 +0,0 @@ -Prado.WebUI.TDatePicker = Class.create(); -Object.extend(Prado.WebUI.TDatePicker, -{ - /** - * @return Date the date from drop down list options. - */ - getDropDownDate : function(control) - { - var now=new Date(); - var year=now.getFullYear(); - var month=now.getMonth(); - var day=1; - - var month_list = this.getMonthListControl(control); - var day_list = this.getDayListControl(control); - var year_list = this.getYearListControl(control); - - var day = day_list ? $F(day_list) : 1; - var month = month_list ? $F(month_list) : now.getMonth(); - var year = year_list ? $F(year_list) : now.getFullYear(); - - return new Date(year,month,day, 0, 0, 0); - }, - - getYearListControl : function(control) - { - return $(control.id+"_year"); - }, - - getMonthListControl : function(control) - { - return $(control.id+"_month"); - }, - - getDayListControl : function(control) - { - return $(control.id+"_day"); - } -}); - -Prado.WebUI.TDatePicker.prototype = -{ - MonthNames : [ "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" - ], - AbbreviatedMonthNames : ["Jan", "Feb", "Mar", "Apr", "May", - "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], - - ShortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], - - Format : "yyyy-MM-dd", - - FirstDayOfWeek : 1, // 0 for sunday - - ClassName : "", - - CalendarStyle : "default", - - FromYear : 2000, UpToYear: 2015, - - initialize : function(options) - { - this.options = options || []; - this.control = $(options.ID); - this.dateSlot = new Array(42); - this.weekSlot = new Array(6); - this.minimalDaysInFirstWeek = 4; - this.selectedDate = this.newDate(); - - //which element to trigger to show the calendar - if(this.options.Trigger) - { - this.trigger = $(this.options.Trigger) ; - var triggerEvent = this.options.TriggerEvent || "click"; - } - else - { - this.trigger = this.control; - var triggerEvent = this.options.TriggerEvent || "focus"; - } - - Object.extend(this,options); - - Event.observe(this.trigger, triggerEvent, this.show.bindEvent(this)); - - }, - - create : function() - { - if(typeof(this._calDiv) != "undefined") - return; - - var div; - var table; - var tbody; - var tr; - var td; - - // Create the top-level div element - this._calDiv = document.createElement("div"); - this._calDiv.className = "TDatePicker_"+this.CalendarStyle+" "+this.ClassName; - this._calDiv.style.display = "none"; - this._calDiv.style.position = "absolute" - - // header div - div = document.createElement("div"); - div.className = "calendarHeader"; - this._calDiv.appendChild(div); - - table = document.createElement("table"); - table.style.cellSpacing = 0; - div.appendChild(table); - - tbody = document.createElement("tbody"); - table.appendChild(tbody); - - tr = document.createElement("tr"); - tbody.appendChild(tr); - - // Previous Month Button - td = document.createElement("td"); - var previousMonth = document.createElement("input"); - previousMonth.className = "prevMonthButton button"; - previousMonth.type = "button" - previousMonth.value = "<<"; - td.appendChild(previousMonth); - tr.appendChild(td); - - - - // - // Create the month drop down - // - td = document.createElement("td"); - tr.appendChild(td); - this._monthSelect = document.createElement("select"); - this._monthSelect.className = "months"; - for (var i = 0 ; i < this.MonthNames.length ; i++) { - var opt = document.createElement("option"); - opt.innerHTML = this.MonthNames[i]; - opt.value = i; - if (i == this.selectedDate.getMonth()) { - opt.selected = true; - } - this._monthSelect.appendChild(opt); - } - td.appendChild(this._monthSelect); - - - // - // Create the year drop down - // - td = document.createElement("td"); - td.className = "labelContainer"; - tr.appendChild(td); - this._yearSelect = document.createElement("select"); - for(var i=this.FromYear; i <= this.UpToYear; ++i) { - var opt = document.createElement("option"); - opt.innerHTML = i; - opt.value = i; - if (i == this.selectedDate.getFullYear()) { - opt.selected = false; - } - this._yearSelect.appendChild(opt); - } - td.appendChild(this._yearSelect); - - - td = document.createElement("td"); - var nextMonth = document.createElement("input"); - nextMonth.className = "nextMonthButton button"; - nextMonth.type = "button"; - nextMonth.value = ">>"; - td.appendChild(nextMonth); - tr.appendChild(td); - - // Calendar body - div = document.createElement("div"); - div.className = "calendarBody"; - this._calDiv.appendChild(div); - var calendarBody = div; - - // Create the inside of calendar body - - var text; - table = document.createElement("table"); - table.align="center"; - table.className = "grid"; - - div.appendChild(table); - var thead = document.createElement("thead"); - table.appendChild(thead); - tr = document.createElement("tr"); - thead.appendChild(tr); - - for(i=0; i < 7; ++i) { - td = document.createElement("th"); - text = document.createTextNode(this.ShortWeekDayNames[(i+this.FirstDayOfWeek)%7]); - td.appendChild(text); - td.className = "weekDayHead"; - tr.appendChild(td); - } - - // Date grid - tbody = document.createElement("tbody"); - table.appendChild(tbody); - - for(week=0; week<6; ++week) { - tr = document.createElement("tr"); - tbody.appendChild(tr); - - for(day=0; day<7; ++day) { - td = document.createElement("td"); - td.className = "calendarDate"; - text = document.createTextNode(String.fromCharCode(160)); - td.appendChild(text); - - tr.appendChild(td); - var tmp = new Object(); - tmp.tag = "DATE"; - tmp.value = -1; - tmp.data = text; - this.dateSlot[(week*7)+day] = tmp; - - Event.observe(td, "mouseover", this.hover.bindEvent(this)); - Event.observe(td, "mouseout", this.hover.bindEvent(this)); - - } - } - - // Calendar Footer - div = document.createElement("div"); - div.className = "calendarFooter"; - this._calDiv.appendChild(div); - - var todayButton = document.createElement("input"); - todayButton.type="button"; - todayButton.className = "todayButton"; - var today = this.newDate(); - var buttonText = today.SimpleFormat(this.Format,this); - todayButton.value = buttonText; - div.appendChild(todayButton); - - if(Prado.Browser().ie) - { - this.iePopUp = document.createElement('iframe'); - this.iePopUp.src = Prado.WebUI.TDatePicker.spacer; - this.iePopUp.style.position = "absolute" - this.iePopUp.scrolling="no" - this.iePopUp.frameBorder="0" - this.control.parentNode.appendChild(this.iePopUp); - } - - this.control.parentNode.appendChild(this._calDiv); - - this.update(); - this.updateHeader(); - - this.ieHack(true); - - // IE55+ extension - previousMonth.hideFocus = true; - nextMonth.hideFocus = true; - todayButton.hideFocus = true; - // end IE55+ extension - - // hook up events - Event.observe(previousMonth, "click", this.prevMonth.bindEvent(this)); - Event.observe(nextMonth, "click", this.nextMonth.bindEvent(this)); - Event.observe(todayButton, "click", this.selectToday.bindEvent(this)); - //Event.observe(clearButton, "click", this.clearSelection.bindEvent(this)); - Event.observe(this._monthSelect, "change", this.monthSelect.bindEvent(this)); - Event.observe(this._yearSelect, "change", this.yearSelect.bindEvent(this)); - - // ie6 extension - Event.observe(this._calDiv, "mousewheel", this.mouseWheelChange.bindEvent(this)); - - Event.observe(calendarBody, "click", this.selectDate.bindEvent(this)); - - Prado.Element.focus(this.control); - - }, - - ieHack : function(cleanup) - { - // IE hack - if(this.iePopUp) - { - this.iePopUp.style.display = "block"; - this.iePopUp.style.top = (this._calDiv.offsetTop -1 ) + "px"; - this.iePopUp.style.left = (this._calDiv.offsetLeft -1)+ "px"; - this.iePopUp.style.width = Math.abs(this._calDiv.offsetWidth -2)+ "px"; - this.iePopUp.style.height = (this._calDiv.offsetHeight + 1)+ "px"; - if(cleanup) this.iePopUp.style.display = "none"; - } - }, - - keyPressed : function(ev) - { - if(!this.showing) return; - if (!ev) ev = document.parentWindow.event; - var kc = ev.keyCode != null ? ev.keyCode : ev.charCode; - - if(kc == Event.KEY_RETURN || kc == Event.KEY_SPACEBAR || kc == Event.KEY_TAB) - { - this.setSelectedDate(this.selectedDate); - Event.stop(ev); - this.hide(); - } - if(kc == Event.KEY_ESC) - { - Event.stop(ev); this.hide(); - } - - var getDaysPerMonth = function (nMonth, nYear) - { - nMonth = (nMonth + 12) % 12; - var days= [31,28,31,30,31,30,31,31,30,31,30,31]; - var res = days[nMonth]; - if (nMonth == 1) //feburary, leap years has 29 - res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0; - return res; - } - - if(kc < 37 || kc > 40) return true; - - var current = this.selectedDate; - var d = current.valueOf(); - if(kc == Event.KEY_LEFT) - { - if(ev.ctrlKey || ev.shiftKey) // -1 month - { - current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() - 1,current.getFullYear())) ); // no need to catch dec -> jan for the year - d = current.setMonth( current.getMonth() - 1 ); - } - else - d -= 86400000; //-1 day - } - else if (kc == Event.KEY_RIGHT) - { - if(ev.ctrlKey || ev.shiftKey) // +1 month - { - current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() + 1,current.getFullYear())) ); // no need to catch dec -> jan for the year - d = current.setMonth( current.getMonth() + 1 ); - } - else - d += 86400000; //+1 day - } - else if (kc == Event.KEY_UP) - { - if(ev.ctrlKey || ev.shiftKey) //-1 year - { - current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() - 1)) ); // no need to catch dec -> jan for the year - d = current.setFullYear( current.getFullYear() - 1 ); - } - else - d -= 604800000; // -7 days - } - else if (kc == Event.KEY_DOWN) - { - if(ev.ctrlKey || ev.shiftKey) // +1 year - { - current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() + 1)) ); // no need to catch dec -> jan for the year - d = current.setFullYear( current.getFullYear() + 1 ); - } - else - d += 7 * 24 * 61 * 60 * 1000; // +7 days - } - this.setSelectedDate(d); - Event.stop(ev); - }, - - selectDate : function(ev) - { - var el = Event.element(ev); - while (el.nodeType != 1) - el = el.parentNode; - - while (el != null && el.tagName && el.tagName.toLowerCase() != "td") - el = el.parentNode; - - // if no td found, return - if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td") - return; - - var d = this.newDate(this.selectedDate); - var n = Number(el.firstChild.data); - if (isNaN(n) || n <= 0 || n == null) - return; - - d.setDate(n); - this.setSelectedDate(d); - this.hide(); - }, - - selectToday : function() - { - if(this.selectedDate.toISODate() == this.newDate().toISODate()) - this.hide(); - - this.setSelectedDate(this.newDate()); - }, - - clearSelection : function() - { - this.setSelectedDate(this.newDate()); - this.hide(); - }, - - monthSelect : function(ev) - { - this.setMonth(Form.Element.getValue(Event.element(ev))); - }, - - yearSelect : function(ev) - { - this.setYear(Form.Element.getValue(Event.element(ev))); - }, - - // ie6 extension - mouseWheelChange : function (e) - { - if (e == null) e = document.parentWindow.event; - var n = - e.wheelDelta / 120; - var d = this.newDate(this.selectedDate); - var m = d.getMonth() + n; - this.setMonth(m); - - return false; - }, - - onChange : function() - { - if(this.options.InputMode == "TextBox") - { - this.control.value = this.formatDate(); - Event.fireEvent(this.control, "change"); - } - else - { - var day = Prado.WebUI.TDatePicker.getDayListControl(this.control); - var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control); - var year = Prado.WebUI.TDatePicker.getYearListControl(this.control); - var date = this.selectedDate; - if(day) - { - day.selectedIndex = date.getDate()-1; - } - if(month) - { - month.selectedIndex = date.getMonth(); - } - if(year) - { - var years = year.options; - var currentYear = date.getFullYear(); - for(var i = 0; i < years.length; i++) - years[i].selected = years[i].value.toInteger() == currentYear; - } - Event.fireEvent(day || month || year, "change"); - } - }, - - formatDate : function() - { - return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format,this) : ''; - }, - - newDate : function(date) - { - if(!date) - date = new Date(); - if(typeof(date) == "string" || typeof(date) == "number") - date = new Date(date); - return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0); - }, - - setSelectedDate : function(date) - { - if (date == null) - return; - this.selectedDate = this.newDate(date); - - this.updateHeader(); - this.update(); - if (typeof(this.onChange) == "function") - this.onChange(this, date); - }, - - getElement : function() - { - return this._calDiv; - }, - - getSelectedDate : function () - { - return this.selectedDate == null ? null : this.newDate(this.selectedDate); - }, - - setYear : function(year) - { - var d = this.newDate(this.selectedDate); - d.setFullYear(year); - this.setSelectedDate(d); - }, - - setMonth : function (month) - { - var d = this.newDate(this.selectedDate); - d.setMonth(month); - this.setSelectedDate(d); - }, - - nextMonth : function () - { - this.setMonth(this.selectedDate.getMonth()+1); - }, - - prevMonth : function () - { - this.setMonth(this.selectedDate.getMonth()-1); - }, - - getDatePickerOffsetHeight : function() - { - if(this.options.InputMode == "TextBox") - return this.control.offsetHeight; - - var control = Prado.WebUI.TDatePicker.getDayListControl(this.control); - if(control) return control.offsetHeight; - - var control = Prado.WebUI.TDatePicker.getMonthListControl(this.control); - if(control) return control.offsetHeight; - - var control = Prado.WebUI.TDatePicker.getYearListControl(this.control); - if(control) return control.offsetHeight; - return 0; - }, - - show : function() - { - this.create(); - - if(!this.showing) - { - var pos = Position.positionedOffset(this.control); - - pos[1] += this.getDatePickerOffsetHeight(); - - this._calDiv.style.display = "block"; - this._calDiv.style.top = (pos[1]-1) + "px"; - this._calDiv.style.left = pos[0] + "px"; - - this.ieHack(false); - this.documentClickEvent = this.hideOnClick.bindEvent(this); - this.documentKeyDownEvent = this.keyPressed.bindEvent(this); - Event.observe(document.body, "click", this.documentClickEvent); - var date = this.getDateFromInput(); - if(date) - { - this.selectedDate = date; - this.setSelectedDate(date); - } - Event.observe(document,"keydown", this.documentKeyDownEvent); - this.showing = true; - } - }, - - getDateFromInput : function() - { - if(this.options.InputMode == "TextBox") - return Date.SimpleParse($F(this.control), this.Format); - else - return Prado.WebUI.TDatePicker.getDropDownDate(this.control); - }, - - //hide the calendar when clicked outside any calendar - hideOnClick : function(ev) - { - if(!this.showing) return; - var el = Event.element(ev); - var within = false; - do - { - within = within || (el.className && Element.hasClassName(el, "TDatePicker_"+this.CalendarStyle)); - within = within || el == this.trigger; - within = within || el == this.control; - if(within) break; - el = el.parentNode; - } - while(el); - if(!within) this.hide(); - }, - - - hide : function() - { - if(this.showing) - { - this._calDiv.style.display = "none"; - if(this.iePopUp) - this.iePopUp.style.display = "none"; - this.showing = false; - Event.stopObserving(document.body, "click", this.documentClickEvent); - Event.stopObserving(document,"keydown", this.documentKeyDownEvent); - } - }, - - update : function() - { - // Calculate the number of days in the month for the selected date - var date = this.selectedDate; - var today = (this.newDate()).toISODate(); - - var selected = date.toISODate(); - var d1 = new Date(date.getFullYear(), date.getMonth(), 1); - var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1); - var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000)); - - // Find out the weekDay index for the first of this month - var firstIndex = (d1.getDay() - this.FirstDayOfWeek) % 7 ; - if (firstIndex < 0) - firstIndex += 7; - - var index = 0; - while (index < firstIndex) { - this.dateSlot[index].value = -1; - this.dateSlot[index].data.data = String.fromCharCode(160); - this.dateSlot[index].data.parentNode.className = "empty"; - index++; - } - - for (i = 1; i <= monthLength; i++, index++) { - var slot = this.dateSlot[index]; - var slotNode = slot.data.parentNode; - slot.value = i; - slot.data.data = i; - slotNode.className = "date"; - //slotNode.style.color = ""; - if (d1.toISODate() == today) { - slotNode.className += " today"; - } - if (d1.toISODate() == selected) { - // slotNode.style.color = "blue"; - slotNode.className += " selected"; - } - d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1); - } - - var lastDateIndex = index; - - while(index < 42) { - this.dateSlot[index].value = -1; - this.dateSlot[index].data.data = String.fromCharCode(160); - this.dateSlot[index].data.parentNode.className = "empty"; - ++index; - } - - }, - - hover : function(ev) - { - if(Event.element(ev).tagName) - { - if(ev.type == "mouseover") - Event.element(ev).addClassName("hover"); - else - Event.element(ev).removeClassName("hover"); - } - }, - - updateHeader : function () { - - var options = this._monthSelect.options; - var m = this.selectedDate.getMonth(); - for(var i=0; i < options.length; ++i) { - options[i].selected = false; - if (options[i].value == m) { - options[i].selected = true; - } - } - - options = this._yearSelect.options; - var year = this.selectedDate.getFullYear(); - for(var i=0; i < options.length; ++i) { - options[i].selected = false; - if (options[i].value == year) { - options[i].selected = true; - } - } - - } - - -}; \ No newline at end of file diff --git a/framework/Web/Javascripts/datepicker/default.css b/framework/Web/Javascripts/datepicker/default.css deleted file mode 100644 index 9532dad0..00000000 --- a/framework/Web/Javascripts/datepicker/default.css +++ /dev/null @@ -1,98 +0,0 @@ -.TDatePicker_default -{ - border: 1px solid #919EA9; - background-color: White; - text-align: center; - font-size: 11px; - font-family: Tahoma, Arial, Helvetica, sans-serif; - cursor: default; -} - -.TDatePickerButton -{ - width: 30px; -} - -.TDatePickerImageButton -{ - padding: 2px; - border: 1px solid #919EA9; - vertical-align: top; - margin-left: 1px; -} - - -.TDatePickerImageButton:hover -{ - border-color: #ddd; -} - -.TDatePicker_default select -{ - font-size: 11px; -} - -.TDatePicker_default input.button -{ - font-size: 11px; - width: 32px; -} - -.TDatePicker_default .date -{ - padding: 4px 0; - border: 1px solid white; - text-align: center; -} -.TDatePicker_default .hover -{ - border: 1px solid blue; -} -.TDatePicker_default .selected -{ - background-color: blue; - border: 1px solid blue; - color: white; -} -.TDatePicker_default .today -{ - font-weight: bold; -} - -.TDatePicker_default td.empty -{ - border: 1px solid white; - cursor: default; - height: 22px; -} - -.TDatePicker_default th -{ - width: 28px; -} - -.TDatePicker_default .calendarBody -{ - text-align: center; - width: 210px; - margin: 3px 6px; -} - -.TDatePicker_default .grid -{ - border-spacing: 0px; -} - -.TDatePicker_default .calendarFooter -{ - margin: 2px; - border-top: 1px solid #919EA9; - padding-top: 2px; -} -.TDatePicker_default .todayButton -{ - font-size: 11px; - margin: 4px; - padding-left: 1em; - padding-right: 1em; -} \ No newline at end of file diff --git a/framework/Web/Javascripts/datepicker/spacer.gif b/framework/Web/Javascripts/datepicker/spacer.gif deleted file mode 100755 index fc256098..00000000 Binary files a/framework/Web/Javascripts/datepicker/spacer.gif and /dev/null differ diff --git a/framework/Web/Javascripts/effects/CHANGELOG b/framework/Web/Javascripts/effects/CHANGELOG deleted file mode 100644 index 323ca859..00000000 --- a/framework/Web/Javascripts/effects/CHANGELOG +++ /dev/null @@ -1,980 +0,0 @@ -*V1.7.0* (January 19, 2007) - -* Cleanups for Effect.Morph - -* Monkeypatch Prototype 1.5.0 to incorporate [6002], fixes setStyle({opacity:0}) for IE - -* Fix Effect.inspect() for Prototype 1.5.0 final hash changes - -* Update to Prototype 1.5.0 final - -* New option keepBackgroundImage: true for Effect.Highlight, fixes #5037 [docwhat, tomg] - -* Minor tweaks for issues with application/xhtml+xml documents on Firefox, fixes #6836 [sjinks] - -* Fix a possible exception with Sortables, fixes #6828 [craiggwilson] - -* Update to Prototype 1.5.0_rc2 revision [5844] (as of Rails 1.2 RC 2) - -*V1.7.0 beta 2* (December 18, 2006) - -* Change the default setting for effects to support up to 60fps, if renderable by the browser. Add performance info to effects unit test. - -* Change get/setOpacity to use Prototype's new support for cross-browser opacity. - -* Update to Prototype 1.5.0_rc2 revision [5741], which fixes some of the reported issues with beta 1 (see Prototype's CHANGELOG for more): - * Opera 9, while not officially supported, should work now with Prototype and script.aculo.us - * Fixes issue with Safari when using Prototype's Ajax helpers with HTTP authorization - -* Add hash and CSS className support to Effect.Morph, fixes #6674 [Tobie] - Examples: - $(element).morph('myClass') - // will morph to all the properties specified - // in .className (in your external stylesheet). - // All properties which cannot be morphed (such as font-style) - // will be applied AfterFinish - $(element).morph('font-size: 10px') // or - $(element).morph({fontSize: '10px'}) // will morph the font-size to 10px - -*V1.7.0 beta 1* (November 21, 2006) - -* Add Element.morph() and Element.Methods.morph() as a shortcut to Effect.Morph - Example: - // basic Effect.Morph - $('error_message').morph('color:#f00;font-size:17px'); - // fade out after a while - $('error_message').show().morph('font-size:17px').morph('opacity:0',{delay:4}); - -* Update to Prototype 1.5.0_rc2 revision [5580] - -* Add a paramName option to the inplace editor for overriding the default parameter name of "value" - -* Add Effect.Transform that generates parallel executing Effect.Morph sets - Example: - // set up transformation - var transformation = new Effect.Transform([ - { 'div.morphing': 'font-size:20px;padding-left:40em' }, - { 'blah' : 'width:480px;border-width:10px;border-right-width:20px;margin:200px;margin-bottom:-20px;font-size:30px' } - ],{ duration: 0.5 }); - // play transformation (can be called more than once) - transformation.play(); - -* Add Effect.Morph core effect that morphs to a given CSS style rule. Effect.Morph does take orginal styles given by CSS style rules or the style attribute into consideration when calculating the transforms. It works with all length and color based CSS properties, including margins, paddings, borders, opacity and text/background colors. - Example: - new Effect.Morph('mydiv',{ - style: 'font-size:3em;color:#f00;border-width:2em', - duration: 2.0 - }); - -*V1.6.5* (November 8, 2006) - -* Update to Prototype 1.5.0_rc1 revision [5462] - -* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd] - - var node = Builder.node('label', { htmlFor: 'myinput' }); - -* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo] - -* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower] - -* Add rails-trunk update task, clean up references to MIT license - -* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue - -* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues - - new Effect.Event({ afterFinish:function(){ - // do some code here - }, position: 'end' }); - -* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC - -* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel] - -* Add Builder.build() to create nodes from strings containing HTML, [DHH] - - var node = Builder.build("

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: , - container: , - } - var child = { - parent: , - children: , - id: (as per options.format), - element: , - container: , - position: - } - This is intended to become part of the public API, and can be used to manipulate - the tree programatically. - - Modified Sortable.serialize to use Sortable.tree when set in the options. - -* Fix a problem with window scrolling on draggables [thx Gregory Hill] - -* Let the benchmark method return the time taken in ms, so it can be used for time-based assertions - -* Fix problem with id-based handle names and draggables - -* More Element.childrenWithClassName optimization - -* Added benchmark method to unittest.js; some cleaning up of unit tests - -* Add fix for IE memory leaks in included prototype.js from [4094] - -*V1.6.0* - -* Major speedup for sortable with handles initialization [thx Jamis Buck] - -* Update to latest Prototype 1.5.0_pre1 trunk - -* Add functional "random effects" test, also for browser compatibility testing - -* Fix two typos introduced with the 1.5 Methods syntax update - -* Add functional test for $$-triggered effects with .visualEffect - -* Fix shift-tab for autocompleter in Safari, fixes #4423 [thx matt] - -* Prepare for script.aculo.us 1.6, add Prototype 1.5 requirement and check that Element.Methods is available in the scriptaculous loader - -* Refactor effects.js to use the new Prototype 1.5 Element Methods syntax - -* Update to latest Prototype 1.5.0_pre0 trunk - -* Fix a problem with the draggable window scrolling code and scrolling inside overflow containers - -* Add passing through of scroll options from Sortable to Draggable [thx Gregory Hill] - -* Make it possible to scroll window on dragging, #3921 [thx rdmiller] - -* Make Element.forceRerendering give up on any exception (this fixes various problems with IE) - -* added visualEffect method for the Element Mixin, fixed so you can chain multiple calls. [Rick Olson] - -* Fix only option on Sortable.create to accept multiple class names, fixes #3427 [thx glenn nilsson] - -* Added workaround for a rendering bug in Safari when using floating elements with Effect.Appear - -* Update lib/prototype.js to Prototype 1.5.0_pre0 - -*V1.5.3* - -* Change version number to V1.5.3, prepare Rakefile - -* Remove unneeded height restoring in Effect.BlindDown as that is handled internally by the restoreAfterFinish option to Effect.Scale, fixes #3667 [thx Ross Lawley] - -* Added Ajax.InPlaceCollectionEditor which uses a SELECT element instead of a text field (see test/functional/ajax_inplacecollectioneditor_test.html for usage), #3491 [thx anna] - -* Enable in place editor to use RJS (implements a new evalScripts option for the in place editor), #3490 [thx Richard Livsey] - -* Added Sortable.setSequence to programmatically reorder a Sortable, #3711 [thx Mike A. Owens] - -* Added unit test for #3732 (currently fails due to Prototype #3877) [thx michal] - -* Fix span positioning for sliders with ranges not starting at 0, fixes #3731 [thx michal] - -* Make name option on Sortable.serialize work again, fixes #3873 - -* Make dragging cancel only on ESC key, not on any key, fixes #3817 - -* Fix Rakefile for V1.5.2 - -*V1.5.2* - -* Change version number to V1.5.2 - -* Fix a wrong parameter in dragdrop.js, fixes #3555 - -* Fix two typos in effects.js, fixes #3481 [thx jtolds] - -* Add assertEnumEqual for unit testing (from Prototype SVN trunk) [Sam Stephenson] - -* Add Sortable.sequence method to extract the current sequence of a Sortable as an array, fixes #3675 [thx sphivo] - -* Add limit option to effect queues to limit the maximum number of effects in a queue, new unit tests for scoped effect queues, fixes #3498 [thx Abdur-Rahman Advany] - -* Fix Element.collectTextNodesIgnoreClass to correctly filter child nodes, fixes #3380 [thx lam] - -* Fix a condition where OPTION elements could cause unwanted dragging on Draggables, fixes #3441 [thx tom] - -* Fix a crash because of an IE bug in Effect.SlideDown, fixes #3192 [thx Rob Mayhew] - -* Added experimental auto-scroll option to Draggables and Sortables, activate with scroll: 'id_of_scroll_container_element'. - Note: needs testing, call syntax might change - See test/functional/dragdrop3_test.html for usage/demo - -* Added activate method to Autocompleter that allows you to trigger the suggestions through other means than user input [DHH] - -*V1.5.1* - -* Add select option to Autocompleter to optionally use textnodes from elements with a specific CSS class (see test/functional/ajax_autocompleter_test.html for usage) - -* In-place editor: add ok/cancel visibility options and onblur() submission, fixes #3233 [thx pulsation] - Note: currently, blur form submission breaks the cancel link functionality, if enabled - -* Added Effect.toggle for slide, blind and appear/fade effects, fixes #2704 [thx Azad] - -* Added selective component loading to scriptaculous.js, see test/unit/loading_test.html for usage [thx David Zülke] - -* Added local/scoped effect queues [thx David Zülke] - -* New core effect Effect.Move that can do absolute/relative movement [thx David Zülke] - -* Make default effects options modifyable globally by setting Effect.DefaultOptions - -* Make Draggables recognize top/left CSS properties defined in an external stylesheet, fixes #3205 [thx ansonparker] - -* Fixed draggables starting to drag even if mouse button was released with no movement, [thx topfunky] - -* Updated the README to reflect final status - -*V1.5.0* - -* Prepared for V1.5.0 final - -* Update lib/prototype.js to Prototype 1.4.0 final - -*V1.5.0_rc6* - -* Update lib/prototype.js to Prototype 1.4.0_rc4 - -* Fix Effect.SlideDown/SlideUp on Internet Explorer, includes a change to Effect.Scale, (should) fix #2962 and others, [thx wyldeone] - -* Make Draggables that are reverting cancel the default revert effect when they are dragged again while reverting, fixes #3188, [thx maverick] - -* Fix a problem with a wrong reference in Effect.Pulsate, fixes #3184, [thx cyx_] - -* Fix Sortable.findElements for XHTML in Gecko, fixes #3081, [thx fgnass] - -* Fix a problem with the slider getting NaN results when clicking directly on the track, fixes #3020, [thx rectalogic] - -* Fix a problem with Safari not doing sub-pixel rendering when setting opacity to 1 with Element.setOpacity - -* Fix slider to make handle width/height count for track length, fixes #3040, fixes #3017, [thx buggedcom] - -* Added Basic unit test for Effect.inspect - -* Fix Effect.multiple to deal correctly with delays - -* Safeguard Effect.Base.render to only do updates when Effect is in running state, fixes #2912 - -* Added inspect method to Effect.Base - -* Added functional test for DOM-based UL sortables #3016 - -* Added offset option to Effect.ScrollTo - -* More effects.js/dragdrop.js refactoring - -* Refactoring and optimizations for effects (not complete yet) - -* Refactoring and optimizations for Draggables/Droppables/Sortables (not complete yet) - -*V1.5.0_rc5* - -* Make Droppables.remove accept DOM IDs in addition to elements - -* Added some unit tests for drag and drop - -* Update lib/prototype.js to Prototype 1.4.0_rc3 - -* Make 'contents' a synonym for 'content' on Effect.Scale scaleMode option - -* Fix some possible exceptions in slider.js - -* Support for various snapping options on Draggables, adresses #2826, [thx saimonmoore] - -* Support horizontal ghostable Sortables, fixes #2794, [thx johnm] - -* Prevent an exception on IE with a functional test, see #2706 - -* Add functional testing of hoverclasses for sortables - -* Add an assert for correct UTF-8 return chars in Autocompleter - -* Correct IE detection in Autocompleter for Opera, fixes #2558 [thx gary] - -* Add onDrag callback to Draggable observers, #2827 [thx saimonmoore] - -* Added Form.Element.DelayedObserver to controls.js for live-search fields - -* Remove Element.Class in favour of Prototype Element.ClassNames, new function Element.childrenWithClassName() - -* Update Copyright notice in slider.js - -* Fix slider firing onChange events to eagerly on dragging a handle [thx wombert] - -* Fix a problem with Start/End spans and single handles - -* Add event property to Slider object so that callbacks can determine if setValue originated from a UI event or from script - -* Fix Builder.node() throwing unresolved errors in IE6, #2707 [thx flwombat] - -* Give currently active handle on slider the "selected" CSS class - -* Add start and end spans to slider - -* Make track clickable for sliders (moves last active handle [or first handle] to nearest possible position) - -* Make initial values on slider work for single and multiple handle sliders - -*V1.5.0_rc4* - -* Abort Effect.Highlight on elements which have display:none set (prevents problem with Safari) - -* Make Effect.Queue an Enumerable, fix a problem with Effect.Grow, more unit tests - -* Added restricted option to prevent moved of handles prior/after adjacent handles on Sliders with multiple handles - -* Update lib/prototype.js to Prototype 1.4.0_rc2 - -* Fix a bug with wrongly scrolling to the page top in Ajax.InPlaceEditor (circumvents various browser bugs) [Jon Tirsen], #2616 - -* major slider refactoring, changed slider range to default to [0,1]. Slider Range can be set with range:$R(from,to) option. The increment option is not active for now. - -* Added spans support for Control.Slider to mark spans bordered by slider handles, see unit test [thx to www.bartenbach.de for sponsoring this functionality] - -* Added preliminary support for optional multiple handles to Control.Slider [thx to www.bartenbach.de for sponsoring this functionality] - -* Fixed wrong inclusion of libs in inplace editor functional test - -* Fixed Effect.SlideDown/SlideUp to honor refactoring of Effect.Scale, fixes #2523 [thx obiwanki] - -* Reset the zIndex on Draggables correctly, #2483 [thx Jon Whitcraft] - -* Fix onChange callback on Sortables when dragging between sortables, #2488 [thx Dylan Greene] - -* Removed Builder code from effects.js, removed Object.debug (implemented as Test.Unit.inspect) - -* Added slider unit tests, fixed handling of values to autocalculate min/max, fixed upper/lower boundaries on setting the value programmatically - -* Synced to Rails 1.0 release candidate, update to Prototype 1.4.0_rc1, removed util.js, merged rests of util.js into effects.js to prepare for refactoring - -* Give Builder it's own file - -* Fix a logic issue with Autocompleter [thx tshinnic], #2457 - -*V1.5.0_rc3* - -* Make Effect position available to callbacks - -* Droppables.fire: send event to onDrop callback [François Beausoleil], #2389 - -* InPlaceEditor: Add disabling the field while loadTextURL loads and add a class while loading, plus fix various bugs with Internet Explorer and InPlaceEditor, [Jon Tirsen] #2302, #2303 - -* Made Droppables.remove work again [thx Mindaugas Pelionis], #2409 - -* Fixed that IE6 would incorrectly render the "fix-windowed-elements-overlapping" IFRAME on autocompletion [thx tshinnic], #2403 - -* Fixed Element.getOpacity throwing an error on Safari in some situations (this caused the autocompleter not to work) - -* Added format option to Sortable.create and Sortable.serialize to allow custom id formats. The format option takes a regular expression where the first grouping that matches is used for building the parameters. The default format is /^[^_]*_(.*)$/ which matches the string_identifier format. If you want to use the full id of the elements, use "format: /(.*)/". More examples are available in the sortable unit test file. - -* Started refactorings to use the new Prototype features and general code-cleanup - -* Update lib/prototype.js to Prototype 1.4.0_pre11 - -* Fixed a typo breaking the up arrow key for autocompletion [thx tshinnic], #2406 - -* Changed the handle option on Draggbles to accept classnames, or ids or elements [thx to Andrew West], #2274 - -* Force indicator to be hidden on hiding autocompletion update element, #2342 - -* Make Draggables honor external CSS positioning [thx to Mark Shawkey], #2359 - -* Make zindex handling for Draggables honor external CSS styles - -* Fix two Sortable.serialize issues, [thx Avi, Gorou], #2339, #2357 - -* Make Element.getOpacity work with IE, added unit tests [thx to Greg Hill] - -* Make Element.setOpacity honor non-alpha filters on IE (it now works with filters for alpha PNGs) - -* Fixed that Element.class.remove wrongly deleted spaces between class names, fixes #2311, #2313 - -* Fixed Builder for OPTION and OPTGROUP tags on Firefox < 1.5 and Internet Explorer 6, completely fixes #2325 - -* Improved Builder implementation to deal with Firefox-specific requirements and innerHTML parsing, partly fixes #2325 - -*V1.5.0_rc2* - -* Update lib/prototype.js to corrected Prototype 1.4.0_pre7 (fixed a problem with IE) - -* Update lib/prototype.js to Prototype 1.4.0_pre7 - -* Reverted to patched version of Prototype 1.4.0_pre4 for the time being (getResponseHeader problem on Mozilla) - -* Attempt to fix crashes in Safari 2.0.1, probably related to the event registering und unregistering in Draggables, possibly fixes #2310 - -* Update lib/prototype.js to Prototype 1.4.0_pre6 - -* Changed effects_test.html functional test to incoporate Firefox anti-flicker overflow:hidden CSS property - -*V1.5.0_rc1* - -* Prepared Rakefile and README for V1.5.0_rc1 release - -* Droppables w/greedy and hoverclass are now reverted when dragged item is no longer over them, fixes #2184 - -* Let Effect.Highlight correctly parse IE colors, add String.prototype.parseColor() for this, fixes #2037 - -* Fix Effect.Highlight to restore background image only if there was one - -* Made Effect.tagifyText work again on IE - -* Added String.prototype.toArray because Strings aren't iterable on IE - -* Fixed Element.getOpacity falsely returning 0 on IE - -* Some cleaning up in util.js - -* Cleaned up Effect.Opacity - -* Removed useless line in Position.page - -* Make scriptaculous.js work if a query strings are used when calling it - -* Fixed typos in slider.js and the functional test - -* Fixed a bug with Safari and the InPlaceEditor with form submission. Add support for interpreting simple
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/effects/MIT-LICENSE b/framework/Web/Javascripts/effects/MIT-LICENSE deleted file mode 100644 index 30ff1248..00000000 --- a/framework/Web/Javascripts/effects/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -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/effects/README b/framework/Web/Javascripts/effects/README deleted file mode 100644 index 94ff1307..00000000 --- a/framework/Web/Javascripts/effects/README +++ /dev/null @@ -1,57 +0,0 @@ -== 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/effects/builder.js b/framework/Web/Javascripts/effects/builder.js deleted file mode 100644 index 199afc12..00000000 --- a/framework/Web/Javascripts/effects/builder.js +++ /dev/null @@ -1,131 +0,0 @@ -// 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 + ">"; - } 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 + ">"; - } 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/effects/controls.js b/framework/Web/Javascripts/effects/controls.js deleted file mode 100644 index 46f2cc18..00000000 --- a/framework/Web/Javascripts/effects/controls.js +++ /dev/null @@ -1,835 +0,0 @@ -// 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 lastTokenPos) - lastTokenPos = thisTokenPos; - } - return lastTokenPos; - } -} - -Ajax.Autocompleter = Class.create(); -Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } - -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(); -Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
  • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
  • "); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { - partial.push("
  • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
  • "); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) - return "
      " + 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(/

    /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= this.startOn) { - if(timePos >= this.finishOn) { - this.render(1.0); - this.cancel(); - this.event('beforeFinish'); - if(this.finish) this.finish(); - this.event('afterFinish'); - return; - } - var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); - var frame = Math.round(pos * this.options.fps * this.options.duration); - if(frame > this.currentFrame) { - this.render(pos); - this.currentFrame = frame; - } - } - }, - render: function(pos) { - if(this.state == 'idle') { - this.state = 'running'; - this.event('beforeSetup'); - if(this.setup) this.setup(); - this.event('afterSetup'); - } - if(this.state == 'running') { - if(this.options.transition) pos = this.options.transition(pos); - pos *= (this.options.to-this.options.from); - pos += this.options.from; - this.position = pos; - this.event('beforeUpdate'); - if(this.update) this.update(pos); - this.event('afterUpdate'); - } - }, - cancel: function() { - if(!this.options.sync) - Effect.Queues.get(typeof this.options.queue == 'string' ? - 'global' : this.options.queue.scope).remove(this); - this.state = 'finished'; - }, - event: function(eventName) { - if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); - if(this.options[eventName]) this.options[eventName](this); - }, - inspect: function() { - var data = $H(); - for(property in this) - if(typeof this[property] != 'function') data[property] = this[property]; - return '#'; - } -} - -Effect.Parallel = Class.create(); -Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { - initialize: function(effects) { - this.effects = effects || []; - this.start(arguments[1]); - }, - update: function(position) { - this.effects.invoke('render', position); - }, - finish: function(position) { - this.effects.each( function(effect) { - effect.render(1.0); - effect.cancel(); - effect.event('beforeFinish'); - if(effect.finish) effect.finish(position); - effect.event('afterFinish'); - }); - } -}); - -Effect.Event = Class.create(); -Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { - initialize: function() { - var options = Object.extend({ - duration: 0 - }, arguments[0] || {}); - this.start(options); - }, - update: Prototype.emptyFunction -}); - -Effect.Opacity = Class.create(); -Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - // make this work on IE on elements without 'layout' - if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - var options = Object.extend({ - from: this.element.getOpacity() || 0.0, - to: 1.0 - }, arguments[1] || {}); - this.start(options); - }, - update: function(position) { - this.element.setOpacity(position); - } -}); - -Effect.Move = Class.create(); -Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - x: 0, - y: 0, - mode: 'relative' - }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Bug in Opera: Opera returns the "real" position of a static element or - // relative element that does not have top/left explicitly set. - // ==> Always set top and left for position relative elements in your stylesheets - // (to 0 if you do not need them) - this.element.makePositioned(); - this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); - this.originalTop = parseFloat(this.element.getStyle('top') || '0'); - if(this.options.mode == 'absolute') { - // absolute movement, so we need to calc deltaX and deltaY - this.options.x = this.options.x - this.originalLeft; - this.options.y = this.options.y - this.originalTop; - } - }, - update: function(position) { - this.element.setStyle({ - left: Math.round(this.options.x * position + this.originalLeft) + 'px', - top: Math.round(this.options.y * position + this.originalTop) + 'px' - }); - } -}); - -// for backwards compatibility -Effect.MoveBy = function(element, toTop, toLeft) { - return new Effect.Move(element, - Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); -}; - -Effect.Scale = Class.create(); -Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { - initialize: function(element, percent) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - scaleX: true, - scaleY: true, - scaleContent: true, - scaleFromCenter: false, - scaleMode: 'box', // 'box' or 'contents' or {} with provided values - scaleFrom: 100.0, - scaleTo: percent - }, arguments[2] || {}); - this.start(options); - }, - setup: function() { - this.restoreAfterFinish = this.options.restoreAfterFinish || false; - this.elementPositioning = this.element.getStyle('position'); - - this.originalStyle = {}; - ['top','left','width','height','fontSize'].each( function(k) { - this.originalStyle[k] = this.element.style[k]; - }.bind(this)); - - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; - - var fontSize = this.element.getStyle('font-size') || '100%'; - ['em','px','%','pt'].each( function(fontSizeType) { - if(fontSize.indexOf(fontSizeType)>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = fontSizeType; - } - }.bind(this)); - - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - - this.dims = null; - if(this.options.scaleMode=='box') - this.dims = [this.element.offsetHeight, this.element.offsetWidth]; - if(/^content/.test(this.options.scaleMode)) - this.dims = [this.element.scrollHeight, this.element.scrollWidth]; - if(!this.dims) - this.dims = [this.options.scaleMode.originalHeight, - this.options.scaleMode.originalWidth]; - }, - update: function(position) { - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); - if(this.options.scaleContent && this.fontSize) - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); - }, - finish: function(position) { - if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); - }, - setDimensions: function(height, width) { - var d = {}; - if(this.options.scaleX) d.width = Math.round(width) + 'px'; - if(this.options.scaleY) d.height = Math.round(height) + 'px'; - if(this.options.scaleFromCenter) { - var topd = (height - this.dims[0])/2; - var leftd = (width - this.dims[1])/2; - if(this.elementPositioning == 'absolute') { - if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; - if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; - } else { - if(this.options.scaleY) d.top = -topd + 'px'; - if(this.options.scaleX) d.left = -leftd + 'px'; - } - } - this.element.setStyle(d); - } -}); - -Effect.Highlight = Class.create(); -Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Prevent executing on elements not in the layout flow - if(this.element.getStyle('display')=='none') { this.cancel(); return; } - // Disable background image during the effect - this.oldStyle = {}; - if (!this.options.keepBackgroundImage) { - this.oldStyle.backgroundImage = this.element.getStyle('background-image'); - this.element.setStyle({backgroundImage: 'none'}); - } - if(!this.options.endcolor) - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); - if(!this.options.restorecolor) - this.options.restorecolor = this.element.getStyle('background-color'); - // init color calculations - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); - }, - update: function(position) { - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ - return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); - }, - finish: function() { - this.element.setStyle(Object.extend(this.oldStyle, { - backgroundColor: this.options.restorecolor - })); - } -}); - -Effect.ScrollTo = Class.create(); -Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - this.start(arguments[1] || {}); - }, - setup: function() { - Position.prepare(); - var offsets = Position.cumulativeOffset(this.element); - if(this.options.offset) offsets[1] += this.options.offset; - var max = window.innerHeight ? - window.height - window.innerHeight : - document.body.scrollHeight - - (document.documentElement.clientHeight ? - document.documentElement.clientHeight : document.body.clientHeight); - this.scrollStart = Position.deltaY; - this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; - }, - update: function(position) { - Position.prepare(); - window.scrollTo(Position.deltaX, - this.scrollStart + (position*this.delta)); - } -}); - -/* ------------- combination effects ------------- */ - -Effect.Fade = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - var options = Object.extend({ - from: element.getOpacity() || 1.0, - to: 0.0, - afterFinishInternal: function(effect) { - if(effect.options.to!=0) return; - effect.element.hide().setStyle({opacity: oldOpacity}); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Appear = function(element) { - element = $(element); - var options = Object.extend({ - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), - to: 1.0, - // force Safari to render floated elements properly - afterFinishInternal: function(effect) { - effect.element.forceRerendering(); - }, - beforeSetup: function(effect) { - effect.element.setOpacity(effect.options.from).show(); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Puff = function(element) { - element = $(element); - var oldStyle = { - opacity: element.getInlineOpacity(), - position: element.getStyle('position'), - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height - }; - return new Effect.Parallel( - [ new Effect.Scale(element, 200, - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], - Object.extend({ duration: 1.0, - beforeSetupInternal: function(effect) { - Position.absolutize(effect.effects[0].element) - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().setStyle(oldStyle); } - }, arguments[1] || {}) - ); -} - -Effect.BlindUp = function(element) { - element = $(element); - element.makeClipping(); - return new Effect.Scale(element, 0, - Object.extend({ scaleContent: false, - scaleX: false, - restoreAfterFinish: true, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }, arguments[1] || {}) - ); -} - -Effect.BlindDown = function(element) { - element = $(element); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: 0, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - } - }, arguments[1] || {})); -} - -Effect.SwitchOff = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - return new Effect.Appear(element, Object.extend({ - duration: 0.4, - from: 0, - transition: Effect.Transitions.flicker, - afterFinishInternal: function(effect) { - new Effect.Scale(effect.element, 1, { - duration: 0.3, scaleFromCenter: true, - scaleX: false, scaleContent: false, restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); - } - }) - } - }, arguments[1] || {})); -} - -Effect.DropOut = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left'), - opacity: element.getInlineOpacity() }; - return new Effect.Parallel( - [ new Effect.Move(element, {x: 0, y: 100, sync: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 }) ], - Object.extend( - { duration: 0.5, - beforeSetup: function(effect) { - effect.effects[0].element.makePositioned(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); - } - }, arguments[1] || {})); -} - -Effect.Shake = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left') }; - return new Effect.Move(element, - { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - effect.element.undoPositioned().setStyle(oldStyle); - }}) }}) }}) }}) }}) }}); -} - -Effect.SlideDown = function(element) { - element = $(element).cleanWhitespace(); - // SlideDown need to have the content of the element wrapped in a container element with fixed height! - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: window.opera ? 0 : 1, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || {}) - ); -} - -Effect.SlideUp = function(element) { - element = $(element).cleanWhitespace(); - var oldInnerBottom = element.down().getStyle('bottom'); - return new Effect.Scale(element, window.opera ? 0 : 1, - Object.extend({ scaleContent: false, - scaleX: false, - scaleMode: 'box', - scaleFrom: 100, - restoreAfterFinish: true, - beforeStartInternal: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); - effect.element.down().undoPositioned(); - } - }, arguments[1] || {}) - ); -} - -// Bug in opera makes the TD containing this element expand for a instance after finish -Effect.Squish = function(element) { - return new Effect.Scale(element, window.opera ? 1 : 0, { - restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }); -} - -Effect.Grow = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.full - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var initialMoveX, initialMoveY; - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - initialMoveX = initialMoveY = moveX = moveY = 0; - break; - case 'top-right': - initialMoveX = dims.width; - initialMoveY = moveY = 0; - moveX = -dims.width; - break; - case 'bottom-left': - initialMoveX = moveX = 0; - initialMoveY = dims.height; - moveY = -dims.height; - break; - case 'bottom-right': - initialMoveX = dims.width; - initialMoveY = dims.height; - moveX = -dims.width; - moveY = -dims.height; - break; - case 'center': - initialMoveX = dims.width / 2; - initialMoveY = dims.height / 2; - moveX = -dims.width / 2; - moveY = -dims.height / 2; - break; - } - - return new Effect.Move(element, { - x: initialMoveX, - y: initialMoveY, - duration: 0.01, - beforeSetup: function(effect) { - effect.element.hide().makeClipping().makePositioned(); - }, - afterFinishInternal: function(effect) { - new Effect.Parallel( - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), - new Effect.Scale(effect.element, 100, { - scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) - ], Object.extend({ - beforeSetup: function(effect) { - effect.effects[0].element.setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); - } - }, options) - ) - } - }); -} - -Effect.Shrink = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.none - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - moveX = moveY = 0; - break; - case 'top-right': - moveX = dims.width; - moveY = 0; - break; - case 'bottom-left': - moveX = 0; - moveY = dims.height; - break; - case 'bottom-right': - moveX = dims.width; - moveY = dims.height; - break; - case 'center': - moveX = dims.width / 2; - moveY = dims.height / 2; - break; - } - - return new Effect.Parallel( - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) - ], Object.extend({ - beforeStartInternal: function(effect) { - effect.effects[0].element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } - }, options) - ); -} - -Effect.Pulsate = function(element) { - element = $(element); - var options = arguments[1] || {}; - var oldOpacity = element.getInlineOpacity(); - var transition = options.transition || Effect.Transitions.sinoidal; - var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; - reverser.bind(transition); - return new Effect.Opacity(element, - Object.extend(Object.extend({ duration: 2.0, from: 0, - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } - }, options), {transition: reverser})); -} - -Effect.Fold = function(element) { - element = $(element); - var oldStyle = { - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height }; - element.makeClipping(); - return new Effect.Scale(element, 5, Object.extend({ - scaleContent: false, - scaleX: false, - afterFinishInternal: function(effect) { - new Effect.Scale(element, 1, { - scaleContent: false, - scaleY: false, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().setStyle(oldStyle); - } }); - }}, arguments[1] || {})); -}; - -Effect.Morph = Class.create(); -Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - style: {} - }, arguments[1] || {}); - if (typeof options.style == 'string') { - if(options.style.indexOf(':') == -1) { - var cssText = '', selector = '.' + options.style; - $A(document.styleSheets).reverse().each(function(styleSheet) { - if (styleSheet.cssRules) cssRules = styleSheet.cssRules; - else if (styleSheet.rules) cssRules = styleSheet.rules; - $A(cssRules).reverse().each(function(rule) { - if (selector == rule.selectorText) { - cssText = rule.style.cssText; - throw $break; - } - }); - if (cssText) throw $break; - }); - this.style = cssText.parseStyle(); - options.afterFinishInternal = function(effect){ - effect.element.addClassName(effect.options.style); - effect.transforms.each(function(transform) { - if(transform.style != 'opacity') - effect.element.style[transform.style.camelize()] = ''; - }); - } - } else this.style = options.style.parseStyle(); - } else this.style = $H(options.style) - this.start(options); - }, - setup: function(){ - function parseColor(color){ - if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; - color = color.parseColor(); - return $R(0,2).map(function(i){ - return parseInt( color.slice(i*2+1,i*2+3), 16 ) - }); - } - this.transforms = this.style.map(function(pair){ - var property = pair[0].underscore().dasherize(), value = pair[1], unit = null; - - if(value.parseColor('#zzzzzz') != '#zzzzzz') { - value = value.parseColor(); - unit = 'color'; - } else if(property == 'opacity') { - value = parseFloat(value); - if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - } else if(Element.CSS_LENGTH.test(value)) - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), - value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; - - var originalValue = this.element.getStyle(property); - return $H({ - style: property, - originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), - targetValue: unit=='color' ? parseColor(value) : value, - unit: unit - }); - }.bind(this)).reject(function(transform){ - return ( - (transform.originalValue == transform.targetValue) || - ( - transform.unit != 'color' && - (isNaN(transform.originalValue) || isNaN(transform.targetValue)) - ) - ) - }); - }, - update: function(position) { - var style = $H(), value = null; - this.transforms.each(function(transform){ - value = transform.unit=='color' ? - $R(0,2).inject('#',function(m,v,i){ - return m+(Math.round(transform.originalValue[i]+ - (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : - transform.originalValue + Math.round( - ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; - style[transform.style] = value; - }); - this.element.setStyle(style); - } -}); - -Effect.Transform = Class.create(); -Object.extend(Effect.Transform.prototype, { - initialize: function(tracks){ - this.tracks = []; - this.options = arguments[1] || {}; - this.addTracks(tracks); - }, - addTracks: function(tracks){ - tracks.each(function(track){ - var data = $H(track).values().first(); - this.tracks.push($H({ - ids: $H(track).keys().first(), - effect: Effect.Morph, - options: { style: data } - })); - }.bind(this)); - return this; - }, - play: function(){ - return new Effect.Parallel( - this.tracks.map(function(track){ - var elements = [$(track.ids) || $$(track.ids)].flatten(); - return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); - }).flatten(), - this.options - ); - } -}); - -Element.CSS_PROPERTIES = $w( - 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + - 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + - 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + - 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + - 'fontSize fontWeight height left letterSpacing lineHeight ' + - 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ - 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + - 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + - 'right textIndent top width wordSpacing zIndex'); - -Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; - -String.prototype.parseStyle = function(){ - var element = Element.extend(document.createElement('div')); - element.innerHTML = '

    '; - var style = element.down().style, styleRules = $H(); - - Element.CSS_PROPERTIES.each(function(property){ - if(style[property]) styleRules[property] = style[property]; - }); - if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) { - styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]; - } - return styleRules; -}; - -Element.morph = function(element, style) { - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); - return element; -}; - -['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', - 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( - function(f) { Element.Methods[f] = Element[f]; } -); - -Element.Methods.visualEffect = function(element, effect, options) { - s = effect.gsub(/_/, '-').camelize(); - effect_class = s.charAt(0).toUpperCase() + s.substring(1); - new Effect[effect_class](element, options); - return $(element); -}; - -Element.addMethods(); \ No newline at end of file diff --git a/framework/Web/Javascripts/effects/slider.js b/framework/Web/Javascripts/effects/slider.js deleted file mode 100644 index f24f2823..00000000 --- a/framework/Web/Javascripts/effects/slider.js +++ /dev/null @@ -1,278 +0,0 @@ -// script.aculo.us slider.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 - -// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -if(!Control) var Control = {}; -Control.Slider = Class.create(); - -// options: -// axis: 'vertical', or 'horizontal' (default) -// -// callbacks: -// onChange(value) -// onSlide(value) -Control.Slider.prototype = { - initialize: function(handle, track, options) { - var slider = this; - - if(handle instanceof Array) { - this.handles = handle.collect( function(e) { return $(e) }); - } else { - this.handles = [$(handle)]; - } - - this.track = $(track); - this.options = options || {}; - - this.axis = this.options.axis || 'horizontal'; - this.increment = this.options.increment || 1; - this.step = parseInt(this.options.step || '1'); - this.range = this.options.range || $R(0,1); - - this.value = 0; // assure backwards compat - this.values = this.handles.map( function() { return 0 }); - this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; - this.options.startSpan = $(this.options.startSpan || null); - this.options.endSpan = $(this.options.endSpan || null); - - this.restricted = this.options.restricted || false; - - this.maximum = this.options.maximum || this.range.end; - this.minimum = this.options.minimum || this.range.start; - - // Will be used to align the handle onto the track, if necessary - this.alignX = parseInt(this.options.alignX || '0'); - this.alignY = parseInt(this.options.alignY || '0'); - - this.trackLength = this.maximumOffset() - this.minimumOffset(); - - this.handleLength = this.isVertical() ? - (this.handles[0].offsetHeight != 0 ? - this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : - (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : - this.handles[0].style.width.replace(/px$/,"")); - - this.active = false; - this.dragging = false; - this.disabled = false; - - if(this.options.disabled) this.setDisabled(); - - // Allowed values array - this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; - if(this.allowedValues) { - this.minimum = this.allowedValues.min(); - this.maximum = this.allowedValues.max(); - } - - this.eventMouseDown = this.startDrag.bindAsEventListener(this); - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.update.bindAsEventListener(this); - - // Initialize handles in reverse (make sure first handle is active) - this.handles.each( function(h,i) { - i = slider.handles.length-1-i; - slider.setValue(parseFloat( - (slider.options.sliderValue instanceof Array ? - slider.options.sliderValue[i] : slider.options.sliderValue) || - slider.range.start), i); - Element.makePositioned(h); // fix IE - Event.observe(h, "mousedown", slider.eventMouseDown); - }); - - Event.observe(this.track, "mousedown", this.eventMouseDown); - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - - this.initialized = true; - }, - dispose: function() { - var slider = this; - Event.stopObserving(this.track, "mousedown", this.eventMouseDown); - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - this.handles.each( function(h) { - Event.stopObserving(h, "mousedown", slider.eventMouseDown); - }); - }, - setDisabled: function(){ - this.disabled = true; - }, - setEnabled: function(){ - this.disabled = false; - }, - getNearestValue: function(value){ - if(this.allowedValues){ - if(value >= this.allowedValues.max()) return(this.allowedValues.max()); - if(value <= this.allowedValues.min()) return(this.allowedValues.min()); - - var offset = Math.abs(this.allowedValues[0] - value); - var newValue = this.allowedValues[0]; - this.allowedValues.each( function(v) { - var currentOffset = Math.abs(v - value); - if(currentOffset <= offset){ - newValue = v; - offset = currentOffset; - } - }); - return newValue; - } - if(value > this.range.end) return this.range.end; - if(value < this.range.start) return this.range.start; - return value; - }, - setValue: function(sliderValue, handleIdx){ - if(!this.active) { - this.activeHandleIdx = handleIdx || 0; - this.activeHandle = this.handles[this.activeHandleIdx]; - this.updateStyles(); - } - handleIdx = handleIdx || this.activeHandleIdx || 0; - if(this.initialized && this.restricted) { - if((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) - sliderValue = this.values[handleIdx+1]; - } - sliderValue = this.getNearestValue(sliderValue); - this.values[handleIdx] = sliderValue; - this.value = this.values[0]; // assure backwards compat - - this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = - this.translateToPx(sliderValue); - - this.drawSpans(); - if(!this.dragging || !this.event) this.updateFinished(); - }, - setValueBy: function(delta, handleIdx) { - this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, - handleIdx || this.activeHandleIdx || 0); - }, - translateToPx: function(value) { - return Math.round( - ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * - (value - this.range.start)) + "px"; - }, - translateToValue: function(offset) { - return ((offset/(this.trackLength-this.handleLength) * - (this.range.end-this.range.start)) + this.range.start); - }, - getRange: function(range) { - var v = this.values.sortBy(Prototype.K); - range = range || 0; - return $R(v[range],v[range+1]); - }, - minimumOffset: function(){ - return(this.isVertical() ? this.alignY : this.alignX); - }, - maximumOffset: function(){ - return(this.isVertical() ? - (this.track.offsetHeight != 0 ? this.track.offsetHeight : - this.track.style.height.replace(/px$/,"")) - this.alignY : - (this.track.offsetWidth != 0 ? this.track.offsetWidth : - this.track.style.width.replace(/px$/,"")) - this.alignY); - }, - isVertical: function(){ - return (this.axis == 'vertical'); - }, - drawSpans: function() { - var slider = this; - if(this.spans) - $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); - if(this.options.startSpan) - this.setSpan(this.options.startSpan, - $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); - if(this.options.endSpan) - this.setSpan(this.options.endSpan, - $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); - }, - setSpan: function(span, range) { - if(this.isVertical()) { - span.style.top = this.translateToPx(range.start); - span.style.height = this.translateToPx(range.end - range.start + this.range.start); - } else { - span.style.left = this.translateToPx(range.start); - span.style.width = this.translateToPx(range.end - range.start + this.range.start); - } - }, - updateStyles: function() { - this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); - Element.addClassName(this.activeHandle, 'selected'); - }, - startDrag: function(event) { - if(Event.isLeftClick(event)) { - if(!this.disabled){ - this.active = true; - - var handle = Event.element(event); - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var track = handle; - if(track==this.track) { - var offsets = Position.cumulativeOffset(this.track); - this.event = event; - this.setValue(this.translateToValue( - (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) - )); - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } else { - // find the handle (prevents issues with Safari) - while((this.handles.indexOf(handle) == -1) && handle.parentNode) - handle = handle.parentNode; - - if(this.handles.indexOf(handle)!=-1) { - this.activeHandle = handle; - this.activeHandleIdx = this.handles.indexOf(this.activeHandle); - this.updateStyles(); - - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } - } - } - Event.stop(event); - } - }, - update: function(event) { - if(this.active) { - if(!this.dragging) this.dragging = true; - this.draw(event); - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - Event.stop(event); - } - }, - draw: function(event) { - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var offsets = Position.cumulativeOffset(this.track); - pointer[0] -= this.offsetX + offsets[0]; - pointer[1] -= this.offsetY + offsets[1]; - this.event = event; - this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); - if(this.initialized && this.options.onSlide) - this.options.onSlide(this.values.length>1 ? this.values : this.value, this); - }, - endDrag: function(event) { - if(this.active && this.dragging) { - this.finishDrag(event, true); - Event.stop(event); - } - this.active = false; - this.dragging = false; - }, - finishDrag: function(event, success) { - this.active = false; - this.dragging = false; - this.updateFinished(); - }, - updateFinished: function() { - if(this.initialized && this.options.onChange) - this.options.onChange(this.values.length>1 ? this.values : this.value, this); - this.event = null; - } -} \ No newline at end of file diff --git a/framework/Web/Javascripts/extended/base.js b/framework/Web/Javascripts/extended/base.js deleted file mode 100644 index 251882cd..00000000 --- a/framework/Web/Javascripts/extended/base.js +++ /dev/null @@ -1,136 +0,0 @@ - -/** - * Similar to bindAsEventLister, but takes additional arguments. - */ -Function.prototype.bindEvent = function() -{ - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) - { - return __method.apply(object, [event || window.event].concat(args)); - } -} - -/** - * Creates a new function by copying function definition from - * the base and optional definition. - * @param function a base function to copy from. - * @param array additional definition - * @param function return a new function with definition from both - * base and definition. - */ -Class.extend = function(base, definition) -{ - var component = Class.create(); - Object.extend(component.prototype, base.prototype); - if(definition) - Object.extend(component.prototype, definition); - return component; -} - -/* - Base, version 1.0.2 - Copyright 2006, Dean Edwards - License: http://creativecommons.org/licenses/LGPL/2.1/ -*/ - -var Base = function() { - if (arguments.length) { - if (this == window) { // cast an object to this class - Base.prototype.extend.call(arguments[0], arguments.callee.prototype); - } else { - this.extend(arguments[0]); - } - } -}; - -Base.version = "1.0.2"; - -Base.prototype = { - extend: function(source, value) { - var extend = Base.prototype.extend; - if (arguments.length == 2) { - var ancestor = this[source]; - // overriding? - if ((ancestor instanceof Function) && (value instanceof Function) && - ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) { - var method = value; - // var _prototype = this.constructor.prototype; - // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor; - value = function() { - var previous = this.base; - // this.base = fromPrototype ? _prototype[source] : ancestor; - this.base = ancestor; - var returnValue = method.apply(this, arguments); - this.base = previous; - return returnValue; - }; - // point to the underlying method - value.valueOf = function() { - return method; - }; - value.toString = function() { - return String(method); - }; - } - return this[source] = value; - } else if (source) { - var _prototype = {toSource: null}; - // do the "toString" and other methods manually - var _protected = ["toString", "valueOf"]; - // if we are prototyping then include the constructor - if (Base._prototyping) _protected[2] = "constructor"; - for (var i = 0; (name = _protected[i]); i++) { - if (source[name] != _prototype[name]) { - extend.call(this, name, source[name]); - } - } - // copy each of the source object's properties to this object - for (var name in source) { - if (!_prototype[name]) { - extend.call(this, name, source[name]); - } - } - } - return this; - }, - - base: function() { - // call this method from any other method to invoke that method's ancestor - } -}; - -Base.extend = function(_instance, _static) { - var extend = Base.prototype.extend; - if (!_instance) _instance = {}; - // build the prototype - Base._prototyping = true; - var _prototype = new this; - extend.call(_prototype, _instance); - var constructor = _prototype.constructor; - _prototype.constructor = this; - delete Base._prototyping; - // create the wrapper for the constructor function - var klass = function() { - if (!Base._prototyping) constructor.apply(this, arguments); - this.constructor = klass; - }; - klass.prototype = _prototype; - // build the class interface - klass.extend = this.extend; - klass.implement = this.implement; - klass.toString = function() { - return String(constructor); - }; - extend.call(klass, _static); - // single instance - var object = constructor ? klass : _prototype; - // class initialisation - if (object.init instanceof Function) object.init(); - return object; -}; - -Base.implement = function(_interface) { - if (_interface instanceof Function) _interface = _interface.prototype; - this.prototype.extend(_interface); -}; diff --git a/framework/Web/Javascripts/extended/builder.js b/framework/Web/Javascripts/extended/builder.js deleted file mode 100644 index c50fc6c6..00000000 --- a/framework/Web/Javascripts/extended/builder.js +++ /dev/null @@ -1,24 +0,0 @@ - -Object.extend(Builder, -{ - exportTags:function() - { - var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG", "CAPTION"]; - tags.each(function(tag) - { - window[tag]=function() - { - var args=$A(arguments); - if(args.length==0) - return Builder.node(tag,null); - if(args.length==1) - return Builder.node(tag,args[0]); - if(args.length>1) - return Builder.node(tag,args.shift(),args); - - }; - }); - } -}); - -Builder.exportTags(); diff --git a/framework/Web/Javascripts/extended/date.js b/framework/Web/Javascripts/extended/date.js deleted file mode 100644 index b27f9da2..00000000 --- a/framework/Web/Javascripts/extended/date.js +++ /dev/null @@ -1,151 +0,0 @@ - -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/extended/event.js b/framework/Web/Javascripts/extended/event.js deleted file mode 100644 index e464fa94..00000000 --- a/framework/Web/Javascripts/extended/event.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @class Event extensions. - */ -Object.extend(Event, -{ - /** - * Register a function to be executed when the page is loaded. - * Note that the page is only loaded if all resources (e.g. images) - * are loaded. - * - * Example: Show an alert box with message "Page Loaded!" when the - * page finished loading. - * - * 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](); - } -}); \ 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 5cd1bd8e..00000000 --- a/framework/Web/Javascripts/extended/string.js +++ /dev/null @@ -1,171 +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.lengthInternationalization - * is not supported - * @param {String} the decimal character - * @return {Double} null if string does not represent a float value - */ - toDouble : function(decimalchar) - { - if(this.length <= 0) return null; - decimalchar = decimalchar || "."; - var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); - var m = this.match(exp); - - if (m == null) - return null; - m[1] = m[1] || ""; - m[2] = m[2] || "0"; - m[4] = m[4] || "0"; - - var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); - }, - - /** - * Convert strings that represent a currency value (e.g. a float with grouping - * characters) to float. E.g. "10,000.50" will become "10000.50". The number - * of dicimal digits, grouping and decimal characters can be specified. - * The currency input format is very strict, null will be returned if - * the pattern does not match. - * @param {String} the grouping character, default is "," - * @param {Number} number of decimal digits - * @param {String} the decimal character, default is "." - * @type {Double} the currency value as float. - */ - toCurrency : function(groupchar, digits, decimalchar) - { - groupchar = groupchar || ","; - decimalchar = decimalchar || "."; - digits = typeof(digits) == "undefined" ? 2 : digits; - - var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" - + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") - + "\\s*$"); - var m = this.match(exp); - if (m == null) - return null; - var intermed = m[2] + m[5] ; - var cleanInput = m[1] + intermed.replace( - new RegExp("(\\" + groupchar + ")", "g"), "") - + ((digits > 0) ? "." + m[7] : ""); - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); - }, - - /** - * Converts the string to a date by finding values that matches the - * date format pattern. - * @param string date format pattern, e.g. MM-dd-yyyy - * @return {Date} the date extracted from the string - */ - toDate : function(format) - { - return Date.SimpleParse(this, format); - } -}); \ No newline at end of file diff --git a/framework/Web/Javascripts/extra/behaviour.js b/framework/Web/Javascripts/extra/behaviour.js deleted file mode 100644 index ac9adeda..00000000 --- a/framework/Web/Javascripts/extra/behaviour.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work - of Simon Willison (see comments by Simon below). - - Description: - - Uses css selectors to apply javascript behaviours to enable - unobtrusive javascript in html documents. - - Usage: - - var myrules = { - 'b.someclass' : function(element){ - element.onclick = function(){ - alert(this.innerHTML); - } - }, - '#someid u' : function(element){ - element.onmouseover = function(){ - this.innerHTML = "BLAH!"; - } - } - }; - - Behaviour.register(myrules); - - // Call Behaviour.apply() to re-apply the rules (if you - // update the dom, etc). - - License: - - This file is entirely BSD licensed. - - More information: - - http://ripcord.co.nz/behaviour/ - -*/ - -var Behaviour = { - list : new Array, - - register : function(sheet){ - Behaviour.list.push(sheet); - }, - - start : function(){ - Event.OnLoad(Behaviour.apply); - }, - - apply : function(){ - for (h=0;sheet=Behaviour.list[h];h++){ - for (selector in sheet){ - list = document.getElementsBySelector(selector); - - if (!list){ - continue; - } - - for (i=0;element=list[i];i++){ - sheet[selector](element); - } - } - } - } -} - -Behaviour.start(); \ No newline at end of file diff --git a/framework/Web/Javascripts/extra/getElementsBySelector.js b/framework/Web/Javascripts/extra/getElementsBySelector.js deleted file mode 100644 index 592872fc..00000000 --- a/framework/Web/Javascripts/extra/getElementsBySelector.js +++ /dev/null @@ -1,176 +0,0 @@ -/** document.getElementsBySelector(selector) - - returns an array of element objects from the current document - matching the CSS selector. Selectors can contain element names, - class names and ids and can be nested. For example: - - elements = document.getElementsBySelect('div#main p a.external') - - Will return an array of all 'a' elements with 'external' in their - class attribute that are contained inside 'p' elements that are - contained inside the 'div' element which has id="main" - - New in version 0.4: Support for CSS2 and CSS3 attribute selectors: - See http://www.w3.org/TR/css3-selectors/#attribute-selectors - - Version 0.4 - Simon Willison, March 25th 2003 - -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows - -- Opera 7 fails -*/ - -/** - * Returns all children of element. Workaround required for IE5/Windo - */ -function getAllChildren(e) { - // Returns all children of element. Workaround required for IE5/Windows. Ugh. - return e.all ? e.all : e.getElementsByTagName('*'); -} - -/** - * returns an array of element objects from the current document - matching the CSS selector. Selectors can contain element names, - class names and ids and can be nested. For example: - -
    elements = $CSS('div#main p a.external')
    - - Will return an array of all 'a' elements with 'external' in their - class attribute that are contained inside 'p' elements that are - contained inside the 'div' element which has id="main" - */ -$CSS = function(selector) { - // Attempt to fail gracefully in lesser browsers - if (!document.getElementsByTagName) { - return new Array(); - } - // Split selector in to tokens - var tokens = selector.split(' '); - var currentContext = new Array(document); - for (var i = 0; i < tokens.length; i++) { - token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; - if (token.indexOf('#') > -1) { - // Token is an ID selector - var bits = token.split('#'); - var tagName = bits[0]; - var id = bits[1]; - var element = document.getElementById(id); - if (tagName && element.nodeName.toLowerCase() != tagName) { - // tag with that ID not found, return false - return new Array(); - } - // Set currentContext to contain just this element - currentContext = new Array(element); - continue; // Skip to next token - } - if (token.indexOf('.') > -1) { - // Token contains a class selector - var bits = token.split('.'); - var tagName = bits[0]; - var className = bits[1]; - if (!tagName) { - tagName = '*'; - } - // Get elements matching tag, filter them for class selector - var found = new Array; - var foundCount = 0; - for (var h = 0; h < currentContext.length; h++) { - var elements; - if (tagName == '*') { - elements = getAllChildren(currentContext[h]); - } else { - elements = currentContext[h].getElementsByTagName(tagName); - } - for (var j = 0; j < elements.length; j++) { - found[foundCount++] = elements[j]; - } - } - currentContext = new Array; - var currentContextIndex = 0; - for (var k = 0; k < found.length; k++) { - if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) { - currentContext[currentContextIndex++] = found[k]; - } - } - continue; // Skip to next token - } - // Code to deal with attribute selectors - if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { - var tagName = RegExp.$1; - var attrName = RegExp.$2; - var attrOperator = RegExp.$3; - var attrValue = RegExp.$4; - if (!tagName) { - tagName = '*'; - } - // Grab all of the tagName elements within current context - var found = new Array; - var foundCount = 0; - for (var h = 0; h < currentContext.length; h++) { - var elements; - if (tagName == '*') { - elements = getAllChildren(currentContext[h]); - } else { - elements = currentContext[h].getElementsByTagName(tagName); - } - for (var j = 0; j < elements.length; j++) { - found[foundCount++] = elements[j]; - } - } - currentContext = new Array; - var currentContextIndex = 0; - var checkFunction; // This function will be used to filter the elements - switch (attrOperator) { - case '=': // Equality - checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); }; - break; - case '~': // Match one of space seperated words - checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); }; - break; - case '|': // Match start with value followed by optional hyphen - checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); }; - break; - case '^': // Match starts with value - checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); }; - break; - case '$': // Match ends with value - fails with "Warning" in Opera 7 - checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); }; - break; - case '*': // Match ends with value - checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); }; - break; - default : - // Just test for existence of attribute - checkFunction = function(e) { return e.getAttribute(attrName); }; - } - currentContext = new Array; - var currentContextIndex = 0; - for (var k = 0; k < found.length; k++) { - if (checkFunction(found[k])) { - currentContext[currentContextIndex++] = found[k]; - } - } - // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue); - continue; // Skip to next token - } - // If we get here, token is JUST an element (not a class or ID selector) - tagName = token; - var found = new Array; - var foundCount = 0; - for (var h = 0; h < currentContext.length; h++) { - var elements = currentContext[h].getElementsByTagName(tagName); - for (var j = 0; j < elements.length; j++) { - found[foundCount++] = elements[j]; - } - } - currentContext = found; - } - return currentContext; -} - -/* That revolting regular expression explained -/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ - \---/ \---/\-------------/ \-------/ - | | | | - | | | The value - | | ~,|,^,$,* or = - | Attribute - Tag -*/ diff --git a/framework/Web/Javascripts/extra/json.js b/framework/Web/Javascripts/extra/json.js deleted file mode 100644 index 0981169d..00000000 --- a/framework/Web/Javascripts/extra/json.js +++ /dev/null @@ -1,340 +0,0 @@ -/* -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.AJAX.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(); - } -}; \ No newline at end of file diff --git a/framework/Web/Javascripts/extra/logger.js b/framework/Web/Javascripts/extra/logger.js deleted file mode 100644 index b21df1ae..00000000 --- a/framework/Web/Javascripts/extra/logger.js +++ /dev/null @@ -1,753 +0,0 @@ -/* - -Created By: Corey Johnson -E-mail: probablyCorey@gmail.com - -Requires: Prototype Javascript library (http://prototype.conio.net/) - -Use it all you want. Just remember to give me some credit :) - -*/ - -// ------------ -// Custom Event -// ------------ - -CustomEvent = Class.create() -CustomEvent.prototype = { - initialize : function() { - this.listeners = [] - }, - - addListener : function(method) { - this.listeners.push(method) - }, - - removeListener : function(method) { - var foundIndexes = this._findListenerIndexes(method) - - for(var i = 0; i < foundIndexes.length; i++) { - this.listeners.splice(foundIndexes[i], 1) - } - }, - - dispatch : function(handler) { - for(var i = 0; i < this.listeners.length; i++) { - try { - this.listeners[i](handler) - } - catch (e) { - alert("Could not run the listener " + this.listeners[i] + ". " + e) - } - } - }, - - // Private Methods - // --------------- - _findListenerIndexes : function(method) { - var indexes = [] - for(var i = 0; i < this.listeners.length; i++) { - if (this.listeners[i] == method) { - indexes.push(i) - } - } - - return indexes - } -} - -// ------ -// Cookie -// ------ - -var Cookie = { - set : function(name, value, expirationInDays, path) { - var cookie = escape(name) + "=" + escape(value) - - if (expirationInDays) { - var date = new Date() - date.setDate(date.getDate() + expirationInDays) - cookie += "; expires=" + date.toGMTString() - } - - if (path) { - cookie += ";path=" + path - } - - document.cookie = cookie - - if (value && (expirationInDays == undefined || expirationInDays > 0) && !this.get(name)) { - Logger.error("Cookie (" + name + ") was not set correctly... The value was " + value.toString().length + " charachters long (This may be over the cookie limit)"); - } - }, - - get : function(name) { - var pattern = "(^|;)\\s*" + escape(name) + "=([^;]+)" - - var m = document.cookie.match(pattern) - if (m && m[2]) { - return unescape(m[2]) - } - else return null - }, - - getAll : function() { - var cookies = document.cookie.split(';') - var cookieArray = [] - - for (var i = 0; i < cookies.length; i++) { - try { - var name = unescape(cookies[i].match(/^\s*([^=]+)/m)[1]) - var value = unescape(cookies[i].match(/=(.*$)/m)[1]) - } - catch (e) { - continue - } - - cookieArray.push({name : name, value : value}) - - if (cookieArray[name] != undefined) { - Logger.waring("Trying to retrieve cookie named(" + name + "). There appears to be another property with this name though."); - } - - cookieArray[name] = value - } - - return cookieArray - }, - - clear : function(name) { - this.set(name, "", -1) - }, - - clearAll : function() { - var cookies = this.getAll() - - for(var i = 0; i < cookies.length; i++) { - this.clear(cookies[i].name) - } - - } -} - -// ------ -// Logger -// ----- - -Logger = { - logEntries : [], - - onupdate : new CustomEvent(), - onclear : new CustomEvent(), - - - // Logger output - log : function(message, tag) { - var logEntry = new LogEntry(message, tag || "info") - this.logEntries.push(logEntry) - this.onupdate.dispatch(logEntry) - }, - - info : function(message) { - this.log(message, 'info') - if(typeof(console) != "undefined") - console.info(message); - }, - - debug : function(message) { - this.log(message, 'debug') - if(typeof(console) != "undefined") - console.debug(message); - }, - - warn : function(message) { - this.log(message, 'warning') - if(typeof(console) != "undefined") - console.warn(message); - }, - - error : function(message, error) { - this.log(message + ": \n" + error, 'error') - if(typeof(console) != "undefined") - console.error(message); - - }, - - clear : function () { - this.logEntries = [] - this.onclear.dispatch() - } -} - -LogEntry = Class.create() -LogEntry.prototype = { - initialize : function(message, tag) { - this.message = message - this.tag = tag - } -} - -LogConsole = Class.create() -LogConsole.prototype = { - - // Properties - // ---------- - commandHistory : [], - commandIndex : 0, - - hidden : true, - - // Methods - // ------- - - initialize : function(toggleKey) { - this.outputCount = 0 - this.tagPattern = Cookie.get('tagPattern') || ".*" - - // I hate writing javascript in HTML... but what's a better alternative - this.logElement = document.createElement('div') - document.body.appendChild(this.logElement) - Element.hide(this.logElement) - - this.logElement.style.position = "absolute" - this.logElement.style.left = '0px' - this.logElement.style.width = '100%' - - this.logElement.style.textAlign = "left" - this.logElement.style.fontFamily = "lucida console" - this.logElement.style.fontSize = "100%" - this.logElement.style.backgroundColor = 'darkgray' - this.logElement.style.opacity = 0.9 - this.logElement.style.zIndex = 2000 - - // Add toolbarElement - this.toolbarElement = document.createElement('div') - this.logElement.appendChild(this.toolbarElement) - this.toolbarElement.style.padding = "0 0 0 2px" - - // Add buttons - this.buttonsContainerElement = document.createElement('span') - this.toolbarElement.appendChild(this.buttonsContainerElement) - - this.buttonsContainerElement.innerHTML += '' - this.buttonsContainerElement.innerHTML += '' - if(!Prado.Inspector.disabled) - this.buttonsContainerElement.innerHTML += '' - - - //Add Tag Filter - this.tagFilterContainerElement = document.createElement('span') - this.toolbarElement.appendChild(this.tagFilterContainerElement) - this.tagFilterContainerElement.style.cssFloat = 'left' - this.tagFilterContainerElement.appendChild(document.createTextNode("Log Filter")) - - this.tagFilterElement = document.createElement('input') - this.tagFilterContainerElement.appendChild(this.tagFilterElement) - this.tagFilterElement.style.width = '200px' - this.tagFilterElement.value = this.tagPattern - this.tagFilterElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out - - Event.observe(this.tagFilterElement, 'keyup', this.updateTags.bind(this)) - Event.observe(this.tagFilterElement, 'click', function() {this.tagFilterElement.select()}.bind(this)) - - // Add outputElement - this.outputElement = document.createElement('div') - this.logElement.appendChild(this.outputElement) - this.outputElement.style.overflow = "auto" - this.outputElement.style.clear = "both" - this.outputElement.style.height = "200px" - this.outputElement.style.backgroundColor = 'black' - - this.inputContainerElement = document.createElement('div') - this.inputContainerElement.style.width = "100%" - this.logElement.appendChild(this.inputContainerElement) - - this.inputElement = document.createElement('input') - this.inputContainerElement.appendChild(this.inputElement) - this.inputElement.style.width = '100%' - this.inputElement.style.borderWidth = '0px' // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0 - this.inputElement.style.margin = '0px' - this.inputElement.style.padding = '0px' - this.inputElement.value = 'Type command here' - this.inputElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out - - Event.observe(this.inputElement, 'keyup', this.handleInput.bind(this)) - Event.observe(this.inputElement, 'click', function() {this.inputElement.select()}.bind(this)) - - if(document.all && !window.opera) - { - window.setInterval(this.repositionWindow.bind(this), 500) - } - else - { - this.logElement.style.position="fixed"; - this.logElement.style.bottom="0px"; - } - var self=this; - Event.observe(document, 'keydown', function(e) - { - if((e.altKey==true) && Event.keyCode(e) == toggleKey ) //Alt+J | Ctrl+J - self.toggle(); - }); - - // Listen to the logger.... - Logger.onupdate.addListener(this.logUpdate.bind(this)) - Logger.onclear.addListener(this.clear.bind(this)) - - // Preload log element with the log entries that have been entered - for (var i = 0; i < Logger.logEntries.length; i++) { - this.logUpdate(Logger.logEntries[i]) - } - - // Feed all errors into the logger (For some unknown reason I can only get this to work - // with an inline event declaration) - Event.observe(window, 'error', function(msg, url, lineNumber) {Logger.error("Error in (" + (url || location) + ") on line "+lineNumber+"", msg)}) - - // Allow acess key link - var accessElement = document.createElement('span') - accessElement.innerHTML = '' - document.body.appendChild(accessElement) - - if (Cookie.get('ConsoleVisible') == 'true') { - this.toggle() - } - }, - - toggle : function() { - if (this.logElement.style.display == 'none') { - this.show() - } - else { - this.hide() - } - }, - - show : function() { - Element.show(this.logElement) - this.outputElement.scrollTop = this.outputElement.scrollHeight // Scroll to bottom when toggled - if(document.all && !window.opera) - this.repositionWindow(); - Cookie.set('ConsoleVisible', 'true') - this.inputElement.select() - this.hidden = false; - }, - - hide : function() { - this.hidden = true; - Element.hide(this.logElement) - Cookie.set('ConsoleVisible', 'false') - }, - - output : function(message, style) { - // If we are at the bottom of the window, then keep scrolling with the output - var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight - - this.outputCount++ - style = (style ? style += ';' : '') - style += 'padding:1px;margin:0 0 5px 0' - - if (this.outputCount % 2 == 0) style += ";background-color:#101010" - - message = message || "undefined" - message = message.toString().escapeHTML() - - this.outputElement.innerHTML += "
    " + 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-1){ - this.d.getElementById(spanID).innerHTML="[-]"; - } else { - this.d.getElementById(spanID).innerHTML="[+]"; - } - }, - - buildInspectionLevel : function() - { - var display = this.displaying; - var list = display.split("."); - var links = ["[object Window]"]; - var name = ''; - if(display.indexOf("[object ") >= 0) return links.join("."); - for(var i = 0; i < list.length; i++) - { - name += (name.length ? "." : "") + list[i]; - links[i+1] = ""+list[i]+""; - } - return links.join("."); - }, - - buildTree : function() { - mHTML = "
    Inspecting "+this.buildInspectionLevel()+"
    "; - mHTML +="
      "; - this.types.sort(); - var so_objIndex=0; - for(i=0;i[+]" + this.types[i] + " (" + this.nameList[this.types[i]].length + ")
        "; - this.hidden["ul"+i]=0; - for(e=0;e= 0 && /^[a-zA-Z_]/.test(prop)) - { - if(this.displaying.indexOf("[object ") < 0) - more = " more"; - else if(this.displaying.indexOf("[object Window]") >= 0) - more = " more"; - } - mHTML+="
      • [+]" + prop + "
        • " + value + more + "
        "; - this.hidden["mul"+so_objIndex]=0; - so_objIndex++; - } - mHTML+="
      "; - } - mHTML+="
    "; - 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/prado.js b/framework/Web/Javascripts/js/compressed/prado.js index 6fadd8de..df87ac8f 100644 --- a/framework/Web/Javascripts/js/compressed/prado.js +++ b/framework/Web/Javascripts/js/compressed/prado.js @@ -250,7 +250,12 @@ 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;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)));}});}} -Function.prototype.bindEvent=function() +var Prado={Version:'3.0.0',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);}}};Function.prototype.bindEvent=function() {var __method=this,args=$A(arguments),object=args.shift();return function(event) {return __method.apply(object,[event||window.event].concat(args));}} Class.extend=function(base,definition) @@ -259,7 +264,65 @@ Object.extend(component.prototype,definition);return component;} var Base=function(){if(arguments.length){if(this==window){Base.prototype.extend.call(arguments[0],arguments.callee.prototype);}else{this.extend(arguments[0]);}}};Base.version="1.0.2";Base.prototype={extend:function(source,value){var extend=Base.prototype.extend;if(arguments.length==2){var ancestor=this[source];if((ancestor instanceof Function)&&(value instanceof Function)&&ancestor.valueOf()!=value.valueOf()&&/\bbase\b/.test(value)){var method=value;value=function(){var previous=this.base;this.base=ancestor;var returnValue=method.apply(this,arguments);this.base=previous;return returnValue;};value.valueOf=function(){return method;};value.toString=function(){return String(method);};} return this[source]=value;}else if(source){var _prototype={toSource:null};var _protected=["toString","valueOf"];if(Base._prototyping)_protected[2]="constructor";for(var i=0;(name=_protected[i]);i++){if(source[name]!=_prototype[name]){extend.call(this,name,source[name]);}} for(var name in source){if(!_prototype[name]){extend.call(this,name,source[name]);}}} -return this;},base:function(){}};Base.extend=function(_instance,_static){var extend=Base.prototype.extend;if(!_instance)_instance={};Base._prototyping=true;var _prototype=new this;extend.call(_prototype,_instance);var constructor=_prototype.constructor;_prototype.constructor=this;delete Base._prototyping;var klass=function(){if(!Base._prototyping)constructor.apply(this,arguments);this.constructor=klass;};klass.prototype=_prototype;klass.extend=this.extend;klass.implement=this.implement;klass.toString=function(){return String(constructor);};extend.call(klass,_static);var object=constructor?klass:_prototype;if(object.init instanceof Function)object.init();return object;};Base.implement=function(_interface){if(_interface instanceof Function)_interface=_interface.prototype;this.prototype.extend(_interface);};Object.extend(String.prototype,{pad:function(side,len,chr){if(!chr)chr=' ';var s=this;var left=side.toLowerCase()=='left';while(s.length0) +form.action=options['PostBackUrl'];if(options['TrackFocus']) +{var lastFocus=$('PRADO_LASTFOCUS');if(lastFocus) +{var active=document.activeElement;if(active) +lastFocus.value=active.id;else +lastFocus.value=options['EventTarget'];}} +$('PRADO_POSTBACK_TARGET').value=options['EventTarget'];$('PRADO_POSTBACK_PARAMETER').value=options['EventParameter'];Event.stop(event);Event.fireEvent(form,"submit");} +Prado.Element={setValue:function(element,value) +{var el=$(element);if(el&&typeof(el.value)!="undefined") +el.value=value;},select:function(element,method,value) +{var el=$(element);var isList=element.indexOf('[]')>-1;if(!el&&!isList)return;method=isList?'check'+method:el.tagName.toLowerCase()+method;var selection=Prado.Element.Selection;if(isFunction(selection[method])) +selection[method](isList?element:el,value);},click:function(element) +{var el=$(element);if(el) +Event.fireEvent(el,'click');},setAttribute:function(element,attribute,value) +{var el=$(element);if(attribute=="disabled"&&value==false) +el.removeAttribute(attribute);else +el.setAttribute(attribute,value);},setOptions:function(element,options) +{var el=$(element);if(el&&el.tagName.toLowerCase()=="select") +{while(el.length>0) +el.remove(0);for(var i=0;i1) +return Builder.node(tag,args.shift(),args);};});}});Builder.exportTags();Object.extend(String.prototype,{pad:function(side,len,chr){if(!chr)chr=' ';var s=this;var left=side.toLowerCase()=='left';while(s.length28){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;}});Object.extend(Builder,{exportTags:function() -{var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG","CAPTION"];tags.each(function(tag) -{window[tag]=function() -{var args=$A(arguments);if(args.length==0) -return Builder.node(tag,null);if(args.length==1) -return Builder.node(tag,args[0]);if(args.length>1) -return Builder.node(tag,args.shift(),args);};});}});Builder.exportTags();var Prado={Version:'3.0.0',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.PostBack=function(event,options) -{var form=$(options['FormID']);var canSubmit=true;if(options['CausesValidation']&&typeof(Prado.Validation)!="undefined") -{if(!Prado.Validation.validate(options['FormID'],options['ValidationGroup'],$(options['ID']))) -return Event.stop(event);} -if(options['PostBackUrl']&&options['PostBackUrl'].length>0) -form.action=options['PostBackUrl'];if(options['TrackFocus']) -{var lastFocus=$('PRADO_LASTFOCUS');if(lastFocus) -{var active=document.activeElement;if(active) -lastFocus.value=active.id;else -lastFocus.value=options['EventTarget'];}} -$('PRADO_POSTBACK_TARGET').value=options['EventTarget'];$('PRADO_POSTBACK_PARAMETER').value=options['EventParameter'];Event.stop(event);Event.fireEvent(form,"submit");} -Prado.Element={setValue:function(element,value) -{var el=$(element);if(el&&typeof(el.value)!="undefined") -el.value=value;},select:function(element,method,value) -{var el=$(element);var isList=element.indexOf('[]')>-1;if(!el&&!isList)return;method=isList?'check'+method:el.tagName.toLowerCase()+method;var selection=Prado.Element.Selection;if(isFunction(selection[method])) -selection[method](isList?element:el,value);},click:function(element) -{var el=$(element);if(el) -Event.fireEvent(el,'click');},setAttribute:function(element,attribute,value) -{var el=$(element);if(attribute=="disabled"&&value==false) -el.removeAttribute(attribute);else -el.setAttribute(attribute,value);},setOptions:function(element,options) -{var el=$(element);if(el&&el.tagName.toLowerCase()=="select") -{while(el.length>0) -el.remove(0);for(var i=0;i0) window.clipboardData.setData("Text",text);},hover:function(obj) {obj.parentNode.className="copycode copycode_hover";},out:function(obj) -{obj.parentNode.className="copycode";}});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-1?this.radios[index].value:this.options.caption;}} \ No newline at end of file +{obj.parentNode.className="copycode";}});Prado.WebUI.TCheckBoxList=Base.extend({constructor:function(options) +{for(var i=0;i 4) { @@ -240,13 +240,14 @@ Rico.Color.RGBtoHSB = function(r, g, b) { return { h : hue, s : saturation, b : brightness }; } - - + + + Prado.WebUI.TColorPicker = Class.create(); Object.extend(Prado.WebUI.TColorPicker, { - palettes: + palettes: { Small : [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"], ["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"], @@ -261,7 +262,7 @@ Object.extend(Prado.WebUI.TColorPicker, ["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]] }, - UIImages : + UIImages : { 'button.gif' : 'button.gif', // 'target_black.gif' : 'target_black.gif', @@ -272,11 +273,11 @@ Object.extend(Prado.WebUI.TColorPicker, } }); -Object.extend(Prado.WebUI.TColorPicker.prototype, +Object.extend(Prado.WebUI.TColorPicker.prototype, { initialize : function(options) { - var basics = + var basics = { Palette : 'Small', ClassName : 'TColorPicker', @@ -285,7 +286,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, CancelButtonText : 'Cancel', ShowColorPicker : true } - + this.element = null; this.showing = false; @@ -301,10 +302,10 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, updatePicker : function(e) { - var color = Rico.Color.createFromHex(this.input.value); + var color = Rico.Color.createFromHex(this.input.value); this.button.style.backgroundColor = color.toString(); }, - + buttonOnClick : function(event) { var mode = this.options['Mode']; @@ -328,7 +329,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, this.initializeFullPicker(); } this.show(mode); - }, + }, show : function(type) { @@ -340,14 +341,14 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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); + Event.observe(document,"keydown", this._documentKeyDownEvent); this.showing = true; if(type == "Full") @@ -359,7 +360,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, } } }, - + hide : function(event) { if(this.showing) @@ -370,11 +371,11 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, this.element.style.display = "none"; this.showing = false; Event.stopObserving(document.body, "click", this._documentClickEvent); - Event.stopObserving(document,"keydown", this._documentKeyDownEvent); - + Event.stopObserving(document,"keydown", this._documentKeyDownEvent); + if(this._observingMouseMove) - { - Event.stopObserving(document.body, "mousemove", this._onMouseMove); + { + Event.stopObserving(document.body, "mousemove", this._onMouseMove); this._observingMouseMove = false; } } @@ -396,16 +397,16 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, within = within || el == this.button; within = within || el == this.input; if(within) break; - el = el.parentNode; + el = el.parentNode; } while(el); if(!within) this.hide(ev); }, - ieHack : function() + ieHack : function() { // IE hack - if(this.iePopUp) + if(this.iePopUp) { this.iePopUp.style.display = "block"; this.iePopUp.style.top = (this.element.offsetTop) + "px"; @@ -448,7 +449,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, cellOnClick : function(e) { - var el = Event.element(e); + var el = Event.element(e); if(el.tagName.toLowerCase() != "img") return; var color = Rico.Color.createColorFromBackground(el); @@ -464,15 +465,15 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, }, getFullPickerContainer : function(pickerID) - { + { //create the 3 buttons - this.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) @@ -483,13 +484,13 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, //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 = + var inputsTable = TABLE({className:'inputs'}, TBODY(null, TR(null, TD({className:'currentcolor',colSpan:2}, @@ -502,30 +503,30 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, TR(null, TD(null,'S:'), TD(null,this.inputs['S'], '%')), - - TR(null, + + TR(null, TD(null,'V:'), TD(null,this.inputs['V'], '%')), - - TR(null, + + TR(null, TD({className:'gap'},'R:'), TD({className:'gap'},this.inputs['R'])), - - TR(null, + + TR(null, TD(null,'G:'), TD(null, this.inputs['G'])), - TR(null, + TR(null, TD(null,'B:'), TD(null, this.inputs['B'])), - TR(null, + TR(null, TD({className:'gap'},'#'), TD({className:'gap'},this.inputs['HEX'])) )); - var UIimages = - { + var UIimages = + { selector : SPAN({className:'selector'}), background : SPAN({className:'colorpanel'}), slider : SPAN({className:'slider'}), @@ -538,23 +539,23 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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 = + 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'], + TR({className:'options'}, + TD({colSpan:3}, + this.buttons['OK'], this.buttons['Cancel']) ) )); - + return DIV({className:this.options['ClassName']+" FullColorPicker", id:pickerID+"_picker"},pickerTable); }, @@ -565,16 +566,16 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, this.inputs.oldColor.style.backgroundColor = color.asHex(); this.setColor(color,true); - var i = 0; + var i = 0; for(var type in this.inputs) { - Event.observe(this.inputs[type], "change", + Event.observe(this.inputs[type], "change", this.onInputChanged.bindEvent(this,type)); i++; if(i > 6) break; } - + this.isMouseDownOnColor = false; this.isMouseDownOnHue = false; @@ -587,9 +588,9 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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'])); @@ -602,7 +603,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, { Event.observe(document.body, "mousemove", this._onMouseMove); this._observingMouseMove = true; - } + } }, onColorMouseDown : function(ev) @@ -633,15 +634,15 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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 x = this.truncate(px - pos[0],0,255); var y = this.truncate(py - pos[1],0,255); @@ -650,7 +651,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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; @@ -661,7 +662,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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); @@ -672,7 +673,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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; @@ -743,12 +744,12 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, 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); }, @@ -757,11 +758,11 @@ Object.extend(Prado.WebUI.TColorPicker.prototype, { 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(); diff --git a/framework/Web/Javascripts/js/debug/prado.js b/framework/Web/Javascripts/js/debug/prado.js index b9ed0117..12d790e6 100644 --- a/framework/Web/Javascripts/js/debug/prado.js +++ b/framework/Web/Javascripts/js/debug/prado.js @@ -3349,6 +3349,63 @@ var Builder = { +var Prado = +{ + Version: '3.0.0', + + /** + * Returns browser information. Example + * + * 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. */ @@ -3484,140 +3541,379 @@ Base.implement = function(_interface) { if (_interface instanceof Function) _interface = _interface.prototype; this.prototype.extend(_interface); }; - - + /** - * @class String extensions + * Performs a post-back using javascript + * */ -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 - */ +Prado.PostBack = function(event,options) +{ + var form = $(options['FormID']); + var canSubmit = true; - pad : function(side, len, chr) { - if (!chr) chr = ' '; - var s = this; - var left = side.toLowerCase()=='left'; - while (s.length 0) + form.action = options['PostBackUrl']; + + 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']; + } + } + $('PRADO_POSTBACK_TARGET').value = options['EventTarget']; + $('PRADO_POSTBACK_PARAMETER').value = options['EventParameter']; /** - * @param {Number} minimum string length. - * @param {String} character(s) to pad - * @return {String} padded character(s) on the left to satisfy minimum string length + * Since google toolbar prevents browser default action, + * we will always disable default client-side browser action */ - padLeft : function(len, chr) { - return this.pad('left',len,chr); - }, + /*if(options['StopEvent']) */ + Event.stop(event); + Event.fireEvent(form,"submit"); +} +/** + * Additional element utilities. + */ +Prado.Element = +{ /** - * @param {Number} minimum string length. - * @param {String} character(s) to pad - * @return {String} padded character(s) on the right to satisfy minimum string length + * Set the value of a particular element. + * @param string element id + * @param string new element value. */ - padRight : function(len, chr) { - return this.pad('right',len,chr); + setValue : function(element, value) + { + var el = $(element); + if(el && typeof(el.value) != "undefined") + el.value = value; }, - /** - * @param {Number} minimum string length. - * @return {String} append zeros to the left to satisfy minimum string length. - */ - zerofill : function(len) { - return this.padLeft(len,'0'); + select : function(element, method, value) + { + var el = $(element); + var isList = element.indexOf('[]') > -1; + if(!el && !isList) return; + method = isList ? 'check'+method : el.tagName.toLowerCase()+method; + var selection = Prado.Element.Selection; + if(isFunction(selection[method])) + selection[method](isList ? element : el,value); }, - /** - * @return {String} removed white spaces from both ends. - */ - trim : function() { - return this.replace(/^\s+|\s+$/g,''); + click : function(element) + { + var el = $(element); + if(el) + Event.fireEvent(el,'click'); }, - /** - * @return {String} removed white spaces from the left end. - */ - trimLeft : function() { - return this.replace(/^\s+/,''); + setAttribute : function(element, attribute, value) + { + var el = $(element); + if(attribute == "disabled" && value==false) + el.removeAttribute(attribute); + else + el.setAttribute(attribute, value); }, - /** - * @return {String} removed white spaces from the right end. - */ - trimRight : function() { - return this.replace(/\s+$/,''); + setOptions : function(element, options) + { + var el = $(element); + if(el && el.tagName.toLowerCase() == "select") + { + while(el.length > 0) + el.remove(0); + for(var i = 0; iInternationalization - * is not supported - * @param {String} the decimal character - * @return {Double} null if string does not represent a float value - */ - toDouble : function(decimalchar) + selectAll : function(el) { - if(this.length <= 0) return null; - decimalchar = decimalchar || "."; - var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); - var m = this.match(exp); - - if (m == null) - return null; - m[1] = m[1] || ""; - m[2] = m[2] || "0"; - m[4] = m[4] || "0"; - - var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; - var num = parseFloat(cleanInput); - return (isNaN(num) ? null : num); + $A(el.options).each(function(option) + { + option.selected = true; + Logger.warn(option.value); + }); }, - /** - * Convert strings that represent a currency value (e.g. a float with grouping - * characters) to float. E.g. "10,000.50" will become "10000.50". The number + selectInvert : function(el) + { + $A(el.options).each(function(option) + { + option.selected = !option.selected; + }); + }, + + checkValue : function(name, value) + { + $A(document.getElementsByName(name)).each(function(el) + { + el.checked = el.value == value + }); + }, + + checkIndex : function(name, index) + { + var elements = $A(document.getElementsByName(name)); + for(var i = 0; i1) + return Builder.node(tag,args.shift(),args); + + }; + }); + } +}); + +Builder.exportTags(); + +/** + * @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.lengthInternationalization + * is not supported + * @param {String} the decimal character + * @return {Double} null if string does not represent a float value + */ + toDouble : function(decimalchar) + { + if(this.length <= 0) return null; + decimalchar = decimalchar || "."; + var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); + var m = this.match(exp); + + if (m == null) + return null; + m[1] = m[1] || ""; + m[2] = m[2] || "0"; + m[4] = m[4] || "0"; + + var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); + }, + + /** + * Convert strings that represent a currency value (e.g. a float with grouping + * characters) to float. E.g. "10,000.50" will become "10000.50". The number * of dicimal digits, grouping and decimal characters can be specified. * The currency input format is very strict, null will be returned if * the pattern does not match. @@ -3640,14 +3936,14 @@ Object.extend(String.prototype, { return null; var intermed = m[2] + m[5] ; var cleanInput = m[1] + intermed.replace( - new RegExp("(\\" + groupchar + ")", "g"), "") + new RegExp("(\\" + groupchar + ")", "g"), "") + ((digits > 0) ? "." + m[7] : ""); var num = parseFloat(cleanInput); return (isNaN(num) ? null : num); }, /** - * Converts the string to a date by finding values that matches the + * Converts the string to a date by finding values that matches the * date format pattern. * @param string date format pattern, e.g. MM-dd-yyyy * @return {Date} the date extracted from the string @@ -3656,19 +3952,19 @@ Object.extend(String.prototype, { { return Date.SimpleParse(this, format); } -}); - +}); + /** * @class Event extensions. */ -Object.extend(Event, +Object.extend(Event, { /** - * Register a function to be executed when the page is loaded. - * Note that the page is only loaded if all resources (e.g. images) + * Register a function to be executed when the page is loaded. + * Note that the page is only loaded if all resources (e.g. images) * are loaded. - * - * Example: Show an alert box with message "Page Loaded!" when the + * + * Example: Show an alert box with message "Page Loaded!" when the * page finished loading. * * Event.OnLoad(function(){ alert("Page Loaded!"); }); @@ -3676,18 +3972,18 @@ Object.extend(Event, * * @param {Function} function to execute when page is loaded. */ - OnLoad : function (fn) + OnLoad : function (fn) { // opera onload is in document, not window - var w = document.addEventListener && + 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. + * @return {Number} the Unicode character code generated by the key + * that was struck. */ keyCode : function(e) { @@ -3696,33 +3992,33 @@ Object.extend(Event, /** * @param {String} event type or event name. - * @return {Boolean} true if event type is of HTMLEvent, false + * @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', + 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, + * @return {Boolean} true if event type is of MouseEvent, * false otherwise */ isMouseEvent : function(type) { - var events = ['click', 'mousedown', 'mousemove', 'mouseout', + 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 + * 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. @@ -3734,7 +4030,7 @@ Object.extend(Event, if(type == "submit") return element.submit(); if(document.createEvent) - { + { if(Event.isHTMLEvent(type)) { var event = document.createEvent('HTMLEvents'); @@ -3742,11 +4038,11 @@ Object.extend(Event, } else if(Event.isMouseEvent(type)) { - var event = document.createEvent('MouseEvents'); + var event = document.createEvent('MouseEvents'); if (event.initMouseEvent) { event.initMouseEvent(type,true,true, - document.defaultView, 1, 0, 0, 0, 0, false, + document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null); } else @@ -3766,663 +4062,177 @@ Object.extend(Event, 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; - } -}); - - -Object.extend(Builder, -{ - exportTags:function() - { - var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG", "CAPTION"]; - tags.each(function(tag) - { - window[tag]=function() - { - var args=$A(arguments); - if(args.length==0) - return Builder.node(tag,null); - if(args.length==1) - return Builder.node(tag,args[0]); - if(args.length>1) - return Builder.node(tag,args.shift(),args); - - }; - }); - } -}); - -Builder.exportTags(); - - - -var Prado = -{ - Version: '3.0.0', - - /** - * Returns browser information. Example - * - * 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 0) - form.action = options['PostBackUrl']; - - 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']; - } - } - - $('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"); -} - -/* - -Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidation, validationGroup, actionUrl, trackFocus, clientSubmit) -{ - if (typeof(performValidation) == 'undefined') - { - var performValidation = false; - var validationGroup = ''; - var actionUrl = null; - var trackFocus = false; - var clientSubmit = true; - } - var theForm = document.getElementById ? document.getElementById(formID) : document.forms[formID]; - var canSubmit = true; - if (performValidation) - { - //canSubmit = Prado.Validation.validate(validationGroup); - * Prado.Validation.ActiveTarget = theForm; - Prado.Validation.CurrentTargetGroup = null; - Prado.Validation.IsGroupValidation = false; - canSubmit = Prado.Validation.IsValid(theForm); - Logger.debug(canSubmit);* - canSubmit = Prado.Validation.IsValid(theForm); - } - if (canSubmit) - { - if (actionUrl != null && (actionUrl.length > 0)) - { - theForm.action = actionUrl; - } - if (trackFocus) - { - var lastFocus = theForm.elements['PRADO_LASTFOCUS']; - if ((typeof(lastFocus) != 'undefined') && (lastFocus != null)) - { - var active = document.activeElement; - if (typeof(active) == 'undefined') - { - lastFocus.value = eventTarget; - } - else - { - if ((active != null) && (typeof(active.id) != 'undefined')) - { - if (active.id.length > 0) - { - lastFocus.value = active.id; - } - else if (typeof(active.name) != 'undefined') - { - lastFocus.value = active.name; - } - } - } - } - } - if (!clientSubmit) - { - canSubmit = false; - } - } - if (canSubmit && (!theForm.onsubmit || theForm.onsubmit())) - { - theForm.PRADO_POSTBACK_TARGET.value = eventTarget; - theForm.PRADO_POSTBACK_PARAMETER.value = eventParameter; - theForm.submit(); - } -} -*/ - -Prado.Element = -{ - /** - * Set the value of a particular element. - * @param string element id - * @param string new element value. - */ - setValue : function(element, value) - { - var el = $(element); - if(el && typeof(el.value) != "undefined") - el.value = value; - }, - - select : function(element, method, value) - { - var el = $(element); - var isList = element.indexOf('[]') > -1; - if(!el && !isList) return; - method = isList ? 'check'+method : el.tagName.toLowerCase()+method; - var selection = Prado.Element.Selection; - if(isFunction(selection[method])) - selection[method](isList ? element : el,value); - }, - - click : function(element) - { - var el = $(element); - if(el) - Event.fireEvent(el,'click'); - }, - - setAttribute : function(element, attribute, value) - { - var el = $(element); - if(attribute == "disabled" && value==false) - el.removeAttribute(attribute); - else - el.setAttribute(attribute, value); - }, + 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); - setOptions : function(element, options) - { - var el = $(element); - if(el && el.tagName.toLowerCase() == "select") + // do some funky regexs to replace the format string + // with the real values + var frm = new String(format); + for (var sect in bits) { - while(el.length > 0) - el.remove(0); - for(var i = 0; i=minlength; x--) + { + var token=str.substring(i,i+x); + if (token.length < minlength) { return null; } + if (isInteger(token)) { return token; } + } + return null; + }; - selectInvert : function(el) - { - $A(el.options).each(function(option) - { - option.selected = !option.selected; - }); - }, + 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; - checkValue : function(name, value) - { - $A(document.getElementsByName(name)).each(function(el) + while (i_format < format.length) { - el.checked = el.value == value - }); - }, + // 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++); + } - checkIndex : function(name, index) - { - var elements = $A(document.getElementsByName(name)); - for(var i = 0; i 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;} + } } - }, - checkClear : function(name) - { - $A(document.getElementsByName(name)).each(function(el) - { - el.checked = false; - }); - }, + // If there are any trailing characters left in the value, it doesn't match + if (i_val != val.length) { return null; } - checkAll : function(name) - { - $A(document.getElementsByName(name)).each(function(el) - { - el.checked = true; - }); - }, - checkInvert : function(name) - { - $A(document.getElementsByName(name)).each(function(el) + // Is date valid for month? + if (month==2) { - el.checked = !el.checked; - }); - } -}; - -Prado.WebUI = Class.create(); - -//base postback-able controls -/*Prado.WebUI.PostBackControl = Class.create(); -Prado.WebUI.PostBackControl.prototype = -{ - initialize : function(options) - { - this.element = $(options['ID']); + // 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(options.CausesValidation && typeof(Prado.Validation) != 'undefined') + if ((month==4)||(month==6)||(month==9)||(month==11)) { - Prado.Validation.registerTarget(options); + if (date > 30) { return null; } } - //TODO: what do the following options do? - //options['PostBackUrl'] - //options['ClientSubmit'] - - if(this.onInit) - this.onInit(options); + var newdate=new Date(year,month-1,date, 0, 0, 0); + return newdate; } -}; - -//short cut to create postback components -Prado.WebUI.createPostBackComponent = function(definition) -{ - var component = Class.create(); - Object.extend(component.prototype, Prado.WebUI.PostBackControl.prototype); - if(definition) Object.extend(component.prototype, definition); - return component; -} +}); + +Prado.WebUI = Class.create(); -Prado.WebUI.TButton = Prado.WebUI.createPostBackComponent(); -*/ Prado.WebUI.PostBackControl = Class.create(); Prado.WebUI.PostBackControl.prototype = { - _elementOnClick : null, //capture the element's onclick function - initialize : function(options) { + this._elementOnClick = null, //capture the element's onclick function + this.element = $(options.ID); - if(this.onInit) - this.onInit(options); + if(this.element) + { + if(this.onInit) + this.onInit(options); + } }, onInit : function(options) @@ -4432,10 +4242,10 @@ Prado.WebUI.PostBackControl.prototype = this._elementOnClick = this.element.onclick; this.element.onclick = null; } - Event.observe(this.element, "click", this.onClick.bindEvent(this,options)); + Event.observe(this.element, "click", this.elementClicked.bindEvent(this,options)); }, - onClick : function(event, options) + elementClicked : function(event, options) { var src = Event.element(event); var doPostBack = true; @@ -4493,15 +4303,33 @@ Object.extend(Prado.WebUI.TImageButton.prototype, */ addXYInput : function(event,options) { - var imagePos = Position.cumulativeOffset(this.element); - var clickedPos = [event.clientX, event.clientY]; - var x = clickedPos[0]-imagePos[0]+1; - var y = clickedPos[1]-imagePos[1]+1; - var id = options['EventTarget']; - var x_input = INPUT({type:'hidden',name:id+'_x',value:x}); - var y_input = INPUT({type:'hidden',name:id+'_y',value:y}); - this.element.parentNode.appendChild(x_input); - this.element.parentNode.appendChild(y_input); + 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); + } } }); @@ -4516,8 +4344,11 @@ Object.extend(Prado.WebUI.TRadioButton.prototype, initialize : function(options) { this.element = $(options['ID']); - if(!this.element.checked) - this.onRadioButtonInitialize(options); + if(this.element) + { + if(!this.element.checked) + this.onRadioButtonInitialize(options); + } } }); @@ -4526,9 +4357,11 @@ 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)); - Event.observe(this.element, "change", Prado.PostBack.bindEvent(this,options)); + if(this.options['AutoPostBack']==true) + Event.observe(this.element, "change", Prado.PostBack.bindEvent(this,options)); }, handleReturnKey : function(e) @@ -4538,8 +4371,19 @@ Prado.WebUI.TTextBox = Class.extend(Prado.WebUI.PostBackControl, var target = Event.element(e); if(target) { - Event.fireEvent(target, "change"); - Event.stop(e); + 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); + } + } } } } @@ -4630,66 +4474,37 @@ Object.extend(Prado.WebUI.TTextHighlighter, obj.parentNode.className = "copycode"; } }); - - -Prado.WebUI.TRatingList = Class.create(); -Prado.WebUI.TRatingList.prototype = -{ - selectedIndex : -1, - initialize : function(options) + +Prado.WebUI.TCheckBoxList = Base.extend( +{ + constructor : 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 -1 ? - this.radios[index].value : this.options.caption; + for(var i = 0; inew Prado.AutoCompleter('textboxID', 'updateDivID', {callbackID : '...'}); - */ -Prado.AutoCompleter.prototype = Object.extend(new Autocompleter.Base(), -{ - /** - * This component is initialized by - * new Prado.AutoCompleter(...) - * @param string the ID of the textbox element to observe - * @param string the ID of the div to display the auto-complete options - * @param array a hash of options, e.g. auto-completion token separator. - */ - initialize : function(element, update, options) - { - this.baseInitialize(element, update, options); - }, - - /** - * The callback function, i.e., function called on successful AJAX return. - * Calls update choices in the Autocompleter. - * @param string new auto-complete options for display - */ - onUpdateReturn : function(result) - { - if(isString(result) && result.length > 0) - this.updateChoices(result); - }, - - /** - * Requesting new choices using Prado's client-side callback scheme. - */ - getUpdatedChoices : function() - { - Prado.Callback(this.element.id, this.getToken(), this.onUpdateReturn.bind(this)); - } -}); - -/** - * Prado TActivePanel client javascript. Usage - * - * Prado.ActivePanel.register("id", options); - * Prado.ActivePanel.update("id", "hello"); - * - */ -Prado.ActivePanel = -{ - callbacks : {}, - - register : function(id, options) - { - Prado.ActivePanel.callbacks[id] = options; - }, - - update : function(id, param) - { - var request = new Prado.ActivePanel.Request(id, - Prado.ActivePanel.callbacks[id]); - request.callback(param); - } -} - -/** - * Client-script for TActivePanel. Uses Callback to notify the server - * for updates, if update option is set, the innerHTML of the update ID - * is set to the returned output. - */ -Prado.ActivePanel.Request = Class.create(); -Prado.ActivePanel.Request.prototype = -{ - initialize : function(element, options) - { - this.element = element; - this.setOptions(options); - }, - - /** - * Set some options. - */ - setOptions : function(options) - { - this.options = - { - onSuccess : this.onSuccess.bind(this) - } - Object.extend(this.options, options || {}); - }, - - /** - * Make the callback request - */ - callback : function(param) - { - this.options.params = [param]; - new Prado.AJAX.Callback(this.element, this.options); - }, - - /** - * Callback onSuccess handler, update the element innerHTML if necessary - */ - onSuccess : function(result, output) - { - if(this.options.update) - { - if (!this.options.evalScripts) - output = output.stripScripts(); - Element.update(this.options.update, output); - } - } -} - -/** - * Drop container to accept draggable component drops. - */ -Prado.DropContainer = Class.create(); -Prado.DropContainer.prototype = Object.extend(new Prado.ActivePanel.Request(), -{ - initialize : function(element, options) - { - this.element = element; - this.setOptions(options); - Object.extend(this.options, - { - onDrop : this.onDrop.bind(this), - evalScripts : true, - onSuccess : options.onSuccess || this.onSuccess.bind(this) - }); - Droppables.add(element, this.options); - }, - - onDrop : function(draggable, droppable) - { - this.callback(draggable.id) - } -}); - -Prado.ActiveImageButton = Class.create(); -Prado.ActiveImageButton.prototype = -{ - initialize : function(element, options) - { - this.element = $(element); - this.options = options; - Event.observe(this.element, "click", this.click.bind(this)); - }, - - click : function(e) - { - var el = $('{$this->ClientID}'); - var imagePos = Position.cumulativeOffset(this.element); - var clickedPos = [e.clientX, e.clientY]; - var param = (clickedPos[0]-imagePos[0]+1)+","+(clickedPos[1]-imagePos[1]+1); - Prado.Callback(this.element, param, null, this.options); - Event.stop(e); - } -} - - diff --git a/framework/Web/Javascripts/prado/ajax.js b/framework/Web/Javascripts/prado/ajax.js deleted file mode 100644 index 4f1c1ec9..00000000 --- a/framework/Web/Javascripts/prado/ajax.js +++ /dev/null @@ -1,427 +0,0 @@ -/** - * Prado AJAX service. The default service provider is JPSpan. - */ -Prado.AJAX = { Service : 'Prototype' }; - -/** - * Parse and execute javascript embedded in html. - */ -Prado.AJAX.EvalScript = function(output) -{ - - var match = new RegExp(Ajax.Updater.ScriptFragment, 'img'); - var scripts = output.match(match); - if (scripts) - { - match = new RegExp(Ajax.Updater.ScriptFragment, 'im'); - setTimeout((function() - { - for (var i = 0; i < scripts.length; i++) - eval(scripts[i].match(match)[1]); - }).bind(this), 50); - } -} - - -/** - * AJAX service request using Prototype's AJAX request class. - */ -Prado.AJAX.Request = Class.create(); -Prado.AJAX.Request.prototype = Object.extend(Ajax.Request.prototype, -{ - /** - * Evaluate the respond JSON data, override parent implementing. - * If default eval fails, try parsing the JSON data (slower). - */ - evalJSON: function() - { - try - { - var json = this.transport.getResponseHeader('X-JSON'), object; - object = eval(json); - return object; - } - catch (e) - { - if(isString(json)) - { - return Prado.AJAX.JSON.parse(json); - } - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - - if(event == 'Complete' && transport.status) - Ajax.Responders.dispatch('on' + transport.status, this, transport, json); - - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - - if (event == 'Complete') - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - } - -}); - -Prado.AJAX.Error = function(e, code) -{ - e.name = 'Prado.AJAX.Error'; - e.code = code; - return e; -} - -/** - * Post data builder, serialize the data using JSON. - */ -Prado.AJAX.RequestBuilder = Class.create(); -Prado.AJAX.RequestBuilder.prototype = -{ - initialize : function() - { - this.body = ''; - this.data = []; - }, - encode : function(data) - { - return Prado.AJAX.JSON.stringify(data); - }, - build : function(data) - { - var sep = ''; - for ( var argName in data) - { - if(isFunction(data[argName])) continue; - try - { - this.body += sep + argName + '='; - this.body += encodeURIComponent(this.encode(data[argName])); - } catch (e) { - throw Prado.AJAX.Error(e, 1006); - } - sep = '&'; - } - }, - - getAll : function() - { - this.build(this.data); - return this.body; - } -} - - -Prado.AJAX.RemoteObject = function(){}; - -/** - * AJAX service request for Prado RemoteObjects - */ -Prado.AJAX.RemoteObject.Request = Class.create(); -Prado.AJAX.RemoteObject.Request.prototype = Object.extend(Prado.AJAX.Request.prototype, -{ - /** - * Initialize the RemoteObject Request, overrides parent - * implementation by delaying the request to invokeRemoteObject. - */ - initialize : function(options) - { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.post = new Prado.AJAX.RequestBuilder(); - }, - - /** - * Call the remote object, - * @param string the remote server url - * @param array additional arguments - */ - invokeRemoteObject : function(url, args) - { - this.initParameters(args); - this.options.postBody = this.post.getAll(); - this.request(url); - }, - - /** - * Set the additional arguments as post data with key '__parameters' - */ - initParameters : function(args) - { - this.post.data['__parameters'] = []; - for(var i = 0; i - * var TestObject1 = Class.create(); - * TestObject1.prototype = Object.extend(new Prado.AJAX.RemoteObject(), - * { - * initialize : function(handlers, options) - * { - * this.__serverurl = 'http://127.0.0.1/.....'; - * this.baseInitialize(handlers, options); - * } - * - * method1 : function() - * { - * return this.__call(this.__serverurl, 'method1', arguments); - * } - * }); - * - * And client usage, - * - * var test1 = new TestObject1(); //create new remote object - * test1.method1(); //call the method, no onComplete hook - * - * var onComplete = { method1 : function(result){ alert(result) } }; - * //create new remote object with onComplete callback - * var test2 = new TestObject1(onComplete); - * test2.method1(); //call it, on success, onComplete's method1 is called. - * - */ -Prado.AJAX.RemoteObject.prototype = -{ - baseInitialize : function(handlers, options) - { - this.__handlers = handlers || {}; - this.__service = new Prado.AJAX.RemoteObject.Request(options); - }, - - __call : function(url, method, args) - { - this.__service.options.onSuccess = this.__onSuccess.bind(this); - this.__callback = method; - return this.__service.invokeRemoteObject(url+"/"+method, args); - }, - - __onSuccess : function(transport, json) - { - if(this.__handlers[this.__callback]) - this.__handlers[this.__callback](json, transport.responseText); - } -}; - -/** - * Respond to Prado AJAX request exceptions. - */ -Prado.AJAX.Exception = -{ - /** - * Server returns 505 exception. Just log it. - */ - "on505" : function(request, transport, e) - { - var msg = 'HTTP '+transport.status+" with response"; - Logger.error(msg, transport.responseText); - Logger.exception(e); - }, - - onComplete : function(request, transport, e) - { - if(transport.status != 505) - { - var msg = 'HTTP '+transport.status+" with response : \n"; - msg += transport.responseText + "\n"; - msg += "Data : \n"+inspect(e); - Logger.warn(msg); - } - }, - - format : function(e) - { - var msg = e.type + " with message \""+e.message+"\""; - msg += " in "+e.file+"("+e.line+")\n"; - msg += "Stack trace:\n"; - var trace = e.trace; - for(var i = 0; i"+trace[i]["function"]+"()"+"\n"; - } - return msg; - }, - - logException : function(e) - { - var msg = Prado.AJAX.Exception.format(e); - Logger.error("Server Error "+e.code, msg); - } -} - -//Add HTTP exception respones when logger is enabled. -Event.OnLoad(function() -{ - if(typeof Logger != "undefined") - { - Logger.exception = Prado.AJAX.Exception.logException; - Ajax.Responders.register(Prado.AJAX.Exception); - } -}); - -/** - * Prado Callback service that provides component intergration, - * viewstate (read only), and automatic form data serialization. - * Usage: new Prado.AJAX.Callback('MyPage.MyComponentID.raiseCallbackEvent', options) - * These classes should be called by the components developers. - * For inline callback service, use Prado.Callback(callbackID, params). - */ -Prado.AJAX.Callback = Class.create(); -Prado.AJAX.Callback.prototype = Object.extend(new Prado.AJAX.RemoteObject(), -{ - - /** - * Create and request a new Prado callback service. - * @param string|element the callback ID, must be of the form, ClassName.ComponentID.MethodName - * @param list options with list key onCallbackReturn, and more. - * - */ - initialize : function(ID, options) - { - if(!isString(ID) && typeof(ID.id) != "undefined") - ID = ID.id; - if(!isString(ID)) - throw new Error('A Control ID must be specified'); - this.baseInitialize(this, options); - this.options = options || []; - this.__service.post.data['__ID'] = ID; - this.requestCallback(); - }, - - /** - * Get form data for components that implements IPostBackHandler. - */ - collectPostData : function() - { - var IDs = Prado.AJAX.Callback.IDs; - this.__service.post.data['__data'] = {}; - for(var i = 0; i -1) - this.__service.post.data['__data'][id] = - this.collectArrayPostData(id); - else if(isObject($(id))) - this.__service.post.data['__data'][id] = $F(id); - } - }, - - collectArrayPostData : function(name) - { - var elements = document.getElementsByName(name); - var data = []; - $A(elements).each(function(el) - { - if($F(el)) data.push($F(el)); - }); - return data; - }, - - /** - * Prepares and calls the AJAX request. - * Collects the data from components that implements IPostBackHandler - * and the viewstate as part of the request payload. - */ - requestCallback : function() - { - this.collectPostData(); - if(Prado.AJAX.Validate(this.options)) - return this.__call(Prado.AJAX.Callback.Server, 'handleCallback', this.options.params); - }, - - /** - * On callback request return, call the onSuccess function. - */ - handleCallback : function(result, output) - { - if(typeof(result) != "undefined" && !isNull(result)) - { - this.options.onSuccess(result['data'], output); - if(result['actions']) - result.actions.each(Prado.AJAX.Callback.Action.__run); - } - } -}); - -/** - * Prase and evaluate Callback clien-side actions. - */ -Prado.AJAX.Callback.Action = -{ - __run : function(command) - { - for(var name in command) - { - //first parameter must be a valid element or begins with '@' - if(command[name][0] && ($(command[name][0]) || command[name][0].indexOf("[]") > -1)) - { - name.toFunction().apply(this,command[name]); - } - } - } -}; - - -/** - * Returns false if validation required and validates to false, - * returns true otherwise. - * @return boolean true if validation passes. - */ -Prado.AJAX.Validate = function(options) -{ - if(options.CausesValidation) - { - if(options.ValidatorGroup) - return Prado.Validation.ValidateValidatorGroup(options.ValidatorGroup); - else if(options.ValidationGroup) - return Prado.Validation.ValidateValidationGroup(options.ValidationGroup); - else - return Prado.Validation.ValidateNonGroup(options.ValidationForm); - } - else - return true; -}; - - -//Available callback service -Prado.AJAX.Callback.Server = ''; - -//List of IDs that implements IPostBackHandler -Prado.AJAX.Callback.IDs = []; - -/** - * Simple AJAX callback interface, suitable for inline javascript. - * e.g., Click me - * @param {String} callback ID - * @param {Array} parameters to pass to the callback service - * @param {Function} on callback success handler method - * @param {Object} additional callback options - */ -Prado.Callback = function(ID, params, onSuccess, options) -{ - var callback = - { - 'params' : [params] || [], - 'onSuccess' : onSuccess || Prototype.emptyFunction, - 'CausesValidation' : true - }; - - Object.extend(callback, options || {}); - - new Prado.AJAX.Callback(ID, callback); - return false; -} \ No newline at end of file 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..acf5531c --- /dev/null +++ b/framework/Web/Javascripts/prado/colorpicker/colorpicker.js @@ -0,0 +1,532 @@ +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 dac934f6..00000000 --- a/framework/Web/Javascripts/prado/controls.js +++ /dev/null @@ -1,253 +0,0 @@ -Prado.WebUI = Class.create(); - -//base postback-able controls -/*Prado.WebUI.PostBackControl = Class.create(); -Prado.WebUI.PostBackControl.prototype = -{ - initialize : function(options) - { - this.element = $(options['ID']); - -/* if(options.CausesValidation && typeof(Prado.Validation) != 'undefined') - { - Prado.Validation.registerTarget(options); - } - - //TODO: what do the following options do? - //options['PostBackUrl'] - //options['ClientSubmit'] - - if(this.onInit) - this.onInit(options); - } -}; - -//short cut to create postback components -Prado.WebUI.createPostBackComponent = function(definition) -{ - var component = Class.create(); - Object.extend(component.prototype, Prado.WebUI.PostBackControl.prototype); - if(definition) Object.extend(component.prototype, definition); - return component; -} - -Prado.WebUI.TButton = Prado.WebUI.createPostBackComponent(); -*/ -Prado.WebUI.PostBackControl = Class.create(); - -Prado.WebUI.PostBackControl.prototype = -{ - _elementOnClick : null, //capture the element's onclick function - - initialize : function(options) - { - this.element = $(options.ID); - 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.onClick.bindEvent(this,options)); - }, - - onClick : 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) - { - var imagePos = Position.cumulativeOffset(this.element); - var clickedPos = [event.clientX, event.clientY]; - var x = clickedPos[0]-imagePos[0]+1; - var y = clickedPos[1]-imagePos[1]+1; - var id = options['EventTarget']; - var x_input = INPUT({type:'hidden',name:id+'_x',value:x}); - var y_input = INPUT({type:'hidden',name:id+'_y',value:y}); - this.element.parentNode.appendChild(x_input); - 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.checked) - this.onRadioButtonInitialize(options); - } -}); - - -Prado.WebUI.TTextBox = Class.extend(Prado.WebUI.PostBackControl, -{ - onInit : function(options) - { - if(options['TextMode'] != 'MultiLine') - Event.observe(this.element, "keydown", this.handleReturnKey.bind(this)); - 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) - { - Event.fireEvent(target, "change"); - 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"; - } -}); diff --git a/framework/Web/Javascripts/prado/controls/controls.js b/framework/Web/Javascripts/prado/controls/controls.js new file mode 100644 index 00000000..64fb1a30 --- /dev/null +++ b/framework/Web/Javascripts/prado/controls/controls.js @@ -0,0 +1,290 @@ +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 40) return true; + + var current = this.selectedDate; + var d = current.valueOf(); + if(kc == Event.KEY_LEFT) + { + if(ev.ctrlKey || ev.shiftKey) // -1 month + { + current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() - 1,current.getFullYear())) ); // no need to catch dec -> jan for the year + d = current.setMonth( current.getMonth() - 1 ); + } + else + d -= 86400000; //-1 day + } + else if (kc == Event.KEY_RIGHT) + { + if(ev.ctrlKey || ev.shiftKey) // +1 month + { + current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() + 1,current.getFullYear())) ); // no need to catch dec -> jan for the year + d = current.setMonth( current.getMonth() + 1 ); + } + else + d += 86400000; //+1 day + } + else if (kc == Event.KEY_UP) + { + if(ev.ctrlKey || ev.shiftKey) //-1 year + { + current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() - 1)) ); // no need to catch dec -> jan for the year + d = current.setFullYear( current.getFullYear() - 1 ); + } + else + d -= 604800000; // -7 days + } + else if (kc == Event.KEY_DOWN) + { + if(ev.ctrlKey || ev.shiftKey) // +1 year + { + current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() + 1)) ); // no need to catch dec -> jan for the year + d = current.setFullYear( current.getFullYear() + 1 ); + } + else + d += 7 * 24 * 61 * 60 * 1000; // +7 days + } + this.setSelectedDate(d); + Event.stop(ev); + }, + + selectDate : function(ev) + { + var el = Event.element(ev); + while (el.nodeType != 1) + el = el.parentNode; + + while (el != null && el.tagName && el.tagName.toLowerCase() != "td") + el = el.parentNode; + + // if no td found, return + if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td") + return; + + var d = this.newDate(this.selectedDate); + var n = Number(el.firstChild.data); + if (isNaN(n) || n <= 0 || n == null) + return; + + d.setDate(n); + this.setSelectedDate(d); + this.hide(); + }, + + selectToday : function() + { + if(this.selectedDate.toISODate() == this.newDate().toISODate()) + this.hide(); + + this.setSelectedDate(this.newDate()); + }, + + clearSelection : function() + { + this.setSelectedDate(this.newDate()); + this.hide(); + }, + + monthSelect : function(ev) + { + this.setMonth(Form.Element.getValue(Event.element(ev))); + }, + + yearSelect : function(ev) + { + this.setYear(Form.Element.getValue(Event.element(ev))); + }, + + // ie6 extension + mouseWheelChange : function (e) + { + if (e == null) e = document.parentWindow.event; + var n = - e.wheelDelta / 120; + var d = this.newDate(this.selectedDate); + var m = d.getMonth() + n; + this.setMonth(m); + + return false; + }, + + onChange : function() + { + if(this.options.InputMode == "TextBox") + { + this.control.value = this.formatDate(); + Event.fireEvent(this.control, "change"); + } + else + { + var day = Prado.WebUI.TDatePicker.getDayListControl(this.control); + var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control); + var year = Prado.WebUI.TDatePicker.getYearListControl(this.control); + var date = this.selectedDate; + if(day) + { + day.selectedIndex = date.getDate()-1; + } + if(month) + { + month.selectedIndex = date.getMonth(); + } + if(year) + { + var years = year.options; + var currentYear = date.getFullYear(); + for(var i = 0; i < years.length; i++) + years[i].selected = years[i].value.toInteger() == currentYear; + } + Event.fireEvent(day || month || year, "change"); + } + }, + + formatDate : function() + { + return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format,this) : ''; + }, + + newDate : function(date) + { + if(!date) + date = new Date(); + if(typeof(date) == "string" || typeof(date) == "number") + date = new Date(date); + return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0); + }, + + setSelectedDate : function(date) + { + if (date == null) + return; + this.selectedDate = this.newDate(date); + + this.updateHeader(); + this.update(); + if (typeof(this.onChange) == "function") + this.onChange(this, date); + }, + + getElement : function() + { + return this._calDiv; + }, + + getSelectedDate : function () + { + return this.selectedDate == null ? null : this.newDate(this.selectedDate); + }, + + setYear : function(year) + { + var d = this.newDate(this.selectedDate); + d.setFullYear(year); + this.setSelectedDate(d); + }, + + setMonth : function (month) + { + var d = this.newDate(this.selectedDate); + d.setMonth(month); + this.setSelectedDate(d); + }, + + nextMonth : function () + { + this.setMonth(this.selectedDate.getMonth()+1); + }, + + prevMonth : function () + { + this.setMonth(this.selectedDate.getMonth()-1); + }, + + getDatePickerOffsetHeight : function() + { + if(this.options.InputMode == "TextBox") + return this.control.offsetHeight; + + var control = Prado.WebUI.TDatePicker.getDayListControl(this.control); + if(control) return control.offsetHeight; + + var control = Prado.WebUI.TDatePicker.getMonthListControl(this.control); + if(control) return control.offsetHeight; + + var control = Prado.WebUI.TDatePicker.getYearListControl(this.control); + if(control) return control.offsetHeight; + return 0; + }, + + show : function() + { + this.create(); + + if(!this.showing) + { + var pos = Position.positionedOffset(this.control); + + pos[1] += this.getDatePickerOffsetHeight(); + + this._calDiv.style.display = "block"; + this._calDiv.style.top = (pos[1]-1) + "px"; + this._calDiv.style.left = pos[0] + "px"; + + this.ieHack(false); + this.documentClickEvent = this.hideOnClick.bindEvent(this); + this.documentKeyDownEvent = this.keyPressed.bindEvent(this); + Event.observe(document.body, "click", this.documentClickEvent); + var date = this.getDateFromInput(); + if(date) + { + this.selectedDate = date; + this.setSelectedDate(date); + } + Event.observe(document,"keydown", this.documentKeyDownEvent); + this.showing = true; + } + }, + + getDateFromInput : function() + { + if(this.options.InputMode == "TextBox") + return Date.SimpleParse($F(this.control), this.Format); + else + return Prado.WebUI.TDatePicker.getDropDownDate(this.control); + }, + + //hide the calendar when clicked outside any calendar + hideOnClick : function(ev) + { + if(!this.showing) return; + var el = Event.element(ev); + var within = false; + do + { + within = within || (el.className && Element.hasClassName(el, "TDatePicker_"+this.CalendarStyle)); + within = within || el == this.trigger; + within = within || el == this.control; + if(within) break; + el = el.parentNode; + } + while(el); + if(!within) this.hide(); + }, + + + hide : function() + { + if(this.showing) + { + this._calDiv.style.display = "none"; + if(this.iePopUp) + this.iePopUp.style.display = "none"; + this.showing = false; + Event.stopObserving(document.body, "click", this.documentClickEvent); + Event.stopObserving(document,"keydown", this.documentKeyDownEvent); + } + }, + + update : function() + { + // Calculate the number of days in the month for the selected date + var date = this.selectedDate; + var today = (this.newDate()).toISODate(); + + var selected = date.toISODate(); + var d1 = new Date(date.getFullYear(), date.getMonth(), 1); + var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1); + var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000)); + + // Find out the weekDay index for the first of this month + var firstIndex = (d1.getDay() - this.FirstDayOfWeek) % 7 ; + if (firstIndex < 0) + firstIndex += 7; + + var index = 0; + while (index < firstIndex) { + this.dateSlot[index].value = -1; + this.dateSlot[index].data.data = String.fromCharCode(160); + this.dateSlot[index].data.parentNode.className = "empty"; + index++; + } + + for (i = 1; i <= monthLength; i++, index++) { + var slot = this.dateSlot[index]; + var slotNode = slot.data.parentNode; + slot.value = i; + slot.data.data = i; + slotNode.className = "date"; + //slotNode.style.color = ""; + if (d1.toISODate() == today) { + slotNode.className += " today"; + } + if (d1.toISODate() == selected) { + // slotNode.style.color = "blue"; + slotNode.className += " selected"; + } + d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1); + } + + var lastDateIndex = index; + + while(index < 42) { + this.dateSlot[index].value = -1; + this.dateSlot[index].data.data = String.fromCharCode(160); + this.dateSlot[index].data.parentNode.className = "empty"; + ++index; + } + + }, + + hover : function(ev) + { + if(Event.element(ev).tagName) + { + if(ev.type == "mouseover") + Event.element(ev).addClassName("hover"); + else + Event.element(ev).removeClassName("hover"); + } + }, + + updateHeader : function () { + + var options = this._monthSelect.options; + var m = this.selectedDate.getMonth(); + for(var i=0; i < options.length; ++i) { + options[i].selected = false; + if (options[i].value == m) { + options[i].selected = true; + } + } + + options = this._yearSelect.options; + var year = this.selectedDate.getFullYear(); + for(var i=0; i < options.length; ++i) { + options[i].selected = false; + if (options[i].value == year) { + options[i].selected = true; + } + } + + } + + +}; \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/datepicker/default.css b/framework/Web/Javascripts/prado/datepicker/default.css new file mode 100644 index 00000000..9532dad0 --- /dev/null +++ b/framework/Web/Javascripts/prado/datepicker/default.css @@ -0,0 +1,98 @@ +.TDatePicker_default +{ + border: 1px solid #919EA9; + background-color: White; + text-align: center; + font-size: 11px; + font-family: Tahoma, Arial, Helvetica, sans-serif; + cursor: default; +} + +.TDatePickerButton +{ + width: 30px; +} + +.TDatePickerImageButton +{ + padding: 2px; + border: 1px solid #919EA9; + vertical-align: top; + margin-left: 1px; +} + + +.TDatePickerImageButton:hover +{ + border-color: #ddd; +} + +.TDatePicker_default select +{ + font-size: 11px; +} + +.TDatePicker_default input.button +{ + font-size: 11px; + width: 32px; +} + +.TDatePicker_default .date +{ + padding: 4px 0; + border: 1px solid white; + text-align: center; +} +.TDatePicker_default .hover +{ + border: 1px solid blue; +} +.TDatePicker_default .selected +{ + background-color: blue; + border: 1px solid blue; + color: white; +} +.TDatePicker_default .today +{ + font-weight: bold; +} + +.TDatePicker_default td.empty +{ + border: 1px solid white; + cursor: default; + height: 22px; +} + +.TDatePicker_default th +{ + width: 28px; +} + +.TDatePicker_default .calendarBody +{ + text-align: center; + width: 210px; + margin: 3px 6px; +} + +.TDatePicker_default .grid +{ + border-spacing: 0px; +} + +.TDatePicker_default .calendarFooter +{ + margin: 2px; + border-top: 1px solid #919EA9; + padding-top: 2px; +} +.TDatePicker_default .todayButton +{ + font-size: 11px; + margin: 4px; + padding-left: 1em; + padding-right: 1em; +} \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/datepicker/spacer.gif b/framework/Web/Javascripts/prado/datepicker/spacer.gif new file mode 100755 index 00000000..fc256098 Binary files /dev/null and b/framework/Web/Javascripts/prado/datepicker/spacer.gif differ diff --git a/framework/Web/Javascripts/prado/element.js b/framework/Web/Javascripts/prado/element.js deleted file mode 100644 index 0d9c74d1..00000000 --- a/framework/Web/Javascripts/prado/element.js +++ /dev/null @@ -1,163 +0,0 @@ -Prado.Element = -{ - /** - * Set the value of a particular element. - * @param string element id - * @param string new element value. - */ - setValue : function(element, value) - { - var el = $(element); - if(el && typeof(el.value) != "undefined") - el.value = value; - }, - - select : function(element, method, value) - { - var el = $(element); - var isList = element.indexOf('[]') > -1; - if(!el && !isList) return; - method = isList ? 'check'+method : el.tagName.toLowerCase()+method; - var selection = Prado.Element.Selection; - if(isFunction(selection[method])) - selection[method](isList ? element : el,value); - }, - - click : function(element) - { - var el = $(element); - if(el) - Event.fireEvent(el,'click'); - }, - - setAttribute : function(element, attribute, value) - { - var el = $(element); - if(attribute == "disabled" && value==false) - el.removeAttribute(attribute); - else - el.setAttribute(attribute, value); - }, - - setOptions : function(element, options) - { - var el = $(element); - if(el && el.tagName.toLowerCase() == "select") - { - while(el.length > 0) - el.remove(0); - for(var i = 0; i 0) - form.action = options['PostBackUrl']; - - 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']; - } - } - - $('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"); -} - -/* - -Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidation, validationGroup, actionUrl, trackFocus, clientSubmit) -{ - if (typeof(performValidation) == 'undefined') - { - var performValidation = false; - var validationGroup = ''; - var actionUrl = null; - var trackFocus = false; - var clientSubmit = true; - } - var theForm = document.getElementById ? document.getElementById(formID) : document.forms[formID]; - var canSubmit = true; - if (performValidation) - { - //canSubmit = Prado.Validation.validate(validationGroup); - * Prado.Validation.ActiveTarget = theForm; - Prado.Validation.CurrentTargetGroup = null; - Prado.Validation.IsGroupValidation = false; - canSubmit = Prado.Validation.IsValid(theForm); - Logger.debug(canSubmit);* - canSubmit = Prado.Validation.IsValid(theForm); - } - if (canSubmit) - { - if (actionUrl != null && (actionUrl.length > 0)) - { - theForm.action = actionUrl; - } - if (trackFocus) - { - var lastFocus = theForm.elements['PRADO_LASTFOCUS']; - if ((typeof(lastFocus) != 'undefined') && (lastFocus != null)) - { - var active = document.activeElement; - if (typeof(active) == 'undefined') - { - lastFocus.value = eventTarget; - } - else - { - if ((active != null) && (typeof(active.id) != 'undefined')) - { - if (active.id.length > 0) - { - lastFocus.value = active.id; - } - else if (typeof(active.name) != 'undefined') - { - lastFocus.value = active.name; - } - } - } - } - } - if (!clientSubmit) - { - canSubmit = false; - } - } - if (canSubmit && (!theForm.onsubmit || theForm.onsubmit())) - { - theForm.PRADO_POSTBACK_TARGET.value = eventTarget; - theForm.PRADO_POSTBACK_PARAMETER.value = eventParameter; - theForm.submit(); - } -} -*/ \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/logger/logger.js b/framework/Web/Javascripts/prado/logger/logger.js new file mode 100644 index 00000000..b21df1ae --- /dev/null +++ b/framework/Web/Javascripts/prado/logger/logger.js @@ -0,0 +1,753 @@ +/* + +Created By: Corey Johnson +E-mail: probablyCorey@gmail.com + +Requires: Prototype Javascript library (http://prototype.conio.net/) + +Use it all you want. Just remember to give me some credit :) + +*/ + +// ------------ +// Custom Event +// ------------ + +CustomEvent = Class.create() +CustomEvent.prototype = { + initialize : function() { + this.listeners = [] + }, + + addListener : function(method) { + this.listeners.push(method) + }, + + removeListener : function(method) { + var foundIndexes = this._findListenerIndexes(method) + + for(var i = 0; i < foundIndexes.length; i++) { + this.listeners.splice(foundIndexes[i], 1) + } + }, + + dispatch : function(handler) { + for(var i = 0; i < this.listeners.length; i++) { + try { + this.listeners[i](handler) + } + catch (e) { + alert("Could not run the listener " + this.listeners[i] + ". " + e) + } + } + }, + + // Private Methods + // --------------- + _findListenerIndexes : function(method) { + var indexes = [] + for(var i = 0; i < this.listeners.length; i++) { + if (this.listeners[i] == method) { + indexes.push(i) + } + } + + return indexes + } +} + +// ------ +// Cookie +// ------ + +var Cookie = { + set : function(name, value, expirationInDays, path) { + var cookie = escape(name) + "=" + escape(value) + + if (expirationInDays) { + var date = new Date() + date.setDate(date.getDate() + expirationInDays) + cookie += "; expires=" + date.toGMTString() + } + + if (path) { + cookie += ";path=" + path + } + + document.cookie = cookie + + if (value && (expirationInDays == undefined || expirationInDays > 0) && !this.get(name)) { + Logger.error("Cookie (" + name + ") was not set correctly... The value was " + value.toString().length + " charachters long (This may be over the cookie limit)"); + } + }, + + get : function(name) { + var pattern = "(^|;)\\s*" + escape(name) + "=([^;]+)" + + var m = document.cookie.match(pattern) + if (m && m[2]) { + return unescape(m[2]) + } + else return null + }, + + getAll : function() { + var cookies = document.cookie.split(';') + var cookieArray = [] + + for (var i = 0; i < cookies.length; i++) { + try { + var name = unescape(cookies[i].match(/^\s*([^=]+)/m)[1]) + var value = unescape(cookies[i].match(/=(.*$)/m)[1]) + } + catch (e) { + continue + } + + cookieArray.push({name : name, value : value}) + + if (cookieArray[name] != undefined) { + Logger.waring("Trying to retrieve cookie named(" + name + "). There appears to be another property with this name though."); + } + + cookieArray[name] = value + } + + return cookieArray + }, + + clear : function(name) { + this.set(name, "", -1) + }, + + clearAll : function() { + var cookies = this.getAll() + + for(var i = 0; i < cookies.length; i++) { + this.clear(cookies[i].name) + } + + } +} + +// ------ +// Logger +// ----- + +Logger = { + logEntries : [], + + onupdate : new CustomEvent(), + onclear : new CustomEvent(), + + + // Logger output + log : function(message, tag) { + var logEntry = new LogEntry(message, tag || "info") + this.logEntries.push(logEntry) + this.onupdate.dispatch(logEntry) + }, + + info : function(message) { + this.log(message, 'info') + if(typeof(console) != "undefined") + console.info(message); + }, + + debug : function(message) { + this.log(message, 'debug') + if(typeof(console) != "undefined") + console.debug(message); + }, + + warn : function(message) { + this.log(message, 'warning') + if(typeof(console) != "undefined") + console.warn(message); + }, + + error : function(message, error) { + this.log(message + ": \n" + error, 'error') + if(typeof(console) != "undefined") + console.error(message); + + }, + + clear : function () { + this.logEntries = [] + this.onclear.dispatch() + } +} + +LogEntry = Class.create() +LogEntry.prototype = { + initialize : function(message, tag) { + this.message = message + this.tag = tag + } +} + +LogConsole = Class.create() +LogConsole.prototype = { + + // Properties + // ---------- + commandHistory : [], + commandIndex : 0, + + hidden : true, + + // Methods + // ------- + + initialize : function(toggleKey) { + this.outputCount = 0 + this.tagPattern = Cookie.get('tagPattern') || ".*" + + // I hate writing javascript in HTML... but what's a better alternative + this.logElement = document.createElement('div') + document.body.appendChild(this.logElement) + Element.hide(this.logElement) + + this.logElement.style.position = "absolute" + this.logElement.style.left = '0px' + this.logElement.style.width = '100%' + + this.logElement.style.textAlign = "left" + this.logElement.style.fontFamily = "lucida console" + this.logElement.style.fontSize = "100%" + this.logElement.style.backgroundColor = 'darkgray' + this.logElement.style.opacity = 0.9 + this.logElement.style.zIndex = 2000 + + // Add toolbarElement + this.toolbarElement = document.createElement('div') + this.logElement.appendChild(this.toolbarElement) + this.toolbarElement.style.padding = "0 0 0 2px" + + // Add buttons + this.buttonsContainerElement = document.createElement('span') + this.toolbarElement.appendChild(this.buttonsContainerElement) + + this.buttonsContainerElement.innerHTML += '' + this.buttonsContainerElement.innerHTML += '' + if(!Prado.Inspector.disabled) + this.buttonsContainerElement.innerHTML += '' + + + //Add Tag Filter + this.tagFilterContainerElement = document.createElement('span') + this.toolbarElement.appendChild(this.tagFilterContainerElement) + this.tagFilterContainerElement.style.cssFloat = 'left' + this.tagFilterContainerElement.appendChild(document.createTextNode("Log Filter")) + + this.tagFilterElement = document.createElement('input') + this.tagFilterContainerElement.appendChild(this.tagFilterElement) + this.tagFilterElement.style.width = '200px' + this.tagFilterElement.value = this.tagPattern + this.tagFilterElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out + + Event.observe(this.tagFilterElement, 'keyup', this.updateTags.bind(this)) + Event.observe(this.tagFilterElement, 'click', function() {this.tagFilterElement.select()}.bind(this)) + + // Add outputElement + this.outputElement = document.createElement('div') + this.logElement.appendChild(this.outputElement) + this.outputElement.style.overflow = "auto" + this.outputElement.style.clear = "both" + this.outputElement.style.height = "200px" + this.outputElement.style.backgroundColor = 'black' + + this.inputContainerElement = document.createElement('div') + this.inputContainerElement.style.width = "100%" + this.logElement.appendChild(this.inputContainerElement) + + this.inputElement = document.createElement('input') + this.inputContainerElement.appendChild(this.inputElement) + this.inputElement.style.width = '100%' + this.inputElement.style.borderWidth = '0px' // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0 + this.inputElement.style.margin = '0px' + this.inputElement.style.padding = '0px' + this.inputElement.value = 'Type command here' + this.inputElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out + + Event.observe(this.inputElement, 'keyup', this.handleInput.bind(this)) + Event.observe(this.inputElement, 'click', function() {this.inputElement.select()}.bind(this)) + + if(document.all && !window.opera) + { + window.setInterval(this.repositionWindow.bind(this), 500) + } + else + { + this.logElement.style.position="fixed"; + this.logElement.style.bottom="0px"; + } + var self=this; + Event.observe(document, 'keydown', function(e) + { + if((e.altKey==true) && Event.keyCode(e) == toggleKey ) //Alt+J | Ctrl+J + self.toggle(); + }); + + // Listen to the logger.... + Logger.onupdate.addListener(this.logUpdate.bind(this)) + Logger.onclear.addListener(this.clear.bind(this)) + + // Preload log element with the log entries that have been entered + for (var i = 0; i < Logger.logEntries.length; i++) { + this.logUpdate(Logger.logEntries[i]) + } + + // Feed all errors into the logger (For some unknown reason I can only get this to work + // with an inline event declaration) + Event.observe(window, 'error', function(msg, url, lineNumber) {Logger.error("Error in (" + (url || location) + ") on line "+lineNumber+"", msg)}) + + // Allow acess key link + var accessElement = document.createElement('span') + accessElement.innerHTML = '' + document.body.appendChild(accessElement) + + if (Cookie.get('ConsoleVisible') == 'true') { + this.toggle() + } + }, + + toggle : function() { + if (this.logElement.style.display == 'none') { + this.show() + } + else { + this.hide() + } + }, + + show : function() { + Element.show(this.logElement) + this.outputElement.scrollTop = this.outputElement.scrollHeight // Scroll to bottom when toggled + if(document.all && !window.opera) + this.repositionWindow(); + Cookie.set('ConsoleVisible', 'true') + this.inputElement.select() + this.hidden = false; + }, + + hide : function() { + this.hidden = true; + Element.hide(this.logElement) + Cookie.set('ConsoleVisible', 'false') + }, + + output : function(message, style) { + // If we are at the bottom of the window, then keep scrolling with the output + var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight + + this.outputCount++ + style = (style ? style += ';' : '') + style += 'padding:1px;margin:0 0 5px 0' + + if (this.outputCount % 2 == 0) style += ";background-color:#101010" + + message = message || "undefined" + message = message.toString().escapeHTML() + + this.outputElement.innerHTML += "
    " + 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-1){ + this.d.getElementById(spanID).innerHTML="[-]"; + } else { + this.d.getElementById(spanID).innerHTML="[+]"; + } + }, + + buildInspectionLevel : function() + { + var display = this.displaying; + var list = display.split("."); + var links = ["[object Window]"]; + var name = ''; + if(display.indexOf("[object ") >= 0) return links.join("."); + for(var i = 0; i < list.length; i++) + { + name += (name.length ? "." : "") + list[i]; + links[i+1] = ""+list[i]+""; + } + return links.join("."); + }, + + buildTree : function() { + mHTML = "
    Inspecting "+this.buildInspectionLevel()+"
    "; + mHTML +="
      "; + this.types.sort(); + var so_objIndex=0; + for(i=0;i[+]" + this.types[i] + " (" + this.nameList[this.types[i]].length + ")
        "; + this.hidden["ul"+i]=0; + for(e=0;e= 0 && /^[a-zA-Z_]/.test(prop)) + { + if(this.displaying.indexOf("[object ") < 0) + more = " more"; + else if(this.displaying.indexOf("[object Window]") >= 0) + more = " more"; + } + mHTML+="
      • [+]" + prop + "
        • " + value + more + "
        "; + this.hidden["mul"+so_objIndex]=0; + so_objIndex++; + } + mHTML+="
      "; + } + mHTML+="
    "; + 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 -1 ? + this.radios[index].value : this.options.caption; + } +} \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/ratings/stars1.png b/framework/Web/Javascripts/prado/ratings/stars1.png new file mode 100644 index 00000000..e4dd3c25 Binary files /dev/null and b/framework/Web/Javascripts/prado/ratings/stars1.png differ diff --git a/framework/Web/Javascripts/prado/scriptaculous-adapter.js b/framework/Web/Javascripts/prado/scriptaculous-adapter.js new file mode 100644 index 00000000..89e6710b --- /dev/null +++ b/framework/Web/Javascripts/prado/scriptaculous-adapter.js @@ -0,0 +1,811 @@ + +/** + * Similar to bindAsEventLister, but takes additional arguments. + */ +Function.prototype.bindEvent = function() +{ + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) + { + return __method.apply(object, [event || window.event].concat(args)); + } +} + +/** + * Creates a new function by copying function definition from + * the base and optional definition. + * @param function a base function to copy from. + * @param array additional definition + * @param function return a new function with definition from both + * base and definition. + */ +Class.extend = function(base, definition) +{ + var component = Class.create(); + Object.extend(component.prototype, base.prototype); + if(definition) + Object.extend(component.prototype, definition); + return component; +} + +/* + Base, version 1.0.2 + Copyright 2006, Dean Edwards + License: http://creativecommons.org/licenses/LGPL/2.1/ +*/ + +var Base = function() { + if (arguments.length) { + if (this == window) { // cast an object to this class + Base.prototype.extend.call(arguments[0], arguments.callee.prototype); + } else { + this.extend(arguments[0]); + } + } +}; + +Base.version = "1.0.2"; + +Base.prototype = { + extend: function(source, value) { + var extend = Base.prototype.extend; + if (arguments.length == 2) { + var ancestor = this[source]; + // overriding? + if ((ancestor instanceof Function) && (value instanceof Function) && + ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) { + var method = value; + // var _prototype = this.constructor.prototype; + // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor; + value = function() { + var previous = this.base; + // this.base = fromPrototype ? _prototype[source] : ancestor; + this.base = ancestor; + var returnValue = method.apply(this, arguments); + this.base = previous; + return returnValue; + }; + // point to the underlying method + value.valueOf = function() { + return method; + }; + value.toString = function() { + return String(method); + }; + } + return this[source] = value; + } else if (source) { + var _prototype = {toSource: null}; + // do the "toString" and other methods manually + var _protected = ["toString", "valueOf"]; + // if we are prototyping then include the constructor + if (Base._prototyping) _protected[2] = "constructor"; + for (var i = 0; (name = _protected[i]); i++) { + if (source[name] != _prototype[name]) { + extend.call(this, name, source[name]); + } + } + // copy each of the source object's properties to this object + for (var name in source) { + if (!_prototype[name]) { + extend.call(this, name, source[name]); + } + } + } + return this; + }, + + base: function() { + // call this method from any other method to invoke that method's ancestor + } +}; + +Base.extend = function(_instance, _static) { + var extend = Base.prototype.extend; + if (!_instance) _instance = {}; + // build the prototype + Base._prototyping = true; + var _prototype = new this; + extend.call(_prototype, _instance); + var constructor = _prototype.constructor; + _prototype.constructor = this; + delete Base._prototyping; + // create the wrapper for the constructor function + var klass = function() { + if (!Base._prototyping) constructor.apply(this, arguments); + this.constructor = klass; + }; + klass.prototype = _prototype; + // build the class interface + klass.extend = this.extend; + klass.implement = this.implement; + klass.toString = function() { + return String(constructor); + }; + extend.call(klass, _static); + // single instance + var object = constructor ? klass : _prototype; + // class initialisation + if (object.init instanceof Function) object.init(); + return object; +}; + +Base.implement = function(_interface) { + if (_interface instanceof Function) _interface = _interface.prototype; + this.prototype.extend(_interface); +}; + +/** + * Performs a post-back using javascript + * + */ +Prado.PostBack = function(event,options) +{ + var form = $(options['FormID']); + var canSubmit = true; + + if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined") + { + if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID']))) + return Event.stop(event); + } + + if(options['PostBackUrl'] && options['PostBackUrl'].length > 0) + form.action = options['PostBackUrl']; + + 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']; + } + } + + $('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"); +} + +/** + * Additional element utilities. + */ +Prado.Element = +{ + /** + * Set the value of a particular element. + * @param string element id + * @param string new element value. + */ + setValue : function(element, value) + { + var el = $(element); + if(el && typeof(el.value) != "undefined") + el.value = value; + }, + + select : function(element, method, value) + { + var el = $(element); + var isList = element.indexOf('[]') > -1; + if(!el && !isList) return; + method = isList ? 'check'+method : el.tagName.toLowerCase()+method; + var selection = Prado.Element.Selection; + if(isFunction(selection[method])) + selection[method](isList ? element : el,value); + }, + + click : function(element) + { + var el = $(element); + if(el) + Event.fireEvent(el,'click'); + }, + + setAttribute : function(element, attribute, value) + { + var el = $(element); + if(attribute == "disabled" && value==false) + el.removeAttribute(attribute); + else + el.setAttribute(attribute, value); + }, + + setOptions : function(element, options) + { + var el = $(element); + if(el && el.tagName.toLowerCase() == "select") + { + while(el.length > 0) + el.remove(0); + for(var i = 0; i1) + return Builder.node(tag,args.shift(),args); + + }; + }); + } +}); + +Builder.exportTags(); + +/** + * @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.lengthInternationalization + * is not supported + * @param {String} the decimal character + * @return {Double} null if string does not represent a float value + */ + toDouble : function(decimalchar) + { + if(this.length <= 0) return null; + decimalchar = decimalchar || "."; + var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$"); + var m = this.match(exp); + + if (m == null) + return null; + m[1] = m[1] || ""; + m[2] = m[2] || "0"; + m[4] = m[4] || "0"; + + var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4]; + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); + }, + + /** + * Convert strings that represent a currency value (e.g. a float with grouping + * characters) to float. E.g. "10,000.50" will become "10000.50". The number + * of dicimal digits, grouping and decimal characters can be specified. + * The currency input format is very strict, null will be returned if + * the pattern does not match. + * @param {String} the grouping character, default is "," + * @param {Number} number of decimal digits + * @param {String} the decimal character, default is "." + * @type {Double} the currency value as float. + */ + toCurrency : function(groupchar, digits, decimalchar) + { + groupchar = groupchar || ","; + decimalchar = decimalchar || "."; + digits = typeof(digits) == "undefined" ? 2 : digits; + + var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)" + + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "") + + "\\s*$"); + var m = this.match(exp); + if (m == null) + return null; + var intermed = m[2] + m[5] ; + var cleanInput = m[1] + intermed.replace( + new RegExp("(\\" + groupchar + ")", "g"), "") + + ((digits > 0) ? "." + m[7] : ""); + var num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); + }, + + /** + * Converts the string to a date by finding values that matches the + * date format pattern. + * @param string date format pattern, e.g. MM-dd-yyyy + * @return {Date} the date extracted from the string + */ + toDate : function(format) + { + return Date.SimpleParse(this, format); + } +}); + +/** + * @class Event extensions. + */ +Object.extend(Event, +{ + /** + * Register a function to be executed when the page is loaded. + * Note that the page is only loaded if all resources (e.g. images) + * are loaded. + * + * Example: Show an alert box with message "Page Loaded!" when the + * page finished loading. + * + * 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 714aa93f..00000000 --- a/framework/Web/Javascripts/prado/validation3.js +++ /dev/null @@ -1,1276 +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"); - } - }, - - /** - * 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 : "
    • ", post : "
    • ", last : "
    "}; - } - }, - - /** - * 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/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 : "
    • ", post : "
    • ", last : "
    "}; + } + }, + + /** + * 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 2bf2e904..00000000 --- a/framework/Web/Javascripts/ratings/blocks.css +++ /dev/null @@ -1,29 +0,0 @@ -.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/ratings/blocks.png b/framework/Web/Javascripts/ratings/blocks.png deleted file mode 100644 index 16a2b249..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 a68d0e94..00000000 Binary files a/framework/Web/Javascripts/ratings/blocks_blank.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 4cff0148..00000000 Binary files a/framework/Web/Javascripts/ratings/blocks_half.gif and /dev/null differ diff --git a/framework/Web/Javascripts/ratings/blocks_hover.gif b/framework/Web/Javascripts/ratings/blocks_hover.gif deleted file mode 100644 index 58ad7495..00000000 Binary files a/framework/Web/Javascripts/ratings/blocks_hover.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 f91873e2..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 c15a36bd..00000000 --- a/framework/Web/Javascripts/ratings/default.css +++ /dev/null @@ -1,29 +0,0 @@ -.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/ratings/default_blank.gif b/framework/Web/Javascripts/ratings/default_blank.gif deleted file mode 100644 index 4e6fda3c..00000000 Binary files a/framework/Web/Javascripts/ratings/default_blank.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 7cecf0ec..00000000 Binary files a/framework/Web/Javascripts/ratings/default_half.gif and /dev/null differ diff --git a/framework/Web/Javascripts/ratings/default_hover.gif b/framework/Web/Javascripts/ratings/default_hover.gif deleted file mode 100644 index ad0cd28a..00000000 Binary files a/framework/Web/Javascripts/ratings/default_hover.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 a19ab39f..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 e6fd97ba..00000000 --- a/framework/Web/Javascripts/ratings/ratings.js +++ /dev/null @@ -1,60 +0,0 @@ -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 -1 ? - this.radios[index].value : this.options.caption; - } -} \ No newline at end of file diff --git a/framework/Web/Javascripts/ratings/stars1.png b/framework/Web/Javascripts/ratings/stars1.png deleted file mode 100644 index e4dd3c25..00000000 Binary files a/framework/Web/Javascripts/ratings/stars1.png and /dev/null differ diff --git a/framework/Web/Javascripts/rico/colors.js b/framework/Web/Javascripts/rico/colors.js deleted file mode 100644 index ce72302e..00000000 --- a/framework/Web/Javascripts/rico/colors.js +++ /dev/null @@ -1,242 +0,0 @@ -//-------------------- 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 }; -} diff --git a/framework/Web/Javascripts/rico/extension.js b/framework/Web/Javascripts/rico/extension.js deleted file mode 100644 index d3df3a9b..00000000 --- a/framework/Web/Javascripts/rico/extension.js +++ /dev/null @@ -1,175 +0,0 @@ -Prado.RicoLiveGrid = Class.create(); -Prado.RicoLiveGrid.prototype = Object.extend(Rico.LiveGrid.prototype, -{ - initialize : function(tableId, options) - { - this.options = { - tableClass: $(tableId).className || '', - loadingClass: $(tableId).className || '', - scrollerBorderRight: '1px solid #ababab', - bufferTimeout: 20000, - sortAscendImg: 'images/sort_asc.gif', - sortDescendImg: 'images/sort_desc.gif', - sortImageWidth: 9, - sortImageHeight: 5, - ajaxSortURLParms: [], - onRefreshComplete: null, - requestParameters: null, - inlineStyles: true, - visibleRows: 10, - totalRows: 0, - initialOffset: 0 - }; - Object.extend(this.options, options || {}); - - //this.ajaxOptions = {parameters: null}; - //Object.extend(this.ajaxOptions, ajaxOptions || {}); - - this.tableId = tableId; - this.table = $(tableId); - - this.addLiveGridHtml(); - - var columnCount = this.table.rows[0].cells.length; - this.metaData = new Rico.LiveGridMetaData(this.options.visibleRows, this.options.totalRows, columnCount, options); - this.buffer = new Rico.LiveGridBuffer(this.metaData); - - var rowCount = this.table.rows.length; - this.viewPort = new Rico.GridViewPort(this.table, - this.table.offsetHeight/rowCount, - this.options.visibleRows, - this.buffer, this); - this.scroller = new Rico.LiveGridScroller(this,this.viewPort); - this.options.sortHandler = this.sortHandler.bind(this); - - if ( $(tableId + '_header') ) - this.sort = new Rico.LiveGridSort(tableId + '_header', this.options) - - this.processingRequest = null; - this.unprocessedRequest = null; - - //this.initAjax(url); - if (this.options.initialOffset >= 0) - { - var offset = this.options.initialOffset; - this.scroller.moveScroll(offset); - this.viewPort.scrollTo(this.scroller.rowToPixel(offset)); - if (this.options.sortCol) { - this.sortCol = options.sortCol; - this.sortDir = options.sortDir; - } - var grid = this; - setTimeout(function(){ - grid.requestContentRefresh(offset); - },100); - } - }, - - fetchBuffer: function(offset) - { - if ( this.buffer.isInRange(offset) && - !this.buffer.isNearingLimit(offset)) { - return; - } - if (this.processingRequest) { - this.unprocessedRequest = new Rico.LiveGridRequest(offset); - return; - } - var bufferStartPos = this.buffer.getFetchOffset(offset); - this.processingRequest = new Rico.LiveGridRequest(offset); - this.processingRequest.bufferOffset = bufferStartPos; - var fetchSize = this.buffer.getFetchSize(offset); - var partialLoaded = false; - - // var queryString - // if (this.options.requestParameters) - // queryString = this._createQueryString(this.options.requestParameters, 0); - var param = - { - 'page_size' : fetchSize, - 'offset' : bufferStartPos - }; - if(this.sortCol) - { - Object.extend(param, - { - 'sort_col': this.sortCol, - 'sort_dir': this.sortDir - }); - } - /*queryString = (queryString == null) ? '' : queryString+'&'; - queryString = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos; - if (this.sortCol) - queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir; - - this.ajaxOptions.parameters = queryString; - - ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions ); - */ - Prado.Callback(this.tableId, param, this.ajaxUpdate.bind(this), this.options); - this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout); - - }, - - ajaxUpdate: function(result, output) - { - try { - clearTimeout( this.timeoutHandler ); - this.buffer.update(result,this.processingRequest.bufferOffset); - this.viewPort.bufferChanged(); - } - catch(err) {} - finally {this.processingRequest = null; } - this.processQueuedRequest(); - } -}); - -Object.extend(Rico.LiveGridBuffer.prototype, -{ - update: function(newRows, start) - { - if (this.rows.length == 0) { // initial load - this.rows = newRows; - this.size = this.rows.length; - this.startPos = start; - return; - } - if (start > this.startPos) { //appending - if (this.startPos + this.rows.length < start) { - this.rows = newRows; - this.startPos = start;// - } else { - this.rows = this.rows.concat( newRows.slice(0, newRows.length)); - if (this.rows.length > this.maxBufferSize) { - var fullSize = this.rows.length; - this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length) - this.startPos = this.startPos + (fullSize - this.rows.length); - } - } - } else { //prepending - if (start + newRows.length < this.startPos) { - this.rows = newRows; - } else { - this.rows = newRows.slice(0, this.startPos).concat(this.rows); - if (this.rows.length > this.maxBufferSize) - this.rows = this.rows.slice(0, this.maxBufferSize) - } - this.startPos = start; - } - this.size = this.rows.length; - } -}); - - -Object.extend(Rico.GridViewPort.prototype, -{ - populateRow: function(htmlRow, row) - { - if(isdef(htmlRow)) - { - for (var j=0; j < row.length; j++) { - htmlRow.cells[j].innerHTML = row[j] - } - } - } -}); \ No newline at end of file diff --git a/framework/Web/Javascripts/rico/rico.js b/framework/Web/Javascripts/rico/rico.js deleted file mode 100644 index d179b84f..00000000 --- a/framework/Web/Javascripts/rico/rico.js +++ /dev/null @@ -1,3326 +0,0 @@ -/** - * - * Copyright 2005 Sabre Airline Solutions - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - **/ - - -//-------------------- rico.js -var Rico = { - Version: '1.1rc1', - prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1]) -} - -/* -if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3) - throw("Rico requires the Prototype JavaScript framework >= 1.3"); -*/ -Rico.ArrayExtensions = new Array(); - -if (Object.prototype.extend) { - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend; -}else{ - Object.prototype.extend = function(object) { - return Object.extend.apply(this, [this, object]); - } - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend; -} - -if (Array.prototype.push) { - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push; -} - -if (!Array.prototype.remove) { - Array.prototype.remove = function(dx) { - if( isNaN(dx) || dx > this.length ) - return false; - for( var i=0,n=0; i= this.accordionTabs.length) - this.options.onLoadShowTab = 0; - - // set the initial visual state... - for ( var i=0 ; i < this.accordionTabs.length ; i++ ) - { - if (i != this.options.onLoadShowTab){ - this.accordionTabs[i].collapse(); - this.accordionTabs[i].content.style.display = 'none'; - } - } - this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab]; - if (this.options.panelHeight == 'auto'){ - var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0; - var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height')); - if (isNaN(titleBarSize)) - titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight; - - var totalTitleBarSize = this.accordionTabs.length * titleBarSize; - var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height')); - if (isNaN(parentHeight)) - parentHeight = this.container.parentNode.offsetHeight; - - this.options.panelHeight = parentHeight - totalTitleBarSize-2; - } - - this.lastExpandedTab.content.style.height = this.options.panelHeight + "px"; - this.lastExpandedTab.showExpanded(); - this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight; - - }, - - setOptions: function(options) { - this.options = { - expandedBg : '#63699c', - hoverBg : '#63699c', - collapsedBg : '#6b79a5', - expandedTextColor : '#ffffff', - expandedFontWeight : 'bold', - hoverTextColor : '#ffffff', - collapsedTextColor : '#ced7ef', - collapsedFontWeight : 'normal', - hoverTextColor : '#ffffff', - borderColor : '#1f669b', - panelHeight : 200, - onHideTab : null, - onShowTab : null, - onLoadShowTab : 0 - } - Object.extend(this.options, options || {}); - }, - - showTabByIndex: function( anIndex, animate ) { - var doAnimate = arguments.length == 1 ? true : animate; - this.showTab( this.accordionTabs[anIndex], doAnimate ); - }, - - showTab: function( accordionTab, animate ) { - - var doAnimate = arguments.length == 1 ? true : animate; - - if ( this.options.onHideTab ) - this.options.onHideTab(this.lastExpandedTab); - - this.lastExpandedTab.showCollapsed(); - var accordion = this; - var lastExpandedTab = this.lastExpandedTab; - - this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px'; - accordionTab.content.style.display = ''; - - accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight; - - if ( doAnimate ) { - new Effect.AccordionSize( this.lastExpandedTab.content, - accordionTab.content, - 1, - this.options.panelHeight, - 100, 10, - { complete: function() {accordion.showTabDone(lastExpandedTab)} } ); - this.lastExpandedTab = accordionTab; - } - else { - this.lastExpandedTab.content.style.height = "1px"; - accordionTab.content.style.height = this.options.panelHeight + "px"; - this.lastExpandedTab = accordionTab; - this.showTabDone(lastExpandedTab); - } - }, - - showTabDone: function(collapsedTab) { - collapsedTab.content.style.display = 'none'; - this.lastExpandedTab.showExpanded(); - if ( this.options.onShowTab ) - this.options.onShowTab(this.lastExpandedTab); - }, - - _attachBehaviors: function() { - var panels = this._getDirectChildrenByTag(this.container, 'DIV'); - for ( var i = 0 ; i < panels.length ; i++ ) { - - var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV'); - if ( tabChildren.length != 2 ) - continue; // unexpected - - var tabTitleBar = tabChildren[0]; - var tabContentBox = tabChildren[1]; - this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) ); - } - }, - - _getDirectChildrenByTag: function(e, tagName) { - var kids = new Array(); - var allKids = e.childNodes; - for( var i = 0 ; i < allKids.length ; i++ ) - if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName ) - kids.push(allKids[i]); - return kids; - } - -}; - -Rico.Accordion.Tab = Class.create(); - -Rico.Accordion.Tab.prototype = { - - initialize: function(accordion, titleBar, content) { - this.accordion = accordion; - this.titleBar = titleBar; - this.content = content; - this._attachBehaviors(); - }, - - collapse: function() { - this.showCollapsed(); - this.content.style.height = "1px"; - }, - - showCollapsed: function() { - this.expanded = false; - this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg; - this.titleBar.style.color = this.accordion.options.collapsedTextColor; - this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight; - this.content.style.overflow = "hidden"; - }, - - showExpanded: function() { - this.expanded = true; - this.titleBar.style.backgroundColor = this.accordion.options.expandedBg; - this.titleBar.style.color = this.accordion.options.expandedTextColor; - this.content.style.overflow = "visible"; - }, - - titleBarClicked: function(e) { - if ( this.accordion.lastExpandedTab == this ) - return; - this.accordion.showTab(this); - }, - - hover: function(e) { - this.titleBar.style.backgroundColor = this.accordion.options.hoverBg; - this.titleBar.style.color = this.accordion.options.hoverTextColor; - }, - - unhover: function(e) { - if ( this.expanded ) { - this.titleBar.style.backgroundColor = this.accordion.options.expandedBg; - this.titleBar.style.color = this.accordion.options.expandedTextColor; - } - else { - this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg; - this.titleBar.style.color = this.accordion.options.collapsedTextColor; - } - }, - - _attachBehaviors: function() { - this.content.style.border = "1px solid " + this.accordion.options.borderColor; - this.content.style.borderTopWidth = "0px"; - this.content.style.borderBottomWidth = "0px"; - this.content.style.margin = "0px"; - - this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this); - this.titleBar.onmouseover = this.hover.bindAsEventListener(this); - this.titleBar.onmouseout = this.unhover.bindAsEventListener(this); - } - -}; - - -//-------------------- ricoAjaxEngine.js -/* -Rico.AjaxEngine = Class.create(); - -Rico.AjaxEngine.prototype = { - - initialize: function() { - this.ajaxElements = new Array(); - this.ajaxObjects = new Array(); - this.requestURLS = new Array(); - this.options = {}; - }, - - registerAjaxElement: function( anId, anElement ) { - if ( !anElement ) - anElement = $(anId); - this.ajaxElements[anId] = anElement; - }, - - registerAjaxObject: function( anId, anObject ) { - this.ajaxObjects[anId] = anObject; - }, - - registerRequest: function (requestLogicalName, requestURL) { - this.requestURLS[requestLogicalName] = requestURL; - }, - - sendRequest: function(requestName, options) { - // Allow for backwards Compatibility - if ( arguments.length >= 2 ) - if (typeof arguments[1] == 'string') - options = {parameters: this._createQueryString(arguments, 1)}; - this.sendRequestWithData(requestName, null, options); - }, - - sendRequestWithData: function(requestName, xmlDocument, options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - // Allow for backwards Compatibility - if ( arguments.length >= 3 ) - if (typeof arguments[2] == 'string') - options.parameters = this._createQueryString(arguments, 2); - - new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument)); - }, - - sendRequestAndUpdate: function(requestName,container,options) { - // Allow for backwards Compatibility - if ( arguments.length >= 3 ) - if (typeof arguments[2] == 'string') - options.parameters = this._createQueryString(arguments, 2); - - this.sendRequestWithDataAndUpdate(requestName, null, container, options); - }, - - sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - // Allow for backwards Compatibility - if ( arguments.length >= 4 ) - if (typeof arguments[3] == 'string') - options.parameters = this._createQueryString(arguments, 3); - - var updaterOptions = this._requestOptions(options,xmlDocument); - // Turn off onComplete - //updaterOptions.onComplete = null; - - new Ajax.Updater(container, requestURL, updaterOptions); - }, - - // Private -- not part of intended engine API -------------------------------------------------------------------- - - _requestOptions: function(options,xmlDoc) { - var requestHeaders = ['X-Rico-Version', Rico.Version ]; - var sendMethod = 'post'; - if ( xmlDoc == null ) - if (Rico.prototypeVersion < 1.4) - requestHeaders.push( 'Content-type', 'text/xml' ); - else - sendMethod = 'get'; - (!options) ? options = {} : ''; - - // Check and keep any user onComplete functions - if (options.onComplete) - options.onRicoComplete = options.onComplete; - // Fix onComplete - if (options.overrideOnComplete) - options.onComplete = options.overrideOnComplete; - else - options.onComplete = this._onRequestComplete.bind(this); - - // Set the default options and extend with any user options - this.options = { - requestHeaders: requestHeaders, - parameters: options.parameters, - postBody: xmlDoc, - method: sendMethod, - onComplete: options.onComplete - }; - // Set any user options: - Object.extend(this.options, options); - return this.options; - }, - - _createQueryString: function( theArgs, offset ) { - var queryString = "" - for ( var i = offset ; i < theArgs.length ; i++ ) { - if ( i != offset ) - queryString += "&"; - - var anArg = theArgs[i]; - - if ( anArg.name != undefined && anArg.value != undefined ) { - queryString += anArg.name + "=" + escape(anArg.value); - } - else { - var ePos = anArg.indexOf('='); - var argName = anArg.substring( 0, ePos ); - var argValue = anArg.substring( ePos + 1 ); - queryString += argName + "=" + escape(argValue); - } - } - return queryString; - }, - - _onRequestComplete : function(request) { - if(!request) - return; - // User can set an onFailure option - which will be called by prototype - if (request.status != 200) - return; - - var response = request.responseXML.getElementsByTagName("ajax-response"); - if (response == null || response.length != 1) - return; - this._processAjaxResponse( response[0].childNodes ); - - // Check if user has set a onComplete function - var onRicoComplete = this.options.onRicoComplete; - if (onRicoComplete != null) - onRicoComplete(); - }, - - _processAjaxResponse: function( xmlResponseElements ) { - for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) { - var responseElement = xmlResponseElements[i]; - - // only process nodes of type element..... - if ( responseElement.nodeType != 1 ) - continue; - - var responseType = responseElement.getAttribute("type"); - var responseId = responseElement.getAttribute("id"); - - if ( responseType == "object" ) - this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement ); - else if ( responseType == "element" ) - this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement ); - else - alert('unrecognized AjaxResponse type : ' + responseType ); - } - }, - - _processAjaxObjectUpdate: function( ajaxObject, responseElement ) { - ajaxObject.ajaxUpdate( responseElement ); - }, - - _processAjaxElementUpdate: function( ajaxElement, responseElement ) { - ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement); - } - -} - -var ajaxEngine = new Rico.AjaxEngine(); -*/ - -//-------------------- ricoColor.js -/*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 = hexCode.substring(0,2); - var green = hexCode.substring(2,4); - var blue = hexCode.substring(4,6); - 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 = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "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 ) { - var redPart = parseInt(actualColor.substring(1,3), 16); - var greenPart = parseInt(actualColor.substring(3,5), 16); - var bluePart = parseInt(actualColor.substring(5), 16); - return new Rico.Color( redPart, greenPart, bluePart ); - } - 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 }; -} -*/ - -//-------------------- ricoCorner.js -Rico.Corner = { - - round: function(e, options) { - var e = $(e); - this._setOptions(options); - - var color = this.options.color; - if ( this.options.color == "fromElement" ) - color = this._background(e); - - var bgColor = this.options.bgColor; - if ( this.options.bgColor == "fromParent" ) - bgColor = this._background(e.offsetParent); - - this._roundCornersImpl(e, color, bgColor); - }, - - _roundCornersImpl: function(e, color, bgColor) { - if(this.options.border) - this._renderBorder(e,bgColor); - if(this._isTopRounded()) - this._roundTopCorners(e,color,bgColor); - if(this._isBottomRounded()) - this._roundBottomCorners(e,color,bgColor); - }, - - _renderBorder: function(el,bgColor) { - var borderValue = "1px solid " + this._borderColor(bgColor); - var borderL = "border-left: " + borderValue; - var borderR = "border-right: " + borderValue; - var style = "style='" + borderL + ";" + borderR + "'"; - el.innerHTML = "
    " + el.innerHTML + "
    " - }, - - _roundTopCorners: function(el, color, bgColor) { - var corner = this._createCorner(bgColor); - for(var i=0 ; i < this.options.numSlices ; i++ ) - corner.appendChild(this._createCornerSlice(color,bgColor,i,"top")); - el.style.paddingTop = 0; - el.insertBefore(corner,el.firstChild); - }, - - _roundBottomCorners: function(el, color, bgColor) { - var corner = this._createCorner(bgColor); - for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) - corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom")); - el.style.paddingBottom = 0; - el.appendChild(corner); - }, - - _createCorner: function(bgColor) { - var corner = document.createElement("div"); - corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); - return corner; - }, - - _createCornerSlice: function(color,bgColor, n, position) { - var slice = document.createElement("span"); - - var inStyle = slice.style; - inStyle.backgroundColor = color; - inStyle.display = "block"; - inStyle.height = "1px"; - inStyle.overflow = "hidden"; - inStyle.fontSize = "1px"; - - var borderColor = this._borderColor(color,bgColor); - if ( this.options.border && n == 0 ) { - inStyle.borderTopStyle = "solid"; - inStyle.borderTopWidth = "1px"; - inStyle.borderLeftWidth = "0px"; - inStyle.borderRightWidth = "0px"; - inStyle.borderBottomWidth = "0px"; - inStyle.height = "0px"; // assumes css compliant box model - inStyle.borderColor = borderColor; - } - else if(borderColor) { - inStyle.borderColor = borderColor; - inStyle.borderStyle = "solid"; - inStyle.borderWidth = "0px 1px"; - } - - if ( !this.options.compact && (n == (this.options.numSlices-1)) ) - inStyle.height = "2px"; - - this._setMargin(slice, n, position); - this._setBorder(slice, n, position); - return slice; - }, - - _setOptions: function(options) { - this.options = { - corners : "all", - color : "fromElement", - bgColor : "fromParent", - blend : true, - border : false, - compact : false - } - Object.extend(this.options, options || {}); - - this.options.numSlices = this.options.compact ? 2 : 4; - if ( this._isTransparent() ) - this.options.blend = false; - }, - - _whichSideTop: function() { - if ( this._hasString(this.options.corners, "all", "top") ) - return ""; - - if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) - return ""; - - if (this.options.corners.indexOf("tl") >= 0) - return "left"; - else if (this.options.corners.indexOf("tr") >= 0) - return "right"; - return ""; - }, - - _whichSideBottom: function() { - if ( this._hasString(this.options.corners, "all", "bottom") ) - return ""; - - if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) - return ""; - - if(this.options.corners.indexOf("bl") >=0) - return "left"; - else if(this.options.corners.indexOf("br")>=0) - return "right"; - return ""; - }, - - _borderColor : function(color,bgColor) { - if ( color == "transparent" ) - return bgColor; - else if ( this.options.border ) - return this.options.border; - else if ( this.options.blend ) - return this._blend( bgColor, color ); - else - return ""; - }, - - - _setMargin: function(el, n, corners) { - var marginSize = this._marginSize(n); - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); - - if ( whichSide == "left" ) { - el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px"; - } - else if ( whichSide == "right" ) { - el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px"; - } - else { - el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px"; - } - }, - - _setBorder: function(el,n,corners) { - var borderSize = this._borderSize(n); - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); - if ( whichSide == "left" ) { - el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px"; - } - else if ( whichSide == "right" ) { - el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px"; - } - else { - el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px"; - } - if (this.options.border != false) - el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px"; - }, - - _marginSize: function(n) { - if ( this._isTransparent() ) - return 0; - - var marginSizes = [ 5, 3, 2, 1 ]; - var blendedMarginSizes = [ 3, 2, 1, 0 ]; - var compactMarginSizes = [ 2, 1 ]; - var smBlendedMarginSizes = [ 1, 0 ]; - - if ( this.options.compact && this.options.blend ) - return smBlendedMarginSizes[n]; - else if ( this.options.compact ) - return compactMarginSizes[n]; - else if ( this.options.blend ) - return blendedMarginSizes[n]; - else - return marginSizes[n]; - }, - - _borderSize: function(n) { - var transparentBorderSizes = [ 5, 3, 2, 1 ]; - var blendedBorderSizes = [ 2, 1, 1, 1 ]; - var compactBorderSizes = [ 1, 0 ]; - var actualBorderSizes = [ 0, 2, 0, 0 ]; - - if ( this.options.compact && (this.options.blend || this._isTransparent()) ) - return 1; - else if ( this.options.compact ) - return compactBorderSizes[n]; - else if ( this.options.blend ) - return blendedBorderSizes[n]; - else if ( this.options.border ) - return actualBorderSizes[n]; - else if ( this._isTransparent() ) - return transparentBorderSizes[n]; - return 0; - }, - - _hasString: function(str) { for(var i=1 ; i= 0) return true; return false; }, - _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; }, - _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } }, - _isTransparent: function() { return this.options.color == "transparent"; }, - _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); }, - _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); }, - _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; } -} - - -//-------------------- ricoDragAndDrop.js -/* -Rico.DragAndDrop = Class.create(); - -Rico.DragAndDrop.prototype = { - - initialize: function() { - this.dropZones = new Array(); - this.draggables = new Array(); - this.currentDragObjects = new Array(); - this.dragElement = null; - this.lastSelectedDraggable = null; - this.currentDragObjectVisible = false; - this.interestedInMotionEvents = false; - this._mouseDown = this._mouseDownHandler.bindAsEventListener(this); - this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this); - this._mouseUp = this._mouseUpHandler.bindAsEventListener(this); - }, - - registerDropZone: function(aDropZone) { - this.dropZones[ this.dropZones.length ] = aDropZone; - }, - - deregisterDropZone: function(aDropZone) { - var newDropZones = new Array(); - var j = 0; - for ( var i = 0 ; i < this.dropZones.length ; i++ ) { - if ( this.dropZones[i] != aDropZone ) - newDropZones[j++] = this.dropZones[i]; - } - - this.dropZones = newDropZones; - }, - - clearDropZones: function() { - this.dropZones = new Array(); - }, - - registerDraggable: function( aDraggable ) { - this.draggables[ this.draggables.length ] = aDraggable; - this._addMouseDownHandler( aDraggable ); - }, - - clearSelection: function() { - for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) - this.currentDragObjects[i].deselect(); - this.currentDragObjects = new Array(); - this.lastSelectedDraggable = null; - }, - - hasSelection: function() { - return this.currentDragObjects.length > 0; - }, - - setStartDragFromElement: function( e, mouseDownElement ) { - this.origPos = RicoUtil.toDocumentPosition(mouseDownElement); - this.startx = e.screenX - this.origPos.x - this.starty = e.screenY - this.origPos.y - //this.startComponentX = e.layerX ? e.layerX : e.offsetX; - //this.startComponentY = e.layerY ? e.layerY : e.offsetY; - //this.adjustedForDraggableSize = false; - - this.interestedInMotionEvents = this.hasSelection(); - this._terminateEvent(e); - }, - - updateSelection: function( draggable, extendSelection ) { - if ( ! extendSelection ) - this.clearSelection(); - - if ( draggable.isSelected() ) { - this.currentDragObjects.removeItem(draggable); - draggable.deselect(); - if ( draggable == this.lastSelectedDraggable ) - this.lastSelectedDraggable = null; - } - else { - this.currentDragObjects[ this.currentDragObjects.length ] = draggable; - draggable.select(); - this.lastSelectedDraggable = draggable; - } - }, - - _mouseDownHandler: function(e) { - if ( arguments.length == 0 ) - e = event; - - // if not button 1 ignore it... - var nsEvent = e.which != undefined; - if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1)) - return; - - var eventTarget = e.target ? e.target : e.srcElement; - var draggableObject = eventTarget.draggable; - - var candidate = eventTarget; - while (draggableObject == null && candidate.parentNode) { - candidate = candidate.parentNode; - draggableObject = candidate.draggable; - } - - if ( draggableObject == null ) - return; - - this.updateSelection( draggableObject, e.ctrlKey ); - - // clear the drop zones postion cache... - if ( this.hasSelection() ) - for ( var i = 0 ; i < this.dropZones.length ; i++ ) - this.dropZones[i].clearPositionCache(); - - this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() ); - }, - - - _mouseMoveHandler: function(e) { - var nsEvent = e.which != undefined; - if ( !this.interestedInMotionEvents ) { - //this._terminateEvent(e); - return; - } - - if ( ! this.hasSelection() ) - return; - - if ( ! this.currentDragObjectVisible ) - this._startDrag(e); - - if ( !this.activatedDropZones ) - this._activateRegisteredDropZones(); - - //if ( !this.adjustedForDraggableSize ) - // this._adjustForDraggableSize(e); - - this._updateDraggableLocation(e); - this._updateDropZonesHover(e); - - this._terminateEvent(e); - }, - - _makeDraggableObjectVisible: function(e) - { - if ( !this.hasSelection() ) - return; - - var dragElement; - if ( this.currentDragObjects.length > 1 ) - dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects); - else - dragElement = this.currentDragObjects[0].getSingleObjectDragGUI(); - - // go ahead and absolute position it... - if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" ) - dragElement.style.position = "absolute"; - - // need to parent him into the document... - if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 ) - document.body.appendChild(dragElement); - - this.dragElement = dragElement; - this._updateDraggableLocation(e); - - this.currentDragObjectVisible = true; - }, - - /** - _adjustForDraggableSize: function(e) { - var dragElementWidth = this.dragElement.offsetWidth; - var dragElementHeight = this.dragElement.offsetHeight; - if ( this.startComponentX > dragElementWidth ) - this.startx -= this.startComponentX - dragElementWidth + 2; - if ( e.offsetY ) { - if ( this.startComponentY > dragElementHeight ) - this.starty -= this.startComponentY - dragElementHeight + 2; - } - this.adjustedForDraggableSize = true; - }, - **/ -/* - _updateDraggableLocation: function(e) { - var dragObjectStyle = this.dragElement.style; - dragObjectStyle.left = (e.screenX - this.startx) + "px" - dragObjectStyle.top = (e.screenY - this.starty) + "px"; - }, - - _updateDropZonesHover: function(e) { - var n = this.dropZones.length; - for ( var i = 0 ; i < n ; i++ ) { - if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) ) - this.dropZones[i].hideHover(); - } - - for ( var i = 0 ; i < n ; i++ ) { - if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) { - if ( this.dropZones[i].canAccept(this.currentDragObjects) ) - this.dropZones[i].showHover(); - } - } - }, - - _startDrag: function(e) { - for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) - this.currentDragObjects[i].startDrag(); - - this._makeDraggableObjectVisible(e); - }, - - _mouseUpHandler: function(e) { - if ( ! this.hasSelection() ) - return; - - var nsEvent = e.which != undefined; - if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1)) - return; - - this.interestedInMotionEvents = false; - - if ( this.dragElement == null ) { - this._terminateEvent(e); - return; - } - - if ( this._placeDraggableInDropZone(e) ) - this._completeDropOperation(e); - else { - this._terminateEvent(e); - new Effect.Position( this.dragElement, - this.origPos.x, - this.origPos.y, - 200, - 20, - { complete : this._doCancelDragProcessing.bind(this) } ); - } - - Event.stopObserving(document.body, "mousemove", this._mouseMove); - Event.stopObserving(document.body, "mouseup", this._mouseUp); - }, - - _retTrue: function () { - return true; - }, - - _completeDropOperation: function(e) { - if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) { - if ( this.dragElement.parentNode != null ) - this.dragElement.parentNode.removeChild(this.dragElement); - } - - this._deactivateRegisteredDropZones(); - this._endDrag(); - this.clearSelection(); - this.dragElement = null; - this.currentDragObjectVisible = false; - this._terminateEvent(e); - }, - - _doCancelDragProcessing: function() { - this._cancelDrag(); - - if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement) - if ( this.dragElement.parentNode != null ) - this.dragElement.parentNode.removeChild(this.dragElement); - - - this._deactivateRegisteredDropZones(); - this.dragElement = null; - this.currentDragObjectVisible = false; - }, - - _placeDraggableInDropZone: function(e) { - var foundDropZone = false; - var n = this.dropZones.length; - for ( var i = 0 ; i < n ; i++ ) { - if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) { - if ( this.dropZones[i].canAccept(this.currentDragObjects) ) { - this.dropZones[i].hideHover(); - this.dropZones[i].accept(this.currentDragObjects); - foundDropZone = true; - break; - } - } - } - - return foundDropZone; - }, - - _cancelDrag: function() { - for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) - this.currentDragObjects[i].cancelDrag(); - }, - - _endDrag: function() { - for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) - this.currentDragObjects[i].endDrag(); - }, - - _mousePointInDropZone: function( e, dropZone ) { - - var absoluteRect = dropZone.getAbsoluteRect(); - - return e.clientX > absoluteRect.left && - e.clientX < absoluteRect.right && - e.clientY > absoluteRect.top && - e.clientY < absoluteRect.bottom; - }, - - _addMouseDownHandler: function( aDraggable ) - { - htmlElement = aDraggable.getMouseDownHTMLElement(); - if ( htmlElement != null ) { - htmlElement.draggable = aDraggable; - Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this)); - Event.observe(htmlElement, "mousedown", this._mouseDown); - } - }, - - _activateRegisteredDropZones: function() { - var n = this.dropZones.length; - for ( var i = 0 ; i < n ; i++ ) { - var dropZone = this.dropZones[i]; - if ( dropZone.canAccept(this.currentDragObjects) ) - dropZone.activate(); - } - - this.activatedDropZones = true; - }, - - _deactivateRegisteredDropZones: function() { - var n = this.dropZones.length; - for ( var i = 0 ; i < n ; i++ ) - this.dropZones[i].deactivate(); - this.activatedDropZones = false; - }, - - _onmousedown: function () { - Event.observe(document.body, "mousemove", this._mouseMove); - Event.observe(document.body, "mouseup", this._mouseUp); - }, - - _terminateEvent: function(e) { - if ( e.stopPropagation != undefined ) - e.stopPropagation(); - else if ( e.cancelBubble != undefined ) - e.cancelBubble = true; - - if ( e.preventDefault != undefined ) - e.preventDefault(); - else - e.returnValue = false; - } - -} - -Rico.Draggable = Class.create(); - -Rico.Draggable.prototype = { - - initialize: function( type, htmlElement ) { - this.type = type; - this.htmlElement = $(htmlElement); - this.selected = false; - }, - - /** - * Returns the HTML element that should have a mouse down event - * added to it in order to initiate a drag operation - * - **//* - getMouseDownHTMLElement: function() { - return this.htmlElement; - }, - - select: function() { - this.selected = true; - - if ( this.showingSelected ) - return; - - var htmlElement = this.getMouseDownHTMLElement(); - - var color = Rico.Color.createColorFromBackground(htmlElement); - color.isBright() ? color.darken(0.033) : color.brighten(0.033); - - this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color"); - htmlElement.style.backgroundColor = color.asHex(); - this.showingSelected = true; - }, - - deselect: function() { - this.selected = false; - if ( !this.showingSelected ) - return; - - var htmlElement = this.getMouseDownHTMLElement(); - - htmlElement.style.backgroundColor = this.saveBackground; - this.showingSelected = false; - }, - - isSelected: function() { - return this.selected; - }, - - startDrag: function() { - }, - - cancelDrag: function() { - }, - - endDrag: function() { - }, - - getSingleObjectDragGUI: function() { - return this.htmlElement; - }, - - getMultiObjectDragGUI: function( draggables ) { - return this.htmlElement; - }, - - getDroppedGUI: function() { - return this.htmlElement; - }, - - toString: function() { - return this.type + ":" + this.htmlElement + ":"; - } - -} - -Rico.Dropzone = Class.create(); - -Rico.Dropzone.prototype = { - - initialize: function( htmlElement ) { - this.htmlElement = $(htmlElement); - this.absoluteRect = null; - }, - - getHTMLElement: function() { - return this.htmlElement; - }, - - clearPositionCache: function() { - this.absoluteRect = null; - }, - - getAbsoluteRect: function() { - if ( this.absoluteRect == null ) { - var htmlElement = this.getHTMLElement(); - var pos = RicoUtil.toViewportPosition(htmlElement); - - this.absoluteRect = { - top: pos.y, - left: pos.x, - bottom: pos.y + htmlElement.offsetHeight, - right: pos.x + htmlElement.offsetWidth - }; - } - return this.absoluteRect; - }, - - activate: function() { - var htmlElement = this.getHTMLElement(); - if (htmlElement == null || this.showingActive) - return; - - this.showingActive = true; - this.saveBackgroundColor = htmlElement.style.backgroundColor; - - var fallbackColor = "#ffea84"; - var currentColor = Rico.Color.createColorFromBackground(htmlElement); - if ( currentColor == null ) - htmlElement.style.backgroundColor = fallbackColor; - else { - currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2); - htmlElement.style.backgroundColor = currentColor.asHex(); - } - }, - - deactivate: function() { - var htmlElement = this.getHTMLElement(); - if (htmlElement == null || !this.showingActive) - return; - - htmlElement.style.backgroundColor = this.saveBackgroundColor; - this.showingActive = false; - this.saveBackgroundColor = null; - }, - - showHover: function() { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null || this.showingHover ) - return; - - this.saveBorderWidth = htmlElement.style.borderWidth; - this.saveBorderStyle = htmlElement.style.borderStyle; - this.saveBorderColor = htmlElement.style.borderColor; - - this.showingHover = true; - htmlElement.style.borderWidth = "1px"; - htmlElement.style.borderStyle = "solid"; - //htmlElement.style.borderColor = "#ff9900"; - htmlElement.style.borderColor = "#ffff00"; - }, - - hideHover: function() { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null || !this.showingHover ) - return; - - htmlElement.style.borderWidth = this.saveBorderWidth; - htmlElement.style.borderStyle = this.saveBorderStyle; - htmlElement.style.borderColor = this.saveBorderColor; - this.showingHover = false; - }, - - canAccept: function(draggableObjects) { - return true; - }, - - accept: function(draggableObjects) { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null ) - return; - - n = draggableObjects.length; - for ( var i = 0 ; i < n ; i++ ) - { - var theGUI = draggableObjects[i].getDroppedGUI(); - if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" ) - { - theGUI.style.position = "static"; - theGUI.style.top = ""; - theGUI.style.top = ""; - } - htmlElement.appendChild(theGUI); - } - } -} - -var dndMgr = new Rico.DragAndDrop(); - - - -//-------------------- ricoDraggable.js -Rico.Draggable = Class.create(); - -Rico.Draggable.prototype = { - - initialize: function( type, htmlElement ) { - this.type = type; - this.htmlElement = $(htmlElement); - this.selected = false; - }, - - /** - * Returns the HTML element that should have a mouse down event - * added to it in order to initiate a drag operation - * - **//* - getMouseDownHTMLElement: function() { - return this.htmlElement; - }, - - select: function() { - this.selected = true; - - if ( this.showingSelected ) - return; - - var htmlElement = this.getMouseDownHTMLElement(); - - var color = Rico.Color.createColorFromBackground(htmlElement); - color.isBright() ? color.darken(0.033) : color.brighten(0.033); - - this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color"); - htmlElement.style.backgroundColor = color.asHex(); - this.showingSelected = true; - }, - - deselect: function() { - this.selected = false; - if ( !this.showingSelected ) - return; - - var htmlElement = this.getMouseDownHTMLElement(); - - htmlElement.style.backgroundColor = this.saveBackground; - this.showingSelected = false; - }, - - isSelected: function() { - return this.selected; - }, - - startDrag: function() { - }, - - cancelDrag: function() { - }, - - endDrag: function() { - }, - - getSingleObjectDragGUI: function() { - return this.htmlElement; - }, - - getMultiObjectDragGUI: function( draggables ) { - return this.htmlElement; - }, - - getDroppedGUI: function() { - return this.htmlElement; - }, - - toString: function() { - return this.type + ":" + this.htmlElement + ":"; - } - -} - - -//-------------------- ricoDropzone.js -Rico.Dropzone = Class.create(); - -Rico.Dropzone.prototype = { - - initialize: function( htmlElement ) { - this.htmlElement = $(htmlElement); - this.absoluteRect = null; - }, - - getHTMLElement: function() { - return this.htmlElement; - }, - - clearPositionCache: function() { - this.absoluteRect = null; - }, - - getAbsoluteRect: function() { - if ( this.absoluteRect == null ) { - var htmlElement = this.getHTMLElement(); - var pos = RicoUtil.toViewportPosition(htmlElement); - - this.absoluteRect = { - top: pos.y, - left: pos.x, - bottom: pos.y + htmlElement.offsetHeight, - right: pos.x + htmlElement.offsetWidth - }; - } - return this.absoluteRect; - }, - - activate: function() { - var htmlElement = this.getHTMLElement(); - if (htmlElement == null || this.showingActive) - return; - - this.showingActive = true; - this.saveBackgroundColor = htmlElement.style.backgroundColor; - - var fallbackColor = "#ffea84"; - var currentColor = Rico.Color.createColorFromBackground(htmlElement); - if ( currentColor == null ) - htmlElement.style.backgroundColor = fallbackColor; - else { - currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2); - htmlElement.style.backgroundColor = currentColor.asHex(); - } - }, - - deactivate: function() { - var htmlElement = this.getHTMLElement(); - if (htmlElement == null || !this.showingActive) - return; - - htmlElement.style.backgroundColor = this.saveBackgroundColor; - this.showingActive = false; - this.saveBackgroundColor = null; - }, - - showHover: function() { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null || this.showingHover ) - return; - - this.saveBorderWidth = htmlElement.style.borderWidth; - this.saveBorderStyle = htmlElement.style.borderStyle; - this.saveBorderColor = htmlElement.style.borderColor; - - this.showingHover = true; - htmlElement.style.borderWidth = "1px"; - htmlElement.style.borderStyle = "solid"; - //htmlElement.style.borderColor = "#ff9900"; - htmlElement.style.borderColor = "#ffff00"; - }, - - hideHover: function() { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null || !this.showingHover ) - return; - - htmlElement.style.borderWidth = this.saveBorderWidth; - htmlElement.style.borderStyle = this.saveBorderStyle; - htmlElement.style.borderColor = this.saveBorderColor; - this.showingHover = false; - }, - - canAccept: function(draggableObjects) { - return true; - }, - - accept: function(draggableObjects) { - var htmlElement = this.getHTMLElement(); - if ( htmlElement == null ) - return; - - n = draggableObjects.length; - for ( var i = 0 ; i < n ; i++ ) - { - var theGUI = draggableObjects[i].getDroppedGUI(); - if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" ) - { - theGUI.style.position = "static"; - theGUI.style.top = ""; - theGUI.style.top = ""; - } - htmlElement.appendChild(theGUI); - } - } -} -*/ - - -//-------------------- ricoEffect.js - -/** - * Use the Effect namespace for effects. If using scriptaculous effects - * this will already be defined, otherwise we'll just create an empty - * object for it... - **/ -if ( window.Effect == undefined ) - Effect = {}; - -Effect.SizeAndPosition = Class.create(); -Effect.SizeAndPosition.prototype = { - - initialize: function(element, x, y, w, h, duration, steps, options) { - this.element = $(element); - this.x = x; - this.y = y; - this.w = w; - this.h = h; - this.duration = duration; - this.steps = steps; - this.options = arguments[7] || {}; - - this.sizeAndPosition(); - }, - - sizeAndPosition: function() { - if (this.isFinished()) { - if(this.options.complete) this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - - // Get original values: x,y = top left corner; w,h = width height - var currentX = this.element.offsetLeft; - var currentY = this.element.offsetTop; - var currentW = this.element.offsetWidth; - var currentH = this.element.offsetHeight; - - // If values not set, or zero, we do not modify them, and take original as final as well - this.x = (this.x) ? this.x : currentX; - this.y = (this.y) ? this.y : currentY; - this.w = (this.w) ? this.w : currentW; - this.h = (this.h) ? this.h : currentH; - - // how much do we need to modify our values for each step? - var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0; - var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0; - var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0; - var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0; - - this.moveBy(difX, difY); - this.resizeBy(difW, difH); - - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration); - }, - - isFinished: function() { - return this.steps <= 0; - }, - - moveBy: function( difX, difY ) { - var currentLeft = this.element.offsetLeft; - var currentTop = this.element.offsetTop; - var intDifX = parseInt(difX); - var intDifY = parseInt(difY); - - var style = this.element.style; - if ( intDifX != 0 ) - style.left = (currentLeft + intDifX) + "px"; - if ( intDifY != 0 ) - style.top = (currentTop + intDifY) + "px"; - }, - - resizeBy: function( difW, difH ) { - var currentWidth = this.element.offsetWidth; - var currentHeight = this.element.offsetHeight; - var intDifW = parseInt(difW); - var intDifH = parseInt(difH); - - var style = this.element.style; - if ( intDifW != 0 ) - style.width = (currentWidth + intDifW) + "px"; - if ( intDifH != 0 ) - style.height = (currentHeight + intDifH) + "px"; - } -} - -Effect.Size = Class.create(); -Effect.Size.prototype = { - - initialize: function(element, w, h, duration, steps, options) { - new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options); - } -} - -Effect.Position = Class.create(); -Effect.Position.prototype = { - - initialize: function(element, x, y, duration, steps, options) { - new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options); - } -} - -Effect.Round = Class.create(); -Effect.Round.prototype = { - - initialize: function(tagName, className, options) { - var elements = document.getElementsByTagAndClassName(tagName,className); - for ( var i = 0 ; i < elements.length ; i++ ) - Rico.Corner.round( elements[i], options ); - } -}; - -Effect.FadeTo = Class.create(); -Effect.FadeTo.prototype = { - - initialize: function( element, opacity, duration, steps, options) { - this.element = $(element); - this.opacity = opacity; - this.duration = duration; - this.steps = steps; - this.options = arguments[4] || {}; - this.fadeTo(); - }, - - fadeTo: function() { - if (this.isFinished()) { - if(this.options.complete) this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - var currentOpacity = this.getElementOpacity(); - var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0; - - this.changeOpacityBy(delta); - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.fadeTo.bind(this), stepDuration); - }, - - changeOpacityBy: function(v) { - var currentOpacity = this.getElementOpacity(); - var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1)); - this.element.ricoOpacity = newOpacity; - - this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")"; - this.element.style.opacity = newOpacity; /*//*/; - }, - - isFinished: function() { - return this.steps <= 0; - }, - - getElementOpacity: function() { - if ( this.element.ricoOpacity == undefined ) { - var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity'); - this.element.ricoOpacity = opacity != undefined ? opacity : 1.0; - } - return parseFloat(this.element.ricoOpacity); - } -} - -Effect.AccordionSize = Class.create(); - -Effect.AccordionSize.prototype = { - - initialize: function(e1, e2, start, end, duration, steps, options) { - this.e1 = $(e1); - this.e2 = $(e2); - this.start = start; - this.end = end; - this.duration = duration; - this.steps = steps; - this.options = arguments[6] || {}; - - this.accordionSize(); - }, - - accordionSize: function() { - - if (this.isFinished()) { - // just in case there are round errors or such... - this.e1.style.height = this.start + "px"; - this.e2.style.height = this.end + "px"; - - if(this.options.complete) - this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - - var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0; - this.resizeBy(diff); - - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.accordionSize.bind(this), stepDuration); - }, - - isFinished: function() { - return this.steps <= 0; - }, - - resizeBy: function(diff) { - var h1Height = this.e1.offsetHeight; - var h2Height = this.e2.offsetHeight; - var intDiff = parseInt(diff); - if ( diff != 0 ) { - this.e1.style.height = (h1Height - intDiff) + "px"; - this.e2.style.height = (h2Height + intDiff) + "px"; - } - } - -}; - - -//-------------------- ricoEffects.js - -/** - * Use the Effect namespace for effects. If using scriptaculous effects - * this will already be defined, otherwise we'll just create an empty - * object for it... - **/ -if ( window.Effect == undefined ) - Effect = {}; - -Effect.SizeAndPosition = Class.create(); -Effect.SizeAndPosition.prototype = { - - initialize: function(element, x, y, w, h, duration, steps, options) { - this.element = $(element); - this.x = x; - this.y = y; - this.w = w; - this.h = h; - this.duration = duration; - this.steps = steps; - this.options = arguments[7] || {}; - - this.sizeAndPosition(); - }, - - sizeAndPosition: function() { - if (this.isFinished()) { - if(this.options.complete) this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - - // Get original values: x,y = top left corner; w,h = width height - var currentX = this.element.offsetLeft; - var currentY = this.element.offsetTop; - var currentW = this.element.offsetWidth; - var currentH = this.element.offsetHeight; - - // If values not set, or zero, we do not modify them, and take original as final as well - this.x = (this.x) ? this.x : currentX; - this.y = (this.y) ? this.y : currentY; - this.w = (this.w) ? this.w : currentW; - this.h = (this.h) ? this.h : currentH; - - // how much do we need to modify our values for each step? - var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0; - var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0; - var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0; - var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0; - - this.moveBy(difX, difY); - this.resizeBy(difW, difH); - - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration); - }, - - isFinished: function() { - return this.steps <= 0; - }, - - moveBy: function( difX, difY ) { - var currentLeft = this.element.offsetLeft; - var currentTop = this.element.offsetTop; - var intDifX = parseInt(difX); - var intDifY = parseInt(difY); - - var style = this.element.style; - if ( intDifX != 0 ) - style.left = (currentLeft + intDifX) + "px"; - if ( intDifY != 0 ) - style.top = (currentTop + intDifY) + "px"; - }, - - resizeBy: function( difW, difH ) { - var currentWidth = this.element.offsetWidth; - var currentHeight = this.element.offsetHeight; - var intDifW = parseInt(difW); - var intDifH = parseInt(difH); - - var style = this.element.style; - if ( intDifW != 0 ) - style.width = (currentWidth + intDifW) + "px"; - if ( intDifH != 0 ) - style.height = (currentHeight + intDifH) + "px"; - } -} - -Effect.Size = Class.create(); -Effect.Size.prototype = { - - initialize: function(element, w, h, duration, steps, options) { - new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options); - } -} - -Effect.Position = Class.create(); -Effect.Position.prototype = { - - initialize: function(element, x, y, duration, steps, options) { - new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options); - } -} - -Effect.Round = Class.create(); -Effect.Round.prototype = { - - initialize: function(tagName, className, options) { - var elements = document.getElementsByTagAndClassName(tagName,className); - for ( var i = 0 ; i < elements.length ; i++ ) - Rico.Corner.round( elements[i], options ); - } -}; - -Effect.FadeTo = Class.create(); -Effect.FadeTo.prototype = { - - initialize: function( element, opacity, duration, steps, options) { - this.element = $(element); - this.opacity = opacity; - this.duration = duration; - this.steps = steps; - this.options = arguments[4] || {}; - this.fadeTo(); - }, - - fadeTo: function() { - if (this.isFinished()) { - if(this.options.complete) this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - var currentOpacity = this.getElementOpacity(); - var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0; - - this.changeOpacityBy(delta); - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.fadeTo.bind(this), stepDuration); - }, - - changeOpacityBy: function(v) { - var currentOpacity = this.getElementOpacity(); - var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1)); - this.element.ricoOpacity = newOpacity; - - this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")"; - this.element.style.opacity = newOpacity; /*//*/; - }, - - isFinished: function() { - return this.steps <= 0; - }, - - getElementOpacity: function() { - if ( this.element.ricoOpacity == undefined ) { - var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity'); - this.element.ricoOpacity = opacity != undefined ? opacity : 1.0; - } - return parseFloat(this.element.ricoOpacity); - } -} - -Effect.AccordionSize = Class.create(); - -Effect.AccordionSize.prototype = { - - initialize: function(e1, e2, start, end, duration, steps, options) { - this.e1 = $(e1); - this.e2 = $(e2); - this.start = start; - this.end = end; - this.duration = duration; - this.steps = steps; - this.options = arguments[6] || {}; - - this.accordionSize(); - }, - - accordionSize: function() { - - if (this.isFinished()) { - // just in case there are round errors or such... - this.e1.style.height = this.start + "px"; - this.e2.style.height = this.end + "px"; - - if(this.options.complete) - this.options.complete(this); - return; - } - - if (this.timer) - clearTimeout(this.timer); - - var stepDuration = Math.round(this.duration/this.steps) ; - - var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0; - this.resizeBy(diff); - - this.duration -= stepDuration; - this.steps--; - - this.timer = setTimeout(this.accordionSize.bind(this), stepDuration); - }, - - isFinished: function() { - return this.steps <= 0; - }, - - resizeBy: function(diff) { - var h1Height = this.e1.offsetHeight; - var h2Height = this.e2.offsetHeight; - var intDiff = parseInt(diff); - if ( diff != 0 ) { - this.e1.style.height = (h1Height - intDiff) + "px"; - this.e2.style.height = (h2Height + intDiff) + "px"; - } - } - -}; - - -//-------------------- ricoLiveGrid.js -// Rico.LiveGridMetaData ----------------------------------------------------- - -Rico.LiveGridMetaData = Class.create(); - -Rico.LiveGridMetaData.prototype = { - - initialize: function( pageSize, totalRows, columnCount, options ) { - this.pageSize = pageSize; - this.totalRows = totalRows; - this.setOptions(options); - this.ArrowHeight = 16; - this.columnCount = columnCount; - }, - - setOptions: function(options) { - this.options = { - largeBufferSize : 7.0, // 7 pages - nearLimitFactor : 0.2 // 20% of buffer - }; - Object.extend(this.options, options || {}); - }, - - getPageSize: function() { - return this.pageSize; - }, - - getTotalRows: function() { - return this.totalRows; - }, - - setTotalRows: function(n) { - this.totalRows = n; - }, - - getLargeBufferSize: function() { - return parseInt(this.options.largeBufferSize * this.pageSize); - }, - - getLimitTolerance: function() { - return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor); - } -}; - -// Rico.LiveGridScroller ----------------------------------------------------- - -Rico.LiveGridScroller = Class.create(); - -Rico.LiveGridScroller.prototype = { - - initialize: function(liveGrid, viewPort) { - this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0; - this.liveGrid = liveGrid; - this.metaData = liveGrid.metaData; - this.createScrollBar(); - this.scrollTimeout = null; - this.lastScrollPos = 0; - this.viewPort = viewPort; - this.rows = new Array(); - }, - - isUnPlugged: function() { - return this.scrollerDiv.onscroll == null; - }, - - plugin: function() { - this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this); - }, - - unplug: function() { - this.scrollerDiv.onscroll = null; - }, - - sizeIEHeaderHack: function() { - if ( !this.isIE ) return; - var headerTable = $(this.liveGrid.tableId + "_header"); - if ( headerTable ) - headerTable.rows[0].cells[0].style.width = - (headerTable.rows[0].cells[0].offsetWidth + 1) + "px"; - }, - - createScrollBar: function() { - var visibleHeight = this.liveGrid.viewPort.visibleHeight(); - // create the outer div... - this.scrollerDiv = document.createElement("div"); - var scrollerStyle = this.scrollerDiv.style; - scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight; - scrollerStyle.position = "relative"; - scrollerStyle.left = this.isIE ? "-6px" : "-3px"; - scrollerStyle.width = "19px"; - scrollerStyle.height = visibleHeight + "px"; - scrollerStyle.overflow = "auto"; - - // create the inner div... - this.heightDiv = document.createElement("div"); - this.heightDiv.style.width = "1px"; - - this.heightDiv.style.height = parseInt(visibleHeight * - this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ; - this.scrollerDiv.appendChild(this.heightDiv); - this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this); - - var table = this.liveGrid.table; - table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling ); - var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll"; - Event.observe(table, eventName, - function(evt) { - if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up - this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight); - else - this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight); - this.handleScroll(false); - }.bindAsEventListener(this), - false); - }, - - updateSize: function() { - var table = this.liveGrid.table; - var visibleHeight = this.viewPort.visibleHeight(); - this.heightDiv.style.height = parseInt(visibleHeight * - this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px"; - }, - - rowToPixel: function(rowOffset) { - return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight - }, - - moveScroll: function(rowOffset) { - this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset); - if ( this.metaData.options.onscroll ) - this.metaData.options.onscroll( this.liveGrid, rowOffset ); - }, - - handleScroll: function() { - if ( this.scrollTimeout ) - clearTimeout( this.scrollTimeout ); - - var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop; - if (scrollDiff != 0.00) { - var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight; - if (r != 0) { - this.unplug(); - if ( scrollDiff < 0 ) { - this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r); - } else { - this.scrollerDiv.scrollTop -= r; - } - this.plugin(); - } - } - var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight); - this.liveGrid.requestContentRefresh(contentOffset); - this.viewPort.scrollTo(this.scrollerDiv.scrollTop); - - if ( this.metaData.options.onscroll ) - this.metaData.options.onscroll( this.liveGrid, contentOffset ); - - this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 ); - this.lastScrollPos = this.scrollerDiv.scrollTop; - - }, - - scrollIdle: function() { - if ( this.metaData.options.onscrollidle ) - this.metaData.options.onscrollidle(); - } -}; - -// Rico.LiveGridBuffer ----------------------------------------------------- - -Rico.LiveGridBuffer = Class.create(); - -Rico.LiveGridBuffer.prototype = { - - initialize: function(metaData, viewPort) { - this.startPos = 0; - this.size = 0; - this.metaData = metaData; - this.rows = new Array(); - this.updateInProgress = false; - this.viewPort = viewPort; - this.maxBufferSize = metaData.getLargeBufferSize() * 2; - this.maxFetchSize = metaData.getLargeBufferSize(); - this.lastOffset = 0; - }, - - getBlankRow: function() { - if (!this.blankRow ) { - this.blankRow = new Array(); - for ( var i=0; i < this.metaData.columnCount ; i++ ) - this.blankRow[i] = " "; - } - return this.blankRow; - }, - - loadRows: function(ajaxResponse) { - var rowsElement = ajaxResponse.getElementsByTagName('rows')[0]; - this.updateUI = rowsElement.getAttribute("update_ui") == "true" - var newRows = new Array() - var trs = rowsElement.getElementsByTagName("tr"); - for ( var i=0 ; i < trs.length; i++ ) { - var row = newRows[i] = new Array(); - var cells = trs[i].getElementsByTagName("td"); - for ( var j=0; j < cells.length ; j++ ) { - var cell = cells[j]; - var convertSpaces = cell.getAttribute("convert_spaces") == "true"; - var cellContent = RicoUtil.getContentAsString(cell); - row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent; - if (!row[j]) - row[j] = ' '; - } - } - return newRows; - }, - - update: function(ajaxResponse, start) { - var newRows = this.loadRows(ajaxResponse); - if (this.rows.length == 0) { // initial load - this.rows = newRows; - this.size = this.rows.length; - this.startPos = start; - return; - } - if (start > this.startPos) { //appending - if (this.startPos + this.rows.length < start) { - this.rows = newRows; - this.startPos = start;// - } else { - this.rows = this.rows.concat( newRows.slice(0, newRows.length)); - if (this.rows.length > this.maxBufferSize) { - var fullSize = this.rows.length; - this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length) - this.startPos = this.startPos + (fullSize - this.rows.length); - } - } - } else { //prepending - if (start + newRows.length < this.startPos) { - this.rows = newRows; - } else { - this.rows = newRows.slice(0, this.startPos).concat(this.rows); - if (this.rows.length > this.maxBufferSize) - this.rows = this.rows.slice(0, this.maxBufferSize) - } - this.startPos = start; - } - this.size = this.rows.length; - }, - - clear: function() { - this.rows = new Array(); - this.startPos = 0; - this.size = 0; - }, - - isOverlapping: function(start, size) { - return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0) - }, - - isInRange: function(position) { - return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); - //&& this.size() != 0; - }, - - isNearingTopLimit: function(position) { - return position - this.startPos < this.metaData.getLimitTolerance(); - }, - - endPos: function() { - return this.startPos + this.rows.length; - }, - - isNearingBottomLimit: function(position) { - return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance(); - }, - - isAtTop: function() { - return this.startPos == 0; - }, - - isAtBottom: function() { - return this.endPos() == this.metaData.getTotalRows(); - }, - - isNearingLimit: function(position) { - return ( !this.isAtTop() && this.isNearingTopLimit(position)) || - ( !this.isAtBottom() && this.isNearingBottomLimit(position) ) - }, - - getFetchSize: function(offset) { - var adjustedOffset = this.getFetchOffset(offset); - var adjustedSize = 0; - if (adjustedOffset >= this.startPos) { //apending - var endFetchOffset = this.maxFetchSize + adjustedOffset; - if (endFetchOffset > this.metaData.totalRows) - endFetchOffset = this.metaData.totalRows; - adjustedSize = endFetchOffset - adjustedOffset; - if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){ - adjustedSize = this.maxFetchSize; - } - } else {//prepending - var adjustedSize = this.startPos - adjustedOffset; - if (adjustedSize > this.maxFetchSize) - adjustedSize = this.maxFetchSize; - } - return adjustedSize; - }, - - getFetchOffset: function(offset) { - var adjustedOffset = offset; - if (offset > this.startPos) //apending - adjustedOffset = (offset > this.endPos()) ? offset : this.endPos(); - else { //prepending - if (offset + this.maxFetchSize >= this.startPos) { - var adjustedOffset = this.startPos - this.maxFetchSize; - if (adjustedOffset < 0) - adjustedOffset = 0; - } - } - this.lastOffset = adjustedOffset; - return adjustedOffset; - }, - - getRows: function(start, count) { - var begPos = start - this.startPos - var endPos = begPos + count - - // er? need more data... - if ( endPos > this.size ) - endPos = this.size - - var results = new Array() - var index = 0; - for ( var i=begPos ; i < endPos; i++ ) { - results[index++] = this.rows[i] - } - return results - }, - - convertSpaces: function(s) { - return s.split(" ").join(" "); - } - -}; - - -//Rico.GridViewPort -------------------------------------------------- -Rico.GridViewPort = Class.create(); - -Rico.GridViewPort.prototype = { - - initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) { - this.lastDisplayedStartPos = 0; - this.div = table.parentNode; - this.table = table - this.rowHeight = rowHeight; - this.div.style.height = this.rowHeight * visibleRows; - this.div.style.overflow = "hidden"; - this.buffer = buffer; - this.liveGrid = liveGrid; - this.visibleRows = visibleRows + 1; - this.lastPixelOffset = 0; - this.startPos = 0; - }, - - populateRow: function(htmlRow, row) { - for (var j=0; j < row.length; j++) { - htmlRow.cells[j].innerHTML = row[j] - } - }, - - bufferChanged: function() { - this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight)); - }, - - clearRows: function() { - if (!this.isBlank) { - this.liveGrid.table.className = this.liveGrid.options.loadingClass; - for (var i=0; i < this.visibleRows; i++) - this.populateRow(this.table.rows[i], this.buffer.getBlankRow()); - this.isBlank = true; - } - }, - - clearContents: function() { - this.clearRows(); - this.scrollTo(0); - this.startPos = 0; - this.lastStartPos = -1; - }, - - refreshContents: function(startPos) { - if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) { - return; - } - if ((startPos + this.visibleRows < this.buffer.startPos) - || (this.buffer.startPos + this.buffer.size < startPos) - || (this.buffer.size == 0)) { - this.clearRows(); - return; - } - this.isBlank = false; - var viewPrecedesBuffer = this.buffer.startPos > startPos - var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos; - var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) - ? this.buffer.startPos + this.buffer.size - : startPos + this.visibleRows; - var rowSize = contentEndPos - contentStartPos; - var rows = this.buffer.getRows(contentStartPos, rowSize ); - var blankSize = this.visibleRows - rowSize; - var blankOffset = viewPrecedesBuffer ? 0: rowSize; - var contentOffset = viewPrecedesBuffer ? blankSize: 0; - - for (var i=0; i < rows.length; i++) {//initialize what we have - this.populateRow(this.table.rows[i + contentOffset], rows[i]); - } - for (var i=0; i < blankSize; i++) {// blank out the rest - this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow()); - } - this.isPartialBlank = blankSize > 0; - this.lastRowPos = startPos; - - this.liveGrid.table.className = this.liveGrid.options.tableClass; - // Check if user has set a onRefreshComplete function - var onRefreshComplete = this.liveGrid.options.onRefreshComplete; - if (onRefreshComplete != null) - onRefreshComplete(); - }, - - scrollTo: function(pixelOffset) { - if (this.lastPixelOffset == pixelOffset) - return; - - this.refreshContents(parseInt(pixelOffset / this.rowHeight)) - this.div.scrollTop = pixelOffset % this.rowHeight - - this.lastPixelOffset = pixelOffset; - }, - - visibleHeight: function() { - return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height')); - } - -}; - - -Rico.LiveGridRequest = Class.create(); -Rico.LiveGridRequest.prototype = { - initialize: function( requestOffset, options ) { - this.requestOffset = requestOffset; - } -}; - -// Rico.LiveGrid ----------------------------------------------------- - -Rico.LiveGrid = Class.create(); - -Rico.LiveGrid.prototype = { - - initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) { - - this.options = { - tableClass: $(tableId).className, - loadingClass: $(tableId).className, - scrollerBorderRight: '1px solid #ababab', - bufferTimeout: 20000, - sortAscendImg: 'images/sort_asc.gif', - sortDescendImg: 'images/sort_desc.gif', - sortImageWidth: 9, - sortImageHeight: 5, - ajaxSortURLParms: [], - onRefreshComplete: null, - requestParameters: null, - inlineStyles: true - }; - Object.extend(this.options, options || {}); - - this.ajaxOptions = {parameters: null}; - Object.extend(this.ajaxOptions, ajaxOptions || {}); - - this.tableId = tableId; - this.table = $(tableId); - - this.addLiveGridHtml(); - - var columnCount = this.table.rows[0].cells.length; - this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options); - this.buffer = new Rico.LiveGridBuffer(this.metaData); - - var rowCount = this.table.rows.length; - this.viewPort = new Rico.GridViewPort(this.table, - this.table.offsetHeight/rowCount, - visibleRows, - this.buffer, this); - this.scroller = new Rico.LiveGridScroller(this,this.viewPort); - this.options.sortHandler = this.sortHandler.bind(this); - - if ( $(tableId + '_header') ) - this.sort = new Rico.LiveGridSort(tableId + '_header', this.options) - - this.processingRequest = null; - this.unprocessedRequest = null; - - this.initAjax(url); - if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) { - var offset = 0; - if (this.options.offset ) { - offset = this.options.offset; - this.scroller.moveScroll(offset); - this.viewPort.scrollTo(this.scroller.rowToPixel(offset)); - } - if (this.options.sortCol) { - this.sortCol = options.sortCol; - this.sortDir = options.sortDir; - } - this.requestContentRefresh(offset); - } - }, - - addLiveGridHtml: function() { - // Check to see if need to create a header table. - if (this.table.getElementsByTagName("thead").length > 0){ - // Create Table this.tableId+'_header' - var tableHeader = this.table.cloneNode(true); - tableHeader.setAttribute('id', this.tableId+'_header'); - tableHeader.setAttribute('class', this.table.className+'_header'); - - // Clean up and insert - for( var i = 0; i < tableHeader.tBodies.length; i++ ) - tableHeader.removeChild(tableHeader.tBodies[i]); - this.table.deleteTHead(); - this.table.parentNode.insertBefore(tableHeader,this.table); - } - - new Insertion.Before(this.table, "
    "); - this.table.previousSibling.appendChild(this.table); - new Insertion.Before(this.table,"
    "); - this.table.previousSibling.appendChild(this.table); - }, - - resetContents: function() { - this.scroller.moveScroll(0); - this.buffer.clear(); - this.viewPort.clearContents(); - }, - - sortHandler: function(column) { - this.sortCol = column.name; - this.sortDir = column.currentSort; - - this.resetContents(); - this.requestContentRefresh(0) - }, - - setTotalRows: function( newTotalRows ) { - this.resetContents(); - this.metaData.setTotalRows(newTotalRows); - this.scroller.updateSize(); - }, - - initAjax: function(url) { - ajaxEngine.registerRequest( this.tableId + '_request', url ); - ajaxEngine.registerAjaxObject( this.tableId + '_updater', this ); - }, - - invokeAjax: function() { - }, - - handleTimedOut: function() { - //server did not respond in 4 seconds... assume that there could have been - //an error or something, and allow requests to be processed again... - this.processingRequest = null; - this.processQueuedRequest(); - }, - - fetchBuffer: function(offset) { - if ( this.buffer.isInRange(offset) && - !this.buffer.isNearingLimit(offset)) { - return; - } - if (this.processingRequest) { - this.unprocessedRequest = new Rico.LiveGridRequest(offset); - return; - } - var bufferStartPos = this.buffer.getFetchOffset(offset); - this.processingRequest = new Rico.LiveGridRequest(offset); - this.processingRequest.bufferOffset = bufferStartPos; - var fetchSize = this.buffer.getFetchSize(offset); - var partialLoaded = false; - - var queryString - if (this.options.requestParameters) - queryString = this._createQueryString(this.options.requestParameters, 0); - - queryString = (queryString == null) ? '' : queryString+'&'; - queryString = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos; - if (this.sortCol) - queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir; - - this.ajaxOptions.parameters = queryString; - - ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions ); - - this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout); - - }, - - setRequestParams: function() { - this.options.requestParameters = []; - for ( var i=0 ; i < arguments.length ; i++ ) - this.options.requestParameters[i] = arguments[i]; - }, - - requestContentRefresh: function(contentOffset) { - this.fetchBuffer(contentOffset); - }, - - ajaxUpdate: function(ajaxResponse) { - try { - clearTimeout( this.timeoutHandler ); - this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset); - this.viewPort.bufferChanged(); - } - catch(err) {} - finally {this.processingRequest = null; } - this.processQueuedRequest(); - }, - - _createQueryString: function( theArgs, offset ) { - var queryString = "" - if (!theArgs) - return queryString; - - for ( var i = offset ; i < theArgs.length ; i++ ) { - if ( i != offset ) - queryString += "&"; - - var anArg = theArgs[i]; - - if ( anArg.name != undefined && anArg.value != undefined ) { - queryString += anArg.name + "=" + escape(anArg.value); - } - else { - var ePos = anArg.indexOf('='); - var argName = anArg.substring( 0, ePos ); - var argValue = anArg.substring( ePos + 1 ); - queryString += argName + "=" + escape(argValue); - } - } - return queryString; - }, - - processQueuedRequest: function() { - if (this.unprocessedRequest != null) { - this.requestContentRefresh(this.unprocessedRequest.requestOffset); - this.unprocessedRequest = null - } - } -}; - - -//-------------------- ricoLiveGridSort.js -Rico.LiveGridSort = Class.create(); - -Rico.LiveGridSort.prototype = { - - initialize: function(headerTableId, options) { - this.headerTableId = headerTableId; - this.headerTable = $(headerTableId); - this.options = options; - this.setOptions(); - this.applySortBehavior(); - - if ( this.options.sortCol ) { - this.setSortUI( this.options.sortCol, this.options.sortDir ); - } - }, - - setSortUI: function( columnName, sortDirection ) { - var cols = this.options.columns; - for ( var i = 0 ; i < cols.length ; i++ ) { - if ( cols[i].name == columnName ) { - this.setColumnSort(i, sortDirection); - break; - } - } - }, - - setOptions: function() { - // preload the images... - new Image().src = this.options.sortAscendImg; - new Image().src = this.options.sortDescendImg; - - this.sort = this.options.sortHandler; - if ( !this.options.columns ) - this.options.columns = this.introspectForColumnInfo(); - else { - // allow client to pass { columns: [ ["a", true], ["b", false] ] } - // and convert to an array of Rico.TableColumn objs... - this.options.columns = this.convertToTableColumns(this.options.columns); - } - }, - - applySortBehavior: function() { - var headerRow = this.headerTable.rows[0]; - var headerCells = headerRow.cells; - for ( var i = 0 ; i < headerCells.length ; i++ ) { - this.addSortBehaviorToColumn( i, headerCells[i] ); - } - }, - - addSortBehaviorToColumn: function( n, cell ) { - if ( this.options.columns[n].isSortable() ) { - cell.id = this.headerTableId + '_' + n; - cell.style.cursor = 'pointer'; - cell.onclick = this.headerCellClicked.bindAsEventListener(this); - cell.innerHTML = cell.innerHTML + '' - + '   '; - } - }, - - // event handler.... - headerCellClicked: function(evt) { - var eventTarget = evt.target ? evt.target : evt.srcElement; - var cellId = eventTarget.id; - var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 )); - var sortedColumnIndex = this.getSortedColumnIndex(); - if ( sortedColumnIndex != -1 ) { - if ( sortedColumnIndex != columnNumber ) { - this.removeColumnSort(sortedColumnIndex); - this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC); - } - else - this.toggleColumnSort(sortedColumnIndex); - } - else - this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC); - - if (this.options.sortHandler) { - this.options.sortHandler(this.options.columns[columnNumber]); - } - }, - - removeColumnSort: function(n) { - this.options.columns[n].setUnsorted(); - this.setSortImage(n); - }, - - setColumnSort: function(n, direction) { - this.options.columns[n].setSorted(direction); - this.setSortImage(n); - }, - - toggleColumnSort: function(n) { - this.options.columns[n].toggleSort(); - this.setSortImage(n); - }, - - setSortImage: function(n) { - var sortDirection = this.options.columns[n].getSortDirection(); - - var sortImageSpan = $( this.headerTableId + '_img_' + n ); - if ( sortDirection == Rico.TableColumn.UNSORTED ) - sortImageSpan.innerHTML = '  '; - else if ( sortDirection == Rico.TableColumn.SORT_ASC ) - sortImageSpan.innerHTML = '  '; - else if ( sortDirection == Rico.TableColumn.SORT_DESC ) - sortImageSpan.innerHTML = '  '; - }, - - getSortedColumnIndex: function() { - var cols = this.options.columns; - for ( var i = 0 ; i < cols.length ; i++ ) { - if ( cols[i].isSorted() ) - return i; - } - - return -1; - }, - - introspectForColumnInfo: function() { - var columns = new Array(); - var headerRow = this.headerTable.rows[0]; - var headerCells = headerRow.cells; - for ( var i = 0 ; i < headerCells.length ; i++ ) - columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) ); - return columns; - }, - - convertToTableColumns: function(cols) { - var columns = new Array(); - for ( var i = 0 ; i < cols.length ; i++ ) - columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) ); - return columns; - }, - - deriveColumnNameFromCell: function(cell,columnNumber) { - var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent; - return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber; - } -}; - -Rico.TableColumn = Class.create(); - -Rico.TableColumn.UNSORTED = 0; -Rico.TableColumn.SORT_ASC = "ASC"; -Rico.TableColumn.SORT_DESC = "DESC"; - -Rico.TableColumn.prototype = { - initialize: function(name, sortable) { - this.name = name; - this.sortable = sortable; - this.currentSort = Rico.TableColumn.UNSORTED; - }, - - isSortable: function() { - return this.sortable; - }, - - isSorted: function() { - return this.currentSort != Rico.TableColumn.UNSORTED; - }, - - getSortDirection: function() { - return this.currentSort; - }, - - toggleSort: function() { - if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC ) - this.currentSort = Rico.TableColumn.SORT_ASC; - else if ( this.currentSort == Rico.TableColumn.SORT_ASC ) - this.currentSort = Rico.TableColumn.SORT_DESC; - }, - - setUnsorted: function(direction) { - this.setSorted(Rico.TableColumn.UNSORTED); - }, - - setSorted: function(direction) { - // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC... - this.currentSort = direction; - } - -}; - - -//-------------------- ricoUtil.js -Rico.ArrayExtensions = new Array(); - -if (Object.prototype.extend) { - // in prototype.js... - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend; -}else{ - Object.prototype.extend = function(object) { - return Object.extend.apply(this, [this, object]); - } - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend; -} - -if (Array.prototype.push) { - // in prototype.js... - Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push; -} - -if (!Array.prototype.remove) { - Array.prototype.remove = function(dx) { - if( isNaN(dx) || dx > this.length ) - return false; - for( var i=0,n=0; ithis 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: , + container: , + } + var child = { + parent: , + children: , + id: (as per options.format), + element: , + container: , + position: + } + This is intended to become part of the public API, and can be used to manipulate + the tree programatically. + - Modified Sortable.serialize to use Sortable.tree when set in the options. + +* Fix a problem with window scrolling on draggables [thx Gregory Hill] + +* Let the benchmark method return the time taken in ms, so it can be used for time-based assertions + +* Fix problem with id-based handle names and draggables + +* More Element.childrenWithClassName optimization + +* Added benchmark method to unittest.js; some cleaning up of unit tests + +* Add fix for IE memory leaks in included prototype.js from [4094] + +*V1.6.0* + +* Major speedup for sortable with handles initialization [thx Jamis Buck] + +* Update to latest Prototype 1.5.0_pre1 trunk + +* Add functional "random effects" test, also for browser compatibility testing + +* Fix two typos introduced with the 1.5 Methods syntax update + +* Add functional test for $$-triggered effects with .visualEffect + +* Fix shift-tab for autocompleter in Safari, fixes #4423 [thx matt] + +* Prepare for script.aculo.us 1.6, add Prototype 1.5 requirement and check that Element.Methods is available in the scriptaculous loader + +* Refactor effects.js to use the new Prototype 1.5 Element Methods syntax + +* Update to latest Prototype 1.5.0_pre0 trunk + +* Fix a problem with the draggable window scrolling code and scrolling inside overflow containers + +* Add passing through of scroll options from Sortable to Draggable [thx Gregory Hill] + +* Make it possible to scroll window on dragging, #3921 [thx rdmiller] + +* Make Element.forceRerendering give up on any exception (this fixes various problems with IE) + +* added visualEffect method for the Element Mixin, fixed so you can chain multiple calls. [Rick Olson] + +* Fix only option on Sortable.create to accept multiple class names, fixes #3427 [thx glenn nilsson] + +* Added workaround for a rendering bug in Safari when using floating elements with Effect.Appear + +* Update lib/prototype.js to Prototype 1.5.0_pre0 + +*V1.5.3* + +* Change version number to V1.5.3, prepare Rakefile + +* Remove unneeded height restoring in Effect.BlindDown as that is handled internally by the restoreAfterFinish option to Effect.Scale, fixes #3667 [thx Ross Lawley] + +* Added Ajax.InPlaceCollectionEditor which uses a SELECT element instead of a text field (see test/functional/ajax_inplacecollectioneditor_test.html for usage), #3491 [thx anna] + +* Enable in place editor to use RJS (implements a new evalScripts option for the in place editor), #3490 [thx Richard Livsey] + +* Added Sortable.setSequence to programmatically reorder a Sortable, #3711 [thx Mike A. Owens] + +* Added unit test for #3732 (currently fails due to Prototype #3877) [thx michal] + +* Fix span positioning for sliders with ranges not starting at 0, fixes #3731 [thx michal] + +* Make name option on Sortable.serialize work again, fixes #3873 + +* Make dragging cancel only on ESC key, not on any key, fixes #3817 + +* Fix Rakefile for V1.5.2 + +*V1.5.2* + +* Change version number to V1.5.2 + +* Fix a wrong parameter in dragdrop.js, fixes #3555 + +* Fix two typos in effects.js, fixes #3481 [thx jtolds] + +* Add assertEnumEqual for unit testing (from Prototype SVN trunk) [Sam Stephenson] + +* Add Sortable.sequence method to extract the current sequence of a Sortable as an array, fixes #3675 [thx sphivo] + +* Add limit option to effect queues to limit the maximum number of effects in a queue, new unit tests for scoped effect queues, fixes #3498 [thx Abdur-Rahman Advany] + +* Fix Element.collectTextNodesIgnoreClass to correctly filter child nodes, fixes #3380 [thx lam] + +* Fix a condition where OPTION elements could cause unwanted dragging on Draggables, fixes #3441 [thx tom] + +* Fix a crash because of an IE bug in Effect.SlideDown, fixes #3192 [thx Rob Mayhew] + +* Added experimental auto-scroll option to Draggables and Sortables, activate with scroll: 'id_of_scroll_container_element'. + Note: needs testing, call syntax might change + See test/functional/dragdrop3_test.html for usage/demo + +* Added activate method to Autocompleter that allows you to trigger the suggestions through other means than user input [DHH] + +*V1.5.1* + +* Add select option to Autocompleter to optionally use textnodes from elements with a specific CSS class (see test/functional/ajax_autocompleter_test.html for usage) + +* In-place editor: add ok/cancel visibility options and onblur() submission, fixes #3233 [thx pulsation] + Note: currently, blur form submission breaks the cancel link functionality, if enabled + +* Added Effect.toggle for slide, blind and appear/fade effects, fixes #2704 [thx Azad] + +* Added selective component loading to scriptaculous.js, see test/unit/loading_test.html for usage [thx David Zülke] + +* Added local/scoped effect queues [thx David Zülke] + +* New core effect Effect.Move that can do absolute/relative movement [thx David Zülke] + +* Make default effects options modifyable globally by setting Effect.DefaultOptions + +* Make Draggables recognize top/left CSS properties defined in an external stylesheet, fixes #3205 [thx ansonparker] + +* Fixed draggables starting to drag even if mouse button was released with no movement, [thx topfunky] + +* Updated the README to reflect final status + +*V1.5.0* + +* Prepared for V1.5.0 final + +* Update lib/prototype.js to Prototype 1.4.0 final + +*V1.5.0_rc6* + +* Update lib/prototype.js to Prototype 1.4.0_rc4 + +* Fix Effect.SlideDown/SlideUp on Internet Explorer, includes a change to Effect.Scale, (should) fix #2962 and others, [thx wyldeone] + +* Make Draggables that are reverting cancel the default revert effect when they are dragged again while reverting, fixes #3188, [thx maverick] + +* Fix a problem with a wrong reference in Effect.Pulsate, fixes #3184, [thx cyx_] + +* Fix Sortable.findElements for XHTML in Gecko, fixes #3081, [thx fgnass] + +* Fix a problem with the slider getting NaN results when clicking directly on the track, fixes #3020, [thx rectalogic] + +* Fix a problem with Safari not doing sub-pixel rendering when setting opacity to 1 with Element.setOpacity + +* Fix slider to make handle width/height count for track length, fixes #3040, fixes #3017, [thx buggedcom] + +* Added Basic unit test for Effect.inspect + +* Fix Effect.multiple to deal correctly with delays + +* Safeguard Effect.Base.render to only do updates when Effect is in running state, fixes #2912 + +* Added inspect method to Effect.Base + +* Added functional test for DOM-based UL sortables #3016 + +* Added offset option to Effect.ScrollTo + +* More effects.js/dragdrop.js refactoring + +* Refactoring and optimizations for effects (not complete yet) + +* Refactoring and optimizations for Draggables/Droppables/Sortables (not complete yet) + +*V1.5.0_rc5* + +* Make Droppables.remove accept DOM IDs in addition to elements + +* Added some unit tests for drag and drop + +* Update lib/prototype.js to Prototype 1.4.0_rc3 + +* Make 'contents' a synonym for 'content' on Effect.Scale scaleMode option + +* Fix some possible exceptions in slider.js + +* Support for various snapping options on Draggables, adresses #2826, [thx saimonmoore] + +* Support horizontal ghostable Sortables, fixes #2794, [thx johnm] + +* Prevent an exception on IE with a functional test, see #2706 + +* Add functional testing of hoverclasses for sortables + +* Add an assert for correct UTF-8 return chars in Autocompleter + +* Correct IE detection in Autocompleter for Opera, fixes #2558 [thx gary] + +* Add onDrag callback to Draggable observers, #2827 [thx saimonmoore] + +* Added Form.Element.DelayedObserver to controls.js for live-search fields + +* Remove Element.Class in favour of Prototype Element.ClassNames, new function Element.childrenWithClassName() + +* Update Copyright notice in slider.js + +* Fix slider firing onChange events to eagerly on dragging a handle [thx wombert] + +* Fix a problem with Start/End spans and single handles + +* Add event property to Slider object so that callbacks can determine if setValue originated from a UI event or from script + +* Fix Builder.node() throwing unresolved errors in IE6, #2707 [thx flwombat] + +* Give currently active handle on slider the "selected" CSS class + +* Add start and end spans to slider + +* Make track clickable for sliders (moves last active handle [or first handle] to nearest possible position) + +* Make initial values on slider work for single and multiple handle sliders + +*V1.5.0_rc4* + +* Abort Effect.Highlight on elements which have display:none set (prevents problem with Safari) + +* Make Effect.Queue an Enumerable, fix a problem with Effect.Grow, more unit tests + +* Added restricted option to prevent moved of handles prior/after adjacent handles on Sliders with multiple handles + +* Update lib/prototype.js to Prototype 1.4.0_rc2 + +* Fix a bug with wrongly scrolling to the page top in Ajax.InPlaceEditor (circumvents various browser bugs) [Jon Tirsen], #2616 + +* major slider refactoring, changed slider range to default to [0,1]. Slider Range can be set with range:$R(from,to) option. The increment option is not active for now. + +* Added spans support for Control.Slider to mark spans bordered by slider handles, see unit test [thx to www.bartenbach.de for sponsoring this functionality] + +* Added preliminary support for optional multiple handles to Control.Slider [thx to www.bartenbach.de for sponsoring this functionality] + +* Fixed wrong inclusion of libs in inplace editor functional test + +* Fixed Effect.SlideDown/SlideUp to honor refactoring of Effect.Scale, fixes #2523 [thx obiwanki] + +* Reset the zIndex on Draggables correctly, #2483 [thx Jon Whitcraft] + +* Fix onChange callback on Sortables when dragging between sortables, #2488 [thx Dylan Greene] + +* Removed Builder code from effects.js, removed Object.debug (implemented as Test.Unit.inspect) + +* Added slider unit tests, fixed handling of values to autocalculate min/max, fixed upper/lower boundaries on setting the value programmatically + +* Synced to Rails 1.0 release candidate, update to Prototype 1.4.0_rc1, removed util.js, merged rests of util.js into effects.js to prepare for refactoring + +* Give Builder it's own file + +* Fix a logic issue with Autocompleter [thx tshinnic], #2457 + +*V1.5.0_rc3* + +* Make Effect position available to callbacks + +* Droppables.fire: send event to onDrop callback [François Beausoleil], #2389 + +* InPlaceEditor: Add disabling the field while loadTextURL loads and add a class while loading, plus fix various bugs with Internet Explorer and InPlaceEditor, [Jon Tirsen] #2302, #2303 + +* Made Droppables.remove work again [thx Mindaugas Pelionis], #2409 + +* Fixed that IE6 would incorrectly render the "fix-windowed-elements-overlapping" IFRAME on autocompletion [thx tshinnic], #2403 + +* Fixed Element.getOpacity throwing an error on Safari in some situations (this caused the autocompleter not to work) + +* Added format option to Sortable.create and Sortable.serialize to allow custom id formats. The format option takes a regular expression where the first grouping that matches is used for building the parameters. The default format is /^[^_]*_(.*)$/ which matches the string_identifier format. If you want to use the full id of the elements, use "format: /(.*)/". More examples are available in the sortable unit test file. + +* Started refactorings to use the new Prototype features and general code-cleanup + +* Update lib/prototype.js to Prototype 1.4.0_pre11 + +* Fixed a typo breaking the up arrow key for autocompletion [thx tshinnic], #2406 + +* Changed the handle option on Draggbles to accept classnames, or ids or elements [thx to Andrew West], #2274 + +* Force indicator to be hidden on hiding autocompletion update element, #2342 + +* Make Draggables honor external CSS positioning [thx to Mark Shawkey], #2359 + +* Make zindex handling for Draggables honor external CSS styles + +* Fix two Sortable.serialize issues, [thx Avi, Gorou], #2339, #2357 + +* Make Element.getOpacity work with IE, added unit tests [thx to Greg Hill] + +* Make Element.setOpacity honor non-alpha filters on IE (it now works with filters for alpha PNGs) + +* Fixed that Element.class.remove wrongly deleted spaces between class names, fixes #2311, #2313 + +* Fixed Builder for OPTION and OPTGROUP tags on Firefox < 1.5 and Internet Explorer 6, completely fixes #2325 + +* Improved Builder implementation to deal with Firefox-specific requirements and innerHTML parsing, partly fixes #2325 + +*V1.5.0_rc2* + +* Update lib/prototype.js to corrected Prototype 1.4.0_pre7 (fixed a problem with IE) + +* Update lib/prototype.js to Prototype 1.4.0_pre7 + +* Reverted to patched version of Prototype 1.4.0_pre4 for the time being (getResponseHeader problem on Mozilla) + +* Attempt to fix crashes in Safari 2.0.1, probably related to the event registering und unregistering in Draggables, possibly fixes #2310 + +* Update lib/prototype.js to Prototype 1.4.0_pre6 + +* Changed effects_test.html functional test to incoporate Firefox anti-flicker overflow:hidden CSS property + +*V1.5.0_rc1* + +* Prepared Rakefile and README for V1.5.0_rc1 release + +* Droppables w/greedy and hoverclass are now reverted when dragged item is no longer over them, fixes #2184 + +* Let Effect.Highlight correctly parse IE colors, add String.prototype.parseColor() for this, fixes #2037 + +* Fix Effect.Highlight to restore background image only if there was one + +* Made Effect.tagifyText work again on IE + +* Added String.prototype.toArray because Strings aren't iterable on IE + +* Fixed Element.getOpacity falsely returning 0 on IE + +* Some cleaning up in util.js + +* Cleaned up Effect.Opacity + +* Removed useless line in Position.page + +* Make scriptaculous.js work if a query strings are used when calling it + +* Fixed typos in slider.js and the functional test + +* Fixed a bug with Safari and the InPlaceEditor with form submission. Add support for interpreting simple
    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 + ">"; + } 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 + ">"; + } 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 lastTokenPos) + lastTokenPos = thisTokenPos; + } + return lastTokenPos; + } +} + +Ajax.Autocompleter = Class.create(); +Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } + +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(); +Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
      " + 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(/

    /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= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if(typeof this[property] != 'function') data[property] = this[property]; + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Event = Class.create(); +Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { + initialize: function() { + var options = Object.extend({ + duration: 0 + }, arguments[0] || {}); + this.start(options); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: Math.round(this.options.x * position + this.originalLeft) + 'px', + top: Math.round(this.options.y * position + this.originalTop) + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = Math.round(width) + 'px'; + if(this.options.scaleY) d.height = Math.round(height) + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = {}; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if(!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if(effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || {})); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || {})); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); + effect.element.down().undoPositioned(); + } + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || {})); +}; + +Effect.Morph = Class.create(); +Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: {} + }, arguments[1] || {}); + if (typeof options.style == 'string') { + if(options.style.indexOf(':') == -1) { + var cssText = '', selector = '.' + options.style; + $A(document.styleSheets).reverse().each(function(styleSheet) { + if (styleSheet.cssRules) cssRules = styleSheet.cssRules; + else if (styleSheet.rules) cssRules = styleSheet.rules; + $A(cssRules).reverse().each(function(rule) { + if (selector == rule.selectorText) { + cssText = rule.style.cssText; + throw $break; + } + }); + if (cssText) throw $break; + }); + this.style = cssText.parseStyle(); + options.afterFinishInternal = function(effect){ + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + if(transform.style != 'opacity') + effect.element.style[transform.style.camelize()] = ''; + }); + } + } else this.style = options.style.parseStyle(); + } else this.style = $H(options.style) + this.start(options); + }, + setup: function(){ + function parseColor(color){ + if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0].underscore().dasherize(), value = pair[1], unit = null; + + if(value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if(property == 'opacity') { + value = parseFloat(value); + if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if(Element.CSS_LENGTH.test(value)) + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), + value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; + + var originalValue = this.element.getStyle(property); + return $H({ + style: property, + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }); + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = $H(), value = null; + this.transforms.each(function(transform){ + value = transform.unit=='color' ? + $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(transform.originalValue[i]+ + (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : + transform.originalValue + Math.round( + ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; + style[transform.style] = value; + }); + this.element.setStyle(style); + } +}); + +Effect.Transform = Class.create(); +Object.extend(Effect.Transform.prototype, { + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || {}; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + var data = $H(track).values().first(); + this.tracks.push($H({ + ids: $H(track).keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var elements = [$(track.ids) || $$(track.ids)].flatten(); + return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.prototype.parseStyle = function(){ + var element = Element.extend(document.createElement('div')); + element.innerHTML = '

    '; + var style = element.down().style, styleRules = $H(); + + Element.CSS_PROPERTIES.each(function(property){ + if(style[property]) styleRules[property] = style[property]; + }); + if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) { + styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]; + } + return styleRules; +}; + +Element.morph = function(element, style) { + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); + return element; +}; + +['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', + 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( + function(f) { Element.Methods[f] = Element[f]; } +); + +Element.Methods.visualEffect = function(element, effect, options) { + s = effect.gsub(/_/, '-').camelize(); + effect_class = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[effect_class](element, options); + return $(element); +}; + +Element.addMethods(); \ No newline at end of file diff --git a/framework/Web/Javascripts/scriptaculous/slider.js b/framework/Web/Javascripts/scriptaculous/slider.js new file mode 100644 index 00000000..f24f2823 --- /dev/null +++ b/framework/Web/Javascripts/scriptaculous/slider.js @@ -0,0 +1,278 @@ +// script.aculo.us slider.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(!Control) var Control = {}; +Control.Slider = Class.create(); + +// options: +// axis: 'vertical', or 'horizontal' (default) +// +// callbacks: +// onChange(value) +// onSlide(value) +Control.Slider.prototype = { + initialize: function(handle, track, options) { + var slider = this; + + if(handle instanceof Array) { + this.handles = handle.collect( function(e) { return $(e) }); + } else { + this.handles = [$(handle)]; + } + + this.track = $(track); + this.options = options || {}; + + this.axis = this.options.axis || 'horizontal'; + this.increment = this.options.increment || 1; + this.step = parseInt(this.options.step || '1'); + this.range = this.options.range || $R(0,1); + + this.value = 0; // assure backwards compat + this.values = this.handles.map( function() { return 0 }); + this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; + this.options.startSpan = $(this.options.startSpan || null); + this.options.endSpan = $(this.options.endSpan || null); + + this.restricted = this.options.restricted || false; + + this.maximum = this.options.maximum || this.range.end; + this.minimum = this.options.minimum || this.range.start; + + // Will be used to align the handle onto the track, if necessary + this.alignX = parseInt(this.options.alignX || '0'); + this.alignY = parseInt(this.options.alignY || '0'); + + this.trackLength = this.maximumOffset() - this.minimumOffset(); + + this.handleLength = this.isVertical() ? + (this.handles[0].offsetHeight != 0 ? + this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : + (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : + this.handles[0].style.width.replace(/px$/,"")); + + this.active = false; + this.dragging = false; + this.disabled = false; + + if(this.options.disabled) this.setDisabled(); + + // Allowed values array + this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; + if(this.allowedValues) { + this.minimum = this.allowedValues.min(); + this.maximum = this.allowedValues.max(); + } + + this.eventMouseDown = this.startDrag.bindAsEventListener(this); + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.update.bindAsEventListener(this); + + // Initialize handles in reverse (make sure first handle is active) + this.handles.each( function(h,i) { + i = slider.handles.length-1-i; + slider.setValue(parseFloat( + (slider.options.sliderValue instanceof Array ? + slider.options.sliderValue[i] : slider.options.sliderValue) || + slider.range.start), i); + Element.makePositioned(h); // fix IE + Event.observe(h, "mousedown", slider.eventMouseDown); + }); + + Event.observe(this.track, "mousedown", this.eventMouseDown); + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + + this.initialized = true; + }, + dispose: function() { + var slider = this; + Event.stopObserving(this.track, "mousedown", this.eventMouseDown); + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + this.handles.each( function(h) { + Event.stopObserving(h, "mousedown", slider.eventMouseDown); + }); + }, + setDisabled: function(){ + this.disabled = true; + }, + setEnabled: function(){ + this.disabled = false; + }, + getNearestValue: function(value){ + if(this.allowedValues){ + if(value >= this.allowedValues.max()) return(this.allowedValues.max()); + if(value <= this.allowedValues.min()) return(this.allowedValues.min()); + + var offset = Math.abs(this.allowedValues[0] - value); + var newValue = this.allowedValues[0]; + this.allowedValues.each( function(v) { + var currentOffset = Math.abs(v - value); + if(currentOffset <= offset){ + newValue = v; + offset = currentOffset; + } + }); + return newValue; + } + if(value > this.range.end) return this.range.end; + if(value < this.range.start) return this.range.start; + return value; + }, + setValue: function(sliderValue, handleIdx){ + if(!this.active) { + this.activeHandleIdx = handleIdx || 0; + this.activeHandle = this.handles[this.activeHandleIdx]; + this.updateStyles(); + } + handleIdx = handleIdx || this.activeHandleIdx || 0; + if(this.initialized && this.restricted) { + if((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) + sliderValue = this.values[handleIdx+1]; + } + sliderValue = this.getNearestValue(sliderValue); + this.values[handleIdx] = sliderValue; + this.value = this.values[0]; // assure backwards compat + + this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = + this.translateToPx(sliderValue); + + this.drawSpans(); + if(!this.dragging || !this.event) this.updateFinished(); + }, + setValueBy: function(delta, handleIdx) { + this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, + handleIdx || this.activeHandleIdx || 0); + }, + translateToPx: function(value) { + return Math.round( + ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * + (value - this.range.start)) + "px"; + }, + translateToValue: function(offset) { + return ((offset/(this.trackLength-this.handleLength) * + (this.range.end-this.range.start)) + this.range.start); + }, + getRange: function(range) { + var v = this.values.sortBy(Prototype.K); + range = range || 0; + return $R(v[range],v[range+1]); + }, + minimumOffset: function(){ + return(this.isVertical() ? this.alignY : this.alignX); + }, + maximumOffset: function(){ + return(this.isVertical() ? + (this.track.offsetHeight != 0 ? this.track.offsetHeight : + this.track.style.height.replace(/px$/,"")) - this.alignY : + (this.track.offsetWidth != 0 ? this.track.offsetWidth : + this.track.style.width.replace(/px$/,"")) - this.alignY); + }, + isVertical: function(){ + return (this.axis == 'vertical'); + }, + drawSpans: function() { + var slider = this; + if(this.spans) + $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); + if(this.options.startSpan) + this.setSpan(this.options.startSpan, + $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); + if(this.options.endSpan) + this.setSpan(this.options.endSpan, + $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); + }, + setSpan: function(span, range) { + if(this.isVertical()) { + span.style.top = this.translateToPx(range.start); + span.style.height = this.translateToPx(range.end - range.start + this.range.start); + } else { + span.style.left = this.translateToPx(range.start); + span.style.width = this.translateToPx(range.end - range.start + this.range.start); + } + }, + updateStyles: function() { + this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); + Element.addClassName(this.activeHandle, 'selected'); + }, + startDrag: function(event) { + if(Event.isLeftClick(event)) { + if(!this.disabled){ + this.active = true; + + var handle = Event.element(event); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var track = handle; + if(track==this.track) { + var offsets = Position.cumulativeOffset(this.track); + this.event = event; + this.setValue(this.translateToValue( + (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) + )); + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } else { + // find the handle (prevents issues with Safari) + while((this.handles.indexOf(handle) == -1) && handle.parentNode) + handle = handle.parentNode; + + if(this.handles.indexOf(handle)!=-1) { + this.activeHandle = handle; + this.activeHandleIdx = this.handles.indexOf(this.activeHandle); + this.updateStyles(); + + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } + } + } + Event.stop(event); + } + }, + update: function(event) { + if(this.active) { + if(!this.dragging) this.dragging = true; + this.draw(event); + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + Event.stop(event); + } + }, + draw: function(event) { + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var offsets = Position.cumulativeOffset(this.track); + pointer[0] -= this.offsetX + offsets[0]; + pointer[1] -= this.offsetY + offsets[1]; + this.event = event; + this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); + if(this.initialized && this.options.onSlide) + this.options.onSlide(this.values.length>1 ? this.values : this.value, this); + }, + endDrag: function(event) { + if(this.active && this.dragging) { + this.finishDrag(event, true); + Event.stop(event); + } + this.active = false; + this.dragging = false; + }, + finishDrag: function(event, success) { + this.active = false; + this.dragging = false; + this.updateFinished(); + }, + updateFinished: function() { + if(this.initialized && this.options.onChange) + this.options.onChange(this.values.length>1 ? this.values : this.value, this); + this.event = null; + } +} \ No newline at end of file -- cgit v1.2.3