From 8af7d1f67a3bad48919c38a40371bf687a2599c0 Mon Sep 17 00:00:00 2001 From: pies Date: Tue, 31 May 2005 22:40:49 +0000 Subject: [PATCH] Sync'd with Olle's sandbox and with the Ajax stuff I've received. I'm trying to put together a sample application using Ajax, but it's gonna take at least few days (mostly because I've already done it and got bored with it:) Changes are mostly comments, plus a few more methods for the Controller class (which really needs thinning). I think I'll create two helper classes, Html and Ajax to handle the tag-generating stuff and take some code off libs/controller.php. Also, added /vendors/javascript/prototype.js and /public/js/prototype.js -- they are the same, perhaps we should just distribute one. One other change is a standards-fix for Controller::urlFor() (ampersands are entity-encoded now), but it seems puny compared to the former. Larry, can you refresh the PHPDocs? git-svn-id: https://svn.cakephp.org/repo/trunk/cake@205 3807eeeb-6ff5-0310-8944-8be069107fe0 --- public/index.php | 5 - public/js/prototype.js | 765 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 765 insertions(+), 5 deletions(-) create mode 100644 public/js/prototype.js diff --git a/public/index.php b/public/index.php index 0940ac2a2..43cb2f504 100644 --- a/public/index.php +++ b/public/index.php @@ -45,11 +45,6 @@ require (ROOT.'config/core.php'); require (ROOT.'config/paths.php'); require (ROOT.'libs/basics.php'); -/* for older versions of php */ -// ini_set("include_path", ROOT.'vendors/pear' . PATH_SEPARATOR . ini_get("include_path")); -// require_once ('PHP/Compat.php'); -// $components = PHP_Compat::loadVersion(); - DEBUG? error_reporting(E_ALL): error_reporting(0); $TIME_START = getMicrotime(); diff --git a/public/js/prototype.js b/public/js/prototype.js new file mode 100644 index 000000000..b7647f271 --- /dev/null +++ b/public/js/prototype.js @@ -0,0 +1,765 @@ +/* Prototype: an object-oriented Javascript library, version 1.2.1 + * (c) 2005 Sam Stephenson + * + * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff + * against the source tree, available from the Prototype darcs repository. + * + * Prototype is freely distributable under the terms of an MIT-style license. + * + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.2.1' +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.prototype.extend = function(object) { + for (property in object) { + this[property] = object[property]; + } + return this; +} + +Function.prototype.bind = function(object) { + var method = this; + return function() { + method.apply(object, arguments); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var method = this; + return function(event) { + method.call(object, event || window.event); + } +} + +Number.prototype.toColorPart = function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; +} + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + + this.registerCallback(); + } +} + +/*--------------------------------------------------------------------------*/ + +function $() { + var elements = new Array(); + + for (var i = 0; i < arguments.length; i++) { + var element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + + if (arguments.length == 1) + return element; + + elements.push(element); + } + + return elements; +} + +/*--------------------------------------------------------------------------*/ + +if (!Array.prototype.push) { + Array.prototype.push = function() { + var startLength = this.length; + for (var i = 0; i < arguments.length; i++) + this[startLength + i] = arguments[i]; + return this.length; + } +} + +if (!Function.prototype.apply) { + // Based on code from http://www.youngpup.net/ + Function.prototype.apply = function(object, parameters) { + var parameterStrings = new Array(); + if (!object) object = window; + if (!parameters) parameters = new Array(); + + for (var i = 0; i < parameters.length; i++) + parameterStrings[i] = 'x[' + i + ']'; + + object.__apply__ = this; + var result = eval('obj.__apply__(' + + parameterStrings[i].join(', ') + ')'); + object.__apply__ = null; + + return result; + } +} + +/*--------------------------------------------------------------------------*/ + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')}, + function() {return new XMLHttpRequest()} + ) || false; + }, + + emptyFunction: function() {} +} + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + parameters: '' + }.extend(options || {}); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = (new Ajax.Base()).extend({ + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + + try { + if (this.options.method == 'get') + url += '?' + this.options.parameters + '&_='; + + this.transport.open(this.options.method, url, + this.options.asynchronous); + + if (this.options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version); + + if (this.options.method == 'post') { + this.transport.setRequestHeader('Connection', 'close'); + this.transport.setRequestHeader('Content-type', + 'application/x-www-form-urlencoded'); + } + + this.transport.send(this.options.method == 'post' ? + this.options.parameters + '&_=' : null); + + } catch (e) { + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState != 1) + this.respondToReadyState(this.transport.readyState); + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + (this.options['on' + event] || Ajax.emptyFunction)(this.transport); + } +}); + +Ajax.Updater = Class.create(); +Ajax.Updater.prototype = (new Ajax.Base()).extend({ + initialize: function(container, url, options) { + this.container = $(container); + this.setOptions(options); + + if (this.options.asynchronous) { + this.onComplete = this.options.onComplete; + this.options.onComplete = this.updateContent.bind(this); + } + + this.request = new Ajax.Request(url, this.options); + + if (!this.options.asynchronous) + this.updateContent(); + }, + + updateContent: function() { + if (this.options.insertion) { + new this.options.insertion(this.container, + this.request.transport.responseText); + } else { + this.container.innerHTML = this.request.transport.responseText; + } + + if (this.onComplete) { + setTimeout((function() {this.onComplete(this.request)}).bind(this), 10); + } + } +}); + +/*--------------------------------------------------------------------------*/ + +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + $(element).focus(); + $(element).select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + focusFirstElement: function(form) { + form = $(form); + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (element.type != 'hidden' && !element.disabled) { + Field.activate(element); + break; + } + } + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return encodeURIComponent(parameter[0]) + '=' + + encodeURIComponent(parameter[1]); + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + var index = element.selectedIndex; + var value = element.options[index].value || element.options[index].text; + return [element.name, (index >= 0) ? value : '']; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + + this.registerCallback(); + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({ + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = (new Abstract.TimedObserver()).extend({ + getValue: function() { + return Form.serialize(this.element); + } +}); + + +/*--------------------------------------------------------------------------*/ + +document.getElementsByClassName = function(className) { + var children = document.getElementsByTagName('*') || document.all; + var elements = new Array(); + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var classNames = child.className.split(' '); + for (var j = 0; j < classNames.length; j++) { + if (classNames[j] == className) { + elements.push(child); + break; + } + } + } + + return elements; +} + +/*--------------------------------------------------------------------------*/ + +var Element = { + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = + (element.style.display == 'none' ? '' : 'none'); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + } +} + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content; + + if (this.adjacency && this.element.insertAdjacentHTML) { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.fragment = this.range.createContextualFragment(this.content); + this.insertContent(); + } + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({ + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function() { + this.element.parentNode.insertBefore(this.fragment, this.element); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({ + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function() { + this.element.insertBefore(this.fragment, this.element.firstChild); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({ + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function() { + this.element.appendChild(this.fragment); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function() { + this.element.parentNode.insertBefore(this.fragment, + this.element.nextSibling); + } +}); + +/*--------------------------------------------------------------------------*/ + +var Effect = new Object(); + +Effect.Highlight = Class.create(); +Effect.Highlight.prototype = { + initialize: function(element) { + this.element = $(element); + this.start = 153; + this.finish = 255; + this.current = this.start; + this.fade(); + }, + + fade: function() { + if (this.isFinished()) return; + if (this.timer) clearTimeout(this.timer); + this.highlight(this.element, this.current); + this.current += 17; + this.timer = setTimeout(this.fade.bind(this), 250); + }, + + isFinished: function() { + return this.current > this.finish; + }, + + highlight: function(element, current) { + element.style.backgroundColor = "#ffff" + current.toColorPart(); + } +} + + +Effect.Fade = Class.create(); +Effect.Fade.prototype = { + initialize: function(element) { + this.element = $(element); + this.start = 100; + this.finish = 0; + this.current = this.start; + this.fade(); + }, + + fade: function() { + if (this.isFinished()) { this.element.style.display = 'none'; return; } + if (this.timer) clearTimeout(this.timer); + this.setOpacity(this.element, this.current); + this.current -= 10; + this.timer = setTimeout(this.fade.bind(this), 50); + }, + + isFinished: function() { + return this.current <= this.finish; + }, + + setOpacity: function(element, opacity) { + opacity = (opacity == 100) ? 99.999 : opacity; + element.style.filter = "alpha(opacity:"+opacity+")"; + element.style.opacity = opacity/100 /*//*/; + } +} + +Effect.Scale = Class.create(); +Effect.Scale.prototype = { + initialize: function(element, percent) { + this.element = $(element); + this.startScale = 1.0; + this.startHeight = this.element.offsetHeight; + this.startWidth = this.element.offsetWidth; + this.currentHeight = this.startHeight; + this.currentWidth = this.startWidth; + this.finishScale = (percent/100) /*//*/; + if (this.element.style.fontSize=="") this.sizeEm = 1.0; + if (this.element.style.fontSize.indexOf("em")>0) + this.sizeEm = parseFloat(this.element.style.fontSize); + if(this.element.effect_scale) { + clearTimeout(this.element.effect_scale.timer); + this.startScale = this.element.effect_scale.currentScale; + this.startHeight = this.element.effect_scale.startHeight; + this.startWidth = this.element.effect_scale.startWidth; + if(this.element.effect_scale.sizeEm) + this.sizeEm = this.element.effect_scale.sizeEm; + } + this.element.effect_scale = this; + this.currentScale = this.startScale; + this.factor = this.finishScale - this.startScale; + this.options = arguments[2] || {}; + this.scale(); + }, + + scale: function() { + if (this.isFinished()) { + this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale); + if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em"; + if(this.options.complete) this.options.complete(this); + return; + } + if (this.timer) clearTimeout(this.timer); + if (this.options.step) this.options.step(this); + this.setDimensions(this.element, this.currentWidth, this.currentHeight); + if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em"; + this.currentScale += (this.factor/10) /*//*/; + this.currentWidth = this.startWidth * this.currentScale; + this.currentHeight = this.startHeight * this.currentScale; + this.timer = setTimeout(this.scale.bind(this), 50); + }, + + isFinished: function() { + return (this.factor < 0) ? + this.currentScale <= this.finishScale : this.currentScale >= this.finishScale; + }, + + setDimensions: function(element, width, height) { + element.style.width = width + 'px'; + element.style.height = height + 'px'; + } +} + +Effect.Squish = Class.create(); +Effect.Squish.prototype = { + initialize: function(element) { + this.element = $(element); + new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } ); + }, + hide: function() { + this.element.style.display = 'none'; + } +} + +Effect.Puff = Class.create(); +Effect.Puff.prototype = { + initialize: function(element) { + this.element = $(element); + this.opacity = 100; + this.startTop = this.element.top || this.element.offsetTop; + this.startLeft = this.element.left || this.element.offsetLeft; + new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } ); + }, + fade: function(effect) { + topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2; + leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2; + this.element.style.position='absolute'; + this.element.style.top = this.startTop-topd + "px"; + this.element.style.left = this.startLeft-leftd + "px"; + this.opacity -= 10; + this.setOpacity(this.element, this.opacity); + if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari + }, + hide: function() { + this.element.style.display = 'none'; + }, + setOpacity: function(element, opacity) { + opacity = (opacity == 100) ? 99.999 : opacity; + element.style.filter = "alpha(opacity:"+opacity+")"; + element.style.opacity = opacity/100 /*//*/; + } +} + +Effect.Appear = Class.create(); +Effect.Appear.prototype = { + initialize: function(element) { + this.element = $(element); + this.start = 0; + this.finish = 100; + this.current = this.start; + this.fade(); + }, + + fade: function() { + if (this.isFinished()) return; + if (this.timer) clearTimeout(this.timer); + this.setOpacity(this.element, this.current); + this.current += 10; + this.timer = setTimeout(this.fade.bind(this), 50); + }, + + isFinished: function() { + return this.current > this.finish; + }, + + setOpacity: function(element, opacity) { + opacity = (opacity == 100) ? 99.999 : opacity; + element.style.filter = "alpha(opacity:"+opacity+")"; + element.style.opacity = opacity/100 /*//*/; + element.style.display = ''; + } +} + +Effect.ContentZoom = Class.create(); +Effect.ContentZoom.prototype = { + initialize: function(element, percent) { + this.element = $(element); + if (this.element.style.fontSize=="") this.sizeEm = 1.0; + if (this.element.style.fontSize.indexOf("em")>0) + this.sizeEm = parseFloat(this.element.style.fontSize); + if(this.element.effect_contentzoom) { + this.sizeEm = this.element.effect_contentzoom.sizeEm; + } + this.element.effect_contentzoom = this; + this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/; + if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; }; + } +}