Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/cpaint2.inc.js
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/cpaint2.inc.js?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/cpaint2.inc.js (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/cpaint2.inc.js Wed May 3 14:24:53 2006
@@ -0,0 +1,1127 @@
+/**
+* CPAINT - Cross-Platform Asynchronous INterface Toolkit
+*
+* http://cpaint.sourceforge.net
+*
+* released under the terms of the LGPL
+* see http://www.fsf.org/licensing/licenses/lgpl.txt for details
+*
+* $Id$
+* $Log$
+* Revision 1.19 2005/09/03 16:40:21 saloon12yrd
+* 2.0.1 RC1
+* - improved AJAX capability check
+* - taking use_cpaint_api == false into account in cpaint_call.call_proxy()
+* - updated versions
+* - updated changelog
+* - added text changelog to release branch
+*
+* Revision 1.17 2005/08/17 15:52:04 saloon12yrd
+* added automatic detection / conversion of numeric values
+*
+* Revision 1.10 2005/08/02 19:02:43 saloon12yrd
+* removed debugging code
+*
+* Revision 1.5 2005/07/14 17:14:20 saloon12yrd
+* added support for arbitrary XML attributes
+*
+*
+* @package CPAINT
+* @access public
+* @copyright Copyright (c) 2005 Paul Sullivan, Dominique Stender - http://cpaint.sourceforge.net
+* @author Paul Sullivan <wiley14@gmail.com>
+* @author Dominique Stender <dstender@st-webdevelopment.de>
+* @version 2.0.1
+*/
+function cpaint() {
+ /**
+ * configuration options both for this class but also for the cpaint_call() objects.
+ *
+ * @access protected
+ * @var array config
+ */
+ var config = new Array();
+ config['debugging'] = 0;
+ config['proxy_url'] = '';
+ config['transfer_mode'] = 'GET';
+ config['async'] = true;
+ config['response_type'] = 'OBJECT';
+ config['persistent_connection'] = false;
+ config['use_cpaint_api'] = true;
+
+ /**
+ * maintains the next free index in the stack
+ *
+ * @access protected
+ * @var integer stack_count
+ */
+ var stack_count = 0;
+
+ /**
+ * property returns whether or not the browser is AJAX capable
+ *
+ * @access public
+ * @return boolean
+ */
+ this.capable = test_ajax_capability();
+
+ /**
+ * switches debug mode on/off.
+ *
+ * @access public
+ * @param boolean debug debug flag
+ * @return void
+ */
+ this.set_debug = function() {
+
+ if (typeof arguments[0] == 'boolean') {
+ if (arguments[0] === true) {
+ config['debugging'] = 1;
+
+ } else {
+ config['debugging'] = 0;
+ }
+
+ } else if (typeof arguments[0] == 'number') {
+ config['debugging'] = Math.round(arguments[0]);
+ }
+ }
+
+ /**
+ * defines the URL of the proxy script.
+ *
+ * @access public
+ * @param string proxy_url URL of the proxyscript to connect
+ * @return void
+ */
+ this.set_proxy_url = function() {
+
+ if (typeof arguments[0] == 'string') {
+
+ config['proxy_url'] = arguments[0];
+ }
+ }
+
+ /**
+ * sets the transfer_mode (GET|POST).
+ *
+ * @access public
+ * @param string transfer_mode transfer_mode
+ * @return void
+ */
+ this.set_transfer_mode = function() {
+
+ if (arguments[0].toUpperCase() == 'GET'
+ || arguments[0].toUpperCase() == 'POST') {
+
+ config['transfer_mode'] = arguments[0].toUpperCase();
+ }
+ }
+
+ /**
+ * sets the flag whether or not to use asynchronous calls.
+ *
+ * @access public
+ * @param boolean async syncronization flag
+ * @return void
+ */
+ this.set_async = function() {
+
+ if (typeof arguments[0] == 'boolean') {
+ config['async'] = arguments[0];
+ }
+ }
+
+ /**
+ * defines the response type.
+ *
+ * allowed values are:
+ * TEXT = raw text response
+ * XML = raw XMLHttpObject
+ * OBJECT = parsed JavaScript object structure from XMLHttpObject
+ *
+ * the default is OBJECT.
+ *
+ * @access public
+ * @param string response_type response type
+ * @return void
+ */
+ this.set_response_type = function() {
+
+ if (arguments[0].toUpperCase() == 'TEXT'
+ || arguments[0].toUpperCase() == 'XML'
+ || arguments[0].toUpperCase() == 'OBJECT') {
+
+ config['response_type'] = arguments[0].toUpperCase();
+ }
+ }
+
+ /**
+ * sets the flag whether or not to use a persistent connection.
+ *
+ * @access public
+ * @param boolean persistent_connection persistance flag
+ * @return void
+ */
+ this.set_persistent_connection = function() {
+
+ if (typeof arguments[0] == 'boolean') {
+ config['persistent_connection'] = arguments[0];
+ }
+ }
+
+
+ /**
+ * sets the flag whether or not to use the cpaint api on the backend.
+ *
+ * @access public
+ * @param boolean cpaint_api api_flag
+ * @return void
+ */
+ this.set_use_cpaint_api = function() {
+ if (typeof arguments[0] == 'boolean') {
+ config['use_cpaint_api'] = arguments[0];
+ }
+ }
+
+ /**
+ * tests whether one of the necessary implementations
+ * of the XMLHttpRequest class are available
+ *
+ * @access protected
+ * @return boolean
+ */
+ function test_ajax_capability() {
+ var cpc = new cpaint_call(0);
+
+ return cpc.test_ajax_capability();
+ }
+
+ /**
+ * takes the arguments supplied and triggers a call to the CPAINT backend
+ * based on the settings.
+ *
+ * upon response cpaint_call.callback() will automatically be called
+ * to perform post-processing operations.
+ *
+ * @access public
+ * @param string url remote URL to call
+ * @param string remote_method remote method to call
+ * @param object client_callback client side callback method to deliver the remote response to. do NOT supply a string!
+ * @param mixed argN remote parameters from now on
+ * @return void
+ */
+ this.call = function() {
+ var use_stack = -1;
+
+ if (config['persistent_connection'] == true
+ && typeof __cpaint_stack[0] == 'object') {
+
+ switch (__cpaint_stack[0].get_http_state()) {
+ case -1:
+ // no XMLHttpObject object has already been instanciated
+ // create new object and configure it
+ use_stack = 0;
+ debug('no XMLHttpObject object to re-use for persistence, creating new one later', 2);
+ break;
+
+ case 4:
+ // object is ready for a new request, no need to do anything
+ use_stack = 0
+ debug('re-using the persistent connection', 2);
+ break;
+
+ default:
+ // connection is currently in use, don't do anything
+ debug('the persistent connection is in use - skipping this request', 2);
+ }
+
+ } else if (config['persistent_connection'] == true) {
+ // persistent connection is active, but no object has been instanciated
+ use_stack = 0;
+ __cpaint_stack[use_stack] = new cpaint_call(use_stack);
+ debug('no cpaint_call object available for re-use, created new one', 2);
+
+ } else {
+ // no connection persistance
+ use_stack = stack_count;
+ __cpaint_stack[use_stack] = new cpaint_call(use_stack);
+ debug('no cpaint_call object created new one', 2);
+ }
+
+ // configure cpaint_call if allowed to
+ if (use_stack != -1) {
+ __cpaint_stack[use_stack].set_debug(config['debugging']);
+ __cpaint_stack[use_stack].set_proxy_url(config['proxy_url']);
+ __cpaint_stack[use_stack].set_transfer_mode(config['transfer_mode']);
+ __cpaint_stack[use_stack].set_async(config['async']);
+ __cpaint_stack[use_stack].set_response_type(config['response_type']);
+ __cpaint_stack[use_stack].set_persistent_connection(config['persistent_connection']);
+ __cpaint_stack[use_stack].set_use_cpaint_api(config['use_cpaint_api']);
+ __cpaint_stack[use_stack].set_client_callback(arguments[2]);
+
+ // distribute according to proxy use
+ if (config['proxy_url'] != '') {
+ __cpaint_stack[use_stack].call_proxy(arguments);
+
+ } else {
+ __cpaint_stack[use_stack].call_direct(arguments);
+ }
+
+ // increase stack counter
+ stack_count++;
+ debug('stack size: ' + __cpaint_stack.length, 2);
+ }
+ }
+
+ /**
+ * debug method
+ *
+ * @access protected
+ * @param string message the message to debug
+ * @param integer debug_level debug level at which the message appears
+ * @return void
+ */
+ var debug = function(message, debug_level) {
+ if (config['debugging'] >= debug_level) {
+ alert('[CPAINT Debug] ' + message);
+ }
+ }
+}
+
+/**
+* internal FIFO stack of cpaint_call() objects.
+*
+* @access protected
+* @var array __cpaint_stack
+*/
+var __cpaint_stack = new Array();
+
+/**
+* local instance of cpaint_transformer
+* MSIE is unable to handle static classes... sheesh.
+*
+* @access public
+* @var object __cpaint_transformer
+*/
+var __cpaint_transformer = new cpaint_transformer();
+
+/**
+* transport agent class
+*
+* creates the request object, takes care of the response, handles the
+* client callback. Is configured by the cpaint() object.
+*
+* @package CPAINT
+* @access public
+* @copyright Copyright (c) 2005 Paul Sullivan, Dominique Stender - http://cpaint.sourceforge.net
+* @author Dominique Stender <dstender@st-webdevelopment.de>
+* @author Paul Sullivan <wiley14@gmail.com>
+* @param integer stack_id stack Id in cpaint
+* @version 2.0.0
+*/
+function cpaint_call() {
+ /**
+ * whether or not debugging is used.
+ *
+ * @access public
+ * @var boolean debugging
+ */
+ var debugging = false;
+
+
+ /**
+ * XMLHttpObject used for this request.
+ *
+ * @access protected
+ * @var object httpobj
+ */
+ var httpobj = false;
+
+ /**
+ * URL of the proxy script to use.
+ * the proxy script is necessary only if data from remote domains is to be retrieved.
+ *
+ * @access public
+ * @var string proxy_url
+ */
+ var proxy_url = '';
+
+ /**
+ * HTTP transfer mode.
+ *
+ * allowed values: (GET|POST), default is GET in respect to Operas deficiencies.
+ *
+ * @access public
+ * @var string transfer_mode
+ */
+ var transfer_mode = 'GET';
+
+ /**
+ * configuration option whether request/response pairs
+ * are meant to be performed synchronous or asynchronous.
+ *
+ * default is asynchronous, since synchronized calls aren't completely supported in most browsers.
+ *
+ * @access public
+ * var boolean async
+ */
+ var async = true;
+
+ /**
+ * response type (TEXT|XML|OBJECT).
+ *
+ * @access public
+ * @var string response_type
+ */
+ var response_type = 'OBJECT';
+
+ /**
+ * whether or not to use a persistent connection
+ * to the server side.
+ *
+ * default is false (new connection on every call).
+ *
+ * @access public
+ * @var boolean persistent_connection
+ */
+ var persistent_connection = false;
+
+ /**
+ * whether or not to use the cpaint api on the backend
+ *
+ * default is true (uses cpaint api)
+ *
+ * @access public
+ * @var boolean cpaint_api
+ */
+ var use_cpaint_api = true;
+
+ /**
+ * client callback function.
+ *
+ * @access public
+ * @var function client_callback
+ */
+ var client_callback;
+
+ /**
+ * stores the stack Id within the cpaint object
+ *
+ * @access protected
+ * @var stack_id
+ */
+ var stack_id = arguments[0];
+
+ /**
+ * switches debug mode on/off (0|1|2).
+ *
+ * @access public
+ * @param integer debug debug flag
+ * @return void
+ */
+ this.set_debug = function() {
+
+ if (typeof arguments[0] == 'number') {
+ debugging = Math.round(arguments[0]);
+ }
+ }
+
+ /**
+ * defines the URL of the proxy script.
+ *
+ * @access public
+ * @param string proxy_url URL of the proxyscript to connect
+ * @return void
+ */
+ this.set_proxy_url = function() {
+
+ if (typeof arguments[0] == 'string') {
+ proxy_url = arguments[0];
+ }
+ }
+
+ /**
+ * sets the transfer_mode (GET|POST).
+ *
+ * @access public
+ * @param string transfer_mode transfer_mode
+ * @return void
+ */
+ this.set_transfer_mode = function() {
+
+ if (arguments[0].toUpperCase() == 'GET'
+ || arguments[0].toUpperCase() == 'POST') {
+
+ transfer_mode = arguments[0].toUpperCase();
+ }
+ }
+
+ /**
+ * sets the flag whether or not to use asynchronous calls.
+ *
+ * @access public
+ * @param boolean async syncronization flag
+ * @return void
+ */
+ this.set_async = function() {
+
+ if (typeof arguments[0] == 'boolean') {
+ async = arguments[0];
+ }
+ }
+
+ /**
+ * defines the response type.
+ *
+ * allowed values are:
+ * TEXT = raw text response
+ * XML = raw XMLHttpObject
+ * OBJECT = parsed JavaScript object structure
+ *
+ * default is OBJECT.
+ *
+ * @access public
+ * @param string response_type response type
+ * @return void
+ */
+ this.set_response_type = function() {
+
+ if (arguments[0].toUpperCase() == 'TEXT'
+ || arguments[0].toUpperCase() == 'XML'
+ || arguments[0].toUpperCase() == 'OBJECT') {
+
+ response_type = arguments[0].toUpperCase();
+ }
+ }
+
+ /**
+ * sets the flag whether or not to use a persistent connection.
+ *
+ * @access public
+ * @param boolean persistent_connection persistance flag
+ * @return void
+ */
+ this.set_persistent_connection = function() {
+
+ if (typeof arguments[0] == 'boolean') {
+ persistent_connection = arguments[0];
+ }
+ }
+
+ /**
+ * sets the flag whether or not to use the cpaint api on the backend.
+ *
+ * @access public
+ * @param boolean cpaint_api api_flag
+ * @return void
+ */
+ this.set_use_cpaint_api = function() {
+ if (typeof arguments[0] == 'boolean') {
+ use_cpaint_api = arguments[0];
+ }
+ }
+
+ /**
+ * sets the client callback function.
+ *
+ * @access public
+ * @param function client_callback the client callback function
+ * @return void
+ */
+ this.set_client_callback = function() {
+
+ if (typeof arguments[0] == 'function') {
+ client_callback = arguments[0];
+ }
+ }
+
+ /**
+ * returns the ready state of the internal XMLHttpObject
+ *
+ * if no such object was set up already, -1 is returned
+ *
+ * @access public
+ * @return integer
+ */
+ this.get_http_state = function() {
+ var return_value = -1;
+
+ if (typeof httpobj == 'object') {
+ return_value = httpobj.readyState;
+ }
+
+ return return_value;
+ }
+
+ /**
+ * internal method for remote calls to the local server without use of the proxy script.
+ *
+ * @access public
+ * @param array call_arguments array of arguments initially passed to cpaint.call()
+ * @return void
+ */
+ this.call_direct = function(call_arguments) {
+ var url = call_arguments[0];
+ var remote_method = call_arguments[1];
+ var querystring = '';
+ var i = 0;
+
+ // correct link to self
+ if (url == 'SELF') {
+ url = document.location.href;
+ }
+
+ if (use_cpaint_api == true) {
+ // backend uses cpaint api
+ // pass parameters to remote method
+ for (i = 3; i < call_arguments.length; i++) {
+ querystring += '&cpaint_argument[]=' + encodeURIComponent(call_arguments[i]);
+ }
+
+ // add response type to querystring
+ querystring += '&cpaint_response_type=' + response_type;
+
+ // build header
+ if (transfer_mode == 'GET') {
+ url = url + '?cpaint_function=' + remote_method + querystring;
+
+ } else {
+ querystring = 'cpaint_function=' + remote_method + querystring;
+ }
+
+ } else {
+ // backend does not use cpaint api
+ // pass parameters to remote method
+ for (i = 3; i < call_arguments.length; i++) {
+
+ if (i == 3) {
+ querystring += encodeURIComponent(call_arguments[i]);
+
+ } else {
+ querystring += '&' + encodeURIComponent(call_arguments[i]);
+ }
+ }
+
+ // build header
+ if (transfer_mode == 'GET') {
+ url = url + querystring;
+ }
+ }
+
+ // open connection
+ get_connection_object();
+
+ // open connection to remote target
+ debug('opening connection to "' + url + '"', 1);
+ httpobj.open(transfer_mode, url, async);
+
+ // send "urlencoded" header if necessary (if POST)
+ if (transfer_mode == "POST") {
+
+ try {
+ httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ } catch (cp_err) {
+ alert('ERROR! POST cannot be completed due to incompatible browser. Use GET as your request method.');
+ }
+ }
+
+ // callback handling for asynchronous calls
+ httpobj.onreadystatechange = callback;
+
+ // send content
+ if (transfer_mode == 'GET') {
+ httpobj.send(null);
+
+ } else {
+ debug('sending query: ' + querystring, 1);
+ httpobj.send(querystring);
+ }
+
+ if (async == false) {
+ // manual callback handling for synchronized calls
+ callback();
+ }
+ }
+
+
+ /**
+ * internal method for calls to remote servers through the proxy script.
+ *
+ * @access public
+ * @param array call_arguments array of arguments passed to cpaint.call()
+ * @return void
+ */
+ this.call_proxy = function(call_arguments) {
+ var proxyscript = proxy_url;
+ var url = call_arguments[0];
+ var remote_method = call_arguments[1];
+ var querystring = '';
+ var i = 0;
+
+ var querystring_argument_prefix = 'cpaint_argument[]=';
+
+ // pass parameters to remote method
+ if (use_cpaint_api == false) {
+ // when not talking to a CPAINT backend, don't prefix arguments
+ querystring_argument_prefix = '';
+ }
+
+ for (i = 3; i < call_arguments.length; i++) {
+ querystring += encodeURIComponent(querystring_argument_prefix + call_arguments[i] + '&');
+ }
+
+ if (use_cpaint_api == true) {
+ // add remote function name to querystring
+ querystring += encodeURIComponent('&cpaint_function=' + remote_method);
+
+ // add response type to querystring
+ querystring += encodeURIComponent('&cpaint_responsetype=' + response_type);
+ }
+
+ // build header
+ if (transfer_mode == 'GET') {
+ proxyscript += '?cpaint_remote_url=' + encodeURIComponent(url)
+ + '&cpaint_remote_query=' + querystring
+ + '&cpaint_remote_method=' + transfer_mode
+ + '&cpaint_response_type=' + response_type;
+
+ } else {
+ querystring = 'cpaint_remote_url=' + encodeURIComponent(url)
+ + '&cpaint_remote_query=' + querystring
+ + '&cpaint_remote_method=' + transfer_mode
+ + '&cpaint_response_type=' + response_type;
+ }
+
+ // open connection
+ get_connection_object();
+
+ // open connection to remote target
+ debug('opening connection to proxy "' + proxyscript + '"', 1);
+ httpobj.open(transfer_mode, proxyscript, async);
+
+ // send "urlencoded" header if necessary (if POST)
+ if (transfer_mode == "POST") {
+
+ try {
+ httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ } catch (cp_err) {
+ alert('[CPAINT Error] POST cannot be completed due to incompatible browser. Use GET as your request method.');
+ }
+ }
+
+ // callback handling for asynchronous calls
+ httpobj.onreadystatechange = callback;
+
+ // send content
+ if (transfer_mode == 'GET') {
+ httpobj.send(null);
+
+ } else {
+ debug('sending query: ' + querystring, 1);
+ httpobj.send(querystring);
+ }
+
+ if (async == false) {
+ // manual callback handling for synchronized calls
+ callback();
+ }
+ }
+
+ this.test_ajax_capability = function() {
+ return get_connection_object();
+ }
+
+ /**
+ * creates a new connection object.
+ *
+ * @access protected
+ * @return boolean
+ */
+ var get_connection_object = function() {
+ var return_value = false;
+ var new_connection = false;
+
+ // open new connection only if necessary
+ if (persistent_connection == false) {
+ // no persistance, create a new object every time
+ debug('Using new connection object', 1);
+ new_connection = true;
+
+ } else {
+ // persistent connection object, only open one if no object exists
+ debug('Using shared connection object.', 1);
+
+ if (typeof httpobj != 'object') {
+ debug('Getting new persistent connection object.', 1);
+ new_connection = true;
+ }
+ }
+
+ if (new_connection == true) {
+ try {
+ httpobj = new ActiveXObject('Msxml2.XMLHTTP');
+
+ } catch (e) {
+
+ try {
+ httpobj = new ActiveXObject('Microsoft.XMLHTTP');
+
+ } catch (oc) {
+ httpobj = null;
+ }
+ }
+
+ if (!httpobj && typeof XMLHttpRequest != 'undefined') {
+ httpobj = new XMLHttpRequest();
+ }
+
+ if (!httpobj) {
+ alert('[CPAINT Error] Could not create connection object');
+
+ } else {
+ return_value = true;
+ }
+ }
+
+ // @todo: problem with asynchronous calls?
+ if (httpobj.readyState != 4) {
+ httpobj.abort();
+ }
+
+ return return_value;
+ }
+
+ /**
+ * internal callback function.
+ *
+ * will perform some consistency checks (response code, NULL value testing)
+ * and if response_type = 'OBJECT' it will automatically call
+ * cpaint_call.parse_ajax_xml() to have a JavaScript object structure generated.
+ *
+ * after all that is done the client side callback function will be called
+ * with the generated response as single value.
+ *
+ * @access protected
+ * @return void
+ */
+ var callback = function() {
+ var response = null;
+
+ if (httpobj.readyState == 4) {
+ debug(httpobj.responseText, 1);
+
+ // fetch correct response
+ switch (response_type) {
+ case 'XML':
+ response = __cpaint_transformer.xml_conversion(httpobj.responseXML);
+ break;
+
+ case 'OBJECT':
+ response = __cpaint_transformer.object_conversion(httpobj.responseXML);
+ break;
+
+ case 'TEXT':
+ response = __cpaint_transformer.text_conversion(httpobj.responseText);
+ break;
+
+ default:
+ alert('[CPAINT Error] invalid response type \'' + response_type + '\'');
+ }
+
+ // call client side callback
+ if (response != null
+ && typeof client_callback == 'function') {
+ client_callback(response, httpobj.responseText);
+ }
+
+ // remove ourselves from the stack
+ remove_from_stack();
+ }
+ }
+
+ /**
+ * removes an entry from the stack
+ *
+ * @access protected
+ * @return void
+ */
+ var remove_from_stack = function() {
+ // remove only if everything is okay and we're not configured as persistent connection
+ if (typeof stack_id == 'number'
+ && __cpaint_stack[stack_id]
+ && persistent_connection == false) {
+
+ __cpaint_stack[stack_id] = null;
+ }
+ }
+
+ /**
+ * debug method
+ *
+ * @access protected
+ * @param string message the message to debug
+ * @param integer debug_level debug level at which the message appears
+ * @return void
+ */
+ var debug = function(message, debug_level) {
+
+ if (debugging >= debug_level) {
+ alert('[CPAINT Debug] ' + message);
+ }
+ }
+}
+
+/**
+* CPAINT transformation object
+*
+* @package CPAINT
+* @access public
+* @copyright Copyright (c) 2005 Paul Sullivan, Dominique Stender - http://cpaint.sourceforge.net
+* @author Paul Sullivan <wiley14@gmail.com>
+* @author Dominique Stender <dstender@st-webdevelopment.de>
+* @version 2.0.0
+*/
+function cpaint_transformer() {
+
+ /**
+ * will take a XMLHttpObject and generate a JavaScript
+ * object structure from it.
+ *
+ * is internally called by cpaint_call.callback() if necessary.
+ * will call cpaint_call.create_object_structure() to create nested object structures.
+ *
+ * @access public
+ * @param object xml_document a XMLHttpObject
+ * @return object
+ */
+ this.object_conversion = function(xml_document) {
+ var return_value = new cpaint_result_object();
+ var i = 0;
+ var firstNodeName = '';
+
+ if (typeof xml_document == 'object'
+ && xml_document != null) {
+
+ // find the first element node - for MSIE the <?xml?> node is the very first...
+ for (i = 0; i < xml_document.childNodes.length; i++) {
+
+ if (xml_document.childNodes[i].nodeType == 1) {
+ firstNodeName = xml_document.childNodes[i].nodeName;
+ break;
+ }
+ }
+
+ var ajax_response = xml_document.getElementsByTagName(firstNodeName);
+
+ return_value[firstNodeName] = new Array();
+
+ for (i = 0; i < ajax_response.length; i++) {
+ var tmp_node = create_object_structure(ajax_response[i]);
+ tmp_node.id = ajax_response[i].getAttribute('id')
+ return_value[firstNodeName].push(tmp_node);
+ }
+
+ } else {
+ alert('[CPAINT Error] received invalid XML response');
+ }
+
+ return return_value;
+ }
+
+ /**
+ * performs the necessary conversions for the XML response type
+ *
+ * @access public
+ * @param object xml_document a XMLHttpObject
+ * @return object
+ */
+ this.xml_conversion = function(xml_document) {
+ return xml_document;
+ }
+
+ /**
+ * performs the necessary conversions for the TEXT response type
+ *
+ * @access public
+ * @param string text_document the response text
+ * @return string
+ */
+ this.text_conversion = function(text) {
+ return decode(text);
+ }
+
+ /**
+ * this method takes a HTML / XML node object and creates a
+ * JavaScript object structure from it.
+ *
+ * @access public
+ * @param object stream a node in the XML structure
+ * @return object
+ */
+ var create_object_structure = function(stream) {
+ var return_value = new cpaint_result_object();
+ var node_name = '';
+ var i = 0;
+ var attrib = 0;
+
+ if (stream.hasChildNodes() == true) {
+ for (i = 0; i < stream.childNodes.length; i++) {
+
+ node_name = decode(stream.childNodes[i].nodeName);
+ node_name = node_name.replace(/[^a-zA-Z0-9]*/g, '');
+
+ // reset / create subnode
+ if (typeof return_value[node_name] != 'object') {
+ return_value[node_name] = new Array();
+ }
+
+ if (stream.childNodes[i].nodeType == 1) {
+ var tmp_node = create_object_structure(stream.childNodes[i]);
+
+ for (attrib = 0; attrib < stream.childNodes[i].attributes.length; attrib++) {
+ tmp_node.set_attribute(decode(stream.childNodes[i].attributes[attrib].nodeName), decode(stream.childNodes[i].attributes[attrib].nodeValue));
+ }
+
+ return_value[node_name].push(tmp_node);
+
+ } else if (stream.childNodes[i].nodeType == 3) {
+ return_value.data = decode(stream.firstChild.data);
+ }
+ }
+ }
+
+ return return_value;
+ }
+
+ /**
+ * converts an encoded text back to viewable characters.
+ *
+ * @access public
+ * @param string rawtext raw text as provided by the backend
+ * @return mixed
+ */
+ var decode = function(rawtext) {
+ var plaintext = '';
+ var i = 0;
+ var c1 = 0;
+ var c2 = 0;
+ var c3 = 0;
+ var u = 0;
+ var t = 0;
+
+ // remove special JavaScript encoded non-printable characters
+ while (i < rawtext.length) {
+ if (rawtext.charAt(i) == '\\'
+ && rawtext.charAt(i + 1) == 'u') {
+
+ u = 0;
+
+ for (j = 2; j < 6; j += 1) {
+ t = parseInt(rawtext.charAt(i + j), 16);
+
+ if (!isFinite(t)) {
+ break;
+ }
+ u = u * 16 + t;
+ }
+
+ plaintext += String.fromCharCode(u);
+ i += 6;
+
+ } else {
+ plaintext += rawtext.charAt(i);
+ i++;
+ }
+ }
+
+ // convert numeric data to number type
+ if (plaintext !== ''
+ && !isNaN(plaintext)
+ && isFinite(plaintext)) {
+
+ plaintext = Number(plaintext);
+ }
+
+ return plaintext;
+ }
+}
+
+/**
+* this is the basic prototype for a cpaint node object
+* as used in cpaint_call.parse_ajax_xml()
+*
+* @package CPAINT
+* @access public
+* @copyright Copyright (c) 2005 Paul Sullivan, Dominique Stender - http://cpaint.sourceforge.net
+* @author Paul Sullivan <wiley14@gmail.com>
+* @author Dominique Stender <dstender@st-webdevelopment.de>
+* @version 2.0.0
+*/
+function cpaint_result_object() {
+ this.id = 0;
+ this.data = 0;
+ var __attributes = new Array();
+
+ /**
+ * Returns a subnode with the given type and id.
+ *
+ * @access public
+ * @param string type The type of the subnode. Equivalent to the XML tag name.
+ * @param string id The id of the subnode. Equivalent to the XML tag names id attribute.
+ * @return object
+ */
+ this.find_item_by_id = function() {
+ var return_value = null;
+ var type = arguments[0];
+ var id = arguments[1];
+ var i = 0;
+
+ if (this[type]) {
+
+ for (i = 0; i < this[type].length; i++) {
+
+ if (this[type][i].get_attribute('id') == id) {
+ return_value = this[type][i];
+ break;
+ }
+ }
+ }
+
+ return return_value;
+ }
+
+ /**
+ * retrieves the value of an attribute.
+ *
+ * @access public
+ * @param string name name of the attribute
+ * @return mixed
+ */
+ this.get_attribute = function() {
+ var return_value = null;
+ var id = arguments[0];
+
+ if (typeof __attributes[id] != 'undefined') {
+ return_value = __attributes[id];
+ }
+
+ return return_value;
+ }
+
+ /**
+ * assigns a value to an attribute.
+ *
+ * if that attribute does not exist it will be created.
+ *
+ * @access public
+ * @param string name name of the attribute
+ * @param string value value of the attribute
+ * @return void
+ */
+ this.set_attribute = function() {
+ __attributes[arguments[0]] = arguments[1];
+ }
+}
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/css/pagelet.css
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/css/pagelet.css?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/css/pagelet.css (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/css/pagelet.css Wed May 3 14:24:53 2006
@@ -0,0 +1,39 @@
+.dojoDialogSpeller {
+ background : #fff;
+ border : 1px;
+ border-style: solid;
+ border-color: black;
+ position: fixed;
+}
+
+.pagelet {
+ background : #fff;
+ border : 1px;
+ border-style: solid;
+ border-color: black;
+}
+
+.pagelet_inactive {
+ border : 1px;
+ border-style: solid;
+ border-color: black;
+ background: #eee;
+}
+
+.pagelet_readonly {
+ border : 1px;
+ border-style: solid;
+ border-color: black;
+ background: #eee;
+}
+
+
+.myfaces_SpellingError {
+ background-color: yellow;
+ border: 1px solid #999;
+}
+
+.myfaces_SuggestEntry {
+ color: blue;
+ cursor: pointer;
+}
\ No newline at end of file
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CANCEL_0.gif
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CANCEL_0.gif?rev=399437&view=auto
==============================================================================
Binary file - no diff available.
Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CANCEL_0.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CLEAR_0.gif
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CLEAR_0.gif?rev=399437&view=auto
==============================================================================
Binary file - no diff available.
Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/CLEAR_0.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/OK_0.gif
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/OK_0.gif?rev=399437&view=auto
==============================================================================
Binary file - no diff available.
Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/OK_0.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/RESUME_0.gif
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/RESUME_0.gif?rev=399437&view=auto
==============================================================================
Binary file - no diff available.
Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/RESUME_0.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/SPELLCHECK_0.gif
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/SPELLCHECK_0.gif?rev=399437&view=auto
==============================================================================
Binary file - no diff available.
Propchange: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/img/SPELLCHECK_0.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/myfacesdlg.js
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/myfacesdlg.js?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/myfacesdlg.js (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/myfacesdlg.js Wed May 3 14:24:53 2006
@@ -0,0 +1,65 @@
+
+/**
+ we have double code I know, todo clean this up with the pagelet.js
+ */
+ function myfaces_shiftToTop(id) {
+ try {
+ var element = dojo.byId(id);
+ var parent = element.parentNode;
+
+ if(parent == document.body) return;
+ parent.removeChild(element);
+ document.body.insertBefore(element, document.body.firstChild);
+ } catch (e) {};//we ignore error messages because it is uncritical
+ //and we sometimes run into situations where we do not need it
+ }
+
+ /**
+ hide function for our own dialog system
+ (dojos seem to freak out the ie over huge stress)
+ */
+ function hidRawTextDialog(bindingVar, dialogDivId) {
+ if(bindingVar.bgIframe != null)
+ bindingVar.bgIframe.hide();
+ dojo.html.hide(dialogDivId);
+ }
+
+ /**
+ show function for our own dialog system
+ (dojos seem to freak out the ie over huge stress)
+ */
+ function showRawTextDialog(bindingVar, dialogDivId, textAreaId) {
+ myfaces_shiftToTop(dialogDivId);
+ //myfaces_shiftToBody(dialogDivId);
+
+ var textArea = dojo.byId(textAreaId);
+ var viewport_size = dojo.html.getViewportSize();
+
+ textArea.style.width = (parseInt(viewport_size[0] ) - 80)+"px";
+ textArea.style.height = (parseInt(viewport_size[1] ) - 80)+"px";
+
+ var dialog = dojo.byId(dialogDivId);
+
+ var scroll_offset = dojo.html.getScrollOffset();
+ //ie fix
+ dialog.style.position = "absolute";
+ //if (dojo.render.html.ie) {//ie does not do fixed yet, we have to simulate
+ dialog.style.left = (parseInt(scroll_offset[0])+ 20)+"px"
+ dialog.style.top = (parseInt(scroll_offset[1])+20) +"px";
+ //}
+ var viewport_size = dojo.html.getViewportSize();
+
+ dialog.style.width = (parseInt(viewport_size[0] ) - 40)+"px";
+ dialog.style.height = (parseInt(viewport_size[1] ) - 40)+"px";
+
+ if(!bindingVar.bgIframe)
+ bindingVar.bgIframe = new dojo.html.BackgroundIframe();
+
+ bindingVar.bgIframe.show([0,0, parseInt(viewport_size[0]), parseInt(viewport_size[1])]);
+ bindingVar.bgIframe.setZIndex(1);
+
+ dialog.style.zIndex = 3;
+ dialog.style.visibility = "visible";
+ dojo.fx.html.fadeShow(dialog, 200);
+ }
+
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/pagelet.js
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/pagelet.js?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/pagelet.js (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/pagelet.js Wed May 3 14:24:53 2006
@@ -0,0 +1,868 @@
+/*
+ Copyright (c) 2004-2005, Irian GesmbH
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/**
+* first initialize our package as dojo subpackage upon
+* our resource loading criterion
+*
+*/
+
+dojo.provide("org.apache.myfaces.pagelet.PageletEditor");
+dojo.require("org.apache.myfaces.pagelet.Progressor");
+/*
+new rich edit from div
+
+oncreate
+hitch the value from the hidden field
+
+change the onsubmits of the of the hidden
+field so that the values are traversed before
+the old submit
+
+set the hidden field that onvaluechange is plastered
+into the rich text
+
+*/
+
+org.apache.myfaces.pagelet.PageletEditor = function() {
+ //dojo.widget.html.Editor = function() {
+
+ dojo.widget.html.Editor.call(this);
+ this.widgetType = "PageletEditor";
+
+}
+dojo.inherits(org.apache.myfaces.pagelet.PageletEditor, dojo.widget.html.Editor);
+dojo.lang.extend(org.apache.myfaces.pagelet.PageletEditor, {
+
+ insertToolbar: function(tbNode, richTextNode) {
+ //interception point for the toolbar
+ //here we can add a scrolling div which shifts
+ //the rich text node into the inner core
+
+
+ //and then add the richtext node to the mix
+ dojo.html.insertBefore(tbNode, richTextNode);
+ //dojo.html.insertBefore(this._toolbarContainer.domNode, this._richText.domNode);
+ },
+
+ setRichText: function(richText) {
+ if(this._richText && this._richText == richText) {
+ dojo.debug("Already set the richText to this richText!");
+ return;
+ }
+
+ if(this._richText && !this._richText.isClosed) {
+ dojo.debug("You are switching richTexts yet you haven't closed the current one. Losing reference!");
+ }
+ this._richText = richText;
+ //this._richTextContainer = document.createElement("div");
+ //this._richTextContainer.style.overflow = "auto";
+
+ //this._richText.domNode.style.overflow = 'auto';
+ //this._richText.domNode.style.height="500px";
+
+
+ dojo.event.connect(this._richText, "close", this, "onClose");
+ dojo.event.connect(this._richText, "onLoad", this, "onLoad");
+ dojo.event.connect(this._richText, "onDisplayChanged", this, "updateToolbar");
+
+
+ if(dojo.render.html.ie)
+ dojo.event.connect(this._richText.editNode, "onkeydown",this, "keydown");
+
+
+ if(this._toolbarContainer) {
+ this._toolbarContainer.enable();
+ this.updateToolbar(true);
+ }
+
+ },
+
+ focus: function() {
+ //TODO push this into a timeout code for moz fixing
+ if(this._richText != null && this._richText.editNode != null)
+ this._richText.editNode.focus();
+ else
+ dojo.lang.setTimeout(this,this.focus, 100);
+
+ },
+
+ /**
+ * some key shifting here
+ * due to demands by third parties
+ * we have to shift the default ie behavior a little bit
+ * in the enter key areas
+ */
+ keydown: function(evt) {
+ if(!this.changeNotified && typeof(myfaces_stateChange_notificationFields)!="undefined" && myfaces_stateChange_notificationFields != null) {
+ //first trigger the notifier we have a change
+ var notifierArray = myfaces_stateChange_notificationFields;
+ this.changeNotified = true;
+ if(notifierArray != null) {
+ for(var notifierField in notifierArray) {
+
+ if(notifierArray[notifierField] != null) {
+ notifierField = dojo.byId(notifierArray[notifierField]);
+ notifierField.value = "true";
+
+ }
+ }
+ }
+ }
+
+ //enter now is enter
+ if((!evt.ctrlKey) && evt.keyCode == 13) {
+ //This is a fix for the input key handler in ie
+ //so that it behaves in a sane way regarding line breaks
+ evt.preventDefault();
+ //since this has to work on ie only
+ if (document.selection) {
+ var range = document.selection.createRange();
+ if (this._richText.editNode.parentElement.contains(range.parentElement())) {
+ range.pasteHTML("<br>");
+ range.select();
+ }
+ }
+ } else if(evt.keyCode == 13) {//ctrl enter now is paragraph, I hate IE
+ evt.preventDefault();
+ //since this has to work on ie only
+ if (document.selection) {
+ var range = document.selection.createRange();
+ if (this._richText.editNode.parentElement.contains(range.parentElement())) {
+ range.pasteHTML("<p></p>");
+ range.select();
+ }
+ }
+ }
+ }
+ }
+);
+
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:PageletEditor");
+
+/**
+* Pagelets
+* pagelet javascripts
+* @author Werner Punz
+* @version 1.0 ie only
+*/
+
+/*==================Utility subsystem=================*/
+/******************************************************
+* shifting the element to the body
+* to fix the dreaded ie positioning
+* bug regarding fixed
+*******************************************************/
+function myfaces_shiftToBody(id) {
+ try {
+ var element = dojo.byId(id);
+ var parent = element.parentNode;
+
+ if(parent == document.body) return;
+ parent.removeChild(element);
+ document.body.insertBefore(element, document.body.firstChild);
+ } catch (e) {};//we ignore error messages because it is uncritical
+ //and we sometimes run into situations where we do not need it
+}
+
+/******************************************************
+* sets the scroll offst of a given window
+*******************************************************/
+function setScrollOffset(scrollOffset) {
+ window.scrollTo(scrollOffset[0], scrollOffset[1]);
+}
+
+
+
+
+
+/*===================Spellchecker subsystem==========================*/
+/********************************************************************
+* generic dojoed spellchecker class which does some spellchecking
+* and does a fixup of the markup code with replacement
+*
+* @param parentRef a reference to the parent variable for callback reasons(Timer)
+* @param contentDiv the div or edit field holding the content
+* @param isRichEdit if true a rich edit control has to be shown (currently unused)
+* @param spellurl the spellchecking url
+* @param spellMethid the spellchecker method (jsf method binding string)
+**********************************************************************/
+function myfaces_Spellchecker(parentRef, contentDivId, isRichEdit, spellurl, spellmethod) {
+ this.parentRef = parentRef;
+ this.contentDivId = contentDivId;
+ this.spellcheckingTag = "<span class='myfaces_SpellingError' id='myfaces_SpellErr:spellErrCnt'>myFaces_contentNode</span>"
+ this.spellmethod = spellmethod;
+
+ if(spellurl != null)
+ this.searchUrl = spellurl + "?%{param1}";
+ else
+ this.searchUrl = "./org/apache/myfaces/ajax/spellchecker?%{param1}";
+
+ myfaces_shiftToBody("dojoDialog_spellcheckResults");
+ this.isRichEdit = isRichEdit;
+ if(this.isRichEdit == null)
+ this.isRichEdit = false;
+};
+
+/************************************************************
+ * helper to fetch the content holder
+ ************************************************************/
+myfaces_Spellchecker.prototype.getContentHolder = function() {
+ var contentHolder = null;
+ if(!this.isRichEdit) {
+ contentHolder = dojo.byId(this.contentDivId);
+ } else {
+ contentHolder = dojo.widget.manager.getWidgetById(this.contentDivId);
+ contentHolder = contentHolder._richText;
+ }
+ if(contentHolder == null) dojo.debug("Error: there is no content holder for this id:"+this.contentDivId);
+ return contentHolder;
+};
+
+
+
+/**********************************************************
+ * convenience method for fetching the content
+ * @returns the content of the current
+ * edit area
+ **********************************************************/
+myfaces_Spellchecker.prototype.getContent = function() {
+ var contentHolder = this.getContentHolder();
+
+ var content = null;
+ if(contentHolder.getEditorContent != null)
+ content = contentHolder.getEditorContent();
+ else if(contentHolder.value != null)
+ content = contentHolder.value;
+ else
+ content = contentHolder.innerHTML;
+ return content;
+};
+
+
+/*************************************************************
+ * this method converts a found error keyword into a
+ * href with a given styleclass for identification
+ * @param errorString the found error which has to be tagged
+ *************************************************************/
+myfaces_Spellchecker.prototype.markAsError = function(errorString) {
+
+ var content = this.getContent();
+ var correctionString = this.spellcheckingTag.replace(/myFaces_contentNode/,errorString);
+ var pattern = new RegExp("[^a-zA-Z_0-9]"+errorString+"[^a-zA-Z_0-9]","g"); //replaceall
+ var contentHolder = this.getContentHolder();
+
+ content = content.replace (pattern, correctionString.replace("spellErrCnt","_0"));
+ if(contentHolder.editNode != null)
+ contentHolder.editNode.innerHTML = content;
+ else if(contentHolder.value != null)
+ contentHolder.value = content;
+ else
+ contentHolder.innerHTML = content;
+};
+
+/*****************************************************
+ * an ajaxed mark as error
+ * the calling link
+ * is set via the object initialization
+ * parameter
+ *
+ ******************************************************/
+myfaces_Spellchecker.prototype.markAsErrorAjax = function(dummyparam) {
+ var content = this.getContent();
+ /**
+ * note we use a parametrized array
+ * the first entry is the operation we want to achieve
+ * the second one the content
+ * the third+ one is an additional paramlist
+ * depending on the op
+ */
+ var requestUri = dojo.string.paramString(this.searchUrl,{"param1":
+ "spck[]="+encodeURIComponent("spellcheck")+ //first param the commend
+ "&spck[]="+encodeURIComponent(this.spellmethod) //second param speller method
+ });
+ var _this = this;
+ var progressor = new org.apache.myfaces.pagelet.Progressor();
+ progressor.showInProgress("Spellchecking");
+ dojo.io.bind({
+ url : requestUri,
+ method : "post",
+ useCache:true,
+ content : {"content": content},
+ load :function(type, data, evt) {
+ progressor.hideInProgress();
+
+
+
+ var contentHolder = _this.getContentHolder();
+ //mozilla rendering
+ if(dojo.render.html.moz){
+ //moz cannot handle the inline rich edit styleclass stuff for now
+ //so we have to do it manually, since we do not have a replaceAll we have to do it manually
+ var dataNew = data.replace("class\='myfaces_SpellingError'>", "class='myfaces_SpellingError' style='background-color: yellow;border: 1px solid #999;' >");
+ while(dataNew != data) {
+ data = dataNew;
+ dataNew = data.replace("class\='myfaces_SpellingError'>", "class='myfaces_SpellingError' style='background-color: yellow;border: 1px solid #999;' >");
+ }
+ }
+
+
+ if(contentHolder.editNode != null)
+ contentHolder.editNode.innerHTML = data;
+ else if(contentHolder.value != null)
+ contentHolder.value = data;
+ else
+ contentHolder.innerHTML = data;
+
+ _this.activateSpellcheckingArr();
+
+ },
+ error: function(type, data, evt) {
+ progressor.hideInProgress();
+ },
+ mimetype: "text/plain",
+ transport: "XMLHTTPTransport"
+ });
+};
+
+/*********************************************************
+* ajax cleanup this basically passes the string and cleans
+* up the remaining spellcheckign parts
+* it uses the connection params from the object initializer
+*
+**********************************************************/
+myfaces_Spellchecker.prototype.cleanupAjax = function() {
+ //var searchUrl = "http://localhost:8080/spellchecker/org/apache/myfaces/ajax/spellchecker?%{param1}";
+ var content = this.getContent();
+
+ /**
+ * note we use a parametrized array
+ * the first entry is the operation we want to achieve
+ * the second one the content
+ * the third+ one is an additional paramlist
+ * depending on the op
+ */
+ var requestUri = dojo.string.paramString(this.searchUrl,{"param1":
+ "spck[]="+encodeURIComponent("cleanup")+ //first param the comment
+ "&spck[]="+encodeURIComponent(this.spellmethod) //second param speller method
+ });
+
+
+ var _this = this;
+ var progressor = new org.apache.myfaces.pagelet.Progressor();
+ progressor.showInProgress("Cleanup");
+
+ try {
+ dojo.io.bind({
+ sync: true,
+ url: requestUri,
+ useCache:true,
+ method: "POST",
+ content: {"content": content},
+
+ load:function(type, data, evt) {
+ progressor.hideInProgress();
+ var contentHolder = _this.getContentHolder();
+
+ if(contentHolder.editNode != null)
+ contentHolder.editNode.innerHTML = data;
+ else if(contentHolder.value != null)
+ contentHolder.value = data;
+ else
+ contentHolder.innerHTML = data;
+
+ if(dojo.render.html.moz) {
+ //only in design mode off we can enable javascript for now
+ //I dont know how the google people did it without
+ contentHolder.document.designMode = "on";
+ }
+ },
+ error: function(type, data, evt) {
+ progressor.hideInProgress();
+ dojo.debug("error-transport"+data);
+ },
+ mimetype: "text/plain",
+ transport: "XMLHTTPTransport"
+ });
+ } catch (e) {
+ progressor.hideInProgress();
+ alert("Error:"+e.message);
+ }
+};
+
+/**
+ * some resetting from the
+ */
+myfaces_Spellchecker.prototype.reset = function() {
+
+ if(dojo.render.html.moz) {
+ var contentHolder = this.getContentHolder();
+ //only in design mode off we can enable javascript for now
+ //I dont know how the google people did it without
+ contentHolder.document.designMode = "on";
+ }
+};
+
+/*************************************************************
+* activates the spell checking areas
+* for further processing
+* this is called after the spellchecking marking
+* it sets the event handlers of the spellcheck markers
+* to the suggestion list parameters
+**************************************************************/
+myfaces_Spellchecker.prototype.activateSpellcheckingArr = function() {
+ //we have the walk the hrefs and set the onclick handlers to
+ //an ajax and popup trigger
+
+ //now we walk the dom and dynamically readjust the elements
+ //this works only on ie unfortunately :-(
+ var errorHrefs = dojo.html.getElementsByClass("myfaces_SpellingError", document,"*",0);
+ for(var href in errorHrefs) {
+ dojo.event.connect(errorHrefs[href], "onclick", this,"onCorrectionList");
+ }
+ //on moz we have to do it differently again, since we have a list of spelling errors
+ //anyway which roots from 0... to somethign we can iterate over the ids
+ if(dojo.render.html.moz){
+ var contentHolder = this.getContentHolder();
+ //only in design mode off we can enable javascript for now
+ //I dont know how the google people did it without
+ contentHolder.document.designMode = "off";
+
+
+ var spellingErrCnt = 0;
+ while(true) {
+ var errId = "myfaces_SpellErr:" + spellingErrCnt;
+ spellingErrCnt += 1;
+ var errSpan = contentHolder.document.getElementById(errId);
+ if(errSpan == null) return;
+ dojo.event.connect(errSpan, "onclick", this,"onCorrectionList");
+ }
+ }
+
+};
+
+/***********************************************************
+* convenience method to access the tooltip singleton
+*
+* @param parentid the id the tooltip has to process, in our
+* case a simple spellchecking marked area
+************************************************************/
+myfaces_Spellchecker.prototype.getToolTip = function(parentId) {
+ var tip = dojo.widget.manager.getWidgetById("myfaces_Spcktooltip_dojoDialog_spellcheckResults");
+ if(tip == null) {
+ myfaces_shiftToBody("dojoDialog_spellcheckResults");
+
+ tip = dojo.widget.createWidget("Tooltip",{id:("myfaces_Spcktooltip_dojoDialog_spellcheckResults"),
+ executeScripts:true,
+
+ connectId:parentId},dojo.byId("dojoDialog_spellcheckResults"));
+ }
+ return tip;
+};
+
+
+/*************************************************************
+* trigger for an actiavation of a click to the
+* on correction list within an error
+*
+* @param evt standard javascript event param passed by the js
+* event subsystem
+**************************************************************/
+myfaces_Spellchecker.prototype.onCorrectionList = function(evt) {
+
+ if(evt.target.id != null) {
+ var toolTip = this.getToolTip(evt.target.id);
+ var content = evt.target.innerHTML;
+ var _this = this;
+ var _target = evt.target;
+ var jsonedData = null;
+ var requestUri = dojo.string.paramString(this.searchUrl,{"param1":
+ "spck[]="+encodeURIComponent("showsuggestions")+ //first param the comment
+ "&spck[]="+encodeURIComponent(this.spellmethod) //second param speller method
+ });
+ var progressor = new org.apache.myfaces.pagelet.Progressor();
+
+ progressor.showInProgress("Getting suggestions");
+ try {
+ dojo.io.bind({
+ sync: true,
+ url: requestUri,
+ useCache:true,
+ method: "POST",
+ content: {"content": content,"targetid": (evt.target.id+"")},
+
+ load:function(type, data, evt) {
+ progressor.hideInProgress();
+ var jsonFunc = new Function("jsoner", "return "+data);
+ jsonedData = jsonFunc();
+ },
+
+ error: function(type, data, evt) {
+
+ dojo.debug("error-transport"+data);
+ },
+ mimetype: "text/plain",
+ transport: "XMLHTTPTransport"
+ });
+ } catch (e) {
+ progressor.hideInProgress();
+ alert("Error:"+e.message);
+ }
+
+ toolTip.domNode.innerHTML = jsonedData["content"]+ "<li><div class='myfaces_SuggestEntry' id='"+evt.target.id+"_closecorr'>[close]</div></li>";
+ if(toolTip.displayed) {
+ toolTip.erase();
+ toolTip.displayed = false;
+ }
+
+ /*display the tooltip with a slight correctional position compared to the original pos*/
+ var scroll_offset = dojo.html.getScrollOffset();
+ if(!dojo.render.html.ie) {
+
+ //TODO mozilla iframe fixup for this one
+ var contentHolder = this.getContentHolder();
+ scroll_offset = [contentHolder.document.scrollLeft, contentHolder.document.scrollTop]
+ //toolTip.mouseX = evt.pageX + scroll_offset[0]|| evt.clientX + scroll_offset[0];
+ //toolTip.mouseY = evt.pageY + scroll_offset[1]|| evt.clientY + scroll_offset[1];
+ scroll_offset = dojo.html.getScrollOffset();
+ //toolTip.mouseX = evt.pageX + scroll_offset[0]|| evt.clientX + scroll_offset[0];
+ //toolTip.mouseY = evt.pageY + scroll_offset[1]|| evt.clientY + scroll_offset[1];
+ //TODO we have to walk all parents for the offset calc, here is a problem with
+ //moz
+ //alternatively we could use one of the corners
+
+ //We can resolve this in ie 7
+ //toolTip.domNode.style.position = "fixed";
+ } else {
+ toolTip.mouseX = evt.pageX + scroll_offset[0]|| evt.clientX + scroll_offset[0];
+ toolTip.mouseY = evt.pageY + scroll_offset[1]|| evt.clientY + scroll_offset[1];
+ }
+ toolTip.displayed = false;
+ toolTip.display();
+
+ if(jsonedData["noEntries"] != null) {
+ var noEntries = parseInt(jsonedData["noEntries"]);
+ for(var cnt = 1; cnt <= noEntries; cnt++) {
+ var targetHREF = dojo.byId(evt.target.id+"_corrid_"+cnt);
+ //we need to store the ref cascade to trackback once the correction is triggered
+ targetHREF["callerHrefId"] = evt.target.id;
+ dojo.event.connect(targetHREF,"onclick",_this,"onDoCorrection");
+ }
+ }
+ dojo.event.connect(dojo.byId(evt.target.id+"_closecorr"),"onclick",this, "onHideToolTip");
+ }
+};
+
+/***********************************************************
+* hide the tooltip event callback
+*
+* @param evt the event param sent by the javascript event
+* subsystem
+***********************************************************/
+myfaces_Spellchecker.prototype.onHideToolTip = function(evt) {
+ var scrollOffset = dojo.html.getScrollOffset();
+ var tip = dojo.widget.manager.getWidgetById("myfaces_Spcktooltip_dojoDialog_spellcheckResults");
+
+ if(tip !== null) {
+ tip.erase();
+ tip.displayed = false;
+ };
+ setScrollOffset(scrollOffset);
+ return false;
+};
+
+/***********************************************************
+* correction event callback
+*
+* @param evt the event handler param passed by the js event
+* subsystem
+************************************************************/
+myfaces_Spellchecker.prototype.onDoCorrection = function(evt) {
+ var targetId = evt.target["callerHrefId"];
+ var scrollOffset = dojo.html.getScrollOffset();
+ var toolTip = this.getToolTip(targetId);
+ var target = dojo.byId(targetId);
+
+ if(dojo.render.html.moz) { //we have the target in an iframe
+ target = this.getContentHolder().document.getElementById(targetId);
+ target.innerHTML = evt.target.innerHTML;
+ //we have to do some tricks here because the dom editor does not like node shifting
+ target.style.backgroundColor="";
+ target.onClick = "";
+ } else {
+ target.outerHTML = evt.target.innerHTML;
+ }
+
+
+
+ toolTip.hide();
+ setScrollOffset(scrollOffset);
+ return false;
+}
+
+
+
+/*================ Dialog edit subsystem =================*/
+/*========================================================
+* we define an event callback class to
+* have a functionality encapuslation in a sane manner
+* we have a general wrapper here to have a distinction between
+* the spellchecker itself and the connections to the outer
+* system, a more clear split was planned originally
+* but for now we have this messy split here
+* in the long run this has to be changed to something more clear
+*
+* @param parentRef the ref to the var needed for internal timers
+* @param dlgId the div dialogId which is referenced by the pagelet
+* @param parentControlId the id of the parent control which has to be filled internally (usually a hidden field)
+* @param dialogEditorId the id of the internal dialog editor
+* @param spellurl the url for the spellchecker ajax call
+* @param spellmethod the jsf spellmethod binding passthrough param
+* @param readonly readonly
+* @param controlMode the controlMode as defined by the pagelet component
+* itself (currently supported pagelet pagelet-richtext und pagelet-textarea und pagelet-textarea)
+*=========================================================*/
+function myfaces_Pagelet(parentRef, dlgid, parentControlId, dialogEditorId, spellurl, spellmethod, readonly, controlMode) {
+
+ /*we reference only the ids to avoid tangeling control objects on ie*/
+ this.dialogId = dlgid;
+ this.parentRef = parentRef;
+ this.parentId = parentControlId;
+ this.dialogEditId = dialogEditorId;
+ this.readonly = readonly;
+ this.controlMode = controlMode;
+
+ myfaces_shiftToBody(this.dialogId);
+
+ //causes layout problems if not done, after subsequent posts
+ dojo.byId(this.dialogId).style.visibility="hidden";
+ dojo.byId(this.dialogId).style.position="absolute";
+
+ var parentContent = dojo.byId(this.parentId);
+ var dialogEditor = dojo.byId(this.dialogEditId);
+ var val = null;
+
+ if(parentContent.value)
+ val = parentContent.value;
+ else
+ val = parentContent.innerHTML;
+
+ if(dialogEditor.value)
+ dialogEditor.value = val;
+ else
+ dialogEditor.innerHTML = val;
+
+ /*register a spellchecking object in a 0:1 reference*/
+ /*which we will use later for dynamic spellcheck triggering*/
+ /*and content aftercleaning*/
+ this.spellchecker = new myfaces_Spellchecker(this.parentRef+".spellchecker", this.dialogEditId+"_dj", true, spellurl, spellmethod);
+};
+
+
+
+
+/*********************************************************************************
+* method which returns the editor
+*
+* @param fixit adds a setContent method to the editor (which is missing currently)
+* @param enforceCreation enforces the creation of a new editor
+* even if an old one already was created
+*********************************************************************************/
+myfaces_Pagelet.prototype.getEditor = function(fixit, enforceCreation) {
+ var editor = dojo.widget.manager.getWidgetById(this.dialogEditId+"_dj");
+
+ if(editor == null) {
+ var oldItemGroups = dojo.widget.html.Editor.itemGroups;
+
+
+
+ //var theitems = [ "linkGroup", "|", "textGroup", "blockGroup","|", "justifyGroup", "|", "listGroup", "indentGroup", "|", "colorGroup"];
+ //todo move the items from here to jsf
+ var theitems = [ "textGroup" ,"|", "justifyGroup"];
+ if(this.controlMode == "pagelet-rawtext") {
+ theitems = [];
+ }
+
+
+ editor = dojo.widget.createWidget("PageletEditor", {id:(this.dialogEditId+"_dj"), items: theitems },
+ dojo.byId(this.dialogEditId));
+
+ }
+ if(fixit != null && fixit && editor.setEditorContent == null) {
+ editor.setEditorContent = function(text) {
+ if(editor._richText != null && editor._richText.editNode != null)
+ editor._richText.editNode.innerHTML = text;
+ else
+ dojo.debug("no rich text found"+this.dialogEditId);
+ }
+ }
+ return editor;
+};
+
+
+/************************************************************
+* event handler which shows the main dialog
+* so that the text can be edited
+*
+* @param evt standard event param
+*************************************************************/
+myfaces_Pagelet.prototype.onShowdlg = function (evt) {
+ var dialog = dojo.byId(this.dialogId);
+ myfaces_shiftToBody(this.dialogId);
+
+ var scroll_offset = dojo.html.getScrollOffset();
+ //ie fix
+ dialog.style.position = "absolute";
+ //if (dojo.render.html.ie) {//ie does not do fixed yet, we have to simulate
+ dialog.style.left = (parseInt(scroll_offset[0])+ 20)+"px"
+ dialog.style.top = (parseInt(scroll_offset[1])+20) +"px";
+ //}
+ var viewport_size = dojo.html.getViewportSize();
+
+ dialog.style.width = (parseInt(viewport_size[0] ) - 40)+"px";
+ dialog.style.height = (parseInt(viewport_size[1] ) - 40)+"px";
+
+ if(!this.bgIframe)
+ this.bgIframe = new dojo.html.BackgroundIframe();
+
+ this.bgIframe.show([0,0, parseInt(viewport_size[0]), parseInt(viewport_size[1])]);
+ this.bgIframe.setZIndex(1);
+
+
+ dialog.style.zIndex = 3;
+ dialog.style.visibility = "visible";
+
+ dojo.fx.html.fadeShow(dialog, 200);
+
+ var editorDiv = dojo.byId(this.dialogEditId);
+ editorDiv.style.width = (parseInt(viewport_size[0]) - 40)+"px";
+
+ if(this.readonly != null && !this.readonly)
+ editorDiv.style.height = (parseInt(viewport_size[1]) - 96)+"px";
+ else if(dojo.render.html.ie) //Fixup for a layouting bug in ie
+ editorDiv.style.height = (parseInt(viewport_size[1]) - 50)+"px";
+ else
+ editorDiv.style.height = (parseInt(viewport_size[1]) - 70)+"px";
+
+ editorDiv.style.overflow = "auto";
+
+
+ var parent = dojo.byId(this.parentId);
+
+ var editor = null;
+ if(!this.readonly)
+ editor = this.getEditor(true);
+
+
+ dojo.html.show(this.dialogId);
+ dojo.html.show(this.dialogEditId);//keep it suppressed so that we do not regenerate it
+
+ var parentContent = null;
+
+ //we probe for a rich text field first for getting the values
+ parentContent = dojo.widget.manager.getWidgetById(this.parentId+"RichText");
+ if(parentContent == null)
+ parentContent = dojo.byId(this.parentId);
+
+ var val = null;
+
+ if(parentContent.getEditorContent) {
+ val = parentContent.getEditorContent();
+ //alert(parentContent.getEditorContent());
+ } else if(parentContent.value) {
+ val = parentContent.value;
+ } else {
+ val = parentContent.innerHTML;
+ }
+
+ dojo.lang.setTimeout(this, this.onDlgFill, 500, val);
+
+};
+
+myfaces_Pagelet.prototype.onDlgFill = function(val) {
+ if(this.readonly) {
+ //in this case we are preinitalized
+ var dialogEditor = dojo.byId(this.dialogEditId);
+ dialogEditor.innerHTML = val;
+ return;
+ }
+
+ var editor = this.getEditor(true);
+
+ if(editor.setEditorContent) {
+ editor.setEditorContent(val);
+ editor.focus();
+ } else
+ dojo.lang.setTimeout(this, this.onDlgFill, 200, val);
+
+};
+
+
+/************************************************************
+* event handler which closes the
+* editor dialog
+*
+* @param evt standard javascript event
+*************************************************************/
+myfaces_Pagelet.prototype.onDlgClose = function(evt) {
+ var dialog = dojo.byId(this.dialogId);
+
+ var parent = dojo.widget.manager.getWidgetById(this.parentId+"RichText");
+ if(parent == null)
+ parent = dojo.byId(this.parentId);
+
+ /*lets ajax the cleanup (because in the end only the server knows the data structures)*/
+ this.spellchecker.cleanupAjax();
+
+ var editor = this.getEditor();
+
+ if(parent.setEditorContent) {
+ parent.setEditorContent(editor.getEditorContent());
+ } else if(parent.value)
+ parent.value = editor.getEditorContent();
+ else
+ parent.innerHTML = editor.getEditorContent();
+
+ /*we need an optional backup control for the value binding*/
+ /*TODO remove this binding legacy in favor of a generalized control approach*/
+ var parentBack = dojo.byId(this.parentId+"_ta");
+
+ if(parentBack != null )
+ parentBack.value = editor.getEditorContent();
+
+ //ie bleed through fix
+ if(this.bgIframe != null)
+ this.bgIframe.hide();
+ dojo.html.hide(this.dialogId);
+};
+
+myfaces_Pagelet.prototype.onDlgCancel = function(evt) {
+ //ie bleed through fix
+ this.spellchecker.reset();
+ if(this.bgIframe != null)
+ this.bgIframe.hide();
+ dojo.html.hide(this.dialogId);
+}
+
+/*******************************************************
+* standard spell check callback
+********************************************************/
+myfaces_Pagelet.prototype.onSpellCheck = function() {
+ this.spellchecker.markAsErrorAjax("");
+};
+
+/*******************************************************
+* standard cleanup callback
+********************************************************/
+myfaces_Pagelet.prototype.onCleanup = function() {
+ this.spellchecker.cleanupAjax();
+};
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/progressor.js
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/progressor.js?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/progressor.js (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/progressor.js Wed May 3 14:24:53 2006
@@ -0,0 +1,63 @@
+dojo.hostenv.setModulePrefix("org.apache.myfaces.pagelet", "../spellchecker.AjaxInputSpellcheckRenderer");
+dojo.widget.manager.registerWidgetPackage("org.apache.myfaces.pagelet");
+
+dojo.provide("org.apache.myfaces.pagelet.Progressor");
+/*=====================================================
+ * class for a a generic progress
+ * handler
+ * this class currently shows a floating
+ * div and blends it out
+ *====================================================*/
+org.apache.myfaces.pagelet.Progressor = function() {
+ dojo.widget.HtmlWidget.call(this);
+ /**************************************************
+ * shows the progress text
+ *
+ * @param text the progress text to be shown
+ **************************************************/
+ this.showInProgress = function (text) {
+
+ //ie bleed through fix
+ if(!this.bgIframe)
+ this.bgIframe = new dojo.html.BackgroundIframe();
+
+ var inprogress = dojo.byId("dojoDialog_inprogress");
+ myfaces_shiftToBody("dojoDialog_inprogress");
+ inprogress.style.position = "absolute";
+ if (inprogress === null) {
+ return;
+ }
+ if (text !== null) {
+ inprogress.innerHTML = text;
+ }
+
+ //visible neede otherwise fade show does not work
+ var scroll_offset = dojo.html.getScrollOffset();
+ inprogress.style.left = (parseInt(scroll_offset[0])+ 20)+"px"
+ inprogress.style.top = (parseInt(scroll_offset[1])+20) +"px";
+
+ var w = dojo.style.getOuterWidth(inprogress);
+ var h = dojo.style.getOuterHeight(inprogress);
+
+ inprogress.style.visibility = "visible";
+ dojo.fx.html.fadeShow(inprogress, 300);
+ this.bgIframe.show([0,0,w,h]);
+ this.bgIframe.setZIndex(98);
+ inprogress.style.zIndex = 99;
+
+ };
+
+ /**
+ * hides the progress text
+ */
+ this.hideInProgress = function () {
+ var inprogress = dojo.byId("dojoDialog_inprogress");
+ if (inprogress === null) {
+ return;
+ }
+ dojo.fx.html.fadeHide(inprogress, 300);
+ inprogress.style.visibility = "hidden";
+ this.bgIframe.hide();
+ };
+}
+dojo.inherits(org.apache.myfaces.pagelet.Progressor, dojo.widget.HtmlWidget);
\ No newline at end of file
Added: myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/spell_checker.css
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/spell_checker.css?rev=399437&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/spell_checker.css (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources/org/apache/myfaces/custom/pagelet/resource/spell_checker.css Wed May 3 14:24:53 2006
@@ -0,0 +1,55 @@
+.status {
+ color: #FF0000;
+ padding-left: 150px;
+ white-space: nowrap;
+}
+
+.suggestion_box {
+ background-color: #E8F1FF;
+ border: 1px solid #000000;
+ position: absolute;
+ padding: 2px 2px 2px 2px;
+}
+.suggestion {
+ cursor: pointer;
+ text-decoration: underline;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #000000;
+}
+.edit_box {
+ background-color: #FFFFFF;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ border: 1px inset #000000;
+ padding-top: 2px;
+ padding-left: 2px;
+ overflow: auto;
+}
+.text_box {
+ background-color: #FFFFFF;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+}
+.highlight {
+ color: #FF0000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ text-decoration: underline;
+ cursor: pointer;
+}
+.no_misspellings {
+ color: #009933;
+}
+.check_spelling {
+ color: #0066CC;
+ text-decoration: underline;
+ cursor: pointer;
+}
+.resume_editing {
+ color: #009933;
+ text-decoration: underline;
+ cursor: pointer;
+}
\ No newline at end of file
|