diff --git a/activemq-web/src/main/java/org/apache/activemq/web/MessageListenerServlet.java b/activemq-web/src/main/java/org/apache/activemq/web/MessageListenerServlet.java index 3a32678742..0f8219b785 100644 --- a/activemq-web/src/main/java/org/apache/activemq/web/MessageListenerServlet.java +++ b/activemq-web/src/main/java/org/apache/activemq/web/MessageListenerServlet.java @@ -41,6 +41,7 @@ import org.apache.activemq.MessageAvailableConsumer; import org.apache.activemq.MessageAvailableListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.mortbay.jetty.RetryRequest; import org.mortbay.util.ajax.Continuation; import org.mortbay.util.ajax.ContinuationSupport; @@ -61,7 +62,7 @@ public class MessageListenerServlet extends MessageServletSupport { private long defaultReadTimeout = -1; - private long maximumReadTimeout = 20000; + private long maximumReadTimeout = 10000; private int maximumMessages = 100; @@ -90,44 +91,85 @@ public class MessageListenerServlet extends MessageServletSupport { * @throws IOException */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // lets turn the HTTP post into a JMS Message - try { - WebClient client = getWebClient(request); - // System.err.println("POST client="+client+" - // session="+request.getSession().getId()+" - // info="+request.getPathInfo()+" query="+request.getQueryString()); - - String text = getPostedMessageBody(request); - - // lets create the destination from the URI? - Destination destination = getDestination(client, request); - if (destination == null) - throw new NoDestinationSuppliedException(); - - if (log.isDebugEnabled()) { - log.debug("Sending message to: " + destination + " with text: " + text); + + WebClient client = getWebClient(request); + + synchronized (client) { + + // System.err.println("POST client="+client+" session="+request.getSession().getId()+" info="+request.getPathInfo()+" contentType="+request.getContentType()); + + String[] destinations = request.getParameterValues("destination"); + String[] messages = request.getParameterValues("message"); + String[] types = request.getParameterValues("type"); + + if (destinations.length!=messages.length || messages.length!=types.length) + { + // System.err.println("ERROR destination="+destinations.length+" message="+messages.length+" type="+types.length); + response.sendError(HttpServletResponse.SC_BAD_REQUEST,"missmatched destination, message or type"); + return; + } + + for (int i=0;i"); - * writer.flush(); String m=swriter.toString(); - * System.err.println(m); response.getWriter().write(m); - * response.getWriter().flush(); - */ - } catch (JMSException e) { - throw new ServletException("Could not post JMS message: " + e, e); } + + if ("true".equals(request.getParameter("poll"))) + { + try + { + doMessages(client,request,response); + } + catch (JMSException e) + { + throw new ServletException("JMS problem: " + e, e); + } + } + // System.err.println("=="); } /** @@ -136,22 +178,25 @@ public class MessageListenerServlet extends MessageServletSupport { */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String end="--"; try { WebClient client = getWebClient(request); - // System.err.println("GET client="+client+" - // session="+request.getSession().getId()+" - // info="+request.getPathInfo()+" query="+request.getQueryString()); + // System.err.println("GET client="+client+" session="+request.getSession().getId()+" uri="+request.getRequestURI()+" query="+request.getQueryString()); - Destination destination = getDestination(client, request); - if (destination != null) - doSubscription(client, destination, request, response); - else - doMessages(client, request, response); + doMessages(client, request, response); + } + catch(RetryRequest r) + { + end="??"; + throw r; } - catch (JMSException e) { throw new ServletException("JMS problem: " + e, e); } + finally + { + // System.err.println(end); + } } @@ -171,7 +216,8 @@ public class MessageListenerServlet extends MessageServletSupport { // This is a poll for any messages long timeout = getReadTimeout(request); - + // System.err.println("doMessage timeout="+timeout); + Continuation continuation = null; Message message = null; @@ -220,9 +266,9 @@ public class MessageListenerServlet extends MessageServletSupport { // Send any message we already have if (message != null) { String id = (String) consumerIdMap.get(consumer); - writer.print("\n"); + writer.print("'>"); writeMessageResponse(writer, message); writer.println(""); messages++; @@ -238,9 +284,8 @@ public class MessageListenerServlet extends MessageServletSupport { message = consumer.receiveNoWait(); // System.err.println("received "+message+" from "+consumer); while (message != null && messages < maximumMessages) { - Destination destination = message.getJMSDestination(); String id = (String) consumerIdMap.get(consumer); - writer.print(""); writeMessageResponse(writer, message); @@ -251,13 +296,13 @@ public class MessageListenerServlet extends MessageServletSupport { } // Add poll message - writer.println(""); - writer.println(""); + // writer.println(""); + writer.print(""); writer.flush(); String m = swriter.toString(); // System.err.println(m); - response.getWriter().write(m); + response.getWriter().println(m); } } @@ -273,6 +318,7 @@ public class MessageListenerServlet extends MessageServletSupport { */ protected void doSubscription(WebClient client, Destination destination, HttpServletRequest request, HttpServletResponse response) throws JMSException, ServletException, IOException { + // System.err.println("doSubscription destination="+destination); String s = request.getParameter("listen"); if (s == null || s.length() == 0) { log.warn("No listen paramenter for subscribe"); diff --git a/activemq-web/src/main/java/org/apache/activemq/web/MessageServletSupport.java b/activemq-web/src/main/java/org/apache/activemq/web/MessageServletSupport.java index 1cf89b49c5..bddb6dc3f7 100644 --- a/activemq-web/src/main/java/org/apache/activemq/web/MessageServletSupport.java +++ b/activemq-web/src/main/java/org/apache/activemq/web/MessageServletSupport.java @@ -156,13 +156,16 @@ public abstract class MessageServletSupport extends HttpServlet { */ protected Destination getDestinationFromURI(WebClient client, HttpServletRequest request) throws JMSException { String uri = request.getPathInfo(); - if (uri == null) { + if (uri == null) return null; - } + // replace URI separator with JMS destination separator if (uri.startsWith("/")) { uri = uri.substring(1); + if (uri.length()==0) + return null; } + uri = uri.replace('/', '.'); System.err.println("destination uri="+uri); return getDestination(client, request, uri); @@ -172,7 +175,24 @@ public abstract class MessageServletSupport extends HttpServlet { * @return the Destination object for the given destination name */ protected Destination getDestination(WebClient client, HttpServletRequest request, String destinationName) throws JMSException { - if (isTopic(request)) { + + // TODO cache destinations ??? + + boolean is_topic=defaultTopicFlag; + if (destinationName.startsWith("topic://")) + { + is_topic=true; + destinationName=destinationName.substring(8); + } + else if (destinationName.startsWith("channel://")) + { + is_topic=true; + destinationName=destinationName.substring(10); + } + else + is_topic=isTopic(request); + + if (is_topic) { return client.getSession().createTopic(destinationName); } else { @@ -202,7 +222,7 @@ public abstract class MessageServletSupport extends HttpServlet { */ protected String getPostedMessageBody(HttpServletRequest request) throws IOException { String answer = request.getParameter(bodyParameter); - if (answer == null) { + if (answer == null && "text/xml".equals(request.getContentType())) { // lets read the message body instead BufferedReader reader = request.getReader(); StringBuffer buffer = new StringBuffer(); diff --git a/activemq-web/src/main/webapp/chat.js b/activemq-web/src/main/webapp/chat.js index fba55890ab..6d65ff17eb 100755 --- a/activemq-web/src/main/webapp/chat.js +++ b/activemq-web/src/main/webapp/chat.js @@ -4,8 +4,8 @@ var connection = null; -var chatTopic = "CHAT.DEMO"; -var chatMembership = "CHAT.DEMO"; +var chatTopic = "topic://CHAT.DEMO"; +var chatMembership = "topic://CHAT.DEMO"; @@ -40,10 +40,9 @@ var room = { username=name; - amq.addTopicListener('chat',chatTopic,room); - // amq.sendMessage(chatSubscription, "" + username + ""); - - // switch the input form + $('join').className='hidden'; + Behaviour.apply(); + amq.addListener('chat',chatTopic,this._chat); $('join').className='hidden'; $('joined').className=''; $('phrase').focus(); @@ -76,7 +75,7 @@ var room = } }, - amqMessage: function(message) + _chat: function(message) { var chat=$('chat'); var type=message.attributes['type'].value; diff --git a/activemq-web/src/main/webapp/index.html b/activemq-web/src/main/webapp/index.html index 8fe1646818..ebe4b48d2f 100755 --- a/activemq-web/src/main/webapp/index.html +++ b/activemq-web/src/main/webapp/index.html @@ -14,6 +14,8 @@ normal HTTP POST and to receive messages from a destination using a HTTP GET.

+

Currently only working with firefox!

+

Market data example

diff --git a/activemq-web/src/main/webapp/js/amq.js b/activemq-web/src/main/webapp/js/amq.js index dc6def9099..40a243892e 100644 --- a/activemq-web/src/main/webapp/js/amq.js +++ b/activemq-web/src/main/webapp/js/amq.js @@ -3,13 +3,87 @@ // AMQ handler var amq = { - first: true, - pollEvent: function(first) {}, + _first: true, + _pollEvent: function(first) {}, + _handlers: new Array(), + + _messages:0, + _messageQueue: '', + _queueMessages: false, + + _messageHandler: function(request) + { + try + { + if (request.status == 200) + { + var response = request.responseXML.getElementsByTagName("ajax-response"); + if (response != null && response.length == 1) + { + for ( var i = 0 ; i < response[0].childNodes.length ; i++ ) + { + var responseElement = response[0].childNodes[i]; + + // only process nodes of type element..... + if ( responseElement.nodeType != 1 ) + continue; + + var id = responseElement.getAttribute('id'); + + + var handler = amq._handlers[id]; + if (handler!=null) + { + for (var j = 0; j < responseElement.childNodes.length; j++) + { + var child = responseElement.childNodes[j] + if (child.nodeType == 1) + { + handler(child); + } + } + } + } + } + } + } + catch(e) + { + alert(e); + } + }, + + _pollHandler: function(request) + { + this._queueMessages=true; + try + { + amq._messageHandler(request); + amq._pollEvent(amq._first); + amq._first=false; + } + catch(e) + { + alert(e); + } + + this._queueMessages=false; + + if (this._messages==0) + new Ajax.Request('/amq', { method: 'get', onSuccess: amq._pollHandler }); + else + { + var body = this._messageQueue+'&poll=true'; + this._messageQueue=''; + this._messages=0; + new Ajax.Request('/amq', { method: 'post', onSuccess: amq._pollHandler, postBody: body }); + } + }, addPollHandler : function(func) { - var old = this.pollEvent; - this.pollEvent = function(first) + var old = this._pollEvent; + this._pollEvent = function(first) { old(first); func(first); @@ -18,63 +92,37 @@ var amq = sendMessage : function(destination,message) { - ajaxEngine.sendRequestWithData('amqSend', message, 'destination='+destination); + this._sendMessage(destination,message,'send'); }, - // Listen on a topic. handler must have a amqMessage method taking a message arguement - addTopicListener : function(id,topic,handler) + // Listen on a channel or topic. handler must be a function taking a message arguement + addListener : function(id,destination,handler) { - var ajax2amq = { ajaxUpdate: function(msg) { handler.amqMessage(amqFirstElement(msg)) } }; - ajaxEngine.registerAjaxObject(id, ajax2amq); - ajaxEngine.sendRequest('amqListen', 'destination='+topic+'&topic=true&id='+id+'&listen=true'); + amq._handlers[id]=handler; + this._sendMessage(destination,id,'listen'); }, - // Listen on a channel. handler must have a amqMessage method taking a message arguement - addChannelListener: function(id,channel,handler) + // remove Listener from channel or topic. + removeListener : function(destination) { - var ajax2amq = { ajaxUpdate: function(msg) { handler.amqMessage(amqFirstElement(msg)) } }; - ajaxEngine.registerAjaxObject(id, ajax2amq); - ajaxEngine.sendRequest('amqListen', 'destination='+channel+'&topic=false&id='+id+'&listen=true'); + this._sendMessage(destination,'','unlisten'); + }, + + _sendMessage : function(destination,message,type) + { + if (this._queueMessages) + { + this._messageQueue+=(this._messages==0?'destination=':'&destination=')+destination+'&message='+message+'&type='+type; + this._messages++; + } + else + { + new Ajax.Request('/amq', { method: 'post', postBody: 'destination='+destination+'&message='+message+'&type='+type}); + } } + }; -function initAMQ() -{ - // Register URLs. All the same at the moment and params are used to distinguish types - ajaxEngine.registerRequest('amqListen','/amq'); - ajaxEngine.registerRequest('amqPoll', '/amq'); - ajaxEngine.registerRequest('amqSend', '/amq'); - - var pollHandler = { - ajaxUpdate: function(ajaxResponse) - { - // Poll again for events - amq.pollEvent(amq.first); - amq.first=false; - ajaxEngine.sendRequest('amqPoll'); - } - }; - ajaxEngine.registerAjaxObject('amqPoll', pollHandler); - - var sendHandler = { - ajaxUpdate: function(ajaxResponse) - { - } - }; - ajaxEngine.registerAjaxObject('amqSend', sendHandler); - - ajaxEngine.sendRequest('amqPoll',"timeout=0"); // first poll to establish polling session ID -} -Behaviour.addLoadEvent(initAMQ); +Behaviour.addLoadEvent(function(){new Ajax.Request('/amq', { method: 'get', parameters: 'timeout=0', onSuccess: amq._pollHandler });}); - -function amqFirstElement(t) { - for (i = 0; i < t.childNodes.length; i++) { - var child = t.childNodes[i] - if (child.nodeType == 1) { - return child - } - } - return null -} diff --git a/activemq-web/src/main/webapp/js/default.js b/activemq-web/src/main/webapp/js/default.js index 7160b06a26..2c795c99b4 100644 --- a/activemq-web/src/main/webapp/js/default.js +++ b/activemq-web/src/main/webapp/js/default.js @@ -12,13 +12,7 @@ var DefaultJS = { var path = scriptTags[i].src.replace(/default\.js$/,''); this.script(path + 'prototype.js'); this.script(path + 'behaviour.js'); - - /* Ignore non-UI parts of Rico - this.script(path + 'rico.js'); - */ - this.script(path + 'ricoAjax.js'); - - this.script(path + 'scriptaculous.js'); + // this.script(path + 'scriptaculous.js'); this.script(path + 'amq.js'); break; } diff --git a/activemq-web/src/main/webapp/js/prototype.js b/activemq-web/src/main/webapp/js/prototype.js index 4172691adc..e9ccd3c885 100644 --- a/activemq-web/src/main/webapp/js/prototype.js +++ b/activemq-web/src/main/webapp/js/prototype.js @@ -1,8 +1,8 @@ -/* Prototype JavaScript framework, version 1.3.1 +/* Prototype JavaScript framework, version 1.4.0 * (c) 2005 Sam Stephenson * * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff - * against the source tree, available from the Prototype darcs repository. + * against the source tree, available from the Prototype darcs repository. * * Prototype is freely distributable under the terms of an MIT-style license. * @@ -11,13 +11,16 @@ /*--------------------------------------------------------------------------*/ var Prototype = { - Version: '1.3.1', - emptyFunction: function() {} + Version: '1.4.0', + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} } var Class = { create: function() { - return function() { + return function() { this.initialize.apply(this, arguments); } } @@ -32,29 +35,47 @@ Object.extend = function(destination, source) { return destination; } -Object.prototype.extend = function(object) { - return Object.extend.apply(this, [this, object]); +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } } -Function.prototype.bind = function(object) { - var __method = this; +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); return function() { - __method.apply(object, arguments); + return __method.apply(object, args.concat($A(arguments))); } } Function.prototype.bindAsEventListener = function(object) { var __method = this; return function(event) { - __method.call(object, event || window.event); + return __method.call(object, event || window.event); } } -Number.prototype.toColorPart = function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; -} +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); var Try = { these: function() { @@ -90,10 +111,10 @@ PeriodicalExecuter.prototype = { onTimerEvent: function() { if (!this.currentlyExecuting) { - try { + try { this.currentlyExecuting = true; - this.callback(); - } finally { + this.callback(); + } finally { this.currentlyExecuting = false; } } @@ -110,7 +131,7 @@ function $() { if (typeof element == 'string') element = document.getElementById(element); - if (arguments.length == 1) + if (arguments.length == 1) return element; elements.push(element); @@ -118,40 +139,27 @@ function $() { 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] = 'parameters[' + i + ']'; - - object.__apply__ = this; - var result = eval('object.__apply__(' + - parameterStrings.join(', ') + ')'); - object.__apply__ = null; - - return result; - } -} - -String.prototype.extend({ +Object.extend(String.prototype, { stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(eval); + }, + escapeHTML: function() { var div = document.createElement('div'); var text = document.createTextNode(this); @@ -162,10 +170,382 @@ String.prototype.extend({ unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); - return div.childNodes[0].nodeValue; + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; } }); +String.prototype.parseQuery = String.prototype.toQueryParams; + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value >= (result || value)) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value <= (result || value)) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + iterator(value = collections.pluck(index)); + return value; + }); + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + shift: function() { + var result = this[0]; + for (var i = 0; i < this.length - 1; i++) + this[i] = this[i + 1]; + this.length--; + return result; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +var Hash = { + _each: function(iterator) { + for (key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + var Ajax = { getTransport: function() { return Try.these( @@ -173,9 +553,50 @@ var Ajax = { function() {return new ActiveXObject('Microsoft.XMLHTTP')}, function() {return new XMLHttpRequest()} ) || false; - } + }, + + activeRequestCount: 0 } +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + Ajax.Base = function() {}; Ajax.Base.prototype = { setOptions: function(options) { @@ -183,12 +604,13 @@ Ajax.Base.prototype = { method: 'post', asynchronous: true, parameters: '' - }.extend(options || {}); + } + Object.extend(this.options, options || {}); }, responseIsSuccess: function() { return this.transport.status == undefined - || this.transport.status == 0 + || this.transport.status == 0 || (this.transport.status >= 200 && this.transport.status < 300); }, @@ -198,10 +620,10 @@ Ajax.Base.prototype = { } Ajax.Request = Class.create(); -Ajax.Request.Events = +Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; -Ajax.Request.prototype = (new Ajax.Base()).extend({ +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { initialize: function(url, options) { this.transport = Ajax.getTransport(); this.setOptions(options); @@ -213,10 +635,13 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({ if (parameters.length > 0) parameters += '&_='; try { - if (this.options.method == 'get') - url += (url.indexOf('?')<0?'?':'&') + parameters; + this.url = url; + if (this.options.method == 'get' && parameters.length > 0) + this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - this.transport.open(this.options.method, url, + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, this.options.asynchronous); if (this.options.asynchronous) { @@ -230,21 +655,22 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({ this.transport.send(this.options.method == 'post' ? body : null); } catch (e) { + this.dispatchException(e); } }, setRequestHeaders: function() { - var requestHeaders = + var requestHeaders = ['X-Requested-With', 'XMLHttpRequest', 'X-Prototype-Version', Prototype.Version]; if (this.options.method == 'post') { - requestHeaders.push('Content-type', + requestHeaders.push('Content-type', 'application/x-www-form-urlencoded'); /* Force "Connection: close" for Mozilla browsers to work around * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. + * header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType) requestHeaders.push('Connection', 'close'); @@ -263,26 +689,64 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({ this.respondToReadyState(this.transport.readyState); }, + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalJSON: function() { + try { + return eval(this.header('X-JSON')); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + respondToReadyState: function(readyState) { var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); - if (event == 'Complete') - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(this.transport); + if (event == 'Complete') { + try { + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } - (this.options['on' + event] || Prototype.emptyFunction)(this.transport); + if ((this.header('Content-type') || '').match(/^text\/javascript/i)) + this.evalResponse(); + } + + try { + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + } catch (e) { + this.dispatchException(e); + } /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ if (event == 'Complete') this.transport.onreadystatechange = Prototype.emptyFunction; + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Updater = Class.create(); -Ajax.Updater.ScriptFragment = '(?:)((\n|.)*?)(?:<\/script>)'; -Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({ +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { initialize: function(container, url, options) { this.containers = { success: container.success ? $(container.success) : $(container), @@ -294,9 +758,9 @@ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({ this.setOptions(options); var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function() { + this.options.onComplete = (function(transport, object) { this.updateContent(); - onComplete(this.transport); + onComplete(transport, object); }).bind(this); this.request(url); @@ -305,43 +769,34 @@ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({ updateContent: function() { var receiver = this.responseIsSuccess() ? this.containers.success : this.containers.failure; + var response = this.transport.responseText; - var match = new RegExp(Ajax.Updater.ScriptFragment, 'img'); - var response = this.transport.responseText.replace(match, ''); - var scripts = this.transport.responseText.match(match); + if (!this.options.evalScripts) + response = response.stripScripts(); if (receiver) { if (this.options.insertion) { new this.options.insertion(receiver, response); } else { - receiver.innerHTML = response; + Element.update(receiver, response); } } if (this.responseIsSuccess()) { if (this.onComplete) - setTimeout((function() {this.onComplete( - this.transport)}).bind(this), 10); - } - - if (this.options.evalScripts && 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), 10); + setTimeout(this.onComplete.bind(this), 10); } } }); Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({ +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { initialize: function(container, url, options) { this.setOptions(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); - this.decay = 1; + this.decay = (this.options.decay || 1); this.updater = {}; this.container = container; @@ -358,17 +813,17 @@ Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({ stop: function() { this.updater.onComplete = undefined; clearTimeout(this.timer); - (this.onComplete || Ajax.emptyFunction).apply(this, arguments); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(request) { if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? + this.decay = (request.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = request.responseText; } - this.timer = setTimeout(this.onTimerEvent.bind(this), + this.timer = setTimeout(this.onTimerEvent.bind(this), this.decay * this.frequency * 1000); }, @@ -376,23 +831,13 @@ Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({ this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); - -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; +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(child); + return elements; + }); } /*--------------------------------------------------------------------------*/ @@ -402,11 +847,14 @@ if (!window.Element) { } Object.extend(Element, { + visible: function(element) { + return $(element).style.display != 'none'; + }, + toggle: function() { for (var i = 0; i < arguments.length; i++) { var element = $(arguments[i]); - element.style.display = - (element.style.display == 'none' ? '' : 'none'); + Element[Element.visible(element) ? 'hide' : 'show'](element); } }, @@ -428,54 +876,142 @@ Object.extend(Element, { element = $(element); element.parentNode.removeChild(element); }, - + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + getHeight: function(element) { element = $(element); - return element.offsetHeight; + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); }, hasClassName: function(element, className) { - element = $(element); - if (!element) - return; - var a = element.className.split(' '); - for (var i = 0; i < a.length; i++) { - if (a[i] == className) - return true; - } - return false; + if (!(element = $(element))) return; + return Element.classNames(element).include(className); }, addClassName: function(element, className) { - element = $(element); - Element.removeClassName(element, className); - element.className += ' ' + className; + if (!(element = $(element))) return; + return Element.classNames(element).add(className); }, removeClassName: function(element, className) { - element = $(element); - if (!element) - return; - var newClassName = ''; - var a = element.className.split(' '); - for (var i = 0; i < a.length; i++) { - if (a[i] != className) { - if (i > 0) - newClassName += ' '; - newClassName += a[i]; - } - } - element.className = newClassName; + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); }, - + // removes whitespace-only text node children cleanWhitespace: function(element) { - var element = $(element); + element = $(element); for (var i = 0; i < element.childNodes.length; i++) { var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) Element.remove(node); } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; } }); @@ -491,68 +1027,127 @@ Abstract.Insertion = function(adjacency) { Abstract.Insertion.prototype = { initialize: function(element, content) { this.element = $(element); - this.content = content; - + this.content = content.stripScripts(); + if (this.adjacency && this.element.insertAdjacentHTML) { - this.element.insertAdjacentHTML(this.adjacency, this.content); + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + if (this.element.tagName.toLowerCase() == 'tbody') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } } else { this.range = this.element.ownerDocument.createRange(); if (this.initializeRange) this.initializeRange(); - this.fragment = this.range.createContextualFragment(this.content); - this.insertContent(); + this.insertContent([this.range.createContextualFragment(this.content)]); } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
'; + return $A(div.childNodes[0].childNodes[0].childNodes); } } var Insertion = new Object(); Insertion.Before = Class.create(); -Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({ +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { initializeRange: function() { this.range.setStartBefore(this.element); }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, this.element); + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); } }); Insertion.Top = Class.create(); -Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({ +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { initializeRange: function() { this.range.selectNodeContents(this.element); this.range.collapse(true); }, - - insertContent: function() { - this.element.insertBefore(this.fragment, this.element.firstChild); + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); } }); Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({ +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { initializeRange: function() { this.range.selectNodeContents(this.element); this.range.collapse(this.element); }, - - insertContent: function() { - this.element.appendChild(this.fragment); + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); } }); Insertion.After = Class.create(); -Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { initializeRange: function() { this.range.setStartAfter(this.element); }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, - this.element.nextSibling); + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); } }); +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); var Field = { clear: function() { for (var i = 0; i < arguments.length; i++) @@ -562,20 +1157,22 @@ var Field = { 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(); + element = $(element); + element.focus(); + if (element.select) + element.select(); } } @@ -585,18 +1182,18 @@ 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) { - var form = $(form); + form = $(form); var elements = new Array(); for (tagName in Form.Element.Serializers) { @@ -606,19 +1203,19 @@ var Form = { } return elements; }, - + getInputs: function(form, typeName, name) { - var form = $(form); + form = $(form); var inputs = form.getElementsByTagName('input'); - + if (!typeName && !name) return inputs; - + var matchingInputs = new Array(); for (var i = 0; i < inputs.length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || - (name && input.name != name)) + (name && input.name != name)) continue; matchingInputs.push(input); } @@ -643,16 +1240,15 @@ var Form = { } }, + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + focusFirstElement: function(form) { - var 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; - } - } + Field.activate(Form.findFirstElement(form)); }, reset: function(form) { @@ -662,21 +1258,29 @@ var Form = { Form.Element = { serialize: function(element) { - var element = $(element); + element = $(element); var method = element.tagName.toLowerCase(); var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return encodeURIComponent(parameter[0]) + '=' + - encodeURIComponent(parameter[1]); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } }, - + getValue: function(element) { - var element = $(element); + element = $(element); var method = element.tagName.toLowerCase(); var parameter = Form.Element.Serializers[method](element); - - if (parameter) + + if (parameter) return parameter[1]; } } @@ -689,7 +1293,7 @@ Form.Element.Serializers = { case 'password': case 'text': return Form.Element.Serializers.textarea(element); - case 'checkbox': + case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element); } @@ -706,17 +1310,30 @@ Form.Element.Serializers = { }, select: function(element) { - var value = ''; - if (element.type == 'select-one') { - var index = element.selectedIndex; - if (index >= 0) - value = element.options[index].value || element.options[index].text; - } else { - value = new Array(); - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) - value.push(opt.value || opt.text); + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value; + if (!value && !('value' in opt)) + value = opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = new Array(); + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) { + var optValue = opt.value; + if (!optValue && !('value' in opt)) + optValue = opt.text; + value.push(optValue); } } return [element.name, value]; @@ -735,15 +1352,15 @@ Abstract.TimedObserver.prototype = { this.frequency = frequency; this.element = $(element); this.callback = callback; - + this.lastValue = this.getValue(); this.registerCallback(); }, - + registerCallback: function() { setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, - + onTimerEvent: function() { var value = this.getValue(); if (this.lastValue != value) { @@ -754,14 +1371,14 @@ Abstract.TimedObserver.prototype = { } Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({ +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(); -Form.Observer.prototype = (new Abstract.TimedObserver()).extend({ +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { getValue: function() { return Form.serialize(this.element); } @@ -774,14 +1391,14 @@ Abstract.EventObserver.prototype = { initialize: function(element, callback) { this.element = $(element); this.callback = callback; - + this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, - + onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { @@ -789,57 +1406,45 @@ Abstract.EventObserver.prototype = { this.lastValue = value; } }, - + registerFormCallbacks: function() { var elements = Form.getElements(this.element); for (var i = 0; i < elements.length; i++) this.registerCallback(elements[i]); }, - + registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { - case 'checkbox': + case 'checkbox': case 'radio': - element.target = this; - element.prev_onclick = element.onclick || Prototype.emptyFunction; - element.onclick = function() { - this.prev_onclick(); - this.target.onElementEvent(); - } + Event.observe(element, 'click', this.onElementEvent.bind(this)); break; case 'password': case 'text': case 'textarea': case 'select-one': case 'select-multiple': - element.target = this; - element.prev_onchange = element.onchange || Prototype.emptyFunction; - element.onchange = function() { - this.prev_onchange(); - this.target.onElementEvent(); - } + Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } - } + } } } Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({ +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(); -Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({ +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { getValue: function() { return Form.serialize(this.element); } }); - - if (!window.Event) { var Event = new Object(); } @@ -865,21 +1470,22 @@ Object.extend(Event, { }, pointerX: function(event) { - return event.pageX || (event.clientX + + return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); }, pointerY: function(event) { - return event.pageY || (event.clientY + + return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); }, stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); } else { event.returnValue = false; + event.cancelBubble = true; } }, @@ -894,7 +1500,7 @@ Object.extend(Event, { }, observers: false, - + _observeAndCache: function(element, name, observer, useCapture) { if (!this.observers) this.observers = []; if (element.addEventListener) { @@ -905,7 +1511,7 @@ Object.extend(Event, { element.attachEvent('on' + name, observer); } }, - + unloadCache: function() { if (!Event.observers) return; for (var i = 0; i < Event.observers.length; i++) { @@ -918,24 +1524,24 @@ Object.extend(Event, { observe: function(element, name, observer, useCapture) { var element = $(element); useCapture = useCapture || false; - + if (name == 'keypress' && - ((navigator.appVersion.indexOf('AppleWebKit') > 0) + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent)) name = 'keydown'; - + this._observeAndCache(element, name, observer, useCapture); }, stopObserving: function(element, name, observer, useCapture) { var element = $(element); useCapture = useCapture || false; - + if (name == 'keypress' && - ((navigator.appVersion.indexOf('AppleWebKit') > 0) + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.detachEvent)) name = 'keydown'; - + if (element.removeEventListener) { element.removeEventListener(name, observer, useCapture); } else if (element.detachEvent) { @@ -946,24 +1552,22 @@ Object.extend(Event, { /* prevent memory leaks in IE */ Event.observe(window, 'unload', Event.unloadCache, false); - var Position = { - // set to true if needed, warning: firefox performance problems // NOT neeeded for page scrolling, only if draggable contained in // scrollable elements - includeScrollOffsets: false, + includeScrollOffsets: false, // must be called before calling withinIncludingScrolloffset, every time the // page is scrolled prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop || 0; }, @@ -971,7 +1575,7 @@ var Position = { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; + valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return [valueL, valueT]; @@ -987,6 +1591,31 @@ var Position = { return [valueL, valueT]; }, + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + // caches x/y coordinate pair to use with overlap within: function(element, x, y) { if (this.includeScrollOffsets) @@ -997,7 +1626,7 @@ var Position = { return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && + x >= this.offset[0] && x < this.offset[0] + element.offsetWidth); }, @@ -1010,18 +1639,18 @@ var Position = { return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && + this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth; }, @@ -1034,5 +1663,123 @@ var Position = { target.style.left = offsets[0] + 'px'; target.style.width = source.offsetWidth + 'px'; target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px';; + element.style.left = left + 'px';; + element.style.width = width + 'px';; + element.style.height = height + 'px';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; } } + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} \ No newline at end of file diff --git a/activemq-web/src/main/webapp/js/rico.js b/activemq-web/src/main/webapp/js/rico.js deleted file mode 100644 index 4bdc95b437..0000000000 --- a/activemq-web/src/main/webapp/js/rico.js +++ /dev/null @@ -1,2667 +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.1-beta2' -} - -Rico.ArrayExtensions = new Array(); - -if (Object.prototype.extend) { - // in prototype.js... - 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; i 1 ) - queryString = this._createQueryString(arguments, 1); - - new Ajax.Request(requestURL, this._requestOptions(queryString)); - }, - - sendRequestWithData: function(requestName, xmlDocument) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 2 ) - queryString = this._createQueryString(arguments, 2); - - new Ajax.Request(requestURL + (requestURL.indexOf("?")<0?"?":"&") + queryString, this._requestOptions(null,xmlDocument)); - }, - - sendRequestAndUpdate: function(requestName,container,options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 3 ) - queryString = this._createQueryString(arguments, 3); - - var updaterOptions = this._requestOptions(queryString); - updaterOptions.onComplete = null; - updaterOptions.extend(options); - - new Ajax.Updater(container, requestURL, updaterOptions); - }, - - sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 4 ) - queryString = this._createQueryString(arguments, 4); - - - var updaterOptions = this._requestOptions(queryString,xmlDocument); - updaterOptions.onComplete = null; - updaterOptions.extend(options); - - new Ajax.Updater(container, requestURL + (requestURL.indexOf("?")<0?"?":"&") + queryString, updaterOptions); - }, - - // Private -- not part of intended engine API -------------------------------------------------------------------- - - _requestOptions: function(queryString,xmlDoc) { - var self = this; - - var requestHeaders = ['X-Rico-Version', Rico.Version ]; - var sendMethod = "post" - if ( arguments[1] ) - requestHeaders.push( 'Content-type', 'text/xml' ); - else - sendMethod = "get"; - - return { requestHeaders: requestHeaders, - parameters: queryString, - postBody: arguments[1] ? xmlDoc : null, - method: sendMethod, - onComplete: self._onRequestComplete.bind(self) }; - }, - - _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) { - - //!!TODO: error handling infrastructure?? - if (request.status != 200) - return; - - var response = request.responseXML.getElementsByTagName("ajax-response"); - - if (response == null || response.length != 1) - return; - this._processAjaxResponse( response[0].childNodes ); - }, - - _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 - }.extend(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"; - } - }, - - _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; - }, - - 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) } ); - } - }, - - _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() ) { - 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 ) - { - var htmlElement = aDraggable.getMouseDownHTMLElement(); - if ( htmlElement != null ) { - htmlElement.draggable = aDraggable; - this._addMouseDownEvent( htmlElement ); - } - }, - - _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; - }, - - _addMouseDownEvent: function( htmlElement ) { - if ( typeof document.implementation != "undefined" && - document.implementation.hasFeature("HTML", "1.0") && - document.implementation.hasFeature("Events", "2.0") && - document.implementation.hasFeature("CSS", "2.0") ) { - htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false); - } - else { - htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) ); - } - }, - - _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; - }, - - initializeEventHandlers: function() { - if ( typeof document.implementation != "undefined" && - document.implementation.hasFeature("HTML", "1.0") && - document.implementation.hasFeature("Events", "2.0") && - document.implementation.hasFeature("CSS", "2.0") ) { - document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false); - document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false); - } - else { - document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) ); - document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) ); - } - } -} - -var dndMgr = new Rico.DragAndDrop(); -dndMgr.initializeEventHandlers(); - - -//-------------------- 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); - } - } -} - - -//-------------------- 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; - if ( this.element.currentStyle ) { - opacity = this.element.currentStyle.opacity; - } - else if ( document.defaultView.getComputedStyle != undefined ) { - var computedStyle = document.defaultView.getComputedStyle; - opacity = computedStyle(this.element, null).getPropertyValue('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.scrollArrowHeight = 16; - this.columnCount = columnCount; - }, - - setOptions: function(options) { - this.options = { - largeBufferSize : 7.0, // 7 pages - nearLimitFactor : 0.2 // 20% of buffer - }.extend(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 = "1px solid #ababab"; // hard coded color!!! - 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 ); - }, - - 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 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 ); - }, - - 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; - } 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) { - 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; - }, - - 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(this.div.style.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 ) { - if ( options == null ) - options = {}; - - this.tableId = tableId; - this.table = $(tableId); - 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.additionalParms = options.requestParameters || []; - - options.sortHandler = this.sortHandler.bind(this); - - if ( $(tableId + '_header') ) - this.sort = new Rico.LiveGridSort(tableId + '_header', options) - - this.processingRequest = null; - this.unprocessedRequest = null; - - this.initAjax(url); - if ( options.prefetchBuffer || options.prefetchOffset > 0) { - var offset = 0; - if (options.offset ) { - offset = options.offset; - this.scroller.moveScroll(offset); - this.viewPort.scrollTo(this.scroller.rowToPixel(offset)); - } - if (options.sortCol) { - this.sortCol = options.sortCol; - this.sortDir = options.sortDir; - } - this.requestContentRefresh(offset); - } - }, - - 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) - }, - - setRequestParams: function() { - this.additionalParms = []; - for ( var i=0 ; i < arguments.length ; i++ ) - this.additionalParms[i] = arguments[i]; - }, - - 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 callParms = []; - callParms.push(this.tableId + '_request'); - callParms.push('id=' + this.tableId); - callParms.push('page_size=' + fetchSize); - callParms.push('offset=' + bufferStartPos); - if ( this.sortCol) { - callParms.push('sort_col=' + this.sortCol); - callParms.push('sort_dir=' + this.sortDir); - } - - for( var i=0 ; i < this.additionalParms.length ; i++ ) - callParms.push(this.additionalParms[i]); - ajaxEngine.sendRequest.apply( ajaxEngine, callParms ); - - this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), 20000 ); //todo: make as option - }, - - 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(); - }, - - 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.setOptions(options); - 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(options) { - this.options = { - sortAscendImg: 'images/sort_asc.gif', - sortDescendImg: 'images/sort_desc.gif', - imageWidth: 9, - imageHeight: 5, - ajaxSortURLParms: [] - }.extend(options); - - // preload the images... - new Image().src = this.options.sortAscendImg; - new Image().src = this.options.sortDescendImg; - - this.sort = 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] ) ); - }, - - 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 .SET_DESC... - this.currentSort = direction; - } - -}; - - -//-------------------- ricoUtil.js - -var RicoUtil = { - - getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) { - if ( arguments.length == 2 ) - mozillaEquivalentCSS = cssProperty; - - var el = $(htmlElement); - if ( el.currentStyle ) - return el.currentStyle[cssProperty]; - else - return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS); - }, - - createXmlDocument : function() { - if (document.implementation && document.implementation.createDocument) { - var doc = document.implementation.createDocument("", "", null); - - if (doc.readyState == null) { - doc.readyState = 1; - doc.addEventListener("load", function () { - doc.readyState = 4; - if (typeof doc.onreadystatechange == "function") - doc.onreadystatechange(); - }, false); - } - - return doc; - } - - if (window.ActiveXObject) - return Try.these( - function() { return new ActiveXObject('MSXML2.DomDocument') }, - function() { return new ActiveXObject('Microsoft.DomDocument')}, - function() { return new ActiveXObject('MSXML.DomDocument') }, - function() { return new ActiveXObject('MSXML3.DomDocument') } - ) || false; - - return null; - }, - - getContentAsString: function( parentNode ) { - return parentNode.xml != undefined ? - this._getContentAsStringIE(parentNode) : - this._getContentAsStringMozilla(parentNode); - }, - - _getContentAsStringIE: function(parentNode) { - var contentStr = ""; - for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) - contentStr += parentNode.childNodes[i].xml; - return contentStr; - }, - - _getContentAsStringMozilla: function(parentNode) { - var xmlSerializer = new XMLSerializer(); - var contentStr = ""; - for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) - contentStr += xmlSerializer.serializeToString(parentNode.childNodes[i]); - return contentStr; - }, - - toViewportPosition: function(element) { - return this._toAbsolute(element,true); - }, - - toDocumentPosition: function(element) { - return this._toAbsolute(element,false); - }, - - /** - * Compute the elements position in terms of the window viewport - * so that it can be compared to the position of the mouse (dnd) - * This is additions of all the offsetTop,offsetLeft values up the - * offsetParent hierarchy, ...taking into account any scrollTop, - * scrollLeft values along the way... - * - * IE has a bug reporting a correct offsetLeft of elements within a - * a relatively positioned parent!!! - **/ - _toAbsolute: function(element,accountForDocScroll) { - - if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 ) - return this._toAbsoluteMozilla(element,accountForDocScroll); - - var x = 0; - var y = 0; - var parent = element; - while ( parent ) { - - var borderXOffset = 0; - var borderYOffset = 0; - if ( parent != element ) { - var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" )); - var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" )); - borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset; - borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset; - } - - x += parent.offsetLeft - parent.scrollLeft + borderXOffset; - y += parent.offsetTop - parent.scrollTop + borderYOffset; - parent = parent.offsetParent; - } - - if ( accountForDocScroll ) { - x -= this.docScrollLeft(); - y -= this.docScrollTop(); - } - - return { x:x, y:y }; - }, - - /** - * Mozilla did not report all of the parents up the hierarchy via the - * offsetParent property that IE did. So for the calculation of the - * offsets we use the offsetParent property, but for the calculation of - * the scrollTop/scrollLeft adjustments we navigate up via the parentNode - * property instead so as to get the scroll offsets... - * - **/ - _toAbsoluteMozilla: function(element,accountForDocScroll) { - var x = 0; - var y = 0; - var parent = element; - while ( parent ) { - x += parent.offsetLeft; - y += parent.offsetTop; - parent = parent.offsetParent; - } - - parent = element; - while ( parent && - parent != document.body && - parent != document.documentElement ) { - if ( parent.scrollLeft ) - x -= parent.scrollLeft; - if ( parent.scrollTop ) - y -= parent.scrollTop; - parent = parent.parentNode; - } - - if ( accountForDocScroll ) { - x -= this.docScrollLeft(); - y -= this.docScrollTop(); - } - - return { x:x, y:y }; - }, - - docScrollLeft: function() { - if ( window.pageXOffset ) - return window.pageXOffset; - else if ( document.documentElement && document.documentElement.scrollLeft ) - return document.documentElement.scrollLeft; - else if ( document.body ) - return document.body.scrollLeft; - else - return 0; - }, - - docScrollTop: function() { - if ( window.pageYOffset ) - return window.pageYOffset; - else if ( document.documentElement && document.documentElement.scrollTop ) - return document.documentElement.scrollTop; - else if ( document.body ) - return document.body.scrollTop; - else - return 0; - } - -}; diff --git a/activemq-web/src/main/webapp/js/ricoAjax.js b/activemq-web/src/main/webapp/js/ricoAjax.js deleted file mode 100644 index 9ba355c985..0000000000 --- a/activemq-web/src/main/webapp/js/ricoAjax.js +++ /dev/null @@ -1,469 +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.1-beta2' -} - -Rico.ArrayExtensions = new Array(); - -if (Object.prototype.extend) { - // in prototype.js... - 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; i 1 ) - queryString = this._createQueryString(arguments, 1); - - new Ajax.Request(requestURL, this._requestOptions(queryString)); - }, - - sendRequestWithData: function(requestName, xmlDocument) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 2 ) - queryString = this._createQueryString(arguments, 2); - - new Ajax.Request(requestURL + (requestURL.indexOf("?")<0?"?":"&") + queryString, this._requestOptions(null,xmlDocument)); - }, - - sendRequestAndUpdate: function(requestName,container,options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 3 ) - queryString = this._createQueryString(arguments, 3); - - var updaterOptions = this._requestOptions(queryString); - updaterOptions.onComplete = null; - updaterOptions.extend(options); - - new Ajax.Updater(container, requestURL, updaterOptions); - }, - - sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) { - var requestURL = this.requestURLS[requestName]; - if ( requestURL == null ) - return; - - var queryString = ""; - if ( arguments.length > 4 ) - queryString = this._createQueryString(arguments, 4); - - - var updaterOptions = this._requestOptions(queryString,xmlDocument); - updaterOptions.onComplete = null; - updaterOptions.extend(options); - - new Ajax.Updater(container, requestURL + (requestURL.indexOf("?")<0?"?":"&") + queryString, updaterOptions); - }, - - // Private -- not part of intended engine API -------------------------------------------------------------------- - - _requestOptions: function(queryString,xmlDoc) { - var self = this; - - var requestHeaders = ['X-Rico-Version', Rico.Version ]; - var sendMethod = "post" - if ( arguments[1] ) - requestHeaders.push( 'Content-type', 'text/xml' ); - else - sendMethod = "get"; - - return { requestHeaders: requestHeaders, - parameters: queryString, - postBody: arguments[1] ? xmlDoc : null, - method: sendMethod, - onComplete: self._onRequestComplete.bind(self) }; - }, - - _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) { - - //!!TODO: error handling infrastructure?? - if (request.status != 200) - return; - - var response = request.responseXML.getElementsByTagName("ajax-response"); - - if (response == null || response.length != 1) - return; - this._processAjaxResponse( response[0].childNodes ); - }, - - _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 ) { - if (ajaxElement) { - ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement); - } - } - -} - -var ajaxEngine = new Rico.AjaxEngine(); - - -//-------------------- ricoUtil.js - -var RicoUtil = { - - getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) { - if ( arguments.length == 2 ) - mozillaEquivalentCSS = cssProperty; - - var el = $(htmlElement); - if ( el.currentStyle ) - return el.currentStyle[cssProperty]; - else - return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS); - }, - - createXmlDocument : function() { - if (document.implementation && document.implementation.createDocument) { - var doc = document.implementation.createDocument("", "", null); - - if (doc.readyState == null) { - doc.readyState = 1; - doc.addEventListener("load", function () { - doc.readyState = 4; - if (typeof doc.onreadystatechange == "function") - doc.onreadystatechange(); - }, false); - } - - return doc; - } - - if (window.ActiveXObject) - return Try.these( - function() { return new ActiveXObject('MSXML2.DomDocument') }, - function() { return new ActiveXObject('Microsoft.DomDocument')}, - function() { return new ActiveXObject('MSXML.DomDocument') }, - function() { return new ActiveXObject('MSXML3.DomDocument') } - ) || false; - - return null; - }, - - getContentAsString: function( parentNode ) { - return parentNode.xml != undefined ? - this._getContentAsStringIE(parentNode) : - this._getContentAsStringMozilla(parentNode); - }, - - _getContentAsStringIE: function(parentNode) { - var contentStr = ""; - for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) - contentStr += parentNode.childNodes[i].xml; - return contentStr; - }, - - _getContentAsStringMozilla: function(parentNode) { - var xmlSerializer = new XMLSerializer(); - var contentStr = ""; - for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) - contentStr += xmlSerializer.serializeToString(parentNode.childNodes[i]); - return contentStr; - }, - - toViewportPosition: function(element) { - return this._toAbsolute(element,true); - }, - - toDocumentPosition: function(element) { - return this._toAbsolute(element,false); - }, - - /** - * Compute the elements position in terms of the window viewport - * so that it can be compared to the position of the mouse (dnd) - * This is additions of all the offsetTop,offsetLeft values up the - * offsetParent hierarchy, ...taking into account any scrollTop, - * scrollLeft values along the way... - * - * IE has a bug reporting a correct offsetLeft of elements within a - * a relatively positioned parent!!! - **/ - _toAbsolute: function(element,accountForDocScroll) { - - if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 ) - return this._toAbsoluteMozilla(element,accountForDocScroll); - - var x = 0; - var y = 0; - var parent = element; - while ( parent ) { - - var borderXOffset = 0; - var borderYOffset = 0; - if ( parent != element ) { - var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" )); - var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" )); - borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset; - borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset; - } - - x += parent.offsetLeft - parent.scrollLeft + borderXOffset; - y += parent.offsetTop - parent.scrollTop + borderYOffset; - parent = parent.offsetParent; - } - - if ( accountForDocScroll ) { - x -= this.docScrollLeft(); - y -= this.docScrollTop(); - } - - return { x:x, y:y }; - }, - - /** - * Mozilla did not report all of the parents up the hierarchy via the - * offsetParent property that IE did. So for the calculation of the - * offsets we use the offsetParent property, but for the calculation of - * the scrollTop/scrollLeft adjustments we navigate up via the parentNode - * property instead so as to get the scroll offsets... - * - **/ - _toAbsoluteMozilla: function(element,accountForDocScroll) { - var x = 0; - var y = 0; - var parent = element; - while ( parent ) { - x += parent.offsetLeft; - y += parent.offsetTop; - parent = parent.offsetParent; - } - - parent = element; - while ( parent && - parent != document.body && - parent != document.documentElement ) { - if ( parent.scrollLeft ) - x -= parent.scrollLeft; - if ( parent.scrollTop ) - y -= parent.scrollTop; - parent = parent.parentNode; - } - - if ( accountForDocScroll ) { - x -= this.docScrollLeft(); - y -= this.docScrollTop(); - } - - return { x:x, y:y }; - }, - - docScrollLeft: function() { - if ( window.pageXOffset ) - return window.pageXOffset; - else if ( document.documentElement && document.documentElement.scrollLeft ) - return document.documentElement.scrollLeft; - else if ( document.body ) - return document.body.scrollLeft; - else - return 0; - }, - - docScrollTop: function() { - if ( window.pageYOffset ) - return window.pageYOffset; - else if ( document.documentElement && document.documentElement.scrollTop ) - return document.documentElement.scrollTop; - else if ( document.body ) - return document.body.scrollTop; - else - return 0; - } - -}; diff --git a/activemq-web/src/main/webapp/portfolio/portfolio.js b/activemq-web/src/main/webapp/portfolio/portfolio.js index 4e3874f640..cf4239f818 100644 --- a/activemq-web/src/main/webapp/portfolio/portfolio.js +++ b/activemq-web/src/main/webapp/portfolio/portfolio.js @@ -3,7 +3,7 @@ var priceHandler = { - amqMessage: function(message) + _price: function(message) { if (message != null) { @@ -36,7 +36,7 @@ function portfolioPoll(first) { if (first) { - amq.addTopicListener('stocks','STOCKS.*',priceHandler); + amq.addListener('stocks','topic://STOCKS.*',priceHandler._price); } }