OSDN Git Service

2.0.3 jp10 beta
authorhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Sun, 20 May 2007 16:24:55 +0000 (16:24 +0000)
committerhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Sun, 20 May 2007 16:24:55 +0000 (16:24 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/plugin@574 1ca29b6e-896d-4ea0-84a5-967f57386b96

107 files changed:
trunk/NP_TrackBack/NP_TrackBack.php
trunk/NP_TrackBack/trackback/grid.php
trunk/NP_TrackBack/trackback/index.php
trunk/NP_TrackBack/trackback/japanese-euc.help.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/all_ajax.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/blocked_ajax.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/menu.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_all.xml
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_blocked.xml
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_doblock.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dodelete.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dounblock.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.help.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/all_ajax.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/blocked_ajax.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/menu.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_all.xml
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_blocked.xml
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_doblock.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dodelete.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dounblock.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js [deleted file]
trunk/NP_TrackBack/trackback/js/prototype.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico.js [deleted file]
trunk/NP_TrackBack/trackback/js/rico/css/coffee-with-milk.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/grayedout.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/greenHdg.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/iegradient.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/ricoCalendar.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/ricoGrid.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/ricoLiveGridForms.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/ricoMenu.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/ricoTree.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/tanChisel.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/css/warmfall.css [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/export-owc.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/export-plain.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/aline.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/calarrow.png [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/calendaricon.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/close.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/divider.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/doc.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/dotbutton.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/drop.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/filtercol.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/folderclosed.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/folderopen.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/grayedout.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/left.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/link.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/node.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodeblank.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodelast.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodeline.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodem.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodemlast.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodep.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/nodeplast.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/resize.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/ricologo.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/right.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/shadow.png [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/shadow_ll.png [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/shadow_ur.png [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/sort_asc.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/images/sort_desc.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/prototype.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/rico.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoAjaxEngine.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoBehaviors.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoCalendar.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoColor.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoColorPicker.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoCommon.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoComponents.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoDashboard.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoDragDrop.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoEffects.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoGridCommon.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoLiveGrid.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridAjax.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridForms.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridMenu.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoMenu.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoSheet.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.xsl [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid2xl.xsl [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoStyles.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/ricoTree.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_de.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_es.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_fr.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_it.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ja.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_pt.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ru.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ua.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_zh.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/all_ajax.html
trunk/NP_TrackBack/trackback/templates/blocked_ajax.html
trunk/NP_TrackBack/trackback/templates/response_all.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/response_blocked.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/response_doblock.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/response_dodelete.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/response_dounblock.xml [new file with mode: 0644]

index 36bf5ed..252d615 100644 (file)
        * ==========================================================================================
        */
 
-       // Compatiblity with Nucleus < = 2.0
-       if (!function_exists('sql_table')) { function sql_table($name) { return 'nucleus_' . $name; } }
-
-       
        class NP_TrackBack extends NucleusPlugin {
-
                var $useCurl = 1; // use curl? 2:precheck+read by curl, 1: read by curl 0: fread
 
 //modify start+++++++++
                        ';
                        if($offset)
                                $query .= ' LIMIT '.intval($offset).', ' .intval($amount);
-                       $res = mysql_query($query);
+                       $res = sql_query($query);
                        while ($row = mysql_fetch_array($res))
                        {
 
 //mod by cles end
 
 /*
-                       $res = mysql_query('
+                       $res = sql_query('
                                SELECT 
                                        url, 
                                        md5(url) as urlHash,
                                $query .= ' LIMIT '.intval($amount);
                        
                        if( $amount != 0)
-                               $res = mysql_query($query);
+                               $res = sql_query($query);
 
                        $gVars = array(
                                'action' => $this->getTrackBackUrl(intval($tb_id)),
                                ORDER BY 
                                        timestamp DESC
                        ';
-                       $result = mysql_query($q);
+                       $result = sql_query($q);
                        $total = mysql_result($result,0,0);
 
                        if($amount != -1 && $total > $amount){
                                echo "\t\t\t<description>".htmlspecialchars($excerpt, ENT_QUOTES)."</description>\n";
        
                                $query = 'SELECT url, blog_name, excerpt, title, UNIX_TIMESTAMP(timestamp) as timestamp FROM '.sql_table('plugin_tb').' WHERE tb_id='.intval($tb_id).' AND block = 0 ORDER BY timestamp DESC';
-                               $res = mysql_query($query);
+                               $res = sql_query($query);
                                while ($o = mysql_fetch_object($res)) 
                                {
                                        // No need to do conversion, because it is already UTF-8
 //modify end+++++++++
 
                        // 4. Save data in the DB
-                       $res = @mysql_query('
+                       $res = @sql_query('
                                SELECT 
                                        tb_id, block, spam
                                FROM 
                        {
                                // Existing TB, update it
 /*
-                               $res = @mysql_query('
+                               $res = @sql_query('
                                        UPDATE
                                                '.sql_table('plugin_tb').'
                                        SET 
 //modify start+++++++++
                                $rows = mysql_fetch_assoc($res);
                                $spam = ( $rows['block'] || $rows['spam'] ) ? true : false;
-                               $res = @mysql_query('
+                               $res = @sql_query('
                                        UPDATE
                                                '.sql_table('plugin_tb').'
                                        SET 
                                ';
 //modify end+++++++++
                                
-                               $res = @mysql_query($query);
+                               $res = @sql_query($query);
 
                                if (!$res) {
                                        return 'Could not save trackback data, possibly because of a double entry: ' . mysql_error() . $query;
                function redirect($tb_id, $urlHash){
                        global $CONF;
                        $query = 'SELECT url FROM '.sql_table('plugin_tb').' WHERE tb_id='.intval($tb_id).' and md5(url)="'.$urlHash.'"';
-                       $res = mysql_query($query);
+                       $res = sql_query($query);
                        
                        $url = $CONF['SiteURL'];
                        
                
                function event_RetrieveTrackback($data) {
                        
-                       $res = mysql_query('
+                       $res = sql_query('
                        SELECT 
                        url, 
                        title, 
                {
                        
                        // Check to see if the cache contains this link
-                       $res = mysql_query('SELECT url, title FROM '.sql_table('plugin_tb_lookup').' WHERE link=\''.mysql_real_escape_string($link).'\'');
+                       $res = sql_query('SELECT url, title FROM '.sql_table('plugin_tb_lookup').' WHERE link=\''.mysql_real_escape_string($link).'\'');
 
                        if ($row = mysql_fetch_array($res)) 
                        {
                                                        $convertedTitle = $title;
 /*
                                                // Store in cache
-                                               $res = mysql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','".mysql_real_escape_string($title)."')");
+                                               $res = sql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','".mysql_real_escape_string($title)."')");
 */
                                                // Store in cache
-                                               $res = mysql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','".mysql_real_escape_string($convertedTitle)."')");
+                                               $res = sql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','".mysql_real_escape_string($convertedTitle)."')");
 //modify end+++++++++
                                                $title = $this->_decode_entities($title);
 
                                                $uri = html_entity_decode($uri, ENT_COMPAT);
        
                                                // Store in cache
-                                               $res = mysql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','')");
+                                               $res = sql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','".mysql_real_escape_string($uri)."','')");
        
                                                return array (
                                                        $uri, $uri
                        }
                        
                        // Store in cache
-                       $res = mysql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','','')");
+                       $res = sql_query("INSERT INTO ".sql_table('plugin_tb_lookup')." (link, url, title) VALUES ('".mysql_real_escape_string($link)."','','')");
        
                        return array ('', '');
                }
                /**************************************************************************************/
                /* Internal helper functions for dealing with encodings and entities                  */
        
-               var $entities_cp1251 = array (
-                       '&#128;'                => '&#8364;',
-                       '&#130;'                => '&#8218;',
-                       '&#131;'                => '&#402;',    
-                       '&#132;'                => '&#8222;',   
-                       '&#133;'                => '&#8230;',   
-                       '&#134;'                => '&#8224;',   
-                       '&#135;'                => '&#8225;',   
-                       '&#136;'                => '&#710;',    
-                       '&#137;'                => '&#8240;',   
-                       '&#138;'                => '&#352;',    
-                       '&#139;'                => '&#8249;',   
-                       '&#140;'                => '&#338;',    
-                       '&#142;'                => '&#381;',    
-                       '&#145;'                => '&#8216;',   
-                       '&#146;'                => '&#8217;',   
-                       '&#147;'                => '&#8220;',   
-                       '&#148;'                => '&#8221;',   
-                       '&#149;'                => '&#8226;',   
-                       '&#150;'                => '&#8211;',   
-                       '&#151;'                => '&#8212;',   
-                       '&#152;'                => '&#732;',    
-                       '&#153;'                => '&#8482;',   
-                       '&#154;'                => '&#353;',    
-                       '&#155;'                => '&#8250;',   
-                       '&#156;'                => '&#339;',    
-                       '&#158;'                => '&#382;',    
-                       '&#159;'                => '&#376;',    
-               );
-       
                var $entities_default = array (
                        '&quot;'                => '&#34;',             
                        '&amp;'                 => '&#38;',             
                        '&gt;'                  => '&#62;',             
                );
        
-               var $entities_latin = array (
-                       '&nbsp;'                => '&#160;',    
-                       '&iexcl;'               => '&#161;',    
-                       '&cent;'                => '&#162;',    
-                       '&pound;'               => '&#163;',    
-                       '&curren;'              => '&#164;',    
-                       '&yen;'                 => '&#165;',    
-                       '&brvbar;'              => '&#166;',    
-                       '&sect;'                => '&#167;',    
-                       '&uml;'                 => '&#168;',    
-                       '&copy;'                => '&#169;',    
-                       '&ordf;'                => '&#170;',    
-                       '&laquo;'               => '&#171;',    
-                       '&not;'                 => '&#172;',    
-                       '&shy;'                 => '&#173;',    
-                       '&reg;'                 => '&#174;',    
-                       '&macr;'                => '&#175;',    
-                       '&deg;'                 => '&#176;',    
-                       '&plusmn;'              => '&#177;',    
-                       '&sup2;'                => '&#178;',    
-                       '&sup3;'                => '&#179;',    
-                       '&acute;'               => '&#180;',    
-                       '&micro;'               => '&#181;',    
-                       '&para;'                => '&#182;',    
-                       '&middot;'              => '&#183;',    
-                       '&cedil;'               => '&#184;',    
-                       '&sup1;'                => '&#185;',    
-                       '&ordm;'                => '&#186;',    
-                       '&raquo;'               => '&#187;',    
-                       '&frac14;'              => '&#188;',    
-                       '&frac12;'              => '&#189;',    
-                       '&frac34;'              => '&#190;',    
-                       '&iquest;'              => '&#191;',    
-                       '&Agrave;'              => '&#192;',    
-                       '&Aacute;'              => '&#193;',    
-                       '&Acirc;'               => '&#194;',    
-                       '&Atilde;'              => '&#195;',    
-                       '&Auml;'                => '&#196;',    
-                       '&Aring;'               => '&#197;',    
-                       '&AElig;'               => '&#198;',    
-                       '&Ccedil;'              => '&#199;',    
-                       '&Egrave;'              => '&#200;',    
-                       '&Eacute;'              => '&#201;',    
-                       '&Ecirc;'               => '&#202;',    
-                       '&Euml;'                => '&#203;',    
-                       '&Igrave;'              => '&#204;',    
-                       '&Iacute;'              => '&#205;',    
-                       '&Icirc;'               => '&#206;',    
-                       '&Iuml;'                => '&#207;',    
-                       '&ETH;'                 => '&#208;',    
-                       '&Ntilde;'              => '&#209;',    
-                       '&Ograve;'              => '&#210;',    
-                       '&Oacute;'              => '&#211;',    
-                       '&Ocirc;'               => '&#212;',    
-                       '&Otilde;'              => '&#213;',    
-                       '&Ouml;'                => '&#214;',    
-                       '&times;'               => '&#215;',    
-                       '&Oslash;'              => '&#216;',    
-                       '&Ugrave;'              => '&#217;',    
-                       '&Uacute;'              => '&#218;',    
-                       '&Ucirc;'               => '&#219;',    
-                       '&Uuml;'                => '&#220;',    
-                       '&Yacute;'              => '&#221;',    
-                       '&THORN;'               => '&#222;',    
-                       '&szlig;'               => '&#223;',    
-                       '&agrave;'              => '&#224;',    
-                       '&aacute;'              => '&#225;',    
-                       '&acirc;'               => '&#226;',    
-                       '&atilde;'              => '&#227;',    
-                       '&auml;'                => '&#228;',    
-                       '&aring;'               => '&#229;',    
-                       '&aelig;'               => '&#230;',    
-                       '&ccedil;'              => '&#231;',    
-                       '&egrave;'              => '&#232;',    
-                       '&eacute;'              => '&#233;',    
-                       '&ecirc;'               => '&#234;',    
-                       '&euml;'                => '&#235;',    
-                       '&igrave;'              => '&#236;',    
-                       '&iacute;'              => '&#237;',    
-                       '&icirc;'               => '&#238;',    
-                       '&iuml;'                => '&#239;',    
-                       '&eth;'                 => '&#240;',    
-                       '&ntilde;'              => '&#241;',    
-                       '&ograve;'              => '&#242;',    
-                       '&oacute;'              => '&#243;',    
-                       '&ocirc;'               => '&#244;',    
-                       '&otilde;'              => '&#245;',    
-                       '&ouml;'                => '&#246;',    
-                       '&divide;'              => '&#247;',    
-                       '&oslash;'              => '&#248;',    
-                       '&ugrave;'              => '&#249;',    
-                       '&uacute;'              => '&#250;',    
-                       '&ucirc;'               => '&#251;',    
-                       '&uuml;'                => '&#252;',    
-                       '&yacute;'              => '&#253;',    
-                       '&thorn;'               => '&#254;',    
-                       '&yuml;'                => '&#255;',    
-               );      
-       
-               var $entities_extended = array (
-                       '&OElig;'               => '&#338;',    
-                       '&oelig;'               => '&#229;',    
-                       '&Scaron;'              => '&#352;',    
-                       '&scaron;'              => '&#353;',    
-                       '&Yuml;'                => '&#376;',    
-                       '&circ;'                => '&#710;',    
-                       '&tilde;'               => '&#732;',    
-                       '&esnp;'                => '&#8194;',   
-                       '&emsp;'                => '&#8195;',   
-                       '&thinsp;'              => '&#8201;',   
-                       '&zwnj;'                => '&#8204;',   
-                       '&zwj;'                 => '&#8205;',   
-                       '&lrm;'                 => '&#8206;',   
-                       '&rlm;'                 => '&#8207;',   
-                       '&ndash;'               => '&#8211;',   
-                       '&mdash;'               => '&#8212;',   
-                       '&lsquo;'               => '&#8216;',   
-                       '&rsquo;'               => '&#8217;',   
-                       '&sbquo;'               => '&#8218;',   
-                       '&ldquo;'               => '&#8220;',   
-                       '&rdquo;'               => '&#8221;',   
-                       '&bdquo;'               => '&#8222;',   
-                       '&dagger;'              => '&#8224;',   
-                       '&Dagger;'              => '&#8225;',   
-                       '&permil;'              => '&#8240;',   
-                       '&lsaquo;'              => '&#8249;',
-                       '&rsaquo;'              => '&#8250;',
-                       '&euro;'                => '&#8364;',
-                       '&fnof;'                => '&#402;',    
-                       '&Alpha;'               => '&#913;',    
-                       '&Beta;'                => '&#914;',    
-                       '&Gamma;'               => '&#915;',    
-                       '&Delta;'               => '&#916;',    
-                       '&Epsilon;'             => '&#917;',    
-                       '&Zeta;'                => '&#918;',    
-                       '&Eta;'                 => '&#919;',    
-                       '&Theta;'               => '&#920;',    
-                       '&Iota;'                => '&#921;',    
-                       '&Kappa;'               => '&#922;',    
-                       '&Lambda;'              => '&#923;',    
-                       '&Mu;'                  => '&#924;',    
-                       '&Nu;'                  => '&#925;',    
-                       '&Xi;'                  => '&#926;',    
-                       '&Omicron;'             => '&#927;',    
-                       '&Pi;'                  => '&#928;',    
-                       '&Rho;'                 => '&#929;',    
-                       '&Sigma;'               => '&#931;',    
-                       '&Tau;'                 => '&#932;',    
-                       '&Upsilon;'             => '&#933;',    
-                       '&Phi;'                 => '&#934;',    
-                       '&Chi;'                 => '&#935;',    
-                       '&Psi;'                 => '&#936;',    
-                       '&Omega;'               => '&#937;',    
-                       '&alpha;'               => '&#945;',    
-                       '&beta;'                => '&#946;',    
-                       '&gamma;'               => '&#947;',    
-                       '&delta;'               => '&#948;',    
-                       '&epsilon;'             => '&#949;',    
-                       '&zeta;'                => '&#950;',    
-                       '&eta;'                 => '&#951;',    
-                       '&theta;'               => '&#952;',    
-                       '&iota;'                => '&#953;',    
-                       '&kappa;'               => '&#954;',    
-                       '&lambda;'              => '&#955;',    
-                       '&mu;'                  => '&#956;',    
-                       '&nu;'                  => '&#957;',    
-                       '&xi;'                  => '&#958;',    
-                       '&omicron;'             => '&#959;',    
-                       '&pi;'                  => '&#960;',    
-                       '&rho;'                 => '&#961;',    
-                       '&sigmaf;'              => '&#962;',    
-                       '&sigma;'               => '&#963;',    
-                       '&tau;'                 => '&#964;',    
-                       '&upsilon;'             => '&#965;',    
-                       '&phi;'                 => '&#966;',    
-                       '&chi;'                 => '&#967;',    
-                       '&psi;'                 => '&#968;',    
-                       '&omega;'               => '&#969;',    
-                       '&thetasym;'    => '&#977;',    
-                       '&upsih;'               => '&#978;',    
-                       '&piv;'                 => '&#982;',    
-                       '&bull;'                => '&#8226;',   
-                       '&hellip;'              => '&#8230;',   
-                       '&prime;'               => '&#8242;',   
-                       '&Prime;'               => '&#8243;',   
-                       '&oline;'               => '&#8254;',   
-                       '&frasl;'               => '&#8260;',   
-                       '&weierp;'              => '&#8472;',   
-                       '&image;'               => '&#8465;',   
-                       '&real;'                => '&#8476;',   
-                       '&trade;'               => '&#8482;',   
-                       '&alefsym;'     => '&#8501;',   
-                       '&larr;'                => '&#8592;',   
-                       '&uarr;'                => '&#8593;',   
-                       '&rarr;'                => '&#8594;',   
-                       '&darr;'                => '&#8595;',   
-                       '&harr;'                => '&#8596;',   
-                       '&crarr;'               => '&#8629;',   
-                       '&lArr;'                => '&#8656;',   
-                       '&uArr;'                => '&#8657;',   
-                       '&rArr;'                => '&#8658;',   
-                       '&dArr;'                => '&#8659;',   
-                       '&hArr;'                => '&#8660;',   
-                       '&forall;'              => '&#8704;',   
-                       '&part;'                => '&#8706;',   
-                       '&exist;'               => '&#8707;',   
-                       '&empty;'               => '&#8709;',   
-                       '&nabla;'               => '&#8711;',   
-                       '&isin;'                => '&#8712;',   
-                       '&notin;'               => '&#8713;',   
-                       '&ni;'                  => '&#8715;',   
-                       '&prod;'                => '&#8719;',   
-                       '&sum;'                 => '&#8721;',   
-                       '&minus;'               => '&#8722;',   
-                       '&lowast;'              => '&#8727;',   
-                       '&radic;'               => '&#8730;',   
-                       '&prop;'                => '&#8733;',   
-                       '&infin;'               => '&#8734;',   
-                       '&ang;'                 => '&#8736;',   
-                       '&and;'                 => '&#8743;',   
-                       '&or;'                  => '&#8744;',   
-                       '&cap;'                 => '&#8745;',   
-                       '&cup;'                 => '&#8746;',   
-                       '&int;'                 => '&#8747;',   
-                       '&there4;'              => '&#8756;',   
-                       '&sim;'                 => '&#8764;',   
-                       '&cong;'                => '&#8773;',   
-                       '&asymp;'               => '&#8776;',   
-                       '&ne;'                  => '&#8800;',   
-                       '&equiv;'               => '&#8801;',   
-                       '&le;'                  => '&#8804;',   
-                       '&ge;'                  => '&#8805;',   
-                       '&sub;'                 => '&#8834;',   
-                       '&sup;'                 => '&#8835;',   
-                       '&nsub;'                => '&#8836;',   
-                       '&sube;'                => '&#8838;',   
-                       '&supe;'                => '&#8839;',   
-                       '&oplus;'               => '&#8853;',   
-                       '&otimes;'      => '&#8855;',   
-                       '&perp;'                => '&#8869;',   
-                       '&sdot;'                => '&#8901;',   
-                       '&lceil;'               => '&#8968;',   
-                       '&rceil;'               => '&#8969;',   
-                       '&lfloor;'              => '&#8970;',   
-                       '&rfloor;'              => '&#8971;',   
-                       '&lang;'                => '&#9001;',   
-                       '&rang;'                => '&#9002;',   
-                       '&loz;'                 => '&#9674;',   
-                       '&spades;'              => '&#9824;',   
-                       '&clubs;'               => '&#9827;',   
-                       '&hearts;'              => '&#9829;',   
-                       '&diams;'               => '&#9830;',   
-               );
-       
-       
 //modify start+++++++++
                function _restore_to_utf8($contents)
                {
                         
                        /// Convert all hexadecimal entities to decimal entities
                        $string = preg_replace('/&#[Xx]([0-9A-Fa-f]+);/e', "'&#'.hexdec('\\1').';'", $string);          
-
-                       // Deal with invalid cp1251 numeric entities
-                       $string = strtr($string, $this->entities_cp1251);
+                       
+                       global $_entities;
+                       // Deal with invalid cp1251 numeric entities    
+                       $string = strtr($string, $_entities['cp1251']);
 
                        // Convert all named entities to numeric entities
                        $string = strtr($string, $this->entities_default);
-                       $string = strtr($string, $this->entities_latin);
-                       $string = strtr($string, $this->entities_extended);
+                       $string = strtr($string, $_entities['named']);
 
                        // Convert all numeric entities to UTF-8
                        $string = preg_replace('/&#([0-9]+);/e', "'&#x'.dechex('\\1').';'", $string);
                        return $string;
                }
        
-               function _hex_to_utf8($s)
-               {
-                       /* IN:  string containing one hexadecimal Unicode character
-                        * OUT: string containing one binary UTF-8 character
-                        */
-                        
-                       $c = hexdec($s);
-               
-                       if ($c < 0x80) {
-                               $str = chr($c);
-                       }
-                       else if ($c < 0x800) {
-                               $str = chr(0xC0 | $c>>6) . chr(0x80 | $c & 0x3F);
-                       }
-                       else if ($c < 0x10000) {
-                               $str = chr(0xE0 | $c>>12) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F);
-                       }
-                       else if ($c < 0x200000) {
-                               $str = chr(0xF0 | $c>>18) . chr(0x80 | $c>>12 & 0x3F) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F);
-                       }
-                       
-                       return $str;
+               function _hex_to_utf8($s){
+                       return entity::_hex_to_utf8($s);
                }               
 
                function _utf8_to_entities($string)
@@ -2580,7 +2270,7 @@ function _strip_controlchar($string){
                        
                // save data in the DB
                $query = 'INSERT INTO ' . sql_table('plugin_tb_lc') . " (tb_id, from_id) VALUES ('".intval($tb_id)."','".intval($itemid)."')";
-               $res = @mysql_query($query);
+               $res = @sql_query($query);
                if (!$res) 
                        return 'Could not save trackback data, possibly because of a double entry: ' . mysql_error();
        }
@@ -2593,7 +2283,7 @@ function _strip_controlchar($string){
                
                // create SQL query
                $query = 'SELECT t.from_id as from_id , i.ititle as ititle, i.ibody as ibody, i.itime as itime, i.iblog as iblog FROM '.sql_table('plugin_tb_lc').' as t, '.sql_table('item').' as i WHERE t.tb_id='.intval($tb_id) .' and i.inumber=t.from_id ORDER BY i.itime DESC';
-               $res = mysql_query($query);
+               $res = sql_query($query);
                
                $vars = array(
                        'tburl' => $this->getTrackBackUrl($tb_id)
@@ -2632,7 +2322,7 @@ function _strip_controlchar($string){
                if (!$this->canDelete($tb_id))
                        return 'You\'re not allowed to delete this trackback item';
                $query = 'DELETE FROM ' . sql_table('plugin_tb_lc') . " WHERE tb_id='" . intval($tb_id) . "' and from_id='" . intval($from_id) ."'";
-               mysql_query($query);
+               sql_query($query);
                return '';
        }
        
@@ -2660,7 +2350,7 @@ function _strip_controlchar($string){
                function getName()        {             return 'TrackBack';   }
                function getAuthor()      {             return 'rakaz + nakahara21 + hsur'; }
                function getURL()         {             return 'http://blog.cles.jp/np_cles/category/31/subcatid/3'; }
-               function getVersion()     {             return '2.0.3 jp9'; }
+               function getVersion()     {             return '2.0.3 jp10'; }
                function getDescription() {             return _TB_DESCRIPTION; }
        
 //modify start+++++++++
@@ -2672,7 +2362,7 @@ function _strip_controlchar($string){
 
                function getEventList()   {             return array('QuickMenu','PostAddItem','AddItemFormExtras','EditItemFormExtras','PreUpdateItem','PrepareItemForEdit', 'BookmarkletExtraHead', 'RetrieveTrackback', 'SendTrackback', 'InitSkinParse'); }
 //modify end+++++++++
-               function getMinNucleusVersion() {       return 200; }
+               function getMinNucleusVersion() {       return 330; }
        
                function supportsFeature($feature) {
                        switch($feature) {
@@ -2743,7 +2433,7 @@ function _strip_controlchar($string){
 //mod by cles end
 
                        /* Create tables */
-                       mysql_query("
+                       sql_query("
                                CREATE TABLE IF NOT EXISTS 
                                        ".sql_table('plugin_tb')."
                                (
@@ -2762,7 +2452,7 @@ function _strip_controlchar($string){
                                )
                        ");
                                                
-                       mysql_query("
+                       sql_query("
                                CREATE TABLE IF NOT EXISTS
                                        ".sql_table('plugin_tb_lookup')."
                                (
@@ -2774,16 +2464,16 @@ function _strip_controlchar($string){
                                )
                        ");
 //modify start+++++++++
-                       @mysql_query('ALTER TABLE `' . sql_table('plugin_tb') . '` ADD INDEX `tb_id_block_timestamp_idx` ( `tb_id`, `block`, `timestamp` DESC )');
-                       @mysql_query('CREATE TABLE IF NOT EXISTS ' . sql_table('plugin_tb_lc'). ' (tb_id int(11) not null, from_id int(11) not null, PRIMARY KEY (tb_id,from_id))');
+                       @sql_query('ALTER TABLE `' . sql_table('plugin_tb') . '` ADD INDEX `tb_id_block_timestamp_idx` ( `tb_id`, `block`, `timestamp` DESC )');
+                       @sql_query('CREATE TABLE IF NOT EXISTS ' . sql_table('plugin_tb_lc'). ' (tb_id int(11) not null, from_id int(11) not null, PRIMARY KEY (tb_id,from_id))');
 //modify end+++++++++
                }
        
                function uninstall() {
                        if ($this->getOption('DropTable') == 'yes') {
-                               mysql_query ('DROP TABLE '.sql_table('plugin_tb'));
-                               mysql_query ('DROP TABLE '.sql_table('plugin_tb_lookup'));
-                               mysql_query ("DROP table ".sql_table('plugin_tb_lc'));
+                               sql_query ('DROP TABLE '.sql_table('plugin_tb'));
+                               sql_query ('DROP TABLE '.sql_table('plugin_tb_lookup'));
+                               sql_query ("DROP table ".sql_table('plugin_tb_lc'));
                        }
                }
 
index 9c8d8a5..f5ac256 100644 (file)
                        if( !$sort_col ) $sort_col = $colname['date'];
 
                        $sort_dir = ( requestVar('sort_dir') == 'ASC' ) ? 'ASC' : 'DESC';
+
+                       $rres = sql_query ("
+                       SELECT
+                       count(*) as count
+                       FROM
+                       ".sql_table('plugin_tb')." AS t,
+                       ".sql_table('item')." AS i
+                       WHERE
+                       t.tb_id = i.inumber AND
+                       ".$filter[$type]);
+                       $rrow = mysql_fetch_array($rres);
+                       $count = $rrow['count'];
                        
-                       $rres = mysql_query ("
+                       $rres = sql_query ("
                        SELECT
                        i.ititle AS story,
                        i.inumber AS story_id,
                                $rrow['title']          = $oPluginAdmin->plugin->_cut_string($rrow['title'], 50);
                                $rrow['title']          = $oPluginAdmin->plugin->_strip_controlchar($rrow['title']);
                                $rrow['title']          = htmlspecialchars($rrow['title']);
-                               //                              $rrow['title']          = _CHARSET == 'UTF-8' ? $rrow['title'] : $oPluginAdmin->plugin->_utf8_to_entities($rrow['title']);
+                               $rrow['title']          = preg_replace("/-+/","-",$rrow['title']);
                                
                                $rrow['blog_name']      = $oPluginAdmin->plugin->_cut_string($rrow['blog_name'], 50);
                                $rrow['blog_name']      = $oPluginAdmin->plugin->_strip_controlchar($rrow['blog_name']);
                                $rrow['blog_name']      = htmlspecialchars($rrow['blog_name']);
-                               //                              $rrow['blog_name']      = _CHARSET == 'UTF-8' ? $rrow['blog_name'] : $oPluginAdmin->plugin->_utf8_to_entities($rrow['blog_name']);
+                               $rrow['blog_name']              = preg_replace("/-+/","-",$rrow['blog_name']);
                                
                                $rrow['excerpt']        = $oPluginAdmin->plugin->_cut_string($rrow['excerpt'], 100);
                                $rrow['excerpt']        = $oPluginAdmin->plugin->_strip_controlchar($rrow['excerpt']);
                                $rrow['excerpt']        = htmlspecialchars($rrow['excerpt']);
-                               //                              $rrow['excerpt']        = _CHARSET == 'UTF-8' ? $rrow['excerpt'] : $oPluginAdmin->plugin->_utf8_to_entities($rrow['excerpt']);
+                               $rrow['excerpt']                = preg_replace("/-+/","-",$rrow['excerpt']);
                                
                                $rrow['url']            = htmlspecialchars($rrow['url'], ENT_QUOTES);
                                
                        $oTemplate->set ('items', $items);
                        $oTemplate->template('templates/response_'.$type.'.xml');                       
                        break;
+                       
+               case 'dodelete':
+                       $ids = explode(',', requestVar('ids'));
+                       
+                       $safeids = array();
+                       foreach( $ids as $id ){
+                               $id = trim($id);
+                               if( is_numeric($id) )
+                                       $safeids[] = $id;
+                       }
+                       
+                       if( count($safeids) > 0 ){              
+                               $safeids = implode(',',$safeids);
+                               
+                               $res = sql_query(
+                                               ' DELETE FROM '
+                                               . sql_table('plugin_tb')
+                                               . ' WHERE id in (' . $safeids. ')'
+                               );
+                               $oTemplate->set ('message', $safeids . ' deleted.');
+                       } else {
+                               $oTemplate->set ('message', 'no rows deleted.');
+                       }
+                       
+                       $oTemplate->template('templates/response_dodelete.xml');
+                       break;
+                       
+               case 'doblock':
+                       $ids = explode(',', requestVar('ids'));
+                       
+                       $safeids = array();
+                       foreach( $ids as $id ){
+                               $id = trim($id);
+                               if( is_numeric($id) )
+                                       $safeids[] = $id;
+                       }
+                       
+                       if( count($safeids) > 0 ){              
+                               $safeids = implode(',',$safeids);
+                               
+                               $res = sql_query(
+                                               ' UPDATE '
+                                               . sql_table('plugin_tb')
+                                               .' SET block = 1 '
+                                               . ' WHERE id in (' . $safeids. ')'
+                               );
+                               $oTemplate->set ('message', $safeids . ' blocked.');
+                       } else {
+                               $oTemplate->set ('message', 'no rows blocked.');
+                       }
+                       
+                       $oTemplate->template('templates/response_doblock.xml');
+                       break;
+                                               
+               case 'dounblock':
+                       $ids = explode(',', requestVar('ids'));
+                       
+                       $safeids = array();
+                       foreach( $ids as $id ){
+                               $id = trim($id);
+                               if( is_numeric($id) )
+                                       $safeids[] = $id;
+                       }
+                       
+                       if( count($safeids) > 0 ){              
+                               $safeids = implode(',',$safeids);
+                               
+                               $res = sql_query(
+                                               ' UPDATE '
+                                               . sql_table('plugin_tb')
+                                               .' SET block = 0 '
+                                               . ' WHERE id in (' . $safeids. ')'
+                               );
+                               $oTemplate->set ('message', $safeids . ' unblocked.');
+                       } else {
+                               $oTemplate->set ('message', 'no rows unblocked.');
+                       }
+                       
+                       $oTemplate->template('templates/response_dounblock.xml');
+                       break;
        }
 
        // Create the admin area page
index 42e4fa6..b1752e3 100644 (file)
@@ -7,7 +7,7 @@
        
        
        // Send out Content-type
-       sendContentType('application/xhtml+xml', 'admin-trackback', _CHARSET);  
+       //sendContentType('application/xhtml+xml', 'admin-trackback', _CHARSET);        
 
        $oPluginAdmin = new PluginAdmin('TrackBack');
 
@@ -27,7 +27,9 @@
        if (!in_array($action, $aActionsNotToCheck)) {
                if (!$manager->checkTicket()) doError(_ERROR_BADTICKET);
        }
-       $oPluginAdmin->start();
+
+       //$oPluginAdmin->start();
+       $oPluginAdmin->admin->pagehead();
        
 //modify start+++++++++
                $plug =& $oPluginAdmin->plugin;
@@ -59,7 +61,7 @@
 
 //modify start+++++++++
                case 'tableUpgrade':
-                       mysql_query("
+                       sql_query("
                                CREATE TABLE IF NOT EXISTS
                                        ".sql_table('plugin_tb_lookup')."
                                (
                                 CHANGE `blog_name` `blog_name` TEXT NOT NULL,
                                 DROP PRIMARY KEY,
                                 ADD `id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ;";
-                       $res = @mysql_query($q);
+                       $res = @sql_query($q);
                        if (!$res){
                                echo 'Could not alter table: ' . mysql_error();
                        }else{
                                $tableVersion = 1;
                                $oTemplate->template('templates/updatetablefinished.html');
                        }
-                       @mysql_query('ALTER TABLE `' . sql_table('plugin_tb') . '` ADD INDEX `tb_id_block_timestamp_idx` ( `tb_id`, `block`, `timestamp` DESC )');
+                       @sql_query('ALTER TABLE `' . sql_table('plugin_tb') . '` ADD INDEX `tb_id_block_timestamp_idx` ( `tb_id`, `block`, `timestamp` DESC )');
                        break;
 //modify end+++++++++
 
                case 'block':
                        $tb = intRequestVar('tb');
 
-                       $res = mysql_query ("
+                       $res = sql_query ("
                                UPDATE
                                        ".sql_table('plugin_tb')."
                                SET
                        $action = requestVar('next');
                        break;
                case 'blocked_clear':
-                       $res = mysql_query ("DELETE FROM ".sql_table('plugin_tb')." WHERE block = 1");
+                       $res = sql_query ("DELETE FROM ".sql_table('plugin_tb')." WHERE block = 1");
                        $action = requestVar('next');
                        break;
                        
                case 'blocked_spamclear':
-                       $res = mysql_query ("DELETE FROM ".sql_table('plugin_tb')." WHERE block = 1 and spam = 1");
+                       $res = sql_query ("DELETE FROM ".sql_table('plugin_tb')." WHERE block = 1 and spam = 1");
                        $action = requestVar('next');
                        break;
 
                case 'unblock':
                        $tb = intRequestVar('tb');
 
-                       $res = mysql_query ("
+                       $res = sql_query ("
                                UPDATE
                                        ".sql_table('plugin_tb')."
                                SET
                case 'delete':
                        $tb = intRequestVar('tb');
 
-                       $res = mysql_query ("
+                       $res = sql_query ("
                                DELETE FROM
                                        ".sql_table('plugin_tb')."
                                WHERE
 
                case 'blocked':
                case 'all':     
-                       $rres = mysql_query ("
+                       $rres = sql_query ("
                                SELECT
                                        COUNT(*) AS count
                                FROM
                        } else {\r                               $start  = intRequestVar('start') ? intRequestVar('start') : 0;
                                $amount = intRequestVar('amount') ? intRequestVar('amount') : 25;
 
-                               $rres = mysql_query ("
+                               $rres = sql_query ("
                                        SELECT
                                        i.ititle AS story,
                                        i.inumber AS story_id,
                        $start  = intRequestVar('start') ? intRequestVar('start') : 0;
                        $amount = intRequestVar('amount') ? intRequestVar('amount') : 25;
 
-                       $ires = mysql_query ("
+                       $ires = sql_query ("
                                SELECT
                                        ititle,
                                        inumber
                                $story['id']    = $id;
                                $story['title'] = $irow['ititle'];
 
-                               $rres = mysql_query ("
+                               $rres = sql_query ("
                                        SELECT
                                                COUNT(*) AS count
                                        FROM
                                else
                                        $count = 0;
                                        
-                               $rres = mysql_query ("
+                               $rres = sql_query ("
                                        SELECT
                                                t.id AS id,
                                                t.title AS title,
                                                        
                
                case 'index':
-                       $bres = mysql_query ("
+                       $bres = sql_query ("
                                SELECT
                                        bnumber AS bnumber,
                                        bname AS bname,
                        
                        while ($brow = mysql_fetch_array($bres))
                        {
-                               $ires = mysql_query ("
+                               $ires = sql_query ("
                                        SELECT
                                                i.inumber AS inumber,
                                            i.ititle AS ititle,
index 33d01e9..4c2d3dd 100644 (file)
@@ -150,6 +150,12 @@ div.tb div.info {
 <h3>ÆüËܸìÈǹ¹¿·ÍúÎò</h3>
 
 <ul>
+       <li>Version 2.0.3jp10 : (2007/**/**)</li>
+       <li>¡¡[Fixed] mysql_query()¤òsql_query()¤ËÊѹ¹</li>
+       <li>¡¡[Changed] ¼ÂÂλ²¾È¥Æ¡¼¥Ö¥ë¤Ë¤Ä¤¤¤ÆNucleusɸ½à¤â¤Î¤ò»È¤¦¤è¤¦¤Ë¤·¤¿</li>
+       <li>¡¡[Changed] ¥¤¥ó¥¹¥È¡¼¥ë¤Ç¤­¤ë¥Ð¡¼¥¸¥ç¥ó¤ò3.3°Ê¹ß¤·¤¿</li>
+       <li>¡¡[Changed] Rico¤ò2.0¤Ë¥¢¥Ã¥×¥Ç¡¼¥È¤·¤¿¤Î¤Ëȼ¤¤¡¢´ÉÍý²èÌ̤ε¡Ç½¤òÁý¶¯</li>
+       
        <li>Version 2.0.3jp9 : (2007/05/04)</li>
        <li>¡¡[Added] doIf()¤òÄɲÃ(Nucleus 3.3¸þ¤±)</li>
        <li>¡¡[Added] URL¤¬Ìµ¸ú¤Ê¥È¥é¥Ã¥¯¥Ð¥Ã¥¯¤ò̵»ë¤¹¤ë¤è¤¦¤Ë¤·¤¿</li>
index c21fe97..727e1d2 100644 (file)
        All trackbacks
 </h2>
 
-<div id="showingLabel"><?php echo $count ; ?>·ïÃæ 1 - 5 ·ïÌܤòɽ¼¨¤·¤Æ¤¤¤Þ¤¹</div>
+<div id="message" style="color: red;"></div>
 
-<div style="width: 100%">
-<div id="viewPort" style="float:left; width: 420px">
-<table id="tb_grid" style="border:0; margin:0; width: 400px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
-</div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = liveGrid.metaData.getTotalRows() + "·ïÃæ " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + "·ïÌܤòɽ¼¨¤·¤Æ¤¤¤Þ¤¹¡£";
-    }
+¾åµ­¤ÇÁªÂò¤·¤¿¥È¥é¥Ã¥¯¥Ð¥Ã¥¯¤ò°ì³ç¤·¤Æ½èÍý¤·¤Þ¤¹
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
+<a href="#" onclick="javascript: doBlock()"><img alt="Block" border="0" src="<?php echo $plugindirurl?>silk/delete.png" /></a>
+</div>
 
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width  + 'px';
-       $('tb_grid').style.width =  ( width - 40 ) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=all','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=all',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=doblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
index 899d288..08eff9f 100644 (file)
        <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_spamclear&next=blocked'),ENT_QUOTES); ?>">spamȽÄꤵ¤ì¤¿¥È¥é¥Ã¥¯¥Ð¥Ã¥¯¤Î¥¯¥ê¥¢</a></li> 
 </ul>
 
-<div id="showingLabel"><?php echo $count ; ?>·ïÃæ 1 - 5 ·ïÌܤòɽ¼¨¤·¤Æ¤¤¤Þ¤¹</div>
+<div id="message" style="color: red;"></div>
 
-<div style="float:left; width: 100%">
-<div id="viewPort" style="float:left; width: 620px">
-<table id="tb_grid" style="border:0; margin:0; width: 600px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
+¾åµ­¤ÇÁªÂò¤·¤¿¥È¥é¥Ã¥¯¥Ð¥Ã¥¯¤ò°ì³ç¤·¤Æ½èÍý¤·¤Þ¤¹
+<a href="#" onclick="javascript: doUnblock()"><img alt="Unblock" border="0" src="<?php echo $plugindirurl;?>silk/accept.png" /></a>
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
 </div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = liveGrid.metaData.getTotalRows() + "·ïÃæ " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + "·ïÌܤòɽ¼¨¤·¤Æ¤¤¤Þ¤¹¡£";
-    }
-
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width + 'px';
-       $('tb_grid').style.width = (width - 40) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=blocked','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=blocked',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doUnBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=dounblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
index 64c8983..af6b325 100644 (file)
@@ -1,8 +1,9 @@
 <?php global $manager?>
 <h2>Trackback</h2>
 
-<script type="text/javascript" src="<?php echo $CONF['PluginURL'].'trackback/js/'?>prototype-1.4.0.js"></script>
-<script type="text/javascript" src="<?php echo $CONF['PluginURL'].'trackback/js/'?>rico.js"></script>
+<script type="text/javascript" src="<?php echo $CONF['PluginURL']?>trackback/js/prototype.js"></script>
+<script type="text/javascript" src="<?php echo $CONF['PluginURL']?>trackback/js/rico/rico.js"></script>
+
 <ul>
        <li>
                <img border="0" src="<?php echo $plugindirurl?>silk/application_view_list.png" />
index bbd5a44..7a160ad 100644 (file)
@@ -1,31 +1,35 @@
-<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
 <?php global $manager; ?>
 
 <ajax-response>
-       <response type="object" id='tb_grid_updater'>
-               <rows update_ui='true' >
-               <?php while (list(,$item) = each ($items)): ?>
-               <tr>
-                       <td>
-                               <?php echo str_replace(' ', '&#160;', date("Y-m-d\nH:i:s",$item['timestamp']));?>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['url'];?>"><img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" /></a>
-                               <strong><?php echo $item['title'];?></strong><br />
-                               <?php echo $item['excerpt'];?>
-                               <em>(<?php echo $item['blog_name'];?>)</em>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=block&tb='.$item['id'].'&next=all&start='.$start),ENT_QUOTES);?>"><img alt="Block" border="0" src="<?php echo $plugindirurl?>silk/delete.png" /></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=delete&tb='.$item['id'].'&next=all&start='.$start),ENT_QUOTES);?>"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
-                       </td>
-               </tr>
-               <?php endwhile; ?>
+       <response type="object" id="tb_grid_updater">
+               <rowcount><?php echo $count; ?></rowcount>
+               <rows update_ui="true" offset="<?php echo $start; ?>" >
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
                </rows> 
        </response>
 </ajax-response>
index bcbb086..d085390 100644 (file)
@@ -1,38 +1,41 @@
-<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
 <?php global $manager; ?>
 
 <ajax-response>
        <response type="object" id='tb_grid_updater'>
+               <rowcount><?php echo $count; ?></rowcount>
                <rows update_ui='true' >
-               <?php while (list(,$item) = each ($items)): ?>
-               <tr>
-                       <td>
-                               <?php echo str_replace(' ', '&#160;', date("Y-m-d\nH:i:s",$item['timestamp']));?>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['url'];?>"><img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" /></a>
-                               <strong><?php echo $item['title'];?></strong>
-                               <?php echo $item['spam'] ? 
-                                       '<img alt="spam" border="0" src="' . $plugindirurl . 'silk/delete.png" />' : 
-                                       '';?>
-                               <?php echo $item['link'] ? 
-                                       '' : 
-                                       '<img alt="NOT Linked" border="0" src="' . $plugindirurl . 'silk/link_break.png" />';?>
-                               <br />
-                               <?php echo $item['excerpt'];?>
-                               <em>(<?php echo $item['blog_name'];?>)</em>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=unblock&tb='.$item['id'].'&next=blocked'),ENT_QUOTES);?>"><img alt="Unblock" border="0" src="<?php echo $plugindirurl;?>silk/accept.png" /></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=delete&tb='.$item['id'].'&next=blocked'),ENT_QUOTES);?>"><img alt="Delete" border="0" src="<?php echo $plugindirurl;?>silk/cross.png" /></a>
-                       </td>
-               </tr>
-               <?php endwhile; ?>
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['spam'] ? 
+                                               '<img alt="spam" border="0" src="' . $plugindirurl . 'silk/delete.png" />' : 
+                                               '';?>
+                                       <?php echo $item['link'] ? 
+                                               '' : 
+                                               '<img alt="NOT Linked" border="0" src="' . $plugindirurl . 'silk/link_break.png" />';?>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
                </rows> 
        </response>
 </ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_doblock.xml b/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_doblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dodelete.xml b/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dodelete.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dounblock.xml b/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_dounblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
index 6ec2ebc..80af01a 100644 (file)
@@ -150,6 +150,12 @@ div.tb div.info {
 <h3>日本語版更新履歴</h3>
 
 <ul>
+       <li>Version 2.0.3jp10 : (2007/**/**)</li>
+       <li> [Fixed] mysql_query()をsql_query()に変更</li>
+       <li> [Changed] 実体参照テーブルについてNucleus標準ものを使うようにした</li>
+       <li> [Changed] インストールできるバージョンを3.3以降した</li>
+       <li> [Changed] Ricoを2.0にアップデートしたのに伴い、管理画面の機能を増強</li>
+       
        <li>Version 2.0.3jp9 : (2007/05/04)</li>
        <li> [Added] doIf()を追加(Nucleus 3.3向け)</li>
        <li> [Added] URLが無効なトラックバックを無視するようにした</li>
index cc8bd98..3e97be9 100644 (file)
        All trackbacks
 </h2>
 
-<div id="showingLabel"><?php echo $count ; ?>件中 1 - 5 件目を表示しています</div>
+<div id="message" style="color: red;"></div>
 
-<div style="width: 100%">
-<div id="viewPort" style="float:left; width: 420px">
-<table id="tb_grid" style="border:0; margin:0; width: 400px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
-</div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = liveGrid.metaData.getTotalRows() + "件中 " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + "件目を表示しています。";
-    }
+上記で選択したトラックバックを一括して処理します
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
+<a href="#" onclick="javascript: doBlock()"><img alt="Block" border="0" src="<?php echo $plugindirurl?>silk/delete.png" /></a>
+</div>
 
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width  + 'px';
-       $('tb_grid').style.width =  ( width - 40 ) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=all','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=all',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=doblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
index a292651..344a9db 100644 (file)
        <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_spamclear&next=blocked'),ENT_QUOTES); ?>">spam判定されたトラックバックのクリア</a></li> 
 </ul>
 
-<div id="showingLabel"><?php echo $count ; ?>件中 1 - 5 件目を表示しています</div>
+<div id="message" style="color: red;"></div>
 
-<div style="float:left; width: 100%">
-<div id="viewPort" style="float:left; width: 620px">
-<table id="tb_grid" style="border:0; margin:0; width: 600px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
+上記で選択したトラックバックを一括して処理します
+<a href="#" onclick="javascript: doUnblock()"><img alt="Unblock" border="0" src="<?php echo $plugindirurl;?>silk/accept.png" /></a>
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
 </div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = liveGrid.metaData.getTotalRows() + "件中 " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + "件目を表示しています。";
-    }
-
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width + 'px';
-       $('tb_grid').style.width = (width - 40) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=blocked','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=blocked',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doUnBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=dounblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
index 6b9c742..ac37024 100644 (file)
@@ -1,8 +1,9 @@
 <?php global $manager?>
 <h2>Trackback</h2>
 
-<script type="text/javascript" src="<?php echo $CONF['PluginURL'].'trackback/js/'?>prototype-1.4.0.js"></script>
-<script type="text/javascript" src="<?php echo $CONF['PluginURL'].'trackback/js/'?>rico.js"></script>
+<script type="text/javascript" src="<?php echo $CONF['PluginURL']?>trackback/js/prototype.js"></script>
+<script type="text/javascript" src="<?php echo $CONF['PluginURL']?>trackback/js/rico/rico.js"></script>
+
 <ul>
        <li>
                <img border="0" src="<?php echo $plugindirurl?>silk/application_view_list.png" />
index bbd5a44..7a160ad 100644 (file)
@@ -1,31 +1,35 @@
-<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
 <?php global $manager; ?>
 
 <ajax-response>
-       <response type="object" id='tb_grid_updater'>
-               <rows update_ui='true' >
-               <?php while (list(,$item) = each ($items)): ?>
-               <tr>
-                       <td>
-                               <?php echo str_replace(' ', '&#160;', date("Y-m-d\nH:i:s",$item['timestamp']));?>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['url'];?>"><img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" /></a>
-                               <strong><?php echo $item['title'];?></strong><br />
-                               <?php echo $item['excerpt'];?>
-                               <em>(<?php echo $item['blog_name'];?>)</em>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=block&tb='.$item['id'].'&next=all&start='.$start),ENT_QUOTES);?>"><img alt="Block" border="0" src="<?php echo $plugindirurl?>silk/delete.png" /></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=delete&tb='.$item['id'].'&next=all&start='.$start),ENT_QUOTES);?>"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
-                       </td>
-               </tr>
-               <?php endwhile; ?>
+       <response type="object" id="tb_grid_updater">
+               <rowcount><?php echo $count; ?></rowcount>
+               <rows update_ui="true" offset="<?php echo $start; ?>" >
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
                </rows> 
        </response>
 </ajax-response>
index bcbb086..d085390 100644 (file)
@@ -1,38 +1,41 @@
-<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
 <?php global $manager; ?>
 
 <ajax-response>
        <response type="object" id='tb_grid_updater'>
+               <rowcount><?php echo $count; ?></rowcount>
                <rows update_ui='true' >
-               <?php while (list(,$item) = each ($items)): ?>
-               <tr>
-                       <td>
-                               <?php echo str_replace(' ', '&#160;', date("Y-m-d\nH:i:s",$item['timestamp']));?>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo $item['url'];?>"><img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" /></a>
-                               <strong><?php echo $item['title'];?></strong>
-                               <?php echo $item['spam'] ? 
-                                       '<img alt="spam" border="0" src="' . $plugindirurl . 'silk/delete.png" />' : 
-                                       '';?>
-                               <?php echo $item['link'] ? 
-                                       '' : 
-                                       '<img alt="NOT Linked" border="0" src="' . $plugindirurl . 'silk/link_break.png" />';?>
-                               <br />
-                               <?php echo $item['excerpt'];?>
-                               <em>(<?php echo $item['blog_name'];?>)</em>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=unblock&tb='.$item['id'].'&next=blocked'),ENT_QUOTES);?>"><img alt="Unblock" border="0" src="<?php echo $plugindirurl;?>silk/accept.png" /></a>
-                       </td>
-                       <td>
-                               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=delete&tb='.$item['id'].'&next=blocked'),ENT_QUOTES);?>"><img alt="Delete" border="0" src="<?php echo $plugindirurl;?>silk/cross.png" /></a>
-                       </td>
-               </tr>
-               <?php endwhile; ?>
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['spam'] ? 
+                                               '<img alt="spam" border="0" src="' . $plugindirurl . 'silk/delete.png" />' : 
+                                               '';?>
+                                       <?php echo $item['link'] ? 
+                                               '' : 
+                                               '<img alt="NOT Linked" border="0" src="' . $plugindirurl . 'silk/link_break.png" />';?>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
                </rows> 
        </response>
 </ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_doblock.xml b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_doblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dodelete.xml b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dodelete.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dounblock.xml b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_dounblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js b/trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js
deleted file mode 100644 (file)
index 0e85338..0000000
+++ /dev/null
@@ -1,1781 +0,0 @@
-/*  Prototype JavaScript framework, version 1.4.0
- *  (c) 2005 Sam Stephenson <sam@conio.net>
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- *
-/*--------------------------------------------------------------------------*/
-
-var Prototype = {
-  Version: '1.4.0',
-  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
-
-  emptyFunction: function() {},
-  K: function(x) {return x}
-}
-
-var Class = {
-  create: function() {
-    return function() {
-      this.initialize.apply(this, arguments);
-    }
-  }
-}
-
-var Abstract = new Object();
-
-Object.extend = function(destination, source) {
-  for (property in source) {
-    destination[property] = source[property];
-  }
-  return destination;
-}
-
-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() {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function() {
-    return __method.apply(object, args.concat($A(arguments)));
-  }
-}
-
-Function.prototype.bindAsEventListener = function(object) {
-  var __method = this;
-  return function(event) {
-    return __method.call(object, event || window.event);
-  }
-}
-
-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() {
-    var returnValue;
-
-    for (var i = 0; i < arguments.length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create();
-PeriodicalExecuter.prototype = {
-  initialize: function(callback, frequency) {
-    this.callback = callback;
-    this.frequency = frequency;
-    this.currentlyExecuting = false;
-
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    if (!this.currentlyExecuting) {
-      try {
-        this.currentlyExecuting = true;
-        this.callback();
-      } finally {
-        this.currentlyExecuting = false;
-      }
-    }
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-function $() {
-  var elements = new Array();
-
-  for (var i = 0; i < arguments.length; i++) {
-    var element = arguments[i];
-    if (typeof element == 'string')
-      element = document.getElementById(element);
-
-    if (arguments.length == 1)
-      return element;
-
-    elements.push(element);
-  }
-
-  return elements;
-}
-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);
-    div.appendChild(text);
-    return div.innerHTML;
-  },
-
-  unescapeHTML: function() {
-    var div = document.createElement('div');
-    div.innerHTML = this.stripTags();
-    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 '#<Enumerable:' + this.toArray().inspect() + '>';
-  }
-}
-
-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 '#<Hash:{' + this.map(function(pair) {
-      return pair.map(Object.inspect).join(': ');
-    }).join(', ') + '}>';
-  }
-}
-
-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(
-      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
-      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) {
-    this.options = {
-      method:       'post',
-      asynchronous: true,
-      parameters:   ''
-    }
-    Object.extend(this.options, options || {});
-  },
-
-  responseIsSuccess: function() {
-    return this.transport.status == undefined
-        || this.transport.status == 0
-        || (this.transport.status >= 200 && this.transport.status < 300);
-  },
-
-  responseIsFailure: function() {
-    return !this.responseIsSuccess();
-  }
-}
-
-Ajax.Request = Class.create();
-Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(url, options) {
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-    this.request(url);
-  },
-
-  request: function(url) {
-    var parameters = this.options.parameters || '';
-    if (parameters.length > 0) parameters += '&_=';
-
-    try {
-      this.url = url;
-      if (this.options.method == 'get' && parameters.length > 0)
-        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
-
-      Ajax.Responders.dispatch('onCreate', this, this.transport);
-
-      this.transport.open(this.options.method, this.url,
-        this.options.asynchronous);
-
-      if (this.options.asynchronous) {
-        this.transport.onreadystatechange = this.onStateChange.bind(this);
-        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
-      }
-
-      this.setRequestHeaders();
-
-      var body = this.options.postBody ? this.options.postBody : parameters;
-      this.transport.send(this.options.method == 'post' ? body : null);
-
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  setRequestHeaders: function() {
-    var requestHeaders =
-      ['X-Requested-With', 'XMLHttpRequest',
-       'X-Prototype-Version', Prototype.Version];
-
-    if (this.options.method == 'post') {
-      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.
-       */
-      if (this.transport.overrideMimeType)
-        requestHeaders.push('Connection', 'close');
-    }
-
-    if (this.options.requestHeaders)
-      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
-    for (var i = 0; i < requestHeaders.length; i += 2)
-      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
-  },
-
-  onStateChange: function() {
-    var readyState = this.transport.readyState;
-    if (readyState != 1)
-      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') {
-      try {
-        (this.options['on' + this.transport.status]
-         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
-         || Prototype.emptyFunction)(transport, json);
-      } catch (e) {
-        this.dispatchException(e);
-      }
-
-      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();
-
-Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
-  initialize: function(container, url, options) {
-    this.containers = {
-      success: container.success ? $(container.success) : $(container),
-      failure: container.failure ? $(container.failure) :
-        (container.success ? null : $(container))
-    }
-
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-
-    var onComplete = this.options.onComplete || Prototype.emptyFunction;
-    this.options.onComplete = (function(transport, object) {
-      this.updateContent();
-      onComplete(transport, object);
-    }).bind(this);
-
-    this.request(url);
-  },
-
-  updateContent: function() {
-    var receiver = this.responseIsSuccess() ?
-      this.containers.success : this.containers.failure;
-    var response = this.transport.responseText;
-
-    if (!this.options.evalScripts)
-      response = response.stripScripts();
-
-    if (receiver) {
-      if (this.options.insertion) {
-        new this.options.insertion(receiver, response);
-      } else {
-        Element.update(receiver, response);
-      }
-    }
-
-    if (this.responseIsSuccess()) {
-      if (this.onComplete)
-        setTimeout(this.onComplete.bind(this), 10);
-    }
-  }
-});
-
-Ajax.PeriodicalUpdater = Class.create();
-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 = (this.options.decay || 1);
-
-    this.updater = {};
-    this.container = container;
-    this.url = url;
-
-    this.start();
-  },
-
-  start: function() {
-    this.options.onComplete = this.updateComplete.bind(this);
-    this.onTimerEvent();
-  },
-
-  stop: function() {
-    this.updater.onComplete = undefined;
-    clearTimeout(this.timer);
-    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
-  },
-
-  updateComplete: function(request) {
-    if (this.options.decay) {
-      this.decay = (request.responseText == this.lastText ?
-        this.decay * this.options.decay : 1);
-
-      this.lastText = request.responseText;
-    }
-    this.timer = setTimeout(this.onTimerEvent.bind(this),
-      this.decay * this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    this.updater = new Ajax.Updater(this.container, this.url, this.options);
-  }
-});
-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;
-  });
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Element) {
-  var Element = new Object();
-}
-
-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[Element.visible(element) ? 'hide' : 'show'](element);
-    }
-  },
-
-  hide: function() {
-    for (var i = 0; i < arguments.length; i++) {
-      var element = $(arguments[i]);
-      element.style.display = 'none';
-    }
-  },
-
-  show: function() {
-    for (var i = 0; i < arguments.length; i++) {
-      var element = $(arguments[i]);
-      element.style.display = '';
-    }
-  },
-
-  remove: function(element) {
-    element = $(element);
-    element.parentNode.removeChild(element);
-  },
-
-  update: function(element, html) {
-    $(element).innerHTML = html.stripScripts();
-    setTimeout(function() {html.evalScripts()}, 10);
-  },
-
-  getHeight: function(element) {
-    element = $(element);
-    return element.offsetHeight;
-  },
-
-  classNames: function(element) {
-    return new Element.ClassNames(element);
-  },
-
-  hasClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).include(className);
-  },
-
-  addClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).add(className);
-  },
-
-  removeClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).remove(className);
-  },
-
-  // removes whitespace-only text node children
-  cleanWhitespace: function(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))
-        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;
-  }
-});
-
-var Toggle = new Object();
-Toggle.display = Element.toggle;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.Insertion = function(adjacency) {
-  this.adjacency = adjacency;
-}
-
-Abstract.Insertion.prototype = {
-  initialize: function(element, content) {
-    this.element = $(element);
-    this.content = content.stripScripts();
-
-    if (this.adjacency && this.element.insertAdjacentHTML) {
-      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.insertContent([this.range.createContextualFragment(this.content)]);
-    }
-
-    setTimeout(function() {content.evalScripts()}, 10);
-  },
-
-  contentFromAnonymousTable: function() {
-    var div = document.createElement('div');
-    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
-    return $A(div.childNodes[0].childNodes[0].childNodes);
-  }
-}
-
-var Insertion = new Object();
-
-Insertion.Before = Class.create();
-Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
-  initializeRange: function() {
-    this.range.setStartBefore(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 = Object.extend(new Abstract.Insertion('afterBegin'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(true);
-  },
-
-  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 = Object.extend(new Abstract.Insertion('beforeEnd'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.appendChild(fragment);
-    }).bind(this));
-  }
-});
-
-Insertion.After = Class.create();
-Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
-  initializeRange: function() {
-    this.range.setStartAfter(this.element);
-  },
-
-  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++)
-      $(arguments[i]).value = '';
-  },
-
-  focus: function(element) {
-    $(element).focus();
-  },
-
-  present: function() {
-    for (var i = 0; i < arguments.length; i++)
-      if ($(arguments[i]).value == '') return false;
-    return true;
-  },
-
-  select: function(element) {
-    $(element).select();
-  },
-
-  activate: function(element) {
-    element = $(element);
-    element.focus();
-    if (element.select)
-      element.select();
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Form = {
-  serialize: function(form) {
-    var elements = Form.getElements($(form));
-    var queryComponents = new Array();
-
-    for (var i = 0; i < elements.length; i++) {
-      var queryComponent = Form.Element.serialize(elements[i]);
-      if (queryComponent)
-        queryComponents.push(queryComponent);
-    }
-
-    return queryComponents.join('&');
-  },
-
-  getElements: function(form) {
-    form = $(form);
-    var elements = new Array();
-
-    for (tagName in Form.Element.Serializers) {
-      var tagElements = form.getElementsByTagName(tagName);
-      for (var j = 0; j < tagElements.length; j++)
-        elements.push(tagElements[j]);
-    }
-    return elements;
-  },
-
-  getInputs: function(form, typeName, name) {
-    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))
-        continue;
-      matchingInputs.push(input);
-    }
-
-    return matchingInputs;
-  },
-
-  disable: function(form) {
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.blur();
-      element.disabled = 'true';
-    }
-  },
-
-  enable: function(form) {
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.disabled = '';
-    }
-  },
-
-  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) {
-    Field.activate(Form.findFirstElement(form));
-  },
-
-  reset: function(form) {
-    $(form).reset();
-  }
-}
-
-Form.Element = {
-  serialize: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter) {
-      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) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter)
-      return parameter[1];
-  }
-}
-
-Form.Element.Serializers = {
-  input: function(element) {
-    switch (element.type.toLowerCase()) {
-      case 'submit':
-      case 'hidden':
-      case 'password':
-      case 'text':
-        return Form.Element.Serializers.textarea(element);
-      case 'checkbox':
-      case 'radio':
-        return Form.Element.Serializers.inputSelector(element);
-    }
-    return false;
-  },
-
-  inputSelector: function(element) {
-    if (element.checked)
-      return [element.name, element.value];
-  },
-
-  textarea: function(element) {
-    return [element.name, element.value];
-  },
-
-  select: function(element) {
-    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];
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var $F = Form.Element.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = function() {}
-Abstract.TimedObserver.prototype = {
-  initialize: function(element, frequency, callback) {
-    this.frequency = frequency;
-    this.element   = $(element);
-    this.callback  = callback;
-
-    this.lastValue = this.getValue();
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  }
-}
-
-Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.Observer = Class.create();
-Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = function() {}
-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) {
-      this.callback(this.element, value);
-      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 'radio':
-          Event.observe(element, 'click', this.onElementEvent.bind(this));
-          break;
-        case 'password':
-        case 'text':
-        case 'textarea':
-        case 'select-one':
-        case 'select-multiple':
-          Event.observe(element, 'change', this.onElementEvent.bind(this));
-          break;
-      }
-    }
-  }
-}
-
-Form.Element.EventObserver = Class.create();
-Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.EventObserver = Class.create();
-Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-if (!window.Event) {
-  var Event = new Object();
-}
-
-Object.extend(Event, {
-  KEY_BACKSPACE: 8,
-  KEY_TAB:       9,
-  KEY_RETURN:   13,
-  KEY_ESC:      27,
-  KEY_LEFT:     37,
-  KEY_UP:       38,
-  KEY_RIGHT:    39,
-  KEY_DOWN:     40,
-  KEY_DELETE:   46,
-
-  element: function(event) {
-    return event.target || event.srcElement;
-  },
-
-  isLeftClick: function(event) {
-    return (((event.which) && (event.which == 1)) ||
-            ((event.button) && (event.button == 1)));
-  },
-
-  pointerX: function(event) {
-    return event.pageX || (event.clientX +
-      (document.documentElement.scrollLeft || document.body.scrollLeft));
-  },
-
-  pointerY: function(event) {
-    return event.pageY || (event.clientY +
-      (document.documentElement.scrollTop || document.body.scrollTop));
-  },
-
-  stop: function(event) {
-    if (event.preventDefault) {
-      event.preventDefault();
-      event.stopPropagation();
-    } else {
-      event.returnValue = false;
-      event.cancelBubble = true;
-    }
-  },
-
-  // find the first node with the given tagName, starting from the
-  // node the event was triggered on; traverses the DOM upwards
-  findElement: function(event, tagName) {
-    var element = Event.element(event);
-    while (element.parentNode && (!element.tagName ||
-        (element.tagName.toUpperCase() != tagName.toUpperCase())))
-      element = element.parentNode;
-    return element;
-  },
-
-  observers: false,
-
-  _observeAndCache: function(element, name, observer, useCapture) {
-    if (!this.observers) this.observers = [];
-    if (element.addEventListener) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.addEventListener(name, observer, useCapture);
-    } else if (element.attachEvent) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.attachEvent('on' + name, observer);
-    }
-  },
-
-  unloadCache: function() {
-    if (!Event.observers) return;
-    for (var i = 0; i < Event.observers.length; i++) {
-      Event.stopObserving.apply(this, Event.observers[i]);
-      Event.observers[i][0] = null;
-    }
-    Event.observers = false;
-  },
-
-  observe: function(element, name, observer, useCapture) {
-    var element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (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.match(/Konqueror|Safari|KHTML/)
-        || element.detachEvent))
-      name = 'keydown';
-
-    if (element.removeEventListener) {
-      element.removeEventListener(name, observer, useCapture);
-    } else if (element.detachEvent) {
-      element.detachEvent('on' + name, observer);
-    }
-  }
-});
-
-/* 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,
-
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
-  prepare: function() {
-    this.deltaX =  window.pageXOffset
-                || document.documentElement.scrollLeft
-                || document.body.scrollLeft
-                || 0;
-    this.deltaY =  window.pageYOffset
-                || document.documentElement.scrollTop
-                || document.body.scrollTop
-                || 0;
-  },
-
-  realOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.scrollTop  || 0;
-      valueL += element.scrollLeft || 0;
-      element = element.parentNode;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  cumulativeOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-    } while (element);
-    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)
-      return this.withinIncludingScrolloffsets(element, x, y);
-    this.xcomp = x;
-    this.ycomp = y;
-    this.offset = this.cumulativeOffset(element);
-
-    return (y >= this.offset[1] &&
-            y <  this.offset[1] + element.offsetHeight &&
-            x >= this.offset[0] &&
-            x <  this.offset[0] + element.offsetWidth);
-  },
-
-  withinIncludingScrolloffsets: function(element, x, y) {
-    var offsetcache = this.realOffset(element);
-
-    this.xcomp = x + offsetcache[0] - this.deltaX;
-    this.ycomp = y + offsetcache[1] - this.deltaY;
-    this.offset = this.cumulativeOffset(element);
-
-    return (this.ycomp >= this.offset[1] &&
-            this.ycomp <  this.offset[1] + element.offsetHeight &&
-            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) /
-        element.offsetHeight;
-    if (mode == 'horizontal')
-      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
-        element.offsetWidth;
-  },
-
-  clone: function(source, target) {
-    source = $(source);
-    target = $(target);
-    target.style.position = 'absolute';
-    var offsets = this.cumulativeOffset(source);
-    target.style.top    = offsets[1] + 'px';
-    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/trunk/NP_TrackBack/trackback/js/prototype.js b/trunk/NP_TrackBack/trackback/js/prototype.js
new file mode 100644 (file)
index 0000000..5d2100f
--- /dev/null
@@ -0,0 +1,3271 @@
+/*  Prototype JavaScript framework, version 1.5.1
+ *  (c) 2005-2007 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.5.1',
+
+  Browser: {
+    IE:     !!(window.attachEvent && !window.opera),
+    Opera:  !!window.opera,
+    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
+  },
+
+  BrowserFeatures: {
+    XPath: !!document.evaluate,
+    ElementExtensions: !!window.HTMLElement,
+    SpecificElementExtensions:
+      (document.createElement('div').__proto__ !==
+       document.createElement('form').__proto__)
+  },
+
+  ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
+  JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
+
+  emptyFunction: function() { },
+  K: function(x) { return x }
+}
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+  for (var property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+}
+
+Object.extend(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;
+    }
+  },
+
+  toJSON: function(object) {
+    var type = typeof object;
+    switch(type) {
+      case 'undefined':
+      case 'function':
+      case 'unknown': return;
+      case 'boolean': return object.toString();
+    }
+    if (object === null) return 'null';
+    if (object.toJSON) return object.toJSON();
+    if (object.ownerDocument === document) return;
+    var results = [];
+    for (var property in object) {
+      var value = Object.toJSON(object[property]);
+      if (value !== undefined)
+        results.push(property.toJSON() + ': ' + value);
+    }
+    return '{' + results.join(', ') + '}';
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({}, object);
+  }
+});
+
+Function.prototype.bind = function() {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function() {
+    return __method.apply(object, args.concat($A(arguments)));
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function(event) {
+    return __method.apply(object, [event || window.event].concat(args));
+  }
+}
+
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    return this.toPaddedString(2, 16);
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  },
+
+  toPaddedString: function(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  },
+
+  toJSON: function() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
+});
+
+Date.prototype.toJSON = function() {
+  return '"' + this.getFullYear() + '-' +
+    (this.getMonth() + 1).toPaddedString(2) + '-' +
+    this.getDate().toPaddedString(2) + 'T' +
+    this.getHours().toPaddedString(2) + ':' +
+    this.getMinutes().toPaddedString(2) + ':' +
+    this.getSeconds().toPaddedString(2) + '"';
+};
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.callback(this);
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+}
+Object.extend(String, {
+  interpret: function(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = count === undefined ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return this;
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = truncation === undefined ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : this;
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  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(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var self = arguments.callee;
+    self.text.data = this;
+    return self.div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = document.createElement('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return {};
+
+    return match[1].split(separator || '&').inject({}, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift());
+        var value = pair.length > 1 ? pair.join('=') : pair[0];
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (hash[key].constructor != Array) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  times: function(count) {
+    var result = '';
+    for (var i = 0; i < count; i++) result += this;
+    return result;
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function() {
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+      var character = String.specialChar[match[0]];
+      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  },
+
+  toJSON: function() {
+    return this.inspect(true);
+  },
+
+  unfilterJSON: function(filter) {
+    return this.sub(filter || Prototype.JSONFilter, '#{1}');
+  },
+
+  evalJSON: function(sanitize) {
+    var json = this.unfilterJSON();
+    try {
+      if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
+        return eval('(' + json + ')');
+    } catch (e) { }
+    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+  },
+
+  include: function(pattern) {
+    return this.indexOf(pattern) > -1;
+  },
+
+  startsWith: function(pattern) {
+    return this.indexOf(pattern) === 0;
+  },
+
+  endsWith: function(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.lastIndexOf(pattern) === d;
+  },
+
+  empty: function() {
+    return this == '';
+  },
+
+  blank: function() {
+    return /^\s*$/.test(this);
+  }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+  escapeHTML: function() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  },
+  unescapeHTML: function() {
+    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (typeof replacement == 'function') return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+Object.extend(String.prototype.escapeHTML, {
+  div:  document.createElement('div'),
+  text: document.createTextNode('')
+});
+
+with (String.prototype.escapeHTML) div.appendChild(text);
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern  = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    return this.template.gsub(this.pattern, function(match) {
+      var before = match[1];
+      if (before == '\\') return match[2];
+      return before + String.interpret(object[match[3]]);
+    });
+  }
+}
+
+var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+var Enumerable = {
+  each: function(iterator) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        iterator(value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator) {
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.map(iterator);
+  },
+
+  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 = false;
+    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 || Prototype.K)(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;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = fillWith === undefined ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  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.map(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 (result == undefined || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value < result)
+        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.map(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.map();
+  },
+
+  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) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+}
+
+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, length = iterable.length; i < length; i++)
+      results.push(iterable[i]);
+    return results;
+  }
+}
+
+if (Prototype.Browser.WebKit) {
+  $A = Array.from = function(iterable) {
+    if (!iterable) return [];
+    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
+      iterable.toArray) {
+      return iterable.toArray();
+    } else {
+      var results = [];
+      for (var i = 0, length = iterable.length; i < length; i++)
+        results.push(iterable[i]);
+      return results;
+    }
+  }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+  Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < 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 != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(value && 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, length = this.length; i < length; i++)
+      if (this[i] == object) return i;
+    return -1;
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  },
+
+  toJSON: function() {
+    var results = [];
+    this.each(function(object) {
+      var value = Object.toJSON(object);
+      if (value !== undefined) results.push(value);
+    });
+    return '[' + results.join(', ') + ']';
+  }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+  Array.prototype.concat = function() {
+    var array = [];
+    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      if (arguments[i].constructor == Array) {
+        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  }
+}
+var Hash = function(object) {
+  if (object instanceof Hash) this.merge(object);
+  else Object.extend(this, object || {});
+};
+
+Object.extend(Hash, {
+  toQueryString: function(obj) {
+    var parts = [];
+    parts.add = arguments.callee.addPair;
+
+    this.prototype._each.call(obj, function(pair) {
+      if (!pair.key) return;
+      var value = pair.value;
+
+      if (value && typeof value == 'object') {
+        if (value.constructor == Array) value.each(function(value) {
+          parts.add(pair.key, value);
+        });
+        return;
+      }
+      parts.add(pair.key, value);
+    });
+
+    return parts.join('&');
+  },
+
+  toJSON: function(object) {
+    var results = [];
+    this.prototype._each.call(object, function(pair) {
+      var value = Object.toJSON(pair.value);
+      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
+    });
+    return '{' + results.join(', ') + '}';
+  }
+});
+
+Hash.toQueryString.addPair = function(key, value, prefix) {
+  key = encodeURIComponent(key);
+  if (value === undefined) this.push(key);
+  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
+}
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+  _each: function(iterator) {
+    for (var key in this) {
+      var value = this[key];
+      if (value && value == Hash.prototype[key]) 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(this, function(mergedHash, pair) {
+      mergedHash[pair.key] = pair.value;
+      return mergedHash;
+    });
+  },
+
+  remove: function() {
+    var result;
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      var value = this[arguments[i]];
+      if (value !== undefined){
+        if (result === undefined) result = value;
+        else {
+          if (result.constructor != Array) result = [result];
+          result.push(value)
+        }
+      }
+      delete this[arguments[i]];
+    }
+    return result;
+  },
+
+  toQueryString: function() {
+    return Hash.toQueryString(this);
+  },
+
+  inspect: function() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  },
+
+  toJSON: function() {
+    return Hash.toJSON(this);
+  }
+});
+
+function $H(object) {
+  if (object instanceof Hash) return object;
+  return new Hash(object);
+};
+
+// Safari iterates over shadowed properties
+if (function() {
+  var i = 0, Test = function(value) { this.key = value };
+  Test.prototype.key = 'foo';
+  for (var property in new Test('bar')) i++;
+  return i > 1;
+}()) Hash.prototype._each = function(iterator) {
+  var cache = [];
+  for (var key in this) {
+    var value = this[key];
+    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
+    cache.push(key);
+    var pair = [key, value];
+    pair.key = key;
+    pair.value = value;
+    iterator(pair);
+  }
+};
+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;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  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(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+}
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (typeof responder[callback] == 'function') {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) {}
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate: function() {
+    Ajax.activeRequestCount++;
+  },
+  onComplete: function() {
+    Ajax.activeRequestCount--;
+  }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   ''
+    }
+    Object.extend(this.options, options || {});
+
+    this.options.method = this.options.method.toLowerCase();
+    if (typeof this.options.parameters == 'string')
+      this.options.parameters = this.options.parameters.toQueryParams();
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+  _complete: false,
+
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.clone(this.options.parameters);
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    this.parameters = params;
+
+    if (params = Hash.toQueryString(params)) {
+      // when GET, append parameters to URL
+      if (this.method == 'get')
+        this.url += (this.url.include('?') ? '&' : '?') + params;
+      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+        params += '&_=';
+    }
+
+    try {
+      if (this.options.onCreate) this.options.onCreate(this.transport);
+      Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous)
+        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+      this.transport.send(this.body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (typeof extras.push == 'function')
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    return !this.transport.status
+        || (this.transport.status >= 200 && this.transport.status < 300);
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState];
+    var transport = this.transport, json = this.evalJSON();
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + this.transport.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(transport, json);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = this.getHeader('Content-type');
+      if (contentType && contentType.strip().
+        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+          this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+      Ajax.Responders.dispatch('on' + state, this, transport, json);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) { return null }
+  },
+
+  evalJSON: function() {
+    try {
+      var json = this.getHeader('X-JSON');
+      return json ? json.evalJSON() : null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+  initialize: function(container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    }
+
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;
+    this.options.onComplete = (function(transport, param) {
+      this.updateContent();
+      onComplete(transport, param);
+    }).bind(this);
+
+    this.request(url);
+  },
+
+  updateContent: function() {
+    var receiver = this.container[this.success() ? 'success' : 'failure'];
+    var response = this.transport.responseText;
+
+    if (!this.options.evalScripts) response = response.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (this.options.insertion)
+        new this.options.insertion(receiver, response);
+      else
+        receiver.update(response);
+    }
+
+    if (this.success()) {
+      if (this.onComplete)
+        setTimeout(this.onComplete.bind(this), 10);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+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 = (this.options.decay || 1);
+
+    this.updater = {};
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(request) {
+    if (this.options.decay) {
+      this.decay = (request.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = request.responseText;
+    }
+    this.timer = setTimeout(this.onTimerEvent.bind(this),
+      this.decay * this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (typeof element == 'string')
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(query.snapshotItem(i));
+    return results;
+  };
+
+  document.getElementsByClassName = function(className, parentElement) {
+    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+    return document._getElementsByXPath(q, parentElement);
+  }
+
+} else document.getElementsByClassName = function(className, parentElement) {
+  var children = ($(parentElement) || document.body).getElementsByTagName('*');
+  var elements = [], child;
+  for (var i = 0, length = children.length; i < length; i++) {
+    child = children[i];
+    if (Element.hasClassName(child, className))
+      elements.push(Element.extend(child));
+  }
+  return elements;
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element) var Element = {};
+
+Element.extend = function(element) {
+  var F = Prototype.BrowserFeatures;
+  if (!element || !element.tagName || element.nodeType == 3 ||
+   element._extended || F.SpecificElementExtensions || element == window)
+    return element;
+
+  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
+   T = Element.Methods.ByTag;
+
+  // extend methods for all tags (Safari doesn't need this)
+  if (!F.ElementExtensions) {
+    Object.extend(methods, Element.Methods),
+    Object.extend(methods, Element.Methods.Simulated);
+  }
+
+  // extend methods for specific tags
+  if (T[tagName]) Object.extend(methods, T[tagName]);
+
+  for (var property in methods) {
+    var value = methods[property];
+    if (typeof value == 'function' && !(property in element))
+      element[property] = cache.findOrStore(value);
+  }
+
+  element._extended = Prototype.emptyFunction;
+  return element;
+};
+
+Element.extend.cache = {
+  findOrStore: function(value) {
+    return this[value] = this[value] || function() {
+      return value.apply(null, [this].concat($A(arguments)));
+    }
+  }
+};
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, html) {
+    html = typeof html == 'undefined' ? '' : html.toString();
+    $(element).innerHTML = html.stripScripts();
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  replace: function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    if (element.outerHTML) {
+      element.outerHTML = html.stripScripts();
+    } else {
+      var range = element.ownerDocument.createRange();
+      range.selectNodeContents(element);
+      element.parentNode.replaceChild(
+        range.createContextualFragment(html.stripScripts()), element);
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $A($(element).getElementsByTagName('*')).each(Element.extend);
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (typeof selector == 'string')
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = element.ancestors();
+    return expression ? Selector.findElement(ancestors, expression, index) :
+      ancestors[index || 0];
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return element.firstDescendant();
+    var descendants = element.descendants();
+    return expression ? Selector.findElement(descendants, expression, index) :
+      descendants[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+    var previousSiblings = element.previousSiblings();
+    return expression ? Selector.findElement(previousSiblings, expression, index) :
+      previousSiblings[index || 0];
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+    var nextSiblings = element.nextSiblings();
+    return expression ? Selector.findElement(nextSiblings, expression, index) :
+      nextSiblings[index || 0];
+  },
+
+  getElementsBySelector: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  getElementsByClassName: function(element, className) {
+    return document.getElementsByClassName(className, element);
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      if (!element.attributes) return null;
+      var t = Element._attributeTranslations;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name])  name = t.names[name];
+      var attribute = element.attributes[name];
+      return attribute ? attribute.nodeValue : null;
+    }
+    return element.getAttribute(name);
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    if (elementClassName.length == 0) return false;
+    if (elementClassName == className ||
+        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+      return true;
+    return false;
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).add(className);
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).remove(className);
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+    return element;
+  },
+
+  observe: function() {
+    Event.observe.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  stopObserving: function() {
+    Event.stopObserving.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = Position.cumulativeOffset(element);
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles, camelized) {
+    element = $(element);
+    var elementStyle = element.style;
+
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property])
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
+          (camelized ? property : property.camelize())] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      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;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    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;
+      }
+    }
+    return element;
+  },
+
+  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 = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = element.style.overflow || 'auto';
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  }
+};
+
+Object.extend(Element.Methods, {
+  childOf: Element.Methods.descendantOf,
+  childElements: Element.Methods.immediateDescendants
+});
+
+if (Prototype.Browser.Opera) {
+  Element.Methods._getStyle = Element.Methods.getStyle;
+  Element.Methods.getStyle = function(element, style) {
+    switch(style) {
+      case 'left':
+      case 'top':
+      case 'right':
+      case 'bottom':
+        if (Element._getStyle(element, 'position') == 'static') return null;
+      default: return Element._getStyle(element, style);
+    }
+  };
+}
+else if (Prototype.Browser.IE) {
+  Element.Methods.getStyle = function(element, style) {
+    element = $(element);
+    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value && element.currentStyle) value = element.currentStyle[style];
+
+    if (style == 'opacity') {
+      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if (value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+
+    if (value == 'auto') {
+      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+        return element['offset'+style.capitalize()] + 'px';
+      return null;
+    }
+    return value;
+  };
+
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    var filter = element.getStyle('filter'), style = element.style;
+    if (value == 1 || value === '') {
+      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
+      return element;
+    } else if (value < 0.00001) value = 0;
+    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
+      'alpha(opacity=' + (value * 100) + ')';
+    return element;
+  };
+
+  // IE is missing .innerHTML support for TABLE-related elements
+  Element.Methods.update = function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    var tagName = element.tagName.toUpperCase();
+    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+      var div = document.createElement('div');
+      switch (tagName) {
+        case 'THEAD':
+        case 'TBODY':
+          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
+          depth = 2;
+          break;
+        case 'TR':
+          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
+          depth = 3;
+          break;
+        case 'TD':
+          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
+          depth = 4;
+      }
+      $A(element.childNodes).each(function(node) { element.removeChild(node) });
+      depth.times(function() { div = div.firstChild });
+      $A(div.childNodes).each(function(node) { element.appendChild(node) });
+    } else {
+      element.innerHTML = html.stripScripts();
+    }
+    setTimeout(function() { html.evalScripts() }, 10);
+    return element;
+  }
+}
+else if (Prototype.Browser.Gecko) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1) ? 0.999999 :
+      (value === '') ? '' : (value < 0.00001) ? 0 : value;
+    return element;
+  };
+}
+
+Element._attributeTranslations = {
+  names: {
+    colspan:   "colSpan",
+    rowspan:   "rowSpan",
+    valign:    "vAlign",
+    datetime:  "dateTime",
+    accesskey: "accessKey",
+    tabindex:  "tabIndex",
+    enctype:   "encType",
+    maxlength: "maxLength",
+    readonly:  "readOnly",
+    longdesc:  "longDesc"
+  },
+  values: {
+    _getAttr: function(element, attribute) {
+      return element.getAttribute(attribute, 2);
+    },
+    _flag: function(element, attribute) {
+      return $(element).hasAttribute(attribute) ? attribute : null;
+    },
+    style: function(element) {
+      return element.style.cssText.toLowerCase();
+    },
+    title: function(element) {
+      var node = element.getAttributeNode('title');
+      return node.specified ? node.nodeValue : null;
+    }
+  }
+};
+
+(function() {
+  Object.extend(this, {
+    href: this._getAttr,
+    src:  this._getAttr,
+    type: this._getAttr,
+    disabled: this._flag,
+    checked:  this._flag,
+    readonly: this._flag,
+    multiple: this._flag
+  });
+}).call(Element._attributeTranslations.values);
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    var t = Element._attributeTranslations, node;
+    attribute = t.names[attribute] || attribute;
+    node = $(element).getAttributeNode(attribute);
+    return node && node.specified;
+  }
+};
+
+Element.Methods.ByTag = {};
+
+Object.extend(Element, Element.Methods);
+
+if (!Prototype.BrowserFeatures.ElementExtensions &&
+ document.createElement('div').__proto__) {
+  window.HTMLElement = {};
+  window.HTMLElement.prototype = document.createElement('div').__proto__;
+  Prototype.BrowserFeatures.ElementExtensions = true;
+}
+
+Element.hasAttribute = function(element, attribute) {
+  if (element.hasAttribute) return element.hasAttribute(attribute);
+  return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+  if (!methods) {
+    Object.extend(Form, Form.Methods);
+    Object.extend(Form.Element, Form.Element.Methods);
+    Object.extend(Element.Methods.ByTag, {
+      "FORM":     Object.clone(Form.Methods),
+      "INPUT":    Object.clone(Form.Element.Methods),
+      "SELECT":   Object.clone(Form.Element.Methods),
+      "TEXTAREA": Object.clone(Form.Element.Methods)
+    });
+  }
+
+  if (arguments.length == 2) {
+    var tagName = methods;
+    methods = arguments[1];
+  }
+
+  if (!tagName) Object.extend(Element.Methods, methods || {});
+  else {
+    if (tagName.constructor == Array) tagName.each(extend);
+    else extend(tagName);
+  }
+
+  function extend(tagName) {
+    tagName = tagName.toUpperCase();
+    if (!Element.Methods.ByTag[tagName])
+      Element.Methods.ByTag[tagName] = {};
+    Object.extend(Element.Methods.ByTag[tagName], methods);
+  }
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    var cache = Element.extend.cache;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = cache.findOrStore(value);
+    }
+  }
+
+  function findDOMClass(tagName) {
+    var klass;
+    var trans = {
+      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+      "FrameSet", "IFRAME": "IFrame"
+    };
+    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName.capitalize() + 'Element';
+    if (window[klass]) return window[klass];
+
+    window[klass] = {};
+    window[klass].prototype = document.createElement(tagName).__proto__;
+    return window[klass];
+  }
+
+  if (F.ElementExtensions) {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+  }
+
+  if (F.SpecificElementExtensions) {
+    for (var tag in Element.Methods.ByTag) {
+      var klass = findDOMClass(tag);
+      if (typeof klass == "undefined") continue;
+      copy(T[tag], klass.prototype);
+    }
+  }
+
+  Object.extend(Element, Element.Methods);
+  delete Element.ByTag;
+};
+
+var Toggle = { display: Element.toggle };
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content.stripScripts();
+
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      try {
+        this.element.insertAdjacentHTML(this.adjacency, this.content);
+      } catch (e) {
+        var tagName = this.element.tagName.toUpperCase();
+        if (['TBODY', 'TR'].include(tagName)) {
+          this.insertContent(this.contentFromAnonymousTable());
+        } else {
+          throw e;
+        }
+      }
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.insertContent([this.range.createContextualFragment(this.content)]);
+    }
+
+    setTimeout(function() {content.evalScripts()}, 10);
+  },
+
+  contentFromAnonymousTable: function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+    return $A(div.childNodes[0].childNodes[0].childNodes);
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+  initializeRange: function() {
+    this.range.setStartBefore(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 = Object.extend(new Abstract.Insertion('afterBegin'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+
+  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 = Object.extend(new Abstract.Insertion('beforeEnd'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.appendChild(fragment);
+    }).bind(this));
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+
+  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($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license.  Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create();
+
+Selector.prototype = {
+  initialize: function(expression) {
+    this.expression = expression.strip();
+    this.compileMatcher();
+  },
+
+  compileMatcher: function() {
+    // Selectors with namespaced attributes can't use the XPath version
+    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
+      return this.compileXPathMatcher();
+
+    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+        c = Selector.criteria, le, p, m;
+
+    if (Selector._cache[e]) {
+      this.matcher = Selector._cache[e]; return;
+    }
+    this.matcher = ["this.matcher = function(root) {",
+                    "var r = root, h = Selector.handlers, c = false, n;"];
+
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        p = ps[i];
+        if (m = e.match(p)) {
+          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
+             new Template(c[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.matcher.push("return h.unique(n);\n}");
+    eval(this.matcher.join('\n'));
+    Selector._cache[this.expression] = this.matcher;
+  },
+
+  compileXPathMatcher: function() {
+    var e = this.expression, ps = Selector.patterns,
+        x = Selector.xpath, le,  m;
+
+    if (Selector._cache[e]) {
+      this.xpath = Selector._cache[e]; return;
+    }
+
+    this.matcher = ['.//*'];
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        if (m = e.match(ps[i])) {
+          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
+            new Template(x[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.xpath = this.matcher.join('');
+    Selector._cache[this.expression] = this.xpath;
+  },
+
+  findElements: function(root) {
+    root = root || document;
+    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
+    return this.matcher(root);
+  },
+
+  match: function(element) {
+    return this.findElements(document).include(element);
+  },
+
+  toString: function() {
+    return this.expression;
+  },
+
+  inspect: function() {
+    return "#<Selector:" + this.expression.inspect() + ">";
+  }
+};
+
+Object.extend(Selector, {
+  _cache: {},
+
+  xpath: {
+    descendant:   "//*",
+    child:        "/*",
+    adjacent:     "/following-sibling::*[1]",
+    laterSibling: '/following-sibling::*',
+    tagName:      function(m) {
+      if (m[1] == '*') return '';
+      return "[local-name()='" + m[1].toLowerCase() +
+             "' or local-name()='" + m[1].toUpperCase() + "']";
+    },
+    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+    id:           "[@id='#{1}']",
+    attrPresence: "[@#{1}]",
+    attr: function(m) {
+      m[3] = m[5] || m[6];
+      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+    },
+    pseudo: function(m) {
+      var h = Selector.xpath.pseudos[m[1]];
+      if (!h) return '';
+      if (typeof h === 'function') return h(m);
+      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+    },
+    operators: {
+      '=':  "[@#{1}='#{3}']",
+      '!=': "[@#{1}!='#{3}']",
+      '^=': "[starts-with(@#{1}, '#{3}')]",
+      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+      '*=': "[contains(@#{1}, '#{3}')]",
+      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+    },
+    pseudos: {
+      'first-child': '[not(preceding-sibling::*)]',
+      'last-child':  '[not(following-sibling::*)]',
+      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
+      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+      'checked':     "[@checked]",
+      'disabled':    "[@disabled]",
+      'enabled':     "[not(@disabled)]",
+      'not': function(m) {
+        var e = m[6], p = Selector.patterns,
+            x = Selector.xpath, le, m, v;
+
+        var exclusion = [];
+        while (e && le != e && (/\S/).test(e)) {
+          le = e;
+          for (var i in p) {
+            if (m = e.match(p[i])) {
+              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
+              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+              e = e.replace(m[0], '');
+              break;
+            }
+          }
+        }
+        return "[not(" + exclusion.join(" and ") + ")]";
+      },
+      'nth-child':      function(m) {
+        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+      },
+      'nth-last-child': function(m) {
+        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+      },
+      'nth-of-type':    function(m) {
+        return Selector.xpath.pseudos.nth("position() ", m);
+      },
+      'nth-last-of-type': function(m) {
+        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+      },
+      'first-of-type':  function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+      },
+      'last-of-type':   function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+      },
+      'only-of-type':   function(m) {
+        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+      },
+      nth: function(fragment, m) {
+        var mm, formula = m[6], predicate;
+        if (formula == 'even') formula = '2n+0';
+        if (formula == 'odd')  formula = '2n+1';
+        if (mm = formula.match(/^(\d+)$/)) // digit only
+          return '[' + fragment + "= " + mm[1] + ']';
+        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+          if (mm[1] == "-") mm[1] = -1;
+          var a = mm[1] ? Number(mm[1]) : 1;
+          var b = mm[2] ? Number(mm[2]) : 0;
+          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+          "((#{fragment} - #{b}) div #{a} >= 0)]";
+          return new Template(predicate).evaluate({
+            fragment: fragment, a: a, b: b });
+        }
+      }
+    }
+  },
+
+  criteria: {
+    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
+    className:    'n = h.className(n, r, "#{1}", c); c = false;',
+    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
+    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+    attr: function(m) {
+      m[3] = (m[5] || m[6]);
+      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+    },
+    pseudo:       function(m) {
+      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+    },
+    descendant:   'c = "descendant";',
+    child:        'c = "child";',
+    adjacent:     'c = "adjacent";',
+    laterSibling: 'c = "laterSibling";'
+  },
+
+  patterns: {
+    // combinators must be listed first
+    // (and descendant needs to be last combinator)
+    laterSibling: /^\s*~\s*/,
+    child:        /^\s*>\s*/,
+    adjacent:     /^\s*\+\s*/,
+    descendant:   /^\s/,
+
+    // selectors follow
+    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
+    id:           /^#([\w\-\*]+)(\b|$)/,
+    className:    /^\.([\w\-\*]+)(\b|$)/,
+    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
+    attrPresence: /^\[([\w]+)\]/,
+    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
+  },
+
+  handlers: {
+    // UTILITY FUNCTIONS
+    // joins two collections
+    concat: function(a, b) {
+      for (var i = 0, node; node = b[i]; i++)
+        a.push(node);
+      return a;
+    },
+
+    // marks an array of nodes for counting
+    mark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = true;
+      return nodes;
+    },
+
+    unmark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = undefined;
+      return nodes;
+    },
+
+    // mark each child node with its position (for nth calls)
+    // "ofType" flag indicates whether we're indexing for nth-of-type
+    // rather than nth-child
+    index: function(parentNode, reverse, ofType) {
+      parentNode._counted = true;
+      if (reverse) {
+        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+          node = nodes[i];
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+        }
+      } else {
+        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+      }
+    },
+
+    // filters out duplicates and extends all nodes
+    unique: function(nodes) {
+      if (nodes.length == 0) return nodes;
+      var results = [], n;
+      for (var i = 0, l = nodes.length; i < l; i++)
+        if (!(n = nodes[i])._counted) {
+          n._counted = true;
+          results.push(Element.extend(n));
+        }
+      return Selector.handlers.unmark(results);
+    },
+
+    // COMBINATOR FUNCTIONS
+    descendant: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, node.getElementsByTagName('*'));
+      return results;
+    },
+
+    child: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
+          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+      }
+      return results;
+    },
+
+    adjacent: function(nodes) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        var next = this.nextElementSibling(node);
+        if (next) results.push(next);
+      }
+      return results;
+    },
+
+    laterSibling: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, Element.nextSiblings(node));
+      return results;
+    },
+
+    nextElementSibling: function(node) {
+      while (node = node.nextSibling)
+             if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    previousElementSibling: function(node) {
+      while (node = node.previousSibling)
+        if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    // TOKEN FUNCTIONS
+    tagName: function(nodes, root, tagName, combinator) {
+      tagName = tagName.toUpperCase();
+      var results = [], h = Selector.handlers;
+      if (nodes) {
+        if (combinator) {
+          // fastlane for ordinary descendant combinators
+          if (combinator == "descendant") {
+            for (var i = 0, node; node = nodes[i]; i++)
+              h.concat(results, node.getElementsByTagName(tagName));
+            return results;
+          } else nodes = this[combinator](nodes);
+          if (tagName == "*") return nodes;
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName.toUpperCase() == tagName) results.push(node);
+        return results;
+      } else return root.getElementsByTagName(tagName);
+    },
+
+    id: function(nodes, root, id, combinator) {
+      var targetNode = $(id), h = Selector.handlers;
+      if (!nodes && root == document) return targetNode ? [targetNode] : [];
+      if (nodes) {
+        if (combinator) {
+          if (combinator == 'child') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (targetNode.parentNode == node) return [targetNode];
+          } else if (combinator == 'descendant') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Element.descendantOf(targetNode, node)) return [targetNode];
+          } else if (combinator == 'adjacent') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Selector.handlers.previousElementSibling(targetNode) == node)
+                return [targetNode];
+          } else nodes = h[combinator](nodes);
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node == targetNode) return [targetNode];
+        return [];
+      }
+      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+    },
+
+    className: function(nodes, root, className, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      return Selector.handlers.byClassName(nodes, root, className);
+    },
+
+    byClassName: function(nodes, root, className) {
+      if (!nodes) nodes = Selector.handlers.descendant([root]);
+      var needle = ' ' + className + ' ';
+      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+        nodeClassName = node.className;
+        if (nodeClassName.length == 0) continue;
+        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+          results.push(node);
+      }
+      return results;
+    },
+
+    attrPresence: function(nodes, root, attr) {
+      var results = [];
+      for (var i = 0, node; node = nodes[i]; i++)
+        if (Element.hasAttribute(node, attr)) results.push(node);
+      return results;
+    },
+
+    attr: function(nodes, root, attr, value, operator) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      var handler = Selector.operators[operator], results = [];
+      for (var i = 0, node; node = nodes[i]; i++) {
+        var nodeValue = Element.readAttribute(node, attr);
+        if (nodeValue === null) continue;
+        if (handler(nodeValue, value)) results.push(node);
+      }
+      return results;
+    },
+
+    pseudo: function(nodes, name, value, root, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      return Selector.pseudos[name](nodes, value, root);
+    }
+  },
+
+  pseudos: {
+    'first-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.previousElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'last-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.nextElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'only-child': function(nodes, value, root) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+          results.push(node);
+      return results;
+    },
+    'nth-child':        function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root);
+    },
+    'nth-last-child':   function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true);
+    },
+    'nth-of-type':      function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, false, true);
+    },
+    'nth-last-of-type': function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true, true);
+    },
+    'first-of-type':    function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, false, true);
+    },
+    'last-of-type':     function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, true, true);
+    },
+    'only-of-type':     function(nodes, formula, root) {
+      var p = Selector.pseudos;
+      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+    },
+
+    // handles the an+b logic
+    getIndices: function(a, b, total) {
+      if (a == 0) return b > 0 ? [b] : [];
+      return $R(1, total).inject([], function(memo, i) {
+        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+        return memo;
+      });
+    },
+
+    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+    nth: function(nodes, formula, root, reverse, ofType) {
+      if (nodes.length == 0) return [];
+      if (formula == 'even') formula = '2n+0';
+      if (formula == 'odd')  formula = '2n+1';
+      var h = Selector.handlers, results = [], indexed = [], m;
+      h.mark(nodes);
+      for (var i = 0, node; node = nodes[i]; i++) {
+        if (!node.parentNode._counted) {
+          h.index(node.parentNode, reverse, ofType);
+          indexed.push(node.parentNode);
+        }
+      }
+      if (formula.match(/^\d+$/)) { // just a number
+        formula = Number(formula);
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.nodeIndex == formula) results.push(node);
+      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+        if (m[1] == "-") m[1] = -1;
+        var a = m[1] ? Number(m[1]) : 1;
+        var b = m[2] ? Number(m[2]) : 0;
+        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+          for (var j = 0; j < l; j++)
+            if (node.nodeIndex == indices[j]) results.push(node);
+        }
+      }
+      h.unmark(nodes);
+      h.unmark(indexed);
+      return results;
+    },
+
+    'empty': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        // IE treats comments as element nodes
+        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+        results.push(node);
+      }
+      return results;
+    },
+
+    'not': function(nodes, selector, root) {
+      var h = Selector.handlers, selectorType, m;
+      var exclusions = new Selector(selector).findElements(root);
+      h.mark(exclusions);
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node._counted) results.push(node);
+      h.unmark(exclusions);
+      return results;
+    },
+
+    'enabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node.disabled) results.push(node);
+      return results;
+    },
+
+    'disabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.disabled) results.push(node);
+      return results;
+    },
+
+    'checked': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.checked) results.push(node);
+      return results;
+    }
+  },
+
+  operators: {
+    '=':  function(nv, v) { return nv == v; },
+    '!=': function(nv, v) { return nv != v; },
+    '^=': function(nv, v) { return nv.startsWith(v); },
+    '$=': function(nv, v) { return nv.endsWith(v); },
+    '*=': function(nv, v) { return nv.include(v); },
+    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+  },
+
+  matchElements: function(elements, expression) {
+    var matches = new Selector(expression).findElements(), h = Selector.handlers;
+    h.mark(matches);
+    for (var i = 0, results = [], element; element = elements[i]; i++)
+      if (element._counted) results.push(element);
+    h.unmark(matches);
+    return results;
+  },
+
+  findElement: function(elements, expression, index) {
+    if (typeof expression == 'number') {
+      index = expression; expression = false;
+    }
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    var exprs = expressions.join(','), expressions = [];
+    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+      expressions.push(m[1].strip());
+    });
+    var results = [], h = Selector.handlers;
+    for (var i = 0, l = expressions.length, selector; i < l; i++) {
+      selector = new Selector(expressions[i].strip());
+      h.concat(results, selector.findElements(element));
+    }
+    return (l > 1) ? h.unique(results) : results;
+  }
+});
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, getHash) {
+    var data = elements.inject({}, function(result, element) {
+      if (!element.disabled && element.name) {
+        var key = element.name, value = $(element).getValue();
+        if (value != null) {
+               if (key in result) {
+            if (result[key].constructor != Array) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return getHash ? data : Hash.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, getHash) {
+    return Form.serializeElements(Form.getElements(form), getHash);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('disable');
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('enable');
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    return $(form).getElements().find(function(element) {
+      return element.type != 'hidden' && !element.disabled &&
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  },
+
+  request: function(form, options) {
+    form = $(form), options = Object.clone(options || {});
+
+    var params = options.parameters;
+    options.parameters = form.serialize(true);
+
+    if (params) {
+      if (typeof params == 'string') params = params.toQueryParams();
+      Object.extend(options.parameters, params);
+    }
+
+    if (form.hasAttribute('method') && !options.method)
+      options.method = form.method;
+
+    return new Ajax.Request(form.readAttribute('action'), options);
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+}
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = {};
+        pair[element.name] = value;
+        return Hash.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    try {
+      element.focus();
+      if (element.select && (element.tagName.toLowerCase() != 'input' ||
+        !['button', 'reset', 'submit'].include(element.type)))
+        element.select();
+    } catch (e) {}
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.blur();
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.disabled = false;
+    return element;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+      default:
+        return Form.Element.Serializers.textarea(element);
+    }
+  },
+
+  inputSelector: function(element) {
+    return element.checked ? element.value : null;
+  },
+
+  textarea: function(element) {
+    return element.value;
+  },
+
+  select: function(element) {
+    return this[element.type == 'select-one' ?
+      'selectOne' : 'selectMany'](element);
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    var value = this.getValue();
+    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+      ? this.lastValue != value : String(this.lastValue) != String(value));
+    if (changed) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+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) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback.bind(this));
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) {
+  var Event = new Object();
+}
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+  KEY_HOME:     36,
+  KEY_END:      35,
+  KEY_PAGEUP:   33,
+  KEY_PAGEDOWN: 34,
+
+  element: function(event) {
+    return $(event.target || event.srcElement);
+  },
+
+  isLeftClick: function(event) {
+    return (((event.which) && (event.which == 1)) ||
+            ((event.button) && (event.button == 1)));
+  },
+
+  pointerX: function(event) {
+    return event.pageX || (event.clientX +
+      (document.documentElement.scrollLeft || document.body.scrollLeft));
+  },
+
+  pointerY: function(event) {
+    return event.pageY || (event.clientY +
+      (document.documentElement.scrollTop || document.body.scrollTop));
+  },
+
+  stop: function(event) {
+    if (event.preventDefault) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else {
+      event.returnValue = false;
+      event.cancelBubble = true;
+    }
+  },
+
+  // find the first node with the given tagName, starting from the
+  // node the event was triggered on; traverses the DOM upwards
+  findElement: function(event, tagName) {
+    var element = Event.element(event);
+    while (element.parentNode && (!element.tagName ||
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))
+      element = element.parentNode;
+    return element;
+  },
+
+  observers: false,
+
+  _observeAndCache: function(element, name, observer, useCapture) {
+    if (!this.observers) this.observers = [];
+    if (element.addEventListener) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.addEventListener(name, observer, useCapture);
+    } else if (element.attachEvent) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.attachEvent('on' + name, observer);
+    }
+  },
+
+  unloadCache: function() {
+    if (!Event.observers) return;
+    for (var i = 0, length = Event.observers.length; i < length; i++) {
+      Event.stopObserving.apply(this, Event.observers[i]);
+      Event.observers[i][0] = null;
+    }
+    Event.observers = false;
+  },
+
+  observe: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+      (Prototype.Browser.WebKit || element.attachEvent))
+      name = 'keydown';
+
+    Event._observeAndCache(element, name, observer, useCapture);
+  },
+
+  stopObserving: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (Prototype.Browser.WebKit || element.attachEvent))
+      name = 'keydown';
+
+    if (element.removeEventListener) {
+      element.removeEventListener(name, observer, useCapture);
+    } else if (element.detachEvent) {
+      try {
+        element.detachEvent('on' + name, observer);
+      } catch (e) {}
+    }
+  }
+});
+
+/* prevent memory leaks in IE */
+if (Prototype.Browser.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,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  realOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    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) {
+        if(element.tagName=='BODY') break;
+        var 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)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = this.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = this.realOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = this.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            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) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  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 {
+      if (!window.opera || element.tagName=='BODY') {
+        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 (Prototype.Browser.WebKit) {
+  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];
+  }
+}
+
+Element.addMethods();
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico.js b/trunk/NP_TrackBack/trackback/js/rico.js
deleted file mode 100644 (file)
index 535e0de..0000000
+++ /dev/null
@@ -1,2819 +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.2',
-  prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
-}
-
-if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
-      throw("Rico requires the Prototype JavaScript framework >= 1.3");
-
-Rico.ArrayExtensions = new Array();
-
-if (Object.prototype.extend) {
-   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
-}else{
-  Object.prototype.extend = function(object) {
-    return Object.extend.apply(this, [this, object]);
-  }
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
-}
-
-if (Array.prototype.push) {
-   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
-}
-
-if (!Array.prototype.remove) {
-   Array.prototype.remove = function(dx) {
-      if( isNaN(dx) || dx > this.length )
-         return false;
-      for( var i=0,n=0; i<this.length; i++ )
-         if( i != dx )
-            this[n++]=this[i];
-      this.length-=1;
-   };
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
-}
-
-if (!Array.prototype.removeItem) {
-   Array.prototype.removeItem = function(item) {
-      for ( var i = 0 ; i < this.length ; i++ )
-         if ( this[i] == item ) {
-            this.remove(i);
-            break;
-         }
-   };
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
-}
-
-if (!Array.prototype.indices) {
-   Array.prototype.indices = function() {
-      var indexArray = new Array();
-      for ( index in this ) {
-         var ignoreThis = false;
-         for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
-            if ( this[index] == Rico.ArrayExtensions[i] ) {
-               ignoreThis = true;
-               break;
-            }
-         }
-         if ( !ignoreThis )
-            indexArray[ indexArray.length ] = index;
-      }
-      return indexArray;
-   }
-  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
-}
-
-// Create the loadXML method and xml getter for Mozilla
-if ( window.DOMParser &&
-         window.XMLSerializer &&
-         window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
-
-   if (!Document.prototype.loadXML) {
-      Document.prototype.loadXML = function (s) {
-         var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
-         while (this.hasChildNodes())
-            this.removeChild(this.lastChild);
-
-         for (var i = 0; i < doc2.childNodes.length; i++) {
-            this.appendChild(this.importNode(doc2.childNodes[i], true));
-         }
-      };
-       }
-
-       Document.prototype.__defineGetter__( "xml",
-          function () {
-                  return (new XMLSerializer()).serializeToString(this);
-          }
-        );
-}
-
-document.getElementsByTagAndClassName = function(tagName, className) {
-  if ( tagName == null )
-     tagName = '*';
-
-  var children = document.getElementsByTagName(tagName) || document.all;
-  var elements = new Array();
-
-  if ( className == null )
-    return children;
-
-  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;
-}
-
-
-//-------------------- ricoAccordion.js
-Rico.Accordion = Class.create();
-
-Rico.Accordion.prototype = {
-
-   initialize: function(container, options) {
-      this.container            = $(container);
-      this.lastExpandedTab      = null;
-      this.accordionTabs        = new Array();
-      this.setOptions(options);
-      this._attachBehaviors();
-      if(!container) return;
-
-      this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
-      // validate onloadShowTab
-       if (this.options.onLoadShowTab >= this.accordionTabs.length)
-        this.options.onLoadShowTab = 0;
-
-      // set the initial visual state...
-      for ( var i=0 ; i < this.accordionTabs.length ; i++ )
-      {
-        if (i != this.options.onLoadShowTab){
-         this.accordionTabs[i].collapse();
-         this.accordionTabs[i].content.style.display = 'none';
-        }
-      }
-      this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
-      if (this.options.panelHeight == 'auto'){
-          var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
-          var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
-          if (isNaN(titleBarSize))
-            titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
-          
-          var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
-          var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
-          if (isNaN(parentHeight))
-            parentHeight = this.container.parentNode.offsetHeight;
-          
-          this.options.panelHeight = parentHeight - totalTitleBarSize-2;
-      }
-      
-      this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
-      this.lastExpandedTab.showExpanded();
-      this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
-
-   },
-
-   setOptions: function(options) {
-      this.options = {
-         expandedBg          : '#63699c',
-         hoverBg             : '#63699c',
-         collapsedBg         : '#6b79a5',
-         expandedTextColor   : '#ffffff',
-         expandedFontWeight  : 'bold',
-         hoverTextColor      : '#ffffff',
-         collapsedTextColor  : '#ced7ef',
-         collapsedFontWeight : 'normal',
-         hoverTextColor      : '#ffffff',
-         borderColor         : '#1f669b',
-         panelHeight         : 200,
-         onHideTab           : null,
-         onShowTab           : null,
-         onLoadShowTab       : 0
-      }
-      Object.extend(this.options, options || {});
-   },
-
-   showTabByIndex: function( anIndex, animate ) {
-      var doAnimate = arguments.length == 1 ? true : animate;
-      this.showTab( this.accordionTabs[anIndex], doAnimate );
-   },
-
-   showTab: function( accordionTab, animate ) {
-     if ( this.lastExpandedTab == accordionTab )
-        return;
-
-      var doAnimate = arguments.length == 1 ? true : animate;
-
-      if ( this.options.onHideTab )
-         this.options.onHideTab(this.lastExpandedTab);
-
-      this.lastExpandedTab.showCollapsed(); 
-      var accordion = this;
-      var lastExpandedTab = this.lastExpandedTab;
-
-      this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
-      accordionTab.content.style.display = '';
-
-      accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
-
-      if ( doAnimate ) {
-         new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
-                                   accordionTab.content,
-                                   1,
-                                   this.options.panelHeight,
-                                   100, 10,
-                                   { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
-         this.lastExpandedTab = accordionTab;
-      }
-      else {
-         this.lastExpandedTab.content.style.height = "1px";
-         accordionTab.content.style.height = this.options.panelHeight + "px";
-         this.lastExpandedTab = accordionTab;
-         this.showTabDone(lastExpandedTab);
-      }
-   },
-
-   showTabDone: function(collapsedTab) {
-      collapsedTab.content.style.display = 'none';
-      this.lastExpandedTab.showExpanded();
-      if ( this.options.onShowTab )
-         this.options.onShowTab(this.lastExpandedTab);
-   },
-
-   _attachBehaviors: function() {
-      var panels = this._getDirectChildrenByTag(this.container, 'DIV');
-      for ( var i = 0 ; i < panels.length ; i++ ) {
-
-         var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
-         if ( tabChildren.length != 2 )
-            continue; // unexpected
-
-         var tabTitleBar   = tabChildren[0];
-         var tabContentBox = tabChildren[1];
-         this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
-      }
-   },
-
-   _getDirectChildrenByTag: function(e, tagName) {
-      var kids = new Array();
-      var allKids = e.childNodes;
-      for( var i = 0 ; i < allKids.length ; i++ )
-         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
-            kids.push(allKids[i]);
-      return kids;
-   }
-
-};
-
-Rico.Accordion.Tab = Class.create();
-
-Rico.Accordion.Tab.prototype = {
-
-   initialize: function(accordion, titleBar, content) {
-      this.accordion = accordion;
-      this.titleBar  = titleBar;
-      this.content   = content;
-      this._attachBehaviors();
-   },
-
-   collapse: function() {
-      this.showCollapsed();
-      this.content.style.height = "1px";
-   },
-
-   showCollapsed: function() {
-      this.expanded = false;
-      this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
-      this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
-      this.titleBar.style.fontWeight      = this.accordion.options.collapsedFontWeight;
-      this.content.style.overflow = "hidden";
-   },
-
-   showExpanded: function() {
-      this.expanded = true;
-      this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
-      this.titleBar.style.color           = this.accordion.options.expandedTextColor;
-      this.content.style.overflow         = "auto";
-   },
-
-   titleBarClicked: function(e) {
-      if ( this.accordion.lastExpandedTab == this )
-         return;
-      this.accordion.showTab(this);
-   },
-
-   hover: function(e) {
-               this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
-               this.titleBar.style.color           = this.accordion.options.hoverTextColor;
-   },
-
-   unhover: function(e) {
-      if ( this.expanded ) {
-         this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
-         this.titleBar.style.color           = this.accordion.options.expandedTextColor;
-      }
-      else {
-         this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
-         this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
-      }
-   },
-
-   _attachBehaviors: function() {
-      this.content.style.border = "1px solid " + this.accordion.options.borderColor;
-      this.content.style.borderTopWidth    = "0px";
-      this.content.style.borderBottomWidth = "0px";
-      this.content.style.margin            = "0px";
-
-      this.titleBar.onclick     = this.titleBarClicked.bindAsEventListener(this);
-      this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
-      this.titleBar.onmouseout  = this.unhover.bindAsEventListener(this);
-   }
-
-};
-
-
-//-------------------- ricoAjaxEngine.js
-Rico.AjaxEngine = Class.create();
-
-Rico.AjaxEngine.prototype = {
-
-   initialize: function() {
-      this.ajaxElements = new Array();
-      this.ajaxObjects  = new Array();
-      this.requestURLS  = new Array();
-      this.options = {};
-   },
-
-   registerAjaxElement: function( anId, anElement ) {
-      if ( !anElement )
-         anElement = $(anId);
-      this.ajaxElements[anId] = anElement;
-   },
-
-   registerAjaxObject: function( anId, anObject ) {
-      this.ajaxObjects[anId] = anObject;
-   },
-
-   registerRequest: function (requestLogicalName, requestURL) {
-      this.requestURLS[requestLogicalName] = requestURL;
-   },
-
-   sendRequest: function(requestName, options) {
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 2 )
-       if (typeof arguments[1] == 'string')
-         options = {parameters: this._createQueryString(arguments, 1)};
-      this.sendRequestWithData(requestName, null, options);
-   },
-
-   sendRequestWithData: function(requestName, xmlDocument, options) {
-      var requestURL = this.requestURLS[requestName];
-      if ( requestURL == null )
-         return;
-
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 3 )
-        if (typeof arguments[2] == 'string')
-          options.parameters = this._createQueryString(arguments, 2);
-
-      new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
-   },
-
-   sendRequestAndUpdate: function(requestName,container,options) {
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 3 )
-        if (typeof arguments[2] == 'string')
-          options.parameters = this._createQueryString(arguments, 2);
-
-      this.sendRequestWithDataAndUpdate(requestName, null, container, options);
-   },
-
-   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
-      var requestURL = this.requestURLS[requestName];
-      if ( requestURL == null )
-         return;
-
-      // Allow for backwards Compatibility
-      if ( arguments.length >= 4 )
-        if (typeof arguments[3] == 'string')
-          options.parameters = this._createQueryString(arguments, 3);
-
-      var updaterOptions = this._requestOptions(options,xmlDocument);
-
-      new Ajax.Updater(container, requestURL, updaterOptions);
-   },
-
-   // Private -- not part of intended engine API --------------------------------------------------------------------
-
-   _requestOptions: function(options,xmlDoc) {
-      var requestHeaders = ['X-Rico-Version', Rico.Version ];
-      var sendMethod = 'post';
-      if ( xmlDoc == null )
-        if (Rico.prototypeVersion < 1.4)
-        requestHeaders.push( 'Content-type', 'text/xml' );
-      else
-          sendMethod = 'get';
-      (!options) ? options = {} : '';
-
-      if (!options._RicoOptionsProcessed){
-      // Check and keep any user onComplete functions
-        if (options.onComplete)
-             options.onRicoComplete = options.onComplete;
-        // Fix onComplete
-        if (options.overrideOnComplete)
-          options.onComplete = options.overrideOnComplete;
-        else
-          options.onComplete = this._onRequestComplete.bind(this);
-        options._RicoOptionsProcessed = true;
-      }
-
-     // Set the default options and extend with any user options
-     this.options = {
-                     requestHeaders: requestHeaders,
-                     parameters:     options.parameters,
-                     postBody:       xmlDoc,
-                     method:         sendMethod,
-                     onComplete:     options.onComplete
-                    };
-     // Set any user options:
-     Object.extend(this.options, options);
-     return this.options;
-   },
-
-   _createQueryString: function( theArgs, offset ) {
-      var queryString = ""
-      for ( var i = offset ; i < theArgs.length ; i++ ) {
-          if ( i != offset )
-            queryString += "&";
-
-          var anArg = theArgs[i];
-
-          if ( anArg.name != undefined && anArg.value != undefined ) {
-            queryString += anArg.name +  "=" + escape(anArg.value);
-          }
-          else {
-             var ePos  = anArg.indexOf('=');
-             var argName  = anArg.substring( 0, ePos );
-             var argValue = anArg.substring( ePos + 1 );
-             queryString += argName + "=" + escape(argValue);
-          }
-      }
-      return queryString;
-   },
-
-   _onRequestComplete : function(request) {
-      if(!request)
-          return;
-      // User can set an onFailure option - which will be called by prototype
-      if (request.status != 200)
-        return;
-
-      var response = request.responseXML.getElementsByTagName("ajax-response");
-      if (response == null || response.length != 1)
-         return;
-      this._processAjaxResponse( response[0].childNodes );
-      
-      // Check if user has set a onComplete function
-      var onRicoComplete = this.options.onRicoComplete;
-      if (onRicoComplete != null)
-          onRicoComplete();
-   },
-
-   _processAjaxResponse: function( xmlResponseElements ) {
-      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
-         var responseElement = xmlResponseElements[i];
-
-         // only process nodes of type element.....
-         if ( responseElement.nodeType != 1 )
-            continue;
-
-         var responseType = responseElement.getAttribute("type");
-         var responseId   = responseElement.getAttribute("id");
-
-         if ( responseType == "object" )
-            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
-         else if ( responseType == "element" )
-            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
-         else
-            alert('unrecognized AjaxResponse type : ' + responseType );
-      }
-   },
-
-   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
-      ajaxObject.ajaxUpdate( responseElement );
-   },
-
-   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
-      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
-   }
-
-}
-
-var ajaxEngine = new Rico.AjaxEngine();
-
-
-//-------------------- ricoColor.js
-Rico.Color = Class.create();
-
-Rico.Color.prototype = {
-
-   initialize: function(red, green, blue) {
-      this.rgb = { r: red, g : green, b : blue };
-   },
-
-   setRed: function(r) {
-      this.rgb.r = r;
-   },
-
-   setGreen: function(g) {
-      this.rgb.g = g;
-   },
-
-   setBlue: function(b) {
-      this.rgb.b = b;
-   },
-
-   setHue: function(h) {
-
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.h = h;
-
-      // convert back to RGB...
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
-   },
-
-   setSaturation: function(s) {
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.s = s;
-
-      // convert back to RGB and set values...
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
-   },
-
-   setBrightness: function(b) {
-      // get an HSB model, and set the new hue...
-      var hsb = this.asHSB();
-      hsb.b = b;
-
-      // convert back to RGB and set values...
-      this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
-   },
-
-   darken: function(percent) {
-      var hsb  = this.asHSB();
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
-   },
-
-   brighten: function(percent) {
-      var hsb  = this.asHSB();
-      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
-   },
-
-   blend: function(other) {
-      this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
-      this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
-      this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
-   },
-
-   isBright: function() {
-      var hsb = this.asHSB();
-      return this.asHSB().b > 0.5;
-   },
-
-   isDark: function() {
-      return ! this.isBright();
-   },
-
-   asRGB: function() {
-      return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
-   },
-
-   asHex: function() {
-      return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
-   },
-
-   asHSB: function() {
-      return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
-   },
-
-   toString: function() {
-      return this.asHex();
-   }
-
-};
-
-Rico.Color.createFromHex = function(hexCode) {
-  if(hexCode.length==4) {
-    var shortHexCode = hexCode; 
-    var hexCode = '#';
-    for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) + 
-shortHexCode.charAt(i));
-  }
-   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.parentNode )
-      return Rico.Color.createColorFromBackground(elem.parentNode);
-
-   if ( actualColor == null )
-      return new Rico.Color(255,255,255);
-
-   if ( actualColor.indexOf("rgb(") == 0 ) {
-      var colors = actualColor.substring(4, actualColor.length - 1 );
-      var colorArray = colors.split(",");
-      return new Rico.Color( parseInt( colorArray[0] ),
-                            parseInt( colorArray[1] ),
-                            parseInt( colorArray[2] )  );
-
-   }
-   else if ( actualColor.indexOf("#") == 0 ) {
-      return Rico.Color.createFromHex(actualColor);
-   }
-   else
-      return new Rico.Color(255,255,255);
-}
-
-Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
-
-   var red   = 0;
-       var green = 0;
-       var blue  = 0;
-
-   if (saturation == 0) {
-      red = parseInt(brightness * 255.0 + 0.5);
-          green = red;
-          blue = red;
-       }
-       else {
-      var h = (hue - Math.floor(hue)) * 6.0;
-      var f = h - Math.floor(h);
-      var p = brightness * (1.0 - saturation);
-      var q = brightness * (1.0 - saturation * f);
-      var t = brightness * (1.0 - (saturation * (1.0 - f)));
-
-      switch (parseInt(h)) {
-         case 0:
-            red   = (brightness * 255.0 + 0.5);
-            green = (t * 255.0 + 0.5);
-            blue  = (p * 255.0 + 0.5);
-            break;
-         case 1:
-            red   = (q * 255.0 + 0.5);
-            green = (brightness * 255.0 + 0.5);
-            blue  = (p * 255.0 + 0.5);
-            break;
-         case 2:
-            red   = (p * 255.0 + 0.5);
-            green = (brightness * 255.0 + 0.5);
-            blue  = (t * 255.0 + 0.5);
-            break;
-         case 3:
-            red   = (p * 255.0 + 0.5);
-            green = (q * 255.0 + 0.5);
-            blue  = (brightness * 255.0 + 0.5);
-            break;
-         case 4:
-            red   = (t * 255.0 + 0.5);
-            green = (p * 255.0 + 0.5);
-            blue  = (brightness * 255.0 + 0.5);
-            break;
-          case 5:
-            red   = (brightness * 255.0 + 0.5);
-            green = (p * 255.0 + 0.5);
-            blue  = (q * 255.0 + 0.5);
-            break;
-           }
-       }
-
-   return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
-}
-
-Rico.Color.RGBtoHSB = function(r, g, b) {
-
-   var hue;
-   var saturation;
-   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 = "<div " + style + ">" + el.innerHTML + "</div>"
-   },
-
-   _roundTopCorners: function(el, color, bgColor) {
-      var corner = this._createCorner(bgColor);
-      for(var i=0 ; i < this.options.numSlices ; i++ )
-         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
-      el.style.paddingTop = 0;
-      el.insertBefore(corner,el.firstChild);
-   },
-
-   _roundBottomCorners: function(el, color, bgColor) {
-      var corner = this._createCorner(bgColor);
-      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
-         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
-      el.style.paddingBottom = 0;
-      el.appendChild(corner);
-   },
-
-   _createCorner: function(bgColor) {
-      var corner = document.createElement("div");
-      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
-      return corner;
-   },
-
-   _createCornerSlice: function(color,bgColor, n, position) {
-      var slice = document.createElement("span");
-
-      var inStyle = slice.style;
-      inStyle.backgroundColor = color;
-      inStyle.display  = "block";
-      inStyle.height   = "1px";
-      inStyle.overflow = "hidden";
-      inStyle.fontSize = "1px";
-
-      var borderColor = this._borderColor(color,bgColor);
-      if ( this.options.border && n == 0 ) {
-         inStyle.borderTopStyle    = "solid";
-         inStyle.borderTopWidth    = "1px";
-         inStyle.borderLeftWidth   = "0px";
-         inStyle.borderRightWidth  = "0px";
-         inStyle.borderBottomWidth = "0px";
-         inStyle.height            = "0px"; // assumes css compliant box model
-         inStyle.borderColor       = borderColor;
-      }
-      else if(borderColor) {
-         inStyle.borderColor = borderColor;
-         inStyle.borderStyle = "solid";
-         inStyle.borderWidth = "0px 1px";
-      }
-
-      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
-         inStyle.height = "2px";
-
-      this._setMargin(slice, n, position);
-      this._setBorder(slice, n, position);
-      return slice;
-   },
-
-   _setOptions: function(options) {
-      this.options = {
-         corners : "all",
-         color   : "fromElement",
-         bgColor : "fromParent",
-         blend   : true,
-         border  : false,
-         compact : false
-      }
-      Object.extend(this.options, options || {});
-
-      this.options.numSlices = this.options.compact ? 2 : 4;
-      if ( this._isTransparent() )
-         this.options.blend = false;
-   },
-
-   _whichSideTop: function() {
-      if ( this._hasString(this.options.corners, "all", "top") )
-         return "";
-
-      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
-         return "";
-
-      if (this.options.corners.indexOf("tl") >= 0)
-         return "left";
-      else if (this.options.corners.indexOf("tr") >= 0)
-          return "right";
-      return "";
-   },
-
-   _whichSideBottom: function() {
-      if ( this._hasString(this.options.corners, "all", "bottom") )
-         return "";
-
-      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
-         return "";
-
-      if(this.options.corners.indexOf("bl") >=0)
-         return "left";
-      else if(this.options.corners.indexOf("br")>=0)
-         return "right";
-      return "";
-   },
-
-   _borderColor : function(color,bgColor) {
-      if ( color == "transparent" )
-         return bgColor;
-      else if ( this.options.border )
-         return this.options.border;
-      else if ( this.options.blend )
-         return this._blend( bgColor, color );
-      else
-         return "";
-   },
-
-
-   _setMargin: function(el, n, corners) {
-      var marginSize = this._marginSize(n);
-      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
-
-      if ( whichSide == "left" ) {
-         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
-      }
-      else if ( whichSide == "right" ) {
-         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
-      }
-      else {
-         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
-      }
-   },
-
-   _setBorder: function(el,n,corners) {
-      var borderSize = this._borderSize(n);
-      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
-      if ( whichSide == "left" ) {
-         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
-      }
-      else if ( whichSide == "right" ) {
-         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
-      }
-      else {
-         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
-      }
-      if (this.options.border != false)
-        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
-   },
-
-   _marginSize: function(n) {
-      if ( this._isTransparent() )
-         return 0;
-
-      var marginSizes          = [ 5, 3, 2, 1 ];
-      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
-      var compactMarginSizes   = [ 2, 1 ];
-      var smBlendedMarginSizes = [ 1, 0 ];
-
-      if ( this.options.compact && this.options.blend )
-         return smBlendedMarginSizes[n];
-      else if ( this.options.compact )
-         return compactMarginSizes[n];
-      else if ( this.options.blend )
-         return blendedMarginSizes[n];
-      else
-         return marginSizes[n];
-   },
-
-   _borderSize: function(n) {
-      var transparentBorderSizes = [ 5, 3, 2, 1 ];
-      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
-      var compactBorderSizes     = [ 1, 0 ];
-      var actualBorderSizes      = [ 0, 2, 0, 0 ];
-
-      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
-         return 1;
-      else if ( this.options.compact )
-         return compactBorderSizes[n];
-      else if ( this.options.blend )
-         return blendedBorderSizes[n];
-      else if ( this.options.border )
-         return actualBorderSizes[n];
-      else if ( this._isTransparent() )
-         return transparentBorderSizes[n];
-      return 0;
-   },
-
-   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
-   _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
-   _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
-   _isTransparent: function() { return this.options.color == "transparent"; },
-   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
-   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
-   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
-}
-
-
-//-------------------- ricoDragAndDrop.js
-Rico.DragAndDrop = Class.create();
-
-Rico.DragAndDrop.prototype = {
-
-   initialize: function() {
-      this.dropZones                = new Array();
-      this.draggables               = new Array();
-      this.currentDragObjects       = new Array();
-      this.dragElement              = null;
-      this.lastSelectedDraggable    = null;
-      this.currentDragObjectVisible = false;
-      this.interestedInMotionEvents = false;
-      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
-      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
-      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
-   },
-
-   registerDropZone: function(aDropZone) {
-      this.dropZones[ this.dropZones.length ] = aDropZone;
-   },
-
-   deregisterDropZone: function(aDropZone) {
-      var newDropZones = new Array();
-      var j = 0;
-      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
-         if ( this.dropZones[i] != aDropZone )
-            newDropZones[j++] = this.dropZones[i];
-      }
-
-      this.dropZones = newDropZones;
-   },
-
-   clearDropZones: function() {
-      this.dropZones = new Array();
-   },
-
-   registerDraggable: function( aDraggable ) {
-      this.draggables[ this.draggables.length ] = aDraggable;
-      this._addMouseDownHandler( aDraggable );
-   },
-
-   clearSelection: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].deselect();
-      this.currentDragObjects = new Array();
-      this.lastSelectedDraggable = null;
-   },
-
-   hasSelection: function() {
-      return this.currentDragObjects.length > 0;
-   },
-
-   setStartDragFromElement: function( e, mouseDownElement ) {
-      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
-      this.startx = e.screenX - this.origPos.x
-      this.starty = e.screenY - this.origPos.y
-      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
-      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
-      //this.adjustedForDraggableSize = false;
-
-      this.interestedInMotionEvents = this.hasSelection();
-      this._terminateEvent(e);
-   },
-
-   updateSelection: function( draggable, extendSelection ) {
-      if ( ! extendSelection )
-         this.clearSelection();
-
-      if ( draggable.isSelected() ) {
-         this.currentDragObjects.removeItem(draggable);
-         draggable.deselect();
-         if ( draggable == this.lastSelectedDraggable )
-            this.lastSelectedDraggable = null;
-      }
-      else {
-         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
-         draggable.select();
-         this.lastSelectedDraggable = draggable;
-      }
-   },
-
-   _mouseDownHandler: function(e) {
-      if ( arguments.length == 0 )
-         e = event;
-
-      // if not button 1 ignore it...
-      var nsEvent = e.which != undefined;
-      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
-         return;
-
-      var eventTarget      = e.target ? e.target : e.srcElement;
-      var draggableObject  = eventTarget.draggable;
-
-      var candidate = eventTarget;
-      while (draggableObject == null && candidate.parentNode) {
-         candidate = candidate.parentNode;
-         draggableObject = candidate.draggable;
-      }
-   
-      if ( draggableObject == null )
-         return;
-
-      this.updateSelection( draggableObject, e.ctrlKey );
-
-      // clear the drop zones postion cache...
-      if ( this.hasSelection() )
-         for ( var i = 0 ; i < this.dropZones.length ; i++ )
-            this.dropZones[i].clearPositionCache();
-
-      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
-   },
-
-
-   _mouseMoveHandler: function(e) {
-      var nsEvent = e.which != undefined;
-      if ( !this.interestedInMotionEvents ) {
-         //this._terminateEvent(e);
-         return;
-      }
-
-      if ( ! this.hasSelection() )
-         return;
-
-      if ( ! this.currentDragObjectVisible )
-         this._startDrag(e);
-
-      if ( !this.activatedDropZones )
-         this._activateRegisteredDropZones();
-
-      //if ( !this.adjustedForDraggableSize )
-      //   this._adjustForDraggableSize(e);
-
-      this._updateDraggableLocation(e);
-      this._updateDropZonesHover(e);
-
-      this._terminateEvent(e);
-   },
-
-   _makeDraggableObjectVisible: function(e)
-   {
-      if ( !this.hasSelection() )
-         return;
-
-      var dragElement;
-      if ( this.currentDragObjects.length > 1 )
-         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
-      else
-         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
-
-      // go ahead and absolute position it...
-      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
-         dragElement.style.position = "absolute";
-
-      // need to parent him into the document...
-      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
-         document.body.appendChild(dragElement);
-
-      this.dragElement = dragElement;
-      this._updateDraggableLocation(e);
-
-      this.currentDragObjectVisible = true;
-   },
-
-   /**
-   _adjustForDraggableSize: function(e) {
-      var dragElementWidth  = this.dragElement.offsetWidth;
-      var dragElementHeight = this.dragElement.offsetHeight;
-      if ( this.startComponentX > dragElementWidth )
-         this.startx -= this.startComponentX - dragElementWidth + 2;
-      if ( e.offsetY ) {
-         if ( this.startComponentY > dragElementHeight )
-            this.starty -= this.startComponentY - dragElementHeight + 2;
-      }
-      this.adjustedForDraggableSize = true;
-   },
-   **/
-
-   _leftOffset: function(e) {
-          return e.offsetX ? document.body.scrollLeft : 0
-       },
-
-   _topOffset: function(e) {
-          return e.offsetY ? document.body.scrollTop:0
-       },
-
-               
-   _updateDraggableLocation: function(e) {
-      var dragObjectStyle = this.dragElement.style;
-      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
-      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - 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 Rico.Effect.Position( this.dragElement,
-                              this.origPos.x,
-                              this.origPos.y,
-                              200,
-                              20,
-                              { complete : this._doCancelDragProcessing.bind(this) } );
-      }
-
-     Event.stopObserving(document.body, "mousemove", this._mouseMove);
-     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
-   },
-
-   _retTrue: function () {
-      return true;
-   },
-
-   _completeDropOperation: function(e) {
-      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
-         if ( this.dragElement.parentNode != null )
-            this.dragElement.parentNode.removeChild(this.dragElement);
-      }
-
-      this._deactivateRegisteredDropZones();
-      this._endDrag();
-      this.clearSelection();
-      this.dragElement = null;
-      this.currentDragObjectVisible = false;
-      this._terminateEvent(e);
-   },
-
-   _doCancelDragProcessing: function() {
-      this._cancelDrag();
-
-        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
-           if ( this.dragElement.parentNode != null )
-              this.dragElement.parentNode.removeChild(this.dragElement);
-
-
-      this._deactivateRegisteredDropZones();
-      this.dragElement = null;
-      this.currentDragObjectVisible = false;
-   },
-
-   _placeDraggableInDropZone: function(e) {
-      var foundDropZone = false;
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ ) {
-         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
-            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
-               this.dropZones[i].hideHover();
-               this.dropZones[i].accept(this.currentDragObjects);
-               foundDropZone = true;
-               break;
-            }
-         }
-      }
-
-      return foundDropZone;
-   },
-
-   _cancelDrag: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].cancelDrag();
-   },
-
-   _endDrag: function() {
-      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
-         this.currentDragObjects[i].endDrag();
-   },
-
-   _mousePointInDropZone: function( e, dropZone ) {
-
-      var absoluteRect = dropZone.getAbsoluteRect();
-
-      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
-             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
-             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
-             e.clientY  < absoluteRect.bottom + this._topOffset(e);
-   },
-
-   _addMouseDownHandler: function( aDraggable )
-   {
-       htmlElement  = aDraggable.getMouseDownHTMLElement();
-      if ( htmlElement  != null ) { 
-         htmlElement.draggable = aDraggable;
-         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
-         Event.observe(htmlElement, "mousedown", this._mouseDown);
-      }
-   },
-
-   _activateRegisteredDropZones: function() {
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ ) {
-         var dropZone = this.dropZones[i];
-         if ( dropZone.canAccept(this.currentDragObjects) )
-            dropZone.activate();
-      }
-
-      this.activatedDropZones = true;
-   },
-
-   _deactivateRegisteredDropZones: function() {
-      var n = this.dropZones.length;
-      for ( var i = 0 ; i < n ; i++ )
-         this.dropZones[i].deactivate();
-      this.activatedDropZones = false;
-   },
-
-   _onmousedown: function () {
-     Event.observe(document.body, "mousemove", this._mouseMove);
-     Event.observe(document.body, "mouseup",  this._mouseUp);
-   },
-
-   _terminateEvent: function(e) {
-      if ( e.stopPropagation != undefined )
-         e.stopPropagation();
-      else if ( e.cancelBubble != undefined )
-         e.cancelBubble = true;
-
-      if ( e.preventDefault != undefined )
-         e.preventDefault();
-      else
-         e.returnValue = false;
-   },
-
-
-          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
-
-Rico.Effect = {};
-
-Rico.Effect.SizeAndPosition = Class.create();
-Rico.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";
-   }
-}
-
-Rico.Effect.Size = Class.create();
-Rico.Effect.Size.prototype = {
-
-   initialize: function(element, w, h, duration, steps, options) {
-      new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
-  }
-}
-
-Rico.Effect.Position = Class.create();
-Rico.Effect.Position.prototype = {
-
-   initialize: function(element, x, y, duration, steps, options) {
-      new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
-  }
-}
-
-Rico.Effect.Round = Class.create();
-Rico.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 );
-   }
-};
-
-Rico.Effect.FadeTo = Class.create();
-Rico.Effect.FadeTo.prototype = {
-
-   initialize: function( element, opacity, duration, steps, options) {
-      this.element  = $(element);
-      this.opacity  = opacity;
-      this.duration = duration;
-      this.steps    = steps;
-      this.options  = arguments[4] || {};
-      this.fadeTo();
-   },
-
-   fadeTo: function() {
-      if (this.isFinished()) {
-         if(this.options.complete) this.options.complete(this);
-         return;
-      }
-
-      if (this.timer)
-         clearTimeout(this.timer);
-
-      var stepDuration = Math.round(this.duration/this.steps) ;
-      var currentOpacity = this.getElementOpacity();
-      var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
-
-      this.changeOpacityBy(delta);
-      this.duration -= stepDuration;
-      this.steps--;
-
-      this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
-   },
-
-   changeOpacityBy: function(v) {
-      var currentOpacity = this.getElementOpacity();
-      var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
-      this.element.ricoOpacity = newOpacity;
-
-      this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
-      this.element.style.opacity = newOpacity; /*//*/;
-   },
-
-   isFinished: function() {
-      return this.steps <= 0;
-   },
-
-   getElementOpacity: function() {
-      if ( this.element.ricoOpacity == undefined ) {
-         var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
-         this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
-      }
-      return parseFloat(this.element.ricoOpacity);
-   }
-}
-
-Rico.Effect.AccordionSize = Class.create();
-
-Rico.Effect.AccordionSize.prototype = {
-
-   initialize: function(e1, e2, start, end, duration, steps, options) {
-      this.e1       = $(e1);
-      this.e2       = $(e2);
-      this.start    = start;
-      this.end      = end;
-      this.duration = duration;
-      this.steps    = steps;
-      this.options  = arguments[6] || {};
-
-      this.accordionSize();
-   },
-
-   accordionSize: function() {
-
-      if (this.isFinished()) {
-         // just in case there are round errors or such...
-         this.e1.style.height = this.start + "px";
-         this.e2.style.height = this.end + "px";
-
-         if(this.options.complete)
-            this.options.complete(this);
-         return;
-      }
-
-      if (this.timer)
-         clearTimeout(this.timer);
-
-      var stepDuration = Math.round(this.duration/this.steps) ;
-
-      var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
-      this.resizeBy(diff);
-
-      this.duration -= stepDuration;
-      this.steps--;
-
-      this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
-   },
-
-   isFinished: function() {
-      return this.steps <= 0;
-   },
-
-   resizeBy: function(diff) {
-      var h1Height = this.e1.offsetHeight;
-      var h2Height = this.e2.offsetHeight;
-      var intDiff = parseInt(diff);
-      if ( diff != 0 ) {
-         this.e1.style.height = (h1Height - intDiff) + "px";
-         this.e2.style.height = (h2Height + intDiff) + "px";
-      }
-   }
-
-};
-
-
-//-------------------- ricoLiveGrid.js
-// Rico.LiveGridMetaData -----------------------------------------------------
-
-Rico.LiveGridMetaData = Class.create();
-
-Rico.LiveGridMetaData.prototype = {
-
-   initialize: function( pageSize, totalRows, columnCount, options ) {
-      this.pageSize  = pageSize;
-      this.totalRows = totalRows;
-      this.setOptions(options);
-      this.ArrowHeight = 16;
-      this.columnCount = columnCount;
-   },
-
-   setOptions: function(options) {
-      this.options = {
-         largeBufferSize    : 7.0,   // 7 pages
-         nearLimitFactor    : 0.2    // 20% of buffer
-      };
-      Object.extend(this.options, options || {});
-   },
-
-   getPageSize: function() {
-      return this.pageSize;
-   },
-
-   getTotalRows: function() {
-      return this.totalRows;
-   },
-
-   setTotalRows: function(n) {
-      this.totalRows = n;
-   },
-
-   getLargeBufferSize: function() {
-      return parseInt(this.options.largeBufferSize * this.pageSize);
-   },
-
-   getLimitTolerance: function() {
-      return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
-   }
-};
-
-// Rico.LiveGridScroller -----------------------------------------------------
-
-Rico.LiveGridScroller = Class.create();
-
-Rico.LiveGridScroller.prototype = {
-
-   initialize: function(liveGrid, viewPort) {
-      this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
-      this.liveGrid = liveGrid;
-      this.metaData = liveGrid.metaData;
-      this.createScrollBar();
-      this.scrollTimeout = null;
-      this.lastScrollPos = 0;
-      this.viewPort = viewPort;
-      this.rows = new Array();
-   },
-
-   isUnPlugged: function() {
-      return this.scrollerDiv.onscroll == null;
-   },
-
-   plugin: function() {
-      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
-   },
-
-   unplug: function() {
-      this.scrollerDiv.onscroll = null;
-   },
-
-   sizeIEHeaderHack: function() {
-      if ( !this.isIE ) return;
-      var headerTable = $(this.liveGrid.tableId + "_header");
-      if ( headerTable )
-         headerTable.rows[0].cells[0].style.width =
-            (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
-   },
-
-   createScrollBar: function() {
-      var visibleHeight = this.liveGrid.viewPort.visibleHeight();
-      // create the outer div...
-      this.scrollerDiv  = document.createElement("div");
-      var scrollerStyle = this.scrollerDiv.style;
-      this.scrollerDiv.id = "sc"
-      scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
-      scrollerStyle.position    = "relative";
-      scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
-      scrollerStyle.width       = "19px";
-      scrollerStyle.height      = visibleHeight + "px";
-      scrollerStyle.overflow    = "auto";
-
-      // create the inner div...
-      this.heightDiv = document.createElement("div");
-      this.heightDiv.style.width  = "1px";
-
-      this.heightDiv.style.height = parseInt(visibleHeight *
-                        this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
-      this.scrollerDiv.appendChild(this.heightDiv);
-      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
-
-     var table = this.liveGrid.table;
-     table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
-         var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
-         Event.observe(table, eventName, 
-                       function(evt) {
-                          if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
-                             this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
-                          else
-                             this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
-                          this.handleScroll(false);
-                       }.bindAsEventListener(this), 
-                       false);
-     },
-
-   updateSize: function() {
-      var table = this.liveGrid.table;
-      var visibleHeight = this.viewPort.visibleHeight();
-      this.heightDiv.style.height = parseInt(visibleHeight *
-                                  this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
-   },
-
-   rowToPixel: function(rowOffset) {
-      return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
-   },
-   
-   moveScroll: function(rowOffset) {
-      this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
-      if ( this.metaData.options.onscroll )
-         this.metaData.options.onscroll( this.liveGrid, rowOffset );
-   },
-
-   handleScroll: function() {
-     if ( this.scrollTimeout )
-         clearTimeout( this.scrollTimeout );
-
-    var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
-    if (scrollDiff != 0.00) {
-       var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
-       if (r != 0) {
-          this.unplug();
-          if ( scrollDiff < 0 ) {
-             this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
-          } else {
-             this.scrollerDiv.scrollTop -= r;
-          }
-          this.plugin();
-       }
-    }
-    var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
-    this.liveGrid.requestContentRefresh(contentOffset);
-    this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
-
-    if ( this.metaData.options.onscroll )
-       this.metaData.options.onscroll( this.liveGrid, contentOffset );
-
-    this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
-    this.lastScrollPos = this.scrollerDiv.scrollTop;
-
-   },
-
-   scrollIdle: function() {
-      if ( this.metaData.options.onscrollidle )
-         this.metaData.options.onscrollidle();
-   }
-};
-
-// Rico.LiveGridBuffer -----------------------------------------------------
-
-Rico.LiveGridBuffer = Class.create();
-
-Rico.LiveGridBuffer.prototype = {
-
-   initialize: function(metaData, viewPort) {
-      this.startPos = 0;
-      this.size     = 0;
-      this.metaData = metaData;
-      this.rows     = new Array();
-      this.updateInProgress = false;
-      this.viewPort = viewPort;
-      this.maxBufferSize = metaData.getLargeBufferSize() * 2;
-      this.maxFetchSize = metaData.getLargeBufferSize();
-      this.lastOffset = 0;
-   },
-
-   getBlankRow: function() {
-      if (!this.blankRow ) {
-         this.blankRow = new Array();
-         for ( var i=0; i < this.metaData.columnCount ; i++ ) 
-            this.blankRow[i] = "&#160;";
-     }
-     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] = '&#160;';
-         }
-      }
-      return newRows;
-   },
-      
-   update: function(ajaxResponse, start) {
-     var newRows = this.loadRows(ajaxResponse);
-      if (this.rows.length == 0) { // initial load
-         this.rows = newRows;
-         this.size = this.rows.length;
-         this.startPos = start;
-         return;
-      }
-      if (start > this.startPos) { //appending
-         if (this.startPos + this.rows.length < start) {
-            this.rows =  newRows;
-            this.startPos = start;//
-         } else {
-              this.rows = this.rows.concat( newRows.slice(0, newRows.length));
-            if (this.rows.length > this.maxBufferSize) {
-               var fullSize = this.rows.length;
-               this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
-               this.startPos = this.startPos +  (fullSize - this.rows.length);
-            }
-         }
-      } else { //prepending
-         if (start + newRows.length < this.startPos) {
-            this.rows =  newRows;
-         } else {
-            this.rows = newRows.slice(0, this.startPos).concat(this.rows);
-            if (this.rows.length > this.maxBufferSize) 
-               this.rows = this.rows.slice(0, this.maxBufferSize)
-         }
-         this.startPos =  start;
-      }
-      this.size = this.rows.length;
-   },
-   
-   clear: function() {
-      this.rows = new Array();
-      this.startPos = 0;
-      this.size = 0;
-   },
-
-   isOverlapping: function(start, size) {
-      return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
-   },
-
-   isInRange: function(position) {
-      return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); 
-             //&& this.size()  != 0;
-   },
-
-   isNearingTopLimit: function(position) {
-      return position - this.startPos < this.metaData.getLimitTolerance();
-   },
-
-   endPos: function() {
-      return this.startPos + this.rows.length;
-   },
-   
-   isNearingBottomLimit: function(position) {
-      return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
-   },
-
-   isAtTop: function() {
-      return this.startPos == 0;
-   },
-
-   isAtBottom: function() {
-      return this.endPos() == this.metaData.getTotalRows();
-   },
-
-   isNearingLimit: function(position) {
-      return ( !this.isAtTop()    && this.isNearingTopLimit(position)) ||
-             ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
-   },
-
-   getFetchSize: function(offset) {
-      var adjustedOffset = this.getFetchOffset(offset);
-      var adjustedSize = 0;
-      if (adjustedOffset >= this.startPos) { //apending
-         var endFetchOffset = this.maxFetchSize  + adjustedOffset;
-         if (endFetchOffset > this.metaData.totalRows)
-            endFetchOffset = this.metaData.totalRows;
-         adjustedSize = endFetchOffset - adjustedOffset;  
-                       if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
-                          adjustedSize = this.maxFetchSize;
-                       }
-      } else {//prepending
-         var adjustedSize = this.startPos - adjustedOffset;
-         if (adjustedSize > this.maxFetchSize)
-            adjustedSize = this.maxFetchSize;
-      }
-      return adjustedSize;
-   }, 
-
-   getFetchOffset: function(offset) {
-      var adjustedOffset = offset;
-      if (offset > this.startPos)  //apending
-         adjustedOffset = (offset > this.endPos()) ? offset :  this.endPos(); 
-      else { //prepending
-         if (offset + this.maxFetchSize >= this.startPos) {
-            var adjustedOffset = this.startPos - this.maxFetchSize;
-            if (adjustedOffset < 0)
-               adjustedOffset = 0;
-         }
-      }
-      this.lastOffset = adjustedOffset;
-      return adjustedOffset;
-   },
-
-   getRows: function(start, count) {
-      var begPos = start - this.startPos
-      var endPos = begPos + count
-
-      // er? need more data...
-      if ( endPos > this.size )
-         endPos = this.size
-
-      var results = new Array()
-      var index = 0;
-      for ( var i=begPos ; i < endPos; i++ ) {
-         results[index++] = this.rows[i]
-      }
-      return results
-   },
-
-   convertSpaces: function(s) {
-      return s.split(" ").join("&#160;");
-   }
-
-};
-
-
-//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) + "px";
-      this.div.style.overflow = "hidden";
-      this.buffer = buffer;
-      this.liveGrid = liveGrid;
-      this.visibleRows = visibleRows + 1;
-      this.lastPixelOffset = 0;
-      this.startPos = 0;
-   },
-
-   populateRow: function(htmlRow, row) {
-      for (var j=0; j < row.length; j++) {
-         htmlRow.cells[j].innerHTML = row[j]
-      }
-   },
-   
-   bufferChanged: function() {
-      this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
-   },
-   
-   clearRows: function() {
-      if (!this.isBlank) {
-         this.liveGrid.table.className = this.liveGrid.options.loadingClass;
-         for (var i=0; i < this.visibleRows; i++)
-            this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
-         this.isBlank = true;
-      }
-   },
-   
-   clearContents: function() {   
-      this.clearRows();
-      this.scrollTo(0);
-      this.startPos = 0;
-      this.lastStartPos = -1;   
-   },
-   
-   refreshContents: function(startPos) {
-      if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
-         return;
-      }
-      if ((startPos + this.visibleRows < this.buffer.startPos)  
-          || (this.buffer.startPos + this.buffer.size < startPos) 
-          || (this.buffer.size == 0)) {
-         this.clearRows();
-         return;
-      }
-      this.isBlank = false;
-      var viewPrecedesBuffer = this.buffer.startPos > startPos
-      var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos; 
-      var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) 
-                                 ? this.buffer.startPos + this.buffer.size
-                                 : startPos + this.visibleRows;
-      var rowSize = contentEndPos - contentStartPos;
-      var rows = this.buffer.getRows(contentStartPos, rowSize ); 
-      var blankSize = this.visibleRows - rowSize;
-      var blankOffset = viewPrecedesBuffer ? 0: rowSize;
-      var contentOffset = viewPrecedesBuffer ? blankSize: 0;
-
-      for (var i=0; i < rows.length; i++) {//initialize what we have
-        this.populateRow(this.table.rows[i + contentOffset], rows[i]);
-      }
-      for (var i=0; i < blankSize; i++) {// blank out the rest 
-        this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
-      }
-      this.isPartialBlank = blankSize > 0;
-      this.lastRowPos = startPos;
-
-       this.liveGrid.table.className = this.liveGrid.options.tableClass;
-       // Check if user has set a onRefreshComplete function
-       var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
-       if (onRefreshComplete != null)
-           onRefreshComplete();
-   },
-
-   scrollTo: function(pixelOffset) {      
-      if (this.lastPixelOffset == pixelOffset)
-         return;
-
-      this.refreshContents(parseInt(pixelOffset / this.rowHeight))
-      this.div.scrollTop = pixelOffset % this.rowHeight        
-      
-      this.lastPixelOffset = pixelOffset;
-   },
-   
-   visibleHeight: function() {
-      return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
-   }
-
-};
-
-
-Rico.LiveGridRequest = Class.create();
-Rico.LiveGridRequest.prototype = {
-   initialize: function( requestOffset, options ) {
-      this.requestOffset = requestOffset;
-   }
-};
-
-// Rico.LiveGrid -----------------------------------------------------
-
-Rico.LiveGrid = Class.create();
-
-Rico.LiveGrid.prototype = {
-
-   initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) {
-
-     this.options = {
-                tableClass:           $(tableId).className,
-                loadingClass:         $(tableId).className,
-                scrollerBorderRight: '1px solid #ababab',
-                bufferTimeout:        20000,
-                sortAscendImg:        'images/sort_asc.gif',
-                sortDescendImg:       'images/sort_desc.gif',
-                sortImageWidth:       9,
-                sortImageHeight:      5,
-                ajaxSortURLParms:     [],
-                onRefreshComplete:    null,
-                requestParameters:    null,
-                inlineStyles:         true
-                };
-      Object.extend(this.options, options || {});
-
-      this.ajaxOptions = {parameters: null};
-      Object.extend(this.ajaxOptions, ajaxOptions || {});
-
-      this.tableId     = tableId; 
-      this.table       = $(tableId);
-
-      this.addLiveGridHtml();
-
-      var columnCount  = this.table.rows[0].cells.length;
-      this.metaData    = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
-      this.buffer      = new Rico.LiveGridBuffer(this.metaData);
-
-      var rowCount = this.table.rows.length;
-      this.viewPort =  new Rico.GridViewPort(this.table, 
-                                            this.table.offsetHeight/rowCount,
-                                            visibleRows,
-                                            this.buffer, this);
-      this.scroller    = new Rico.LiveGridScroller(this,this.viewPort);
-      this.options.sortHandler = this.sortHandler.bind(this);
-
-      if ( $(tableId + '_header') )
-         this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
-
-      this.processingRequest = null;
-      this.unprocessedRequest = null;
-
-      this.initAjax(url);
-      if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
-         var offset = 0;
-         if (this.options.offset ) {
-            offset = this.options.offset;            
-            this.scroller.moveScroll(offset);
-            this.viewPort.scrollTo(this.scroller.rowToPixel(offset));            
-         }
-         if (this.options.sortCol) {
-             this.sortCol = options.sortCol;
-             this.sortDir = options.sortDir;
-         }
-         this.requestContentRefresh(offset);
-      }
-   },
-
-   addLiveGridHtml: function() {
-     // Check to see if need to create a header table.
-     if (this.table.getElementsByTagName("thead").length > 0){
-       // Create Table this.tableId+'_header'
-       var tableHeader = this.table.cloneNode(true);
-       tableHeader.setAttribute('id', this.tableId+'_header');
-       tableHeader.setAttribute('class', this.table.className+'_header');
-
-       // Clean up and insert
-       for( var i = 0; i < tableHeader.tBodies.length; i++ ) 
-       tableHeader.removeChild(tableHeader.tBodies[i]);
-       this.table.deleteTHead();
-       this.table.parentNode.insertBefore(tableHeader,this.table);
-     }
-
-    new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
-    this.table.previousSibling.appendChild(this.table);
-    new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
-    this.table.previousSibling.appendChild(this.table);
-   },
-
-
-   resetContents: function() {
-      this.scroller.moveScroll(0);
-      this.buffer.clear();
-      this.viewPort.clearContents();
-   },
-   
-   sortHandler: function(column) {
-          if(!column) return ;
-      this.sortCol = column.name;
-      this.sortDir = column.currentSort;
-
-      this.resetContents();
-      this.requestContentRefresh(0) 
-   },
-
-   adjustRowSize: function() {
-         
-       },
-       
-   setTotalRows: function( newTotalRows ) {
-      this.resetContents();
-      this.metaData.setTotalRows(newTotalRows);
-      this.scroller.updateSize();
-   },
-
-   initAjax: function(url) {
-      ajaxEngine.registerRequest( this.tableId + '_request', url );
-      ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
-   },
-
-   invokeAjax: function() {
-   },
-
-   handleTimedOut: function() {
-      //server did not respond in 4 seconds... assume that there could have been
-      //an error or something, and allow requests to be processed again...
-      this.processingRequest = null;
-      this.processQueuedRequest();
-   },
-
-   fetchBuffer: function(offset) {
-      if ( this.buffer.isInRange(offset) &&
-         !this.buffer.isNearingLimit(offset)) {
-         return;
-         }
-      if (this.processingRequest) {
-          this.unprocessedRequest = new Rico.LiveGridRequest(offset);
-         return;
-      }
-      var bufferStartPos = this.buffer.getFetchOffset(offset);
-      this.processingRequest = new Rico.LiveGridRequest(offset);
-      this.processingRequest.bufferOffset = bufferStartPos;   
-      var fetchSize = this.buffer.getFetchSize(offset);
-      var partialLoaded = false;
-      
-      var queryString
-      if (this.options.requestParameters)
-         queryString = this._createQueryString(this.options.requestParameters, 0);
-
-        queryString = (queryString == null) ? '' : queryString+'&';
-        queryString  = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
-        if (this.sortCol)
-            queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
-
-        this.ajaxOptions.parameters = queryString;
-
-       ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
-
-       this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
-
-   },
-
-   setRequestParams: function() {
-      this.options.requestParameters = [];
-      for ( var i=0 ; i < arguments.length ; i++ )
-         this.options.requestParameters[i] = arguments[i];
-   },
-
-   requestContentRefresh: function(contentOffset) {
-      this.fetchBuffer(contentOffset);
-   },
-
-   ajaxUpdate: function(ajaxResponse) {
-      try {
-         clearTimeout( this.timeoutHandler );
-         this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
-         this.viewPort.bufferChanged();
-      }
-      catch(err) {}
-      finally {this.processingRequest = null; }
-      this.processQueuedRequest();
-   },
-
-   _createQueryString: function( theArgs, offset ) {
-      var queryString = ""
-      if (!theArgs)
-          return queryString;
-
-      for ( var i = offset ; i < theArgs.length ; i++ ) {
-          if ( i != offset )
-            queryString += "&";
-
-          var anArg = theArgs[i];
-
-          if ( anArg.name != undefined && anArg.value != undefined ) {
-            queryString += anArg.name +  "=" + escape(anArg.value);
-          }
-          else {
-             var ePos  = anArg.indexOf('=');
-             var argName  = anArg.substring( 0, ePos );
-             var argValue = anArg.substring( ePos + 1 );
-             queryString += argName + "=" + escape(argValue);
-          }
-      }
-      return queryString;
-   },
-
-   processQueuedRequest: function() {
-      if (this.unprocessedRequest != null) {
-         this.requestContentRefresh(this.unprocessedRequest.requestOffset);
-         this.unprocessedRequest = null
-      }
-   }
-};
-
-
-//-------------------- ricoLiveGridSort.js
-Rico.LiveGridSort = Class.create();
-
-Rico.LiveGridSort.prototype = {
-
-   initialize: function(headerTableId, options) {
-      this.headerTableId = headerTableId;
-      this.headerTable   = $(headerTableId);
-      this.options = options;
-      this.setOptions();
-      this.applySortBehavior();
-
-      if ( this.options.sortCol ) {
-         this.setSortUI( this.options.sortCol, this.options.sortDir );
-      }
-   },
-
-   setSortUI: function( columnName, sortDirection ) {
-      var cols = this.options.columns;
-      for ( var i = 0 ; i < cols.length ; i++ ) {
-         if ( cols[i].name == columnName ) {
-            this.setColumnSort(i, sortDirection);
-            break;
-         }
-      }
-   },
-
-   setOptions: function() {
-      // preload the images...
-      new Image().src = this.options.sortAscendImg;
-      new Image().src = this.options.sortDescendImg;
-
-      this.sort = this.options.sortHandler;
-      if ( !this.options.columns )
-         this.options.columns = this.introspectForColumnInfo();
-      else {
-         // allow client to pass { columns: [ ["a", true], ["b", false] ] }
-         // and convert to an array of Rico.TableColumn objs...
-         this.options.columns = this.convertToTableColumns(this.options.columns);
-      }
-   },
-
-   applySortBehavior: function() {
-      var headerRow   = this.headerTable.rows[0];
-      var headerCells = headerRow.cells;
-      for ( var i = 0 ; i < headerCells.length ; i++ ) {
-         this.addSortBehaviorToColumn( i, headerCells[i] );
-      }
-   },
-
-   addSortBehaviorToColumn: function( n, cell ) {
-      if ( this.options.columns[n].isSortable() ) {
-         cell.id            = this.headerTableId + '_' + n;
-         cell.style.cursor  = 'pointer';
-         cell.onclick       = this.headerCellClicked.bindAsEventListener(this);
-         cell.innerHTML     = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
-                           + '&#160;&#160;&#160;</span>';
-      }
-   },
-
-   // 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) {
-       if(isNaN(n)) return ;
-      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 = '&#160;&#160;';
-      else if ( sortDirection == Rico.TableColumn.SORT_ASC )
-         sortImageSpan.innerHTML = '&#160;&#160;<img width="'  + this.options.sortImageWidth    + '" ' +
-                                                     'height="'+ this.options.sortImageHeight   + '" ' +
-                                                     'src="'   + this.options.sortAscendImg + '"/>';
-      else if ( sortDirection == Rico.TableColumn.SORT_DESC )
-         sortImageSpan.innerHTML = '&#160;&#160;<img width="'  + this.options.sortImageWidth    + '" ' +
-                                                     'height="'+ this.options.sortImageHeight   + '" ' +
-                                                     'src="'   + this.options.sortDescendImg + '"/>';
-   },
-
-   getSortedColumnIndex: function() {
-      var cols = this.options.columns;
-      for ( var i = 0 ; i < cols.length ; i++ ) {
-         if ( cols[i].isSorted() )
-            return i;
-      }
-
-      return -1;
-   },
-
-   introspectForColumnInfo: function() {
-      var columns = new Array();
-      var headerRow   = this.headerTable.rows[0];
-      var headerCells = headerRow.cells;
-      for ( var i = 0 ; i < headerCells.length ; i++ )
-         columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
-      return columns;
-   },
-
-   convertToTableColumns: function(cols) {
-      var columns = new Array();
-      for ( var i = 0 ; i < cols.length ; i++ )
-         columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
-      return columns;
-   },
-
-   deriveColumnNameFromCell: function(cell,columnNumber) {
-      var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
-      return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
-   }
-};
-
-Rico.TableColumn = Class.create();
-
-Rico.TableColumn.UNSORTED  = 0;
-Rico.TableColumn.SORT_ASC  = "ASC";
-Rico.TableColumn.SORT_DESC = "DESC";
-
-Rico.TableColumn.prototype = {
-   initialize: function(name, sortable) {
-      this.name        = name;
-      this.sortable    = sortable;
-      this.currentSort = Rico.TableColumn.UNSORTED;
-   },
-
-   isSortable: function() {
-      return this.sortable;
-   },
-
-   isSorted: function() {
-      return this.currentSort != Rico.TableColumn.UNSORTED;
-   },
-
-   getSortDirection: function() {
-      return this.currentSort;
-   },
-
-   toggleSort: function() {
-      if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
-         this.currentSort = Rico.TableColumn.SORT_ASC;
-      else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
-         this.currentSort = Rico.TableColumn.SORT_DESC;
-   },
-
-   setUnsorted: function(direction) {
-      this.setSorted(Rico.TableColumn.UNSORTED);
-   },
-
-   setSorted: function(direction) {
-      // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
-      this.currentSort = direction;
-   }
-
-};
-
-
-//-------------------- ricoUtil.js
-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++ ) {
-         var n = parentNode.childNodes[i];
-         if (n.nodeType == 4) {
-             contentStr += n.nodeValue;
-         }
-         else {
-           contentStr += n.xml;
-       }
-     }
-     return contentStr;
-  },
-
-  _getContentAsStringMozilla: function(parentNode) {
-     var xmlSerializer = new XMLSerializer();
-     var contentStr = "";
-     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
-          var n = parentNode.childNodes[i];
-          if (n.nodeType == 4) { // CDATA node
-              contentStr += n.nodeValue;
-          }
-          else {
-            contentStr += xmlSerializer.serializeToString(n);
-        }
-     }
-     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/trunk/NP_TrackBack/trackback/js/rico/css/coffee-with-milk.css b/trunk/NP_TrackBack/trackback/js/rico/css/coffee-with-milk.css
new file mode 100644 (file)
index 0000000..6b58e87
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+Based on "Coffee with milk" table design by Roger Johansson, 456 Berea Street
+www.456bereastreet.com
+================================================*/
+
+.ricoLG_table {
+       border-top:1px solid #523A0B !important;
+       border-right:none;
+       font:normal 76%/150% "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif;
+       color:#000;
+}
+tr.ricoLG_hdg .ricoLG_cell, tr.ricoLG_hdg th, tr.ricoLG_hdg td {  /* td/th required for IE */
+       background:#EBE5D9 !important;
+       line-height:normal;
+       text-align:left;
+}
+
+tr.ricoLG_hdg th, tr.ricoLG_hdg td {
+       border-bottom:1px solid #523A0B;
+       background:#EBE5D9;
+       }
+
+tr.ricoLG_hdg th, tr.ricoLG_hdg td {
+  border-left: 1px solid #E0D8CD !important;
+}
+
+.ricoLG_bottom th, .ricoLG_bottom td {
+  border-left: 1px solid #FFF;
+}
+
+tr.ricoLG_hdg div.ricoLG_cell {
+       background:#EBE5D9;
+       font-weight:bold;
+       padding:0.5em 0 0.5em 0.5em;
+}
+div.ricoLG_outerDiv table a {
+       color:#523A0B;
+       text-decoration:none;
+       border-bottom:1px dotted;
+       }
+div.ricoLG_outerDiv tbody a:visited {
+       color:#444;
+       font-weight:normal;
+       }
+div.ricoLG_outerDiv table a:hover {
+       border-bottom-style:solid;
+       }
+
+.ricoLG_bottom div.ricoLG_oddRow {
+       background-color:#F7F4EE;
+       border-top: 1px solid #EBE5D9;
+       border-bottom: 1px solid #EBE5D9;
+}
+.ricoLG_bottom div.ricoLG_evenRow {
+       border-top: 1px solid #FFF;
+       border-bottom: 1px solid #FFF;
+}
+.ricoLG_selection {
+       background-color:#ffffee !important;
+       border-color:#523A0B !important;
+}
+.ricoLG_table {
+  border-style:none;
+}
+
+caption {
+       font-family:Georgia,Times,serif;
+       font-weight:normal;
+       font-size:1.4em;
+       text-align:left;
+       margin:0;
+       padding:0.5em 0.25em;
+       }
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/grayedout.css b/trunk/NP_TrackBack/trackback/js/rico/css/grayedout.css
new file mode 100644 (file)
index 0000000..5fc400f
--- /dev/null
@@ -0,0 +1,68 @@
+/* -------------------------------------------------------
+Based on Grayed Out table design
+Author: Terence Ordona
+URL: http://www.imaputz.com/
+ ------------------------------------------------------- */
+div.ricoLG_outerDiv *, div.ricoLG_cell {
+  font-size: 11px;
+  font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
+}
+
+.ricoLG_table {
+       border-top: 1px solid #CCC;
+       border-right: 1px solid #CCC;
+}
+
+tr.ricoLG_hdg th, tr.ricoLG_hdg td {
+       background-color: #FFF !important;
+  background: url(../images/grayedout.gif) #FFF repeat-x scroll center left;
+  border-bottom: 1px solid #CCC;
+}
+
+.ricoLG_table th, .ricoLG_table td {
+       border-left: 1px solid #CCC;
+}
+
+.ricoLG_bottom th, .ricoLG_bottom td {
+       border-bottom: 1px solid #CCC;
+}
+
+.ricoLG_bottom div.ricoLG_cell {
+  border-bottom: none;
+  padding: 5px;
+}
+
+tr.ricoLG_hdg .ricoLG_cell {
+  font-weight: normal;
+}
+
+div.ricoLG_outerDiv a:visited, div.ricoLG_outerDiv a:link {
+       color: #009;
+       text-decoration: none;
+}
+
+div.ricoLG_outerDiv a:hover {
+       color: #009;
+       text-decoration: underline;
+}
+
+.ricoLG_oddRow {
+       background-color: #EEE;
+}
+
+div.ricoLG_selection {
+       background-color: #999;
+       color: #FFF;
+}
+
+div.ricoLG_highlightDiv {
+       border-color: #999;
+}
+       
+caption {
+       text-align: left;
+       font-size: 100%;
+       padding: .75em;
+       color: #000;
+}
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/greenHdg.css b/trunk/NP_TrackBack/trackback/js/rico/css/greenHdg.css
new file mode 100644 (file)
index 0000000..28c385c
--- /dev/null
@@ -0,0 +1,8 @@
+/* display grid headings with a green background */
+
+tr.ricoLG_hdg .ricoLG_cell, tr.ricoLG_hdg th, tr.ricoLG_hdg td {  /* td/th required for IE */
+  background-color : #cedebd !important;
+  color            : #000000;
+  font-weight      : bold;
+}
+div.ricoLG_selection { background-color: #cedebd; }
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/iegradient.css b/trunk/NP_TrackBack/trackback/js/rico/css/iegradient.css
new file mode 100644 (file)
index 0000000..af5421a
--- /dev/null
@@ -0,0 +1,3 @@
+tr.ricoLG_hdg .ricoLG_cell, tr.ricoLG_hdg th, tr.ricoLG_hdg td {  /* td/th required for IE */
+  Filter: progid:DXImageTransform.Microsoft.Gradient(gradientType=0,startColorStr=white,endColorStr=Gainsboro); 
+}
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/ricoCalendar.css b/trunk/NP_TrackBack/trackback/js/rico/css/ricoCalendar.css
new file mode 100644 (file)
index 0000000..ece53a5
--- /dev/null
@@ -0,0 +1,112 @@
+/* ricoCalendar */
+
+div.ricoCalContainer, div.ricoTreeContainer {
+  position:absolute;
+  z-index:9999;
+  font-size:8pt;
+  left:0px;
+  top:0px;
+}
+
+table.ricoCalTab {
+  border:1px solid #666666;
+}
+
+table.ricoCalTab thead a {
+  border:1px solid #D4D0C8;
+  text-decoration: none;
+  color:black;
+}
+
+table.ricoCalTab thead img {
+  border:none;
+  padding-left: 0.3em;
+  padding-right: 0.3em;
+}
+
+table.ricoCalTab thead a:hover {
+  border:1px solid #666666;
+  cursor:pointer;
+}
+
+table.ricoCalTab thead td {
+  background-color: #D4D0C8;
+  font-weight: bold;
+  text-align:center;
+  padding: 2px;
+}
+
+table.ricoCalTab tfoot td {
+  color:#FFF;
+  text-align:center;
+  background-color: #666666;
+  padding: 2px;
+}
+
+table.ricoCalTab tfoot span {
+  text-decoration: underline;
+  cursor:pointer;
+}
+
+table.ricoCalTab tbody {
+  background-color: white;
+}
+
+tr.ricoCalDayNames td {
+  font-weight: bold;
+  padding: 0px 2px 0px 2px;
+  text-align:right;
+}
+
+td.ricoCal0, td.ricoCal1, td.ricoCal2, td.ricoCal3, td.ricoCal4, td.ricoCal5, td.ricoCal6, td.ricoCalToday, td.ricoCalEmpty {
+  text-decoration:none;
+  text-align:right;
+  width:3em;
+}
+
+/* Monday-Friday */
+td.ricoCal1, td.ricoCal2, td.ricoCal3, td.ricoCal4, td.ricoCal5 {
+  cursor:pointer;
+  color:black;
+}
+
+/* Sunday, Saturday */
+td.ricoCal0, td.ricoCal6 {
+  cursor:pointer;
+  color:#999;
+}
+
+td.ricoCalToday {
+  cursor:pointer;
+  color:red;
+  font-weight:bold;
+}
+
+td.ricoCalWeekNum {
+  background-color: #D4D0C8;
+  color:black;
+  text-align:center;
+}
+
+.ricoCalMenu {
+  position:absolute;
+  background-color: #FEE;
+  border-bottom:1px solid #666666;
+  border-right:1px solid #666666;
+}
+
+.ricoCalMenu td {
+  border-top:1px solid #666666;
+  border-left:1px solid #666666;
+}
+
+.ricoCalMenu a {
+  display:block;
+  text-decoration:none;
+  color:black;
+  cursor:pointer;
+}
+
+.ricoCalMenu a:hover {
+  background-color: #FCC;
+}
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/ricoGrid.css b/trunk/NP_TrackBack/trackback/js/rico/css/ricoGrid.css
new file mode 100644 (file)
index 0000000..584e8be
--- /dev/null
@@ -0,0 +1,125 @@
+div.ricoLG_outerDiv {
+  position:relative;
+  /*border:thin solid blue;  /* for debugging */
+}
+
+div.ricoLG_innerDiv, div.ricoLG_frozenTabsDiv {
+  overflow:hidden;
+  margin:0px;
+  padding:0px;
+  position:absolute;
+  top:0px;
+}
+
+div.ricoLG_scrollDiv {
+  overflow:scroll;
+  position:relative;
+}
+
+div.ricoLG_scrollTabsDiv {
+  position:absolute;
+  top:0px;
+}
+
+div.ricoLG_resizeDiv {
+  position:absolute;
+  top:0px;
+  width:1px;
+  z-index:2;
+  background-color:blue;
+}
+
+div.ricoLG_highlightDiv {
+  position:absolute;
+  border: 2px solid black;
+}
+
+.ricoLG_table {
+  margin: 0px;
+  padding: 0px;
+  border-right: 1px solid silver;
+  border-top: 1px solid silver;
+}
+
+.ricoLG_table th, .ricoLG_table td {
+  border-left: 1px solid silver;
+}
+
+table.ricoLG_bottom {
+  border-top-style: none;
+}
+
+.ricoLG_evenRow   { }
+.ricoLG_oddRow    { background-color: #EEE; }
+.ricoLG_selection { background-color: #cedebd; }
+
+div.ricoLG_col {
+  overflow:hidden;
+  width:100px;
+}
+
+.ricoLG_top div.ricoLG_col {
+  position:relative;
+}
+
+.ricoLG_top div.ricoLG_Resize {
+  position:absolute;
+  width:5px;
+  height:100%;
+  top:0px;
+  cursor:e-resize;
+}
+
+.ricoLG_HdrIcon {
+  padding-left:2px;
+  padding-right:2px;
+}
+
+.ricoLG_bottom div.ricoLG_cell, .ricoLG_top th, .ricoLG_top td {
+  border-bottom: 1px solid silver;
+}
+
+div.ricoLG_cell {
+  overflow:hidden;
+  height:1.2em;
+  padding-left: 3px;
+  margin: 0px;
+  font-size: 10pt;
+       padding-top:3px;
+       padding-bottom:3px;
+}
+
+div.ricoLG_messageDiv {
+  position:absolute;
+  z-index:200;
+  border:1px solid green;
+  background-color:white;
+  font-weight:bold;
+  font-size:larger;
+  color:navy;
+  text-align:center;
+  padding:4px;
+}
+
+p.ricoBookmark {
+  margin-bottom: 3px;
+  font-size: 10pt;
+}
+
+div.alignleft {
+  text-align: left;
+}
+
+div.aligncenter {
+  text-align: center;
+}
+
+div.alignright {
+  text-align: right;
+}
+
+span.ricoSessionTimer {
+  background-color:black;
+  color:white;
+}
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/ricoLiveGridForms.css b/trunk/NP_TrackBack/trackback/js/rico/css/ricoLiveGridForms.css
new file mode 100644 (file)
index 0000000..c7f0170
--- /dev/null
@@ -0,0 +1,81 @@
+/* ricoLiveGridForms */
+
+span.ricoSaveMsg {
+  background-color:yellow;
+}
+
+span.ricoSessionTimer {
+  background-color:black;
+  color:white;
+}
+
+div.ricoLG_editDiv, div.ricoLG_editResponseDiv {
+  color:#000; background:#E8ECF3;
+  overflow:auto;
+  padding:8px;
+  border: 1px solid navy;
+  position:absolute;
+  font-size: 10pt;
+  z-index:300;
+  top:0px;
+  left:0px;
+}
+
+form .ricoEditLabel, form .ricoEditLabelWithHelp {
+  font-weight: bold;
+  text-align: left;
+  padding-right: 1em;
+}
+
+form .ricoEditLabelWithHelp {
+  color: navy;
+}
+
+form {
+  margin:0px;
+}
+
+.tabHeader {
+  height: 1.8em;
+       color : #AAA;
+       background: #D8E0F2;
+       font-weight : bold;
+  float: left;
+  display: inline;
+  margin-left: 2px;
+  margin-right: 2px;
+  text-align: center;
+  white-space:nowrap;
+  overflow:hidden;
+}
+
+.tabHover {
+       color : #666;
+  cursor: pointer;
+}
+
+.tabSelected {
+       color : #444;
+       background: #CFD4E6;
+  cursor: auto;
+}
+
+.tabContentContainer {
+  clear:both;
+}
+
+div.ricoLG_editDiv .tabContent, div.ricoLG_editDiv .noTabContent {
+  color:#000; background:#CFD4E6;
+  overflow: hidden;
+  padding: 4px;
+  white-space:nowrap;
+}
+
+div.ricoLG_editDiv .noTabContent {
+  float:left;  /* required by IE7 */
+}
+
+span.ricoLookup {
+  display:none;
+}
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/ricoMenu.css b/trunk/NP_TrackBack/trackback/js/rico/css/ricoMenu.css
new file mode 100644 (file)
index 0000000..4e00895
--- /dev/null
@@ -0,0 +1,95 @@
+/* ricoMenu */
+
+div.ricoMenu, div.ricoMenuSafari {
+position: absolute;
+z-index: 100;
+border:1px solid #666;
+padding:2px;
+cursor:default;
+visibility: hidden;
+}
+
+div.ricoMenu, div.ricoMenu div.ricoMenuHeading, div.ricoMenu a {
+background-color:menu;
+color: menutext;
+text-decoration: none;
+font-family:tahoma,arial,helvetica,sans-serif;
+font-size: 8pt;
+display:block;
+}
+
+div.ricoMenuSafari, div.ricoMenuSafari div.ricoMenuHeading, div.ricoMenuSafari a {
+background-color:#EDEDED;
+text-decoration: none;
+font-family:tahoma,arial,helvetica,sans-serif;
+font-size: 8pt;
+display:block;
+}
+
+div.ricoMenu div.ricoMenuHeading{
+padding: 1px 0px;
+font-weight:bold;
+}
+
+div.ricoMenuSafari div.ricoMenuHeading{
+padding: 1px 0px;
+color: black;
+display: block;
+font-weight:bold;
+}
+
+div.ricoMenu .enabled {
+position: relative;
+}
+
+div.ricoMenuSafari .enabled {
+color: black;
+}
+
+div.ricoMenu .enabled, div.ricoMenu .enabled-hover, div.ricoMenuSafari .enabled, div.ricoMenuSafari .enabled-hover, div.ricoMenu .disabled, div.ricoMenuSafari .disabled {
+padding-left: 1em;
+padding-top:0.1em;
+padding-bottom:0.1em;
+z-index: 101;
+}
+
+div.ricoMenu .disabled, div.ricoMenuSafari .disabled {
+color: #999;
+}
+
+div.ricoMenu hr{
+height:1px;
+margin:1px;
+border:0;
+color: menu;
+background-color: menu;
+}
+
+div.ricoMenu .enabled-hover, div.ricoMenu .ricoSubMenuOpen {
+   background-color: Highlight;
+   color:            HighlightText;
+}
+
+div.ricoMenuSafari .enabled-hover, div.ricoMenuSafari .ricoSubMenuOpen {
+   background-color: #1657B8;
+   color:            white;
+}
+
+div.ricoMenu .ricoSubMenu, div.ricoMenu .ricoSubMenuOpen, div.ricoMenuSafari .ricoSubMenu, div.ricoMenuSafari .ricoSubMenuOpen {
+padding: 1px 0px;
+display: block;
+font-weight:bold;
+z-index: 101;
+position: relative;
+}
+
+div.ricoMenu div.ricoMenuBreak, div.ricoMenuSafari div.ricoMenuBreak {
+height:1px;
+margin:3px 0 3px 0;
+padding:0;
+background-color: #AAA;
+width:100%;
+line-height:5px;
+overflow:hidden;
+}
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/ricoTree.css b/trunk/NP_TrackBack/trackback/js/rico/css/ricoTree.css
new file mode 100644 (file)
index 0000000..36b7d17
--- /dev/null
@@ -0,0 +1,42 @@
+/* ricoTree */
+
+div.ricoTreeContainer {
+  background-color:#cedebd;
+  padding:4px;
+  border:1px solid black;
+  top:0px;
+  left:0px;
+  position:absolute;
+  z-index:9999;
+}
+
+div.ricoTree {
+  border:thin inset;
+  overflow:auto;
+  background-color:#FFF;
+}
+
+div.ricoTree p, div.ricoTree a {
+  margin:0px;
+  padding-left:0.3em;
+  white-space:nowrap;
+}
+
+div.ricoTree a {
+  cursor:pointer;
+  text-decoration:none;
+}
+
+div.ricoTree a:hover {
+  background-color:#EEE;
+}
+
+div.ricoTree img {
+  margin:0px;
+  padding:0px;
+  display:block;
+}
+
+div.ricoTree * {
+  font-size:8pt;
+}
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/tanChisel.css b/trunk/NP_TrackBack/trackback/js/rico/css/tanChisel.css
new file mode 100644 (file)
index 0000000..613a17c
--- /dev/null
@@ -0,0 +1,36 @@
+tr.ricoLG_hdg .ricoLG_cell, tr.ricoLG_hdg th, tr.ricoLG_hdg td {  /* td/th required for IE */
+  background-color:#e0e0c0 !important;
+       vertical-align:middle;
+}
+
+tr.ricoLG_hdg div.ricoLG_cell {
+       border-top: 1px solid #F0F0E8;
+}
+
+.ricoLG_bottom div.ricoLG_cell, .ricoLG_top th, .ricoLG_top td {
+       border-bottom: 1px solid #D8d0c0;;
+}
+
+.ricoLG_table th, .ricoLG_table td {
+       border-left: 1px solid #F0F0E8;
+       border-right: 1px solid #D8d0c0;
+}
+
+div.ricoMenu, div.ricoMenu div.ricoMenuHeading, div.ricoMenu .ricoSubMenu, div.ricoMenuSafari, div.ricoMenuSafari div.ricoMenuHeading, div.ricoMenuSafari .ricoSubMenu {
+  background-color:#f0f0e0;
+}
+
+div.ricoMenu, div.ricoMenu div.ricoMenuHeading, div.ricoMenu .ricoSubMenu, div.ricoMenu .ricoSubMenuOpen, div.ricoMenuSafari, div.ricoMenuSafari div.ricoMenuHeading, div.ricoMenuSafari .ricoSubMenu, div.ricoMenuSafari .ricoSubMenuOpen {
+       border-top: 1px solid #F0F0E8;
+       border-left: 1px solid #F0F0E8;
+       border-bottom: 1px solid #D8d0c0;;
+       border-right: 1px solid #D8d0c0;
+}
+
+.ricoLG_table {
+  border-style:none;
+}
+
+div.ricoLG_selection {
+  background-color:#e0e0c0;
+}
diff --git a/trunk/NP_TrackBack/trackback/js/rico/css/warmfall.css b/trunk/NP_TrackBack/trackback/js/rico/css/warmfall.css
new file mode 100644 (file)
index 0000000..82ac9f7
--- /dev/null
@@ -0,0 +1,63 @@
+/* -------------------------------------------------------
+Based on warm fall table design
+Author: Mya Leigh
+Theme: A Warm, Fall Table - Easy to Read
+URL: http://www.myaleigh.com 
+ ------------------------------------------------------- */
+.ricoLG_table {
+       border-top: 1px solid #84785e;
+       border-right: 1px solid #84785e;
+}
+
+tr.ricoLG_hdg .ricoLG_cell, tr.ricoLG_hdg th, tr.ricoLG_hdg td {  /* td/th required for IE */
+       background-color: #a24116 !important;
+  color: #ffffff !important;  
+}
+
+.ricoLG_table th, .ricoLG_table td {
+       border-left: 1px solid #84785e;
+}
+
+.ricoLG_bottom div.ricoLG_cell, .ricoLG_top th, .ricoLG_top td {
+  border-bottom: 1px solid #84785e;
+}
+
+tr.ricoLG_hdg .ricoLG_cell {
+       background-color: #a24116;
+  border: 0;
+  color: #ffffff;  
+       padding: .75em;
+  font: "Verdana", Arial, Helvetica, sans-serif;
+  font-weight: bold;
+}
+
+div.ricoLG_outerDiv a:visited, div.ricoLG_outerDiv a:link, div.ricoLG_outerDiv a:active {
+       color: #101011;
+       text-decoration: none;
+}
+
+div.ricoLG_outerDiv a:hover {
+       text-decoration: underline;
+}
+
+div.ricoLG_outerDiv tbody a:visited {
+       color:#444;
+}
+
+.ricoLG_oddRow {
+       background-color: #fffce1;
+       color: #101011;
+}
+
+.ricoLG_selection {
+       background-color: #a24116;
+       color: #ffffff;
+}
+       
+caption {
+       text-align: left;
+       font-size: 100%;
+       padding: .75em;
+       color: #000;
+}
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/export-owc.html b/trunk/NP_TrackBack/trackback/js/rico/export-owc.html
new file mode 100644 (file)
index 0000000..1be9994
--- /dev/null
@@ -0,0 +1,34 @@
+<html>
+<head>
+<title>Export</title>
+<SCRIPT TYPE="text/javascript">
+function getdata() {
+  if (!window.opener || window.opener.closed) {
+    alert('Error! Parent window is closed');
+    return;
+  }
+  var divID=window.location.search;
+  if (divID.length<2) {
+    alert('Error! Invalid id');
+    return;
+  }
+  divID=divID.substring(1);
+  var oDiv=window.opener.document.getElementById(divID);
+  if (!oDiv) {
+    alert('Error! Can not find \"'+divID+'\"');
+    return;
+  }
+  var oSS=document.getElementById('ss')
+  if (!oSS) {
+    alert('Error! Can not find spreadsheet');
+    return;
+  }
+  oSS.HTMLData=oDiv.innerHTML;
+}
+window.onload=getdata;
+</SCRIPT>
+</head>
+<body>
+<object id="ss" classid="CLSID:0002E559-0000-0000-C000-000000000046" style="width:100%;height:100%"></object>
+</body>
+</html>
diff --git a/trunk/NP_TrackBack/trackback/js/rico/export-plain.html b/trunk/NP_TrackBack/trackback/js/rico/export-plain.html
new file mode 100644 (file)
index 0000000..9b983ea
--- /dev/null
@@ -0,0 +1,28 @@
+<html>
+<head>
+<title>Export</title>
+<SCRIPT TYPE="text/javascript">
+function getdata() {
+  if (!window.opener || window.opener.closed) {
+    alert('Error! Parent window is closed');
+    return;
+  }
+  var divID=window.location.search;
+  if (divID.length<2) {
+    alert('Error! Invalid id');
+    return;
+  }
+  divID=divID.substring(1);
+  var oDiv=window.opener.document.getElementById(divID);
+  if (!oDiv) {
+    alert('Error! Can not find \"'+divID+'\"');
+    return;
+  }
+  document.body.innerHTML=oDiv.innerHTML;
+}
+window.onload=getdata;
+</SCRIPT>
+</head>
+<body>
+</body>
+</html>
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/aline.gif b/trunk/NP_TrackBack/trackback/js/rico/images/aline.gif
new file mode 100644 (file)
index 0000000..7f5cb43
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/aline.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/calarrow.png b/trunk/NP_TrackBack/trackback/js/rico/images/calarrow.png
new file mode 100644 (file)
index 0000000..acdcfed
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/calarrow.png differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/calendaricon.gif b/trunk/NP_TrackBack/trackback/js/rico/images/calendaricon.gif
new file mode 100644 (file)
index 0000000..abdf6ac
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/calendaricon.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/close.gif b/trunk/NP_TrackBack/trackback/js/rico/images/close.gif
new file mode 100644 (file)
index 0000000..65c5f16
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/close.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/divider.gif b/trunk/NP_TrackBack/trackback/js/rico/images/divider.gif
new file mode 100644 (file)
index 0000000..d9863d4
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/divider.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/doc.gif b/trunk/NP_TrackBack/trackback/js/rico/images/doc.gif
new file mode 100644 (file)
index 0000000..231036d
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/doc.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/dotbutton.gif b/trunk/NP_TrackBack/trackback/js/rico/images/dotbutton.gif
new file mode 100644 (file)
index 0000000..20c85cc
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/dotbutton.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/drop.gif b/trunk/NP_TrackBack/trackback/js/rico/images/drop.gif
new file mode 100644 (file)
index 0000000..afce892
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/drop.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/filtercol.gif b/trunk/NP_TrackBack/trackback/js/rico/images/filtercol.gif
new file mode 100644 (file)
index 0000000..2e93828
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/filtercol.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/folderclosed.gif b/trunk/NP_TrackBack/trackback/js/rico/images/folderclosed.gif
new file mode 100644 (file)
index 0000000..7c61d6f
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/folderclosed.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/folderopen.gif b/trunk/NP_TrackBack/trackback/js/rico/images/folderopen.gif
new file mode 100644 (file)
index 0000000..c16e11b
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/folderopen.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/grayedout.gif b/trunk/NP_TrackBack/trackback/js/rico/images/grayedout.gif
new file mode 100644 (file)
index 0000000..ead27af
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/grayedout.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/left.gif b/trunk/NP_TrackBack/trackback/js/rico/images/left.gif
new file mode 100644 (file)
index 0000000..f652075
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/left.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/link.gif b/trunk/NP_TrackBack/trackback/js/rico/images/link.gif
new file mode 100644 (file)
index 0000000..a679f4d
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/link.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/node.gif b/trunk/NP_TrackBack/trackback/js/rico/images/node.gif
new file mode 100644 (file)
index 0000000..d2dfe4b
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/node.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodeblank.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodeblank.gif
new file mode 100644 (file)
index 0000000..4f1f916
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodeblank.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodelast.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodelast.gif
new file mode 100644 (file)
index 0000000..3fe0a7e
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodelast.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodeline.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodeline.gif
new file mode 100644 (file)
index 0000000..5767a1f
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodeline.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodem.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodem.gif
new file mode 100644 (file)
index 0000000..fcc2d37
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodem.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodemlast.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodemlast.gif
new file mode 100644 (file)
index 0000000..11ae43a
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodemlast.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodep.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodep.gif
new file mode 100644 (file)
index 0000000..5b68013
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodep.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/nodeplast.gif b/trunk/NP_TrackBack/trackback/js/rico/images/nodeplast.gif
new file mode 100644 (file)
index 0000000..b87f003
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/nodeplast.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/resize.gif b/trunk/NP_TrackBack/trackback/js/rico/images/resize.gif
new file mode 100644 (file)
index 0000000..8efd1b5
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/resize.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/ricologo.gif b/trunk/NP_TrackBack/trackback/js/rico/images/ricologo.gif
new file mode 100644 (file)
index 0000000..9b14203
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/ricologo.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/right.gif b/trunk/NP_TrackBack/trackback/js/rico/images/right.gif
new file mode 100644 (file)
index 0000000..5517f2b
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/right.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/shadow.png b/trunk/NP_TrackBack/trackback/js/rico/images/shadow.png
new file mode 100644 (file)
index 0000000..7862c9b
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/shadow.png differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ll.png b/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ll.png
new file mode 100644 (file)
index 0000000..cc0665b
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ll.png differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ur.png b/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ur.png
new file mode 100644 (file)
index 0000000..cad0f2c
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/shadow_ur.png differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/sort_asc.gif b/trunk/NP_TrackBack/trackback/js/rico/images/sort_asc.gif
new file mode 100644 (file)
index 0000000..6330232
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/sort_asc.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/images/sort_desc.gif b/trunk/NP_TrackBack/trackback/js/rico/images/sort_desc.gif
new file mode 100644 (file)
index 0000000..b3a681c
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/js/rico/images/sort_desc.gif differ
diff --git a/trunk/NP_TrackBack/trackback/js/rico/prototype.js b/trunk/NP_TrackBack/trackback/js/rico/prototype.js
new file mode 100644 (file)
index 0000000..5906575
--- /dev/null
@@ -0,0 +1,3269 @@
+/*  Prototype JavaScript framework, version 1.5.1_rc3
+ *  (c) 2005-2007 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.5.1_rc3',
+
+  Browser: {
+    IE:     !!(window.attachEvent && !window.opera),
+    Opera:  !!window.opera,
+    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
+  },
+
+  BrowserFeatures: {
+    XPath: !!document.evaluate,
+    ElementExtensions: !!window.HTMLElement,
+    SpecificElementExtensions:
+      (document.createElement('div').__proto__ !==
+       document.createElement('form').__proto__)
+  },
+
+  ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
+  JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
+
+  emptyFunction: function() { },
+  K: function(x) { return x }
+}
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+  for (var property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+}
+
+Object.extend(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;
+    }
+  },
+
+  toJSON: function(object) {
+    var type = typeof object;
+    switch(type) {
+      case 'undefined':
+      case 'function':
+      case 'unknown': return;
+      case 'boolean': return object.toString();
+    }
+    if (object === null) return 'null';
+    if (object.toJSON) return object.toJSON();
+    if (object.ownerDocument === document) return;
+    var results = [];
+    for (var property in object) {
+      var value = Object.toJSON(object[property]);
+      if (value !== undefined)
+        results.push(property.toJSON() + ': ' + value);
+    }
+    return '{' + results.join(', ') + '}';
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({}, object);
+  }
+});
+
+Function.prototype.bind = function() {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function() {
+    return __method.apply(object, args.concat($A(arguments)));
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function(event) {
+    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+  }
+}
+
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    return this.toPaddedString(2, 16);
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  },
+
+  toPaddedString: function(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  },
+
+  toJSON: function() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
+});
+
+Date.prototype.toJSON = function() {
+  return '"' + this.getFullYear() + '-' +
+    (this.getMonth() + 1).toPaddedString(2) + '-' +
+    this.getDate().toPaddedString(2) + 'T' +
+    this.getHours().toPaddedString(2) + ':' +
+    this.getMinutes().toPaddedString(2) + ':' +
+    this.getSeconds().toPaddedString(2) + '"';
+};
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.callback(this);
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+}
+Object.extend(String, {
+  interpret: function(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = count === undefined ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return this;
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = truncation === undefined ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : this;
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  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(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var self = arguments.callee;
+    self.text.data = this;
+    return self.div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = document.createElement('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return {};
+
+    return match[1].split(separator || '&').inject({}, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift());
+        var value = pair.length > 1 ? pair.join('=') : pair[0];
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (hash[key].constructor != Array) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  times: function(count) {
+    var result = '';
+    for (var i = 0; i < count; i++) result += this;
+    return result;
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function() {
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+      var character = String.specialChar[match[0]];
+      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  },
+
+  toJSON: function() {
+    return this.inspect(true);
+  },
+
+  unfilterJSON: function(filter) {
+    return this.sub(filter || Prototype.JSONFilter, '#{1}');
+  },
+
+  evalJSON: function(sanitize) {
+    var json = this.unfilterJSON();
+    try {
+      if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
+        return eval('(' + json + ')');
+    } catch (e) { }
+    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+  },
+
+  include: function(pattern) {
+    return this.indexOf(pattern) > -1;
+  },
+
+  startsWith: function(pattern) {
+    return this.indexOf(pattern) === 0;
+  },
+
+  endsWith: function(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.lastIndexOf(pattern) === d;
+  },
+
+  empty: function() {
+    return this == '';
+  },
+
+  blank: function() {
+    return /^\s*$/.test(this);
+  }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+  escapeHTML: function() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  },
+  unescapeHTML: function() {
+    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (typeof replacement == 'function') return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+Object.extend(String.prototype.escapeHTML, {
+  div:  document.createElement('div'),
+  text: document.createTextNode('')
+});
+
+with (String.prototype.escapeHTML) div.appendChild(text);
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern  = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    return this.template.gsub(this.pattern, function(match) {
+      var before = match[1];
+      if (before == '\\') return match[2];
+      return before + String.interpret(object[match[3]]);
+    });
+  }
+}
+
+var $break    = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+  each: function(iterator) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        iterator(value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator) {
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.map(iterator);
+  },
+
+  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 = false;
+    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 || Prototype.K)(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;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = fillWith === undefined ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  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.map(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 (result == undefined || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value < result)
+        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.map(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.map();
+  },
+
+  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) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+}
+
+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, length = iterable.length; i < length; i++)
+      results.push(iterable[i]);
+    return results;
+  }
+}
+
+if (Prototype.Browser.WebKit) {
+  $A = Array.from = function(iterable) {
+    if (!iterable) return [];
+    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
+      iterable.toArray) {
+      return iterable.toArray();
+    } else {
+      var results = [];
+      for (var i = 0, length = iterable.length; i < length; i++)
+        results.push(iterable[i]);
+      return results;
+    }
+  }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+  Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < 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 != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(value && 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, length = this.length; i < length; i++)
+      if (this[i] == object) return i;
+    return -1;
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  },
+
+  toJSON: function() {
+    var results = [];
+    this.each(function(object) {
+      var value = Object.toJSON(object);
+      if (value !== undefined) results.push(value);
+    });
+    return '[' + results.join(', ') + ']';
+  }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+  Array.prototype.concat = function() {
+    var array = [];
+    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      if (arguments[i].constructor == Array) {
+        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  }
+}
+var Hash = function(object) {
+  if (object instanceof Hash) this.merge(object);
+  else Object.extend(this, object || {});
+};
+
+Object.extend(Hash, {
+  toQueryString: function(obj) {
+    var parts = [];
+    parts.add = arguments.callee.addPair;
+
+    this.prototype._each.call(obj, function(pair) {
+      if (!pair.key) return;
+      var value = pair.value;
+
+      if (value && typeof value == 'object') {
+        if (value.constructor == Array) value.each(function(value) {
+          parts.add(pair.key, value);
+        });
+        return;
+      }
+      parts.add(pair.key, value);
+    });
+
+    return parts.join('&');
+  },
+
+  toJSON: function(object) {
+    var results = [];
+    this.prototype._each.call(object, function(pair) {
+      var value = Object.toJSON(pair.value);
+      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
+    });
+    return '{' + results.join(', ') + '}';
+  }
+});
+
+Hash.toQueryString.addPair = function(key, value, prefix) {
+  key = encodeURIComponent(key);
+  if (value === undefined) this.push(key);
+  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
+}
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+  _each: function(iterator) {
+    for (var key in this) {
+      var value = this[key];
+      if (value && value == Hash.prototype[key]) 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(this, function(mergedHash, pair) {
+      mergedHash[pair.key] = pair.value;
+      return mergedHash;
+    });
+  },
+
+  remove: function() {
+    var result;
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      var value = this[arguments[i]];
+      if (value !== undefined){
+        if (result === undefined) result = value;
+        else {
+          if (result.constructor != Array) result = [result];
+          result.push(value)
+        }
+      }
+      delete this[arguments[i]];
+    }
+    return result;
+  },
+
+  toQueryString: function() {
+    return Hash.toQueryString(this);
+  },
+
+  inspect: function() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  },
+
+  toJSON: function() {
+    return Hash.toJSON(this);
+  }
+});
+
+function $H(object) {
+  if (object instanceof Hash) return object;
+  return new Hash(object);
+};
+
+// Safari iterates over shadowed properties
+if (function() {
+  var i = 0, Test = function(value) { this.key = value };
+  Test.prototype.key = 'foo';
+  for (var property in new Test('bar')) i++;
+  return i > 1;
+}()) Hash.prototype._each = function(iterator) {
+  var cache = [];
+  for (var key in this) {
+    var value = this[key];
+    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
+    cache.push(key);
+    var pair = [key, value];
+    pair.key = key;
+    pair.value = value;
+    iterator(pair);
+  }
+};
+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;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  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(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+}
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (typeof responder[callback] == 'function') {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) {}
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate: function() {
+    Ajax.activeRequestCount++;
+  },
+  onComplete: function() {
+    Ajax.activeRequestCount--;
+  }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   ''
+    }
+    Object.extend(this.options, options || {});
+
+    this.options.method = this.options.method.toLowerCase();
+    if (typeof this.options.parameters == 'string')
+      this.options.parameters = this.options.parameters.toQueryParams();
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+  _complete: false,
+
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.clone(this.options.parameters);
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    this.parameters = params;
+
+    if (params = Hash.toQueryString(params)) {
+      // when GET, append parameters to URL
+      if (this.method == 'get')
+        this.url += (this.url.include('?') ? '&' : '?') + params;
+      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+        params += '&_=';
+    }
+
+    try {
+      if (this.options.onCreate) this.options.onCreate(this.transport);
+      Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous)
+        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+      this.transport.send(this.body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (typeof extras.push == 'function')
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    return !this.transport.status
+        || (this.transport.status >= 200 && this.transport.status < 300);
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState];
+    var transport = this.transport, json = this.evalJSON();
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + this.transport.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(transport, json);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = this.getHeader('Content-type');
+      if (contentType && contentType.strip().
+        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+          this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+      Ajax.Responders.dispatch('on' + state, this, transport, json);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) { return null }
+  },
+
+  evalJSON: function() {
+    try {
+      var json = this.getHeader('X-JSON');
+      return json ? json.evalJSON() : null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+  initialize: function(container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    }
+
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;
+    this.options.onComplete = (function(transport, param) {
+      this.updateContent();
+      onComplete(transport, param);
+    }).bind(this);
+
+    this.request(url);
+  },
+
+  updateContent: function() {
+    var receiver = this.container[this.success() ? 'success' : 'failure'];
+    var response = this.transport.responseText;
+
+    if (!this.options.evalScripts) response = response.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (this.options.insertion)
+        new this.options.insertion(receiver, response);
+      else
+        receiver.update(response);
+    }
+
+    if (this.success()) {
+      if (this.onComplete)
+        setTimeout(this.onComplete.bind(this), 10);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+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 = (this.options.decay || 1);
+
+    this.updater = {};
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(request) {
+    if (this.options.decay) {
+      this.decay = (request.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = request.responseText;
+    }
+    this.timer = setTimeout(this.onTimerEvent.bind(this),
+      this.decay * this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (typeof element == 'string')
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(query.snapshotItem(i));
+    return results;
+  };
+
+  document.getElementsByClassName = function(className, parentElement) {
+    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+    return document._getElementsByXPath(q, parentElement);
+  }
+
+} else document.getElementsByClassName = function(className, parentElement) {
+  var children = ($(parentElement) || document.body).getElementsByTagName('*');
+  var elements = [], child;
+  for (var i = 0, length = children.length; i < length; i++) {
+    child = children[i];
+    if (Element.hasClassName(child, className))
+      elements.push(Element.extend(child));
+  }
+  return elements;
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element) var Element = {};
+
+Element.extend = function(element) {
+  var F = Prototype.BrowserFeatures;
+  if (!element || !element.tagName || element.nodeType == 3 ||
+   element._extended || F.SpecificElementExtensions || element == window)
+    return element;
+
+  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
+   T = Element.Methods.ByTag;
+
+  // extend methods for all tags (Safari doesn't need this)
+  if (!F.ElementExtensions) {
+    Object.extend(methods, Element.Methods),
+    Object.extend(methods, Element.Methods.Simulated);
+  }
+
+  // extend methods for specific tags
+  if (T[tagName]) Object.extend(methods, T[tagName]);
+
+  for (var property in methods) {
+    var value = methods[property];
+    if (typeof value == 'function' && !(property in element))
+      element[property] = cache.findOrStore(value);
+  }
+
+  element._extended = Prototype.emptyFunction;
+  return element;
+};
+
+Element.extend.cache = {
+  findOrStore: function(value) {
+    return this[value] = this[value] || function() {
+      return value.apply(null, [this].concat($A(arguments)));
+    }
+  }
+};
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, html) {
+    html = typeof html == 'undefined' ? '' : html.toString();
+    $(element).innerHTML = html.stripScripts();
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  replace: function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    if (element.outerHTML) {
+      element.outerHTML = html.stripScripts();
+    } else {
+      var range = element.ownerDocument.createRange();
+      range.selectNodeContents(element);
+      element.parentNode.replaceChild(
+        range.createContextualFragment(html.stripScripts()), element);
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $A($(element).getElementsByTagName('*')).each(Element.extend);
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (typeof selector == 'string')
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = element.ancestors();
+    return expression ? Selector.findElement(ancestors, expression, index) :
+      ancestors[index || 0];
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return element.firstDescendant();
+    var descendants = element.descendants();
+    return expression ? Selector.findElement(descendants, expression, index) :
+      descendants[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+    var previousSiblings = element.previousSiblings();
+    return expression ? Selector.findElement(previousSiblings, expression, index) :
+      previousSiblings[index || 0];
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+    var nextSiblings = element.nextSiblings();
+    return expression ? Selector.findElement(nextSiblings, expression, index) :
+      nextSiblings[index || 0];
+  },
+
+  getElementsBySelector: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  getElementsByClassName: function(element, className) {
+    return document.getElementsByClassName(className, element);
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      if (!element.attributes) return null;
+      var t = Element._attributeTranslations;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name])  name = t.names[name];
+      var attribute = element.attributes[name];
+      return attribute ? attribute.nodeValue : null;
+    }
+    return element.getAttribute(name);
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    if (elementClassName.length == 0) return false;
+    if (elementClassName == className ||
+        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+      return true;
+    return false;
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).add(className);
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).remove(className);
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+    return element;
+  },
+
+  observe: function() {
+    Event.observe.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  stopObserving: function() {
+    Event.stopObserving.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = Position.cumulativeOffset(element);
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles, camelized) {
+    element = $(element);
+    var elementStyle = element.style;
+
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property])
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
+          (camelized ? property : property.camelize())] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      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;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    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;
+      }
+    }
+    return element;
+  },
+
+  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 = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = element.style.overflow || 'auto';
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  }
+};
+
+Object.extend(Element.Methods, {
+  childOf: Element.Methods.descendantOf,
+  childElements: Element.Methods.immediateDescendants
+});
+
+if (Prototype.Browser.Opera) {
+  Element.Methods._getStyle = Element.Methods.getStyle;
+  Element.Methods.getStyle = function(element, style) {
+    switch(style) {
+      case 'left':
+      case 'top':
+      case 'right':
+      case 'bottom':
+        if (Element._getStyle(element, 'position') == 'static') return null;
+      default: return Element._getStyle(element, style);
+    }
+  };
+}
+else if (Prototype.Browser.IE) {
+  Element.Methods.getStyle = function(element, style) {
+    element = $(element);
+    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value && element.currentStyle) value = element.currentStyle[style];
+
+    if (style == 'opacity') {
+      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if (value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+
+    if (value == 'auto') {
+      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+        return element['offset'+style.capitalize()] + 'px';
+      return null;
+    }
+    return value;
+  };
+
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    var filter = element.getStyle('filter'), style = element.style;
+    if (value == 1 || value === '') {
+      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
+      return element;
+    } else if (value < 0.00001) value = 0;
+    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
+      'alpha(opacity=' + (value * 100) + ')';
+    return element;
+  };
+
+  // IE is missing .innerHTML support for TABLE-related elements
+  Element.Methods.update = function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    var tagName = element.tagName.toUpperCase();
+    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+      var div = document.createElement('div');
+      switch (tagName) {
+        case 'THEAD':
+        case 'TBODY':
+          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
+          depth = 2;
+          break;
+        case 'TR':
+          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
+          depth = 3;
+          break;
+        case 'TD':
+          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
+          depth = 4;
+      }
+      $A(element.childNodes).each(function(node) { element.removeChild(node) });
+      depth.times(function() { div = div.firstChild });
+      $A(div.childNodes).each(function(node) { element.appendChild(node) });
+    } else {
+      element.innerHTML = html.stripScripts();
+    }
+    setTimeout(function() { html.evalScripts() }, 10);
+    return element;
+  }
+}
+else if (Prototype.Browser.Gecko) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1) ? 0.999999 :
+      (value === '') ? '' : (value < 0.00001) ? 0 : value;
+    return element;
+  };
+}
+
+Element._attributeTranslations = {
+  names: {
+    colspan:   "colSpan",
+    rowspan:   "rowSpan",
+    valign:    "vAlign",
+    datetime:  "dateTime",
+    accesskey: "accessKey",
+    tabindex:  "tabIndex",
+    enctype:   "encType",
+    maxlength: "maxLength",
+    readonly:  "readOnly",
+    longdesc:  "longDesc"
+  },
+  values: {
+    _getAttr: function(element, attribute) {
+      return element.getAttribute(attribute, 2);
+    },
+    _flag: function(element, attribute) {
+      return $(element).hasAttribute(attribute) ? attribute : null;
+    },
+    style: function(element) {
+      return element.style.cssText.toLowerCase();
+    },
+    title: function(element) {
+      var node = element.getAttributeNode('title');
+      return node.specified ? node.nodeValue : null;
+    }
+  }
+};
+
+(function() {
+  Object.extend(this, {
+    href: this._getAttr,
+    src:  this._getAttr,
+    disabled: this._flag,
+    checked:  this._flag,
+    readonly: this._flag,
+    multiple: this._flag
+  });
+}).call(Element._attributeTranslations.values);
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    var t = Element._attributeTranslations, node;
+    attribute = t.names[attribute] || attribute;
+    node = $(element).getAttributeNode(attribute);
+    return node && node.specified;
+  }
+};
+
+Element.Methods.ByTag = {};
+
+Object.extend(Element, Element.Methods);
+
+if (!Prototype.BrowserFeatures.ElementExtensions &&
+ document.createElement('div').__proto__) {
+  window.HTMLElement = {};
+  window.HTMLElement.prototype = document.createElement('div').__proto__;
+  Prototype.BrowserFeatures.ElementExtensions = true;
+}
+
+Element.hasAttribute = function(element, attribute) {
+  if (element.hasAttribute) return element.hasAttribute(attribute);
+  return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+  if (arguments.length == 2) {
+    var tagName = methods;
+    methods = arguments[1];
+  }
+
+  if (!tagName) Object.extend(Element.Methods, methods || {});
+  else {
+    if (tagName.constructor == Array) tagName.each(extend);
+    else extend(tagName);
+  }
+
+  function extend(tagName) {
+    tagName = tagName.toUpperCase();
+    if (!Element.Methods.ByTag[tagName])
+      Element.Methods.ByTag[tagName] = {};
+    Object.extend(Element.Methods.ByTag[tagName], methods);
+  }
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    var cache = Element.extend.cache;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = cache.findOrStore(value);
+    }
+  }
+
+  function findDOMClass(tagName) {
+    var klass;
+    var trans = {
+      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+      "FrameSet", "IFRAME": "IFrame"
+    };
+    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName.capitalize() + 'Element';
+    if (window[klass]) return window[klass];
+
+    window[klass] = {};
+    window[klass].prototype = document.createElement(tagName).__proto__;
+    return window[klass];
+  }
+
+  if (F.ElementExtensions) {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+  }
+
+  if (F.SpecificElementExtensions) {
+    for (var tag in Element.Methods.ByTag) {
+      var klass = findDOMClass(tag);
+      if (typeof klass == "undefined") continue;
+      copy(T[tag], klass.prototype);
+    }
+  }
+
+  Object.extend(Element, Element.Methods);
+  delete Element.ByTag;
+};
+
+var Toggle = { display: Element.toggle };
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content.stripScripts();
+
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      try {
+        this.element.insertAdjacentHTML(this.adjacency, this.content);
+      } catch (e) {
+        var tagName = this.element.tagName.toUpperCase();
+        if (['TBODY', 'TR'].include(tagName)) {
+          this.insertContent(this.contentFromAnonymousTable());
+        } else {
+          throw e;
+        }
+      }
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.insertContent([this.range.createContextualFragment(this.content)]);
+    }
+
+    setTimeout(function() {content.evalScripts()}, 10);
+  },
+
+  contentFromAnonymousTable: function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+    return $A(div.childNodes[0].childNodes[0].childNodes);
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+  initializeRange: function() {
+    this.range.setStartBefore(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 = Object.extend(new Abstract.Insertion('afterBegin'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+
+  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 = Object.extend(new Abstract.Insertion('beforeEnd'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.appendChild(fragment);
+    }).bind(this));
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+
+  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($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license.  Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create();
+
+Selector.prototype = {
+  initialize: function(expression) {
+    this.expression = expression.strip();
+    this.compileMatcher();
+  },
+
+  compileMatcher: function() {
+    // Selectors with namespaced attributes can't use the XPath version
+    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
+      return this.compileXPathMatcher();
+
+    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+        c = Selector.criteria, le, p, m;
+
+    if (Selector._cache[e]) {
+      this.matcher = Selector._cache[e]; return;
+    }
+    this.matcher = ["this.matcher = function(root) {",
+                    "var r = root, h = Selector.handlers, c = false, n;"];
+
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        p = ps[i];
+        if (m = e.match(p)) {
+          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
+             new Template(c[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.matcher.push("return h.unique(n);\n}");
+    eval(this.matcher.join('\n'));
+    Selector._cache[this.expression] = this.matcher;
+  },
+
+  compileXPathMatcher: function() {
+    var e = this.expression, ps = Selector.patterns,
+        x = Selector.xpath, le,  m;
+
+    if (Selector._cache[e]) {
+      this.xpath = Selector._cache[e]; return;
+    }
+
+    this.matcher = ['.//*'];
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        if (m = e.match(ps[i])) {
+          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
+            new Template(x[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.xpath = this.matcher.join('');
+    Selector._cache[this.expression] = this.xpath;
+  },
+
+  findElements: function(root) {
+    root = root || document;
+    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
+    return this.matcher(root);
+  },
+
+  match: function(element) {
+    return this.findElements(document).include(element);
+  },
+
+  toString: function() {
+    return this.expression;
+  },
+
+  inspect: function() {
+    return "#<Selector:" + this.expression.inspect() + ">";
+  }
+};
+
+Object.extend(Selector, {
+  _cache: {},
+
+  xpath: {
+    descendant:   "//*",
+    child:        "/*",
+    adjacent:     "/following-sibling::*[1]",
+    laterSibling: '/following-sibling::*',
+    tagName:      function(m) {
+      if (m[1] == '*') return '';
+      return "[local-name()='" + m[1].toLowerCase() +
+             "' or local-name()='" + m[1].toUpperCase() + "']";
+    },
+    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+    id:           "[@id='#{1}']",
+    attrPresence: "[@#{1}]",
+    attr: function(m) {
+      m[3] = m[5] || m[6];
+      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+    },
+    pseudo: function(m) {
+      var h = Selector.xpath.pseudos[m[1]];
+      if (!h) return '';
+      if (typeof h === 'function') return h(m);
+      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+    },
+    operators: {
+      '=':  "[@#{1}='#{3}']",
+      '!=': "[@#{1}!='#{3}']",
+      '^=': "[starts-with(@#{1}, '#{3}')]",
+      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+      '*=': "[contains(@#{1}, '#{3}')]",
+      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+    },
+    pseudos: {
+      'first-child': '[not(preceding-sibling::*)]',
+      'last-child':  '[not(following-sibling::*)]',
+      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
+      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+      'checked':     "[@checked]",
+      'disabled':    "[@disabled]",
+      'enabled':     "[not(@disabled)]",
+      'not': function(m) {
+        var e = m[6], p = Selector.patterns,
+            x = Selector.xpath, le, m, v;
+
+        var exclusion = [];
+        while (e && le != e && (/\S/).test(e)) {
+          le = e;
+          for (var i in p) {
+            if (m = e.match(p[i])) {
+              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
+              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+              e = e.replace(m[0], '');
+              break;
+            }
+          }
+        }
+        return "[not(" + exclusion.join(" and ") + ")]";
+      },
+      'nth-child':      function(m) {
+        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+      },
+      'nth-last-child': function(m) {
+        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+      },
+      'nth-of-type':    function(m) {
+        return Selector.xpath.pseudos.nth("position() ", m);
+      },
+      'nth-last-of-type': function(m) {
+        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+      },
+      'first-of-type':  function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+      },
+      'last-of-type':   function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+      },
+      'only-of-type':   function(m) {
+        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+      },
+      nth: function(fragment, m) {
+        var mm, formula = m[6], predicate;
+        if (formula == 'even') formula = '2n+0';
+        if (formula == 'odd')  formula = '2n+1';
+        if (mm = formula.match(/^(\d+)$/)) // digit only
+          return '[' + fragment + "= " + mm[1] + ']';
+        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+          if (mm[1] == "-") mm[1] = -1;
+          var a = mm[1] ? Number(mm[1]) : 1;
+          var b = mm[2] ? Number(mm[2]) : 0;
+          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+          "((#{fragment} - #{b}) div #{a} >= 0)]";
+          return new Template(predicate).evaluate({
+            fragment: fragment, a: a, b: b });
+        }
+      }
+    }
+  },
+
+  criteria: {
+    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
+    className:    'n = h.className(n, r, "#{1}", c); c = false;',
+    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
+    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+    attr: function(m) {
+      m[3] = (m[5] || m[6]);
+      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+    },
+    pseudo:       function(m) {
+      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+    },
+    descendant:   'c = "descendant";',
+    child:        'c = "child";',
+    adjacent:     'c = "adjacent";',
+    laterSibling: 'c = "laterSibling";'
+  },
+
+  patterns: {
+    // combinators must be listed first
+    // (and descendant needs to be last combinator)
+    laterSibling: /^\s*~\s*/,
+    child:        /^\s*>\s*/,
+    adjacent:     /^\s*\+\s*/,
+    descendant:   /^\s/,
+
+    // selectors follow
+    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
+    id:           /^#([\w\-\*]+)(\b|$)/,
+    className:    /^\.([\w\-\*]+)(\b|$)/,
+    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s)/,
+    attrPresence: /^\[([\w]+)\]/,
+    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
+  },
+
+  handlers: {
+    // UTILITY FUNCTIONS
+    // joins two collections
+    concat: function(a, b) {
+      for (var i = 0, node; node = b[i]; i++)
+        a.push(node);
+      return a;
+    },
+
+    // marks an array of nodes for counting
+    mark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = true;
+      return nodes;
+    },
+
+    unmark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = undefined;
+      return nodes;
+    },
+
+    // mark each child node with its position (for nth calls)
+    // "ofType" flag indicates whether we're indexing for nth-of-type
+    // rather than nth-child
+    index: function(parentNode, reverse, ofType) {
+      parentNode._counted = true;
+      if (reverse) {
+        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+          node = nodes[i];
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+        }
+      } else {
+        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+      }
+    },
+
+    // filters out duplicates and extends all nodes
+    unique: function(nodes) {
+      if (nodes.length == 0) return nodes;
+      var results = [], n;
+      for (var i = 0, l = nodes.length; i < l; i++)
+        if (!(n = nodes[i])._counted) {
+          n._counted = true;
+          results.push(Element.extend(n));
+        }
+      return Selector.handlers.unmark(results);
+    },
+
+    // COMBINATOR FUNCTIONS
+    descendant: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, node.getElementsByTagName('*'));
+      return results;
+    },
+
+    child: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
+          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+      }
+      return results;
+    },
+
+    adjacent: function(nodes) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        var next = this.nextElementSibling(node);
+        if (next) results.push(next);
+      }
+      return results;
+    },
+
+    laterSibling: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, Element.nextSiblings(node));
+      return results;
+    },
+
+    nextElementSibling: function(node) {
+      while (node = node.nextSibling)
+             if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    previousElementSibling: function(node) {
+      while (node = node.previousSibling)
+        if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    // TOKEN FUNCTIONS
+    tagName: function(nodes, root, tagName, combinator) {
+      tagName = tagName.toUpperCase();
+      var results = [], h = Selector.handlers;
+      if (nodes) {
+        if (combinator) {
+          // fastlane for ordinary descendant combinators
+          if (combinator == "descendant") {
+            for (var i = 0, node; node = nodes[i]; i++)
+              h.concat(results, node.getElementsByTagName(tagName));
+            return results;
+          } else nodes = this[combinator](nodes);
+          if (tagName == "*") return nodes;
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName.toUpperCase() == tagName) results.push(node);
+        return results;
+      } else return root.getElementsByTagName(tagName);
+    },
+
+    id: function(nodes, root, id, combinator) {
+      var targetNode = $(id), h = Selector.handlers;
+      if (!nodes && root == document) return targetNode ? [targetNode] : [];
+      if (nodes) {
+        if (combinator) {
+          if (combinator == 'child') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (targetNode.parentNode == node) return [targetNode];
+          } else if (combinator == 'descendant') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Element.descendantOf(targetNode, node)) return [targetNode];
+          } else if (combinator == 'adjacent') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Selector.handlers.previousElementSibling(targetNode) == node)
+                return [targetNode];
+          } else nodes = h[combinator](nodes);
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node == targetNode) return [targetNode];
+        return [];
+      }
+      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+    },
+
+    className: function(nodes, root, className, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      return Selector.handlers.byClassName(nodes, root, className);
+    },
+
+    byClassName: function(nodes, root, className) {
+      if (!nodes) nodes = Selector.handlers.descendant([root]);
+      var needle = ' ' + className + ' ';
+      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+        nodeClassName = node.className;
+        if (nodeClassName.length == 0) continue;
+        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+          results.push(node);
+      }
+      return results;
+    },
+
+    attrPresence: function(nodes, root, attr) {
+      var results = [];
+      for (var i = 0, node; node = nodes[i]; i++)
+        if (Element.hasAttribute(node, attr)) results.push(node);
+      return results;
+    },
+
+    attr: function(nodes, root, attr, value, operator) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      var handler = Selector.operators[operator], results = [];
+      for (var i = 0, node; node = nodes[i]; i++) {
+        var nodeValue = Element.readAttribute(node, attr);
+        if (nodeValue === null) continue;
+        if (handler(nodeValue, value)) results.push(node);
+      }
+      return results;
+    },
+
+    pseudo: function(nodes, name, value, root, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      return Selector.pseudos[name](nodes, value, root);
+    }
+  },
+
+  pseudos: {
+    'first-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.previousElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'last-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.nextElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'only-child': function(nodes, value, root) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+          results.push(node);
+      return results;
+    },
+    'nth-child':        function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root);
+    },
+    'nth-last-child':   function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true);
+    },
+    'nth-of-type':      function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, false, true);
+    },
+    'nth-last-of-type': function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true, true);
+    },
+    'first-of-type':    function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, false, true);
+    },
+    'last-of-type':     function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, true, true);
+    },
+    'only-of-type':     function(nodes, formula, root) {
+      var p = Selector.pseudos;
+      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+    },
+
+    // handles the an+b logic
+    getIndices: function(a, b, total) {
+      if (a == 0) return b > 0 ? [b] : [];
+      return $R(1, total).inject([], function(memo, i) {
+        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+        return memo;
+      });
+    },
+
+    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+    nth: function(nodes, formula, root, reverse, ofType) {
+      if (nodes.length == 0) return [];
+      if (formula == 'even') formula = '2n+0';
+      if (formula == 'odd')  formula = '2n+1';
+      var h = Selector.handlers, results = [], indexed = [], m;
+      h.mark(nodes);
+      for (var i = 0, node; node = nodes[i]; i++) {
+        if (!node.parentNode._counted) {
+          h.index(node.parentNode, reverse, ofType);
+          indexed.push(node.parentNode);
+        }
+      }
+      if (formula.match(/^\d+$/)) { // just a number
+        formula = Number(formula);
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.nodeIndex == formula) results.push(node);
+      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+        if (m[1] == "-") m[1] = -1;
+        var a = m[1] ? Number(m[1]) : 1;
+        var b = m[2] ? Number(m[2]) : 0;
+        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+          for (var j = 0; j < l; j++)
+            if (node.nodeIndex == indices[j]) results.push(node);
+        }
+      }
+      h.unmark(nodes);
+      h.unmark(indexed);
+      return results;
+    },
+
+    'empty': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        // IE treats comments as element nodes
+        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+        results.push(node);
+      }
+      return results;
+    },
+
+    'not': function(nodes, selector, root) {
+      var h = Selector.handlers, selectorType, m;
+      var exclusions = new Selector(selector).findElements(root);
+      h.mark(exclusions);
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node._counted) results.push(node);
+      h.unmark(exclusions);
+      return results;
+    },
+
+    'enabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node.disabled) results.push(node);
+      return results;
+    },
+
+    'disabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.disabled) results.push(node);
+      return results;
+    },
+
+    'checked': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.checked) results.push(node);
+      return results;
+    }
+  },
+
+  operators: {
+    '=':  function(nv, v) { return nv == v; },
+    '!=': function(nv, v) { return nv != v; },
+    '^=': function(nv, v) { return nv.startsWith(v); },
+    '$=': function(nv, v) { return nv.endsWith(v); },
+    '*=': function(nv, v) { return nv.include(v); },
+    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+  },
+
+  matchElements: function(elements, expression) {
+    var matches = new Selector(expression).findElements(), h = Selector.handlers;
+    h.mark(matches);
+    for (var i = 0, results = [], element; element = elements[i]; i++)
+      if (element._counted) results.push(element);
+    h.unmark(matches);
+    return results;
+  },
+
+  findElement: function(elements, expression, index) {
+    if (typeof expression == 'number') {
+      index = expression; expression = false;
+    }
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    var exprs = expressions.join(','), expressions = [];
+    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+      expressions.push(m[1].strip());
+    });
+    var results = [], h = Selector.handlers;
+    for (var i = 0, l = expressions.length, selector; i < l; i++) {
+      selector = new Selector(expressions[i].strip());
+      h.concat(results, selector.findElements(element));
+    }
+    return (l > 1) ? h.unique(results) : results;
+  }
+});
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, getHash) {
+    var data = elements.inject({}, function(result, element) {
+      if (!element.disabled && element.name) {
+        var key = element.name, value = $(element).getValue();
+        if (value != null) {
+               if (key in result) {
+            if (result[key].constructor != Array) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return getHash ? data : Hash.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, getHash) {
+    return Form.serializeElements(Form.getElements(form), getHash);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('disable');
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('enable');
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    return $(form).getElements().find(function(element) {
+      return element.type != 'hidden' && !element.disabled &&
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  },
+
+  request: function(form, options) {
+    form = $(form), options = Object.clone(options || {});
+
+    var params = options.parameters;
+    options.parameters = form.serialize(true);
+
+    if (params) {
+      if (typeof params == 'string') params = params.toQueryParams();
+      Object.extend(options.parameters, params);
+    }
+
+    if (form.hasAttribute('method') && !options.method)
+      options.method = form.method;
+
+    return new Ajax.Request(form.readAttribute('action'), options);
+  }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+}
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = {};
+        pair[element.name] = value;
+        return Hash.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    try {
+      element.focus();
+      if (element.select && (element.tagName.toLowerCase() != 'input' ||
+        !['button', 'reset', 'submit'].include(element.type)))
+        element.select();
+    } catch (e) {}
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.blur();
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.disabled = false;
+    return element;
+  }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+Object.extend(Element.Methods.ByTag, {
+  "FORM":     Object.clone(Form.Methods),
+  "INPUT":    Object.clone(Form.Element.Methods),
+  "SELECT":   Object.clone(Form.Element.Methods),
+  "TEXTAREA": Object.clone(Form.Element.Methods)
+});
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+      default:
+        return Form.Element.Serializers.textarea(element);
+    }
+  },
+
+  inputSelector: function(element) {
+    return element.checked ? element.value : null;
+  },
+
+  textarea: function(element) {
+    return element.value;
+  },
+
+  select: function(element) {
+    return this[element.type == 'select-one' ?
+      'selectOne' : 'selectMany'](element);
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    var value = this.getValue();
+    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+      ? this.lastValue != value : String(this.lastValue) != String(value));
+    if (changed) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+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) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback.bind(this));
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) {
+  var Event = new Object();
+}
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+  KEY_HOME:     36,
+  KEY_END:      35,
+  KEY_PAGEUP:   33,
+  KEY_PAGEDOWN: 34,
+
+  element: function(event) {
+    return $(event.target || event.srcElement);
+  },
+
+  isLeftClick: function(event) {
+    return (((event.which) && (event.which == 1)) ||
+            ((event.button) && (event.button == 1)));
+  },
+
+  pointerX: function(event) {
+    return event.pageX || (event.clientX +
+      (document.documentElement.scrollLeft || document.body.scrollLeft));
+  },
+
+  pointerY: function(event) {
+    return event.pageY || (event.clientY +
+      (document.documentElement.scrollTop || document.body.scrollTop));
+  },
+
+  stop: function(event) {
+    if (event.preventDefault) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else {
+      event.returnValue = false;
+      event.cancelBubble = true;
+    }
+  },
+
+  // find the first node with the given tagName, starting from the
+  // node the event was triggered on; traverses the DOM upwards
+  findElement: function(event, tagName) {
+    var element = Event.element(event);
+    while (element.parentNode && (!element.tagName ||
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))
+      element = element.parentNode;
+    return element;
+  },
+
+  observers: false,
+
+  _observeAndCache: function(element, name, observer, useCapture) {
+    if (!this.observers) this.observers = [];
+    if (element.addEventListener) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.addEventListener(name, observer, useCapture);
+    } else if (element.attachEvent) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.attachEvent('on' + name, observer);
+    }
+  },
+
+  unloadCache: function() {
+    if (!Event.observers) return;
+    for (var i = 0, length = Event.observers.length; i < length; i++) {
+      Event.stopObserving.apply(this, Event.observers[i]);
+      Event.observers[i][0] = null;
+    }
+    Event.observers = false;
+  },
+
+  observe: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+      (Prototype.Browser.WebKit || element.attachEvent))
+      name = 'keydown';
+
+    Event._observeAndCache(element, name, observer, useCapture);
+  },
+
+  stopObserving: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (Prototype.Browser.WebKit || element.attachEvent))
+      name = 'keydown';
+
+    if (element.removeEventListener) {
+      element.removeEventListener(name, observer, useCapture);
+    } else if (element.detachEvent) {
+      try {
+        element.detachEvent('on' + name, observer);
+      } catch (e) {}
+    }
+  }
+});
+
+/* prevent memory leaks in IE */
+if (Prototype.Browser.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,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  realOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    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) {
+        if(element.tagName=='BODY') break;
+        var 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)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = this.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = this.realOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = this.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            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) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  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 {
+      if (!window.opera || element.tagName=='BODY') {
+        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 (Prototype.Browser.WebKit) {
+  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];
+  }
+}
+
+Element.addMethods();
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico/rico.js b/trunk/NP_TrackBack/trackback/js/rico/rico.js
new file mode 100644 (file)
index 0000000..00e187e
--- /dev/null
@@ -0,0 +1,214 @@
+/**
+  *
+  *  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.
+  **/
+
+
+// This module does NOT depend on prototype.js
+
+var Rico = {
+  Version: '2.0 beta2',
+  loadRequested: 1,
+  loadComplete: 2,
+  init : function() {
+    try {  // fix IE background image flicker (credit: www.mister-pixel.com)
+      document.execCommand("BackgroundImageCache", false, true);
+    } catch(err) {}
+    this.preloadMsgs='';
+    var elements = document.getElementsByTagName('script');
+    this.baseHref= location.protocol + "//" + location.host;
+    this.loadedFiles={};
+    this.loadQueue=[];    
+    this.windowIsLoaded=false;
+    this.onLoadCallbacks=[];
+    for (var i=0; i<elements.length; i++) {
+      if (!elements[i].src) continue;
+      var src = elements[i].src;
+      var slashIdx = src.lastIndexOf('/');
+      var path = src.substring(0, slashIdx+1);
+      var filename = src.substring(slashIdx+1);
+      this.loadedFiles[filename]=this.loadComplete;
+      if (filename == 'rico.js') {
+        this.jsDir = path;
+        this.cssDir= path+'css/';
+        this.imgDir= path+'images/';
+        this.htmDir= path;
+        this.xslDir= path;
+      }
+    }
+    if (typeof Prototype=='undefined')
+      this.include('prototype.js');
+    this.include('ricoCommon.js');
+    var func=function() { Rico.windowLoaded(); };
+    if (window.addEventListener)
+      window.addEventListener('load', func, false);
+    else if (window.attachEvent)
+      window.attachEvent('onload', func);
+    this.onLoad(function() { Rico.writeDebugMsg('Pre-load messages:\n'+Rico.preloadMsgs); });
+  },
+  
+  // Array entries can reference a javascript file or css stylesheet
+  // A dependency on another module can be indicated with a plus-sign prefix: '+DependsOnModule'
+  moduleDependencies : {
+    Accordion  : ['ricoBehaviors.js','ricoEffects.js','ricoComponents.js'],
+    Color      : ['ricoColor.js'],
+    Corner     : ['ricoStyles.js'],
+    DragAndDrop: ['ricoDragDrop.js'],
+    Effect     : ['ricoEffects.js'],
+    Calendar   : ['ricoCalendar.js', 'ricoCalendar.css'],
+    Tree       : ['ricoTree.js', 'ricoTree.css'],
+    ColorPicker: ['ricoColorPicker.js', 'ricoStyles.js'],
+    SimpleGrid : ['ricoCommon.js', 'ricoGridCommon.js', 'ricoGrid.css', 'ricoSimpleGrid.js'],
+    LiveGrid   : ['ricoCommon.js', 'ricoGridCommon.js', 'ricoGrid.css', 'ricoBehaviors.js', 'ricoLiveGrid.js'],
+    CustomMenu : ['ricoMenu.js', 'ricoMenu.css'],
+    LiveGridMenu : ['+CustomMenu', 'ricoLiveGridMenu.js'],
+    LiveGridAjax : ['+LiveGrid', 'ricoLiveGridAjax.js'],
+    LiveGridForms: ['+LiveGridAjax', '+LiveGridMenu', '+Accordion', '+Corner', 'ricoLiveGridForms.js', 'ricoLiveGridForms.css'],
+    SpreadSheet  : ['+SimpleGrid', 'ricoSheet.js']
+  },
+  
+  // not reliable when used with XSLT
+  loadModule : function(name) {
+    var dep=this.moduleDependencies[name];
+    if (!dep) return;
+    for (var i=0; i<dep.length; i++)
+      if (dep[i].substring(0,1)=='+')
+        this.loadModule(dep[i].slice(1));
+      else
+        this.include(dep[i]);
+  },
+  
+  // not reliable when used with XSLT
+  include : function(filename) {
+    if (this.loadedFiles[filename]) return;
+    this.addPreloadMsg('include: '+filename);
+    var ext = filename.substr(filename.lastIndexOf('.')+1);
+    switch (ext.toLowerCase()) {
+      case 'js':
+        this.loadQueue.push(filename);
+        this.loadedFiles[filename]=this.loadRequested;
+        this.checkLoadQueue();
+        return;
+      case 'css':
+        var el = document.createElement('link');
+        el.type = 'text/css';
+        el.rel = 'stylesheet'
+        el.href = this.cssDir+filename;
+        this.loadedFiles[filename]=this.loadComplete;
+        document.getElementsByTagName('head')[0].appendChild(el);
+        return;
+    }
+  },
+  
+  checkLoadQueue: function() {
+    if (this.loadQueue.length==0) return;
+    if (this.inProcess) return;  // seems to only be required by IE, but applied to all browsers just to be safe
+    this.addScriptToDOM(this.loadQueue.shift());
+  },
+  
+  addScriptToDOM: function(filename) {
+    this.addPreloadMsg('addScriptToDOM: '+filename);
+    var js = document.createElement('script');
+    js.type = 'text/javascript';
+    js.src = this.jsDir+filename;
+    this.loadedFiles[filename]=this.loadRequested;
+    this.inProcess=filename;
+    var head=document.getElementsByTagName('head')[0];
+    if (filename.substring(0,4)=='rico') {
+      head.appendChild(js);
+    } else if(/WebKit|Khtml/i.test(navigator.userAgent)) {
+      head.appendChild(js);
+      this.includeLoaded(filename);
+    } else {
+      js.onload = js.onreadystatechange = function() {
+        if (js.readyState && js.readyState != 'loaded' && js.readyState != 'complete') return;
+        js.onreadystatechange = js.onload = null;
+        Rico.includeLoaded(filename);
+      };
+      head.appendChild(js);
+    }
+  },
+  
+  // called after a script file has finished loading
+  includeLoaded: function(filename) {
+    this.addPreloadMsg('loaded: '+filename);
+    this.loadedFiles[filename]=this.loadComplete;
+    if (filename==this.inProcess) {
+      this.inProcess=null;
+      this.checkLoadQueue();
+      this.checkIfComplete();
+    }
+  },
+
+  // called by the document onload event
+  windowLoaded: function() {
+    this.windowIsLoaded=true;
+    this.checkIfComplete();
+  },
+  
+  checkIfComplete: function() {
+    var waitingFor=this.windowIsLoaded ? '' : 'window';
+    for(var filename in  this.loadedFiles) {
+      if (this.loadedFiles[filename]==this.loadRequested)
+        waitingFor+=' '+filename;
+    }
+    //window.status='waitingFor: '+waitingFor;
+    this.addPreloadMsg('waitingFor: '+waitingFor);
+    if (waitingFor.length==0) {
+      this.addPreloadMsg('Processing callbacks');
+      while (this.onLoadCallbacks.length > 0) {
+        var callback=this.onLoadCallbacks.pop();
+        if (callback) callback();
+      }
+    }
+  },
+  
+  onLoad: function(callback) {
+    this.onLoadCallbacks.push(callback);
+    this.checkIfComplete();
+  },
+
+  isKonqueror : navigator.userAgent.toLowerCase().indexOf("konqueror") >= 0,
+
+  // logging funtions
+   
+  startTime : new Date(),
+
+  timeStamp: function() {
+    var stamp = new Date();
+    return (stamp.getTime()-this.startTime.getTime())+": ";
+  },
+  
+  setDebugArea: function(id, forceit) {
+    if (!this.debugArea || forceit) {
+      var newarea=document.getElementById(id);
+      if (!newarea) return;
+      this.debugArea=newarea;
+      newarea.value='';
+    }
+  },
+
+  addPreloadMsg: function(msg) {
+    this.preloadMsgs+=Rico.timeStamp()+msg+"\n";
+  },
+
+  writeDebugMsg: function(msg, resetFlag) {
+    if (this.debugArea) {
+      if (resetFlag) this.debugArea.value='';
+      this.debugArea.value+=this.timeStamp()+msg+"\n";
+    }
+  }
+
+}
+
+Rico.init();
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoAjaxEngine.js b/trunk/NP_TrackBack/trackback/js/rico/ricoAjaxEngine.js
new file mode 100644 (file)
index 0000000..5363991
--- /dev/null
@@ -0,0 +1,178 @@
+//-------------------- ricoAjaxEngine.js
+Rico.AjaxEngine = Class.create();
+
+Rico.AjaxEngine.prototype = {
+
+   initialize: function() {
+      this.ajaxElements = new Array();
+      this.ajaxObjects  = new Array();
+      this.requestURLS  = new Array();
+      this.options = {};
+   },
+
+   registerAjaxElement: function( anId, anElement ) {
+      if ( !anElement )
+         anElement = $(anId);
+      this.ajaxElements[anId] = anElement;
+   },
+
+   registerAjaxObject: function( anId, anObject ) {
+      this.ajaxObjects[anId] = anObject;
+   },
+
+   registerRequest: function (requestLogicalName, requestURL) {
+      this.requestURLS[requestLogicalName] = requestURL;
+   },
+
+   sendRequest: function(requestName, options) {
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 2 )
+       if (typeof arguments[1] == 'string')
+         options = {parameters: this._createQueryString(arguments, 1)};
+      this.sendRequestWithData(requestName, null, options);
+   },
+
+   sendRequestWithData: function(requestName, xmlDocument, options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 3 )
+        if (typeof arguments[2] == 'string')
+          options.parameters = this._createQueryString(arguments, 2);
+
+      new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
+   },
+
+   sendRequestAndUpdate: function(requestName,container,options) {
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 3 )
+        if (typeof arguments[2] == 'string')
+          options.parameters = this._createQueryString(arguments, 2);
+
+      this.sendRequestWithDataAndUpdate(requestName, null, container, options);
+   },
+
+   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      // Allow for backwards Compatibility
+      if ( arguments.length >= 4 )
+        if (typeof arguments[3] == 'string')
+          options.parameters = this._createQueryString(arguments, 3);
+
+      var updaterOptions = this._requestOptions(options,xmlDocument);
+
+      new Ajax.Updater(container, requestURL, updaterOptions);
+   },
+
+   // Private -- not part of intended engine API --------------------------------------------------------------------
+
+   _requestOptions: function(options,xmlDoc) {
+      var requestHeaders = ['X-Rico-Version', Rico.Version ];
+      var sendMethod = 'post';
+      if ( xmlDoc == null )
+        if (Rico.prototypeVersion < 1.4)
+        requestHeaders.push( 'Content-type', 'text/xml' );
+      else
+          sendMethod = 'get';
+      (!options) ? options = {} : '';
+
+      if (!options._RicoOptionsProcessed){
+      // Check and keep any user onComplete functions
+        if (options.onComplete)
+             options.onRicoComplete = options.onComplete;
+        // Fix onComplete
+        if (options.overrideOnComplete)
+          options.onComplete = options.overrideOnComplete;
+        else
+          options.onComplete = this._onRequestComplete.bind(this);
+        options._RicoOptionsProcessed = true;
+      }
+
+     // Set the default options and extend with any user options
+     this.options = {
+                     requestHeaders: requestHeaders,
+                     parameters:     options.parameters,
+                     postBody:       xmlDoc,
+                     method:         sendMethod,
+                     onComplete:     options.onComplete
+                    };
+     // Set any user options:
+     Object.extend(this.options, options);
+     return this.options;
+   },
+
+   _createQueryString: function( theArgs, offset ) {
+      var queryString = ""
+      for ( var i = offset ; i < theArgs.length ; i++ ) {
+          if ( i != offset )
+            queryString += "&";
+
+          var anArg = theArgs[i];
+
+          if ( anArg.name != undefined && anArg.value != undefined ) {
+            queryString += anArg.name +  "=" + escape(anArg.value);
+          }
+          else {
+             var ePos  = anArg.indexOf('=');
+             var argName  = anArg.substring( 0, ePos );
+             var argValue = anArg.substring( ePos + 1 );
+             queryString += argName + "=" + escape(argValue);
+          }
+      }
+      return queryString;
+   },
+
+   _onRequestComplete : function(request) {
+      if(!request)
+          return;
+      // User can set an onFailure option - which will be called by prototype
+      if (request.status != 200)
+        return;
+
+      var response = request.responseXML.getElementsByTagName("ajax-response");
+      if (response == null || response.length != 1)
+         return;
+      this._processAjaxResponse( response[0].childNodes );
+      
+      // Check if user has set a onComplete function
+      var onRicoComplete = this.options.onRicoComplete;
+      if (onRicoComplete != null)
+          onRicoComplete();
+   },
+
+   _processAjaxResponse: function( xmlResponseElements ) {
+      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
+         var responseElement = xmlResponseElements[i];
+
+         // only process nodes of type element.....
+         if ( responseElement.nodeType != 1 )
+            continue;
+
+         var responseType = responseElement.getAttribute("type");
+         var responseId   = responseElement.getAttribute("id");
+
+         if ( responseType == "object" )
+            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
+         else if ( responseType == "element" )
+            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
+         else
+            alert('unrecognized AjaxResponse type : ' + responseType );
+      }
+   },
+
+   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
+      ajaxObject.ajaxUpdate( responseElement );
+   },
+
+   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
+      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
+   }
+
+}
+
+Rico.includeLoaded('ricoAjaxEngine.js');
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoBehaviors.js b/trunk/NP_TrackBack/trackback/js/rico/ricoBehaviors.js
new file mode 100644 (file)
index 0000000..ed5d572
--- /dev/null
@@ -0,0 +1,188 @@
+/**
+  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+  *
+  *  Rico is 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
+  **/
+
+
+Rico.selectionSet = function(set, options){
+  new Rico.SelectionSet(set, options)
+}
+
+Rico.SelectionSet = Class.create(); 
+Rico.SelectionSet.prototype = {
+       initialize: function(selectionSet, options){
+               this.options = options || {}
+    if (typeof selectionSet == 'string')
+      selectionSet = $$(selectionSet)
+         this.previouslySelected = [];
+               this.selectionSet = selectionSet;
+               this.selectedClassName = this.options.selectedClass || "selected";
+               this.selectNode = this.options.selectNode || function(e){return e};
+               this.onSelect = this.options.onSelect;
+    this.onFirstSelect = this.options.onFirstSelect;
+               this.clickHandler = this.click.bind(this);
+               selectionSet.each(function(e) {Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,e).wrapper);}.bind(this))
+    if (!this.options.noDefault)
+                 this.selectIndex(this.options.selectedIndex || 0)
+       },
+       reset: function(){
+         this.previouslySelected = [];
+         this.notifySelected(this.selected);
+       },
+       select: function(element){
+               if (this.selected == element)
+                       return;
+
+               if (this.selected)
+                 new Element.ClassNames(this.selectNode(this.selected)).remove(this.selectedClassName)
+    
+    this.notifySelected(element)
+
+               this.selected = element;
+               new Element.ClassNames(this.selectNode(this.selected)).add(this.selectedClassName)
+       },
+       notifySelected: function(element){
+    var index = this.selectionSet.indexOf(element)
+    if (this.onFirstSelect && !this.previouslySelected[index]){
+      this.onFirstSelect(element, index)
+      this.previouslySelected[index] = true;
+    }
+       if (this.onSelect)
+      try{
+           this.onSelect(element, index)
+      } catch (e) {}
+       },
+       selectIndex: function(index){
+               this.select(this.selectionSet[index])
+       },  
+       nextSelectItem: function(index){
+    var index = this.selectionSet.indexOf(this.selected)
+    if (index + 1 >= this.selectionSet.length)
+      return this.selectionSet[index - 1];
+    else
+      return this.selectionSet[index + 1];       
+       },
+       selectNext: function(){
+    var index = this.selectionSet.indexOf(this.selected)
+    if (index >= this.selectionSet.length)
+      this.selectIndex(index - 1)
+    else
+      this.selectIndex(index + 1)
+       },
+       click: function(event,target) {
+               this.select(target);
+       },
+       add: function(item){
+       //      this.selectionSet.push(item)
+         if (item.constructur == Array)
+           item.each(function(e){
+               Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
+           }.bind(this))
+         else
+                 Event.observe(item, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
+       },
+       remove: function(item){
+         this.selectionSet = this.selectionSet.without(item)
+                       //Todo: need to cleanup all events on item - need to keep track of eventwrappers
+       },
+       removeAll: function(){
+               
+       }
+ }
+
+Rico.HoverSet = Class.create();
+Rico.HoverSet.prototype = {
+    initialize: function(hoverSet, options){
+      options = options || [];
+      this.hoverSet = hoverSet;
+      this.hoverClassName = options.hoverClass || "hover";
+      this.hoverNodes = options.hoverNodes || function(e){return [e]};
+               this.listenerHover    = this._onHover.bind(this)
+      this.listenerEndHover = this._onUnHover.bind(this)
+      
+         this.hoverSet.each((function(e) {Event.observe(e, "mousemove", new Rico.EventWrapper(this.listenerHover,e).wrapper);}).bind(this))
+         this.hoverSet.each((function(e) {Event.observe(e, "mouseout", new Rico.EventWrapper(this.listenerEndHover,e).wrapper);}).bind(this))  
+       },
+       _onHover: function(event,target) {
+         this.hover(target);
+       },      
+       _onUnHover: function(event,target) {
+         this.unHover(target);
+       },
+       hover: function(target) {
+         this.hoverNodes(target).each((function(t){Element.classNames(t).add(this.hoverClassName)}).bind(this));
+       },      
+       unHover: function(target) {
+         this.hoverNodes(target).each((function(t){Element.classNames(t).remove(this.hoverClassName)}).bind(this));
+       },
+               add: function(item){
+         Event.observe(item, "mousemove", new Rico.EventWrapper(this.listenerHover,item).wrapper);
+         Event.observe(item, "mouseout", new Rico.EventWrapper(this.listenerEndHover,item).wrapper);
+               },
+               remove: function(item){
+                       //Todo: need to cleanup all events on item - need to keep terack of eventwrappers
+                       //stopObserving
+                       //Event.stopObserving(e, "mousemove", new Rico.EventWrapper(this.listenerHover,e).wrapper);}).bind(this))
+         //this.hoverSet.each((function(e) {Event.observe(e, "mouseout", new Rico.EventWrapper(this.listenerEndHover,e).wrapper);}).bind(this))
+                       //hoverSet
+               },
+               removeAll: function(item){
+               }
+}
+
+Rico.Hover = {
+  groups: {},
+  clearCurrent: function(group) {
+    var last_hover = Rico.Hover.groups[group];
+    if(!last_hover) return  
+    clearTimeout(last_hover[0])
+    last_hover[1].end()
+    Rico.Hover.groups[group] = null;
+  }, 
+  end: function(group) {
+       Rico.Hover.groups[group][1].end();
+  },
+  endWith: function(hover, group) {
+       var timer = setTimeout('Rico.Hover.end("'+ group + '")', hover.exitDelay)
+    Rico.Hover.groups[group] = [timer, hover]
+  }
+}
+
+Rico.HoverDisplay = Class.create();
+Rico.HoverDisplay.prototype = {
+  initialize: function(element, options) {
+       this.element = element;
+       this.options = options || {};
+       this.group = this.options.group;
+       this.exitDelay = this.options.delay || 1000;
+  },
+  begin: function() {
+    Rico.Hover.clearCurrent(this.group)
+               Element.show(this.element)
+  },
+  end: function(delay) {
+    if(delay)
+               Rico.Hover.endWith(this, this.group);
+    else 
+                 Element.hide(this.element)              
+  }
+}
+
+
+Rico.EventWrapper = Class.create();
+Rico.EventWrapper.prototype = {
+  initialize: function(handler, target){
+    this.handler = handler;
+    this.target = target;
+    this.wrapper = this.wrapperCall.bindAsEventListener(this)
+  },
+  wrapperCall: function(event){
+    this.handler(event, this.target)
+  }
+}
+
+Rico.includeLoaded('ricoBehaviors.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoCalendar.js b/trunk/NP_TrackBack/trackback/js/rico/ricoCalendar.js
new file mode 100644 (file)
index 0000000..99d33c6
--- /dev/null
@@ -0,0 +1,443 @@
+//  By Matt Brown
+//  June-October 2006
+//  email: dowdybrown@yahoo.com
+//  Implements a pop-up Gregorian calendar.
+//  Dates of adoption of the Gregorian calendar vary by country - accurate as a US & British calendar from 14 Sept 1752 to present.
+//  Mark special dates with calls to addHoliday()
+//  Inspired by code originally written by Tan Ling Wee on 2 Dec 2001
+
+//  Requires prototype.js and ricoCommon.js
+
+Rico.CalendarControl = Class.create();
+
+Rico.CalendarControl.prototype = {
+
+  initialize: function(id,options) {
+    this.id=id;
+    var today=new Date();
+    Object.extend(this, new Rico.Popup({ignoreClicks:true}));
+    Object.extend(this.options, {
+      startAt : 0,           // week starts with 0=sunday, 1=monday
+      showWeekNumber : 0,    // show week number in first column?
+      showToday : 1,         // show "Today is..." in footer?
+      cursorColor: '#FDD',   // color used to highlight dates as the user moves their mouse
+      repeatInterval : 100,  // when left/right arrow is pressed, repeat action every x milliseconds
+      dateFmt : 'ISO8601',   // default is ISO-8601, 'rico'=use format stored in ricoTranslate object
+      selectedDateBorder : "#666666",  // border to indicate currently selected date
+      minDate : new Date(today.getFullYear()-50,0,1),  // default to +-50 yrs from current date
+      maxDate : new Date(today.getFullYear()+50,11,31)
+    });
+    Object.extend(this.options, options || {});
+    this.close=this.closePopup;
+    this.bPageLoaded=false;
+    this.img=new Array();
+    this.Holidays={};
+    this.todayString=RicoTranslate.getPhrase("Today is ");
+    this.weekString=RicoTranslate.getPhrase("Wk");
+    if (this.options.dateFmt=='rico') this.options.dateFmt=RicoTranslate.dateFmt;
+    this.dateParts=new Array();
+    this.re=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i;
+    if (this.re.exec(this.options.dateFmt)) {
+      this.dateParts[RegExp.$1]=0;
+      this.dateParts[RegExp.$3]=1;
+      this.dateParts[RegExp.$5]=2;
+    }
+  },
+
+
+  // y=0 implies a repeating holiday
+  addHoliday : function(d, m, y, desc, bgColor, txtColor) {
+    this.Holidays[this.holidayKey(y,m-1,d)]={desc:desc, txtColor:txtColor, bgColor:bgColor || '#DDF'};
+  },
+  
+  holidayKey : function(y,m,d) {
+    return 'h'+y.toPaddedString(4)+m.toPaddedString(2)+d.toPaddedString(2);
+  },
+
+  atLoad : function() {
+    this.container=document.createElement("div");
+    this.container.style.display="none"
+    this.container.id=this.id;
+    this.container.className='ricoCalContainer';
+
+    this.maintab=document.createElement("table");
+    this.maintab.cellSpacing=0;
+    this.maintab.cellPadding=0;
+    this.maintab.border=0;
+    this.maintab.className='ricoCalTab';
+
+    for (var i=0; i<7; i++) {
+      var r=this.maintab.insertRow(-1);
+      r.className='row'+i;
+      for (var c=0; c<8; c++)
+        r.insertCell(-1);
+    }
+    this.tbody=this.maintab.tBodies[0];
+    var r=this.tbody.rows[0];
+    r.className='ricoCalDayNames';
+    if (this.options.showWeekNumber) {
+      r.cells[0].innerHTML=this.weekString;
+      for (var i=0; i<7; i++)
+        this.tbody.rows[i].cells[0].className='ricoCalWeekNum';
+    }
+    this.styles=[];
+    for (var i=0; i<7; i++) {
+      var dow=(i+this.options.startAt) % 7;
+      r.cells[i+1].innerHTML=RicoTranslate.dayNames[dow].substring(0,3);
+      this.styles[i+1]='ricoCal'+dow;
+    }
+    
+    // table header (navigation controls)
+    this.thead=this.maintab.createTHead()
+    var r=this.thead.insertRow(-1);
+    var c=r.insertCell(-1);
+    c.colSpan=8;
+    var img=this.createNavArrow('decMonth','left');
+    c.appendChild(document.createElement("a")).appendChild(img);
+    this.titleMonth=document.createElement("a");
+    c.appendChild(this.titleMonth);
+    Event.observe(this.titleMonth,"click", this.popUpMonth.bindAsEventListener(this), false);
+    var img=this.createNavArrow('incMonth','right');
+    c.appendChild(document.createElement("a")).appendChild(img);
+    var s=document.createElement("span");
+    s.innerHTML='&nbsp;';
+    s.style.paddingLeft='3em';
+    c.appendChild(s);
+
+    var img=this.createNavArrow('decYear','left');
+    c.appendChild(document.createElement("a")).appendChild(img);
+    this.titleYear=document.createElement("a");
+    Event.observe(this.titleYear,"click", this.popUpYear.bindAsEventListener(this), false);
+    c.appendChild(this.titleYear);
+    var img=this.createNavArrow('incYear','right');
+    c.appendChild(document.createElement("a")).appendChild(img);
+
+    // table footer (today)
+    if (this.options.showToday) {
+      this.tfoot=this.maintab.createTFoot()
+      var r=this.tfoot.insertRow(-1);
+      this.todayCell=r.insertCell(-1);
+      this.todayCell.colSpan=8;
+      Event.observe(this.todayCell,"click", this.selectNow.bindAsEventListener(this), false);
+    }
+    
+
+    this.container.appendChild(this.maintab);
+    
+    // close icon (upper right)
+    var img=document.createElement("img");
+    img.src=Rico.imgDir+'close.gif';
+    img.onclick=this.close.bind(this);
+    img.style.cursor='pointer';
+    img.style.position='absolute';
+    img.style.top='1px';   /* assumes a 1px border */
+    img.style.right='1px';
+    this.container.appendChild(img);
+    
+    // month selector
+    this.monthSelect=document.createElement("table");
+    this.monthSelect.className='ricoCalMenu';
+    this.monthSelect.cellPadding=2;
+    this.monthSelect.cellSpacing=0;
+    this.monthSelect.border=0;
+    for (var i=0; i<4; i++) {
+      var r=this.monthSelect.insertRow(-1);
+      for (var j=0; j<3; j++) {
+        var c=r.insertCell(-1);
+        var a=document.createElement("a");
+        a.innerHTML=RicoTranslate.monthNames[i*3+j].substring(0,3);
+        a.name=i*3+j;
+        c.appendChild(a);
+        Event.observe(a,"click", this.selectMonth.bindAsEventListener(this), false);
+      }
+    }
+    this.monthSelect.style.display='none';
+    this.container.appendChild(this.monthSelect);
+    
+    // fix anchors so they work in IE6
+    var a=this.container.getElementsByTagName('a');
+    for (var i=0; i<a.length; i++)
+      a[i].href='#';
+    
+    Event.observe(this.tbody,"click", this.saveAndClose.bindAsEventListener(this));
+    Event.observe(this.tbody,"mouseover", this.mouseOver.bindAsEventListener(this));
+    Event.observe(this.tbody,"mouseout",  this.mouseOut.bindAsEventListener(this));
+    document.getElementsByTagName("body")[0].appendChild(this.container);
+    this.setDiv(this.container);
+    this.close()
+    this.bPageLoaded=true
+  },
+  
+  selectNow : function() {
+    this.monthSelected=this.monthNow;
+    this.yearSelected=this.yearNow;
+    this.constructCalendar();
+  },
+  
+  createNavArrow: function(funcname,gifname) {
+    var img=document.createElement("img");
+    img.src=Rico.imgDir+gifname+'.gif';
+    img.name=funcname;
+    Event.observe(img,"click", this[funcname].bindAsEventListener(this), false);
+    Event.observe(img,"mousedown", this.mouseDown.bindAsEventListener(this), false);
+    Event.observe(img,"mouseup", this.mouseUp.bindAsEventListener(this), false);
+    Event.observe(img,"mouseout", this.mouseUp.bindAsEventListener(this), false);
+    return img
+  },
+
+  mouseOver: function(e) {
+    var el=Event.element(e);
+    if (this.lastHighlight==el) return;
+    this.unhighlight();
+    var s=el.innerHTML.replace(/&nbsp;/g,'');
+    if (s=='' || el.className=='ricoCalWeekNum') return;
+    var day=parseInt(s);
+    if (isNaN(day)) return;
+    this.lastHighlight=el;
+    this.tmpColor=el.style.backgroundColor;
+    el.style.backgroundColor=this.options.cursorColor;
+  },
+  
+  unhighlight: function() {
+    if (!this.lastHighlight) return;
+    this.lastHighlight.style.backgroundColor=this.tmpColor;
+    this.lastHighlight=null;
+  },
+  
+  mouseOut: function(e) {
+    var el=Event.element(e);
+    if (el==this.lastHighlight) this.unhighlight();
+  },
+  
+  mouseDown: function(e) {
+    var el=Event.element(e);
+    this.repeatFunc=this[el.name].bind(this);
+    this.timeoutID=setTimeout(this.repeatStart.bind(this),500);
+  },
+  
+  mouseUp: function(e) {
+    clearTimeout(this.timeoutID);
+    clearInterval(this.intervalID)
+  },
+  
+  repeatStart : function() {
+    clearInterval(this.intervalID);
+    this.intervalID=setInterval(this.repeatFunc,this.options.repeatInterval);
+  },
+  
+  // is yr/mo within minDate/MaxDate?
+  isValidMonth : function(yr,mo) {
+    if (yr < this.options.minDate.getFullYear()) return false;
+    if (yr == this.options.minDate.getFullYear() && mo < this.options.minDate.getMonth()) return false;
+    if (yr > this.options.maxDate.getFullYear()) return false;
+    if (yr == this.options.maxDate.getFullYear() && mo > this.options.maxDate.getMonth()) return false;
+    return true;
+  },
+
+  incMonth : function() {
+    var newMonth=this.monthSelected+1;
+    var newYear=this.yearSelected;
+    if (newMonth>11) {
+      newMonth=0;
+      newYear++;
+    }
+    if (!this.isValidMonth(newYear,newMonth)) return;
+    this.monthSelected=newMonth;
+    this.yearSelected=newYear;
+    this.constructCalendar()
+  },
+
+  decMonth : function() {
+    var newMonth=this.monthSelected-1;
+    var newYear=this.yearSelected;
+    if (newMonth<0) {
+      newMonth=11;
+      newYear--;
+    }
+    if (!this.isValidMonth(newYear,newMonth)) return;
+    this.monthSelected=newMonth;
+    this.yearSelected=newYear;
+    this.constructCalendar()
+  },
+  
+  selectMonth : function(e) {
+    var el=Event.element(e);
+    this.monthSelected=parseInt(el.name);
+    this.constructCalendar();
+    Event.stop(e);
+  },
+
+  popUpMonth : function() {
+    this.monthSelect.style.display=this.monthSelect.style.display=='none' ? 'block' : 'none';
+  },
+
+  popDownMonth : function() {
+    this.monthSelect.style.display='none';
+  },
+
+  /*** Year Pulldown ***/
+
+  popUpYear : function() {
+    var newYear=prompt(RicoTranslate.getPhrase("Year ("+this.options.minDate.getFullYear()+"-"+this.options.maxDate.getFullYear()+")"),this.yearSelected);
+    if (newYear==null) return;
+    newYear=parseInt(newYear);
+    if (isNaN(newYear) || newYear<this.options.minDate.getFullYear() || newYear>this.options.maxDate.getFullYear()) {
+      alert(RicoTranslate.getPhrase("Invalid year"));
+    } else {
+      this.yearSelected=newYear;
+      this.constructCalendar();
+    }
+  },
+  
+  incYear : function() {
+    if (this.yearSelected>=this.options.maxDate.getFullYear()) return;
+    this.yearSelected++;
+    this.constructCalendar();
+  },
+
+  decYear : function() {
+    if (this.yearSelected<=this.options.minDate.getFullYear()) return;
+    this.yearSelected--;
+    this.constructCalendar();
+  },
+
+  // tried a number of different week number functions posted on the net
+  // this is the only one that produced consistent results when comparing week numbers for December and the following January
+  WeekNbr : function(year,month,day) {
+    var when = new Date(year,month,day);
+    var newYear = new Date(year,0,1);
+    var offset = 7 + 1 - newYear.getDay();
+    if (offset == 8) offset = 1;
+    var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1;
+    var weeknum = Math.floor((daynum-offset+7)/7);
+    if (weeknum == 0) {
+        year--;
+        var prevNewYear = new Date(year,0,1);
+        var prevOffset = 7 + 1 - prevNewYear.getDay();
+        if (prevOffset == 2 || prevOffset == 8) weeknum = 53; else weeknum = 52;
+    }
+    return weeknum;
+  },
+
+  constructCalendar : function() {
+    var aNumDays = Array (31,0,31,30,31,30,31,31,30,31,30,31)
+    var startDate = new Date (this.yearSelected,this.monthSelected,1)
+    var endDate,numDaysInMonth
+
+    if (typeof this.monthSelected!='number' || this.monthSelected>=12 || this.monthSelected<0) {
+      alert('ERROR in calendar: monthSelected='+this.monthSelected);
+      return;
+    }
+    var today = new Date();
+    this.dateNow  = today.getDate();
+    this.monthNow = today.getMonth();
+    this.yearNow  = today.getFullYear();
+
+    if (this.monthSelected==1) {
+      endDate = new Date (this.yearSelected,this.monthSelected+1,1);
+      endDate = new Date (endDate - (24*60*60*1000));
+      numDaysInMonth = endDate.getDate()
+    } else {
+      numDaysInMonth = aNumDays[this.monthSelected];
+    }
+    var dayPointer = startDate.getDay() - this.options.startAt
+    if (dayPointer<0) dayPointer+=7;
+    this.popDownMonth();
+
+    this.bgcolor=Element.getStyle(this.tbody,'background-color');
+    this.bgcolor=this.bgcolor.replace(/\"/g,'');
+    if (this.options.showWeekNumber) {
+      for (var i=1; i<7; i++)
+        this.tbody.rows[i].cells[0].innerHTML='&nbsp;';
+    }
+    for ( var i=1; i<=dayPointer; i++ )
+      this.resetCell(this.tbody.rows[1].cells[i]);
+
+    for ( var datePointer=1,r=1; datePointer<=numDaysInMonth; datePointer++,dayPointer++ ) {
+      var colnum=dayPointer % 7 + 1;
+      if (this.options.showWeekNumber==1 && colnum==1)
+        this.tbody.rows[r].cells[0].innerHTML=this.WeekNbr(this.yearSelected,this.monthSelected,datePointer);
+      var dateClass=this.styles[colnum];
+      if ((datePointer==this.dateNow)&&(this.monthSelected==this.monthNow)&&(this.yearSelected==this.yearNow))
+        dateClass='ricoCalToday';
+      var c=this.tbody.rows[r].cells[colnum];
+      c.innerHTML="&nbsp;" + datePointer + "&nbsp;";
+      c.className=dateClass;
+      var bordercolor=(datePointer==this.odateSelected) && (this.monthSelected==this.omonthSelected) && (this.yearSelected==this.oyearSelected) ? this.options.selectedDateBorder : this.bgcolor;
+      c.style.border='1px solid '+bordercolor;
+      var h=this.Holidays[this.holidayKey(this.yearSelected,this.monthSelected,datePointer)];
+      if (!h)  h=this.Holidays[this.holidayKey(0,this.monthSelected,datePointer)];
+      c.style.color=h ? h.txtColor : '';
+      c.style.backgroundColor=h ? h.bgColor : '';
+      c.title=h ? h.desc : '';
+      if (colnum==7) r++;
+    }
+    while (dayPointer<42) {
+      var colnum=dayPointer % 7 + 1;
+      this.resetCell(this.tbody.rows[r].cells[colnum]);
+      dayPointer++;
+      if (colnum==7) r++;
+    }
+
+    this.titleMonth.innerHTML = RicoTranslate.monthNames[this.monthSelected].substring(0,3);
+    this.titleYear.innerHTML = this.yearSelected;
+    if (this.options.showToday)
+      this.todayCell.innerHTML=this.todayString+'<span>'+this.dateNow + " " + RicoTranslate.monthNames[this.monthNow].substring(0,3) + " " + this.yearNow+'</span>';
+    this.monthSelect.style.top=this.thead.offsetHeight+'px';
+    this.monthSelect.style.left=this.titleMonth.offsetLeft+'px';
+  },
+  
+  resetCell: function(c) {
+    c.innerHTML="&nbsp;";
+    c.className='ricoCalEmpty';
+    c.style.border='1px solid '+this.bgcolor;
+    c.style.color='';
+    c.style.backgroundColor='';
+    c.title='';
+  },
+  
+  saveAndClose : function(e) {
+    Event.stop(e);
+    var el=Event.element(e);
+    var s=el.innerHTML.replace(/&nbsp;/g,'');
+    if (s=='' || el.className=='ricoCalWeekNum') return;
+    var day=parseInt(s);
+    if (isNaN(day)) return;
+    var d=new Date(this.yearSelected,this.monthSelected,day);
+    var dateStr=d.formatDate(this.options.dateFmt=='ISO8601' ? 'yyyy-mm-dd' : this.options.dateFmt);
+    if (this.returnValue) this.returnValue(dateStr);
+    this.close();
+  },
+
+  open : function(curval) {
+    if (!this.bPageLoaded) return;
+    if (typeof curval=='object') {
+      this.dateSelected  = curval.getDate();
+      this.monthSelected = curval.getMonth();
+      this.yearSelected  = curval.getFullYear();
+    } else if (this.options.dateFmt=='ISO8601') {
+      var d=new Date;
+      d.setISO8601(curval);
+      this.dateSelected  = d.getDate();
+      this.monthSelected = d.getMonth();
+      this.yearSelected  = d.getFullYear();
+    } else if (this.re.exec(curval)) {
+      var aDate=new Array(RegExp.$1,RegExp.$3,RegExp.$5);
+      this.dateSelected  = parseInt(aDate[this.dateParts['dd']], 10);
+      this.monthSelected = parseInt(aDate[this.dateParts['mm']], 10) - 1;
+      this.yearSelected  = parseInt(aDate[this.dateParts['yyyy']], 10);
+    } else {
+      if (curval) alert('ERROR: invalid date passed to calendar ('+curval+')');
+      this.dateSelected  = this.dateNow
+      this.monthSelected = this.monthNow
+      this.yearSelected  = this.yearNow
+    }
+    this.odateSelected=this.dateSelected
+    this.omonthSelected=this.monthSelected
+    this.oyearSelected=this.yearSelected
+    this.constructCalendar();
+    this.openPopup();
+  }
+}
+
+Rico.includeLoaded('ricoCalendar.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoColor.js b/trunk/NP_TrackBack/trackback/js/rico/ricoColor.js
new file mode 100644 (file)
index 0000000..84c3b98
--- /dev/null
@@ -0,0 +1,29 @@
+function attachValueChangeListeners() {
+   $('red').onkeypress   = colorChangedDeffered;
+   $('green').onkeypress = colorChangedDeffered;
+   $('blue').onkeypress  = colorChangedDeffered;
+}
+
+function colorChangedDeffered() {
+  setTimeout( colorChanged, 1 );
+}
+
+function colorChanged() {
+   var red   = Math.min( parseInt($('red').value)   || 0, 255);
+   var green = Math.min( parseInt($('green').value) || 0, 255);
+   var blue  = Math.min( parseInt($('blue').value)  || 0, 255);
+
+   var color = new Rico.Color( red, green, blue );
+
+   var newIllustrateString = "&nbsp;var color = new Rico.Color( ";
+   newIllustrateString += red + ", ";
+   newIllustrateString += green + ", ";
+   newIllustrateString += blue + " ); // color.asHex() = ";
+   newIllustrateString += color.asHex();
+
+   $('rgbCode').innerHTML = newIllustrateString;
+   $('colorBox').style.backgroundColor = color.asHex();
+   //$('colorBox').innerHTML = color.asHex();
+}
+
+Rico.includeLoaded('ricoColor.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoColorPicker.js b/trunk/NP_TrackBack/trackback/js/rico/ricoColorPicker.js
new file mode 100644 (file)
index 0000000..2e93b11
--- /dev/null
@@ -0,0 +1,75 @@
+// ===================================================================
+// Original author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// Adapted to Rico by Matt Brown
+// ===================================================================
+
+
+Rico.ColorPicker = Class.create();
+
+Rico.ColorPicker.prototype = {
+
+  initialize: function(id,options) {
+    this.id=id;
+    this.currentValue = "#FFFFFF";
+    Object.extend(this, new Rico.Popup());
+    Object.extend(this.options, {
+      showColorCode : false,
+      cellsPerRow   : 18,
+      palette       : []
+    });
+    var hexvals=['00','33','66','99','CC','FF'];
+    for (var g=0; g<hexvals.length; g++)
+      for (var r=0; r<hexvals.length; r++)
+        for (var b=0; b<hexvals.length; b++)
+          this.options.palette.push(hexvals[r]+hexvals[g]+hexvals[b]);
+    Object.extend(this.options, options || {});
+  },
+
+  atLoad : function() {
+    this.container=document.createElement("div");
+    this.container.style.display="none"
+    this.container.className='ricoColorPicker';
+    var width = this.options.cellsPerRow;
+    var cp_contents = "<TABLE BORDER='1' CELLSPACING='1' CELLPADDING='0'>";
+    for (var i=0; i<this.options.palette.length; i++) {
+      if ((i % width) == 0) { cp_contents += "<TR>"; }
+      cp_contents += '<TD BGCOLOR="'+this.options.palette[i]+'">&nbsp;</TD>';
+      if ( ((i+1)>=this.options.palette.length) || (((i+1) % width) == 0))
+        cp_contents += "</TR>";
+    }
+    var halfwidth = Math.floor(width/2);
+    if (this.options.showColorCode)
+      cp_contents += "<TR><TD COLSPAN='"+halfwidth+"' ID='colorPickerSelectedColor'>&nbsp;</TD><TD COLSPAN='"+(width-halfwidth)+"' ALIGN='CENTER' ID='colorPickerSelectedColorValue'>#FFFFFF</TD></TR>";
+    else
+      cp_contents += "<TR><TD COLSPAN='"+width+"' ID='colorPickerSelectedColor'>&nbsp;</TD></TR>";
+    cp_contents += "</TABLE>";
+    this.container.innerHTML=cp_contents;
+    document.body.appendChild(this.container);
+    this.setDiv(this.container);
+    this.open=this.openPopup;
+    this.close=this.closePopup;
+    Event.observe(this.container,"mouseover", this.highlightColor.bindAsEventListener(this), false);
+    Event.observe(this.container,"click", this.selectColor.bindAsEventListener(this), false);
+    this.close();
+  },
+
+  selectColor: function(e) {
+    if (this.returnValue) this.returnValue(this.currentValue);
+    this.close();
+  },
+
+  // This function runs when you move your mouse over a color block, if you have a newer browser
+  highlightColor: function(e) {
+    var elem = Event.element(e);
+    if (!elem.tagName || elem.tagName.toLowerCase() != 'td') return;
+    var c=Rico.Color.createColorFromBackground(elem).toString();
+    this.currentValue = c;
+    Element.setStyle('colorPickerSelectedColor',{'background-color':c});
+    d = $("colorPickerSelectedColorValue");
+    if (d) d.innerHTML = c;
+  }
+}
+
+Rico.includeLoaded('ricoColorPicker.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoCommon.js b/trunk/NP_TrackBack/trackback/js/rico/ricoCommon.js
new file mode 100644 (file)
index 0000000..0e6f4ea
--- /dev/null
@@ -0,0 +1,739 @@
+/**
+  *
+  *  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.
+  **/
+
+if (typeof Rico=='undefined')
+  throw("Cannot find the Rico object");
+if (typeof Prototype=='undefined')
+  throw("Rico requires the Prototype JavaScript framework");
+Rico.prototypeVersion = parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1]);
+if (Rico.prototypeVersion < 1.3)
+  throw("Rico requires Prototype JavaScript framework version 1.3 or greater");
+
+/** @singleton */
+var RicoUtil = {
+
+   getDirectChildrenByTag: function(e, tagName) {
+      var kids = new Array();
+      var allKids = e.childNodes;
+      tagName=tagName.toLowerCase();
+      for( var i = 0 ; i < allKids.length ; i++ )
+         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName.toLowerCase() == tagName )
+            kids.push(allKids[i]);
+      return kids;
+   },
+
+   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;
+   },
+
+   getInnerText: function(el) {
+     if (typeof el == "string") return el;
+     if (typeof el == "undefined") { return el };
+     var cs = el.childNodes;
+     var l = cs.length;
+     var str = "";
+     for (var i = 0; i < l; i++) {
+       switch (cs[i].nodeType) {
+         case 1: //ELEMENT_NODE
+           if (Element.getStyle(cs[i],'display')=='none') continue;
+           switch (cs[i].tagName.toLowerCase()) {
+             case 'img':   str += cs[i].alt || cs[i].title || cs[i].src; break;
+             case 'input': if (cs[i].type=='hidden') continue;
+             case 'select':
+             case 'textarea': str += $F(cs[i]) || ''; break;
+             default:      str += this.getInnerText(cs[i]); break;
+           }
+           break;
+         case 3: //TEXT_NODE
+           str += cs[i].nodeValue;
+           break;
+       }
+     }
+     return str;
+   },
+
+   // For Konqueror 3.5, isEncoded must be true
+   getContentAsString: function( parentNode, isEncoded ) {
+      if (isEncoded) return this._getEncodedContent(parentNode);
+      if (typeof parentNode.xml != 'undefined') return this._getContentAsStringIE(parentNode);
+      return this._getContentAsStringMozilla(parentNode);
+   },
+
+   _getEncodedContent: function(parentNode) {
+      if (parentNode.innerHTML) return parentNode.innerHTML;
+      switch (parentNode.childNodes.length) {
+        case 0:  return "";
+        case 1:  return parentNode.firstChild.nodeValue;
+        default: return parentNode.childNodes[1].nodeValue;
+      }
+   },
+
+  _getContentAsStringIE: function(parentNode) {
+     var contentStr = "";
+     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+         var n = parentNode.childNodes[i];
+         if (n.nodeType == 4) {
+             contentStr += n.nodeValue;
+         }
+         else {
+           contentStr += n.xml;
+       }
+     }
+     return contentStr;
+  },
+
+  _getContentAsStringMozilla: function(parentNode) {
+     var xmlSerializer = new XMLSerializer();
+     var contentStr = "";
+     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+          var n = parentNode.childNodes[i];
+          if (n.nodeType == 4) { // CDATA node
+              contentStr += n.nodeValue;
+          }
+          else {
+            contentStr += xmlSerializer.serializeToString(n);
+        }
+     }
+     return contentStr;
+  },
+
+  docElement: function() {
+    return (document.compatMode && document.compatMode.indexOf("CSS")!=-1) ? document.documentElement : document.getElementsByTagName("body")[0];
+  },
+
+/**
+ * return available height - excludes scrollbar & margin
+ */
+  windowHeight: function() {
+    return window.innerHeight? window.innerHeight : this.docElement().clientHeight;
+    //return this.docElement().clientHeight;
+  },
+
+/**
+ * return available width - excludes scrollbar & margin
+ */
+  windowWidth: function() {
+    return this.docElement().clientWidth;
+  },
+
+  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;
+  },
+
+  nan2zero: function(n) {
+    if (typeof(n)=='string') n=parseInt(n);
+    return isNaN(n) || typeof(n)=='undefined' ? 0 : n;
+  },
+
+  eventKey: function(e) {
+    if( typeof( e.keyCode ) == 'number'  ) {
+      return e.keyCode; //DOM
+    } else if( typeof( e.which ) == 'number' ) {
+      return e.which;   //NS 4 compatible
+    } else if( typeof( e.charCode ) == 'number'  ) {
+      return e.charCode; //also NS 6+, Mozilla 0.9+
+    }
+    return -1;  //total failure, we have no way of obtaining the key code
+  },
+
+/**
+ * Return the previous sibling that has the specified tagName
+ */
+   getPreviosSiblingByTagName: function(el,tagName) {
+       var sib=el.previousSibling;
+       while (sib) {
+               if ((sib.tagName==tagName) && (sib.style.display!='none')) return sib;
+               sib=sib.previousSibling;
+       }
+       return null;
+   },
+
+/**
+ * Return the parent HTML element that has the specified tagName.
+ * @param className optional
+ */
+   getParentByTagName: function(el,tagName,className) {
+       var par=el;
+       tagName=tagName.toLowerCase();
+       while (par) {
+               if (par.tagName && par.tagName.toLowerCase()==tagName)
+        if (!className || par.className.indexOf(className)>=0) return par;
+               par=par.parentNode;
+       }
+       return null;
+   },
+
+/**
+ * Wrap the children of a DOM element in a new element
+ * @param el the element whose children are to be wrapped
+ * @param cls class name of the wrapper (optional)
+ * @param id id of the wrapper (optional)
+ * @param wrapperTag type of wrapper element to be created (optional, defaults to DIV)
+ */
+  wrapChildren: function(el,cls,id,wrapperTag) {
+    var tag=wrapperTag || 'div';
+    var wrapper = document.createElement(tag);
+    if (id) wrapper.id=id;
+    if (cls) wrapper.className=cls;
+    while (el.firstChild)
+      wrapper.appendChild(el.firstChild);
+    el.appendChild(wrapper);
+    return wrapper;
+  },
+
+/**
+ * Format a positive number
+ * @param decPlaces the number of digits to display after the decimal point
+ * @param thouSep the character to use as the thousands separator
+ * @param decPoint the character to use as the decimal point
+ */
+  formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) {
+    var a=posnum.toFixed(decPlaces).split(/\./);
+    if (thouSep) {
+      var rgx = /(\d+)(\d{3})/;
+      while (rgx.test(a[0]))
+        a[0]=a[0].replace(rgx, '$1'+thouSep+'$2');
+    }
+    return a.join(decPoint);
+  },
+
+/**
+ * Post condition - if childNodes[n] is refChild, than childNodes[n+1] is newChild.
+ */
+  DOMNode_insertAfter: function(newChild,refChild) {
+    var parentx=refChild.parentNode;
+    if(parentx.lastChild==refChild) { return parentx.appendChild(newChild);}
+    else {return parentx.insertBefore(newChild,refChild.nextSibling);}
+  },
+
+  positionCtlOverIcon: function(ctl,icon) {
+    if (ctl.style.display=='none') ctl.style.display='block';
+    var offsets=Position.page(icon);
+    var correction=Prototype.Browser.IE ? 1 : 2;  // based on a 1px border
+    var lpad=this.nan2zero(Element.getStyle(icon,'padding-left'))
+    ctl.style.left = (offsets[0]+lpad+correction)+'px';
+    var scrTop=this.docScrollTop();
+    var newTop=offsets[1] + correction + scrTop;
+    var ctlht=ctl.offsetHeight;
+    var iconht=icon.offsetHeight;
+    if (newTop+iconht+ctlht < this.windowHeight()+scrTop)
+      newTop+=iconht;  // display below icon
+    else
+      newTop=Math.max(newTop-ctlht,scrTop);  // display above icon
+    ctl.style.top = newTop+'px';
+  },
+
+  createFormField: function(parent,elemTag,elemType,id,name) {
+    if (typeof name!='string') name=id;
+    if (Prototype.Browser.IE) {
+      // IE cannot set NAME attribute on dynamically created elements
+      var s=elemTag+' id="'+id+'"';
+      if (elemType) s+=' type="'+elemType+'"';
+      if (elemTag.match(/^(form|input|select|textarea|object|button|img)$/)) s+=' name="'+name+'"';
+      var field=document.createElement('<'+s+' />');
+    } else {
+      var field=document.createElement(elemTag);
+      if (elemType) field.type=elemType;
+      field.id=id;
+      if (typeof field.name=='string') field.name=name;
+    }
+    parent.appendChild(field);
+    return field;
+  },
+
+/**
+ * Gets the value of the specified cookie
+ */
+  getCookie: function(itemName) {
+    var arg = itemName+'=';
+    var alen = arg.length;
+    var clen = document.cookie.length;
+    var i = 0;
+    while (i < clen) {
+      var j = i + alen;
+      if (document.cookie.substring(i, j) == arg) {
+        var endstr = document.cookie.indexOf (';', j);
+        if (endstr == -1) endstr=document.cookie.length;
+        return unescape(document.cookie.substring(j, endstr));
+      }
+      i = document.cookie.indexOf(' ', i) + 1;
+      if (i == 0) break;
+    }
+    return null;
+  },
+
+/**
+ * Write information to cookie.
+ * For cookies to be retained for the current session only, set daysToKeep=null.
+ * To erase a cookie, pass a negative daysToKeep value.
+ */
+  setCookie: function(itemName,itemValue,daysToKeep,cookiePath,cookieDomain) {
+       var c = itemName+"="+escape(itemValue);
+       if (typeof(daysToKeep)=='number') {
+               var date = new Date();
+               date.setTime(date.getTime()+(daysToKeep*24*60*60*1000));
+               c+="; expires="+date.toGMTString();
+       }
+       if (typeof(cookiePath)=='string') c+="; path="+cookiePath;
+       if (typeof(cookieDomain)=='string') c+="; domain="+cookieDomain;
+    document.cookie = c;
+  }
+
+};
+
+
+// Translation helper object
+/** @singleton */
+var RicoTranslate = {
+  phrases : {},
+  thouSep : ",",
+  decPoint: ".",
+  langCode: "en",
+  re      : /^(\W*)\b(.*)\b(\W*)$/,
+  dateFmt : "mm/dd/yyyy",
+  timeFmt : "hh:nn:ss a/pm",
+  monthNames: ['January','February','March','April','May','June',
+               'July','August','September','October','November','December'],
+  dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
+
+  addPhrase: function(fromPhrase, toPhrase) {
+    this.phrases[fromPhrase]=toPhrase;
+  },
+
+/**
+ * fromPhrase may contain multiple words/phrases separated by tabs
+ * and each portion will be looked up separately.
+ * Punctuation & spaces at the beginning or
+ * ending of a phrase are ignored.
+ */
+  getPhrase: function(fromPhrase) {
+    var words=fromPhrase.split(/\t/);
+    var transWord,translated = '';
+    for (var i=0; i<words.length; i++) {
+      if (this.re.exec(words[i])) {
+        transWord=this.phrases[RegExp.$2];
+        translated += (typeof transWord=='string') ? RegExp.$1+transWord+RegExp.$3 : words[i];
+      } else {
+        translated += words[i];
+      }
+    }
+    return translated;
+  }
+}
+
+
+if (!Date.prototype.formatDate) {
+  Date.prototype.formatDate = function(fmt) {
+    var d=this;
+    var datefmt=(typeof fmt=='string') ? datefmt=fmt : 'translateDate';
+    switch (datefmt) {
+      case 'locale':
+      case 'localeDateTime':
+        return d.toLocaleString();
+      case 'localeDate':
+        return d.toLocaleDateString();
+      case 'translate':
+      case 'translateDateTime':
+        datefmt=RicoTranslate.dateFmt+' '+RicoTranslate.timeFmt;
+        break;
+      case 'translateDate':
+        datefmt=RicoTranslate.dateFmt;
+        break;
+    }
+    return datefmt.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
+      function($1) {
+        switch ($1.toLowerCase()) {
+        case 'yyyy': return d.getFullYear();
+        case 'mmmm': return RicoTranslate.monthNames[d.getMonth()];
+        case 'mmm':  return RicoTranslate.monthNames[d.getMonth()].substr(0, 3);
+        case 'mm':   return (d.getMonth() + 1).toPaddedString(2);
+        case 'm':    return (d.getMonth() + 1);
+        case 'dddd': return RicoTranslate.dayNames[d.getDay()];
+        case 'ddd':  return RicoTranslate.dayNames[d.getDay()].substr(0, 3);
+        case 'dd':   return d.getDate().toPaddedString(2);
+        case 'd':    return d.getDate();
+        case 'hh':   return ((h = d.getHours() % 12) ? h : 12).toPaddedString(2);
+        case 'h':    return ((h = d.getHours() % 12) ? h : 12);
+        case 'HH':   return d.getHours().toPaddedString(2);
+        case 'H':    return d.getHours();
+        case 'nn':   return d.getMinutes().toPaddedString(2);
+        case 'ss':   return d.getSeconds().toPaddedString(2);
+        case 'a/p':  return d.getHours() < 12 ? 'a' : 'p';
+        }
+      }
+    );
+  }
+}
+
+if (!Date.prototype.setISO8601) {
+/**
+ * Converts a string in ISO 8601 format to a date object.
+ * Returns true if string is a valid date or date-time.
+ * Based on info at http://delete.me.uk/2005/03/iso8601.html
+ */
+  Date.prototype.setISO8601 = function (string) {
+    if (!string) return false;
+    var d = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/);
+    if (!d) return false;
+    var offset = 0;
+    var date = new Date(d[1], 0, 1);
+
+    if (d[2]) { date.setMonth(d[2] - 1); }
+    if (d[3]) { date.setDate(d[3]); }
+    if (d[4]) { date.setHours(d[4]); }
+    if (d[5]) { date.setMinutes(d[5]); }
+    if (d[6]) { date.setSeconds(d[6]); }
+    if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
+    if (d[8]) {
+        if (d[10] && d[11]) offset = (Number(d[10]) * 60) + Number(d[11]);
+        offset *= ((d[9] == '-') ? 1 : -1);
+        offset -= date.getTimezoneOffset();
+    }
+    var time = (Number(date) + (offset * 60 * 1000));
+    this.setTime(Number(time));
+    return true;
+  }
+}
+
+if (!Date.prototype.toISO8601String) {
+/**
+ * Convert date to an ISO 8601 formatted string.
+ * <p>format is an integer in the range 1-6:<dl>
+ * <dt>1 (year)</dt>
+ *   <dd>YYYY (eg 1997)</dd>
+ * <dt>2 (year and month)</dt>
+ *   <dd>YYYY-MM (eg 1997-07)</dd>
+ * <dt>3 (complete date)</dt>
+ *   <dd>YYYY-MM-DD (eg 1997-07-16)</dd>
+ * <dt>4 (complete date plus hours and minutes)</dt>
+ *   <dd>YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)</dd>
+ * <dt>5 (complete date plus hours, minutes and seconds)</dt>
+ *   <dd>YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)</dd>
+ * <dt>6 (complete date plus hours, minutes, seconds and a decimal
+ *   fraction of a second)</dt>
+ *   <dd>YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)</dd>
+ *</dl>
+ * Based on: http://www.codeproject.com/jscript/dateformat.asp
+ */
+  Date.prototype.toISO8601String = function (format, offset) {
+    if (!format) { var format = 6; }
+    if (!offset) {
+        var offset = 'Z';
+        var date = this;
+    } else {
+        var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
+        var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
+        offsetnum *= ((d[1] == '-') ? -1 : 1);
+        var date = new Date(Number(Number(this) + (offsetnum * 60000)));
+    }
+
+    var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }
+
+    var str = "";
+    str += date.getUTCFullYear();
+    if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
+    if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
+    if (format > 3) {
+        str += "T" + zeropad(date.getUTCHours()) +
+               ":" + zeropad(date.getUTCMinutes());
+    }
+    if (format > 5) {
+        var secs = Number(date.getUTCSeconds() + "." +
+                   ((date.getUTCMilliseconds() < 100) ? '0' : '') +
+                   zeropad(date.getUTCMilliseconds()));
+        str += ":" + zeropad(secs);
+    } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }
+
+    if (format > 3) { str += offset; }
+    return str;
+  }
+}
+
+if (!String.prototype.formatDate) {
+  String.prototype.formatDate = function(fmt) {
+    var s=this.replace(/-/g,'/');
+    var d = new Date(s);
+    return isNaN(d) ? this : d.formatDate(fmt);
+  }
+}
+
+if (!Number.prototype.formatNumber) {
+/**
+ * Format a number according to the specs in assoc array 'fmt'.
+ * Result is a string, wrapped in a span element with a class of: negNumber, zeroNumber, posNumber
+ * These classes can be set in CSS to display negative numbers in red, for example.
+ *
+ * <p>fmt may contain:<dl>
+ *   <dt>multiplier </dt><dd> the original number is multiplied by this amount before formatting</dd>
+ *   <dt>decPlaces  </dt><dd> number of digits to the right of the decimal point</dd>
+ *   <dt>decPoint   </dt><dd> character to be used as the decimal point</dd>
+ *   <dt>thouSep    </dt><dd> character to use as the thousands separator</dd>
+ *   <dt>prefix     </dt><dd> string added to the beginning of the result (e.g. a currency symbol)</dd>
+ *   <dt>suffix     </dt><dd> string added to the end of the result (e.g. % symbol)</dd>
+ *   <dt>negSign    </dt><dd> specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens</dd>
+ *</dl>
+ */
+  Number.prototype.formatNumber = function(fmt) {
+    if (isNaN(this)) return 'NaN';
+    var n=this;
+    if (typeof fmt.multiplier=='number') n*=fmt.multiplier;
+    var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0;
+    var thouSep=typeof fmt.thouSep=='string' ? fmt.thouSep : RicoTranslate.thouSep;
+    var decPoint=typeof fmt.decPoint=='string' ? fmt.decPoint : RicoTranslate.decPoint;
+    var prefix=fmt.prefix || "";
+    var suffix=fmt.suffix || "";
+    var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L";
+    negSign=negSign.toUpperCase();
+    var s,cls;
+    if (n<0.0) {
+      s=RicoUtil.formatPosNumber(-n,decPlaces,thouSep,decPoint);
+      if (negSign=="P") s="("+s+")";
+      s=prefix+s;
+      if (negSign=="L") s="-"+s;
+      if (negSign=="T") s+="-";
+      cls='negNumber';
+    } else {
+      cls=n==0.0 ? 'zeroNumber' : 'posNumber';
+      s=prefix+RicoUtil.formatPosNumber(n,decPlaces,thouSep,decPoint);
+    }
+    return "<span class='"+cls+"'>"+s+suffix+"</span>";
+  }
+}
+
+if (!String.prototype.formatNumber) {
+/**
+ * Take a string that can be converted via parseFloat
+ * and format it according to the specs in assoc array 'fmt'.
+ */
+  String.prototype.formatNumber = function(fmt) {
+    var n=parseFloat(this);
+    return isNaN(n) ? this : n.formatNumber(fmt);
+  }
+}
+
+/**
+ * Fix select control bleed-thru on floating divs in IE.
+ * Based on technique published by Joe King at:
+ * http://dotnetjunkies.com/WebLog/jking/archive/2003/10/30/2975.aspx
+ */
+Rico.Shim = Class.create();
+
+if (Prototype.Browser.IE) {
+  Rico.Shim.prototype = {
+
+    initialize: function(DivRef) {
+      this.ifr = document.createElement('iframe');
+      this.ifr.style.position="absolute";
+      this.ifr.style.display = "none";
+      this.ifr.src="javascript:false;";
+      DivRef.parentNode.appendChild(this.ifr);
+      this.DivRef=DivRef;
+    },
+
+    hide: function() {
+      this.ifr.style.display = "none";
+    },
+
+    show: function() {
+      this.ifr.style.width   = this.DivRef.offsetWidth;
+      this.ifr.style.height  = this.DivRef.offsetHeight;
+      this.ifr.style.top     = this.DivRef.style.top;
+      this.ifr.style.left    = this.DivRef.style.left;
+      this.ifr.style.zIndex  = this.DivRef.currentStyle.zIndex - 1;
+      this.ifr.style.display = "block";
+    }
+  }
+} else {
+  Rico.Shim.prototype = {
+    initialize: function() {},
+    hide: function() {},
+    show: function() {}
+  }
+}
+
+
+/**
+ * Rico.Shadow is intended for positioned elements.
+ * Uses blur filter in IE, and alpha-transparent png images for all other browsers.
+ * Based on: http://www.positioniseverything.net/articles/dropshadows.html
+ */
+Rico.Shadow = Class.create();
+
+Rico.Shadow.prototype = {
+
+  initialize: function(DivRef) {
+    this.div = document.createElement('div');
+    this.div.style.position="absolute";
+    if (typeof this.div.style.filter=='undefined') {
+      new Image().src = Rico.imgDir+"shadow.png";
+      new Image().src = Rico.imgDir+"shadow_ur.png";
+      new Image().src = Rico.imgDir+"shadow_ll.png";
+      this.createShadow();
+      this.offset=5;
+    } else {
+      this.div.style.backgroundColor='#888';
+      this.div.style.filter='progid:DXImageTransform.Microsoft.Blur(makeShadow=1, shadowOpacity=0.3, pixelRadius=3)';
+      this.offset=0; // MS blur filter already does offset
+    }
+    this.div.style.display = "none";
+    DivRef.parentNode.appendChild(this.div);
+    this.DivRef=DivRef;
+  },
+
+  createShadow: function() {
+    var tab = document.createElement('table');
+    tab.style.height='100%';
+    tab.style.width='100%';
+    tab.cellSpacing=0;
+    tab.dir='ltr';
+
+    var tr1=tab.insertRow(-1);
+    tr1.style.height='8px';
+    var td11=tr1.insertCell(-1);
+    td11.style.width='8px';
+    var td12=tr1.insertCell(-1);
+    td12.style.background="transparent url("+Rico.imgDir+"shadow_ur.png"+") no-repeat right bottom"
+
+    var tr2=tab.insertRow(-1);
+    var td21=tr2.insertCell(-1);
+    td21.style.background="transparent url("+Rico.imgDir+"shadow_ll.png"+") no-repeat right bottom"
+    var td22=tr2.insertCell(-1);
+    td22.style.background="transparent url("+Rico.imgDir+"shadow.png"+") no-repeat right bottom"
+
+    this.div.appendChild(tab);
+  },
+
+  hide: function() {
+    this.div.style.display = "none";
+  },
+
+  show: function() {
+    this.div.style.width = this.DivRef.offsetWidth + 'px';
+    this.div.style.height= this.DivRef.offsetHeight + 'px';
+    this.div.style.top   = (parseInt(this.DivRef.style.top)+this.offset)+'px';
+    this.div.style.left  = (parseInt(this.DivRef.style.left)+this.offset)+'px';
+    this.div.style.zIndex= parseInt(Element.getStyle(this.DivRef,'z-index')) - 1;
+    this.div.style.display = "block";
+  }
+}
+
+
+Rico.Popup = Class.create();
+
+Rico.Popup.prototype = {
+
+  initialize: function(options,DivRef) {
+    this.options = {
+      hideOnEscape  : true,
+      hideOnClick   : true,
+      ignoreClicks  : false,
+      position      : 'absolute',
+      shadow        : true
+    }
+    Object.extend(this.options, options || {});
+    if (DivRef) this.setDiv(DivRef);
+  },
+
+  setDiv: function(DivRef,closeFunc) {
+    this.divPopup=$(DivRef);
+    var position=this.options.position == 'auto' ? Element.getStyle(this.divPopup,'position').toLowerCase() : this.options.position;
+    if (!this.divPopup || position != 'absolute') return;
+    this.closeFunc=closeFunc || this.closePopup.bindAsEventListener(this);
+    this.shim=new Rico.Shim(this.divPopup);
+    if (this.options.shadow)
+      this.shadow=new Rico.Shadow(this.divPopup);
+    if (this.options.hideOnClick)
+      Event.observe(document,"click", this.closeFunc);
+    if (this.options.hideOnEscape)
+      Event.observe(document,"keyup", this._checkKey.bindAsEventListener(this));
+    if (this.options.ignoreClicks) this.ignoreClicks();
+  },
+  
+  ignoreClicks: function() {
+    Event.observe(this.divPopup,"click", this._ignoreClick.bindAsEventListener(this));
+  },
+
+  _ignoreClick: function(e) {
+    if (e.stopPropagation)
+      e.stopPropagation();
+    else
+      e.cancelBubble = true;
+    return true;
+  },
+  
+  // event handler to process keyup events (hide menu on escape key)
+  _checkKey: function(e) {
+    if (RicoUtil.eventKey(e)==27) this.closeFunc();
+    return true;
+  },
+
+  openPopup: function(left,top) {
+    if (typeof left=='number') this.divPopup.style.left=left+'px';
+    if (typeof top=='number') this.divPopup.style.top=top+'px';
+    this.divPopup.style.display="block";
+    if (this.shim) this.shim.show();
+    if (this.shadow) this.shadow.show();
+  },
+
+  closePopup: function() {
+    if (this.shim) this.shim.hide();
+    if (this.shadow) this.shadow.hide();
+    this.divPopup.style.display="none"
+  }
+
+}
+
+Rico.includeLoaded('ricoCommon.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoComponents.js b/trunk/NP_TrackBack/trackback/js/rico/ricoComponents.js
new file mode 100644 (file)
index 0000000..1db5830
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+  *  (c) 2005-2007 Matt Brown (http://dowdybrown.com)
+  *
+  *  Rico is 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
+  **/
+  
+
+Rico.ContentTransitionBase = function() {}
+Rico.ContentTransitionBase.prototype = {
+       initialize: function(titles, contents, options) { 
+    if (typeof titles == 'string')
+      titles = $$(titles)
+    if (typeof contents == 'string')
+      contents = $$(contents)
+         
+         this.titles = titles;
+         this.contents = contents;
+               this.options = Object.extend({
+                       duration:200, 
+                       steps:8,
+                       rate:Rico.Effect.easeIn
+         }, options || {});
+         this.hoverSet = new Rico.HoverSet(titles, options);
+               contents.each(function(p){ if (p) Element.hide(p)})
+         this.selectionSet = new Rico.SelectionSet(titles, Object.extend(this.options, {onSelect: this.select.bind(this)}));
+               if (this.initContent) this.initContent();
+       },
+       reset: function(){
+         this.selectionSet.reset();
+       },
+       select: function(title) {
+         if ( this.selected == this.contentOf(title)) return
+               var panel = this.contentOf(title); 
+               if (this.transition){
+                       if (this.selected){
+                         var effect = this.transition(panel)
+                         if (effect) Rico.animate(effect, this.options)
+      }
+                       else
+                               Element.show(panel);
+               }else{
+                       if (this.selected)
+                               Element.hide(this.selected)
+                       Element.show(panel);
+               }
+               this.selected = panel;
+       },
+       add: function(title, content){
+               this.titles.push(title);
+               this.contents.push(content);
+               this.hoverSet.add(title);
+               this.selectionSet.add(title);   
+               this.selectionSet.select(title);
+       },
+       remove: function(title){},
+       removeAll: function(){
+               this.hoverSet.removeAll();
+               this.selectionSet.removeAll();
+       },
+       openByIndex: function(index){this.selectionSet.selectIndex(index)},
+       contentOf: function(title){ return this.contents[this.titles.indexOf(title)]}
+}
+
+Rico.ContentTransition = Class.create();
+Rico.ContentTransition.prototype = Object.extend(new Rico.ContentTransitionBase(),{});
+
+Rico.SlidingPanel = Class.create();
+Rico.SlidingPanel.prototype = {
+       initialize: function(panel) {
+               this.panel = panel;
+               this.options = arguments[1] || {};
+               this.closed = true;
+               this.showing = false
+               this.openEffect = this.options.openEffect;
+               this.closeEffect = this.options.closeEffect;
+               this.animator = new Rico.Effect.Animator();
+               Element.makeClipping(this.panel)
+       },
+       toggle: function () {
+               if(!this.showing){
+                       this.open();
+               } else { 
+                       this.close();
+    }
+       },
+       open: function () {
+         if (this.closed){
+           this.showing = true;
+                 Element.show(this.panel);
+               this.options.disabler.disableNative();
+    }
+               /*this.animator.stop();*/
+               this.animator.play(this.openEffect,
+                                                                                       { onFinish:function(){ Element.undoClipping($(this.panel))}.bind(this),
+                                                                                               rate:Rico.Effect.easeIn});
+       },
+       close: function () {
+               Element.makeClipping(this.panel)
+               this.animator.stop();
+               this.showing = false;
+               this.animator.play(this.closeEffect,
+                            { onFinish:function(){  Element.hide(this.panel);  
+                                                                                                                                                                                       this.options.disabler.enableNative()}.bind(this),       
+                                                                                               rate:Rico.Effect.easeOut});
+       }
+}
+
+
+//-------------------------------------------
+// Example components
+//-------------------------------------------
+
+Rico.Accordion = Class.create();
+Rico.Accordion.prototype = Object.extend(new Rico.ContentTransitionBase(), {
+  initContent: function() { 
+               this.selected.style.height = this.options.panelHeight + "px";
+       },
+  transition: function(p){ 
+    if (!this.options.noAnimate)
+                 return new Rico.AccordionEffect(this.selected, p, this.options.panelHeight);
+    else{
+      p.style.height = this.options.panelHeight + "px";
+      if (this.selected) Element.hide(this.selected);
+               Element.show(p);
+    }
+       }
+})
+
+
+Rico.TabbedPanel = Class.create();
+Rico.TabbedPanel.prototype = Object.extend(new Rico.ContentTransitionBase(), {
+  initContent: function() { 
+               if (false && (this.options.panelHeight=='auto' || this.options.panelWidth=='auto')) {
+                 // 'auto' is not working yet
+                 var maxwi=0, maxht=0;
+                 for (var i=0; i<this.contents.length; i++) {
+                   var d=Element.getDimensions(this.contents[i]);
+                   maxwi=Math.max(maxwi,d.width);
+                   maxht=Math.max(maxht,d.height);
+                 }
+                 //alert('maxwi='+maxwi+' maxht='+maxht);
+                 if (this.options.panelWidth=='auto') this.options.panelWidth=maxwi;
+                 if (this.options.panelHeight=='auto') this.options.panelHeight=maxht;
+               }
+         if (typeof this.options.panelWidth=='number') this.options.panelWidth+="px";
+         if (typeof this.options.panelHeight=='number') this.options.panelHeight+="px";
+    if (Rico.Corner) {
+      this.options.color='transparent';
+      this.options.corners='top';
+      for (var i=0; i<this.titles.length; i++)
+        if (this.titles[i]) {
+          if (this.options.panelHdrWidth) this.titles[i].style.width=this.options.panelHdrWidth;
+          Rico.Corner.round(this.titles[i], this.options);
+        }
+    }
+               this.transition(this.selected);
+       },
+  transition: function(p){ 
+    if (this.selected) Element.hide(this.selected);
+               Element.show(p);
+    if (this.options.panelHeight) p.style.height = this.options.panelHeight;
+    if (this.options.panelWidth) p.style.width = this.options.panelWidth;
+       }
+})
+
+
+Rico.SlidingPanel.top = function(panel, innerPanel){
+       var options = Object.extend({
+               disabler: Rico.Controls.defaultDisabler
+  }, arguments[2] || {});
+       var height = options.height || Element.getDimensions(innerPanel)[1] || innerPanel.offsetHeight;
+       var top = options.top || Position.positionedOffset(panel)[1];
+       options.openEffect = new Rico.Effect.SizeFromTop(panel, innerPanel, top, height, {baseHeight:height});
+       options.closeEffect = new Rico.Effect.SizeFromTop(panel, innerPanel, top, 1, {baseHeight:height});
+  panel.style.height = "0px";
+       innerPanel.style.top = -height + "px";  
+       return new Rico.SlidingPanel(panel, options);
+}
+
+Rico.SlidingPanel.bottom = function(panel){
+       var options = Object.extend({
+               disabler: Rico.Controls.blankDisabler
+  }, arguments[1] || {});
+       var height = options.height || Element.getDimensions(panel).height;
+       var top = Position.positionedOffset(panel)[1];
+       options.openEffect = new Rico.Effect.SizeFromBottom(panel, top - height, height);
+       options.closeEffect = new Rico.Effect.SizeFromBottom(panel, top, 1);
+       return new Rico.SlidingPanel(panel, options); 
+}
+
+Rico.includeLoaded('ricoComponents.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoDashboard.js b/trunk/NP_TrackBack/trackback/js/rico/ricoDashboard.js
new file mode 100644 (file)
index 0000000..17cc5a7
--- /dev/null
@@ -0,0 +1,329 @@
+
+Rico.Dashboard = Class.create();
+Rico.Dashboard.prototype = {
+       initialize: function(dashboardId, columnCount, options) {
+               this.dashboardDiv = $(dashboardId);
+               this.numCol = columnCount;
+               this.options = options || [];
+               this.cols = new Array(); 
+               this.insertionOutline = document.createElement("div");
+               this.insertionOutline.id = "insertionOutline";
+     
+               //get panels before adding collumns
+               var dashboard = this
+   this.panelList = [];
+   // this.panelList = parsePanels(this.dashboardDiv, function(title, content, panel)
+  //                                 { return new Rico.DashboardPanel(title, content, panel, dashboard);})
+               var colSizes = this.options.columnSizes 
+    if (!colSizes){
+      colSizes = [];
+      for(var i=0; i<this.numCol; i++)
+        colSizes[i] = 100 / columnCount;
+    }
+
+               for(var i=0; i< this.numCol;i++)        {
+          var newColDiv = document.createElement("div");
+          newColDiv.style.width = colSizes[i] + "%";
+          newColDiv.style.minHeight = "1px";
+          newColDiv.className = "column";
+          newColDiv.id = "" + (i+1) ;
+          this.cols.push(newColDiv);
+          this.dashboardDiv.appendChild(newColDiv);
+          //if (i < this.numCol-1){
+         //    var borderDiv = document.createElement("div");
+         //    borderDiv.style.width = "3px";
+         //    borderDiv.style.height = "100%";
+         //    borderDiv.style.background = "111111"
+         //    borderDiv.className = "border";
+         //    //borderDiv.style.visibility = "visible";
+         //    this.dashboardDiv.appendChild(borderDiv);
+         // }
+               }
+      //now add the panels to the columns
+    for (var i=0; i< this.panelList.length; i++) {
+         var panel = this.panelList[i];                
+         this._addToCol(panel, panel.panelDiv.getAttribute('column'));
+               }
+       },
+       
+       addPanel: function(panel, col){
+         this.panelList.push(panel)
+         this._addToCol(panel, col)
+       },
+       
+       _addToCol: function(panel, col) {
+               panel.addToCol(this.cols[col-1]);         
+       },
+       
+       closeAllPanels: function() {
+         var panels = this.panelList;
+         for (var i=0; i<panels.length; i++)
+           panels[i].close();
+         this.panelList = [];
+       },
+       
+       openAllPanels: function(open) {
+               for (var i=0; i<this.panelList.length; i++) 
+                       this.panelList[i].setVisibility(open);
+       },
+       
+       columnAt: function(x) {
+               for (var i=this.cols.length-1; i >=0; i--)      {
+                       if (x >= Position.positionedOffset(this.cols[i])[0])
+                               return this.cols[i];
+               }
+               return this.cols[0];
+       },
+       
+       destroy: function() {
+               try{
+                       for (var i=0; i<this.panelList.length; i++) {
+                               delete this.panelList[i];
+                               this.panelList[i] = null;
+                       }
+                       delete this;
+               }catch(e){}
+       },
+       
+       dropPanel: function(panel){
+         panel.column.removeChild(panel.panelDiv);
+         panel.column = this.insertionColumn;
+         this.insertionColumn.replaceChild(panel.panelDiv, this.insertionOutline);
+  },
+
+  dragPanel: function(panel, left, top){
+    var newCol = this.columnAt(left + panel.panelDiv.offsetWidth/2);
+
+    if (!newCol) return;  
+    
+               this._moveInsertion(newCol);
+               var panels = this.columnPanels(newCol);
+               var insertPos = this._getInsertionPos(panels);
+
+               if (insertPos != 0 && 
+                   top <= Position.positionedOffset(panels[insertPos-1])[1]) {
+                       this.insertionColumn.removeChild(this.insertionOutline);
+                       newCol.insertBefore(this.insertionOutline, panels[insertPos-1]);
+               }
+               if (insertPos != (panels.length-1) && 
+                   top >= Position.positionedOffset(panels[insertPos+1])[1]) {
+                       if (panels[insertPos + 2]) 
+                                 newCol.insertBefore(this.insertionOutline, panels[insertPos+2]);
+                        else
+                                 newCol.appendChild(this.insertionOutline);
+               }    
+               this.insertionColumn = newCol;
+  },
+
+  _moveInsertion: function(column){
+               if (this.insertionColumn != column) {
+                       this.insertionColumn.removeChild(this.insertionOutline)
+                       this.insertionColumn = column;
+                       column.appendChild(this.insertionOutline);
+       }
+  },
+  
+       columnPanels: function(column){
+                       var panels = [];
+                       for (var i=0; i<column.childNodes.length; i++) {
+                               if (!column.childNodes[i].isDragging)  {
+                                       panels.push(column.childNodes[i]);
+                               }
+                       }
+                       return panels;
+       },
+  
+       _getInsertionPos : function(panels) {
+               for (var i=0; i<panels.length; i++) {
+                       if (panels[i] == this.insertionOutline) 
+                         return i;
+               }
+       },
+       
+       startInsertionOutline: function(panelDiv){
+         this.insertionOutline.style.height = panelDiv.offsetHeight + "px";
+         panelDiv.parentNode.insertBefore(this.insertionOutline, panelDiv);
+         this.insertionColumn = panelDiv.parentNode;
+  }
+}
+
+Rico.PanelCreation = {
+  create: function(title, url, dashboard) {    
+               var panelDiv = document.createElement("div");
+    var titleDiv = PanelCreation.createHeader(title)
+    var contentDiv = PanelCreation.createContent()
+               panelDiv.className = "panel";
+               panelDiv.appendChild(titleDiv);
+               panelDiv.appendChild(contentDiv);       
+       return new Rico.DashboardPanel(titleDiv, contentDiv, panelDiv, dashboard)
+       },
+       createHeader: function(title) {
+               this.panelHeaderDiv = document.createElement("div");
+               this.panelHeaderDiv.className = "panelHeader";
+               this.panelHeaderDiv.innerHTML = document.createTextNode(this.title);
+               initializeHeader(this.panelHeaderDiv);
+               return this.panelHeaderDiv;
+       },
+       createContent: function() {
+               this.panelContentDiv = document.createElement("div");
+               this.panelContentDiv.className = "panelContent";
+               this.panelContentDiv.innerHTML = "Loading";
+               return this.panelContentDiv;
+       }
+}
+
+Rico.DashboardPanel = Class.create();
+Rico.DashboardPanel.prototype = {
+       initialize: function(headerDiv, contentDiv, panelDiv, dashboard) {
+               this.dashboard = dashboard;
+               this.panelHeaderDiv = headerDiv;
+               this.panelContentDiv = contentDiv;
+               this.panelDiv = panelDiv;
+               this.open = true;
+               panelDiv.style.zIndex = 1000;
+               this.initializeHeader(headerDiv);
+       Event.observe(headerDiv, "mousedown", this._startDrag.bind(this));
+  },
+    
+       initializeHeader: function(headerDiv) {
+               headerDiv.onmouseover = this.hover.bind(this);
+               headerDiv.onmouseout = this.unHover.bind(this);
+               
+//             this.visibilityToggleDiv = document.createElement("div");
+//             this.visibilityToggleDiv.className = "visibilityToggle";
+//             this.visibilityToggleDiv.innerHTML = '<img src="/images/bkgd_panel_arrow.png"/>';
+//             this.visibilityToggleDiv.style.visibility = "hidden";
+//             this.visibilityToggleDiv.onmousedown = this.toggleVisibility.bind(this);
+       
+               this.titleDiv = document.createElement("div");
+               this.titleDiv.innerHTML = headerDiv.innerHTML;          
+               this.titleDiv.className = "title";
+               
+               headerDiv.innerHTML = '';
+               
+               this.closeDiv = document.createElement("div");
+               this.closeDiv.className = "close";
+               this.closeDiv.innerHTML = '<img src="/images/icn_close.png" alt="Remove" title="Remove this metric from the report" />';
+               this.closeDiv.style.display = "none";
+               this.closeDiv.onmousedown = this.close.bind(this);    
+               
+//             headerDiv.appendChild(this.visibilityToggleDiv);
+               headerDiv.appendChild(this.closeDiv);
+               headerDiv.appendChild(this.titleDiv);
+       },
+
+       addToCol: function(col, isNew) {
+         this.column  = col;
+               if (isNew && toCol.hasChildNodes())
+                       this.column.insertBefore(this.panelDiv, this.column.firstChild);
+               else
+                       this.column.appendChild(this.panelDiv);
+       },
+       
+       moveToColumn: function(col){
+               if (this.column != col) {
+                       this.column.removeChild(this.panelDiv)
+                       this.column = col;
+                       col.appendChild(this.panelDiv);
+               }
+       },    
+    //this.obj.root.onDragStart(parseInt(panel.panelDiv.style.left), parseInt(pnel.panelDiv.style.top), 
+               //                          event.clientX, event.clientY);
+       _startDrag: function(event) {
+               if (this.dashboard.options.startingDrag)
+                       this.dashboard.options.startingDrag();
+
+               Position.absolutize(this.panelDiv)
+               this.dashboard.startInsertionOutline(this.panelDiv)
+               this.panelDiv.style.opacity = .7;
+               this.panelDiv.style.zIndex = 900;
+               //this.panelDiv.style.width = (parseInt(this.panelDiv.offestWidth)-4)+"px";
+               new DragPanel(this, event);
+               Event.stop(event);
+       },
+       
+       hover: function() {
+//             this.visibilityToggleDiv.style.visibility = "visible";
+               this.closeDiv.show();
+       },
+       
+       unHover: function() {
+//             this.visibilityToggleDiv.style.visibility = "hidden";
+               this.closeDiv.hide();
+       },
+       
+       setVisibility: function(visibility) {
+               if (visibility) {
+                       this.panelDiv.show(); 
+               } else {
+                  this.panelDiv.hide();
+               }
+       },
+       
+       toggleVisibility: function() {
+          this.setVisibility(this.panelContentDiv.style.display =='none');
+       },
+       
+       close: function() {
+    if (this.open)
+                 this.panelDiv.parentNode.removeChild(this.panelDiv);
+                 this.open = false;
+       },
+       
+       show: function() {
+               this.panelContentDiv.show();
+               this.visibilityToggleDiv.firstChild.setAttribute("src", "/images/bkgd_panel_arrow.png");
+       },
+
+       hide: function() {
+               this.panelContentDiv.hide();
+               this.visibilityToggleDiv.firstChild.setAttribute("src", "/images/bkgd_panel_arrow.png");
+       },  
+       
+       drop: function() {
+         this.dashboard.dropPanel(this);
+         
+         this.panelDiv.style.position = "static";
+               //this.panelDiv.style.width = "100%";
+               this.unHover();
+               this.panelDiv.style.opacity = 1;
+               if (this.dashboard.options.endingDrag)
+                       this.dashboard.options.endingDrag();
+       }
+}
+
+DragPanel = Class.create();
+DragPanel.prototype = {
+       initialize : function(panel,event){     
+           this.panel = panel;     
+                       this.lastMouseX = event.clientX;
+                       this.lastMouseY = event.clientY;
+                       this.dragHandler = this.drag.bindAsEventListener(this)
+                       this.dropHandler = this.endDrag.bindAsEventListener(this)
+                       Event.observe(document, "mousemove", this.dragHandler);
+                       Event.observe(document, "mouseup", this.dropHandler);
+                       this.panel.panelDiv.isDragging = true
+       },      
+       drag : function(event){
+
+         panelDiv = this.panel.panelDiv
+               var newLeft = parseInt(panelDiv.style.left) + event.clientX - this.lastMouseX;
+               var newTop = parseInt(panelDiv.style.top) + event.clientY - this.lastMouseY;
+               panelDiv.style.left = newLeft + "px";
+               panelDiv.style.top = newTop + "px";                     
+               this.lastMouseX = event.clientX;
+               this.lastMouseY = event.clientY;
+    this.panel.dashboard.dragPanel(this.panel, newLeft, newTop);
+    Event.stop(event);
+       },
+       endDrag : function(event){                      
+               Event.stopObserving(document, "mousemove", this.dragHandler);
+       Event.stopObserving(document, "mouseup", this.dropHandler);     
+               this.panel.drop();      
+               this.panel.panelDiv.style.zIndex = 1000;
+               this.panel.panelDiv.isDragging = false;
+               Event.stop(event);
+       }
+}
+
+Rico.includeLoaded('ricoDashboard.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoDragDrop.js b/trunk/NP_TrackBack/trackback/js/rico/ricoDragDrop.js
new file mode 100644 (file)
index 0000000..ce4f326
--- /dev/null
@@ -0,0 +1,770 @@
+/**
+  *
+  *  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.
+  **/
+//-------------------- ricoDragAndDrop.js
+Rico.DragAndDrop = Class.create();
+
+Rico.DragAndDrop.prototype = {
+
+   initialize: function() {
+      this.dropZones                = new Array();
+      this.draggables               = new Array();
+      this.currentDragObjects       = new Array();
+      this.dragElement              = null;
+      this.lastSelectedDraggable    = null;
+      this.currentDragObjectVisible = false;
+      this.interestedInMotionEvents = false;
+      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
+      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
+      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
+   },
+
+   registerDropZone: function(aDropZone) {
+      this.dropZones[ this.dropZones.length ] = aDropZone;
+   },
+
+   deregisterDropZone: function(aDropZone) {
+      var newDropZones = new Array();
+      var j = 0;
+      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
+         if ( this.dropZones[i] != aDropZone )
+            newDropZones[j++] = this.dropZones[i];
+      }
+
+      this.dropZones = newDropZones;
+   },
+
+   clearDropZones: function() {
+      this.dropZones = new Array();
+   },
+
+   registerDraggable: function( aDraggable ) {
+      this.draggables[ this.draggables.length ] = aDraggable;
+      this._addMouseDownHandler( aDraggable );
+   },
+
+   clearSelection: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].deselect();
+      this.currentDragObjects = new Array();
+      this.lastSelectedDraggable = null;
+   },
+
+   hasSelection: function() {
+      return this.currentDragObjects.length > 0;
+   },
+
+   setStartDragFromElement: function( e, mouseDownElement ) {
+      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
+      this.startx = e.screenX - this.origPos.x
+      this.starty = e.screenY - this.origPos.y
+      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
+      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
+      //this.adjustedForDraggableSize = false;
+
+      this.interestedInMotionEvents = this.hasSelection();
+      this._terminateEvent(e);
+   },
+
+   updateSelection: function( draggable, extendSelection ) {
+      if ( ! extendSelection )
+         this.clearSelection();
+
+      if ( draggable.isSelected() ) {
+         this.currentDragObjects.removeItem(draggable);
+         draggable.deselect();
+         if ( draggable == this.lastSelectedDraggable )
+            this.lastSelectedDraggable = null;
+      }
+      else {
+         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
+         draggable.select();
+         this.lastSelectedDraggable = draggable;
+      }
+   },
+
+   _mouseDownHandler: function(e) {
+      if ( arguments.length == 0 )
+         e = event;
+
+      // if not button 1 ignore it...
+      var nsEvent = e.which != undefined;
+      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+         return;
+
+      var eventTarget      = e.target ? e.target : e.srcElement;
+      var draggableObject  = eventTarget.draggable;
+
+      var candidate = eventTarget;
+      while (draggableObject == null && candidate.parentNode) {
+         candidate = candidate.parentNode;
+         draggableObject = candidate.draggable;
+      }
+   
+      if ( draggableObject == null )
+         return;
+
+      this.updateSelection( draggableObject, e.ctrlKey );
+
+      // clear the drop zones postion cache...
+      if ( this.hasSelection() )
+         for ( var i = 0 ; i < this.dropZones.length ; i++ )
+            this.dropZones[i].clearPositionCache();
+
+      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
+   },
+
+
+   _mouseMoveHandler: function(e) {
+      var nsEvent = e.which != undefined;
+      if ( !this.interestedInMotionEvents ) {
+         //this._terminateEvent(e);
+         return;
+      }
+
+      if ( ! this.hasSelection() )
+         return;
+
+      if ( ! this.currentDragObjectVisible )
+         this._startDrag(e);
+
+      if ( !this.activatedDropZones )
+         this._activateRegisteredDropZones();
+
+      //if ( !this.adjustedForDraggableSize )
+      //   this._adjustForDraggableSize(e);
+
+      this._updateDraggableLocation(e);
+      this._updateDropZonesHover(e);
+
+      this._terminateEvent(e);
+   },
+
+   _makeDraggableObjectVisible: function(e)
+   {
+      if ( !this.hasSelection() )
+         return;
+
+      var dragElement;
+      if ( this.currentDragObjects.length > 1 )
+         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
+      else
+         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
+
+      // go ahead and absolute position it...
+      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
+/*      if (Element.getStyle(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;
+   },
+   **/
+
+   _leftOffset: function(e) {
+          return e.offsetX ? document.body.scrollLeft : 0
+       },
+
+   _topOffset: function(e) {
+          return e.offsetY ? document.body.scrollTop:0
+       },
+
+               
+   _updateDraggableLocation: function(e) {
+      var dragObjectStyle = this.dragElement.style;
+      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
+      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - 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);
+         Rico.animate(new Rico.Effect.Position( this.dragElement, this.origPos.x, this.origPos.y),
+                      {duration: 200,
+                       steps: 20,
+                       onFinish : this._doCancelDragProcessing.bind(this) } );
+      }
+
+     Event.stopObserving(document.body, "mousemove", this._mouseMove);
+     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
+   },
+
+   _retTrue: function () {
+      return true;
+   },
+
+   _completeDropOperation: function(e) {
+      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
+         if ( this.dragElement.parentNode != null )
+            this.dragElement.parentNode.removeChild(this.dragElement);
+      }
+
+      this._deactivateRegisteredDropZones();
+      this._endDrag();
+      this.clearSelection();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+      this._terminateEvent(e);
+   },
+
+   _doCancelDragProcessing: function() {
+      this._cancelDrag();
+
+        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
+           if ( this.dragElement.parentNode != null )
+              this.dragElement.parentNode.removeChild(this.dragElement);
+
+
+      this._deactivateRegisteredDropZones();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+   },
+
+   _placeDraggableInDropZone: function(e) {
+      var foundDropZone = false;
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
+               this.dropZones[i].hideHover();
+               this.dropZones[i].accept(this.currentDragObjects);
+               foundDropZone = true;
+               break;
+            }
+         }
+      }
+
+      return foundDropZone;
+   },
+
+   _cancelDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].cancelDrag();
+   },
+
+   _endDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].endDrag();
+   },
+
+   _mousePointInDropZone: function( e, dropZone ) {
+
+      var absoluteRect = dropZone.getAbsoluteRect();
+
+      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
+             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
+             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
+             e.clientY  < absoluteRect.bottom + this._topOffset(e);
+   },
+
+   _addMouseDownHandler: function( aDraggable )
+   {
+       htmlElement  = aDraggable.getMouseDownHTMLElement();
+      if ( htmlElement  != null ) { 
+         htmlElement.draggable = aDraggable;
+         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
+         Event.observe(htmlElement, "mousedown", this._mouseDown);
+      }
+   },
+
+   _activateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         var dropZone = this.dropZones[i];
+         if ( dropZone.canAccept(this.currentDragObjects) )
+            dropZone.activate();
+      }
+
+      this.activatedDropZones = true;
+   },
+
+   _deactivateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ )
+         this.dropZones[i].deactivate();
+      this.activatedDropZones = false;
+   },
+
+   _onmousedown: function () {
+     Event.observe(document.body, "mousemove", this._mouseMove);
+     Event.observe(document.body, "mouseup",  this._mouseUp);
+   },
+
+   _terminateEvent: function(e) {
+      if ( e.stopPropagation != undefined )
+         e.stopPropagation();
+      else if ( e.cancelBubble != undefined )
+         e.cancelBubble = true;
+
+      if ( e.preventDefault != undefined )
+         e.preventDefault();
+      else
+         e.returnValue = false;
+   },
+
+
+          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");
+//      this.saveBackground = Element.getStyle(htmlElement,'backgroundColor') || Element.getStyle(htmlElement,'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 (Element.getStyle(theGUI,'position')=='absolute')*/
+         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
+         {
+            theGUI.style.position = "static";
+            theGUI.style.top = "";
+            theGUI.style.top = "";
+         }
+         htmlElement.appendChild(theGUI);
+      }
+   }
+}
+
+RicoUtil = Object.extend(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++ ) {
+         var n = parentNode.childNodes[i];
+         if (n.nodeType == 4) {
+             contentStr += n.nodeValue;
+         }
+         else {
+           contentStr += n.xml;
+       }
+     }
+     return contentStr;
+  },
+
+  _getContentAsStringMozilla: function(parentNode) {
+     var xmlSerializer = new XMLSerializer();
+     var contentStr = "";
+     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
+          var n = parentNode.childNodes[i];
+          if (n.nodeType == 4) { // CDATA node
+              contentStr += n.nodeValue;
+          }
+          else {
+            contentStr += xmlSerializer.serializeToString(n);
+        }
+     }
+     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;
+   }
+});
+
+Rico.includeLoaded('ricoDragDrop.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoEffects.js b/trunk/NP_TrackBack/trackback/js/rico/ricoEffects.js
new file mode 100644 (file)
index 0000000..608bb60
--- /dev/null
@@ -0,0 +1,389 @@
+ /**
+   *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+   *
+   *  Rico is 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
+   **/
+
+Rico.animate = function(effect){
+       new Rico.Effect.Animator().play(effect, arguments[1]);
+}
+
+Rico.Effect = {}
+Rico.Effect.easeIn = function(step){
+  return Math.sqrt(step)
+}
+Rico.Effect.easeOut = function(step){
+  return step*step
+}
+Rico.Stepping = {}
+Rico.Stepping.easeIn = Rico.Effect.easeIn;
+Rico.Stepping.easeOut = Rico.Effect.easeOut;
+
+Rico.Effect.Animator = Class.create();
+Rico.Effect.Animator.prototype = {
+       initialize : function(effect) {
+               this.animateMethod = this.animate.bind(this);
+               this.options = arguments[1] || {};
+               this.stepsLeft = 0;
+               if (!effect) return;
+               this.reset(effect, arguments[1]);
+       },
+       reset: function(effect){
+               this.effect = effect;
+    if (arguments[1]) this.setOptions(arguments[1]);
+               this.stepsLeft = this.options.steps;
+               this.duration = this.options.duration;
+       },
+       setOptions: function(options){
+         this.options = Object.extend({
+                       steps: 10,
+                       duration: 200,
+                       rate: function(steps){ return steps;}
+    }, options|| {});
+       },
+       play: function(effect) {
+         this.setOptions(arguments[1])
+         if (effect)
+         if (effect.step)
+                 this.reset(effect, arguments[1]);
+               else{
+                 $H(effect).keys().each((function(e){
+                   var effectClass = {fadeOut:Rico.Effect.FadeOut}[e];
+                   this.reset(new effectClass(effect[e]));
+                 }).bind(this))                  
+               }
+               this.animate();
+       },
+       stop: function() {
+               this.stepsLeft = this.options.steps;
+       },
+       pause: function() {
+               this.interupt = true;
+       },
+       resume: function() {
+         this.interupt = false;
+         if (this.stepsLeft >0)
+           this.animate();
+       },
+       animate: function() {
+         if (this.interupt)
+           return;
+               if (this.stepsLeft <=0) {
+                       if (this.effect.finish)  this.effect.finish();
+                       if (this.options.onFinish) this.options.onFinish();
+                       return;
+               }
+               if (this.timer)
+                       clearTimeout(this.timer);
+               this.effect.step(this.options.rate(this.stepsLeft));
+               this.startNextStep();
+  },
+       startNextStep: function() {
+               var stepDuration = Math.round(this.duration/this.stepsLeft) ;
+    this.duration -= stepDuration;
+    this.stepsLeft--;
+    this.timer = setTimeout(this.animateMethod, stepDuration);
+       },
+  isPlaying: function(){
+    return this.stepsLeft != 0 && !this.interupt;
+  }
+}
+
+Rico.Effect.Group = Class.create();
+Rico.Effect.Group.prototype = {
+  initialize: function(effects){
+    this.effects = effects;
+  },
+  step: function(stepsToGo){ 
+    this.effects.each(function(e){e.step(stepsToGo)});
+  },
+  finish: function(){
+    this.effects.each(function(e){if (e.finish) e.finish()});
+  }
+}
+
+Rico.Effect.SizeAndPosition = Class.create();
+Rico.Effect.SizeAndPosition.prototype = {
+   initialize: function(element, x, y, w, h) {
+      this.element = $(element);
+      this.x = x || this.element.offsetLeft;
+      this.y = y || this.element.offsetTop;
+      this.w = w || this.element.offsetWidth;
+      this.h = h || this.element.offsetHeight;
+   },
+   step: function(stepsToGo) {  
+                       var left = this.element.offsetLeft + ((this.x - this.element.offsetLeft)/stepsToGo) + "px"
+                       var top = this.element.offsetTop + ((this.y - this.element.offsetTop)/stepsToGo) + "px"
+                       var width = this.element.offsetWidth + ((this.w - this.element.offsetWidth)/stepsToGo) + "px"
+                       var height = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/stepsToGo) + "px"
+      var style = this.element.style;
+                       style.left = left;
+                       style.top = top;
+                       style.width = width;
+                       style.height = height;
+   }
+}
+
+Rico.AccordionEffect = Class.create();
+Rico.AccordionEffect.prototype = {
+  initialize: function(toClose, toOpen, height) {
+    this.toClose   = toClose;
+    this.toOpen    = toOpen;
+/*    if (!navigator.appVersion.match(/\bMSIE\b/)) {*/
+      Element.makeClipping(toOpen);
+      Element.makeClipping(toClose);
+/*    }*/
+    Rico.Controls.disableNativeControls(toClose);
+    Element.show(toOpen);
+    this.toOpen.style.height = "0px";
+    this.endHeight = height;
+  },
+  step: function(framesLeft) {
+     var cHeight = Math.max(1,this.toClose.offsetHeight - parseInt((parseInt(this.toClose.offsetHeight))/framesLeft));
+     var closeHeight = cHeight + "px";
+     var openHeight = (this.endHeight - cHeight) + "px"
+     this.toClose.style.height = closeHeight;
+     this.toOpen.style.height = openHeight;
+  },
+  finish: function(){
+    Element.hide(this.toClose)
+    this.toOpen.style.height = this.endHeight + "px";
+    this.toClose.style.height = "0px";
+/*    if (!navigator.appVersion.match(/\bMSIE\b/)) {*/
+      Element.undoClipping(this.toOpen);
+      Element.undoClipping(this.toClose);
+/*    }*/
+
+               Rico.Controls.enableNativeControls(this.toOpen);
+  }
+};
+
+Rico.Effect.SizeFromBottom = Class.create()
+Rico.Effect.SizeFromBottom.prototype = {
+  initialize: function(element, y, h) {
+    this.element = $(element);
+    this.y = y || this.element.offsetTop;
+    this.h = h || this.element.offsetHeight;
+    this.options  = arguments[3] || {};
+  },
+  step: function(framesToGo) {  
+               var top = this.element.offsetTop + ((this.y - this.element.offsetTop)/framesToGo) + "px"
+               var height = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/framesToGo) + "px"
+    var style = this.element.style;
+               style.height = height;     
+               style.top = top;
+  }
+}
+
+Rico.Effect.Position = Class.create();
+Rico.Effect.Position.prototype = {
+  initialize: function(element, x, y) {
+    this.element = $(element);
+    this.x = x || this.element.offsetLeft;
+    this.destTop = y || this.element.offsetTop;
+  },
+  step: function(stepsToGo) {  
+       var left = this.element.offsetLeft + ((this.x - this.element.offsetLeft)/stepsToGo) + "px"
+       var top = this.element.offsetTop + ((this.destTop - this.element.offsetTop)/stepsToGo) + "px"
+    var style = this.element.style;
+       style.left = left;
+       style.top = top;
+  }
+}
+
+Rico.Effect.FadeTo = Class.create()
+Rico.Effect.FadeTo.prototype = {
+  initialize: function(element, value){
+    this.element = element;
+    this.opacity = Element.getStyle(this.element, 'opacity') || 1.0;
+    this.target = Math.min(value, 1.0);
+  },
+  step: function(framesLeft) {
+    var curOpacity = Element.getStyle(this.element, 'opacity');
+    var newOpacity = curOpacity + (this.target - curOpacity)/framesLeft
+    Rico.Effect.setOpacity(this.element, Math.min(Math.max(0,newOpacity),1.0));
+  }
+}
+
+Rico.Effect.FadeOut = Class.create()
+Rico.Effect.FadeOut.prototype = {
+  initialize: function(element){
+    this.effect = new Rico.Effect.FadeTo(element, 0.0)
+  },
+  step: function(framesLeft) {
+    this.effect.step(framesLeft);
+  }
+}
+
+Rico.Effect.FadeIn = Class.create()
+Rico.Effect.FadeIn.prototype = {
+  initialize: function(element){
+    var options = arguments[1] || {}
+    var startValue = options.startValue || 0
+    Element.setStyle(element, 'opacity', startValue);
+    this.effect = new Rico.Effect.FadeTo(element, 1.0)
+  },
+  step: function(framesLeft) {
+    this.effect.step(framesLeft);
+  }
+}
+
+Rico.Effect.setOpacity= function(element, value) {
+   element.style.filter = "alpha(opacity:"+Math.round(value*100)+")";
+   element.style.opacity = value; 
+}
+
+Rico.Effect.SizeFromTop = Class.create()
+Rico.Effect.SizeFromTop.prototype = {
+  initialize: function(element, scrollElement, y, h) {
+     this.element = $(element);
+     this.h = h || this.element.offsetHeight;
+       //       element.style.top = y;
+     this.scrollElement = scrollElement;
+     this.options  = arguments[4] || {};
+     this.baseHeight = this.options.baseHeight ||  Math.max(this.h, this.element.offsetHeight)
+  },
+  step: function(framesToGo) {  
+    var rawHeight = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/framesToGo);
+               var height = rawHeight + "px"
+               var scroll = (rawHeight - this.baseHeight) + "px";
+               this.scrollElement.style.top = scroll;
+               this.element.style.height = height;     
+  }
+}
+
+
+Rico.Effect.Height = Class.create()
+Rico.Effect.Height.prototype = {
+  initialize: function(element, endHeight) {
+    this.element = element
+               this.endHeight = endHeight
+  },
+  step: function(stepsLeft) {
+    if (this.element.constructor != Array){
+      var height = this.element.offsetHeight + ((this.endHeight - this.element.offsetHeight)/stepsLeft) + "px"
+      this.element.style.height = height;
+    } else {
+      var height = this.element[0].offsetHeight + ((this.endHeight - this.element[0].offsetHeight)/stepsLeft) + "px"
+      this.element.each(function(e){e.style.height = height})
+    }
+  }
+}
+
+Rico.Effect.SizeWidth = Class.create();
+Rico.Effect.SizeWidth.prototype = {
+    initialize: function(element, endWidth) {
+      this.element = element
+                       this.endWidth = endWidth
+    },
+    step: function(stepsLeft) {
+       delta = Math.abs(this.endWidth - parseInt(this.element.offsetWidth))/(stepsLeft);
+       this.element.style.width = (this.element.offsetWidth - delta) + "px";
+    }
+}
+
+//these are to support non Safari browsers and keep controls from bleeding through on absolute positioned element.
+Rico.Controls = {
+       editors: [],
+       scrollSelectors: [],
+       
+       disableNativeControls: function(element) {
+               Rico.Controls.defaultDisabler.disableNative(element);
+  },
+       enableNativeControls: function(element){
+               Rico.Controls.defaultDisabler.enableNative(element);
+       },
+       prepareForSizing: function(element){
+    Element.makeClipping(element)
+    Rico.Controls.disableNativeControls(element)
+  },
+  resetSizing: function(element){
+    Element.undoClipping(element)
+    Rico.Controls.enableNativeControls(element)
+       },
+       registerScrollSelectors: function(selectorSet) {
+         selectorSet.each(function(s){Rico.Controls.scrollSelectors.push(Rico.selector(s))});
+       }
+}
+
+Rico.Controls.Disabler = Class.create();
+Rico.Controls.Disabler.prototype = {
+       initialize: function(){
+               this.options = Object.extend({
+                       excludeSet: [],
+                       hidables: Rico.Controls.editors
+    }, arguments[0] || {});
+       },
+  disableNative: function(element) {
+    if (!(/Konqueror|Safari|KHTML/.test(navigator.userAgent))){
+                       if (!navigator.appVersion.match(/\bMSIE\b/))
+                               this.blockControls(element).each(function(e){Element.makeClipping(e)});
+                       else
+                         this.hidableControls(element).each(function(e){e.disable()});
+    }
+  },
+  enableNative: function(element){
+    if (!(/Konqueror|Safari|KHTML/.test(navigator.userAgent))){
+                       if (!navigator.appVersion.match(/\bMSIE\b/))
+                               this.blockControls(element).each(function(e){Element.undoClipping(e)});
+                       else
+                         this.hidableControls(element).each(function(e){e.enable()});
+    }
+  },
+       blockControls: function(element){
+         try{
+               var includes = [];
+               if (this.options.includeSet)
+                       includes = this.options.includeSet;
+               else{
+                 var selectors = this.options.includeSelectors || Rico.Controls.scrollSelectors;
+                       includes = selectors.map(function(s){return s.findAll(element)}).flatten();
+    }
+               return includes.select(function(e){return (Element.getStyle(e, 'display') != 'none') && !this.options.excludeSet.include(e)}.bind(this));
+  }catch(e) { return []}
+       },
+       hidableControls: function(element){
+               if (element)
+                       return this.options.hidables.select(function(e){return Element.childOf(e, element)});
+               else
+                       return this.options.hidables;
+       }
+}      
+                    
+Rico.Controls.defaultDisabler = new Rico.Controls.Disabler();
+Rico.Controls.blankDisabler = new Rico.Controls.Disabler({includeSet:[],hidables:[]});
+                 
+Rico.Controls.HidableInput = Class.create(); 
+Rico.Controls.HidableInput.prototype = {
+       initialize: function(field, view){      
+               this.field = field;
+               this.view = view;
+               this.enable();
+               Rico.Controls.editors.push(this);
+       },
+       enable: function(){
+               Element.hide(this.view);
+               Element.show(this.field);
+       },
+       disable: function(){
+               this.view.value = $F(this.field);
+               if (this.field.offsetWidth > 1) {
+           this.view.style.width =  parseInt(this.field.offsetWidth)  + "px";
+                 Element.hide(this.field);
+                 Element.show(this.view);
+         }
+       }
+}
+
+
+
+Element.forceRefresh = function(item) {
+  try {
+    var n = document.createTextNode(' ')
+    item.appendChild(n); item.removeChild(n);
+  } catch(e) { }
+};
+
+Rico.includeLoaded('ricoEffects.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoGridCommon.js b/trunk/NP_TrackBack/trackback/js/rico/ricoGridCommon.js
new file mode 100644 (file)
index 0000000..01f7392
--- /dev/null
@@ -0,0 +1,685 @@
+/**
+  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+  *  (c) 2005-2007 Matt Brown (http://dowdybrown.com)
+  *
+  *  Rico is 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
+  **/
+
+
+if(typeof Rico=='undefined') throw("GridCommon requires the Rico JavaScript framework");
+if(typeof RicoUtil=='undefined') throw("GridCommon requires the RicoUtil Library");
+
+
+/**
+ * Define methods that are common to both SimpleGrid and LiveGrid
+ */
+Rico.GridCommon = function() {};
+
+Rico.GridCommon.prototype = {
+
+  baseInit: function() {
+    this.options = {
+      resizeBackground : 'resize.gif',
+      saveColumnInfo   : {width:true, filter:false, sort:false},  // save info in cookies?
+      allowColResize   : true,      // allow user to resize columns
+      windowResize     : true,      // Resize grid on window.resize event? Set to false when embedded in an accordian.
+      click            : null,
+      dblclick         : null,
+      contextmenu      : null,
+      useUnformattedColWidth : true,
+      menuEvent        : 'dblclick',  // event that triggers menus - click, dblclick, contextmenu, or none (no menus)
+      defaultWidth     : 100,   // in the absence of any other width info, columns will be this many pixels wide
+      scrollBarWidth   : 19,    // this is the value used in positioning calculations, it does not actually change the width of the scrollbar
+      minScrollWidth   : 100,   // min scroll area width when width of frozen columns exceeds window width
+      columnSpecs      : []
+    }
+    this.colWidths = new Array();
+    this.hdrCells=new Array();
+    this.headerColCnt=0;
+    this.headerRowIdx=0;
+    this.tabs=new Array(2);
+    this.thead=new Array(2);
+    this.tbody=new Array(2);
+  },
+
+  attachMenuEvents: function() {
+    if (!this.options.menuEvent || this.options.menuEvent=='none') return;
+    this.hideScroll=navigator.userAgent.match(/Macintosh\b.*\b(Firefox|Camino)\b/i) || Prototype.Browser.Opera;
+    this.options[this.options.menuEvent]=this.handleMenuClick.bindAsEventListener(this);
+    if (this.highlightDiv) {
+      switch (this.options.highlightElem) {
+        case 'cursorRow':
+          this.attachMenu(this.highlightDiv);
+          break;
+        case 'cursorCell':
+          for (var i=0; i<2; i++)
+            this.attachMenu(this.highlightDiv[i]);
+          break;
+      }
+    }
+    for (var i=0; i<2; i++)
+      this.attachMenu(this.tbody[i]);
+  },
+
+  attachMenu: function(elem) {
+    if (this.options.click)
+      Event.observe(elem, 'click', this.options.click, false);
+    if (this.options.dblclick) {
+      if (Prototype.Browser.WebKit || Prototype.Browser.Opera)
+        Event.observe(elem, 'click', this.handleDblClick.bindAsEventListener(this), false);
+      else
+        Event.observe(elem, 'dblclick', this.options.dblclick, false);
+    }
+    if (this.options.contextmenu) {
+      if (Prototype.Browser.Opera)
+        Event.observe(elem, 'click', this.handleContextMenu.bindAsEventListener(this), false);
+      else
+        Event.observe(elem, 'contextmenu', this.options.contextmenu, false);
+    }
+  },
+
+  // implement double-click for browsers that don't support a double-click event (e.g. Safari)
+  handleDblClick: function(e) {
+    var elem=Event.element(e);
+    if (this.dblClickElem == elem) {
+      this.options.dblclick(e);
+    } else {
+      this.dblClickElem = elem;
+      this.safariTimer=setTimeout(this.clearDblClick.bind(this),300);
+    }
+  },
+
+  clearDblClick: function() {
+    this.dblClickElem=null;
+  },
+
+  // implement right-click for browsers that don't support contextmenu event (e.g. Opera)
+  // use control-click instead
+  handleContextMenu: function(e) {
+    if( typeof( e.which ) == 'number' )
+      var b = e.which; //Netscape compatible
+    else if( typeof( e.button ) == 'number' )
+      var b = e.button; //DOM
+    else
+      return;
+    if (b==1 && e.ctrlKey)
+      this.options.contextmenu(e);
+  },
+
+  cancelMenu: function() {
+    if (this.menu && this.menu.isVisible()) this.menu.cancelmenu();
+  },
+
+  // gather info from original headings
+  getColumnInfo: function(hdrSrc) {
+    Rico.writeDebugMsg("getColumnInfo start");
+    //alert(hdrSrc.tagName+' '+hdrSrc.id+' len='+hdrSrc.length);
+    if (hdrSrc.length == 0) return;
+    this.headerRowCnt=hdrSrc.length;
+    var colcnt;
+    for (r=0; r<this.headerRowCnt; r++) {
+      var headerRow = hdrSrc[r];
+      var headerCells=headerRow.cells;
+      if (r >= this.hdrCells.length) this.hdrCells[r]=new Array();
+      for (c=0; c<headerCells.length; c++) {
+        var obj={};
+        obj.cell=headerCells[c];
+        obj.colSpan=headerCells[c].colSpan || 1;  // Safari & Konqueror return default colspan of 0
+        if (this.options.useUnformattedColWidth) obj.initWidth=headerCells[c].offsetWidth
+        this.hdrCells[r].push(obj);
+      }
+      if (headerRow.id.slice(-5)=='_main') {
+        colcnt=this.hdrCells[r].length;
+        this.headerRowIdx=r;
+      }
+    }
+    Rico.writeDebugMsg("getColumnInfo end");
+    if (!colcnt) {
+      this.headerRowIdx=this.headerRowCnt-1;
+      colcnt=this.hdrCells[this.headerRowIdx].length
+    }
+    return colcnt;
+  },
+
+  // create column array
+  createColumnArray: function() {
+    this.direction=Element.getStyle(this.outerDiv,'direction').toLowerCase();  // ltr or rtl
+    this.align=this.direction=='rtl' ? ['right','left'] : ['left','right'];
+    //alert(this.direction+' : '+this.align[0]);
+    this.columns = new Array();
+    for (var c=0 ; c < this.headerColCnt; c++) {
+      Rico.writeDebugMsg("createColumnArray: c="+c);
+      var tabidx=c<this.options.frozenColumns ? 0 : 1;
+      this.columns.push(new Rico.TableColumn(this, c, this.hdrCells[this.headerRowIdx][c], tabidx));
+    }
+    this.getCookie();
+  },
+
+  // create div structure
+  createDivs: function() {
+    Rico.writeDebugMsg("createDivs start");
+    this.outerDiv   = this.createDiv("outer");
+    this.scrollDiv  = this.createDiv("scroll",this.outerDiv);
+    this.frozenTabs = this.createDiv("frozenTabs",this.outerDiv);
+    this.innerDiv   = this.createDiv("inner",this.outerDiv);
+    this.resizeDiv  = this.createDiv("resize",this.outerDiv);
+    this.resizeDiv.style.display="none";
+    this.exportDiv  = this.createDiv("export",this.outerDiv);
+    this.exportDiv.style.display="none";
+    //this.frozenTabs.style[this.align[0]]='0px';
+    //this.innerDiv.style[this.align[0]]='0px';
+    Rico.writeDebugMsg("createDivs end");
+  },
+
+  createDiv: function(elemName,elemParent) {
+    var id=this.tableId+"_"+elemName+"Div";
+    newdiv=$(id);
+    if (!newdiv) {
+      var newdiv = document.createElement("div");
+      newdiv.id = id;
+      if (elemParent) elemParent.appendChild(newdiv);
+    }
+    newdiv.className = "ricoLG_"+elemName+"Div";
+    return newdiv;
+  },
+
+  baseSizeDivs: function() {
+    this.setOtherHdrCellWidths();
+    this.tabs[0].style.display=this.options.frozenColumns ? '' : 'none';
+    this.hdrHt=Math.max(RicoUtil.nan2zero(this.thead[0].offsetHeight),this.thead[1].offsetHeight);
+    this.dataHt=Math.max(RicoUtil.nan2zero(this.tbody[0].offsetHeight),this.tbody[1].offsetHeight);
+    this.frzWi=this.borderWidth(this.tabs[0]);
+    var borderWi=this.borderWidth(this.columns[0].dataCell);
+    Rico.writeDebugMsg('baseSizeDivs '+this.tableId+': hdrHt='+this.hdrHt+' dataHt='+this.dataHt);
+    //alert(this.tableId+' frzWi='+this.frzWi+' borderWi='+borderWi);
+    for (var i=0; i<this.options.frozenColumns; i++)
+      if (this.columns[i].visible) this.frzWi+=parseInt(this.columns[i].colWidth)+borderWi;
+    this.scrTabWi=this.borderWidth(this.tabs[1]);
+    for (var i=this.options.frozenColumns; i<this.columns.length; i++)
+      if (this.columns[i].visible) this.scrTabWi+=parseInt(this.columns[i].colWidth)+borderWi;
+    this.scrWi=this.scrTabWi+this.options.scrollBarWidth;
+    var wiLimit=RicoUtil.windowWidth()-this.options.scrollBarWidth-8;
+    if (this.outerDiv.parentNode.clientWidth > 0)
+      wiLimit=Math.min(this.outerDiv.parentNode.clientWidth, wiLimit);
+    var overage=this.frzWi+this.scrWi-wiLimit;
+    Rico.writeDebugMsg('baseSizeDivs '+this.tableId+': scrWi='+this.scrWi+' wiLimit='+wiLimit+' overage='+overage+' clientWidth='+this.outerDiv.parentNode.clientWidth);
+    if (overage > 0 && this.options.frozenColumns < this.columns.length)
+      this.scrWi=Math.max(this.scrWi-overage, this.options.minScrollWidth);
+    this.scrollDiv.style.width=this.scrWi+'px';
+    this.scrollDiv.style.top=this.hdrHt+'px';
+    this.frozenTabs.style.width=this.scrollDiv.style[this.align[0]]=this.innerDiv.style[this.align[0]]=this.frzWi+'px';
+    this.outerDiv.style.width=(this.frzWi+this.scrWi)+'px';
+  },
+
+  borderWidth: function(elem) {
+    return RicoUtil.nan2zero(Element.getStyle(elem,'border-left-width')) + RicoUtil.nan2zero(Element.getStyle(elem,'border-right-width'));
+  },
+
+  setOtherHdrCellWidths: function() {
+    for (var r=0; r<this.hdrCells.length; r++) {
+      if (r==this.headerRowIdx) continue;
+      Rico.writeDebugMsg('setOtherHdrCellWidths: r='+r);
+      var c=i=0;
+      while (i<this.headerColCnt && c<this.hdrCells[r].length) {
+        var hdrcell=this.hdrCells[r][c];
+        var cell=hdrcell.cell;
+        var origSpan=newSpan=hdrcell.colSpan;
+        for (var w=j=0; j<origSpan; j++, i++) {
+          if (this.columns[i].hdrCell.style.display=='none')
+            newSpan--;
+          else if (this.columns[i].hdrColDiv.style.display!='none')
+            w+=parseInt(this.columns[i].colWidth);
+        }
+        if (!hdrcell.hdrColDiv || !hdrcell.hdrCellDiv) {
+          var divs=cell.getElementsByTagName('div');
+          hdrcell.hdrColDiv=(divs.length<1) ? RicoUtil.wrapChildren(cell,'ricoLG_col') : divs[0];
+          hdrcell.hdrCellDiv=(divs.length<2) ? RicoUtil.wrapChildren(hdrcell.hdrColDiv,'ricoLG_cell') : divs[1];
+        }
+        if (newSpan==0) {
+          cell.style.display='none';
+        } else if (w==0) {
+          hdrcell.hdrColDiv.style.display='none';
+          cell.colSpan=newSpan;
+        } else {
+          cell.style.display='';
+          hdrcell.hdrColDiv.style.display='';
+          cell.colSpan=newSpan;
+          hdrcell.hdrColDiv.style.width=w+'px';
+        }
+        c++;
+      }
+    }
+  },
+  
+  cell: function(r,c) {
+    return (0<=c && c<this.columns.length && r>=0) ? this.columns[c].cell(r) : null;
+  },
+
+  availHt: function() {
+    var divPos=Position.page(this.outerDiv);
+    return RicoUtil.windowHeight()-divPos[1]-2*this.options.scrollBarWidth-15;  // allow for scrollbar and some margin
+  },
+
+  handleScroll: function(e) {
+    var newTop=(this.hdrHt-this.scrollDiv.scrollTop)+'px';
+    this.tabs[0].style.top=newTop;
+    this.setHorizontalScroll();
+  },
+
+  setHorizontalScroll: function() {
+    var newLeft=(-this.scrollDiv.scrollLeft)+'px';
+    this.hdrTabs[1].style.left=newLeft;
+  },
+
+  pluginScroll: function() {
+     if (this.scrollPluggedIn) return;
+     Event.observe(this.scrollDiv,"scroll",this.scrollEventFunc, false);
+     this.scrollPluggedIn=true;
+  },
+
+  unplugScroll: function() {
+     Event.stopObserving(this.scrollDiv,"scroll", this.scrollEventFunc , false);
+     this.scrollPluggedIn=false;
+  },
+
+  printVisible: function(exportType) {
+    this.exportStart();
+    var limit=this.pageSize;
+    if (this.buffer && this.buffer.totalRows < limit) limit=this.buffer.totalRows;
+    for(var r=0; r < limit; r++) {
+      this.exportText+="<tr>";
+      for (var c=0; c<this.columns.length; c++) {
+        if (this.columns[c].visible)
+          this.exportText+="<td style='"+this.exportStyle(this.columns[c].cell(r))+"'>"+this.columns[c].getFormattedValue(r)+"</td>";
+      }
+      this.exportText+="</tr>";
+    }
+    this.exportFinish(exportType);
+  },
+
+  exportStart: function() {
+    this.exportText="<table border='1' cellspacing='0'><thead style='display: table-header-group;'>";
+
+    for (var r=0; r<this.hdrCells.length; r++) {
+      if (this.hdrCells[r].length==0 || Element.getStyle(this.hdrCells[r][0].cell.parentNode,'display')=='none') continue;
+      this.exportText+="<tr>";
+      for (var c=0,i=0; c<this.hdrCells[r].length; c++) {
+        var hdrcell=this.hdrCells[r][c];
+        var newSpan=hdrcell.colSpan;
+        for (var j=0; j<hdrcell.colSpan; j++, i++)
+          if (!this.columns[i].visible) newSpan--;
+        if (newSpan > 0) {
+          var divs=Element.getElementsByClassName(hdrcell.cell,'ricoLG_cell');
+          var cell=divs && divs.length>0 ? divs[0] : hdrcell.cell;
+          this.exportText+="<td style='"+this.exportStyle(cell)+"'";
+          if (hdrcell.colSpan > 1) this.exportText+=" colspan='"+newSpan+"'";
+          this.exportText+=">"+RicoUtil.getInnerText(cell)+"</td>";
+        }
+      }
+      this.exportText+="</tr>";
+    }
+
+    for (var c=0; c<this.columns.length; c++)
+    this.exportText+="</thead><tbody>";
+  },
+
+  exportFinish: function(exportType) {
+    if (this.hideMsg) this.hideMsg();
+    this.exportText+="</tbody></table>";
+    this.exportDiv.innerHTML=this.exportText;
+    this.exportText=undefined;
+    if (this.cancelMenu) this.cancelMenu();
+    window.open(Rico.htmDir+'export-'+(exportType || 'plain')+'.html?'+this.exportDiv.id,'',this.options.exportWindow);
+  },
+  
+  exportStyle: function(elem) {
+    var styleList=['background-color','color','text-align','font-weight']
+    for (var i=0,s=''; i < styleList.length; i++) {
+      var curstyle=Element.getStyle(elem,styleList[i]);
+      if (curstyle) s+=styleList[i]+':'+curstyle+';';
+    }
+    return s;
+  },
+
+  // Gets the value of the specified cookie
+  getCookie: function() {
+    var c=RicoUtil.getCookie(this.tableId);
+    if (!c) return;
+       var cookieVals=c.split(',');
+       for (var i=0; i<cookieVals.length; i++) {
+         var v=cookieVals[i].split(':');
+         if (v.length!=2) continue;
+         var colnum=parseInt(v[0].slice(1));
+         if (colnum < 0 || colnum >= this.columns.length) continue;
+         var col=this.columns[colnum];
+         switch (v[0].charAt(0)) {
+           case 'w':
+             col.setColWidth(v[1]);
+          col.customWidth=true;
+             break;
+           case 'h':
+             if (v[1].toLowerCase()=='true')
+               col.showColumn(true);
+             else
+               col.hideColumn(true);
+             break;
+           case 's':
+             col.setSorted(v[1]);
+             break;
+           case 'f':
+             var filterTemp=v[1].split('~');
+             col.filterOp=filterTemp.shift();
+          col.filterValues = [];
+          col.filterType = Rico.TableColumn.USERFILTER;
+          for (var j=0; j<filterTemp.length; j++)
+            col.filterValues.push(unescape(filterTemp[j]));
+             break;
+         }
+       }
+  },
+  
+  // Write information to cookie
+  setCookie: function() {
+       var cookieVals=[];
+       for (var i=0; i<this.columns.length; i++) {
+         var col=this.columns[i];
+         if (this.options.saveColumnInfo.width) {
+         if (col.customWidth) cookieVals.push('w'+i+':'+col.colWidth);
+         if (col.customVisible) cookieVals.push('h'+i+':'+col.visible);
+         }
+      if (this.options.saveColumnInfo.sort) {
+        if (col.currentSort != Rico.TableColumn.UNSORTED)
+          cookieVals.push('s'+i+':'+col.currentSort);
+      }
+      if (this.options.saveColumnInfo.filter && col.filterType == Rico.TableColumn.USERFILTER) {
+        var filterTemp=[col.filterOp];
+        for (var j=0; j<col.filterValues.length; j++)
+          filterTemp.push(escape(col.filterValues[j]));
+        cookieVals.push('f'+i+':'+filterTemp.join('~'));
+      }
+       }
+       if (cookieVals.length > 0)
+         RicoUtil.setCookie(this.tableId, cookieVals.join(','), this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
+  }
+
+}
+
+Rico.TableColumn = Class.create();
+
+Rico.TableColumn.UNFILTERED   = 0;
+Rico.TableColumn.SYSTEMFILTER = 1;  /* system-generated filter, not shown to user */
+Rico.TableColumn.USERFILTER   = 2;
+
+Rico.TableColumn.UNSORTED   = 0;
+Rico.TableColumn.SORT_ASC   = "ASC";
+Rico.TableColumn.SORT_DESC  = "DESC";
+Rico.TableColumn.MINWIDTH   = 10; // min column width when user is resizing
+
+Rico.TableColumn.DOLLAR  = {type:'number', prefix:'$', decPlaces:2, ClassName:'alignright'};
+Rico.TableColumn.EURO    = {type:'number', prefix:'&euro;', decPlaces:2, ClassName:'alignright'};
+Rico.TableColumn.PERCENT = {type:'number', suffix:'%', decPlaces:2, multiplier:100, ClassName:'alignright'};
+Rico.TableColumn.QTY     = {type:'number', decPlaces:0, ClassName:'alignright'};
+Rico.TableColumn.DEFAULT = {type:"raw"};
+
+Rico.TableColumn.prototype = {
+
+  baseInit: function(liveGrid,colIdx,hdrInfo,tabIdx) {
+    Rico.writeDebugMsg("TableColumn.init index="+colIdx+" tabIdx="+tabIdx);
+    this.liveGrid  = liveGrid;
+    this.index     = colIdx;
+    this.hideWidth = Rico.isKonqueror || Prototype.Browser.WebKit || liveGrid.headerRowCnt>1 ? 5 : 2;  // column width used for "hidden" columns. Anything less than 5 causes problems with Konqueror. Best to keep this greater than padding used inside cell.
+    this.options   = liveGrid.options;
+    this.tabIdx    = tabIdx;
+    this.hdrCell   = hdrInfo.cell;
+    this.body = document.getElementsByTagName("body")[0];  // work around FireFox bug (document.body doesn't exist after XSLT)
+    this.displayName  = this.getDisplayName(this.hdrCell);
+    var divs=this.hdrCell.getElementsByTagName('div');
+    this.hdrColDiv=(divs.length<1) ? RicoUtil.wrapChildren(this.hdrCell,'ricoLG_col') : divs[0];
+    this.hdrCellDiv=(divs.length<2) ? RicoUtil.wrapChildren(this.hdrColDiv,'ricoLG_cell') : divs[1];
+    var sectionIndex= tabIdx==0 ? colIdx : colIdx-liveGrid.options.frozenColumns;
+    this.dataCell = liveGrid.tbody[tabIdx].rows[0].cells[sectionIndex];
+    var divs=this.dataCell.getElementsByTagName('div');
+    this.dataColDiv=(divs.length<1) ? RicoUtil.wrapChildren(this.dataCell,'ricoLG_col') : divs[0];
+
+    this.mouseDownHandler= this.handleMouseDown.bindAsEventListener(this);
+    this.mouseMoveHandler= this.handleMouseMove.bindAsEventListener(this);
+    this.mouseUpHandler  = this.handleMouseUp.bindAsEventListener(this);
+    this.mouseOutHandler = this.handleMouseOut.bindAsEventListener(this);
+
+    this.fieldName = 'col'+this.index;
+    var spec = liveGrid.options.columnSpecs[colIdx];
+    this.format=Object.extend( {}, Rico.TableColumn.DEFAULT);
+    switch (typeof spec) {
+      case 'object':
+        if (typeof spec.format=='string') Object.extend(this.format, Rico.TableColumn[spec.format.toUpperCase()]);
+        Object.extend(this.format, spec);
+        break;
+      case 'string':
+        if (spec.slice(0,4)=='spec') spec=spec.slice(4).toUpperCase();  // for backwards compatibility
+        this.format=typeof Rico.TableColumn[spec]=='object' ? Rico.TableColumn[spec] : Rico.TableColumn.DEFAULT;
+        break;
+    }
+    this.dataColDiv.className += (this.format.ClassName) ? ' '+this.format.ClassName : ' '+liveGrid.tableId+'_col'+colIdx;
+    this.visible=true;
+    if (typeof this.format.visible=='boolean') this.visible=this.format.visible;
+    if (typeof this.format.type!='string') this.format.type='raw';
+    Rico.writeDebugMsg("TableColumn.init index="+colIdx+" fieldName="+this.fieldName+' type='+this.format.type);
+    this.sortable     = typeof this.format.canSort=='boolean' ? this.format.canSort : liveGrid.options.canSortDefault;
+    this.currentSort  = Rico.TableColumn.UNSORTED;
+    this.filterable   = typeof this.format.canFilter=='boolean' ? this.format.canFilter : liveGrid.options.canFilterDefault;
+    this.filterType   = Rico.TableColumn.UNFILTERED;
+    this.hideable     = typeof this.format.canHide=='boolean' ? this.format.canHide : liveGrid.options.canHideDefault;
+    if (typeof this.isNullable!='boolean') this.isNullable = /number|date/.test(this.format.type);
+    this.isText       = /raw|text/.test(this.format.type);
+
+    var wi=(typeof(this.format.width)=='number') ? this.format.width : hdrInfo.initWidth;
+    wi=(typeof(wi)=='number') ? Math.max(wi,Rico.TableColumn.MINWIDTH) : liveGrid.options.defaultWidth;
+    this.setColWidth(wi);
+    if (!this.visible) this.setDisplayNone();
+    if (this.options.allowColResize && !this.format.noResize) this.insertResizer();
+  },
+
+  insertResizer: function() {
+    this.hdrCell.style.width='';
+    var resizer=this.hdrCellDiv.appendChild(document.createElement('div'));
+    resizer.className='ricoLG_Resize';
+    resizer.style[this.liveGrid.align[1]]='0px';
+    if (this.options.resizeBackground) {
+      var resizePath=Rico.imgDir+this.options.resizeBackground;
+      if (Prototype.Browser.IE) resizePath=location.protocol+resizePath;
+      resizer.style.backgroundImage='url('+resizePath+')';
+    }
+    Event.observe(resizer,"mousedown", this.mouseDownHandler, false);
+  },
+
+  // get the display name of a column
+  getDisplayName: function(el) {
+    var anchors=el.getElementsByTagName("A");
+    //Check the existance of A tags
+    if (anchors.length > 0)
+      return anchors[0].innerHTML;
+    else
+      return el.innerHTML.stripTags();
+  },
+  
+  _clear: function(gridCell) {
+    gridCell.innerHTML='&nbsp;';
+  },
+
+  clearCell: function(rowIndex) {
+    var gridCell=this.cell(rowIndex);
+    this._clear(gridCell,rowIndex);
+    if (!this.liveGrid.buffer) return;
+    var acceptAttr=this.liveGrid.buffer.options.acceptAttr;
+    for (var k=0; k<acceptAttr.length; k++) {
+      switch (acceptAttr[k]) {
+        case 'style': gridCell.style.cssText=''; break;
+        case 'class': gridCell.className=''; break;
+        default:      gridCell['_'+acceptAttr[k]]=''; break;
+      }
+    }
+  },
+
+  dataTable: function() {
+    return this.liveGrid.tabs[this.tabIdx];
+  },
+  
+  numRows: function() {
+    return this.dataColDiv.childNodes.length;
+  },
+
+  clearColumn: function() {
+    var childCnt=this.numRows();
+    for (var r=0; r<childCnt; r++)
+      this.clearCell(r);
+  },
+
+  cell: function(r) {
+    return this.dataColDiv.childNodes[r];
+  },
+  
+  getFormattedValue: function(r) {
+    return RicoUtil.getInnerText(this.cell(r));
+  },
+
+  setColWidth: function(wi) {
+    if (typeof wi=='number') {
+      wi=parseInt(wi);
+      if (wi < Rico.TableColumn.MINWIDTH) return;
+      wi=wi+'px';
+    }
+    Rico.writeDebugMsg('setColWidth '+this.index+': '+wi);
+    this.colWidth=wi;
+    this.hdrColDiv.style.width=wi;
+    this.dataColDiv.style.width=wi;
+  },
+
+  pluginMouseEvents: function() {
+    if (this.mousePluggedIn==true) return;
+    Event.observe(this.body,"mousemove", this.mouseMoveHandler, false);
+    Event.observe(this.body,"mouseup",   this.mouseUpHandler  , false);
+    Event.observe(this.body,"mouseout",  this.mouseOutHandler , false);
+    this.mousePluggedIn=true;
+  },
+
+  unplugMouseEvents: function() {
+    Event.stopObserving(this.body,"mousemove", this.mouseMoveHandler, false);
+    Event.stopObserving(this.body,"mouseup",   this.mouseUpHandler  , false);
+    Event.stopObserving(this.body,"mouseout",  this.mouseOutHandler , false);
+    this.mousePluggedIn=false;
+  },
+
+  handleMouseDown: function(e) {
+    this.resizeStart=e.clientX;
+    this.origWidth=parseInt(this.colWidth);
+    var p=Position.positionedOffset(this.hdrCell);
+    if (this.liveGrid.direction=='rtl') {
+      this.edge=p[0]+this.liveGrid.options.scrollBarWidth;
+      switch (this.tabIdx) {
+        case 0: this.edge+=this.liveGrid.innerDiv.offsetWidth; break;
+        case 1: this.edge-=this.liveGrid.scrollDiv.scrollLeft; break;
+      }
+    } else {
+      this.edge=p[0]+this.hdrCell.offsetWidth;
+      if (this.tabIdx>0) this.edge+=RicoUtil.nan2zero(this.liveGrid.tabs[0].offsetWidth)-this.liveGrid.scrollDiv.scrollLeft;
+    }
+    this.liveGrid.resizeDiv.style.left=this.edge+"px";
+    this.liveGrid.resizeDiv.style.display="";
+    this.liveGrid.outerDiv.style.cursor='e-resize';
+    this.tmpHighlight=this.liveGrid.highlightEnabled;
+    this.liveGrid.highlightEnabled=false;
+    this.pluginMouseEvents();
+    Event.stop(e);
+  },
+
+  handleMouseMove: function(e) {
+    var delta=e.clientX-this.resizeStart;
+    var newWidth=(this.liveGrid.direction=='rtl') ? this.origWidth-delta : this.origWidth+delta;
+    if (newWidth < Rico.TableColumn.MINWIDTH) return;
+    this.liveGrid.resizeDiv.style.left=(this.edge+delta)+"px";
+    this.colWidth=newWidth;
+    Event.stop(e);
+  },
+
+  handleMouseUp: function(e) {
+    this.unplugMouseEvents();
+    Rico.writeDebugMsg('handleMouseUp '+this.liveGrid.tableId);
+    this.liveGrid.outerDiv.style.cursor='';
+    this.liveGrid.resizeDiv.style.display="none";
+    this.setColWidth(this.colWidth);
+    this.customWidth=true;
+    this.liveGrid.setCookie();
+    this.liveGrid.highlightEnabled=this.tmpHighlight;
+    this.liveGrid.sizeDivs();
+    Event.stop(e);
+  },
+
+  handleMouseOut: function(e) {
+    var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
+    while (reltg != null && reltg.nodeName.toLowerCase() != 'body')
+      reltg=reltg.parentNode;
+    if (reltg!=null && reltg.nodeName.toLowerCase() == 'body') return true;
+    this.handleMouseUp(e);
+    return true;
+  },
+
+  setDisplayNone: function() {
+    this.hdrCell.style.display='none';
+    this.hdrColDiv.style.display='none';
+    this.dataCell.style.display='none';
+    this.dataColDiv.style.display='none';
+  },
+
+  // recalcTableWidth defaults to true
+  hideColumn: function(noresize) {
+    Rico.writeDebugMsg('hideColumn '+this.liveGrid.tableId);
+    this.setDisplayNone();
+    this.liveGrid.cancelMenu();
+    this.visible=false;
+    this.customVisible=true;
+    if (noresize) return;
+    this.liveGrid.setCookie();
+    this.liveGrid.sizeDivs();
+  },
+
+  showColumn: function(noresize) {
+    Rico.writeDebugMsg('showColumn '+this.liveGrid.tableId);
+    this.hdrCell.style.display='';
+    this.hdrColDiv.style.display='';
+    this.dataCell.style.display='';
+    this.dataColDiv.style.display='';
+    this.liveGrid.cancelMenu();
+    this.visible=true;
+    this.customVisible=true;
+    if (noresize) return;
+    this.liveGrid.setCookie();
+    this.liveGrid.sizeDivs();
+  },
+
+  setImage: function() {
+    if ( this.currentSort == Rico.TableColumn.SORT_ASC ) {
+       this.imgSort.style.display='';
+       this.imgSort.src=Rico.imgDir+this.options.sortAscendImg;
+    } else if ( this.currentSort == Rico.TableColumn.SORT_DESC ) {
+       this.imgSort.style.display='';
+       this.imgSort.src=Rico.imgDir+this.options.sortDescendImg;
+    } else {
+       this.imgSort.style.display='none';
+    }
+    if (this.filterType == Rico.TableColumn.USERFILTER) {
+       this.imgFilter.style.display='';
+       this.imgFilter.title=this.getFilterText();
+    } else {
+       this.imgFilter.style.display='none';
+    }
+  },
+
+  canHideShow: function() {
+    return this.hideable;
+  }
+
+};
+
+Rico.includeLoaded('ricoGridCommon.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGrid.js b/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGrid.js
new file mode 100644 (file)
index 0000000..bc2af62
--- /dev/null
@@ -0,0 +1,1806 @@
+/**
+  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+  *  (c) 2005-2007 Matt Brown (http://dowdybrown.com)
+  *
+  *  Rico is 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
+  **/
+
+
+if(typeof Rico=='undefined') throw("LiveGrid requires the Rico JavaScript framework");
+if(typeof RicoUtil=='undefined') throw("LiveGrid requires the RicoUtil Library");
+if(typeof RicoTranslate=='undefined') throw("LiveGrid requires the RicoTranslate Library");
+if(typeof Rico.TableColumn=='undefined') throw("LiveGrid requires ricoGridCommon.js");
+
+
+Rico.Buffer = {};
+
+/**
+ * Loads buffer with data that already exists in the document as an HTML table (no AJAX).
+ * Also serves as a base class for AJAX-enabled buffers.
+ */
+Rico.Buffer.Base = Class.create();
+
+Rico.Buffer.Base.prototype = {
+
+  initialize: function(dataTable, options) {
+    this.clear();
+    this.updateInProgress = false;
+    this.lastOffset = 0;
+    this.rcvdRowCount = false;  // true if an eof element was included in the last xml response
+    this.foundRowCount = false; // true if an xml response is ever received with eof true
+    this.totalRows = 0;
+    this.rowcntContent = "";
+    this.rcvdOffset = -1;
+    this.options = {
+      fixedHdrRows     : 0,
+      canFilter        : false, // does buffer object support filtering?
+      isEncoded        : true,  // is the data received via ajax html encoded?
+      acceptAttr       : []     // attributes that can be copied from original/ajax data (e.g. className, style, id)
+    }
+    Object.extend(this.options, options || {});
+    if (dataTable) {
+      this.loadRowsFromTable(dataTable);
+    } else {
+      this.clear();
+    }
+  },
+
+  registerGrid: function(liveGrid) {
+    this.liveGrid = liveGrid;
+  },
+
+  setTotalRows: function( newTotalRows ) {
+    if (this.totalRows == newTotalRows) return;
+    this.totalRows = newTotalRows;
+    if (this.liveGrid) {
+      Rico.writeDebugMsg("setTotalRows, newTotalRows="+newTotalRows);
+      if (this.liveGrid.sizeTo=='data') this.liveGrid.resizeWindow();
+      this.liveGrid.updateHeightDiv();
+    }
+  },
+
+  loadRowsFromTable: function(tableElement) {
+    this.rows = this.dom2jstable(tableElement,this.options.fixedHdrRows);
+    this.startPos = 0;
+    this.size = this.rows.length;
+    this.setTotalRows(this.size);
+    this.rowcntContent = this.size.toString();
+    this.rcvdRowCount = true;
+    this.foundRowCount = true;
+  },
+
+  dom2jstable: function(rowsElement,firstRow) {
+    var newRows = new Array();
+    var trs = rowsElement.getElementsByTagName("tr");
+    var acceptAttr=this.options.acceptAttr;
+    for ( var i=firstRow || 0; i < trs.length; i++ ) {
+      var row = new Array();
+      var cells = trs[i].getElementsByTagName("td");
+      for ( var j=0; j < cells.length ; j++ ) {
+        row[j]={};
+        row[j].content=RicoUtil.getContentAsString(cells[j],this.options.isEncoded);
+        for (var k=0; k<acceptAttr.length; k++) {
+          row[j]['_'+acceptAttr[k]]=cells[j].getAttribute(acceptAttr[k]);
+        }
+        if (Prototype.Browser.IE) row[j]._class=cells[j].getAttribute('className');
+      }
+      newRows.push( row );
+    }
+    return newRows;
+  },
+
+  _blankRow: function() {
+    var newRow=[];
+    for (var i=0; i<this.liveGrid.columns.length; i++) {
+      newRow[i]={};
+      newRow[i].content='';
+    }
+    return newRow;
+  },
+
+  insertRow: function(beforeRowIndex) {
+    this.rows.splice(beforeRowIndex,0,this._blankRow());
+  },
+
+  appendRows: function(cnt) {
+    for (var i=0; i<cnt; i++)
+      this.rows.push(this._blankRow());
+    this.size=this.rows.length;
+  },
+
+  sortBuffer: function(colnum,sortdir,coltype,getvalfunc) {
+    this.sortColumn=colnum;
+    this.getValFunc=getvalfunc;
+    var sortFunc;
+    switch (coltype) {
+      case 'number': sortFunc=this._sortNumeric.bind(this); break;
+      case 'control':sortFunc=this._sortControl.bind(this); break;
+      default:       sortFunc=this._sortAlpha.bind(this); break;
+    }
+    this.rows.sort(sortFunc);
+    if (sortdir=='DESC') this.rows.reverse();
+  },
+
+  _sortAlpha: function(a,b) {
+    var aa = this.sortColumn<a.length ? RicoUtil.getInnerText(a[this.sortColumn].content) : '';
+    var bb = this.sortColumn<b.length ? RicoUtil.getInnerText(b[this.sortColumn].content) : '';
+    if (aa==bb) return 0;
+    if (aa<bb) return -1;
+    return 1;
+  },
+
+  _sortNumeric: function(a,b) {
+    var aa = this.sortColumn<a.length ? parseFloat(RicoUtil.getInnerText(a[this.sortColumn].content)) : 0;
+    if (isNaN(aa)) aa = 0;
+    var bb = this.sortColumn<b.length ? parseFloat(RicoUtil.getInnerText(b[this.sortColumn].content)) : 0;
+    if (isNaN(bb)) bb = 0;
+    return aa-bb;
+  },
+
+  _sortControl: function(a,b) {
+    var aa = this.sortColumn<a.length ? RicoUtil.getInnerText(a[this.sortColumn].content) : '';
+    var bb = this.sortColumn<b.length ? RicoUtil.getInnerText(b[this.sortColumn].content) : '';
+    if (this.getValFunc) {
+      aa=this.getValFunc(aa);
+      bb=this.getValFunc(bb);
+    }
+    if (aa==bb) return 0;
+    if (aa<bb) return -1;
+    return 1;
+  },
+
+  clear: function() {
+    this.rows = new Array();
+    this.startPos = -1;
+    this.size = 0;
+    this.windowPos = 0;
+  },
+
+  isInRange: function(position) {
+    var lastRow=Math.min(this.totalRows, position + this.liveGrid.pageSize)
+    return (position >= this.startPos) && (lastRow <= this.endPos()); // && (this.size != 0);
+  },
+
+  endPos: function() {
+    return this.startPos + this.rows.length;
+  },
+
+  fetch: function(offset) {
+    this.liveGrid.refreshContents(offset);
+    return;
+  },
+
+  exportAllRows: function(populate,finish) {
+    populate(this.getRows(0,this.totalRows));
+    finish();
+  },
+
+  setWindow: function(start, count) {
+    this.windowStart = start - this.startPos;
+    this.windowEnd = Math.min(this.windowStart + count,this.size);
+    this.windowPos = start;
+  },
+
+  isVisible: function(bufRow) {
+    return bufRow < this.rows.length && bufRow >= this.windowStart && bufRow < this.windowEnd;
+  },
+
+  getWindowCell: function(windowRow,col) {
+    var bufrow=this.windowStart+windowRow;
+    return this.isVisible(bufrow) && col < this.rows[bufrow].length ? this.rows[bufrow][col] : null;
+  },
+
+  getWindowValue: function(windowRow,col) {
+    var cell=this.getWindowCell(windowRow,col);
+    return cell ? cell.content : null;
+  },
+
+  setWindowValue: function(windowRow,col,newval) {
+    var bufRow=this.windowStart+windowRow;
+    if (bufRow >= this.windowEnd) return false;
+    return this.setValue(bufRow,col,newval);
+  },
+
+  getCell: function(bufRow,col) {
+    return bufRow < this.size ? this.rows[bufRow][col] : null;
+  },
+
+  getValue: function(bufRow,col) {
+    var cell=this.getCell(bufRow,col);
+    return cell ? cell.content : null;
+  },
+
+  setValue: function(bufRow,col,newval,newstyle) {
+    if (bufRow>=this.size) return false;
+    if (!this.rows[bufRow][col]) this.rows[bufRow][col]={};
+    this.rows[bufRow][col].content=newval;
+    if (typeof newstyle=='string') this.rows[bufRow][col]._style=newstyle;
+    this.rows[bufRow][col].modified=true;
+    return true;
+  },
+
+  getRows: function(start, count) {
+    var begPos = start - this.startPos;
+    var endPos = Math.min(begPos + count,this.size);
+    var results = new Array();
+    for ( var i=begPos; i < endPos; i++ )
+      results.push(this.rows[i]);
+    return results
+  }
+
+};
+
+
+// Rico.LiveGrid -----------------------------------------------------
+
+Rico.LiveGrid = Class.create();
+
+Rico.LiveGrid.prototype = {
+
+  initialize: function( tableId, buffer, options ) {
+    Object.extend(this, new Rico.GridCommon);
+    Object.extend(this, new Rico.LiveGridMethods);
+    this.baseInit();
+    this.tableId = tableId;
+    this.buffer = buffer;
+    Rico.setDebugArea(tableId+"_debugmsgs");    // if used, this should be a textarea
+
+    Object.extend(this.options, {
+      visibleRows      : -1,    // -1 or 'window'=size grid to client window; -2 or 'data'=size grid to min(window,data); -3 or 'body'=size so body does not have a scrollbar
+      frozenColumns    : 0,
+      offset           : 0,     // first row to be displayed
+      prefetchBuffer   : true,  // load table on page load?
+      minPageRows      : 1,
+      maxPageRows      : 50,
+      canSortDefault   : true,  // can be overridden in the column specs
+      canFilterDefault : buffer.options.canFilter, // can be overridden in the column specs
+      canHideDefault   : true,  // can be overridden in the column specs
+      cookiePrefix     : 'liveGrid.'+tableId,
+
+      // highlight & selection parameters
+      highlightElem    : 'none',// what gets highlighted/selected (cursorRow, cursorCell, menuRow, menuCell, selection, or none)
+      highlightSection : 3,     // which section gets highlighted (frozen=1, scrolling=2, all=3, none=0)
+      highlightMethod  : 'class', // outline, class, both (outline is less CPU intensive on the client)
+      highlightClass   : 'ricoLG_selection',
+
+      // export/print parameters
+      maxPrint         : 1000,  // max # of rows that can be printed/exported, 0=disable print/export feature
+      exportWindow     : "height=300,width=500,scrollbars=1,menubar=1,resizable=1",
+
+      // heading parameters
+      headingSort      : 'link', // link: make headings a link that will sort column, hover: make headings a hoverset, none: events on headings are disabled
+      hdrIconsFirst    : true,   // true: put sort & filter icons before header text, false: after
+      sortAscendImg    : 'sort_asc.gif',
+      sortDescendImg   : 'sort_desc.gif',
+      filterImg        : 'filtercol.gif'
+    });
+    // other options:
+    //   sortCol: initial sort column
+
+    this.options.sortHandler = this.sortHandler.bind(this);
+    this.options.filterHandler = this.filterHandler.bind(this);
+    this.options.onRefreshComplete = this.bookmarkHandler.bind(this);
+    this.options.rowOverHandler = this.rowMouseOver.bindAsEventListener(this);
+    this.options.mouseDownHandler = this.selectMouseDown.bindAsEventListener(this);
+    this.options.mouseOverHandler = this.selectMouseOver.bindAsEventListener(this);
+    this.options.mouseUpHandler  = this.selectMouseUp.bindAsEventListener(this);
+    Object.extend(this.options, options || {});
+
+    switch (typeof this.options.visibleRows) {
+      case 'string':
+        this.sizeTo=this.options.visibleRows;
+        this.options.visibleRows=-1;
+        break;
+      case 'number':
+        switch (this.options.visibleRows) {
+          case -1: this.sizeTo='window'; break;
+          case -2: this.sizeTo='data'; break;
+          case -3: this.sizeTo='body'; break;
+        }
+        break;
+      default:
+        this.sizeTo='window';
+        this.options.visibleRows=-1;
+    }
+    this.highlightEnabled=this.options.highlightSection>0;
+    this.pageSize=0;
+    this.createTables();
+    if (this.headerColCnt==0) {
+      alert('ERROR: no columns found in "'+this.tableId+'"');
+      return;
+    }
+    this.createColumnArray();
+       if (this.options.headingSort=='hover')
+         this.createHoverSet();
+
+    this.bookmark=$(this.tableId+"_bookmark");
+    this.sizeDivs();
+    this.createDataCells(this.options.visibleRows);
+    if (this.pageSize == 0) return;
+    this.buffer.registerGrid(this);
+    if (this.buffer.setBufferSize) this.buffer.setBufferSize(this.pageSize);
+    this.scrollTimeout = null;
+    this.lastScrollPos = 0;
+    this.attachMenuEvents();
+
+    // preload the images...
+    new Image().src = Rico.imgDir+this.options.filterImg;
+    new Image().src = Rico.imgDir+this.options.sortAscendImg;
+    new Image().src = Rico.imgDir+this.options.sortDescendImg;
+    Rico.writeDebugMsg("images preloaded");
+
+    this.setSortUI( this.options.sortCol, this.options.sortDir );
+    this.setImages();
+    if (this.listInvisible().length==this.columns.length)
+      this.columns[0].showColumn();
+    this.sizeDivs();
+    this.scrollDiv.style.display="";
+    if (this.buffer.totalRows>0)
+      this.updateHeightDiv();
+    if (this.options.prefetchBuffer) {
+      if (this.bookmark) this.bookmark.innerHTML = RicoTranslate.getPhrase("Loading...");
+      if (this.options.canFilterDefault && this.options.getQueryParms)
+        this.checkForFilterParms();
+      this.buffer.fetch(this.options.offset);
+    }
+    this.scrollEventFunc=this.handleScroll.bindAsEventListener(this);
+    this.wheelEventFunc=this.handleWheel.bindAsEventListener(this);
+    this.wheelEvent=(Prototype.Browser.IE || Prototype.Browser.Opera || Prototype.Browser.WebKit) ? 'mousewheel' : 'DOMMouseScroll';
+    if (this.options.offset && this.options.offset < this.buffer.totalRows)
+      setTimeout(this.scrollToRow.bind(this,this.options.offset),50);  // Safari requires a delay
+    this.pluginScroll();
+    this.setHorizontalScroll();
+    if (this.options.windowResize)
+      setTimeout(this.pluginWindowResize.bind(this),100);
+  }
+};
+
+Rico.LiveGridMethods = function() {};
+
+Rico.LiveGridMethods.prototype = {
+
+  createHoverSet: function() {
+    var hdrs=[];
+    for( var c=0; c < this.headerColCnt; c++ )
+      hdrs.push(this.columns[c].hdrCellDiv);
+         this.hoverSet = new Rico.HoverSet(hdrs);
+  },
+
+  checkForFilterParms: function() {
+    var s=window.location.search;
+    if (s.charAt(0)=='?') s=s.substring(1);
+    var pairs = s.split('&');
+    for (var i=0; i<pairs.length; i++)
+      if (pairs[i].match(/^f\[\d+\]/)) {
+        this.buffer.options.requestParameters.push(pairs[i]);
+      }
+  },
+
+/**
+ * Create one table for frozen columns and one for scrolling columns.
+ * Also create div's to contain them.
+ */
+  createTables: function() {
+    var insertloc;
+    var result = -1;
+    var table = $(this.tableId);
+    if (!table) return result;
+    if (table.tagName.toLowerCase()=='table') {
+      var theads=table.getElementsByTagName("thead");
+      if (theads.length == 1) {
+        Rico.writeDebugMsg("createTables: using thead section, id="+this.tableId);
+        var hdrSrc=theads[0].rows;
+      } else {
+        Rico.writeDebugMsg("createTables: using tbody section, id="+this.tableId);
+        var hdrSrc=new Array(table.rows[0]);
+      }
+      insertloc=table;
+    } else if (this.options.columnSpecs.length > 0) {
+      insertloc=table;
+      Rico.writeDebugMsg("createTables: inserting at "+table.tagName+", id="+this.tableId);
+    } else {
+      alert("ERROR!\n\nUnable to initialize '"+this.tableId+"'\n\nLiveGrid terminated");
+      return result;
+    }
+
+    this.createDivs();
+    this.scrollTabs = this.createDiv("scrollTabs",this.innerDiv);
+    this.shadowDiv  = this.createDiv("shadow",this.scrollDiv);
+    this.shadowDiv.style.direction='ltr';  // avoid FF bug
+    this.messageDiv = this.createDiv("message",this.outerDiv);
+    this.messageDiv.style.display="none";
+    this.messageShadow=new Rico.Shadow(this.messageDiv);
+    this.scrollDiv.style.display="none";
+    this.scrollDiv.scrollTop=0;
+    if (this.options.highlightMethod!='class') {
+      this.highlightDiv=[];
+      switch (this.options.highlightElem) {
+        case 'menuRow':
+        case 'cursorRow':
+          this.highlightDiv[0] = this.createDiv("highlight",this.outerDiv);
+          this.highlightDiv[0].style.display="none";
+          break;
+        case 'menuCell':
+        case 'cursorCell':
+          for (var i=0; i<2; i++) {
+            this.highlightDiv[i] = this.createDiv("highlight",i==0 ? this.frozenTabs : this.scrollTabs);
+            this.highlightDiv[i].style.display="none";
+            this.highlightDiv[i].id+=i;
+          }
+          break;
+        case 'selection':
+          // create one div for each side of the rectangle
+          var parentDiv=this.options.highlightSection==1 ? this.frozenTabs : this.scrollTabs;
+          for (var i=0; i<4; i++) {
+            this.highlightDiv[i] = this.createDiv("highlight",parentDiv);
+            this.highlightDiv[i].style.display="none";
+            this.highlightDiv[i].id+=i;
+            this.highlightDiv[i].style[i % 2==0 ? 'height' : 'width']="0px";
+          }
+          break;
+      }
+    }
+
+    // create new tables
+    for (var i=0; i<2; i++) {
+      this.tabs[i] = document.createElement("table");
+      this.tabs[i].className = 'ricoLG_table';
+      this.tabs[i].border=0;
+      this.tabs[i].cellPadding=0;
+      this.tabs[i].cellSpacing=0;
+      this.tabs[i].id = this.tableId+"_tab"+i;
+      this.thead[i]=this.tabs[i].createTHead();
+      this.thead[i].className='ricoLG_top';
+      if (this.tabs[i].tBodies.length==0)
+        this.tbody[i]=this.tabs[i].appendChild(document.createElement("tbody"));
+      else
+        this.tbody[i]=this.tabs[i].tBodies[0];
+      this.tbody[i].className='ricoLG_bottom';
+      this.tbody[i].insertRow(-1);
+    }
+    this.frozenTabs.appendChild(this.tabs[0]);
+    this.scrollTabs.appendChild(this.tabs[1]);
+    insertloc.parentNode.insertBefore(this.outerDiv,insertloc);
+    if (hdrSrc)
+      this.loadHdrSrc(hdrSrc);
+    else
+      this.createHdr();
+    for( var c=0; c < this.headerColCnt; c++ )
+      this.tbody[c<this.options.frozenColumns ? 0 : 1].rows[0].insertCell(-1);
+    if (table) table.parentNode.removeChild(table);
+    Rico.writeDebugMsg('createTables end');
+  },
+
+  createDataCells: function(visibleRows) {
+    if (visibleRows < 0) {
+      this.appendBlankRow();
+      this.sizeDivs();
+      this.autoAppendRows(this.remainingHt());
+    } else {
+      for( var r=0; r < visibleRows; r++ )
+        this.appendBlankRow();
+    }
+    var s=this.options.highlightSection;
+    if (s & 1) this.attachHighlightEvents(this.tbody[0]);
+    if (s & 2) this.attachHighlightEvents(this.tbody[1]);
+    return;
+  },
+
+  createHdr: function() {
+    for (var i=0; i<2; i++) {
+      var start=(i==0) ? 0 : this.options.frozenColumns;
+      var limit=(i==0) ? this.options.frozenColumns : this.options.columnSpecs.length;
+      Rico.writeDebugMsg('createHdr: i='+i+' start='+start+' limit='+limit);
+      if (this.options.PanelNamesOnTabHdr && this.options.panels) {
+        // place panel names on first row of thead
+        var r = this.thead[i].insertRow(-1);
+        r.className='ricoLG_hdg';
+        var lastIdx=-1, span, newCell=null, spanIdx=0;
+        for( var c=start; c < limit; c++ ) {
+          if (lastIdx == this.options.columnSpecs[c].panelIdx) {
+            span++;
+          } else {
+            if (newCell) newCell.colSpan=span;
+            newCell = r.insertCell(-1);
+            span=1;
+            lastIdx=this.options.columnSpecs[c].panelIdx;
+            newCell.innerHTML=this.options.panels[lastIdx];
+          }
+        }
+        if (newCell) newCell.colSpan=span;
+      }
+      var mainRow = this.thead[i].insertRow(-1);
+      mainRow.id=this.tableId+'_tab'+i+'h_main';
+      mainRow.className='ricoLG_hdg';
+      for( var c=start; c < limit; c++ ) {
+        var newCell = mainRow.insertCell(-1);
+        newCell.innerHTML=this.options.columnSpecs[c].Hdg;
+      }
+      this.headerColCnt = this.getColumnInfo(this.thead[i].rows);
+    }
+  },
+
+  loadHdrSrc: function(hdrSrc) {
+    Rico.writeDebugMsg('loadHdrSrc start');
+    this.headerColCnt = this.getColumnInfo(hdrSrc);
+    for (var i=0; i<2; i++) {
+      for (var r=0; r<hdrSrc.length; r++) {
+        var newrow = this.thead[i].insertRow(-1);
+        newrow.className='ricoLG_hdg';
+      }
+    }
+    if (hdrSrc.length==1) {
+      var cells=hdrSrc[0].cells;
+      for (var c=0; cells.length > 0; c++)
+        this.thead[c<this.options.frozenColumns ? 0 : 1].rows[0].appendChild(cells[0]);
+    } else {
+      for (var r=0; r<hdrSrc.length; r++) {
+        var cells=hdrSrc[r].cells;
+        for (var c=0; cells.length > 0; c++) {
+          if (cells[0].className=='ricoFrozen') {
+            this.thead[0].rows[r].appendChild(cells[0]);
+            if (r==this.headerRowIdx) this.options.frozenColumns=c+1;
+          } else {
+            this.thead[1].rows[r].appendChild(cells[0]);
+          }
+        }
+      }
+    }
+    Rico.writeDebugMsg('loadHdrSrc end');
+  },
+
+  sizeDivs: function() {
+    Rico.writeDebugMsg('sizeDivs: '+this.tableId);
+    this.cancelMenu();
+    this.unhighlight();
+    this.baseSizeDivs();
+    if (this.pageSize == 0) return;
+    this.rowHeight = Math.round(this.dataHt/this.pageSize);
+    var scrHt=this.dataHt;
+    if (this.scrWi>0 || Prototype.Browser.IE || Prototype.Browser.WebKit)
+      scrHt+=this.options.scrollBarWidth;
+    this.scrollDiv.style.height=scrHt+'px';
+    this.innerDiv.style.width=(this.scrWi-this.options.scrollBarWidth+1)+'px';
+    this.resizeDiv.style.height=this.frozenTabs.style.height=this.innerDiv.style.height=(this.hdrHt+this.dataHt+1)+'px';
+    Rico.writeDebugMsg('sizeDivs scrHt='+scrHt+' innerHt='+this.innerDiv.style.height+' rowHt='+this.rowHeight+' pageSize='+this.pageSize);
+    pad=(this.scrWi-this.scrTabWi < this.options.scrollBarWidth) ? 2 : 0;
+    this.shadowDiv.style.width=(this.scrTabWi+pad)+'px';
+    this.outerDiv.style.height=(this.hdrHt+scrHt)+'px';
+    this.setHorizontalScroll();
+  },
+
+  setHorizontalScroll: function() {
+    var scrleft=this.scrollDiv.scrollLeft;
+    this.scrollTabs.style.left=(-scrleft)+'px';
+  },
+
+  remainingHt: function() {
+    var winHt=RicoUtil.windowHeight();
+    var margin=Prototype.Browser.IE ? 15 : 10;
+    switch (this.sizeTo) {
+      case 'window':
+      case 'data':
+        var divPos=Position.page(this.outerDiv);
+        var tabHt=Math.max(this.tabs[0].offsetHeight,this.tabs[1].offsetHeight);
+        Rico.writeDebugMsg("remainingHt, winHt="+winHt+' tabHt='+tabHt+' gridY='+divPos[1]);
+        return winHt-divPos[1]-tabHt-this.options.scrollBarWidth-margin;  // allow for scrollbar and some margin
+      case 'body':
+        //Rico.writeDebugMsg("remainingHt, document.height="+document.height);
+        //Rico.writeDebugMsg("remainingHt, body.offsetHeight="+document.body.offsetHeight);
+        //Rico.writeDebugMsg("remainingHt, body.scrollHeight="+document.body.scrollHeight);
+        //Rico.writeDebugMsg("remainingHt, documentElement.scrollHeight="+document.documentElement.scrollHeight);
+        var bodyHt=Prototype.Browser.IE ? document.body.scrollHeight : document.body.offsetHeight;
+        var remHt=winHt-bodyHt-margin;
+        if (!Prototype.Browser.WebKit) remHt-=this.options.scrollBarWidth;
+        Rico.writeDebugMsg("remainingHt, winHt="+winHt+' pageHt='+bodyHt+' remHt='+remHt);
+        return remHt;
+    }
+  },
+
+  adjustPageSize: function() {
+    var remHt=this.remainingHt();
+    Rico.writeDebugMsg('adjustPageSize remHt='+remHt+' lastRow='+this.lastRowPos);
+    if (remHt > this.rowHeight)
+      this.autoAppendRows(remHt);
+    else if (remHt < 0 || this.sizeTo=='data')
+      this.autoRemoveRows(-remHt);
+  },
+
+  pluginWindowResize: function() {
+    Event.observe(window, "resize", this.resizeWindow.bindAsEventListener(this), false);
+  },
+
+  resizeWindow: function() {
+    Rico.writeDebugMsg('resizeWindow '+this.tableId+' lastRow='+this.lastRowPos);
+    if (!this.sizeTo) {
+      this.sizeDivs();
+      return;
+    }
+    var oldSize=this.pageSize;
+    this.adjustPageSize();
+    if (this.pageSize > oldSize) {
+      this.isPartialBlank=true;
+      var adjStart=this.adjustRow(this.lastRowPos);
+      this.buffer.fetch(adjStart);
+    }
+    if (oldSize != this.pageSize)
+      setTimeout(this.finishResize.bind(this),50);
+    else
+      this.sizeDivs();
+    Rico.writeDebugMsg('resizeWindow complete. old size='+oldSize+' new size='+this.pageSize);
+  },
+
+  finishResize: function() {
+    this.sizeDivs();
+    this.updateHeightDiv();
+  },
+
+  topOfLastPage: function() {
+    return Math.max(this.buffer.totalRows-this.pageSize,0);
+  },
+
+  updateHeightDiv: function() {
+    var notdisp=this.topOfLastPage();
+    var ht = this.scrollDiv.clientHeight + this.rowHeight * notdisp;
+    //if (Prototype.Browser.Opera) ht+=this.options.scrollBarWidth-3;
+    Rico.writeDebugMsg("updateHeightDiv, ht="+ht+' scrollDiv.clientHeight='+this.scrollDiv.clientHeight+' rowsNotDisplayed='+notdisp);
+    this.shadowDiv.style.height=ht+'px';
+  },
+
+  autoRemoveRows: function(overage) {
+    var removeCnt=Math.ceil(overage / this.rowHeight);
+    if (this.sizeTo=='data')
+      removeCnt=Math.max(removeCnt,this.pageSize-this.buffer.totalRows);
+    Rico.writeDebugMsg("autoRemoveRows overage="+overage+" removeCnt="+removeCnt);
+    for (var i=0; i<removeCnt; i++)
+      this.removeRow();
+  },
+
+  removeRow: function() {
+    if (this.pageSize <= this.options.minPageRows) return;
+    this.pageSize--;
+    for( var c=0; c < this.headerColCnt; c++ ) {
+      var cell=this.columns[c].cell(this.pageSize);
+      this.columns[c].dataColDiv.removeChild(cell);
+    }
+  },
+
+  autoAppendRows: function(overage) {
+    var addCnt=Math.floor(overage / this.rowHeight);
+    Rico.writeDebugMsg("autoAppendRows overage="+overage+" cnt="+addCnt+" rowHt="+this.rowHeight);
+    for (var i=0; i<addCnt; i++) {
+      if (this.sizeTo=='data' && this.pageSize>=this.buffer.totalRows) break;
+      this.appendBlankRow();
+    }
+  },
+
+  // on older systems, this can be fairly slow
+  appendBlankRow: function() {
+    if (this.pageSize >= this.options.maxPageRows) return;
+    Rico.writeDebugMsg("appendBlankRow #"+this.pageSize);
+    var cls=this.defaultRowClass(this.pageSize);
+    for( var c=0; c < this.headerColCnt; c++ ) {
+      var newdiv = document.createElement("div");
+      newdiv.className = 'ricoLG_cell '+cls;
+      newdiv.id=this.tableId+'_'+this.pageSize+'_'+c;
+      this.columns[c].dataColDiv.appendChild(newdiv);
+      newdiv.innerHTML='&nbsp;';
+      if (this.columns[c]._create)
+        this.columns[c]._create(newdiv,this.pageSize);
+    }
+    this.pageSize++;
+  },
+
+  defaultRowClass: function(rownum) {
+    return (rownum % 2==0) ? 'ricoLG_evenRow' : 'ricoLG_oddRow';
+  },
+
+  handleMenuClick: function(e) {
+    //Event.stop(e);
+    if (!this.menu) return;
+    this.cancelMenu();
+    this.unhighlight(); // in case highlighting was invoked externally
+    var cell=Event.element(e);
+    if (cell.className=='ricoLG_highlightDiv') {
+      var idx=this.highlightIdx;
+    } else {
+      cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+      if (!cell) return;
+      var idx=this.winCellIndex(cell);
+      if ((this.options.highlightSection & (idx.tabIdx+1))==0) return;
+    }
+    this.highlight(idx);
+    this.highlightEnabled=false;
+    if (this.hideScroll) this.scrollDiv.style.overflow="hidden";
+    this.menuIdx=idx;
+    if (!this.menu.div) this.menu.createDiv();
+    this.menu.liveGrid=this;
+    if (this.menu.buildGridMenu) {
+      var showMenu=this.menu.buildGridMenu(idx.row, idx.column, idx.tabIdx);
+      if (!showMenu) return;
+    }
+    if (this.options.highlightElem=='selection' && !this.isSelected(idx.cell))
+      this.selectCell(idx.cell);
+    this.menu.showmenu(e,this.closeMenu.bind(this));
+  },
+
+  closeMenu: function() {
+    if (!this.menuIdx) return;
+    if (this.hideScroll) this.scrollDiv.style.overflow="";
+    this.unhighlight();
+    this.highlightEnabled=true;
+    this.menuIdx=null;
+  },
+
+/**
+ * @return index of cell within the window
+ */
+  winCellIndex: function(cell) {
+    var a=cell.id.split(/_/);
+    var l=a.length;
+    var r=parseInt(a[l-2]);
+    var c=parseInt(a[l-1]);
+    return {row:r, column:c, tabIdx:this.columns[c].tabIdx, cell:cell};
+  },
+
+/**
+ * @return index of cell within the buffer
+ */
+  bufCellIndex: function(cell) {
+    var idx=this.winCellIndex(cell);
+    idx.row+=this.buffer.windowPos;
+    if (idx.row >= this.buffer.size) idx.onBlankRow=true;
+    return idx;
+  },
+
+  attachHighlightEvents: function(tBody) {
+    switch (this.options.highlightElem) {
+      case 'selection':
+        Event.observe(tBody,"mousedown", this.options.mouseDownHandler, false);
+        tBody.ondrag = function () { return false; };
+        tBody.onselectstart = function () { return false; };
+        break;
+      case 'cursorRow':
+      case 'cursorCell':
+        Event.observe(tBody,"mouseover", this.options.rowOverHandler, false);
+        break;
+    }
+  },
+
+  getVisibleSelection: function() {
+    var cellList=[];
+    if (this.SelectIdxStart && this.SelectIdxEnd) {
+      var r1=Math.max(Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row),this.buffer.windowPos);
+      var r2=Math.min(Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row),this.buffer.windowEnd-1);
+      var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+      var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+      for (var r=r1; r<=r2; r++)
+        for (var c=c1; c<=c2; c++)
+          cellList.push({row:r-this.buffer.windowPos,column:c});
+    }
+    if (this.SelectCtrl) {
+      for (var i=0; i<this.SelectCtrl.length; i++) {
+        if (this.SelectCtrl[i].row>=this.buffer.windowPos && this.SelectCtrl[i].row<this.buffer.windowEnd)
+          cellList.push({row:this.SelectCtrl[i].row-this.buffer.windowPos,column:this.SelectCtrl[i].column});
+      }
+    }
+    return cellList;
+  },
+
+  updateSelectOutline: function() {
+    if (!this.SelectIdxStart || !this.SelectIdxEnd) return;
+    var r1=Math.max(Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowStart);
+    var r2=Math.min(Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row), this.buffer.windowEnd-1);
+    if (r1 > r2) {
+      this.HideSelection();
+      return;
+    }
+    var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+    var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+    var top1=this.columns[c1].cell(r1-this.buffer.windowStart).offsetTop;
+    var cell2=this.columns[c1].cell(r2-this.buffer.windowStart);
+    var bottom2=cell2.offsetTop+cell2.offsetHeight;
+    var left1=this.columns[c1].dataCell.offsetLeft;
+    var left2=this.columns[c2].dataCell.offsetLeft;
+    var right2=left2+this.columns[c2].dataCell.offsetWidth;
+    //window.status='updateSelectOutline: '+r1+' '+r2+' top='+top1+' bot='+bottom2;
+    this.highlightDiv[0].style.top=this.highlightDiv[3].style.top=this.highlightDiv[1].style.top=(this.hdrHt+top1-1) + 'px';
+    this.highlightDiv[2].style.top=(this.hdrHt+bottom2-1)+'px';
+    this.highlightDiv[3].style.left=(left1-2)+'px';
+    this.highlightDiv[0].style.left=this.highlightDiv[2].style.left=(left1-1)+'px';
+    this.highlightDiv[1].style.left=(right2-1)+'px';
+    this.highlightDiv[0].style.width=this.highlightDiv[2].style.width=(right2-left1-1) + 'px';
+    this.highlightDiv[1].style.height=this.highlightDiv[3].style.height=(bottom2-top1) + 'px';
+    //this.highlightDiv[0].style.right=this.highlightDiv[2].style.right=this.highlightDiv[1].style.right=()+'px';
+    //this.highlightDiv[2].style.bottom=this.highlightDiv[3].style.bottom=this.highlightDiv[1].style.bottom=(this.hdrHt+bottom2) + 'px';
+    for (var i=0; i<4; i++)
+      this.highlightDiv[i].style.display='';
+  },
+
+  HideSelection: function(cellList) {
+    if (this.options.highlightMethod!='class') {
+      for (var i=0; i<4; i++)
+        this.highlightDiv[i].style.display='none';
+    }
+    if (this.options.highlightMethod!='outline') {
+      var cellList=this.getVisibleSelection();
+      for (var i=0; i<cellList.length; i++)
+        this.unhighlightCell(this.columns[cellList[i].column].cell(cellList[i].row));
+    }
+  },
+
+  ShowSelection: function() {
+    if (this.options.highlightMethod!='class')
+      this.updateSelectOutline();
+    if (this.options.highlightMethod!='outline') {
+      var cellList=this.getVisibleSelection();
+      for (var i=0; i<cellList.length; i++)
+        this.highlightCell(this.columns[cellList[i].column].cell(cellList[i].row));
+    }
+  },
+
+  ClearSelection: function() {
+    this.HideSelection();
+    this.SelectIdxStart=null;
+    this.SelectIdxEnd=null;
+    this.SelectCtrl=[];
+  },
+
+  selectCell: function(cell) {
+    this.ClearSelection();
+    this.SelectIdxStart=this.SelectIdxEnd=this.bufCellIndex(cell);
+    this.ShowSelection();
+  },
+
+  AdjustSelection: function(cell) {
+    var newIdx=this.bufCellIndex(cell);
+    if (this.SelectIdxStart.tabIdx != newIdx.tabIdx) return;
+    this.HideSelection();
+    this.SelectIdxEnd=newIdx;
+    this.ShowSelection();
+  },
+
+  RefreshSelection: function() {
+    var cellList=this.getVisibleSelection();
+    for (var i=0; i<cellList.length; i++)
+      this.columns[cellList[i].column].displayValue(cellList[i].row);
+  },
+
+  FillSelection: function(newVal,newStyle) {
+    if (this.SelectIdxStart && this.SelectIdxEnd) {
+      var r1=Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+      var r2=Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+      var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+      var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+      for (var r=r1; r<=r2; r++)
+        for (var c=c1; c<=c2; c++)
+          this.buffer.setValue(r,c,newVal,newStyle);
+    }
+    if (this.SelectCtrl) {
+      for (var i=0; i<this.SelectCtrl.length; i++)
+        this.buffer.setValue(this.SelectCtrl[i].row,this.SelectCtrl[i].column,newVal,newStyle);
+    }
+    this.RefreshSelection();
+  },
+
+  selectMouseDown: function(e) {
+    if (this.highlightEnabled==false) return true;
+    this.cancelMenu();
+    var cell=Event.element(e);
+    Event.stop(e);
+    if (!Event.isLeftClick(e)) return;
+    cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+    if (!cell) return;
+    var newIdx=this.bufCellIndex(cell);
+    if (newIdx.onBlankRow) return;
+    if (e.ctrlKey) {
+      if (!this.SelectIdxStart || this.options.highlightMethod!='class') return;
+      if (!this.isSelected(cell)) {
+        this.highlightCell(cell);
+        this.SelectCtrl.push(this.bufCellIndex(cell));
+      } else {
+        for (var i=0; i<this.SelectCtrl.length; i++) {
+          if (this.SelectCtrl[i].row==newIdx.row && this.SelectCtrl[i].column==newIdx.column) {
+            this.unhighlightCell(cell);
+            this.SelectCtrl.splice(i,1);
+            break;
+          }
+        }
+      }
+    } else if (e.shiftKey) {
+      if (!this.SelectIdxStart) return;
+      this.AdjustSelection(cell);
+    } else {
+      this.selectCell(cell);
+      this.pluginSelect();
+    }
+  },
+
+  pluginSelect: function() {
+    if (this.selectPluggedIn) return;
+    var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+    Event.observe(tBody,"mouseover", this.options.mouseOverHandler, false);
+    Event.observe(this.outerDiv,"mouseup",  this.options.mouseUpHandler,  false);
+    if (this.options.highlightMethod!='class')
+    this.selectPluggedIn=true;
+  },
+
+  unplugSelect: function() {
+    var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+    Event.stopObserving(tBody,"mouseover", this.options.mouseOverHandler , false);
+    Event.stopObserving(this.outerDiv,"mouseup", this.options.mouseUpHandler , false);
+    this.selectPluggedIn=false;
+  },
+
+  selectMouseUp: function(e) {
+    this.unplugSelect();
+    var cell=Event.element(e);
+    cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+    if (!cell) return;
+    if (this.SelectIdxStart && this.SelectIdxEnd)
+      this.AdjustSelection(cell);
+    else
+      this.ClearSelection();
+  },
+
+  selectMouseOver: function(e) {
+    var cell=Event.element(e);
+    cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+    if (!cell) return;
+    this.AdjustSelection(cell);
+    Event.stop(e);
+  },
+
+  isSelected: function(cell) {
+    return Element.hasClassName(cell,this.options.highlightClass);
+  },
+
+  highlightCell: function(cell) {
+    Element.addClassName(cell,this.options.highlightClass);
+  },
+
+  unhighlightCell: function(cell) {
+    if (cell==null) return;
+    Element.removeClassName(cell,this.options.highlightClass);
+  },
+
+  selectRow: function(r) {
+    for (var c=0; c<this.columns.length; c++)
+      this.highlightCell(this.columns[c].cell(r));
+  },
+
+  unselectRow: function(r) {
+    for (var c=0; c<this.columns.length; c++)
+      this.unhighlightCell(this.columns[c].cell(r));
+  },
+
+  rowMouseOver: function(e) {
+    if (!this.highlightEnabled) return;
+    var cell=Event.element(e);
+    cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+    if (!cell) return;
+    var newIdx=this.winCellIndex(cell);
+    if ((this.options.highlightSection & (newIdx.tabIdx+1))==0) return;
+    this.highlight(newIdx);
+  },
+
+  highlight: function(newIdx) {
+    if (this.options.highlightMethod!='outline') this.cursorSetClass(newIdx);
+    if (this.options.highlightMethod!='class') this.cursorOutline(newIdx);
+    this.highlightIdx=newIdx;
+  },
+
+  cursorSetClass: function(newIdx) {
+    switch (this.options.highlightElem) {
+      case 'menuCell':
+      case 'cursorCell':
+        if (this.highlightIdx) this.unhighlightCell(this.highlightIdx.cell);
+        this.highlightCell(newIdx.cell);
+        break;
+      case 'menuRow':
+      case 'cursorRow':
+        if (this.highlightIdx) this.unselectRow(this.highlightIdx.row);
+        var s1=this.options.highlightSection & 1;
+        var s2=this.options.highlightSection & 2;
+        var c0=s1 ? 0 : this.options.frozenColumns;
+        var c1=s2 ? this.columns.length : this.options.frozenColumns;
+        for (var c=c0; c<c1; c++)
+          this.highlightCell(this.columns[c].cell(newIdx.row));
+        break;
+      default: return;
+    }
+  },
+
+  cursorOutline: function(newIdx) {
+    switch (this.options.highlightElem) {
+      case 'menuCell':
+      case 'cursorCell':
+        var div=this.highlightDiv[newIdx.tabIdx];
+        div.style.left=(this.columns[newIdx.column].dataCell.offsetLeft-1)+'px';
+        div.style.width=this.columns[newIdx.column].colWidth;
+        this.highlightDiv[1-newIdx.tabIdx].style.display='none';
+        break;
+      case 'menuRow':
+      case 'cursorRow':
+        var div=this.highlightDiv[0];
+        var s1=this.options.highlightSection & 1;
+        var s2=this.options.highlightSection & 2;
+        div.style.left=s1 ? '0px' : this.frozenTabs.style.width;
+        div.style.width=((s1 ? this.frozenTabs.offsetWidth : 0) + (s2 ? this.innerDiv.offsetWidth : 0) - 4)+'px';
+        break;
+      default: return;
+    }
+    div.style.top=(this.hdrHt+newIdx.row*this.rowHeight-1)+'px';
+    div.style.height=(this.rowHeight-1)+'px';
+    div.style.display='';
+  },
+
+  unhighlight: function() {
+    switch (this.options.highlightElem) {
+      case 'menuCell':
+        this.highlightIdx=this.menuIdx;
+      case 'cursorCell':
+        if (this.highlightIdx) this.unhighlightCell(this.highlightIdx.cell);
+        if (!this.highlightDiv) return;
+        for (var i=0; i<2; i++)
+          this.highlightDiv[i].style.display='none';
+        break;
+      case 'menuRow':
+        this.highlightIdx=this.menuIdx;
+      case 'cursorRow':
+        if (this.highlightIdx) this.unselectRow(this.highlightIdx.row);
+        if (this.highlightDiv) this.highlightDiv[0].style.display='none';
+        break;
+    }
+  },
+
+  hideMsg: function() {
+    if (this.messageDiv.style.display=="none") return;
+    this.messageDiv.style.display="none";
+    this.messageShadow.hide();
+  },
+
+  showMsg: function(msg) {
+    this.messageDiv.innerHTML=RicoTranslate.getPhrase(msg);
+    this.messageDiv.style.display="";
+    var msgWidth=this.messageDiv.offsetWidth;
+    var msgHeight=this.messageDiv.offsetHeight;
+    var divwi=this.outerDiv.offsetWidth;
+    var divht=this.outerDiv.offsetHeight;
+    this.messageDiv.style.top=parseInt((divht-msgHeight)/2)+'px';
+    this.messageDiv.style.left=parseInt((divwi-msgWidth)/2)+'px';
+    this.messageShadow.show();
+    Rico.writeDebugMsg("showMsg: "+msg);
+  },
+
+  resetContents: function(resetHt) {
+    Rico.writeDebugMsg("resetContents("+resetHt+")");
+    this.buffer.clear();
+    this.clearRows();
+    if (typeof resetHt=='undefined' || resetHt==true) {
+      this.buffer.setTotalRows(0);
+    } else {
+      this.scrollToRow(0);
+    }
+    if (this.bookmark) this.bookmark.innerHTML="&nbsp;";
+  },
+
+  setImages: function() {
+    for (n=0; n<this.columns.length; n++)
+      this.columns[n].setImage();
+  },
+
+  // returns column index, or -1 if there are no sorted columns
+  findSortedColumn: function() {
+    for (var n=0; n<this.columns.length; n++)
+      if (this.columns[n].isSorted()) return n;
+    return -1;
+  },
+
+  findColumnName: function(name) {
+    for (var n=0; n<this.columns.length; n++)
+      if (this.columns[n].fieldName == name) return n;
+    return -1;
+  },
+
+/**
+ * Set initial sort
+ */
+  setSortUI: function( columnNameOrNum, sortDirection ) {
+    Rico.writeDebugMsg("setSortUI: "+columnNameOrNum+' '+sortDirection);
+    var colnum=this.findSortedColumn();
+    if (colnum >= 0) {
+      sortDirection=this.columns[colnum].getSortDirection();
+    } else {
+      if (typeof sortDirection!='string') {
+        sortDirection=Rico.TableColumn.SORT_ASC;
+      } else {
+        sortDirection=sortDirection.toUpperCase();
+        if (sortDirection != Rico.TableColumn.SORT_DESC) sortDirection=Rico.TableColumn.SORT_ASC;
+      }
+      switch (typeof columnNameOrNum) {
+        case 'string':
+          colnum=this.findColumnName(columnNameOrNum);
+          break;
+        case 'number':
+          colnum=columnNameOrNum;
+          break;
+      }
+    }
+    if (typeof(colnum)!='number' || colnum < 0) return;
+    this.clearSort();
+    this.columns[colnum].setSorted(sortDirection);
+    this.buffer.sortBuffer(colnum,sortDirection,this.columns[colnum].format.type,this.columns[colnum]._sortfunc);
+  },
+
+/**
+ * clear sort flag on all columns
+ */
+  clearSort: function() {
+    for (var x=0;x<this.columns.length;x++)
+      this.columns[x].setUnsorted();
+  },
+
+/**
+ * clear filters on all columns
+ */
+  clearFilters: function() {
+    for (var x=0;x<this.columns.length;x++)
+      this.columns[x].setUnfiltered(true);
+    if (this.options.filterHandler)
+      this.options.filterHandler();
+  },
+
+/**
+ * returns number of columns with a user filter set
+ */
+  filterCount: function() {
+    for (var x=0,cnt=0;x<this.columns.length;x++)
+      if (this.columns[x].isFiltered()) cnt++;
+    return cnt;
+  },
+
+  sortHandler: function() {
+    this.cancelMenu();
+    this.setImages();
+    var n=this.findSortedColumn();
+    if (n < 0) return;
+    Rico.writeDebugMsg("sortHandler: sorting column "+n);
+    this.buffer.sortBuffer(n,this.columns[n].getSortDirection(),this.columns[n].format.type,this.columns[n]._sortfunc);
+    this.clearRows();
+    this.scrollDiv.scrollTop = 0;
+    this.buffer.fetch(0);
+  },
+
+  filterHandler: function() {
+    Rico.writeDebugMsg("filterHandler");
+    this.cancelMenu();
+    this.ClearSelection();
+    this.setImages();
+    if (this.bookmark) this.bookmark.innerHTML="&nbsp;";
+    this.clearRows();
+    this.buffer.fetch(-1);
+  },
+
+  bookmarkHandler: function(firstrow,lastrow) {
+    if (isNaN(firstrow) || !this.bookmark) return;
+    var totrows=this.buffer.totalRows;
+    if (totrows < lastrow) lastrow=totrows;
+    if (totrows<=0) {
+      var newhtml = RicoTranslate.getPhrase("No matching records");
+    } else if (lastrow<0) {
+      var newhtml = RicoTranslate.getPhrase("No records");
+    } else {
+      var newhtml = RicoTranslate.getPhrase("Listing records")+" "+firstrow+" - "+lastrow;
+      var totphrase = this.buffer.foundRowCount ? "of" : "of about";
+      newhtml+=" "+RicoTranslate.getPhrase(totphrase)+" "+totrows;
+    }
+    this.bookmark.innerHTML = newhtml;
+  },
+
+/**
+ * @return array of column objects which have invisible status
+ */
+  listInvisible: function() {
+    var hiddenColumns=new Array();
+    for (var x=0;x<this.columns.length;x++)
+      if (this.columns[x].visible==false)
+        hiddenColumns.push(this.columns[x]);
+    return hiddenColumns;
+  },
+
+/**
+ * Show all columns
+ */
+  showAll: function() {
+    var invisible=this.listInvisible();
+    for (var x=0;x<invisible.length;x++)
+      invisible[x].showColumn();
+  },
+
+  clearRows: function() {
+    if (this.isBlank==true) return;
+    for (var c=0; c < this.columns.length; c++)
+      this.columns[c].clearColumn();
+    this.ClearSelection();
+    this.isBlank = true;
+  },
+
+  blankRow: function(r) {
+     for (var c=0; c < this.columns.length; c++)
+        this.columns[c].clearCell(r);
+  },
+
+  refreshContents: function(startPos) {
+    Rico.writeDebugMsg("refreshContents: startPos="+startPos+" lastRow="+this.lastRowPos+" PartBlank="+this.isPartialBlank+" pageSize="+this.pageSize);
+    this.hideMsg();
+    this.cancelMenu();
+    this.unhighlight(); // in case highlighting was manually invoked
+    this.highlightEnabled=this.options.highlightSection!='none';
+    if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) return;
+    this.isBlank = false;
+    var viewPrecedesBuffer = this.buffer.startPos > startPos
+    var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
+    var contentEndPos = Math.min(this.buffer.startPos + this.buffer.size, startPos + this.pageSize);
+    var onRefreshComplete = this.options.onRefreshComplete;
+
+    if ((startPos + this.pageSize < this.buffer.startPos)
+        || (this.buffer.startPos + this.buffer.size < startPos)
+        || (this.buffer.size == 0)) {
+      this.clearRows();
+      if (onRefreshComplete != null)
+          onRefreshComplete(contentStartPos+1,contentEndPos);
+      return;
+    }
+
+    Rico.writeDebugMsg('refreshContents: contentStartPos='+contentStartPos+' contentEndPos='+contentEndPos+' viewPrecedesBuffer='+viewPrecedesBuffer);
+    if (this.options.highlightElem=='selection') this.HideSelection();
+    var rowSize = contentEndPos - contentStartPos;
+    this.buffer.setWindow(contentStartPos, rowSize );
+    var blankSize = this.pageSize - rowSize;
+    var blankOffset = viewPrecedesBuffer ? 0: rowSize;
+    var contentOffset = viewPrecedesBuffer ? blankSize: 0;
+
+    for (var r=0; r < rowSize; r++) { //initialize what we have
+      for (var c=0; c < this.columns.length; c++)
+        this.columns[c].displayValue(r + contentOffset);
+    }
+    for (var i=0; i < blankSize; i++)     // blank out the rest
+      this.blankRow(i + blankOffset);
+    if (this.options.highlightElem=='selection') this.ShowSelection();
+    this.isPartialBlank = blankSize > 0;
+    this.lastRowPos = startPos;
+    Rico.writeDebugMsg("refreshContents complete, startPos="+startPos);
+    // Check if user has set a onRefreshComplete function
+    if (onRefreshComplete != null)
+      onRefreshComplete(contentStartPos+1,contentEndPos);
+  },
+
+  scrollToRow: function(rowOffset) {
+     var p=this.rowToPixel(rowOffset);
+     Rico.writeDebugMsg("scrollToRow, rowOffset="+rowOffset+" pixel="+p);
+     this.scrollDiv.scrollTop = p; // this causes a scroll event
+     if ( this.options.onscroll )
+        this.options.onscroll( this, rowOffset );
+  },
+
+  scrollUp: function() {
+     this.moveRelative(-1);
+  },
+
+  scrollDown: function() {
+     this.moveRelative(1);
+  },
+
+  pageUp: function() {
+     this.moveRelative(-this.pageSize);
+  },
+
+  pageDown: function() {
+     this.moveRelative(this.pageSize);
+  },
+
+  adjustRow: function(rowOffset) {
+     var notdisp=this.topOfLastPage();
+     if (notdisp == 0 || !rowOffset) return 0;
+     return Math.min(notdisp,rowOffset);
+  },
+
+  rowToPixel: function(rowOffset) {
+     return this.adjustRow(rowOffset) * this.rowHeight;
+  },
+
+/**
+ * @returns row to display at top of scroll div
+ */
+  pixeltorow: function(p) {
+     var notdisp=this.topOfLastPage();
+     if (notdisp == 0) return 0;
+     var prow=parseInt(p/this.rowHeight);
+     return Math.min(notdisp,prow);
+  },
+
+  moveRelative: function(relOffset) {
+     newoffset=Math.max(this.scrollDiv.scrollTop+relOffset*this.rowHeight,0);
+     newoffset=Math.min(newoffset,this.scrollDiv.scrollHeight);
+     //Rico.writeDebugMsg("moveRelative, newoffset="+newoffset);
+     this.scrollDiv.scrollTop=newoffset;
+  },
+
+  pluginScroll: function() {
+     if (this.scrollPluggedIn) return;
+     Rico.writeDebugMsg("pluginScroll: wheelEvent="+this.wheelEvent);
+     Event.observe(this.scrollDiv,"scroll",this.scrollEventFunc, false);
+     for (var t=0; t<2; t++)
+       Event.observe(this.tabs[t],this.wheelEvent,this.wheelEventFunc, false);
+     this.scrollPluggedIn=true;
+  },
+
+  unplugScroll: function() {
+     if (!this.scrollPluggedIn) return;
+     Rico.writeDebugMsg("unplugScroll");
+     Event.stopObserving(this.scrollDiv,"scroll", this.scrollEventFunc , false);
+     for (var t=0; t<2; t++)
+       Event.stopObserving(this.tabs[t],this.wheelEvent,this.wheelEventFunc, false);
+     this.scrollPluggedIn=false;
+  },
+
+  handleWheel: function(e) {
+    var delta = 0;
+    if (e.wheelDelta) {
+      if (Prototype.Browser.Opera)
+        delta = e.wheelDelta/120;
+      else if (Prototype.Browser.WebKit)
+        delta = -e.wheelDelta/12;
+      else
+        delta = -e.wheelDelta/120;
+    } else if (e.detail) {
+      delta = e.detail/3; /* Mozilla/Gecko */
+    }
+    if (delta) this.moveRelative(delta);
+    Event.stop(e);
+    return false;
+  },
+
+  handleScroll: function(e) {
+     if ( this.scrollTimeout )
+       clearTimeout( this.scrollTimeout );
+     this.setHorizontalScroll();
+     var scrtop=this.scrollDiv.scrollTop;
+     var vscrollDiff = this.lastScrollPos-scrtop;
+     if (vscrollDiff == 0.00) return;
+     var newrow=this.pixeltorow(scrtop);
+     if (newrow == this.lastRowPos && !this.isPartialBlank && !this.isBlank) return;
+     var stamp1 = new Date();
+     //Rico.writeDebugMsg("handleScroll, newrow="+newrow+" scrtop="+scrtop);
+     this.buffer.fetch(newrow);
+     if (this.options.onscroll) this.options.onscroll(this, newrow);
+     this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
+     this.lastScrollPos = this.scrollDiv.scrollTop;
+     var stamp2 = new Date();
+     //Rico.writeDebugMsg("handleScroll, time="+(stamp2.getTime()-stamp1.getTime()));
+  },
+
+  scrollIdle: function() {
+     if ( this.options.onscrollidle )
+        this.options.onscrollidle();
+  },
+
+  printAll: function(exportType) {
+    this.exportStart();
+    this.buffer.exportAllRows(this.exportBuffer.bind(this),this.exportFinish.bind(this,exportType));
+  },
+
+/**
+ * Send all rows to print window
+ */
+  exportBuffer: function(rows) {
+    for(var r=0; r < rows.length; r++) {
+      this.exportText+="<tr>";
+      for (var c=0; c<this.columns.length; c++) {
+        if (this.columns[c].visible)
+          this.exportText+="<td>"+this.columns[c]._format(rows[r][c].content)+"</td>";
+      }
+      this.exportText+="</tr>";
+    }
+  }
+
+};
+
+
+Object.extend(Rico.TableColumn.prototype, {
+
+initialize: function(liveGrid,colIdx,hdrInfo,tabIdx) {
+  this.baseInit(liveGrid,colIdx,hdrInfo,tabIdx);
+  Rico.writeDebugMsg(" sortable="+this.sortable+" filterable="+this.filterable+" hideable="+this.hideable+" isNullable="+this.isNullable+' isText='+this.isText);
+  this.fixHeaders(this.liveGrid.tableId, this.options.hdrIconsFirst);
+  if (this.format.type=='control' && this.format.control) {
+    // copy all properties/methods that start with '_'
+    if (typeof this.format.control=='string')
+      this.format.control=eval(this.format.control);
+    for (var property in this.format.control)
+      if (property.charAt(0)=='_') {
+        Rico.writeDebugMsg("Copying control property "+property);
+        this[property] = this.format.control[property];
+      }
+  } else if (this['format_'+this.format.type]) {
+    this._format=this['format_'+this.format.type].bind(this);
+  }
+},
+
+sortAsc: function() {
+  this.setColumnSort(Rico.TableColumn.SORT_ASC);
+},
+
+sortDesc: function() {
+  this.setColumnSort(Rico.TableColumn.SORT_DESC);
+},
+
+setColumnSort: function(direction) {
+  this.liveGrid.clearSort();
+  this.setSorted(direction);
+  if (this.liveGrid.options.saveColumnInfo.sort)
+    this.liveGrid.setCookie();
+  if (this.options.sortHandler)
+    this.options.sortHandler();
+},
+
+isSortable: function() {
+  return this.sortable;
+},
+
+isSorted: function() {
+  return this.currentSort != Rico.TableColumn.UNSORTED;
+},
+
+getSortDirection: function() {
+  return this.currentSort;
+},
+
+toggleSort: function() {
+  if (this.liveGrid.buffer && this.liveGrid.buffer.totalRows==0) return;
+  if (this.currentSort == Rico.TableColumn.SORT_ASC)
+    this.sortDesc();
+  else
+    this.sortAsc();
+},
+
+setUnsorted: function() {
+  this.setSorted(Rico.TableColumn.UNSORTED);
+},
+
+/**
+ * direction must be one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC
+ */
+setSorted: function(direction) {
+  this.currentSort = direction;
+},
+
+canFilter: function() {
+  return this.filterable;
+},
+
+getFilterText: function() {
+  var vals=[];
+  for (var i=0; i<this.filterValues.length; i++) {
+    var v=this.filterValues[i];
+    if (v!=null && v.match(/<span\s+class=(['"]?)ricolookup\1>(.*)<\/span>/i))
+      vals.push(RegExp.leftContext);
+    else
+      vals.push(v);
+  }
+  switch (this.filterOp) {
+    case 'EQ':   return vals[0];
+    case 'NE':   return 'not: '+vals.join(', ');
+    case 'LE':   return '<= '+vals[0];
+    case 'GE':   return '>= '+vals[0];
+    case 'LIKE': return 'like: '+vals[0];
+    case 'NULL': return '<empty>';
+    case 'NOTNULL': return '<not empty>';
+  }
+  return '?';
+},
+
+getFilterQueryParm: function() {
+  if (this.filterType == Rico.TableColumn.UNFILTERED) return '';
+  var retval='&f['+this.index+'][op]='+this.filterOp;
+  retval+='&f['+this.index+'][len]='+this.filterValues.length
+  for (var i=0; i<this.filterValues.length; i++)
+    retval+='&f['+this.index+']['+i+']='+escape(this.filterValues[i]);
+  return retval;
+},
+
+setUnfiltered: function(skipHandler) {
+  this.filterType = Rico.TableColumn.UNFILTERED;
+  if (this.liveGrid.options.saveColumnInfo.filter)
+    this.liveGrid.setCookie();
+  if (this.removeFilterFunc)
+    this.removeFilterFunc();
+  if (this.options.filterHandler && !skipHandler)
+    this.options.filterHandler();
+},
+
+setFilterEQ: function() {
+  if (this.userFilter=='' && this.isNullable)
+    this.setUserFilter('NULL');
+  else
+    this.setUserFilter('EQ');
+},
+setFilterNE: function() {
+  if (this.userFilter=='' && this.isNullable)
+    this.setUserFilter('NOTNULL');
+  else
+    this.setUserFilter('NE');
+},
+addFilterNE: function() {
+  this.filterValues.push(this.userFilter);
+  if (this.liveGrid.options.saveColumnInfo.filter)
+    this.liveGrid.setCookie();
+  if (this.options.filterHandler)
+    this.options.filterHandler();
+},
+setFilterGE: function() { this.setUserFilter('GE'); },
+setFilterLE: function() { this.setUserFilter('LE'); },
+setFilterKW: function() {
+  var keyword=prompt(RicoTranslate.getPhrase("Enter keyword to search for")+RicoTranslate.getPhrase(" (use * as a wildcard):"),'');
+  if (keyword!='' && keyword!=null) {
+    if (keyword.indexOf('*')==-1) keyword='*'+keyword+'*';
+    this.setFilter('LIKE',keyword,Rico.TableColumn.USERFILTER);
+  } else {
+    this.liveGrid.cancelMenu();
+  }
+},
+
+setUserFilter: function(relop) {
+  this.setFilter(relop,this.userFilter,Rico.TableColumn.USERFILTER);
+},
+
+setSystemFilter: function(relop,filter) {
+  this.setFilter(relop,filter,Rico.TableColumn.SYSTEMFILTER);
+},
+
+setFilter: function(relop,filter,type,removeFilterFunc) {
+  this.filterValues = [filter];
+  this.filterType = type;
+  this.filterOp = relop;
+  if (type == Rico.TableColumn.USERFILTER && this.liveGrid.options.saveColumnInfo.filter)
+    this.liveGrid.setCookie();
+  this.removeFilterFunc=removeFilterFunc;
+  if (this.options.filterHandler)
+    this.options.filterHandler();
+},
+
+isFiltered: function() {
+  return this.filterType == Rico.TableColumn.USERFILTER;
+},
+
+format_text: function(v) {
+  if (typeof v!='string')
+    return '&nbsp;';
+  else
+    return v.stripTags();
+},
+
+format_showTags: function(v) {
+  if (typeof v!='string')
+    return '&nbsp;';
+  else
+    return v.replace(/&/g, '&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+},
+
+format_number: function(v) {
+  if (typeof v=='undefined' || v=='' || v==null)
+    return '&nbsp;';
+  else
+    return v.formatNumber(this.format);
+},
+
+format_datetime: function(v) {
+  if (typeof v=='undefined' || v=='' || v==null)
+    return '&nbsp;';
+  else {
+    var d=new Date;
+    d.setISO8601(v);
+    return d.formatDate(this.format.dateFmt || 'translateDateTime');
+  }
+},
+
+format_date: function(v) {
+  if (typeof v=='undefined' || v==null || v=='')
+    return '&nbsp;';
+  else {
+    var d=new Date;
+    if (!d.setISO8601(v)) return v;
+    return d.formatDate(this.format.dateFmt || 'translateDate');
+  }
+},
+
+fixHeaders: function(prefix, iconsfirst) {
+  if (this.sortable) {
+    switch (this.options.headingSort) {
+      case 'link':
+        var a=RicoUtil.wrapChildren(this.hdrCellDiv,'ricoSort',undefined,'a')
+        a.href = "#";
+        a.onclick = this.toggleSort.bindAsEventListener(this);
+        break;
+      case 'hover':
+        this.hdrCellDiv.onclick = this.toggleSort.bindAsEventListener(this);
+        break;
+    }
+  }
+  this.imgFilter = document.createElement('img');
+  this.imgFilter.style.display='none';
+  this.imgFilter.src=Rico.imgDir+this.options.filterImg;
+  this.imgFilter.className='ricoLG_HdrIcon';
+  this.imgSort = document.createElement('img');
+  this.imgSort.style.display='none';
+  this.imgSort.className='ricoLG_HdrIcon';
+  if (iconsfirst) {
+    this.hdrCellDiv.insertBefore(this.imgSort,this.hdrCellDiv.firstChild);
+    this.hdrCellDiv.insertBefore(this.imgFilter,this.hdrCellDiv.firstChild);
+  } else {
+    this.hdrCellDiv.appendChild(this.imgFilter);
+    this.hdrCellDiv.appendChild(this.imgSort);
+  }
+},
+
+getValue: function(windowRow) {
+  return this.liveGrid.buffer.getWindowValue(windowRow,this.index);
+},
+
+getFormattedValue: function(windowRow) {
+  return this._format(this.getValue(windowRow));
+},
+
+getBufferCell: function(windowRow) {
+  return this.liveGrid.buffer.getWindowCell(windowRow,this.index);
+},
+
+setValue: function(windowRow,newval) {
+  this.liveGrid.buffer.setWindowValue(windowRow,this.index,newval);
+},
+
+_format: function(v) {
+  return v;
+},
+
+_display: function(v,gridCell) {
+  gridCell.innerHTML=this._format(v);
+},
+
+displayValue: function(windowRow) {
+  var bufCell=this.getBufferCell(windowRow);
+  if (!bufCell) {
+    this.clearCell(windowRow);
+    return;
+  }
+  var gridCell=this.cell(windowRow);
+  this._display(bufCell.content,gridCell,windowRow);
+  var acceptAttr=this.liveGrid.buffer.options.acceptAttr;
+  for (var k=0; k<acceptAttr.length; k++) {
+    var bufAttr=bufCell['_'+acceptAttr[k]] || '';
+    switch (acceptAttr[k]) {
+      case 'style': gridCell.style.cssText=bufAttr; break;
+      case 'class': gridCell.className=bufAttr; break;
+      default:      gridCell['_'+acceptAttr[k]]=bufAttr; break;
+    }
+  }
+}
+
+});
+
+Rico.TableColumn.checkbox = Class.create();
+
+Rico.TableColumn.checkbox.prototype = {
+
+  initialize: function(checkedValue, uncheckedValue, defaultValue, readOnly) {
+    this._checkedValue=checkedValue;
+    this._uncheckedValue=uncheckedValue;
+    this._defaultValue=defaultValue || false;
+    this._readOnly=readOnly || false;
+    this._checkboxes=[];
+  },
+
+  _create: function(gridCell,windowRow) {
+    this._checkboxes[windowRow]=RicoUtil.createFormField(gridCell,'input','checkbox',this.liveGrid.tableId+'_chkbox_'+this.index+'_'+windowRow);
+    this._clear(gridCell,windowRow);
+    if (this._readOnly)
+      this._checkboxes[windowRow].disabled=true;
+    else
+      Event.observe(this._checkboxes[windowRow], "click", this._onclick.bindAsEventListener(this), false);
+  },
+
+  _onclick: function(e) {
+    var elem=Event.element(e);
+    var windowRow=parseInt(elem.id.split(/_/).pop());
+    var newval=elem.checked ? this._checkedValue : this._uncheckedValue;
+    this.setValue(windowRow,newval);
+  },
+
+  _clear: function(gridCell,windowRow) {
+    this._checkboxes[windowRow].checked=this._defaultValue;
+  },
+
+  _display: function(v,gridCell,windowRow) {
+    this._checkboxes[windowRow].checked=(v==this._checkedValue);
+  }
+
+}
+
+Rico.TableColumn.link = Class.create();
+
+Rico.TableColumn.link.prototype = {
+
+  initialize: function(href,target) {
+    this._href=href;
+    this._target=target;
+    this._anchors=[];
+  },
+
+  _create: function(gridCell,windowRow) {
+    this._anchors[windowRow]=RicoUtil.createFormField(gridCell,'a',null,this.liveGrid.tableId+'_a_'+this.index+'_'+windowRow);
+    if (this._target) this._anchors[windowRow].target=this._target;
+    this._clear(gridCell,windowRow);
+  },
+
+  _clear: function(gridCell,windowRow) {
+    this._anchors[windowRow].href='';
+    this._anchors[windowRow].innerHTML='';
+  },
+
+  _display: function(v,gridCell,windowRow) {
+    this._anchors[windowRow].innerHTML=v;
+    var getWindowValue=this.liveGrid.buffer.getWindowValue.bind(this.liveGrid.buffer);
+    this._anchors[windowRow].href=this._href.replace(/\{\d+\}/g,
+      function ($1) {
+        var colIdx=parseInt($1.substr(1));
+        return getWindowValue(windowRow,colIdx);
+      }
+    );
+  }
+
+}
+
+Rico.TableColumn.lookup = Class.create();
+
+Rico.TableColumn.lookup.prototype = {
+
+  initialize: function(map, defaultCode, defaultDesc) {
+    this._map=map;
+    this._defaultCode=defaultCode || '';
+    this._defaultDesc=defaultDesc || '&nbsp;';
+    this._sortfunc=this._sortvalue.bind(this);
+    this._codes=[];
+    this._descriptions=[];
+  },
+
+  _create: function(gridCell,windowRow) {
+    this._descriptions[windowRow]=RicoUtil.createFormField(gridCell,'span',null,this.liveGrid.tableId+'_desc_'+this.index+'_'+windowRow);
+    this._codes[windowRow]=RicoUtil.createFormField(gridCell,'input','hidden',this.liveGrid.tableId+'_code_'+this.index+'_'+windowRow);
+    this._clear(gridCell,windowRow);
+  },
+
+  _clear: function(gridCell,windowRow) {
+    this._codes[windowRow].value=this._defaultCode;
+    this._descriptions[windowRow].innerHTML=this._defaultDesc;
+  },
+
+  _sortvalue: function(v) {
+    return this._getdesc(v).replace(/&amp;/g, '&').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&nbsp;/g,' ');
+  },
+
+  _getdesc: function(v) {
+    var desc=this._map[v];
+    return (typeof desc=='string') ? desc : this._defaultDesc;
+  },
+
+  _display: function(v,gridCell,windowRow) {
+    this._codes[windowRow].value=v;
+    this._descriptions[windowRow].innerHTML=this._getdesc(v);
+  }
+
+}
+
+Rico.includeLoaded('ricoLiveGrid.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridAjax.js b/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridAjax.js
new file mode 100644 (file)
index 0000000..ab193ff
--- /dev/null
@@ -0,0 +1,412 @@
+if(typeof Rico=='undefined') throw("LiveGridAjax requires the Rico JavaScript framework");
+if(typeof RicoUtil=='undefined') throw("LiveGridAjax requires the RicoUtil object");
+if(typeof Rico.Buffer=='undefined') throw("LiveGridAjax requires the Rico.Buffer object");
+
+
+/**
+ * Data source is a static XML file located on the server
+ */
+Rico.Buffer.AjaxXML = Class.create();
+
+Rico.Buffer.AjaxXML.prototype = {
+
+  initialize: function(url,options,ajaxOptions) {
+    Object.extend(this, new Rico.Buffer.Base());
+    Object.extend(this, new Rico.Buffer.AjaxXMLMethods);
+    this.dataSource=url;
+    this.options.bufferTimeout = 20000;  // time to wait for ajax response (milliseconds)
+    this.options.requestParameters = [];
+    Object.extend(this.options, options || {});
+    this.ajaxOptions = { parameters: null, method : 'get' };
+    Object.extend(this.ajaxOptions, ajaxOptions || {});
+    this.requestCount=0;
+    this.processingRequest=false;
+    this.pendingRequest=-1;
+  }
+}
+
+Rico.Buffer.AjaxXMLMethods = function() {};
+
+Rico.Buffer.AjaxXMLMethods.prototype = {
+
+  fetch: function(offset) {
+    if ( this.isInRange(offset) ) {
+      Rico.writeDebugMsg("AjaxXML fetch: in buffer");
+      this.liveGrid.refreshContents(offset);
+      return;
+    }
+    this.processingRequest=true
+    Rico.writeDebugMsg("AjaxXML fetch, offset="+offset);
+    this.liveGrid.showMsg("Waiting for data...");
+    this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
+    this.sendAjaxRequest(offset,0,this.ajaxUpdate.bind(this,offset));
+  },
+
+/**
+ * Server did not respond in time... assume that there could have been
+ * an error, and allow requests to be processed again.
+ */
+  handleTimedOut: function() {
+    Rico.writeDebugMsg("Request Timed Out");
+    this.liveGrid.showMsg("Request for data timed out!");
+  },
+
+  formQueryHash: function(startPos,fetchSize) {
+    if (typeof fetchSize!='number') fetchSize=this.totalRows;
+    var queryHash= {
+      id: this.liveGrid.tableId,
+      page_size: fetchSize,
+      offset: startPos
+    };
+    if (!this.foundRowCount) queryHash['get_total']='true';
+    if (this.options.requestParameters) {
+      for ( var i=0; i < this.options.requestParameters.length; i++ ) {
+        var anArg = this.options.requestParameters[i];
+        if ( anArg.name != undefined && anArg.value != undefined ) {
+          queryHash[anArg.name]=anArg.value;
+        } else {
+          var ePos  = anArg.indexOf('=');
+          var argName  = anArg.substring( 0, ePos );
+          var argValue = anArg.substring( ePos + 1 );
+          queryHash[argName]=argValue;
+        }
+      }
+    }
+    
+    // sort
+    Object.extend(queryHash,this.sortParm);
+
+    // filters
+    for (n=0; n<this.liveGrid.columns.length; n++) {
+      var c=this.liveGrid.columns[n];
+      if (c.filterType == Rico.TableColumn.UNFILTERED) continue;
+      queryHash['f['+c.index+'][op]']=c.filterOp;
+      queryHash['f['+c.index+'][len]']=c.filterValues.length
+      for (var i=0; i<c.filterValues.length; i++)
+        queryHash['f['+c.index+']['+i+']']=c.filterValues[i];
+    }
+      
+    return $H(queryHash);
+  },
+
+  sendAjaxRequest: function(startPos,fetchSize,onComplete) {
+    this.ajaxOptions.parameters = this.formQueryHash(startPos,fetchSize);
+    this.ajaxOptions.onComplete = onComplete;
+    this.requestCount++;
+    Rico.writeDebugMsg('req '+this.requestCount+':'+this.ajaxOptions.parameters.inspect());
+    new Ajax.Request(this.dataSource, this.ajaxOptions);
+  },
+  
+  clearTimer: function() {
+    if(typeof this.timeoutHandler != "number") return;
+    window.clearTimeout(this.timeoutHandler);
+    delete this.timeoutHandler;
+  },
+
+  ajaxUpdate: function(startPos,request) {
+    this.clearTimer();
+    this.processingRequest=false;
+    if (request.status != 200) {
+      Rico.writeDebugMsg("ajaxUpdate: received http error="+request.status);
+      this.liveGrid.showMsg('Received HTTP error: '+request.status);
+      return;
+    }
+    var response = request.responseXML.getElementsByTagName("ajax-response");
+    if (response == null || response.length != 1) return;
+    this.updateBuffer(response[0],startPos);
+    this.CheckRowCount(response[0],startPos);
+    if (this.options.TimeOut && this.timerMsg)
+      this.restartSessionTimer();
+    if (this.options.onAjaxUpdate)
+      this.options.onAjaxUpdate();
+    if (this.pendingRequest>=0) {
+      var offset=this.pendingRequest;
+      Rico.writeDebugMsg("ajaxUpdate: found pending request for offset="+offset);
+      this.pendingRequest=-1;
+      this.fetch(offset);
+    }
+  },
+
+  CheckRowCount: function(ajaxResponse,offset) {
+    //try {
+      Rico.writeDebugMsg("CheckRowCount, size="+this.size+' rcv cnt type='+typeof(this.rowcntContent));
+      if (this.rcvdRowCount==true) {
+        Rico.writeDebugMsg("found row cnt: "+this.rowcntContent);
+        var eofrow=parseInt(this.rowcntContent);
+        var lastTotalRows=this.totalRows;
+        if (!isNaN(eofrow) && eofrow!=lastTotalRows) {
+          this.setTotalRows(eofrow);
+          var newpos=Math.min(this.liveGrid.topOfLastPage(),offset);
+          Rico.writeDebugMsg("CheckRowCount: new rowcnt="+eofrow+" newpos="+newpos);
+          if (lastTotalRows==0 && this.liveGrid.sizeTo=='data')
+            this.liveGrid.adjustPageSize();
+          //this.lastRowPos=-1;
+          this.liveGrid.scrollToRow(newpos);
+          if ( this.isInRange(newpos) ) {
+            this.liveGrid.refreshContents(newpos);
+          } else {
+            this.fetch(newpos);
+          }
+          return;
+        }
+      } else {
+        var lastbufrow=offset+this.rcvdRows;
+        if (lastbufrow>this.totalRows) {
+          var newcnt=lastbufrow;
+          Rico.writeDebugMsg("extending totrows to "+newcnt);
+          this.setTotalRows(newcnt);
+        }
+      }
+      var newpos=this.liveGrid.pixeltorow(this.liveGrid.scrollDiv.scrollTop);
+      Rico.writeDebugMsg("CheckRowCount: newpos="+newpos);
+      this.liveGrid.refreshContents(newpos);
+    //}
+    //catch(err) {
+    //  alert("Error in CheckRowCount:"+err.message);
+    //}
+  },
+
+  updateBuffer: function(ajaxResponse, start) {
+    Rico.writeDebugMsg("updateBuffer: "+start);
+    this.rcvdRows = 0;
+    var newRows = this.loadRows(ajaxResponse);
+    if (newRows==null) return;
+    this.rcvdRows = newRows.length;
+    Rico.writeDebugMsg("updateBuffer: # of rows="+this.rcvdRows);
+    if (this.rows.length == 0) { // initial load
+      this.rows = newRows;
+      this.startPos = start;
+    } else 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.maxBufferSize && this.rows.length > this.maxBufferSize)
+          this.rows = this.rows.slice(0, this.maxBufferSize)
+      }
+      this.startPos =  start;
+    }
+    this.size = this.rows.length;
+  },
+
+  loadRows: function(ajaxResponse) {
+    Rico.writeDebugMsg("loadRows");
+    this.rcvdRowCount = false;
+    var debugtags = ajaxResponse.getElementsByTagName('debug');
+    for (var i=0; i<debugtags.length; i++)
+      Rico.writeDebugMsg("loadRows, debug msg "+i+": "+RicoUtil.getContentAsString(debugtags[i],this.options.isEncoded));
+    var error = ajaxResponse.getElementsByTagName('error');
+    if (error.length > 0) {
+      var msg=RicoUtil.getContentAsString(error[0],this.options.isEncoded);
+      alert("Data provider returned an error:\n"+msg);
+      Rico.writeDebugMsg("Data provider returned an error:\n"+msg);
+      return null;
+    }
+    var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
+    var rowcnttags = ajaxResponse.getElementsByTagName('rowcount');
+    if (rowcnttags && rowcnttags.length==1) {
+      this.rowcntContent = RicoUtil.getContentAsString(rowcnttags[0],this.options.isEncoded);
+      this.rcvdRowCount = true;
+      this.foundRowCount = true;
+      Rico.writeDebugMsg("loadRows, found RowCount="+this.rowcntContent);
+    }
+    this.updateUI = rowsElement.getAttribute("update_ui") == "true";
+    this.rcvdOffset = rowsElement.getAttribute("offset");
+    Rico.writeDebugMsg("loadRows, rcvdOffset="+this.rcvdOffset);
+    return this.dom2jstable(rowsElement);
+  }
+
+};
+
+
+
+Rico.Buffer.AjaxSQL = Class.create();
+
+Rico.Buffer.AjaxSQL.prototype = {
+
+  initialize: function(url,options,ajaxOptions) {
+    Object.extend(this, new Rico.Buffer.AjaxXML());
+    Object.extend(this, new Rico.Buffer.AjaxSQLMethods());
+    this.dataSource=url;
+    this.options.canFilter=true;
+    this.options.largeBufferSize  = 7.0;   // 7 pages
+    this.options.nearLimitFactor  = 1.0;   // 1 page
+    Object.extend(this.options, options || {});
+    Object.extend(this.ajaxOptions, ajaxOptions || {});
+    this.sortParm={};
+  }
+}
+  
+Rico.Buffer.AjaxSQLMethods = function() {};
+
+Rico.Buffer.AjaxSQLMethods.prototype = {
+
+  registerGrid: function(liveGrid) {
+    this.liveGrid = liveGrid;
+    this.sessionExpired=false;
+    this.timerMsg=$(liveGrid.tableId+'_timer');
+    if (this.options.TimeOut && this.timerMsg) {
+      if (!this.timerMsg.title) this.timerMsg.title=RicoTranslate.getPhrase("minutes before your session expires")
+      this.restartSessionTimer();
+    }
+  },
+  
+  setBufferSize: function(pageSize) {
+    this.maxFetchSize = Math.max(50,parseInt(this.options.largeBufferSize * pageSize));
+    this.nearLimit = parseInt(this.options.nearLimitFactor * pageSize);
+    this.maxBufferSize = this.maxFetchSize * 3;
+  },
+
+  restartSessionTimer: function() {
+    if (this.sessionExpired==true) return;
+    this.timeRemaining=this.options.TimeOut+1;
+    if (this.sessionTimer) clearTimeout(this.sessionTimer);
+    this.updateSessionTimer();
+  },
+  
+  updateSessionTimer: function() {
+    if (--this.timeRemaining<=0) {
+      this.displaySessionTimer(RicoTranslate.getPhrase("EXPIRED"));
+      this.timerMsg.style.backgroundColor="red";
+      this.sessionExpired=true;
+    } else {
+      this.displaySessionTimer(this.timeRemaining);
+      this.sessionTimer=setTimeout(this.updateSessionTimer.bind(this),60000);
+    }
+  },
+  
+  displaySessionTimer: function(msg) {
+    this.timerMsg.innerHTML='&nbsp;'+msg+'&nbsp;';
+  },
+  
+  refresh: function() {
+    this.fetch(this.lastOffset);
+  },
+  
+  /**
+   * Fetch data from database.
+   * @param offset position (row) within the dataset (-1=clear existing buffer before issuing request)
+   */
+  fetch: function(offset) {
+    Rico.writeDebugMsg("AjaxSQL fetch, offset="+offset+' lastOffset='+this.lastOffset);
+    if (this.processingRequest) {
+      Rico.writeDebugMsg("AjaxSQL fetch: queue request");
+      this.pendingRequest=offset;
+      return;
+    }
+    if (offset < 0) {
+      this.clear();
+      this.setTotalRows(0);
+      this.foundRowCount = false;
+      offset=0;
+    }
+    var lastOffset = this.lastOffset;
+    this.lastOffset = offset;
+    var inRange=this.isInRange(offset);
+    if (inRange) {
+      Rico.writeDebugMsg("AjaxSQL fetch: in buffer");
+      this.liveGrid.refreshContents(offset);
+      if (offset > lastOffset) {
+        if (offset+this.liveGrid.pageSize < this.endPos()-this.nearLimit) return;
+        if (this.endPos()==this.totalRows && this.foundRowCount) return;
+      } else if (offset < lastOffset) {
+        if (offset > this.startPos+this.nearLimit) return;
+        if (this.startPos==0) return;
+      } else return;
+    }
+    if (offset >= this.totalRows && this.foundRowCount) return;
+    
+    this.processingRequest=true
+    Rico.writeDebugMsg("AjaxSQL fetch, processing offset="+offset);
+    var bufferStartPos = this.getFetchOffset(offset);
+    var fetchSize = this.getFetchSize(bufferStartPos);
+    var partialLoaded = false;
+
+    if (!inRange) this.liveGrid.showMsg("Waiting for data...");
+    this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
+    this.sendAjaxRequest(bufferStartPos,fetchSize,this.ajaxUpdate.bind(this,bufferStartPos));
+  },
+
+  getFetchSize: function(adjustedOffset) {
+    var adjustedSize = 0;
+    if (adjustedOffset >= this.startPos) { //appending
+      var endFetchOffset = this.maxFetchSize + adjustedOffset;
+      adjustedSize = endFetchOffset - adjustedOffset;
+      if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize)
+        adjustedSize = this.maxFetchSize;
+      Rico.writeDebugMsg("getFetchSize/append, adjustedSize="+adjustedSize+" adjustedOffset="+adjustedOffset+' endFetchOffset='+endFetchOffset);
+    } else { //prepending
+      adjustedSize = Math.min(this.startPos - adjustedOffset,this.maxFetchSize);
+    }
+    return adjustedSize;
+  },
+
+  getFetchOffset: function(offset) {
+    var adjustedOffset = offset;
+    if (offset > this.startPos)
+      adjustedOffset = Math.max(offset, this.endPos());  //appending
+    else if (offset + this.maxFetchSize >= this.startPos)
+      adjustedOffset = Math.max(this.startPos - this.maxFetchSize, 0);  //prepending
+    return adjustedOffset;
+  },
+
+  sortBuffer: function(colnum,sortdir,coltype) {
+    this.sortParm={};
+    if (this.options.sortParmFmt && this.options.sortParmFmt=='displayName') {
+      this.sortParm['sort_col']=this.liveGrid.columns[colnum].displayName.toLowerCase();
+      this.sortParm['sort_dir']=sortdir;
+    }else{
+     this.sortParm['s'+colnum]=sortdir;
+    }
+    this.clear();
+  },
+  
+  exportAllRows: function(populate,finish) {
+    this.exportPopulate=populate;
+    this.exportFinish=finish;
+    this.liveGrid.showMsg("Waiting for data...");
+    this.sendExportRequest(0);
+  },
+  
+/**
+ * Make ajax request for print window data
+ */
+  sendExportRequest: function(offset) {
+    this.timeoutHandler = setTimeout(this.exportTimedOut.bind(this), this.options.bufferTimeout);
+    this.sendAjaxRequest(offset,200,this.exportAppend.bind(this,offset));
+  },
+
+  exportTimedOut: function() {
+    Rico.writeDebugMsg("Print Request Timed Out");
+    this.liveGrid.showMsg("Request for data timed out!");
+    this.exportFinish();
+  },
+
+  exportAppend: function(startPos,request) {
+    this.clearTimer();
+    var response = request.responseXML.getElementsByTagName("ajax-response");
+    if (response == null || response.length != 1) return;
+    var rowsElement = response[0].getElementsByTagName('rows')[0];
+    var rows=this.dom2jstable(rowsElement);
+    this.exportPopulate(rows);
+    if (rows.length==0)
+      this.exportFinish();
+    else
+      this.sendExportRequest(startPos+rows.length);
+  }
+
+};
+
+Rico.includeLoaded('ricoLiveGridAjax.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridForms.js b/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridForms.js
new file mode 100644 (file)
index 0000000..390850a
--- /dev/null
@@ -0,0 +1,830 @@
+if(typeof Rico=='undefined') throw("LiveGridForms requires the Rico JavaScript framework");
+if(typeof RicoUtil=='undefined') throw("LiveGridForms requires the RicoUtil object");
+if(typeof RicoTranslate=='undefined') throw("LiveGridForms requires the RicoTranslate object");
+
+
+Rico.TableEdit = Class.create();
+
+Rico.TableEdit.prototype = {
+
+  initialize: function(liveGrid) {
+    Rico.writeDebugMsg('Rico.TableEdit initialize: '+liveGrid.tableId);
+    this.grid=liveGrid;
+    this.options = {
+      maxDisplayLen    : 20,    // max displayed text field length
+      panelHeight      : 200,   // size of tabbed panels
+      panelWidth       : 500,
+      hoverClass       : 'tabHover',
+      selectedClass    : 'tabSelected',
+      compact          : false,    // compact corners
+      RecordName       : 'record',
+      readOnlyColor    : '#AAA',   // read-only fields displayed using this color
+      showSaveMsg      : 'errors'  // disposition of database update responses (full - show full response, errors - show full response for errors and short response otherwise)
+    }
+    Object.extend(this.options, liveGrid.options);
+    this.menu=liveGrid.menu;
+    this.menu.options.dataMenuHandler=this.editMenu.bind(this);
+    this.menu.ignoreClicks();
+    RicoEditControls.atLoad();
+    this.createEditDiv();
+    this.saveMsg=$(liveGrid.tableId+'_savemsg');
+    Event.observe(document,"click", this.clearSaveMsg.bindAsEventListener(this), false);
+    this.TEerror=false;
+    this.extraMenuItems=new Array();
+    this.responseHandler=this.processResponse.bind(this);
+  },
+  
+  createEditDiv: function() {
+
+    // create editDiv (form)
+    
+    this.requestCount=1;
+    this.editDiv = this.grid.createDiv('edit',document.body);
+    this.editDiv.style.display='none';
+    if (this.options.canEdit || this.options.canAdd) {
+      this.startForm();
+      this.createForm(this.form);
+    } else {
+      var button=this.createButton("Close");
+      Event.observe(button,"click", this.cancelEdit.bindAsEventListener(this), false);
+      this.createForm(this.editDiv);
+    }
+    this.editDivCreated=true;
+    this.formPopup=new Rico.Popup({ignoreClicks:true},this.editDiv);
+
+    // create responseDialog
+    
+    this.responseDialog = this.grid.createDiv('editResponse',document.body);
+    this.responseDialog.style.display='none';
+    
+    var button = document.createElement('button');
+       button.appendChild(document.createTextNode('OK'));
+    button.onclick=this.ackResponse.bindAsEventListener(this);
+    this.responseDialog.appendChild(button);
+
+    this.responseDiv = this.grid.createDiv('editResponseText',this.responseDialog);
+
+    if (this.panelGroup) {
+      Rico.writeDebugMsg("createEditDiv complete, requestCount="+this.requestCount);
+      setTimeout(this.initPanelGroup.bind(this),50);
+    }
+  },
+  
+  initPanelGroup: function() {
+    this.requestCount--;
+    Rico.writeDebugMsg("initPanelGroup: "+this.requestCount);
+    if (this.requestCount>0) return;
+    var wi=parseInt(this.options.panelWidth);
+    this.form.style.width=(wi+10)+'px';
+    if (Prototype.Browser.WebKit) this.editDiv.style.display='block';  // this causes display to flash briefly
+    this.options.bgColor = Rico.Color.createColorFromBackground(this.form);
+    this.editDiv.style.display='none';
+    this.options.panelHdrWidth=(Math.floor(wi / this.options.panels.length)-4)+'px';
+    this.Accordion=new Rico.TabbedPanel(this.panelHdr.findAll(this.notEmpty), this.panelContent.findAll(this.notEmpty), this.options);
+  },
+  
+  notEmpty: function(v) {
+    return typeof(v)!='undefined';
+  },
+  
+  startForm: function() {
+    this.form = document.createElement('form');
+    this.form.onsubmit=function() {return false;};
+    this.editDiv.appendChild(this.form);
+
+    var tab = document.createElement('table');
+    var row = tab.insertRow(-1);
+    var cell = row.insertCell(-1);
+    var button=cell.appendChild(this.createButton("Save \t"+this.options.RecordName));
+    Event.observe(button,"click", this.TESubmit.bindAsEventListener(this), false);
+    var cell = row.insertCell(-1);
+    var button=cell.appendChild(this.createButton("Cancel"));
+    Event.observe(button,"click", this.cancelEdit.bindAsEventListener(this), false);
+    this.form.appendChild(tab);
+
+    // hidden fields
+    this.hiddenFields = document.createElement('div');
+    this.hiddenFields.style.display='none';
+    this.action = this.appendHiddenField(this.grid.tableId+'__action','');
+    for (var i=0; i<this.grid.columns.length; i++) {
+      var fldSpec=this.grid.columns[i].format;
+      if (fldSpec && fldSpec.FormView && fldSpec.FormView=="hidden")
+        this.appendHiddenField(fldSpec.FieldName,fldSpec.ColData);
+    }
+    this.form.appendChild(this.hiddenFields);
+  },
+  
+  createButton: function(buttonLabel) {
+    var button = document.createElement('button');
+    buttonLabel=RicoTranslate.getPhrase(buttonLabel);
+       button.innerHTML="<span style='text-decoration:underline;'>"+buttonLabel.charAt(0)+"</span>"+buttonLabel.substr(1);
+    button.accessKey=buttonLabel.charAt(0);
+    return button;
+  },
+  
+  createPanel: function(i) {
+    var hasFields=false;
+    for (var j=0; j<this.grid.columns.length; j++) {
+      var fldSpec=this.grid.columns[j].format;
+      if (!fldSpec) continue;
+      if (!fldSpec.EntryType) continue
+      if (fldSpec.EntryType=='H') continue;
+      var panelIdx=fldSpec.panelIdx || 0;
+      if (panelIdx==i) {
+        hasFields=true;
+        break;
+      }
+    }
+    if (!hasFields) return false;
+    this.panelHdr[i] = document.createElement('div');
+    this.panelHdr[i].className='tabHeader';
+    this.panelHdr[i].innerHTML=this.options.panels[i];
+    this.panelHdrs.appendChild(this.panelHdr[i]);
+    this.panelContent[i] = document.createElement('div');
+    this.panelContent[i].className='tabContent';
+    this.panelContents.appendChild(this.panelContent[i]);
+    return true;
+  },
+  
+  createForm: function(parentDiv) {
+    var tables=[];
+    this.panelHdr=[];
+    this.panelContent=[];
+    if (this.options.panels) {
+      this.panelGroup = document.createElement('div');
+      this.panelGroup.className='tabPanelGroup';
+      this.panelHdrs = document.createElement('div');
+      this.panelGroup.appendChild(this.panelHdrs);
+      this.panelContents = document.createElement('div');
+      this.panelContents.className='tabContentContainer';
+      this.panelGroup.appendChild(this.panelContents);
+      parentDiv.appendChild(this.panelGroup);
+      if (this.grid.direction=='rtl') {
+        for (var i=this.options.panels.length-1; i>=0; i--)
+          if (this.createPanel(i))
+            tables[i]=this.createFormTable(this.panelContent[i],'tabContent');
+      } else {
+        for (var i=0; i<this.options.panels.length; i++)
+          if (this.createPanel(i))
+            tables[i]=this.createFormTable(this.panelContent[i],'tabContent');
+      }
+      parentDiv.appendChild(this.panelGroup);
+    } else {
+      var div=document.createElement('div');
+      div.className='noTabContent';
+      tables[0]=this.createFormTable(div);
+      parentDiv.appendChild(div);
+    }
+    for (var i=0; i<this.grid.columns.length; i++) {
+      var fldSpec=this.grid.columns[i].format;
+      if (!fldSpec) continue;
+      var panelIdx=fldSpec.panelIdx || 0;
+      if (tables[panelIdx]) this.appendFormField(this.grid.columns[i],tables[panelIdx]);
+    }
+  },
+  
+  createFormTable: function(div) {
+    var tab=document.createElement('table');
+    tab.border=0;
+    div.appendChild(tab);
+    return tab;
+  },
+  
+  appendHiddenField: function(name,value) {
+    var field=RicoUtil.createFormField(this.hiddenFields,'input','hidden',name,name);
+    field.value=value;
+    return field;
+  },
+  
+  appendFormField: function(column, table) {
+    if (!column.format.EntryType) return;
+    if (column.format.EntryType=="H") return;
+    if (column.format.FormView) return;
+    Rico.writeDebugMsg('appendFormField: '+column.format.Hdg+' - '+column.format.EntryType);
+    var row = table.insertRow(-1);
+    var hdr = row.insertCell(-1);
+    column.formLabel=hdr;
+    if (hdr.noWrap) hdr.noWrap=true;
+    var entry = row.insertCell(-1);
+    if (entry.noWrap) entry.noWrap=true;
+    hdr.innerHTML=column.format.Hdg;
+    hdr.className='ricoEditLabel';
+    if (column.format.Help) {
+      hdr.title=column.format.Help;
+      hdr.className='ricoEditLabelWithHelp';
+    }
+    var field, name=column.format.FieldName;
+    switch (column.format.EntryType) {
+      case 'TA','tinyMCE':
+        field=RicoUtil.createFormField(entry,'textarea',null,name);
+        field.cols=column.format.TxtAreaCols;
+        field.rows=column.format.TxtAreaRows;
+        field.innerHTML=column.format.ColData;
+        hdr.style.verticalAlign='top';
+        break;
+      case 'R':
+      case 'RL':
+        field=RicoUtil.createFormField(entry,'div',null,name);
+        if (column.format.isNullable)
+          this.addSelectOption(field,this.options.TableSelectNone,"(none)");
+        this.selectValuesRequest(field,column.format);
+        break;
+      case 'N':
+        field=RicoUtil.createFormField(entry,'select',null,name);
+        if (column.format.isNullable)
+          this.addSelectOption(field,this.options.TableSelectNone,"(none)");
+        field.onchange=this.checkSelectNew.bindAsEventListener(this);
+        this.selectValuesRequest(field,column.format);
+        field=document.createElement('span');
+        field.className='ricoEditLabel';
+        field.id='labelnew__'+column.format.FieldName;
+        field.innerHTML='&nbsp;&nbsp;&nbsp;New&nbsp;value:';
+        entry.appendChild(field);
+        name='textnew__'+column.format.FieldName;
+        field=RicoUtil.createFormField(entry,'input','text',name,name);
+        break;
+      case 'S':
+      case 'SL':
+        field=RicoUtil.createFormField(entry,'select',null,name);
+        if (column.format.isNullable)
+          this.addSelectOption(field,this.options.TableSelectNone,"(none)");
+        this.selectValuesRequest(field,column.format);
+        break;
+      default:
+        field=RicoUtil.createFormField(entry,'input','text',name,name);
+        if (column.format.Length) {
+          field.maxLength=column.format.Length;
+          field.size=Math.min(column.format.Length, this.options.maxDisplayLen);
+        }
+        field.value=column.format.ColData;
+        break;
+    }
+    if (field) {
+      if (column.format.SelectCtl)
+        RicoEditControls.applyTo(column,field);
+    }
+  },
+  
+  checkSelectNew: function(e) {
+    this.updateSelectNew(Event.element(e));
+  },
+  
+  updateSelectNew: function(SelObj) {
+    var vis=(SelObj.value==this.options.TableSelectNew) ? "" : "hidden";
+    $("labelnew__" + SelObj.id).style.visibility=vis
+    $("textnew__" + SelObj.id).style.visibility=vis
+  },
+
+  selectValuesRequest: function(elem,fldSpec) {
+    if (fldSpec.SelectValues) {
+      var valueList=fldSpec.SelectValues.split(',');
+      for (var i=0; i<valueList.length; i++)
+        this.addSelectOption(elem,valueList[i],valueList[i],i);
+    } else {
+      this.requestCount++;
+      var options={};
+      Object.extend(options, this.grid.buffer.ajaxOptions);
+      options.parameters = 'id='+fldSpec.FieldName+'&offset=0&page_size=-1';
+      options.onComplete = this.selectValuesUpdate.bind(this);
+      new Ajax.Request(this.grid.buffer.dataSource, options);
+      Rico.writeDebugMsg("selectValuesRequest: "+options.parameters);
+    }
+  },
+  
+  selectValuesUpdate: function(request) {
+    var response = request.responseXML.getElementsByTagName("ajax-response");
+    Rico.writeDebugMsg("selectValuesUpdate: "+request.status);
+    if (response == null || response.length != 1) return;
+    response=response[0];
+    var error = response.getElementsByTagName('error');
+    if (error.length > 0) {
+      Rico.writeDebugMsg("Data provider returned an error:\n"+RicoUtil.getContentAsString(error[0],this.grid.buffer.isEncoded));
+      alert(RicoTranslate.getPhrase("The request returned an error")+":\n"+RicoUtil.getContentAsString(error[0],this.grid.buffer.isEncoded));
+      return null;
+    }
+    response=response.getElementsByTagName('response')[0];
+    var id = response.getAttribute("id").slice(0,-8);
+    var rowsElement = response.getElementsByTagName('rows')[0];
+    var rows = this.grid.buffer.dom2jstable(rowsElement);
+    var elem=$(id);
+    //alert('selectValuesUpdate:'+id+' '+elem.tagName);
+    Rico.writeDebugMsg("selectValuesUpdate: id="+id+' rows='+rows.length);
+    for (var i=0; i<rows.length; i++) {
+      if (rows[i].length>0) {
+        var c0=rows[i][0].content;
+        var c1=(rows[i].length>1) ? rows[i][1].content : c0;
+        this.addSelectOption(elem,c0,c1,i);
+      }
+    }
+    if ($('textnew__'+id))
+      this.addSelectOption(elem,this.options.TableSelectNew,"(new value)");
+    if (this.panelGroup)
+      setTimeout(this.initPanelGroup.bind(this),50);
+  },
+  
+  addSelectOption: function(elem,value,text,idx) {
+    switch (elem.tagName.toLowerCase()) {
+      case 'div':
+        var opt=RicoUtil.createFormField(elem,'input','radio',elem.id+'_'+idx,elem.id);
+        opt.value=value;
+        var lbl=document.createElement('label');
+        lbl.innerHTML=text;
+        lbl.htmlFor=opt.id;
+        elem.appendChild(lbl);
+        break;
+      case 'select':
+        var opt=document.createElement('option');
+        opt.value=value;
+        opt.text=text;
+        //elem.options.add(opt);
+        if (Prototype.Browser.IE)
+          elem.add(opt);
+        else
+          elem.add(opt,null);
+        break;
+    }
+  },
+  
+  clearSaveMsg: function() {
+    if (this.saveMsg) this.saveMsg.innerHTML="";
+  },
+  
+  addMenuItem: function(menuText,menuAction,enabled) {
+    this.extraMenuItems.push({menuText:menuText,menuAction:menuAction,enabled:enabled});
+  },
+
+  editMenu: function(grid,r,c,onBlankRow) {
+    this.clearSaveMsg();
+    if (this.grid.buffer.sessionExpired==true || this.grid.buffer.startPos<0) return;
+    this.rowIdx=r;
+    var elemTitle=$('pageTitle');
+    var pageTitle=elemTitle ? elemTitle.innerHTML : document.title;
+    this.menu.addMenuHeading(pageTitle);
+    for (var i=0; i<this.extraMenuItems.length; i++) {
+      this.menu.addMenuItem(this.extraMenuItems[i].menuText,this.extraMenuItems[i].menuAction,this.extraMenuItems[i].enabled);
+    }
+    if (onBlankRow==false) {
+      this.menu.addMenuItem("Edit\t this "+this.options.RecordName,this.editRecord.bindAsEventListener(this),this.options.canEdit);
+      this.menu.addMenuItem("Delete\t this "+this.options.RecordName,this.deleteRecord.bindAsEventListener(this),this.options.canDelete);
+    }
+    this.menu.addMenuItem("Add\t new "+this.options.RecordName,this.addRecord.bindAsEventListener(this),this.options.canAdd);
+    return true;
+  },
+
+  cancelEdit: function(e) {
+    Event.stop(e);
+    for (var i=0; i<this.grid.columns.length; i++)
+      if (this.grid.columns[i].format && this.grid.columns[i].format.SelectCtl)
+        RicoEditControls.close(this.grid.columns[i].format.SelectCtl);
+    this.makeFormInvisible();
+    this.grid.highlightEnabled=true;
+    this.menu.cancelmenu();
+    return false;
+  },
+
+  setField: function(fldSpec,fldvalue) {
+    var e=$(fldSpec.FieldName);
+    if (!e) return;
+    //alert('setField: '+fldSpec.FieldName+'='+fldvalue);
+    switch (e.tagName.toUpperCase()) {
+      case 'DIV':
+        var elems=e.getElementsByTagName('INPUT');
+        var fldcode=this.getLookupValue(fldvalue)[0];
+        for (var i=0; i<elems.length; i++)
+          elems[i].checked=(elems[i].value==fldcode);
+        break;
+      case 'INPUT':
+        if (fldSpec.SelectCtl)
+          fldvalue=this.getLookupValue(fldvalue)[0];
+        switch (e.type.toUpperCase()) {
+          case 'HIDDEN':
+          case 'TEXT':
+            e.value=fldvalue;
+            break;
+        }
+        break;
+      case 'SELECT':
+        var opts=e.options;
+        var fldcode=this.getLookupValue(fldvalue)[0];
+        //alert('setField SELECT: id='+e.id+'\nvalue='+fldcode+'\nopt cnt='+opts.length)
+        for (var i=0; i<opts.length; i++) {
+          if (opts[i].value==fldcode) {
+            e.selectedIndex=i;
+            break;
+          }
+        }
+        if (fldSpec.EntryType=='N') {
+          var txt=$('textnew__'+e.id);
+          if (!txt) alert('Warning: unable to find id "textnew__'+e.id+'"');
+          txt.value=fldvalue;
+          if (e.selectedIndex!=i) e.selectedIndex=opts.length-1;
+          this.updateSelectNew(e);
+        }
+        return;
+      case 'TEXTAREA':
+        e.value=fldvalue;
+        if (fldSpec.EntryType=='tinyMCE' && typeof(tinyMCE)!='undefined' && this.initialized)
+          tinyMCE.updateContent(e.id);
+        return;
+    }
+  },
+  
+  getLookupValue: function(value) {
+    if (typeof value!='string')
+      return ['',''];
+    else if (value.match(/<span\s+class=(['"]?)ricolookup\1>(.*)<\/span>/i))
+      return [RegExp.$2,RegExp.leftContext];
+    else
+      return [value,value];
+  },
+  
+  // use with care: Prototype 1.5 does not include disabled fields in the post-back
+  setReadOnly: function(addFlag) {
+    for (var i=0; i<this.grid.columns.length; i++) {
+      var fldSpec=this.grid.columns[i].format;
+      if (!fldSpec) continue;
+      var e=$(fldSpec.FieldName);
+      if (!e) continue;
+      var ro=!fldSpec.Writeable || fldSpec.ReadOnly || (fldSpec.InsertOnly && !addFlag) || (fldSpec.UpdateOnly && addFlag);
+      var color=ro ? this.options.readOnlyColor : '';
+      switch (e.tagName.toUpperCase()) {
+        case 'DIV':
+          var elems=e.getElementsByTagName('INPUT');
+          for (var j=0; j<elems.length; j++)
+            elems[j].disabled=ro;
+          break;
+        case 'SELECT':
+          if (fldSpec.EntryType=='N') {
+            var txt=$('textnew__'+e.id);
+            txt.disabled=ro;
+          }
+          e.disabled=ro;
+          break;
+        case 'TEXTAREA':
+        case 'INPUT':
+          e.readOnly=ro;
+          e.style.color=color;
+          if (fldSpec.selectIcon) fldSpec.selectIcon.style.display=ro ? 'none' : '';
+          break;
+      }
+    }
+  },
+  
+  hideResponse: function(msg) {
+    this.responseDiv.innerHTML=msg;
+    this.responseDialog.style.display='none';
+  },
+  
+  showResponse: function() {
+    var offset=Position.page(this.grid.outerDiv);
+    offset[1]+=RicoUtil.docScrollTop();
+    this.responseDialog.style.top=offset[1]+"px";
+    this.responseDialog.style.display='';
+  },
+  
+  processResponse: function() {
+    var ch=this.responseDiv.childNodes;
+    for (var i=ch.length-1; i>=0; i--) {
+      if (ch[i].nodeType==1 && ch[i].nodeName!='P' && ch[i].nodeName!='DIV' && ch[i].nodeName!='BR')
+        this.responseDiv.removeChild(ch[i]);
+    }
+    var responseText=this.responseDiv.innerHTML;
+    if (responseText.toLowerCase().indexOf('error')==-1 && this.options.showSaveMsg!='full') {
+      this.hideResponse('');
+      this.grid.resetContents();
+      this.grid.buffer.foundRowCount = false;
+      this.grid.buffer.fetch(this.grid.lastRowPos || 0);
+      if (this.saveMsg) this.saveMsg.innerHTML='&nbsp;'+responseText.stripTags()+'&nbsp;';
+    }
+    this.processCallback(this.options.onSubmitResponse);
+  },
+  
+  processCallback: function(callback) {
+    switch (typeof callback) {
+      case 'string': eval(callback); break;
+      case 'function': callback(); break;
+    }
+  },
+  
+  // called when ok pressed on error response message
+  ackResponse: function() {
+    this.hideResponse('');
+    this.grid.highlightEnabled=true;
+  },
+
+  editRecord: function(e) {
+    this.grid.highlightEnabled=false;
+    this.menu.hidemenu();
+    this.hideResponse('Saving...');
+    this.grid.outerDiv.style.cursor = 'auto';
+    this.action.value="upd";
+    for (var i=0; i<this.grid.columns.length; i++) {
+      if (this.grid.columns[i].format) {
+        var v=this.grid.columns[i].getValue(this.rowIdx);
+        this.setField(this.grid.columns[i].format,v);
+        if (this.grid.columns[i].format.selectDesc)
+          this.grid.columns[i].format.selectDesc.innerHTML=this.grid.columns[i]._format(v);
+      }
+    }
+    this.setReadOnly(false);
+    this.key=this.getKey();
+    this.makeFormVisible(this.rowIdx);
+  },
+
+  addRecord: function() {
+    this.menu.hidemenu();
+    this.hideResponse('Saving...');
+    this.setReadOnly(true);
+    this.form.reset();
+    this.action.value="ins";
+    for (var i=0; i<this.grid.columns.length; i++) {
+      if (this.grid.columns[i].format) {
+        this.setField(this.grid.columns[i].format,this.grid.columns[i].format.ColData);
+        if (this.grid.columns[i].format.SelectCtl)
+          RicoEditControls.resetValue(this.grid.columns[i]);
+      }
+    }
+    this.key='';
+    this.makeFormVisible(-1);
+    if (this.Accordion) this.Accordion.selectionSet.selectIndex(0);
+  },
+  
+  drillDown: function(e,masterColNum,detailColNum) {
+    var cell=Event.element(e || window.event);
+    cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+    if (!cell) return;
+    this.grid.unhighlight();
+    var idx=this.grid.winCellIndex(cell);
+    this.grid.menuIdx=idx;  // ensures selection gets cleared when menu is displayed
+    this.grid.highlight(idx);
+    var drillValue=this.grid.columns[masterColNum].getValue(idx.row);
+    for (var i=3; i<arguments.length; i++)
+      arguments[i].setDetailFilter(detailColNum,drillValue);
+    return idx.row;
+  },
+  
+  // set filter on a detail grid that is in a master-detail relationship
+  setDetailFilter: function(colNumber,filterValue) {
+    var c=this.grid.columns[colNumber];
+    c.format.ColData=filterValue;
+    c.setSystemFilter('EQ',filterValue);
+  },
+  
+  makeFormVisible: function(row) {
+    this.editDiv.style.display='block';
+
+    // set left position
+    var editWi=this.editDiv.offsetWidth;
+    var odOffset=Position.page(this.grid.outerDiv);
+    var winWi=RicoUtil.windowWidth();
+    if (editWi+odOffset[0] > winWi)
+      this.editDiv.style.left=(winWi-editWi)+'px';
+    else
+      this.editDiv.style.left=(odOffset[0]+1)+'px';
+
+    // set top position
+    var scrTop=RicoUtil.docScrollTop();
+    var editHt=this.editDiv.offsetHeight;
+    var newTop=odOffset[1]+this.grid.hdrHt+scrTop;
+    var bottom=RicoUtil.windowHeight()+scrTop;
+    if (row >= 0) {
+      newTop+=(row+1)*this.grid.rowHeight;
+      if (newTop+editHt>bottom) newTop-=(editHt+this.grid.rowHeight);
+    } else {
+      if (newTop+editHt>bottom) newTop=bottom-editHt;
+    }
+    this.processCallback(this.options.formOpen);
+    this.formPopup.openPopup(null,Math.max(newTop,scrTop));
+    this.editDiv.style.visibility='visible';
+    if (this.initialized) return;
+    for (i = 0; i < this.grid.columns.length; i++) {
+      spec=this.grid.columns[i].format;
+      if (!spec || !spec.EntryType || !spec.FieldName) continue;
+      switch (spec.EntryType) {
+        case 'tinyMCE':
+          if (typeof tinyMCE!='undefined') tinyMCE.execCommand('mceAddControl', true, spec.FieldName);
+          break;
+      }
+    }
+    this.formPopup.openPopup();  // tinyMCE may have changed the dimensions of the form
+    this.initialized=true;
+  },
+
+  makeFormInvisible: function() {
+    this.editDiv.style.visibility='hidden';
+    this.formPopup.closePopup();
+    this.processCallback(this.options.formClose);
+  },
+  
+  getConfirmDesc: function(rowIdx) {
+    var desc=this.grid.columns[this.options.ConfirmDeleteCol].cell(rowIdx).innerHTML;
+    desc=this.getLookupValue(desc)[1];
+    return desc.stripTags();
+  },
+
+  deleteRecord: function() {
+    this.menu.hidemenu();
+    var desc;
+    if (this.options.ConfirmDeleteCol < 0) {
+      desc=RicoTranslate.getPhrase("this "+this.options.RecordName);
+    } else {
+      desc=this.getConfirmDesc(this.rowIdx);
+      if (desc.length>50) desc=desc.substring(0,50)+'...';
+      desc='\"' + desc + '\"'
+    }
+    if (!this.options.ConfirmDelete.valueOf || confirm(RicoTranslate.getPhrase("Are you sure you want to delete ") + desc + " ?")) {
+      this.hideResponse('Deleting...');
+      this.showResponse();
+      var parms=this.action.name+"=del"+this.getKey();
+      //alert(parms);
+      new Ajax.Updater(this.responseDiv, window.location.pathname, {parameters:parms,onComplete:this.processResponse.bind(this)});
+    }
+    this.menu.cancelmenu();
+  },
+  
+  getKey: function() {
+    var key='';
+    for (var i=0; i<this.grid.columns.length; i++) {
+      if (this.grid.columns[i].format && this.grid.columns[i].format.isKey) {
+        var value=this.grid.columns[i].getValue(this.rowIdx);
+        value=this.getLookupValue(value)[0];
+        key+='&_k'+i+'='+value;
+      }
+    }
+    return key;
+  },
+
+  TESubmit: function(e) {
+    var i,lbl,spec,elem,entrytype;
+    
+    if (!e) e=window.event;
+    Event.stop(e);
+
+    // check fields that are supposed to be non-blank
+
+    for (i = 0; i < this.grid.columns.length; i++) {
+      spec=this.grid.columns[i].format;
+      if (!spec || !spec.EntryType || !spec.FieldName) continue;
+      entrytype=spec.EntryType.charAt(0).toLowerCase();
+      if (!entrytype.match(/d|i|b/)) continue;
+      if (spec.isNullable==true && entrytype!='b') continue;
+      elem=$(spec.FieldName);
+      if (!elem) continue;
+      //alert("nonblank check: " + spec.FieldName);
+      if (elem.tagName.toLowerCase()!='input') continue;
+      if (elem.type.toLowerCase()!='text') continue;
+      if (elem.value.length == 0) {
+        alert(RicoTranslate.getPhrase("Please enter\t a value for")+" \"" + this.grid.columns[i].formLabel.innerHTML + "\"");
+        //setTimeout("FocusField(document." + this.form.name + "." + this.options.NonBlanks[i] + ")",2000);
+        return false;
+      }
+    }
+
+    // recheck any elements on the form with an onchange event
+
+    var InputFields = this.form.getElementsByTagName("input");
+    this.TEerror=false;
+    for (i=0; i < InputFields.length; i++) {
+      if (InputFields[i].type=="text" && InputFields[i].onchange) {
+        InputFields[i].onchange();
+        if (this.TEerror) return false;
+      }
+    }
+    if (typeof tinyMCE!='undefined') tinyMCE.triggerSave();
+    this.makeFormInvisible();
+    this.showResponse();
+    var parms=Form.serialize(this.form)+this.key
+    Rico.writeDebugMsg("TESubmit:"+parms);
+    new Ajax.Updater(this.responseDiv, window.location.pathname, {parameters:parms,onComplete:this.responseHandler});
+    this.menu.cancelmenu();
+    return false;
+  },
+  
+  FocusField: function(elem) {
+    elem.focus();
+    elem.select();
+  },
+
+  TableEditCheckInt: function(TxtObj) {
+    var val=TxtObj.value;
+    if (val=='') return;
+    if (val!=parseInt(val)) {
+      alert(RicoTranslate.getPhrase("Please enter\t an integer value for")+" \"" + $("lbl_"+TxtObj.id).innerHTML + "\"");
+      setTimeout(this.FocusField.bind(this,TxtObj),0);
+      this.TEerror=true;
+    }
+  },
+
+  TableEditCheckPosInt: function(TxtObj) {
+    var val=TxtObj.value;
+    if (val=='') return;
+    if (val!=parseInt(val) || val<0) {
+      alert(RicoTranslate.getPhrase("Please enter\t a positive integer value for")+" \"" + $("lbl_"+TxtObj.id).innerHTML + "\"");
+      setTimeout(this.FocusField.bind(this,TxtObj),0);
+      this.TEerror=true;
+    }
+  }
+}
+
+
+// Registers custom popup widgets to fill in a text box (e.g. ricoCalendar and ricoTree)
+//
+// Custom widget must implement:
+//   open() method (make control visible)
+//   close() method (hide control)
+//   container property (div element that contains the control)
+//   id property (uniquely identifies the widget class)
+//
+// widget calls returnValue method to return a value to the caller
+//
+// this object handles clicks on the control's icon and positions the control appropriately.
+var RicoEditControls = {
+  widgetList:$H(),
+  elemList:$H(),
+  
+  register: function(widget, imgsrc) {
+    var tmp={};
+    tmp[widget.id]={imgsrc:imgsrc, widget:widget, currentEl:''};
+    this.widgetList=this.widgetList.merge(tmp);
+    widget.returnValue=this.setValue.bind(this,widget);
+    Rico.writeDebugMsg("RicoEditControls.register:"+widget.id);
+  },
+  
+  atLoad: function() {
+    var k=this.widgetList.keys();
+    for (var i=0; i<k.length; i++) {
+      var w=this.widgetList[k[i]].widget;
+      if (w.atLoad) w.atLoad();
+    }
+  },
+  
+  applyTo: function(column,inputCtl) {
+    var wInfo=this.widgetList[column.format.SelectCtl];
+    if (!wInfo) return null;
+    Rico.writeDebugMsg('RicoEditControls.applyTo: '+column.displayName+' : '+column.format.SelectCtl);
+    var descSpan = document.createElement('span');
+    var newimg = document.createElement('img');
+    newimg.style.paddingLeft='4px';
+    newimg.style.cursor='pointer';
+    newimg.align='top';
+    newimg.src=wInfo.imgsrc;
+    newimg.id=this.imgId(column.format.FieldName);
+    newimg.onclick=this.processClick.bindAsEventListener(this);
+    inputCtl.parentNode.appendChild(descSpan);
+    inputCtl.parentNode.appendChild(newimg);
+    inputCtl.style.display='none';    // comment out this line for debugging
+    var tmp=new Object();
+    tmp[newimg.id]={descSpan:descSpan, inputCtl:inputCtl, widget:wInfo.widget, listObj:wInfo, column:column};
+    this.elemList=this.elemList.merge(tmp);
+    column.format.selectIcon=newimg;
+    column.format.selectDesc=descSpan;
+  },
+
+  processClick: function(e) {
+    var elem=Event.element(e);
+    var el=this.elemList[elem.id];
+    if (!el) return;
+    if (el.listObj.currentEl==elem.id && el.widget.container.style.display!='none') {
+      el.widget.close();
+      el.listObj.currentEl='';
+    } else {
+      el.listObj.currentEl=elem.id;
+      Rico.writeDebugMsg('RicoEditControls.processClick: '+el.widget.id+' : '+el.inputCtl.value);
+      RicoUtil.positionCtlOverIcon(el.widget.container,elem);
+      el.widget.open(el.inputCtl.value);
+    }
+  },
+  
+  imgId: function(fieldname) {
+    return 'icon_'+fieldname;
+  },
+  
+  resetValue: function(column) {
+    var el=this.elemList[this.imgId(column.format.FieldName)];
+    if (!el) return;
+    el.inputCtl.value=column.format.ColData;
+    el.descSpan.innerHTML=column._format(column.format.ColData);
+  },
+  
+  setValue: function(widget,newVal,newDesc) {
+    var wInfo=this.widgetList[widget.id];
+    if (!wInfo) return null;
+    var id=wInfo.currentEl;
+    if (!id) return null;
+    var el=this.elemList[id];
+    if (!el) return null;
+    el.inputCtl.value=newVal;
+    if (!newDesc) newDesc=el.column._format(newVal);
+    el.descSpan.innerHTML=newDesc;
+    //alert(widget.id+':'+id+':'+el.inputCtl.id+':'+el.inputCtl.value+':'+newDesc);
+  },
+  
+  close: function(id) {
+    var wInfo=this.widgetList[id];
+    if (!wInfo) return;
+    if (wInfo.widget.container.style.display!='none')
+      wInfo.widget.close();
+  }
+}
+
+Rico.includeLoaded('ricoLiveGridForms.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridMenu.js b/trunk/NP_TrackBack/trackback/js/rico/ricoLiveGridMenu.js
new file mode 100644 (file)
index 0000000..4e0dcce
--- /dev/null
@@ -0,0 +1,110 @@
+if(typeof Rico=='undefined')
+  throw("GridMenu requires the Rico JavaScript framework");
+
+
+/**
+ * Standard menu for LiveGrid
+ */
+Rico.GridMenu = Class.create();
+
+Rico.GridMenu.prototype = {
+
+initialize: function(options) {
+  this.options = {
+    width           : '20em',
+    dataMenuHandler : null          // put custom items on the menu
+  };
+  Object.extend(this.options, options || {});
+  Object.extend(this, new Rico.Menu(this.options));
+  this.sortmenu = new Rico.Menu(this.options);
+  this.filtermenu = new Rico.Menu(this.options);
+  this.exportmenu = new Rico.Menu(this.options);
+  this.hideshowmenu = new Rico.Menu(this.options);
+  this.createDiv();
+  this.sortmenu.createDiv();
+  this.filtermenu.createDiv();
+  this.exportmenu.createDiv();
+  this.hideshowmenu.createDiv();
+},
+
+// Build context menu for grid
+buildGridMenu: function(r,c) {
+  this.clearMenu();
+  var totrows=this.liveGrid.buffer.totalRows;
+  var onBlankRow=r >= totrows;
+  var column=this.liveGrid.columns[c];
+  if (this.options.dataMenuHandler) {
+     var showMenu=this.options.dataMenuHandler(this.liveGrid,r,c,onBlankRow);
+     if (!showMenu) return false;
+  }
+
+  // menu items for sorting
+  if (column.sortable && totrows>0) {
+    this.sortmenu.clearMenu();
+    this.addSubMenuItem(RicoTranslate.getPhrase("Sort by")+": "+column.displayName, this.sortmenu, false);
+    this.sortmenu.addMenuItem("Ascending", column.sortAsc.bind(column), true);
+    this.sortmenu.addMenuItem("Descending", column.sortDesc.bind(column), true);
+  }
+
+  // menu items for filtering
+  if (column.canFilter() && (!onBlankRow || column.filterType == Rico.TableColumn.USERFILTER)) {
+    this.filtermenu.clearMenu();
+    this.addSubMenuItem(RicoTranslate.getPhrase("Filter by")+": "+column.displayName, this.filtermenu, false);    
+    column.userFilter=column.getValue(r);
+    if (column.filterType == Rico.TableColumn.USERFILTER) {
+      this.filtermenu.addMenuItem("Remove filter", column.setUnfiltered.bind(column), true);
+      this.filtermenu.addMenuItem("Refresh", this.liveGrid.filterHandler.bind(this.liveGrid), true);
+      if (column.filterOp=='LIKE')
+        this.filtermenu.addMenuItem("Change keyword...", column.setFilterKW.bind(column), true);
+      if (column.filterOp=='NE' && !onBlankRow)
+        this.filtermenu.addMenuItem("Exclude this value also", column.addFilterNE.bind(column), true);
+    } else if (!onBlankRow) {
+      this.filtermenu.addMenuItem("Include only this value", column.setFilterEQ.bind(column), true);
+      this.filtermenu.addMenuItem("Greater than or equal to this value", column.setFilterGE.bind(column), column.userFilter!='');
+      this.filtermenu.addMenuItem("Less than or equal to this value", column.setFilterLE.bind(column), column.userFilter!='');
+      if (column.isText)
+        this.filtermenu.addMenuItem("Contains keyword...", column.setFilterKW.bind(column), true);
+      this.filtermenu.addMenuItem("Exclude this value", column.setFilterNE.bind(column), true);
+    }
+    if (this.liveGrid.filterCount() > 0)
+      this.filtermenu.addMenuItem("Remove all filters", this.liveGrid.clearFilters.bind(this.liveGrid), true);
+  }
+
+  // menu items for Print/Export
+  if (this.liveGrid.options.maxPrint > 0 && totrows>0) {
+    this.exportmenu.clearMenu();
+    this.addSubMenuItem('Print\t/Export',this.exportmenu);
+    this.exportmenu.addMenuItem("Visible rows to web page", this.liveGrid.printVisible.bind(this.liveGrid,'plain'), true);
+    this.exportmenu.addMenuItem("All rows to web page", this.liveGrid.printAll.bind(this.liveGrid,'plain'), this.liveGrid.buffer.totalRows <= this.liveGrid.options.maxPrint);
+    if (Prototype.Browser.IE) {
+      this.exportmenu.addMenuBreak();
+      this.exportmenu.addMenuItem("Visible rows to spreadsheet", this.liveGrid.printVisible.bind(this.liveGrid,'owc'), true);
+      this.exportmenu.addMenuItem("All rows to spreadsheet", this.liveGrid.printAll.bind(this.liveGrid,'owc'), this.liveGrid.buffer.totalRows <= this.liveGrid.options.maxPrint);
+    }
+  }
+
+  // menu items for hide/unhide
+  var hiddenCols=this.liveGrid.listInvisible();
+  for (var showableCnt=0,x=0; x<hiddenCols.length; x++)
+    if (hiddenCols[x].canHideShow()) showableCnt++;
+  if (showableCnt > 0 || column.canHideShow()) {
+    this.hideshowmenu.clearMenu();
+    this.addSubMenuItem('Hide\t/Show',this.hideshowmenu);
+    var visibleCnt=this.liveGrid.columns.length-hiddenCols.length;
+    var enabled=(visibleCnt>1 && column.visible && column.canHideShow());
+    this.hideshowmenu.addMenuItem(RicoTranslate.getPhrase('Hide')+': '+column.displayName, column.hideColumn.bind(column), enabled);
+    for (var cnt=0,x=0; x<hiddenCols.length; x++) {
+      if (hiddenCols[x].canHideShow()) {
+        if (cnt++==0) this.hideshowmenu.addMenuBreak();
+        this.hideshowmenu.addMenuItem(RicoTranslate.getPhrase('Show')+': '+hiddenCols[x].displayName, hiddenCols[x].showColumn.bind(hiddenCols[x]));
+      }
+    }
+    if (hiddenCols.length > 1)
+      this.hideshowmenu.addMenuItem(RicoTranslate.getPhrase('Show All'), this.liveGrid.showAll.bind(this.liveGrid));
+  }
+  return true;
+}
+
+}
+
+Rico.includeLoaded('ricoLiveGridMenu.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoMenu.js b/trunk/NP_TrackBack/trackback/js/rico/ricoMenu.js
new file mode 100644 (file)
index 0000000..544d3e8
--- /dev/null
@@ -0,0 +1,197 @@
+Rico.Menu = Class.create();
+
+Rico.Menu.prototype = {
+
+  initialize: function(options) {
+    Object.extend(this, new Rico.Popup());
+    Object.extend(this.options, {
+      width        : "15em",
+      margin       : 6   // account for shadow
+    });
+    if (typeof options=='string')
+      this.options.width=options;
+    else
+      Object.extend(this.options, options || {});
+    this.hideFunc=null;
+    this.highlightElem=null;
+    new Image().src = Rico.imgDir+'left.gif';
+    new Image().src = Rico.imgDir+'right.gif';
+  },
+  
+  createDiv: function(parentNode) {
+    if (this.div) return;
+    this.div = document.createElement('div');
+    this.div.className = Prototype.Browser.WebKit ? 'ricoMenuSafari' : 'ricoMenu';
+    this.div.style.position="absolute";
+    this.div.style.width=this.options.width;
+    if (!parentNode) parentNode = document.getElementsByTagName("body")[0];
+    parentNode.appendChild(this.div);
+    this.width=this.div.offsetWidth
+    this.setDiv(this.div,this.cancelmenu.bindAsEventListener(this));
+    this.direction=Element.getStyle(this.div,'direction') || 'ltr';
+    this.direction=this.direction.toLowerCase();  // ltr or rtl
+    this.hidemenu();
+    this.itemCount=0;
+  },
+  
+  showmenu: function(e,hideFunc){
+    Event.stop(e);
+    this.hideFunc=hideFunc;
+    if (this.div.childNodes.length==0) {
+      this.cancelmenu();
+      return false;
+    }
+    this.openmenu(e.clientX,e.clientY,0,0);
+  },
+  
+  openmenu: function(x,y,clickItemWi,clickItemHt) {
+    var newLeft=RicoUtil.docScrollLeft()+x;
+    //window.status='openmenu: newLeft='+newLeft+' width='+this.width+' windowWi='+RicoUtil.windowWidth();
+    if (this.direction == 'rtl') {
+      if (newLeft > this.width+clickItemWi) newLeft-=this.width+clickItemWi;
+    } else {
+      if (x+this.width+this.options.margin > RicoUtil.windowWidth()) newLeft-=this.width+clickItemWi;
+    }
+    var newTop=RicoUtil.docScrollTop()+y;
+    this.div.style.visibility="hidden";
+    this.div.style.display="block";
+    var contentHt=this.div.offsetHeight;
+    if (y+contentHt+this.options.margin > RicoUtil.windowHeight())
+      newTop=Math.max(newTop-contentHt+clickItemHt,0);
+    this.openPopup(newLeft,newTop);
+    this.div.style.visibility ="visible";
+    return false;
+  },
+
+  clearMenu: function() {
+    this.div.innerHTML="";
+    this.defaultAction=null;
+    this.itemCount=0;
+  },
+
+  addMenuHeading: function(hdg,translate) {
+    var el=document.createElement('div')
+    el.innerHTML =(translate==null || translate==true) ? RicoTranslate.getPhrase(hdg) : hdg;
+    el.className='ricoMenuHeading';
+    this.div.appendChild(el);
+  },
+
+  addMenuBreak: function() {
+    var brk=document.createElement('div');
+    brk.className="ricoMenuBreak";
+    this.div.appendChild(brk);
+  },
+
+  addSubMenuItem: function(menutext, submenu, translate) {
+    var dir=this.direction=='rtl' ? 'left' : 'right';
+    var a=this.addMenuItem(menutext,null,true,null,translate);
+    a.className='ricoSubMenu';
+    a.style.backgroundImage='url('+Rico.imgDir+dir+'.gif)';
+    a.style.backgroundRepeat='no-repeat';
+    a.style.backgroundPosition=dir;
+    a.onmouseover=this.showSubMenu.bind(this,a,submenu);
+    a.onmouseout=this.subMenuOut.bindAsEventListener(this);
+  },
+  
+  showSubMenu: function(a,submenu) {
+    if (this.openSubMenu) this.hideSubMenu();
+    this.openSubMenu=submenu;
+    this.openMenuAnchor=a;
+    var pos=Position.page(a);
+    if (a.className=='ricoSubMenu') a.className='ricoSubMenuOpen';
+    submenu.openmenu(pos[0]+a.offsetWidth, pos[1], a.offsetWidth-2, a.offsetHeight+2);
+  },
+  
+  subMenuOut: function(e) {
+    if (!this.openSubMenu) return;
+    Event.stop(e);
+    var elem=Event.element(e);
+    var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
+    try {
+      while (reltg != null && reltg != this.openSubMenu.div)
+        reltg=reltg.parentNode;
+    } catch(err) {}
+    if (reltg == this.openSubMenu.div) return;
+    this.hideSubMenu();
+  },
+  
+  hideSubMenu: function() {
+    if (this.openMenuAnchor) {
+      this.openMenuAnchor.className='ricoSubMenu';
+      this.openMenuAnchor=null;
+    }
+    if (this.openSubMenu) {
+      this.openSubMenu.hidemenu();
+      this.openSubMenu=null;
+    }
+  },
+
+  addMenuItem: function(menutext,action,enabled,title,translate,target) {
+    this.itemCount++;
+    if (translate==null) translate=true;
+    var a = document.createElement(typeof action=='string' ? 'a' : 'div');
+    if ( arguments.length < 3 || enabled ) {
+      switch (typeof action) {
+        case 'function': 
+          a.onclick = action; 
+          break;
+        case 'string'  : 
+          a.href = action; 
+          if (target) a.target = target; 
+          break
+      }
+      a.className = 'enabled';
+      if (this.defaultAction==null) this.defaultAction=action;
+    } else {
+      a.disabled = true;
+      a.className = 'disabled';
+    }
+    a.innerHTML = translate ? RicoTranslate.getPhrase(menutext) : menutext;
+    if (typeof title=='string')
+      a.title = translate ? RicoTranslate.getPhrase(title) : title;
+    a=this.div.appendChild(a);
+    Event.observe(a,"mouseover", this.mouseOver.bindAsEventListener(this));
+    Event.observe(a,"mouseout", this.mouseOut.bindAsEventListener(this));
+    return a;
+  },
+  
+  mouseOver: function(e) {
+    if (this.highlightElem && this.highlightElem.className=='enabled-hover') {
+      // required for Safari
+      this.highlightElem.className='enabled';
+      this.highlightElem=null;
+    }
+    var elem=Event.element(e);
+    if (this.openMenuAnchor && this.openMenuAnchor!=elem)
+      this.hideSubMenu();
+    if (elem.className=='enabled') {
+      elem.className='enabled-hover';
+      this.highlightElem=elem;
+    }
+  },
+
+  mouseOut: function(e) {
+    var elem=Event.element(e);
+    if (elem.className=='enabled-hover') elem.className='enabled';
+    if (this.highlightElem==elem) this.highlightElem=null;
+  },
+
+  isVisible: function() {
+    return this.div && Element.visible(this.div);
+  },
+  
+  cancelmenu: function() {
+    if (this.hideFunc) this.hideFunc();
+    this.hideFunc=null;
+    this.hidemenu();
+  },
+
+  hidemenu: function() {
+    if (!this.div) return;
+    if (this.openSubMenu) this.openSubMenu.hidemenu();
+    this.closePopup();
+  }
+
+};
+
+Rico.includeLoaded('ricoMenu.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoSheet.js b/trunk/NP_TrackBack/trackback/js/rico/ricoSheet.js
new file mode 100644 (file)
index 0000000..5d88edd
--- /dev/null
@@ -0,0 +1,1577 @@
+Object.extend(Rico.SimpleGrid.prototype, {
+
+initSheet: function() {
+  this.highlightDiv=[];
+  for (var i=0; i<4; i++) {
+    this.highlightDiv[i] = this.createDiv("highlight",this.scrollDiv);
+    this.highlightDiv[i].style.display="none";
+    this.highlightDiv[i].id+=i;
+    this.highlightDiv[i].style[i % 2==0 ? 'height' : 'width']="0px";
+  }
+  for (var c=1; c<this.columns.length; c++) {
+    var col=this.columns[c];
+    for (var r=0; r<col.numRows(); r++) {
+      var cell=col.cell(r);
+      cell.RicoRow=r+1;
+      cell.RicoCol=c;
+      cell.RicoValue=null;
+    }
+  }
+  if (this.menu) {
+    if (!this.menu.grid) this.registerScrollMenu(this.menu);
+    this.menu.showmenu=this.menu.showSheetMenu;
+  }
+  this.inputArea=RicoUtil.createFormField(this.scrollDiv,'textarea',null,'inputArea');
+  this.inputArea.style.position='absolute';
+  this.inputArea.style.display='none';
+  this.inputArea.style.zIndex=2;
+  this.inputArea.cols=30;
+  this.inputArea.rows=4;
+  this.inputArea.blur();
+  this.clipBox=RicoUtil.createFormField(this.innerDiv,'textarea',null,'clipBox');
+  this.clipBox.style.position='absolute';
+  this.clipBox.style.display='none';
+  this.clipBox.cols=80;
+  this.clipBox.rows=10;
+  this.clipBox.style.top='0px';
+  this.clipBox.style.left='0px';
+  this.selectCellRC(0,1);
+  this.mouseOverHandler = this.selectMouseOver.bindAsEventListener(this);
+  this.mouseUpHandler  = this.selectMouseUp.bindAsEventListener(this);
+  Event.observe(this.inputArea,'keydown',this.inputKeydown.bindAsEventListener(this),false);
+  Event.observe(Prototype.Browser.IE ? document.body : window,'keydown',this.gridKeydown.bindAsEventListener(this),false);
+  Event.observe(this.tbody[1],"mousedown", this.selectMouseDown.bindAsEventListener(this), false);
+
+  // disable drag & select events in IE
+  this.outerDiv.ondrag = this.disableEvent;
+  this.outerDiv.onselectstart = this.disableEvent;
+  this.tbody[1].ondrag = this.disableEvent;
+  this.tbody[1].onselectstart = this.disableEvent;
+},
+
+disableEvent: function(e) {
+  e=e || event;
+  Event.stop(e);
+  return false;
+},
+
+cellIndex: function(cell) {
+  var a=cell.id.split(/_/);
+  var l=a.length;
+  var r=parseInt(a[l-2]);
+  var c=parseInt(a[l-1]);
+  return {row:r, column:c, tabIdx:this.columns[c].tabIdx, cell:cell};
+},
+
+AdjustSelection: function(cell) {
+  var newIdx=this.cellIndex(cell);
+  if (this.SelectIdxStart.tabIdx != newIdx.tabIdx) return;
+  this.HideSelection();
+  this.SelectIdxEnd=newIdx;
+  this.ShowSelection();
+},
+
+selectMouseDown: function(e) {
+  if (this.highlightEnabled==false) return true;
+  this.cancelMenu();
+  var cell=Event.element(e);
+  Event.stop(e);
+  if (!Event.isLeftClick(e)) return;
+  cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+  if (!cell) return;
+  var newIdx=this.cellIndex(cell);
+  if (e.shiftKey) {
+    if (!this.SelectIdxStart) return;
+    this.selectCellRC(newIdx.row,newIdx.column,true);
+  } else {
+    this.selectCellRC(newIdx.row,newIdx.column,false);
+    this.pluginSelect();
+  }
+},
+
+pluginSelect: function() {
+  if (this.selectPluggedIn) return;
+  var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+  Event.observe(tBody,"mouseover", this.mouseOverHandler, false);
+  Event.observe(this.outerDiv,"mouseup",  this.mouseUpHandler,  false);
+  this.selectPluggedIn=true;
+},
+
+unplugSelect: function() {
+  var tBody=this.tbody[this.SelectIdxStart.tabIdx];
+  Event.stopObserving(tBody,"mouseover", this.mouseOverHandler , false);
+  Event.stopObserving(this.outerDiv,"mouseup", this.mouseUpHandler , false);
+  this.selectPluggedIn=false;
+},
+
+selectMouseUp: function(e) {
+  this.unplugSelect();
+  var cell=Event.element(e);
+  cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+  if (!cell) return;
+  this.AdjustSelection(cell);
+},
+
+selectMouseOver: function(e) {
+  var cell=Event.element(e);
+  cell=RicoUtil.getParentByTagName(cell,'div','ricoLG_cell');
+  if (!cell) return;
+  this.AdjustSelection(cell);
+  Event.stop(e);
+},
+
+getSelection: function() {
+  if (!this.SelectIdxStart || !this.SelectIdxEnd) return false;
+  var r1=Math.min(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+  var r2=Math.max(this.SelectIdxEnd.row,this.SelectIdxStart.row);
+  var c1=Math.min(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+  var c2=Math.max(this.SelectIdxEnd.column,this.SelectIdxStart.column);
+  return {r1:r1,c1:c1,r2:r2,c2:c2};
+},
+
+updateSelectOutline: function() {
+  var s=this.getSelection();
+  if (!s || s.r1 > s.r2) {
+    this.HideSelection();
+    return;
+  }
+  var top1=this.columns[s.c1].cell(s.r1).offsetTop;
+  var cell2=this.columns[s.c1].cell(s.r2);
+  var bottom2=cell2.offsetTop+cell2.offsetHeight;
+  var left1=this.columns[s.c1].dataCell.offsetLeft;
+  var left2=this.columns[s.c2].dataCell.offsetLeft;
+  var right2=left2+this.columns[s.c2].dataCell.offsetWidth;
+  //window.status='updateSelectOutline: '+s.r1+' '+s.r2+' top='+top1+' bot='+bottom2;
+  this.highlightDiv[0].style.top=this.highlightDiv[3].style.top=this.highlightDiv[1].style.top=(top1-3) + 'px';
+  this.highlightDiv[2].style.top=(bottom2-2)+'px';
+  this.highlightDiv[3].style.left=(left1-2)+'px';
+  this.highlightDiv[0].style.left=this.highlightDiv[2].style.left=(left1-1)+'px';
+  this.highlightDiv[1].style.left=(right2-1)+'px';
+  this.highlightDiv[0].style.width=this.highlightDiv[2].style.width=(right2-left1-1) + 'px';
+  this.highlightDiv[1].style.height=this.highlightDiv[3].style.height=(bottom2-top1) + 'px';
+  for (var i=0; i<4; i++)
+    this.highlightDiv[i].style.display='';
+},
+
+isSelected: function(r,c) {
+  var s=this.getSelection();
+  return s ? (s.r1 <= r) && (r <= s.r2) && (s.c1 <= c) && (c <= s.c2) : false;
+},
+
+HideSelection: function(cellList) {
+  for (var i=0; i<4; i++)
+    this.highlightDiv[i].style.display='none';
+},
+
+ShowSelection: function() {
+  this.updateSelectOutline();
+},
+
+/*
+ * @param what valid values are: null, 'all', 'formats', 'formulas', 'values'
+ */
+clearSelection: function() {
+  var s=this.getSelection();
+  if (!s) return;
+  var args=$A(arguments);
+  var what=args.shift();
+  if (typeof what=='object') what=args.shift();  // in case first arg is an event object
+  var v=(!what || what=='all') ? 1 : 0;
+  var whatobj={formats:v,formulas:v,values:v};
+  if (typeof what=='string') whatobj[what]=1;
+  if (whatobj.values) whatobj.formulas=1;
+  for (var r=s.r1; r<=s.r2; r++) {
+    for (var c=s.c1; c<=s.c2; c++) {
+      var gridcell=this.columns[c].cell(r);
+      if (whatobj.formats) {
+        gridcell.style.cssText='';
+        gridcell.RicoFormat={};
+      }
+      if (whatobj.formulas) gridcell.RicoFormula=null;
+      if (whatobj.values) gridcell.RicoValue=null;
+      this.formatCell(gridcell);
+    }
+  }
+},
+
+selectCellRC: function(r,c,adjFlag) {
+  if (r < 0 || r >= this.columns[0].numRows()) return;
+  this.HideSelection();
+  if (adjFlag) {
+    if (this.SelectIdxStart.tabIdx == this.columns[c].tabIdx)
+      this.SelectIdxEnd={row:r, column:c, tabIdx:this.columns[c].tabIdx};
+  } else {
+    this.SelectIdxStart=this.SelectIdxEnd={row:r, column:c, tabIdx:this.columns[c].tabIdx};
+    this.columns[c].cell(r).focus(); // causes IE to scroll cell into view (but not FF)
+  }
+  this.ShowSelection();
+},
+
+moveSelection: function(dr,dc,adjFlag,e) {
+  var selIdx=adjFlag ? this.SelectIdxEnd : this.SelectIdxStart;
+  var newr=selIdx.row+dr;
+  var newc=selIdx.column+dc;
+  if (newr>=0 && newr<this.columns[0].numRows() && newc>=1 && newc<this.columns.length)
+    this.selectCellRC(newr,newc,adjFlag);
+  if (e) Event.stop(e);
+},
+
+formatCell: function(cell) {
+  // TO DO: add currency/date formatting here
+  var v=cell.RicoValue;
+  if (v==null)
+    v='';
+  else if (typeof(v)=='number')
+    v = isNaN(v) ? '#VALUE' : cell.RicoFormat ? v.formatNumber(cell.RicoFormat) : v.toString();
+  else if (typeof v!='string')
+    v=v.toString();
+  v=v.replace(/^(\s*)/, '');
+  cell.style.paddingLeft=(RegExp.$1.length/2)+'em';
+  cell.innerHTML = v;
+},
+
+// action='add' or 'remove'
+updateDependencies: function(formulaCell,action) {
+  if (!formulaCell.RicoFormula) return;
+  //alert('updateDependencies '+action+': '+formulaCell.RicoRow+','+formulaCell.RicoCol);
+  var ranges=formulaCell.RicoFormula.getRanges();
+  for (var i=0; i<ranges.length; i++) {
+    if (!ranges[i]) continue;
+    var r1=Math.min(ranges[i][0],ranges[i][2]);
+    var r2=Math.max(ranges[i][0],ranges[i][2]);
+    var c1=Math.min(ranges[i][1],ranges[i][3]);
+    var c2=Math.max(ranges[i][1],ranges[i][3]);
+    for (var c=c1; c<=c2; c++) {
+      var col=this.columns[c];
+      for (var r=r1; r<=r2; r++) {
+        var cell=col.cell(r-1);
+        if (!cell.RicoDependencies) cell.RicoDependencies=new Rico.Formula.f_dependencies();
+        //alert('updateDependencies '+action+': '+formulaCell.RicoRow+','+formulaCell.RicoCol+' is dependent on '+cell.RicoRow+','+cell.RicoCol);
+        cell.RicoDependencies[action](formulaCell);
+      }
+    }
+  }
+},
+
+checkDependencies: function(cell) {
+  if (!cell.RicoDependencies) return;
+  var depcells=cell.RicoDependencies.items;
+  for (var i=0; i<depcells.length; i++) {
+    depcells[i].RicoValue=depcells[i].RicoFormula.eval();
+    this.formatCell(depcells[i]);
+    this.checkDependencies(depcells[i]);
+  }
+},
+
+showInputArea: function(clear,e) {
+  this.unplugScroll();
+  this.inputIdx=this.SelectIdxStart;
+  var col=this.columns[this.inputIdx.column];
+  this.inputIdx.cell=col.cell(this.inputIdx.row);
+  this.inputArea.style.top=(this.inputIdx.cell.offsetTop+col.dataCell.offsetTop)+'px';
+  this.inputArea.style.left=col.dataCell.offsetLeft+'px';
+  this.inputArea.style.display='';
+  this.inputArea.focus();
+  if (clear) {
+    if (Prototype.Browser.WebKit) {
+      // Safari does not bubble the event to the inputArea, so force it
+      this.inputArea.value=String.fromCharCode(e.charCode);
+      this.inputArea.setSelectionRange(1,1);
+      Event.stop(e);
+    } else this.inputArea.value='';
+  } else {
+    if (this.inputIdx.cell.RicoFormula)
+      this.inputArea.value=this.inputIdx.cell.RicoFormula.toEditString();
+    else
+      this.inputArea.value=this.inputIdx.cell.RicoValue || '';
+  }
+},
+
+closeInputArea: function(dr,dc,e) {
+  var newVal=this.inputArea.value;
+  var cell=this.inputIdx.cell;
+  if (this.options.checkEntry)
+    newVal=this.options.checkEntry(newVal,this.inputIdx.cell);
+  this.updateDependencies(cell,'remove');
+  cell.RicoFormula=null;
+  if (!this.options.noFormulas && newVal.charAt(0) == '=') {
+    // parse formula
+    cell.RicoFormula = new Rico.Formula(grid,cell);
+    cell.RicoFormula.parse(newVal);
+    cell.RicoValue = cell.RicoFormula.eval();
+    this.updateDependencies(cell,'add');
+  } else if (newVal=='') {
+    cell.RicoValue = null;
+  } else if (newVal.match(/^(true|false)$/i)) {
+    cell.RicoValue = eval(newVal.toLowerCase());
+  } else if (newVal.match(/^-?\d+(.\d*)?$/)) {
+    // parse number
+    cell.RicoValue = parseFloat(newVal);
+  } else {
+    cell.RicoValue=newVal;
+  }
+  this.formatCell(cell);
+  this.inputArea.blur();
+  this.inputArea.style.display='none';
+  this.checkDependencies(cell);
+  this.pluginScroll();
+  this.moveSelection(dr,dc,false,e);
+},
+
+inputKeydown: function(e) {
+  //window.status='inputKeydown keyCode='+e.keyCode;
+  switch (e.keyCode) {
+    case 13:
+      Event.stop(e);
+      this.closeInputArea(1,0,e);
+      return false;
+    case 9:
+      Event.stop(e);
+      this.closeInputArea(0,e.shiftKey ? -1 : 1,e);
+      return false;
+    case 27:
+      Event.stop(e);
+      this.inputArea.blur();
+      this.inputArea.style.display='none';
+      return false;
+  }
+  return true;
+},
+
+copyToClipbox: function() {
+  var s=this.getSelection();
+  if (!s) return;
+  var clipstr='';
+  for (var r=s.r1; r<=s.r2; r++) {
+    for (var c=s.c1; c<=s.c2; c++) {
+      if (c>s.c1) clipstr+="\t";
+      clipstr+=this.columns[c].cell(r).RicoValue;
+    }
+    clipstr+="\r\n";
+  }
+  this.clipBox.style.display='block';
+  this.clipBox.value=clipstr;
+  this.clipBox.select();
+},
+
+copySelection: function() {
+  var s=this.getSelection();
+  if (!s) return;
+  var clipArray=[];
+  for (var r=s.r1; r<=s.r2; r++) {
+    var cliprow=[];
+    for (var c=s.c1; c<=s.c2; c++) {
+      var clipcell={};
+      var gridcell=this.columns[c].cell(r);
+      clipcell.value=gridcell.RicoValue;
+      clipcell.style=gridcell.style.cssText;
+      if (gridcell.RicoFormat)
+        clipcell.format=Object.extend({}, gridcell.RicoFormat || {});
+      if (gridcell.RicoFormula)
+        clipcell.formula=Object.extend({}, gridcell.RicoFormula);
+      cliprow[c-s.c1]=clipcell;
+    }
+    clipArray[r-s.r1]=cliprow;
+  }
+  return clipArray;
+},
+
+pasteSelection: function(clipArray,pasteType) {
+  var s=this.getSelection();
+  if (!s || !clipArray) return;
+  pasteType=pasteType || 'all';
+  var clipclen=clipArray[0].length;
+  if (s.r1==s.r2 && s.c1==s.c2) {
+    s.r2=Math.min(s.r1+clipArray.length,this.columns[0].numRows())-1;
+    s.c2=Math.min(s.c1+clipclen,this.columns.length)-1;
+  }
+  for (var r=s.r1,clipr=0; r<=s.r2; r++) {
+    var arow=clipArray[clipr];
+    for (var c=s.c1,clipc=0; c<=s.c2; c++) {
+      var clipcell=arow[clipc];
+      var gridcell=this.columns[c].cell(r);
+      this.updateDependencies(gridcell,'remove');
+      gridcell.RicoFormula=null;
+      if (clipcell.formula) {
+        gridcell.RicoFormula=Object.extend({}, clipcell.formula);
+        gridcell.RicoFormula.cell=gridcell;
+        gridcell.RicoValue = gridcell.RicoFormula.eval();
+        this.updateDependencies(gridcell,'add');
+      } else {
+        gridcell.RicoValue=clipcell.value;
+      }
+      gridcell.style.cssText=clipcell.style;
+      if (clipcell.format)
+        gridcell.RicoFormat=Object.extend({}, clipcell.format);
+      this.formatCell(gridcell);
+      this.checkDependencies(gridcell);
+      clipc=(clipc+1) % clipclen;
+    }
+    clipr=(clipr+1) % clipArray.length;
+  }
+},
+
+formatSelection: function(newFormat) {
+  var s=this.getSelection();
+  if (!s) return;
+  for (var r=s.r1; r<=s.r2; r++) {
+    for (var c=s.c1; c<=s.c2; c++) {
+      var gridcell=this.cell(r,c);
+      gridcell.RicoFormat=newFormat;
+      this.formatCell(gridcell);
+    }
+  }
+},
+
+handleCtrlKey: function(e) {
+  switch (e.keyCode) {
+    // Ctrl-C
+    case 67:
+      this.clip=this.copySelection();
+      window.status='copy: '+this.clip.length;
+      Event.stop(e);
+      break;
+
+    // Ctrl-X
+    case 88:
+      this.clip=this.copySelection();
+      this.clearSelection();
+      Event.stop(e);
+      break;
+
+    // Ctrl-V
+    case 86:
+      window.status='paste: '+this.clip.length;
+      this.pasteSelection(this.clip);
+      Event.stop(e);
+      break;
+
+    // Ctrl-B
+    case 66:
+      this.toggleAttr('font-weight','normal','bold');
+      Event.stop(e);
+      break;
+
+    // Ctrl-I
+    case 73:
+      this.toggleAttr('font-style','normal','italic');
+      Event.stop(e);
+      break;
+  }
+},
+
+handleNormalKey: function(e) {
+  switch (e.keyCode) {
+    case 91:
+    case 16:
+    case 17:
+    case 18:
+    case 20:
+    case 27: return;
+
+    // tab
+    case 9:  this.moveSelection(0,e.shiftKey ? -1 : 1,false,e); break;
+    // enter/return
+    case 13: this.moveSelection(1,0,false,e); break;
+    // arrow keys
+    case 37: this.moveSelection(0,-1,e.shiftKey,e); break;
+    case 38: this.moveSelection(-1,0,e.shiftKey,e); break;
+    case 39: this.moveSelection(0,1,e.shiftKey,e); break;
+    case 40: this.moveSelection(1,0,e.shiftKey,e); break;
+    // home
+    case 36: this.selectCellRC(this.SelectIdxStart.row,1); Event.stop(e); break;
+    // F2
+    case 113: this.showInputArea(false,e); break;
+
+    default: this.showInputArea(true,e); break;
+  }
+  return false;
+},
+
+gridKeydown: function(e) {
+  if (e.altKey) return;
+  var elem=Event.element(e);
+  if (elem.id=='inputArea') return true;
+  //window.status='gridKeydown keyCode='+e.keyCode;
+  if (e.ctrlKey)
+    this.handleCtrlKey(e);
+  else
+    this.handleNormalKey(e);
+},
+
+toggleAttr: function(attr,v1,v2) {
+  var v=this.getStyle(this.SelectIdxStart.row,this.SelectIdxStart.column,attr);
+  v=v==v2 ? v1 : v2;
+  this.updateSelectionStyle(attr,v);
+},
+
+getStyle: function(row,col,attr) {
+  var csstxt=this.columns[col].cell(row).style.cssText;
+  if (!csstxt) return;
+  if (csstxt.charAt(csstxt.length-1)!=';') csstxt+=';';   // opera
+  csstxt=' '+csstxt;
+  var re=new RegExp("[ ;]"+attr+"\\s*:\\s*([^ ;]*)\\s*;","i");
+  if (re.test(csstxt))
+    return RegExp.$1;
+  else
+    return;
+},
+
+updateStyleText: function(csstxt,attr,value) {
+  var newval=attr+':'+value+';';
+  if (!csstxt) return newval;
+  csstxt=' '+csstxt.strip();
+  if (csstxt.charAt(csstxt.length-1)!=';') csstxt+=';';   // opera
+  var re=new RegExp("([ ;])"+attr+"\\s*:\\s*([^ ;]*)\\s*;","i");
+  // safari must process the regexp twice, everyone else can run it once
+  if (re.test(csstxt))
+    return Prototype.Browser.WebKit ? csstxt.replace(re,"$1"+newval) : RegExp.leftContext+RegExp.$1+newval+RegExp.rightContext;
+  else
+    return csstxt+newval;
+},
+
+updateSelectionStyle: function(attr,newVal) {
+  var s=this.getSelection();
+  if (!s) return;
+  for (var c=s.c1; c<=s.c2; c++) {
+    var col=this.columns[c];
+    for (var r=s.r1; r<=s.r2; r++)
+      col.cell(r).style.cssText=this.updateStyleText(col.cell(r).style.cssText,attr,newVal);
+  }
+},
+
+showHelp: function() {
+  var msg="Rico Spreadsheet\n\n";
+  msg+="Ctrl-C = copy, Ctrl-X = cut, Ctrl-V = paste (only from/to cells on this grid)\n\n";
+  msg+="Formulas starting with '=' are supported\n";
+  msg+="Formulas may contain parentheses and the following operators: + - * / & % = > < <= >= <>\n";
+  msg+="'+' follows javascript rules regarding type conversion (which are slightly different from Excel)\n";
+  msg+="Formulas may refer to cells using 'A1' notation (and 'A1:B2' for ranges).\n";
+  msg+="The following functions are supported in formulas:\n\n";
+  var funclist=[];
+  for (var funcname in Rico.Formula.prototype)
+    if (funcname.substring(0,5)=='eval_') funclist.push(funcname.substring(5));
+  funclist.sort();
+  var funcstr=funclist.join(', ');
+  var i=funcstr.indexOf(' ',Math.floor(funcstr.length/2));
+  msg+=funcstr.substring(0,i)+"\n"+funcstr.substring(i+1);
+  msg+="\n\nFormula parsing based on code originally published by E. W. Bachtal at http://ewbi.blogs.com/develops/";
+  msg+="\nFuture functionality may include copy/paste from external applications, load/save, number & date formatting, and support for additional functions.";
+  alert(msg);
+}
+
+});
+
+
+Rico.Formula = Class.create();
+
+Rico.Formula.TOK_TYPE_NOOP      = "noop";
+Rico.Formula.TOK_TYPE_OPERAND   = "operand";
+Rico.Formula.TOK_TYPE_FUNCTION  = "function";
+Rico.Formula.TOK_TYPE_SUBEXPR   = "subexpression";
+Rico.Formula.TOK_TYPE_ARGUMENT  = "argument";
+Rico.Formula.TOK_TYPE_OP_PRE    = "operator-prefix";
+Rico.Formula.TOK_TYPE_OP_IN     = "operator-infix";
+Rico.Formula.TOK_TYPE_OP_POST   = "operator-postfix";
+Rico.Formula.TOK_TYPE_WSPACE    = "white-space";
+Rico.Formula.TOK_TYPE_UNKNOWN   = "unknown";
+
+Rico.Formula.TOK_SUBTYPE_START       = "start";
+Rico.Formula.TOK_SUBTYPE_STOP        = "stop";
+
+Rico.Formula.TOK_SUBTYPE_TEXT        = "text";
+Rico.Formula.TOK_SUBTYPE_NUMBER      = "number";
+Rico.Formula.TOK_SUBTYPE_LOGICAL     = "logical";
+Rico.Formula.TOK_SUBTYPE_ERROR       = "error";
+Rico.Formula.TOK_SUBTYPE_RANGE       = "range";
+
+Rico.Formula.TOK_SUBTYPE_MATH        = "math";
+Rico.Formula.TOK_SUBTYPE_CONCAT      = "concatenate";
+Rico.Formula.TOK_SUBTYPE_INTERSECT   = "intersect";
+Rico.Formula.TOK_SUBTYPE_UNION       = "union";
+
+Rico.Formula.prototype = {
+
+initialize: function(grid,cell) {
+  this.grid=grid;
+  this.cell=cell;
+},
+
+// 'A' -> 1, 'AA' -> 27
+colLetter2Num: function(colstr) {
+  colstr=colstr.toUpperCase();
+  switch (colstr.length) {
+    case 1: return colstr.charCodeAt(0)-64;
+    case 2: return (colstr.charCodeAt(0)-64) * 26 + colstr.charCodeAt(1)-64;
+    default: return -1;
+  }
+},
+
+// 1 -> 'A', 27 -> 'AA'
+colNum2Letter: function(colnum) {
+  if (colnum <= 26) return String.fromCharCode(64+colnum);
+  colnum-=1;
+  return String.fromCharCode(64+Math.floor(colnum / 26),65+(colnum % 26));
+},
+
+
+toHTML: function() {
+  var indentCount = 0;
+
+  var indent = function() {
+    var s = "|";
+    for (var i = 0; i < indentCount; i++) {
+      s += "&nbsp;&nbsp;&nbsp;|";
+    }
+    return s;
+  };
+
+  var tokensHtml = "<table cellspacing='0'>";
+  tokensHtml += "<tr>";
+  tokensHtml += "<td class='token' style='font-weight: bold; width: 50px'>index</td>";
+  tokensHtml += "<td class='token' style='font-weight: bold; width: 125px'>type</td>";
+  tokensHtml += "<td class='token' style='font-weight: bold; width: 125px'>subtype</td>";
+  tokensHtml += "<td class='token' style='font-weight: bold; width: 150px'>token</td>";
+  tokensHtml += "<td class='token' style='font-weight: bold; width: 300px'>token tree</td></tr>";
+
+  this.tokens.reset();
+  while (this.tokens.moveNext()) {
+
+    var token = this.tokens.current();
+
+    if (token.subtype == Rico.Formula.TOK_SUBTYPE_STOP)
+      indentCount -= ((indentCount > 0) ? 1 : 0);
+
+    tokensHtml += "<tr>";
+
+    tokensHtml += "<td class='token'>" + (this.tokens.index + 1) + "</td>";
+    tokensHtml += "<td class='token'>" + token.type + "</td>";
+    tokensHtml += "<td class='token'>" + ((token.subtype.length == 0) ? "&nbsp;" : token.subtype) + "</td>";
+    tokensHtml += "<td class='token'>" + ((token.value.length == 0) ? "&nbsp;" : token.value).split(" ").join("&nbsp;") + "</td>";
+    tokensHtml += "<td class='token'>" + indent() + ((token.value.length == 0) ? "&nbsp;" : token.value).split(" ").join("&nbsp;") + "</td>";
+
+    tokensHtml += "</tr>";
+
+    if (token.subtype == Rico.Formula.TOK_SUBTYPE_START) indentCount++;
+  }
+  tokensHtml += "</table>";
+  return tokensHtml;
+},
+
+
+parseCellRef: function(refString) {
+  if (!refString) return null;
+  if (!refString.match(/^(\$?)([a-z]*)(\$?)(\d*)$/i)) return null;
+  var abscol=(RegExp.$1=='$');
+  var absrow=(RegExp.$3=='$');
+  var r=null,c=null;
+  if (RegExp.$2) {
+    c=this.colLetter2Num(RegExp.$2);
+    if (c<0 || c>=this.grid.columns.length) return null;
+    if (!abscol) c-=this.cell.RicoCol;
+  }
+  if (RegExp.$4) {
+    r=parseInt(RegExp.$4);
+    if (!absrow) r-=this.cell.RicoRow;
+  }
+  //alert('parseCellRef: '+refString+"\n"+'r='+r+' c='+c+' absrow='+absrow+' abscol='+abscol);
+  return {row:r, col:c, absRow:absrow, absCol:abscol};
+},
+
+
+resolveCellRef: function(cellRef) {
+  var r=cellRef.row;
+  var c=cellRef.col;
+  if (!cellRef.absRow) r+=this.cell.RicoRow;
+  if (!cellRef.absCol) c+=this.cell.RicoCol;
+  return {row:r, col:c};
+},
+
+
+resolveRange: function(token) {
+  if (!token.rangeStart) return null;
+  var a1=this.resolveCellRef(token.rangeStart);
+  var a2=this.resolveCellRef(token.rangeEnd);
+  //alert('resolveRange: '+a1.row+','+a1.col+' '+a2.row+','+a2.col);
+  var r1=Math.min(a1.row,a2.row);
+  var r2=Math.max(a1.row,a2.row);
+  var c1=Math.min(a1.col,a2.col) || 0;
+  var c2=Math.max(a1.col,a2.col) || this.grid.columns.length-1;
+  return [r1,c1,r2,c2];
+},
+
+
+range2evalstr: function(token) {
+  var rng=this.resolveRange(token);
+  return rng ? rng.join(',') : '';
+},
+
+
+cellref2str: function(cellRef) {
+  var ref=this.resolveCellRef(cellRef);
+  var c=this.colNum2Letter(ref.col);
+  if (cellRef.absCol) c='$'+c;
+  var r=ref.row.toString();
+  if (cellRef.absRow) r='$'+r;
+  return c+r;
+},
+
+
+range2str: function(token) {
+  var s1=this.cellref2str(token.rangeStart);
+  var s2=this.cellref2str(token.rangeEnd);
+  return (s1==s2) ? s1 : s1+':'+s2;
+},
+
+
+GetRange: function(r1,c1,r2,c2) {
+  if (typeof r1=='undefined' || typeof c1=='undefined') return NaN;
+  if (r1==r2 && c1==c2) return this.grid.columns[c1].cell(r1-1).RicoValue;
+  var result=[];
+  for (var r=r1; r<=r2; r++) {
+    var newRow=[];
+    for (var c=c1; c<=c2; c++)
+      newRow.push(this.grid.columns[c].cell(r-1).RicoValue);
+    result.push(newRow);
+  }
+  return result;
+},
+
+
+getRanges: function() {
+  var result=[];
+  this.tokens.reset();
+  while (this.tokens.moveNext()) {
+    var token = this.tokens.current();
+    if (token.subtype=='range') result.push(this.resolveRange(token));
+  }
+  return result;
+},
+
+
+eval_sum: function() {
+  var result=0;
+  for (var i=0; i<arguments.length; i++) {
+    arg=arguments[i];
+    if (arg==null) continue;
+    switch (typeof arg) {
+      case 'number':
+        result+=arg;
+        break;
+      case 'object':
+        for (var r=0; r<arg.length; r++)
+          for (var c=0; c<arg[r].length; c++)
+            if (typeof arg[r][c]=='number') result+=arg[r][c];
+        break;
+    }
+  }
+  return result;
+},
+
+
+eval_count: function() {
+  var result=0;
+  for (var i=0; i<arguments.length; i++) {
+    arg=arguments[i];
+    if (arg==null) continue;
+    switch (typeof arg) {
+      case 'object':
+        for (var r=0; r<arg.length; r++)
+          for (var c=0; c<arg[r].length; c++)
+            if (arg[r][c] || typeof arg[r][c]=='number') result++;
+        break;
+      default:
+        if (arg || typeof arg=='number') result++;
+        break;
+    }
+  }
+  return result;
+},
+
+
+eval_t: function(arg) {
+  return (typeof arg=='string') ? arg : '';
+},
+
+
+eval_trim: function(arg) {
+  arg=this.argString(arg);
+  return arg.strip();
+},
+
+
+eval_lower: function(arg) {
+  arg=this.argString(arg);
+  return arg.toLowerCase();
+},
+
+
+eval_upper: function(arg) {
+  arg=this.argString(arg);
+  return arg.toUpperCase();
+},
+
+
+eval_len: function(arg) {
+  arg=this.argString(arg);
+  return arg.length;
+},
+
+
+eval_value: function(arg) {
+  arg=this.argString(arg);
+  return parseFloat(arg);
+},
+
+
+eval_left: function(arg,numchars) {
+  arg=this.argString(arg);
+  if (typeof numchars!='number') numchars=1;
+  if (numchars<0) return NaN;
+  return arg.slice(0,numchars);
+},
+
+
+eval_right: function(arg,numchars) {
+  arg=this.argString(arg);
+  if (typeof numchars!='number') numchars=1;
+  if (numchars<0) return NaN;
+  if (numchars==0) return '';
+  return arg.slice(-numchars);
+},
+
+
+eval_mid: function(arg,start,numchars) {
+  arg=this.argString(arg);
+  if (typeof start!='number' || start<1) return NaN;
+  if (typeof numchars!='number' || numchars<0) return NaN;
+  return arg.substr(start-1,numchars);
+},
+
+
+eval_if: function(logical_test, value_true, value_false) {
+  var v=this.argBool(logical_test);
+  if (v==null) return NaN;
+  return v ? value_true : value_false;
+},
+
+
+eval_not: function(arg) {
+  var v=this.argBool(arg);
+  return (v==null) ? NaN : !v;
+},
+
+
+eval_and: function() {
+  var args = $A(arguments);
+  args.unshift(function(a,b) { return a&&b; });
+  return this.or_and.apply(this, args);
+},
+
+
+eval_or: function() {
+  var args = $A(arguments);
+  args.unshift(function(a,b) { return a||b; });
+  return this.or_and.apply(this, args);
+},
+
+
+or_and: function() {
+  var result;
+  var func=arguments[0];
+  for (var i=1; i<arguments.length; i++) {
+    arg=arguments[i];
+    if (arg==null) continue;
+    switch (typeof arg) {
+      case 'object':
+        for (var r=0; r<arg.length; r++)
+          for (var c=0; c<arg[r].length; c++) {
+            var v=this.argBool(arg[r][c])
+            if (v!=null) result=(typeof result=='undefined') ? v : func(result,v);
+          }
+        break;
+      default:
+        var v=this.argBool(arg)
+        if (v!=null) result=(typeof result=='undefined') ? v : func(result,v);
+        break;
+    }
+  }
+  return (typeof result=='undefined') ? NaN : result;
+},
+
+
+eval_abs:     function(arg) { return Math.abs(this.argNumber(arg)); },
+eval_acos:    function(arg) { return Math.acos(this.argNumber(arg)); },
+eval_asin:    function(arg) { return Math.asin(this.argNumber(arg)); },
+eval_atan:    function(arg) { return Math.atan(this.argNumber(arg)); },
+eval_atan2:   function(argx,argy) { return Math.atan2(this.argNumber(argy),this.argNumber(argx)); },
+eval_ceiling: function(arg) { return Math.ceil(this.argNumber(arg)); },
+eval_cos:     function(arg) { return Math.cos(this.argNumber(arg)); },
+eval_exp:     function(arg) { return Math.exp(this.argNumber(arg)); },
+eval_floor:   function(arg) { return Math.floor(this.argNumber(arg)); },
+eval_ln:      function(arg) { return Math.log(this.argNumber(arg)); },
+eval_mod:     function(num,divisor) { return this.argNumber(num) % this.argNumber(divisor); },
+eval_pi:      function() { return Math.PI; },
+eval_power:   function(argx,argy) { return Math.pow(this.argNumber(argx),this.argNumber(argy)); },
+eval_rand:    function() { return Math.random(); },
+eval_round:   function(arg) { return Math.round(this.argNumber(arg)); },
+eval_sin:     function(arg) { return Math.sin(this.argNumber(arg)); },
+eval_sqrt:    function(arg) { return Math.sqrt(this.argNumber(arg)); },
+eval_tan:     function(arg) { return Math.tan(this.argNumber(arg)); },
+
+
+argNumber: function(arg) {
+  switch (typeof arg) {
+    case 'boolean': return arg;
+    case 'number': return arg;
+    case 'string': return parseFloat(arg);
+    default: return null;
+  }
+},
+
+
+argBool: function(arg) {
+  switch (typeof arg) {
+    case 'boolean': return arg;
+    case 'number': return arg!=0;
+    default: return null;
+  }
+},
+
+
+argString: function(arg) {
+  switch (typeof arg) {
+    case 'string': return arg;
+    case 'boolean':
+    case 'number': return arg.toString();
+    default: return '';
+  }
+},
+
+
+eval: function() {
+  var evalstr='';
+  this.tokens.reset();
+  while (this.tokens.moveNext()) {
+    var token = this.tokens.current();
+    switch (token.type) {
+      case 'function':
+        if (token.subtype=='start') {
+          var funcname='eval_'+token.value.toLowerCase();
+          if (typeof this[funcname]!='function') {
+            alert('Unknown function: '+token.value);
+            return '#ERROR';
+          }
+          evalstr+='this.'+funcname+'(';
+        } else
+          evalstr+=')';
+        break;
+      case 'subexpression':
+        if (token.subtype=='start')
+          evalstr+='(';
+        else
+          evalstr+=')';
+        break;
+      case 'operator-infix':
+        if (token.value=='&')
+          evalstr+='+';
+        else if (token.value=='=')
+          evalstr+='==';
+        else if (token.value=='<>')
+          evalstr+='!=';
+        else
+          evalstr+=token.value;
+        break;
+      case 'operator-postfix':
+        if (token.value=='%')
+          evalstr+='/100';
+        else
+          evalstr+=token.value;
+        break;
+      case 'operand':
+        if (token.subtype=='range')
+          evalstr+='this.GetRange('+this.range2evalstr(token)+')';
+        else if (token.subtype=='text')
+          evalstr+='"'+token.value+'"';
+        else
+          evalstr+=token.value;
+        break;
+      default:
+        evalstr+=token.value;
+        break;
+    }
+  }
+  this.lastEval=evalstr;
+  //window.status=evalstr;
+  try {
+    var result=eval(evalstr)
+    return result;
+  } catch(e) { alert(e.message); return '#ERROR'; }
+},
+
+
+toEditString: function() {
+  var s='=';
+  this.tokens.reset();
+  while (this.tokens.moveNext()) {
+    var token = this.tokens.current();
+    switch (token.type) {
+      case 'function':
+        if (token.subtype=='start')
+          s+=token.value+'(';
+        else
+          s+=')';
+        break;
+      case 'subexpression':
+        if (token.subtype=='start')
+          s+='(';
+        else
+          s+=')';
+        break;
+      case 'operand':
+        if (token.subtype=='range')
+          s+=this.range2str(token);
+        else if (token.subtype=='text')
+          s+='"'+token.value+'"';
+        else
+          s+=token.value;
+        break;
+      default:
+        s+=token.value;
+    }
+  }
+  return s;
+},
+
+
+// Excel formula parser
+// from http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html
+parse: function(formula) {
+  var tokens = new Rico.Formula.f_tokens();
+  var tokenStack = new Rico.Formula.f_tokenStack();
+
+  var offset = 0;
+
+  var currentChar = function() { return formula.substr(offset, 1); };
+  var doubleChar  = function() { return formula.substr(offset, 2); };
+  var nextChar    = function() { return formula.substr(offset + 1, 1); };
+  var EOF         = function() { return (offset >= formula.length); };
+
+  var token = "";
+
+  var inString = false;
+  var inPath = false;
+  var inRange = false;
+  var inError = false;
+
+  while (formula.length > 0) {
+    if (formula.substr(0, 1) == " ")
+      formula = formula.substr(1);
+    else {
+      if (formula.substr(0, 1) == "=")
+        formula = formula.substr(1);
+      break;
+    }
+  }
+
+  while (!EOF()) {
+
+    // state-dependent character evaluation (order is important)
+
+    // double-quoted strings
+    // embeds are doubled
+    // end marks token
+
+    if (inString) {
+      if (currentChar() == "\"") {
+        if (nextChar() == "\"") {
+          token += "\"";
+          offset += 1;
+        } else {
+          inString = false;
+          tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND, Rico.Formula.TOK_SUBTYPE_TEXT);
+          token = "";
+        }
+      } else {
+        token += currentChar();
+      }
+      offset += 1;
+      continue;
+    }
+
+    // single-quoted strings (links)
+    // embeds are double
+    // end does not mark a token
+
+    if (inPath) {
+      if (currentChar() == "'") {
+        if (nextChar() == "'") {
+          token += "'";
+          offset += 1;
+        } else {
+          inPath = false;
+        }
+      } else {
+        token += currentChar();
+      }
+      offset += 1;
+      continue;
+    }
+
+    // bracked strings (range offset or linked workbook name)
+    // no embeds (changed to "()" by Excel)
+    // end does not mark a token
+
+    if (inRange) {
+      if (currentChar() == "]") {
+        inRange = false;
+      }
+      token += currentChar();
+      offset += 1;
+      continue;
+    }
+
+    // error values
+    // end marks a token, determined from absolute list of values
+
+    if (inError) {
+      token += currentChar();
+      offset += 1;
+      if ((",#NULL!,#DIV/0!,#VALUE!,#REF!,#NAME?,#NUM!,#N/A,").indexOf("," + token + ",") != -1) {
+        inError = false;
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND, Rico.Formula.TOK_SUBTYPE_ERROR);
+        token = "";
+      }
+      continue;
+    }
+
+    // independent character evaulation (order not important)
+
+    // establish state-dependent character evaluations
+
+    if (currentChar() == "\"") {
+      if (token.length > 0) {
+        // not expected
+        tokens.add(token, Rico.Formula.TOK_TYPE_UNKNOWN);
+        token = "";
+      }
+      inString = true;
+      offset += 1;
+      continue;
+    }
+
+    if (currentChar() == "'") {
+      if (token.length > 0) {
+        // not expected
+        tokens.add(token, Rico.Formula.TOK_TYPE_UNKNOWN);
+        token = "";
+      }
+      inPath = true;
+      offset += 1;
+      continue;
+    }
+
+    if (currentChar() == "[") {
+      inRange = true;
+      token += currentChar();
+      offset += 1;
+      continue;
+    }
+
+    if (currentChar() == "#") {
+      if (token.length > 0) {
+        // not expected
+        tokens.add(token, Rico.Formula.TOK_TYPE_UNKNOWN);
+        token = "";
+      }
+      inError = true;
+      token += currentChar();
+      offset += 1;
+      continue;
+    }
+
+    // mark start and end of arrays and array rows
+
+    if (currentChar() == "{") {
+      if (token.length > 0) {
+        // not expected
+        tokens.add(token, Rico.Formula.TOK_TYPE_UNKNOWN);
+        token = "";
+      }
+      tokenStack.push(tokens.add("ARRAY", Rico.Formula.TOK_TYPE_FUNCTION, Rico.Formula.TOK_SUBTYPE_START));
+      tokenStack.push(tokens.add("ARRAYROW", Rico.Formula.TOK_TYPE_FUNCTION, Rico.Formula.TOK_SUBTYPE_START));
+      offset += 1;
+      continue;
+    }
+
+    if (currentChar() == ";") {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.addRef(tokenStack.pop());
+      tokens.add(",", Rico.Formula.TOK_TYPE_ARGUMENT);
+      tokenStack.push(tokens.add("ARRAYROW", Rico.Formula.TOK_TYPE_FUNCTION, Rico.Formula.TOK_SUBTYPE_START));
+      offset += 1;
+      continue;
+    }
+
+    if (currentChar() == "}") {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.addRef(tokenStack.pop());
+      tokens.addRef(tokenStack.pop());
+      offset += 1;
+      continue;
+    }
+
+    // trim white-space
+
+    if (currentChar() == " ") {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.add("", Rico.Formula.TOK_TYPE_WSPACE);
+      offset += 1;
+      while ((currentChar() == " ") && (!EOF())) {
+        offset += 1;
+      }
+      continue;
+    }
+
+    // multi-character comparators
+
+    if ((",>=,<=,<>,").indexOf("," + doubleChar() + ",") != -1) {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.add(doubleChar(), Rico.Formula.TOK_TYPE_OP_IN, Rico.Formula.TOK_SUBTYPE_LOGICAL);
+      offset += 2;
+      continue;
+    }
+
+    // standard infix operators
+
+    if (("+-*/^&=><").indexOf(currentChar()) != -1) {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.add(currentChar(), Rico.Formula.TOK_TYPE_OP_IN);
+      offset += 1;
+      continue;
+    }
+
+    // standard postfix operators
+
+    if (("%").indexOf(currentChar()) != -1) {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.add(currentChar(), Rico.Formula.TOK_TYPE_OP_POST);
+      offset += 1;
+      continue;
+    }
+
+    // start subexpression or function
+
+    if (currentChar() == "(") {
+      if (token.length > 0) {
+        tokenStack.push(tokens.add(token, Rico.Formula.TOK_TYPE_FUNCTION, Rico.Formula.TOK_SUBTYPE_START));
+        token = "";
+      } else {
+        tokenStack.push(tokens.add("", Rico.Formula.TOK_TYPE_SUBEXPR, Rico.Formula.TOK_SUBTYPE_START));
+      }
+      offset += 1;
+      continue;
+    }
+
+    // function, subexpression, array parameters
+
+    if (currentChar() == ",") {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      if (!(tokenStack.type() == Rico.Formula.TOK_TYPE_FUNCTION)) {
+        tokens.add(currentChar(), Rico.Formula.TOK_TYPE_OP_IN, Rico.Formula.TOK_SUBTYPE_UNION);
+      } else {
+        tokens.add(currentChar(), Rico.Formula.TOK_TYPE_ARGUMENT);
+      }
+      offset += 1;
+      continue;
+    }
+
+    // stop subexpression
+
+    if (currentChar() == ")") {
+      if (token.length > 0) {
+        tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+        token = "";
+      }
+      tokens.addRef(tokenStack.pop());
+      offset += 1;
+      continue;
+    }
+
+    // token accumulation
+
+    token += currentChar();
+    offset += 1;
+
+  }
+
+  // dump remaining accumulation
+
+  if (token.length > 0) tokens.add(token, Rico.Formula.TOK_TYPE_OPERAND);
+
+  // move all tokens to a new collection, excluding all unnecessary white-space tokens
+
+  var tokens2 = new Rico.Formula.f_tokens();
+
+  while (tokens.moveNext()) {
+
+    token = tokens.current();
+
+    if (token.type == Rico.Formula.TOK_TYPE_WSPACE) {
+      if ((tokens.BOF()) || (tokens.EOF())) {}
+      else if (!(
+                 ((tokens.previous().type == Rico.Formula.TOK_TYPE_FUNCTION) && (tokens.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+                 ((tokens.previous().type == Rico.Formula.TOK_TYPE_SUBEXPR) && (tokens.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+                 (tokens.previous().type == Rico.Formula.TOK_TYPE_OPERAND)
+                )
+              ) {}
+      else if (!(
+                 ((tokens.next().type == Rico.Formula.TOK_TYPE_FUNCTION) && (tokens.next().subtype == Rico.Formula.TOK_SUBTYPE_START)) ||
+                 ((tokens.next().type == Rico.Formula.TOK_TYPE_SUBEXPR) && (tokens.next().subtype == Rico.Formula.TOK_SUBTYPE_START)) ||
+                 (tokens.next().type == Rico.Formula.TOK_TYPE_OPERAND)
+                 )
+               ) {}
+      else
+        tokens2.add(token.value, Rico.Formula.TOK_TYPE_OP_IN, Rico.Formula.TOK_SUBTYPE_INTERSECT);
+      continue;
+    }
+
+    tokens2.addRef(token);
+
+  }
+
+  // switch infix "-" operator to prefix when appropriate, switch infix "+" operator to noop when appropriate, identify operand
+  // and infix-operator subtypes, pull "@" from in front of function names
+
+  while (tokens2.moveNext()) {
+
+    token = tokens2.current();
+
+    if ((token.type == Rico.Formula.TOK_TYPE_OP_IN) && (token.value == "-")) {
+      if (tokens2.BOF())
+        token.type = Rico.Formula.TOK_TYPE_OP_PRE;
+      else if (
+               ((tokens2.previous().type == Rico.Formula.TOK_TYPE_FUNCTION) && (tokens2.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+               ((tokens2.previous().type == Rico.Formula.TOK_TYPE_SUBEXPR) && (tokens2.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+               (tokens2.previous().type == Rico.Formula.TOK_TYPE_OP_POST) ||
+               (tokens2.previous().type == Rico.Formula.TOK_TYPE_OPERAND)
+              )
+        token.subtype = Rico.Formula.TOK_SUBTYPE_MATH;
+      else
+        token.type = Rico.Formula.TOK_TYPE_OP_PRE;
+      continue;
+    }
+
+    if ((token.type == Rico.Formula.TOK_TYPE_OP_IN) && (token.value == "+")) {
+      if (tokens2.BOF())
+        token.type = Rico.Formula.TOK_TYPE_NOOP;
+      else if (
+               ((tokens2.previous().type == Rico.Formula.TOK_TYPE_FUNCTION) && (tokens2.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+               ((tokens2.previous().type == Rico.Formula.TOK_TYPE_SUBEXPR) && (tokens2.previous().subtype == Rico.Formula.TOK_SUBTYPE_STOP)) ||
+               (tokens2.previous().type == Rico.Formula.TOK_TYPE_OP_POST) ||
+               (tokens2.previous().type == Rico.Formula.TOK_TYPE_OPERAND)
+              )
+        token.subtype = Rico.Formula.TOK_SUBTYPE_MATH;
+      else
+        token.type = Rico.Formula.TOK_TYPE_NOOP;
+      continue;
+    }
+
+    if ((token.type == Rico.Formula.TOK_TYPE_OP_IN) && (token.subtype.length == 0)) {
+      if (("<>=").indexOf(token.value.substr(0, 1)) != -1)
+        token.subtype = Rico.Formula.TOK_SUBTYPE_LOGICAL;
+      else if (token.value == "&")
+        token.subtype = Rico.Formula.TOK_SUBTYPE_CONCAT;
+      else
+        token.subtype = Rico.Formula.TOK_SUBTYPE_MATH;
+      continue;
+    }
+
+    if ((token.type == Rico.Formula.TOK_TYPE_OPERAND) && (token.subtype.length == 0)) {
+      if (isNaN(parseFloat(token.value)))
+        if ((token.value == 'TRUE') || (token.value == 'FALSE'))
+          token.subtype = Rico.Formula.TOK_SUBTYPE_LOGICAL;
+        else {
+          token.subtype = Rico.Formula.TOK_SUBTYPE_RANGE;
+          var a=token.value.split(':');
+          token.rangeStart=this.parseCellRef(a[0]);
+          token.rangeEnd=a.length>1 ? this.parseCellRef(a[1]) : token.rangeStart;
+        }
+      else
+        token.subtype = Rico.Formula.TOK_SUBTYPE_NUMBER;
+      continue;
+    }
+
+    if (token.type == Rico.Formula.TOK_TYPE_FUNCTION) {
+      if (token.value.substr(0, 1) == "@")
+        token.value = token.value.substr(1);
+      continue;
+    }
+
+  }
+
+  tokens2.reset();
+
+  // move all tokens to a new collection, excluding all noops
+
+  this.tokens = new Rico.Formula.f_tokens();
+
+  while (tokens2.moveNext()) {
+    if (tokens2.current().type != Rico.Formula.TOK_TYPE_NOOP)
+      this.tokens.addRef(tokens2.current());
+  }
+}
+
+}
+
+
+Rico.Formula.f_token = Class.create();
+Rico.Formula.f_token.prototype = {
+  initialize: function(value, type, subtype) {
+    this.value = value;
+    this.type = type;
+    this.subtype = subtype;
+  }
+}
+
+
+Rico.Formula.f_tokens = Class.create();
+Rico.Formula.f_tokens.prototype = {
+  initialize: function() {
+    this.items = new Array();
+    this.index = -1;
+  },
+
+  addRef: function(token) {
+    this.items.push(token);
+  },
+
+  add: function(value, type, subtype) {
+    if (!subtype) subtype = "";
+    var token = new Rico.Formula.f_token(value, type, subtype);
+    this.addRef(token);
+    return token;
+  },
+
+  reset: function() {
+    this.index = -1;
+  },
+
+  BOF: function() {
+    return (this.index <= 0);
+  },
+
+  EOF: function() {
+    return (this.index >= (this.items.length - 1));
+  },
+
+  moveNext: function() {
+    if (this.EOF()) return false; this.index++; return true;
+  },
+
+  current: function() {
+    if (this.index == -1) return null; return (this.items[this.index]);
+  },
+
+  next: function() {
+    if (this.EOF()) return null; return (this.items[this.index + 1]);
+  },
+
+  previous: function() {
+    if (this.index < 1) return null; return (this.items[this.index - 1]);
+  }
+}
+
+
+Rico.Formula.f_tokenStack = Class.create();
+Rico.Formula.f_tokenStack.prototype = {
+  initialize: function() {
+    this.items = new Array();
+  },
+
+  push: function(token) {
+    this.items.push(token);
+  },
+
+  pop: function() {
+    var token = this.items.pop();
+    return (new Rico.Formula.f_token("", token.type, Rico.Formula.TOK_SUBTYPE_STOP));
+  },
+
+  token: function() {
+    return ((this.items.length > 0) ? this.items[this.items.length - 1] : null);
+  },
+
+  value: function() {
+    return ((this.token()) ? this.token().value : "");
+  },
+
+  type: function() {
+    return ((this.token()) ? this.token().type : "");
+  },
+
+  subtype: function() {
+    return ((this.token()) ? this.token().subtype : "");
+  }
+}
+
+
+Rico.Formula.f_dependencies = Class.create();
+Rico.Formula.f_dependencies.prototype = {
+  initialize: function() {
+    this.items = [];
+  },
+
+  add: function(cell) {
+    if (!this.items.include(cell)) this.items.push(cell);
+  },
+
+  remove: function(cell) {
+    this.items=this.items.select(function(item) { return (item != cell); });
+  },
+
+  find: function(cell) {
+    return this.items.detect(function(item) { return (item==cell); });
+  },
+
+  clear: function() {
+    this.items.clear();
+  }
+}
+
+
+Object.extend(Rico.Menu.prototype, {
+
+showSheetMenu: function(e,hideFunc) {
+  var elem=this.showSimpleMenu(e,hideFunc);
+  if (!this.grid) return;
+  var newIdx=this.grid.cellIndex(elem);
+  if (!this.grid.isSelected(newIdx.row,newIdx.column))
+    this.grid.selectCellRC(newIdx.row,newIdx.column,false);
+}
+
+});
+
+
+Rico.includeLoaded('ricoSheet.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.js b/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.js
new file mode 100644 (file)
index 0000000..a6b407e
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
+  *  (c) 2005-2007 Matt Brown (http://dowdybrown.com)
+  *
+  *  Rico is 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
+  **/
+
+
+if(typeof Rico=='undefined') throw("SimpleGrid requires the Rico JavaScript framework");
+if(typeof RicoUtil=='undefined') throw("SimpleGrid requires the RicoUtil Library");
+if(typeof RicoTranslate=='undefined') throw("SimpleGrid requires the RicoTranslate Library");
+
+Rico.SimpleGrid = Class.create();
+
+Rico.SimpleGrid.prototype = {
+
+  initialize: function( tableId, options ) {
+    Object.extend(this, new Rico.GridCommon);
+    this.baseInit(tableId);
+    Rico.setDebugArea(tableId+"_debugmsgs");    // if used, this should be a textarea
+    Object.extend(this.options, options || {});
+    this.tableId = tableId;
+    this.createDivs();
+    this.hdrTabs=new Array(2);
+    for (var i=0; i<2; i++) {
+      this.tabs[i]=$(tableId+'_tab'+i);
+      this.hdrTabs[i]=$(tableId+'_tab'+i+'h');
+      if (i==0) this.tabs[i].style.position='absolute';
+      if (i==0) this.tabs[i].style.left='0px';
+      this.hdrTabs[i].style.position='absolute';
+      this.hdrTabs[i].style.top='0px';
+      this.hdrTabs[i].style.zIndex=1;
+      this.thead[i]=this.hdrTabs[i];
+      this.tbody[i]=this.tabs[i];
+      this.headerColCnt = this.getColumnInfo(this.hdrTabs[i].rows);
+      if (i==0) this.options.frozenColumns=this.headerColCnt;
+    }
+    if (this.headerColCnt==0) {
+      alert('ERROR: no columns found in "'+this.tableId+'"');
+      return;
+    }
+    this.hdrHt=Math.max(RicoUtil.nan2zero(this.hdrTabs[0].offsetHeight),this.hdrTabs[1].offsetHeight);
+    for (var i=0; i<2; i++)
+      if (i==0) this.tabs[i].style.top=this.hdrHt+'px';
+    this.createColumnArray();
+    this.pageSize=this.columns[0].dataColDiv.childNodes.length;
+    this.sizeDivs();
+    this.attachMenuEvents();
+    this.scrollEventFunc=this.handleScroll.bindAsEventListener(this);
+    this.pluginScroll();
+    if (this.options.windowResize)
+      Event.observe(window,"resize", this.sizeDivs.bindAsEventListener(this), false);
+  },
+
+  /**
+   * Register a menu that will only be used in the scrolling part of the grid.
+   * If submenus are used, they must be registered after the main menu.
+   */
+  registerScrollMenu: function(menu) {
+    if (!this.menu) this.menu=menu;
+    menu.grid=this;
+    menu.showmenu=menu.showSimpleMenu;
+    menu.showSubMenu=menu.showSimpleSubMenu;
+    menu.createDiv(this.scrollDiv);
+  },
+  
+  handleMenuClick: function(e) {
+    this.cancelMenu();
+    this.menuCell=RicoUtil.getParentByTagName(Event.element(e),'div');
+    this.highlightEnabled=false;
+    if (this.hideScroll) this.scrollDiv.style.overflow="hidden";
+    if (this.menu.buildGridMenu) this.menu.buildGridMenu(this.menuCell);
+    this.menu.showmenu(e,this.closeMenu.bind(this));
+  },
+
+  closeMenu: function() {
+    if (this.hideScroll) this.scrollDiv.style.overflow="";
+    this.highlightEnabled=true;
+  },
+
+  sizeDivs: function() {
+    if (this.outerDiv.offsetParent.style.display=='none') return;
+    this.baseSizeDivs();
+    var maxHt=Math.max(this.options.maxHt || this.availHt(), 50);
+    var totHt=Math.min(this.hdrHt+this.dataHt, maxHt);
+    Rico.writeDebugMsg('sizeDivs '+this.tableId+': hdrHt='+this.hdrHt+' dataHt='+this.dataHt);
+    this.dataHt=totHt-this.hdrHt;
+    if (this.scrWi>0) this.dataHt+=this.options.scrollBarWidth;
+    this.scrollDiv.style.height=this.dataHt+'px';
+    var divAdjust=2;
+    this.innerDiv.style.width=(this.scrWi-this.options.scrollBarWidth+divAdjust)+'px';
+    this.innerDiv.style.height=this.hdrHt+'px';
+    totHt+=divAdjust;
+    this.resizeDiv.style.height=this.frozenTabs.style.height=totHt+'px';
+    this.outerDiv.style.height=(totHt+this.options.scrollBarWidth)+'px';
+    this.setHorizontalScroll();
+  }
+
+};
+
+if (Rico.Menu) {
+Object.extend(Rico.Menu.prototype, {
+
+showSimpleMenu: function(e,hideFunc) {
+  Event.stop(e);
+  this.hideFunc=hideFunc;
+  if (this.div.childNodes.length==0) {
+    this.cancelmenu();
+    return false;
+  }
+  this.clientX=Event.pointerX(e);
+  this.clientY=Event.pointerY(e);
+  var elem=Event.element(e);
+  while (elem && !Element.hasClassName(elem,'ricoLG_cell'))
+    elem=elem.parentNode;
+  if (!elem) return false;
+  var td=RicoUtil.getParentByTagName(elem,'td');
+
+  var newLeft=Math.floor(td.offsetLeft+td.offsetWidth/2);
+  if (this.direction == 'rtl') {
+    if (newLeft > this.width) newLeft-=this.width;
+  } else {
+    if (newLeft+this.width+this.options.margin > this.grid.scrollDiv.scrollLeft+this.grid.scrollDiv.clientWidth) newLeft-=this.width;
+  }
+  this.div.style.visibility="hidden";
+  this.div.style.display="block";
+  var contentHt=this.div.offsetHeight;
+  var newTop=Math.floor(elem.offsetTop+elem.offsetHeight/2);
+  if (newTop+contentHt+this.options.margin > this.grid.scrollDiv.scrollTop+this.grid.scrollDiv.clientHeight)
+    newTop=Math.max(newTop-contentHt,0);
+  this.openPopup(newLeft,newTop);
+  this.div.style.visibility ="visible";
+  return elem;
+},
+
+showSimpleSubMenu: function(a,submenu) {
+  if (this.openSubMenu) this.hideSubMenu();
+  this.openSubMenu=submenu;
+  this.openMenuAnchor=a;
+  if (a.className=='ricoSubMenu') a.className='ricoSubMenuOpen';
+  var top=parseInt(this.div.style.top);
+  var left=parseInt(this.div.style.left);
+  submenu.openPopup(left+a.offsetWidth,top+a.offsetTop);
+  submenu.div.style.visibility ="visible";
+}
+    
+});
+}
+
+Object.extend(Rico.TableColumn.prototype, {
+
+initialize: function(grid,colIdx,hdrInfo,tabIdx) {
+  this.baseInit(grid,colIdx,hdrInfo,tabIdx);
+}
+
+});
+
+Rico.includeLoaded('ricoSimpleGrid.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.xsl b/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid.xsl
new file mode 100644 (file)
index 0000000..e1bce43
--- /dev/null
@@ -0,0 +1,285 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet version="1.0"
+  xmlns:xhtml="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:xs="http://www.w3.org/2001/XMLSchema"
+  xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
+  xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes"
+exclude-result-prefixes="xhtml xsl fn xs xdt">
+
+<xsl:output
+omit-xml-declaration="yes"
+method="html"
+doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
+doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
+
+<xsl:attribute-set name="ricoTable"> 
+  <xsl:attribute name="cellspacing">0</xsl:attribute> 
+  <xsl:attribute name="cellpadding">0</xsl:attribute> 
+</xsl:attribute-set> 
+
+<!-- the identity template -->
+
+<xsl:template match="*">
+  <xsl:copy>
+  <xsl:copy-of select="@*"/>
+  <xsl:apply-templates/>
+  </xsl:copy>
+</xsl:template>
+
+
+<!-- Transform head section -->
+
+<xsl:template match="xhtml:head">
+  <xsl:copy>
+  <xsl:apply-templates mode="head"/>
+<script type="text/javascript">
+//<![CDATA[
+if (typeof ricoInit!='undefined') {
+  if (window.addEventListener)
+    window.addEventListener('load', ricoInit, false);
+  else if (window.attachEvent)
+    window.attachEvent('onload', ricoInit);
+}
+// ]]>
+</script>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="*[name()!='script']" mode="head">
+  <xsl:copy>
+  <xsl:copy-of select="@*|node()"/>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="xhtml:script" mode="head">
+  <xsl:copy>
+  <xsl:copy-of select="@*"/>
+  <xsl:value-of select="." disable-output-escaping="yes"/>
+  </xsl:copy>
+</xsl:template>
+
+
+<!-- Transform tables with class ricoSimpleGrid -->
+  
+<xsl:template match="xhtml:table[@class='ricoSimpleGrid']">
+<xsl:choose>
+
+<xsl:when test="xhtml:thead">
+<xsl:call-template name="processTable">
+<xsl:with-param name="id" select="@id"/>
+<xsl:with-param name="headRows" select="xhtml:thead/xhtml:tr"/>
+<xsl:with-param name="bodyRows" select="xhtml:tbody/xhtml:tr"/>
+</xsl:call-template>
+</xsl:when>
+
+<xsl:when test="xhtml:tbody">
+<xsl:call-template name="processTable">
+<xsl:with-param name="id" select="@id"/>
+<xsl:with-param name="headRows" select="xhtml:tbody/xhtml:tr[1]"/>
+<xsl:with-param name="bodyRows" select="xhtml:tbody/xhtml:tr[position() &gt; 1]"/>
+</xsl:call-template>
+</xsl:when>
+
+<xsl:otherwise>
+<xsl:call-template name="processTable">
+<xsl:with-param name="id" select="@id"/>
+<xsl:with-param name="headRows" select="xhtml:tr[1]"/>
+<xsl:with-param name="bodyRows" select="xhtml:tr[position() &gt; 1]"/>
+</xsl:call-template>
+</xsl:otherwise>
+
+</xsl:choose>
+</xsl:template>
+
+
+<!-- Perform the actual table transformation -->
+  
+<xsl:template name="processTable">
+<xsl:param name="id" />
+<xsl:param name="headRows" />
+<xsl:param name="bodyRows" />
+
+<xsl:variable name="headIdx">
+<xsl:choose>
+<xsl:when test="$headRows[@class='ricoHeading']">
+<xsl:value-of select="count($headRows[@class='ricoHeading']/preceding-sibling::*)+1"/>
+</xsl:when>
+<xsl:otherwise>
+<xsl:value-of select="count($headRows)"/>
+</xsl:otherwise>
+</xsl:choose>
+</xsl:variable>
+
+<xsl:variable name="headMain" select="$headRows[position()=$headIdx]"/>
+<xsl:variable name="headCols" select="$headMain/xhtml:th | $headMain/xhtml:td"/>
+
+<!--
+<p><xsl:value-of select="$id"/>
+<br />headRowCnt: <xsl:value-of select="count($headRows)"/>
+<br />headIdx: <xsl:value-of select="$headIdx"/>
+<br />bodyRowCnt: <xsl:value-of select="count($bodyRows)"/>
+</p>
+-->
+
+<xsl:element name="div">
+<xsl:attribute name="id"><xsl:value-of select="concat($id,'_outerDiv')"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_outerDiv</xsl:attribute>
+<xsl:attribute name="onload"></xsl:attribute>
+
+<!-- Create frozen (left) pane -->
+
+<xsl:element name="div">
+<xsl:attribute name="id"><xsl:value-of select="concat($id,'_frozenTabsDiv')"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_frozenTabsDiv</xsl:attribute>
+
+<xsl:call-template name="convertTHead">
+<xsl:with-param name="rows" select="$headRows"/>
+<xsl:with-param name="headIdx" select="$headIdx"/>
+<xsl:with-param name="frozen" select="1"/>
+<xsl:with-param name="id" select="concat($id,'_tab0h')"/>
+</xsl:call-template>
+
+<xsl:call-template name="convertTBody">
+<xsl:with-param name="rows" select="$bodyRows"/>
+<xsl:with-param name="cols" select="$headCols"/>
+<xsl:with-param name="id" select="concat($id,'_tab0')"/>
+<xsl:with-param name="frozen" select="1"/>
+</xsl:call-template>
+
+</xsl:element>
+
+<xsl:element name="div">
+<xsl:attribute name="id"><xsl:value-of select="concat($id,'_innerDiv')"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_innerDiv</xsl:attribute>
+
+<xsl:element name="div">
+<xsl:attribute name="id"><xsl:value-of select="concat($id,'_scrollTabsDiv')"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_scrollTabsDiv</xsl:attribute>
+
+<xsl:call-template name="convertTHead">
+<xsl:with-param name="rows" select="$headRows"/>
+<xsl:with-param name="headIdx" select="$headIdx"/>
+<xsl:with-param name="frozen" select="0"/>
+<xsl:with-param name="id" select="concat($id,'_tab1h')"/>
+</xsl:call-template>
+
+</xsl:element>
+</xsl:element>
+
+<xsl:element name="div">
+<xsl:attribute name="id"><xsl:value-of select="concat($id,'_scrollDiv')"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_scrollDiv</xsl:attribute>
+
+<xsl:call-template name="convertTBody">
+<xsl:with-param name="rows" select="$bodyRows"/>
+<xsl:with-param name="cols" select="$headCols"/>
+<xsl:with-param name="id" select="concat($id,'_tab1')"/>
+<xsl:with-param name="frozen" select="0"/>
+</xsl:call-template>
+</xsl:element>
+
+</xsl:element>
+
+</xsl:template>
+
+
+<!-- Convert thead section -->
+
+<xsl:template name="convertTHead">
+<xsl:param name = "rows" />
+<xsl:param name = "headIdx" />
+<xsl:param name = "frozen" />
+<xsl:param name = "id" />
+<xsl:element name="table" use-attribute-sets="ricoTable">
+<xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_table ricoLG_top
+<xsl:if test="$frozen">ricoLG_left</xsl:if>
+<xsl:if test="not($frozen)">ricoLG_right</xsl:if>
+</xsl:attribute>
+<xsl:element name="thead">
+  <xsl:for-each select="$rows">
+    <xsl:choose>
+    <xsl:when test="position() = $headIdx">
+      <xsl:apply-templates select="." mode="convertHeadRow">
+      <xsl:with-param name="id" select="concat($id,'_main')"/>
+      <xsl:with-param name="frozen" select="$frozen"/>
+      </xsl:apply-templates>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-templates select="." mode="convertHeadRow">
+      <xsl:with-param name="id" select="concat($id,'_',position())"/>
+      <xsl:with-param name="frozen" select="$frozen"/>
+      </xsl:apply-templates>
+    </xsl:otherwise>
+    </xsl:choose>
+  </xsl:for-each>
+</xsl:element>
+<tbody />
+</xsl:element>
+</xsl:template>
+
+
+<xsl:template match="*" mode="convertHeadRow">
+<xsl:param name = "id" />
+<xsl:param name = "frozen" />
+  <xsl:variable name="class" select="@class"/>
+  <xsl:variable name="cells" select="xhtml:th | xhtml:td"/>
+  <xsl:element name="tr">
+  <xsl:if test="$id">
+    <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
+  </xsl:if>
+  <xsl:attribute name="class">ricoLG_hdg <xsl:value-of select="$class"/></xsl:attribute>
+  <xsl:for-each select="$cells[@class='ricoFrozen' and $frozen or not(@class='ricoFrozen') and not($frozen)]">
+      <xsl:copy>
+        <xsl:copy-of select="@*"/>
+        <div class='ricoLG_col' style='width:100px'>
+          <xsl:element name="div">
+          <xsl:attribute name="class">ricoLG_cell <xsl:value-of select="@class"/></xsl:attribute>
+            <xsl:copy-of select="* | @*[name()!='class'] | text()"/>
+          </xsl:element>
+        </div>
+      </xsl:copy>
+    </xsl:for-each>
+  </xsl:element>
+</xsl:template>
+
+
+<!-- Convert tbody section -->
+
+<xsl:template name="convertTBody">
+<xsl:param name = "rows" />
+<xsl:param name = "cols" />
+<xsl:param name = "id" />
+<xsl:param name = "frozen" />
+<xsl:element name="table" use-attribute-sets="ricoTable">
+<xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
+<xsl:attribute name="class">ricoLG_table ricoLG_bottom
+<xsl:if test="$frozen">ricoLG_left</xsl:if>
+<xsl:if test="not($frozen)">ricoLG_right</xsl:if>
+</xsl:attribute> 
+<xsl:element name="tbody">
+  <tr>
+  <xsl:for-each select="$cols">
+    <xsl:if test="@class='ricoFrozen' and $frozen or not(@class='ricoFrozen') and not($frozen)">
+      <xsl:variable name="colpos" select="position()"/>
+      <td>
+        <div class='ricoLG_col' style='width:100px'>
+          <xsl:for-each select="$rows">
+            <xsl:element name="div">
+            <xsl:attribute name="class">ricoLG_cell <xsl:value-of select="xhtml:td[$colpos]/@class"/></xsl:attribute>
+              <xsl:copy-of select="xhtml:td[$colpos]/* | xhtml:td[$colpos]/@*[name()!='class'] | xhtml:td[$colpos]/text()"/>
+            </xsl:element>
+          </xsl:for-each>
+        </div>
+      </td>
+    </xsl:if>
+  </xsl:for-each>
+  </tr>
+</xsl:element>
+</xsl:element>
+</xsl:template>
+
+</xsl:stylesheet> 
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid2xl.xsl b/trunk/NP_TrackBack/trackback/js/rico/ricoSimpleGrid2xl.xsl
new file mode 100644 (file)
index 0000000..d827945
--- /dev/null
@@ -0,0 +1,160 @@
+<xsl:stylesheet version="1.0"
+  xmlns="urn:schemas-microsoft-com:office:spreadsheet"
+  xmlns:xhtml="http://www.w3.org/1999/xhtml"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+       xmlns:msxsl="urn:schemas-microsoft-com:xslt"
+       xmlns:o="urn:schemas-microsoft-com:office:office"
+       xmlns:x="urn:schemas-microsoft-com:office:excel"
+  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
+
+<xsl:output method="xml" indent="yes" omit-xml-declaration="no" media-type="application/xml"/>
+
+<xsl:template match="/">
+  <xsl:processing-instruction name="mso-application">
+  <xsl:text>progid="Excel.Sheet"</xsl:text> 
+  </xsl:processing-instruction>
+
+  <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
+   xmlns:o="urn:schemas-microsoft-com:office:office"
+   xmlns:x="urn:schemas-microsoft-com:office:excel"
+   xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
+   xmlns:html="http://www.w3.org/TR/REC-html40">
+
+ <Styles>
+  <Style ss:ID="Default" ss:Name="Normal">
+   <Alignment ss:Vertical="Bottom"/>
+   <Borders/>
+   <Font/>
+   <Interior/>
+   <NumberFormat/>
+   <Protection/>
+  </Style>
+  <Style ss:ID="s21">
+   <Font ss:Bold="1"/>
+   <Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
+  </Style>
+  <Style ss:ID="s22">
+   <Alignment ss:Horizontal="Left" ss:Vertical="Bottom"/>
+   <Font ss:Bold="1"/>
+   <Interior ss:Color="#99CCFF" ss:Pattern="Solid"/>
+  </Style>
+  <Style ss:ID="s23" ss:Name="Currency">
+   <NumberFormat
+    ss:Format="_(&quot;$&quot;* #,##0.00_);_(&quot;$&quot;* \(#,##0.00\);_(&quot;$&quot;* &quot;-&quot;??_);_(@_)"/>
+  </Style>
+  <Style ss:ID="s24">
+   <NumberFormat ss:Format="_(* #,##0.00_);_(* \(#,##0.00\);_(* &quot;-&quot;??_);_(@_)"/>
+  </Style>
+  <Style ss:ID="s25">
+   <Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
+  </Style>
+ </Styles>
+
+  <xsl:apply-templates mode="top"/> 
+
+  </Workbook>
+</xsl:template>
+
+
+<xsl:template match="*" mode="top">
+  <xsl:choose>
+
+  <xsl:when test="xhtml:table[@class='ricoSimpleGrid']">
+  <xsl:apply-templates mode="grid"/> 
+  </xsl:when>
+
+  <xsl:otherwise>
+  <xsl:apply-templates select="*" mode="top"/> 
+  </xsl:otherwise>
+  
+  </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="*" mode="grid">
+
+  <xsl:choose>
+  
+  <xsl:when test="xhtml:thead">
+  <xsl:call-template name="processTable">
+  <xsl:with-param name="id" select="@id"/>
+  <xsl:with-param name="headRows" select="xhtml:thead/xhtml:tr"/>
+  <xsl:with-param name="bodyRows" select="xhtml:tbody/xhtml:tr"/>
+  </xsl:call-template>
+  </xsl:when>
+  
+  <xsl:when test="xhtml:tbody">
+  <xsl:call-template name="processTable">
+  <xsl:with-param name="id" select="@id"/>
+  <xsl:with-param name="headRows" select="xhtml:tbody/xhtml:tr[1]"/>
+  <xsl:with-param name="bodyRows" select="xhtml:tbody/xhtml:tr[position() &gt; 1]"/>
+  </xsl:call-template>
+  </xsl:when>
+  
+  <xsl:otherwise>
+  <xsl:call-template name="processTable">
+  <xsl:with-param name="id" select="@id"/>
+  <xsl:with-param name="headRows" select="xhtml:tr[1]"/>
+  <xsl:with-param name="bodyRows" select="xhtml:tr[position() &gt; 1]"/>
+  </xsl:call-template>
+  </xsl:otherwise>
+  
+  </xsl:choose>
+
+</xsl:template>
+
+
+<!-- Perform the actual table transformation -->
+  
+<xsl:template name="processTable">
+<xsl:param name="id" />
+<xsl:param name="headRows" />
+<xsl:param name="bodyRows" />
+
+ <Worksheet>
+ <xsl:attribute name="ss:Name">
+   <xsl:value-of select='$id'/>
+ </xsl:attribute>
+  <Table>
+
+  <xsl:apply-templates select="$headRows" mode="convertHeadRow"/>
+  <xsl:apply-templates select="$bodyRows" mode="convertBodyRow"/>
+
+  </Table>
+ </Worksheet>
+
+</xsl:template>
+
+
+<xsl:template match="*" mode="convertHeadRow">
+   <Row>
+    <xsl:apply-templates select="xhtml:td | xhtml:th" mode="convertHeadCell"/>
+   </Row>
+</xsl:template>
+
+
+<xsl:template match="*" mode="convertHeadCell">
+  <xsl:element name="Cell">
+  <xsl:attribute name="ss:StyleID">s22</xsl:attribute>
+  <xsl:if test="@colspan">
+  <xsl:attribute name="ss:MergeAcross"><xsl:value-of select="number(@colspan)-1"/></xsl:attribute>
+  </xsl:if>
+    <Data ss:Type="String">
+    <xsl:value-of select="."/>
+    </Data>
+  </xsl:element>
+</xsl:template>
+
+
+<xsl:template match="*" mode="convertBodyRow">
+   <Row>
+    <xsl:apply-templates select="xhtml:td | xhtml:th" mode="convertBodyCell"/>
+   </Row>
+</xsl:template>
+
+
+<xsl:template match="*" mode="convertBodyCell">
+    <Cell><Data ss:Type="String"><xsl:value-of select="."/></Data></Cell>
+</xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoStyles.js b/trunk/NP_TrackBack/trackback/js/rico/ricoStyles.js
new file mode 100644 (file)
index 0000000..34af1aa
--- /dev/null
@@ -0,0 +1,469 @@
+/**
+  *
+  *  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.
+  **/
+
+//-------------------- 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.length==4) {
+    var shortHexCode = hexCode; 
+    var hexCode = '#';
+    for(var i=1;i<4;i++)
+      hexCode += (shortHexCode.charAt(i) + shortHexCode.charAt(i));
+  }
+  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 = Element.getStyle(elem, "background-color");
+
+   // if color is tranparent, check parent
+   // Safari returns "rgba(0, 0, 0, 0)", which means transparent
+   if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
+      return Rico.Color.createColorFromBackground(elem.parentNode);
+
+   if ( actualColor == null )
+      return new Rico.Color(255,255,255);
+
+   if ( actualColor.indexOf("rgb(") == 0 ) {
+      var colors = actualColor.substring(4, actualColor.length - 1 );
+      var colorArray = colors.split(",");
+      return new Rico.Color( parseInt( colorArray[0] ),
+                            parseInt( colorArray[1] ),
+                            parseInt( colorArray[2] )  );
+
+   }
+   else if ( actualColor.indexOf("#") == 0 ) {
+      return Rico.Color.createFromHex(actualColor);
+   }
+   else
+      return new Rico.Color(255,255,255);
+}
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+   var red   = 0;
+       var green = 0;
+       var blue  = 0;
+
+   if (saturation == 0) {
+      red = parseInt(brightness * 255.0 + 0.5);
+          green = red;
+          blue = red;
+       }
+       else {
+      var h = (hue - Math.floor(hue)) * 6.0;
+      var f = h - Math.floor(h);
+      var p = brightness * (1.0 - saturation);
+      var q = brightness * (1.0 - saturation * f);
+      var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+      switch (parseInt(h)) {
+         case 0:
+            red   = (brightness * 255.0 + 0.5);
+            green = (t * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 1:
+            red   = (q * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 2:
+            red   = (p * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (t * 255.0 + 0.5);
+            break;
+         case 3:
+            red   = (p * 255.0 + 0.5);
+            green = (q * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+         case 4:
+            red   = (t * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+          case 5:
+            red   = (brightness * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (q * 255.0 + 0.5);
+            break;
+           }
+       }
+
+   return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+}
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+   var hue;
+   var saturation;
+   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 == "fromElement" ? this._background(e) : this.options.color;
+      var bgColor = this.options.bgColor == "fromParent" ? this._background(e.parentNode) : this.options.bgColor;
+      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 = "<div " + style + ">" + el.innerHTML + "</div>"
+   },
+
+   _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 = '0px';
+      el.insertBefore(corner,el.firstChild);
+   },
+
+   _roundBottomCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+      el.style.paddingBottom = 0;
+      el.appendChild(corner);
+   },
+
+   _createCorner: function(bgColor) {
+      var corner = document.createElement("div");
+      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+      return corner;
+   },
+
+   _createCornerSlice: function(color,bgColor, n, position) {
+      var slice = document.createElement("span");
+
+      var inStyle = slice.style;
+      inStyle.backgroundColor = color;
+      inStyle.display  = "block";
+      inStyle.height   = "1px";
+      inStyle.overflow = "hidden";
+      inStyle.fontSize = "1px";
+
+      var borderColor = this._borderColor(color,bgColor);
+      if ( this.options.border && n == 0 ) {
+         inStyle.borderTopStyle    = "solid";
+         inStyle.borderTopWidth    = "1px";
+         inStyle.borderLeftWidth   = "0px";
+         inStyle.borderRightWidth  = "0px";
+         inStyle.borderBottomWidth = "0px";
+         inStyle.height            = "0px"; // assumes css compliant box model
+         inStyle.borderColor       = borderColor;
+      }
+      else if(borderColor) {
+         inStyle.borderColor = borderColor;
+         inStyle.borderStyle = "solid";
+         inStyle.borderWidth = "0px 1px";
+      }
+
+      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
+         inStyle.height = "2px";
+
+      this._setMargin(slice, n, position);
+      this._setBorder(slice, n, position);
+      return slice;
+   },
+
+   _setOptions: function(options) {
+      this.options = {
+         corners : "all",
+         color   : "fromElement",
+         bgColor : "fromParent",
+         blend   : true,
+         border  : false,
+         compact : false
+      }
+      Object.extend(this.options, options || {});
+
+      this.options.numSlices = this.options.compact ? 2 : 4;
+      if ( this._isTransparent() )
+         this.options.blend = false;
+   },
+
+   _whichSideTop: function() {
+      if ( this._hasString(this.options.corners, "all", "top") )
+         return "";
+
+      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
+         return "";
+
+      if (this.options.corners.indexOf("tl") >= 0)
+         return "left";
+      else if (this.options.corners.indexOf("tr") >= 0)
+          return "right";
+      return "";
+   },
+
+   _whichSideBottom: function() {
+      if ( this._hasString(this.options.corners, "all", "bottom") )
+         return "";
+
+      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
+         return "";
+
+      if(this.options.corners.indexOf("bl") >=0)
+         return "left";
+      else if(this.options.corners.indexOf("br")>=0)
+         return "right";
+      return "";
+   },
+
+   _borderColor : function(color,bgColor) {
+      if ( color == "transparent" )
+         return bgColor;
+      else if ( this.options.border )
+         return this.options.border;
+      else if ( this.options.blend )
+         return this._blend( bgColor, color );
+      else
+         return "";
+   },
+
+
+   _setMargin: function(el, n, corners) {
+      var marginSize = this._marginSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+      if ( whichSide == "left" ) {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
+      }
+      else {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+      }
+   },
+
+   _setBorder: function(el,n,corners) {
+      var borderSize = this._borderSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+      if ( whichSide == "left" ) {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
+      }
+      else {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+      }
+      if (this.options.border != false)
+        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+   },
+
+   _marginSize: function(n) {
+      if ( this._isTransparent() )
+         return 0;
+
+      var marginSizes          = [ 5, 3, 2, 1 ];
+      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
+      var compactMarginSizes   = [ 2, 1 ];
+      var smBlendedMarginSizes = [ 1, 0 ];
+
+      if ( this.options.compact && this.options.blend )
+         return smBlendedMarginSizes[n];
+      else if ( this.options.compact )
+         return compactMarginSizes[n];
+      else if ( this.options.blend )
+         return blendedMarginSizes[n];
+      else
+         return marginSizes[n];
+   },
+
+   _borderSize: function(n) {
+      var transparentBorderSizes = [ 5, 3, 2, 1 ];
+      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
+      var compactBorderSizes     = [ 1, 0 ];
+      var actualBorderSizes      = [ 0, 2, 0, 0 ];
+
+      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
+         return 1;
+      else if ( this.options.compact )
+         return compactBorderSizes[n];
+      else if ( this.options.blend )
+         return blendedBorderSizes[n];
+      else if ( this.options.border )
+         return actualBorderSizes[n];
+      else if ( this._isTransparent() )
+         return transparentBorderSizes[n];
+      return 0;
+   },
+
+   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[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; }
+}
+
+Rico.includeLoaded('ricoStyles.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/ricoTree.js b/trunk/NP_TrackBack/trackback/js/rico/ricoTree.js
new file mode 100644 (file)
index 0000000..1e05ffc
--- /dev/null
@@ -0,0 +1,318 @@
+//  Rico Tree Control
+//  by Matt Brown
+//  Oct 2006
+//  email: dowdybrown@yahoo.com
+
+//  Requires prototype.js and ricoCommon.js
+
+// each node in nodeIndex is an Array with 6+n positions
+//  node[0] is 0/1 when the node is closed/open
+//  node[1] is 0/1 when the folder is closed/open
+//  node[2] is 1 if the node is a leaf node
+//  node[3] is the node id
+//  node[4] is the node description
+//  node[5] is 1 when the node is selectable, 0 otherwise
+//  node[6]...node[6+n] are the child nodes
+
+Rico.TreeControl = Class.create();
+
+Rico.TreeControl.prototype = {
+
+  initialize: function(id,url,options) {
+    Object.extend(this, new Rico.Popup({ignoreClicks:true}));
+    Object.extend(this.options, {
+      nodeIdDisplay:'none',   // first, last, tooltip, or none
+      showCheckBox: false,
+      showFolders: false,
+      showPlusMinus: true,
+      defaultAction: this.nodeClick.bindAsEventListener(this),
+      height: '300px',
+      width: '300px',
+      leafIcon: Rico.imgDir+'doc.gif'
+    });
+    Object.extend(this.options, options || {});
+    this.img=[];
+    this.FirstChildNode=6;
+    this.nodeIndex={};
+    this.nodeCount=0;
+    this.foldersTree=0;
+    this.timeOutId=0;
+    this.id=id;
+    this.dataSource=url;
+    this.close=this.closePopup;
+  },
+
+  atLoad : function() {
+    var imgsrc = new Array("node.gif","nodelast.gif","folderopen.gif","folderclosed.gif");
+    for (i=0;i<imgsrc.length;i++) {
+      this.img[i] = new Image
+      this.img[i].src = Rico.imgDir+imgsrc[i]
+      //this.img[i].src = Rico.imgDir + imgsrc[i]
+    }
+    this.treeDiv=document.createElement("div");
+    this.treeDiv.id=this.id;
+    this.treeDiv.className='ricoTree';
+    this.treeDiv.style.height=this.options.height;
+    this.treeDiv.style.width=this.options.width;
+    this.container=document.createElement("div");
+    this.container.style.display="none"
+    this.container.className='ricoTreeContainer';
+    this.container.appendChild(this.treeDiv);
+    document.body.appendChild(this.container);
+    this.setDiv(this.container);
+    this.close();
+  },
+
+  // Building the data in the tree
+  open: function() {
+    this.openPopup();
+    if (this.nodeCount==0) this.loadXMLDoc();
+  },
+
+  loadXMLDoc: function(branchPin) {
+    var parms="id="+this.id;
+    if (branchPin) parms+="&Parent="+branchPin;
+    Rico.writeDebugMsg('Tree loadXMLDoc:\n'+parms+'\n'+this.dataSource);
+    new Ajax.Request(this.dataSource, {parameters:parms,method:'get',onComplete:this.processResponse.bind(this)});
+  },
+
+  processResponse: function(request) {
+    var response = request.responseXML.getElementsByTagName("ajax-response");
+    if (response == null || response.length != 1) return;
+    var rowsElement = response[0].getElementsByTagName('rows')[0];
+    var trs = rowsElement.getElementsByTagName("tr");
+    //alert('processResponse: '+trs.length);
+    for ( var i=0 ; i < trs.length; i++ ) {
+      var cells = trs[i].getElementsByTagName("td");
+      if (cells.length != 5) continue;
+      // cells[0]=parent node id
+      // cells[1]=node id
+      // cells[2]=description
+      // cells[3]=L/zero (leaf), C/non-zero (container)
+      // cells[4]= 0->not selectable, 1->selectable (use default action), otherwise the node is selectable and cells[4] contains the action
+      var content=[];
+      for (var j=0; j<cells.length; j++)
+        content[j]=this.getContent(cells[j]);
+        //content[j]=RicoUtil.getContentAsString(cells[j]);
+      var node=this.addNode(content[3],content[1],content[2],content[4]);
+      if (this.foldersTree==0) {
+        this.foldersTree = node;
+        node[0]=1;
+        node[1]=1;
+      } else {
+        var parentNode=this.nodeIndex[content[0]]
+        if (typeof parentNode=='undefined')
+          alert('ERROR!\nReceived invalid response from server - could not find parent in existing tree:\n'+content[0]);
+        else
+          parentNode.push(node);
+      }
+    }
+    if (this.nodeCount==1 && node[2])
+      this.loadXMLDoc(node[3]);
+    else
+      this.redrawTree();
+  },
+
+  getContent: function(cell) {
+    if (cell.innerHTML) return cell.innerHTML;
+    switch (cell.childNodes.length) {
+      case 0:  return "";
+      case 1:  return cell.firstChild.nodeValue;
+      default: return cell.childNodes[1].nodeValue;
+    }
+  },
+
+  // create new node
+  // NodeType is "C" or non-zero (container), or "L" or zero (leaf)
+  // id is the unique identifier for the node
+  // desc is the text displayed to the user
+  addNode: function(NodeType,id,desc,selectable) {
+    var arrayAux
+    //alert("addNode: " + desc + " (" + selectable + ")")
+    arrayAux = new Array
+    arrayAux[0] = 0
+    arrayAux[1] = 0
+    arrayAux[2] = (NodeType=='0' || NodeType.toUpperCase()=='L' ? 0 : 1)
+    arrayAux[3] = id
+    arrayAux[4] = desc
+    arrayAux[5] = parseInt(selectable);
+    this.nodeIndex[id]=arrayAux
+    this.nodeCount++;
+  
+    return arrayAux
+  },
+
+  RemoveAllChildren: function(obj) {
+       while (obj.hasChildNodes()) {
+               this.RemoveAllChildren(obj.childNodes[0])
+               obj.removeChild(obj.childNodes[0])
+       }
+  },
+
+  redrawTree: function() {
+    //alert('redrawTree');
+    this.RemoveAllChildren(this.treeDiv)
+    this.redrawNode(this.foldersTree, 0, 1, [])
+  },
+
+  DisplayImages: function(row,arNames) {
+    var i,img,td
+    for(i=0;i<arNames.length;i++) {
+      img = document.createElement("img")
+      img.src=Rico.imgDir+arNames[i] + ".gif"
+      td=row.insertCell(-1)
+      td.appendChild(img)
+    }
+  },
+
+  redrawNode: function(foldersNode, level, lastNode, leftSide) {
+    var tab,row
+    //alert("redrawNode at level " + level + " (" + foldersNode[3] + ")")
+    
+    tab = document.createElement("table")
+    tab.border=0
+    tab.cellSpacing=0
+    tab.cellPadding=0
+    row=tab.insertRow(0)
+    this.DisplayImages(row,leftSide)
+    var newLeft=leftSide.slice(0);
+    if (level>0) {
+      var suffix=lastNode ? 'last' : '';
+      if (this.options.showPlusMinus && foldersNode[2])
+        this.showPlusMinus(row.insertCell(-1),foldersNode,suffix);
+      else
+        this.NodeImage(row.insertCell(-1),suffix)
+      newLeft.push(lastNode ? "nodeblank" : "nodeline")
+    }
+    if (this.options.showFolders)
+      this.showFolders(row.insertCell(-1),foldersNode);
+    if (this.options.showCheckBox && foldersNode[5])
+      this.showCheckBox(row.insertCell(-1),foldersNode);
+    this.displayLabel(row,foldersNode)
+    this.treeDiv.appendChild(tab)
+  
+    if (foldersNode.length > this.FirstChildNode && foldersNode[0]) {
+      //there are sub-nodes and the folder is open
+      for (var i=this.FirstChildNode; i<foldersNode.length;i++)
+        this.redrawNode(foldersNode[i], level+1, (i==foldersNode.length-1 ? 1 : 0), newLeft)
+    }
+  },
+
+  NodeImage: function(td, suffix) {
+    var img
+    img = document.createElement("img")
+    img.src=Rico.imgDir+"node"+suffix+".gif"
+    td.appendChild(img)
+  },
+
+
+  showPlusMinus: function(td,foldersNode,suffix) {
+    var img = document.createElement("img")
+    img.name=foldersNode[3];
+    img.style.cursor='pointer';
+    if (foldersNode.length > this.FirstChildNode)
+      img.onclick=this.openBranch.bindAsEventListener(this);
+    else
+      img.onclick=this.getChildren.bindAsEventListener(this);
+    var prefix=foldersNode[1] ? "nodem" : "nodep"
+    img.src=Rico.imgDir+prefix+suffix+".gif";
+    td.appendChild(img)
+  },
+
+  showFolders: function(td,foldersNode) {
+    var img = document.createElement("img")
+    if (!foldersNode[2]) {
+      img.src=this.options.leafIcon;
+    } else {
+      img.name=foldersNode[3];
+      img.style.cursor='pointer';
+      if (foldersNode.length > this.FirstChildNode)
+        img.onclick=this.openBranch.bindAsEventListener(this);
+      else
+        img.onclick=this.getChildren.bindAsEventListener(this);
+      img.src=Rico.imgDir+(foldersNode[1] ? "folderopen.gif" : "folderclosed.gif");
+    }
+    td.appendChild(img)
+  },
+
+  showCheckBox: function(td,foldersNode) {
+    var inp=document.createElement("input")
+    inp.type="checkbox"
+    inp.name=foldersNode[3]
+    td.appendChild(inp)
+  },
+
+  displayLabel: function(row,foldersNode) {
+    if (foldersNode[5]) {
+      var span=document.createElement('a');
+      span.href='#';
+      span.onclick=this.options.defaultAction;
+    } else {
+      var span=document.createElement('p');
+    }
+    span.id=this.id+"__"+foldersNode[3];
+    var desc=foldersNode[4];
+    switch (this.options.nodeIdDisplay) {
+      case 'last': desc+=' ('+foldersNode[3]+')'; break;
+      case 'first': desc=foldersNode[3]+' - '+desc; break;
+      case 'tooltip': span.title=foldersNode[3]; break;
+    }
+       span.appendChild(document.createTextNode(desc))
+    var td=row.insertCell(-1)
+    td.appendChild(span)
+  },
+
+  //when a parent is closed all children also are
+  closeFolders: function(foldersNode) {
+    var i=0
+    if (foldersNode[2]) {
+      for (i=this.FirstChildNode; i< foldersNode.length; i++)
+        this.closeFolders(foldersNode[i])
+    }
+    foldersNode[0] = 0
+    foldersNode[1] = 0
+  },
+  
+  nodeClick: function(e) {
+    var node=Event.element(e);
+    if (this.returnValue) {
+      var v=node.id;
+      var i=v.indexOf('__');
+      if (i>=0) v=v.substr(i+2);
+      this.returnValue(v,node.innerHTML);
+    }
+    this.close();
+  },
+
+  //recurse over the tree structure
+  //called by openbranch
+  clickOnFolderRec: function(foldersNode, folderName) {
+    var i=0
+    if (foldersNode[3] == folderName) {
+      if (foldersNode[0]) {
+        this.closeFolders(foldersNode)
+      } else {
+        foldersNode[0] = 1
+        foldersNode[1] = 1
+      }
+    } else if (foldersNode[2]) {
+      for (i=this.FirstChildNode; i< foldersNode.length; i++)
+        this.clickOnFolderRec(foldersNode[i], folderName)
+    }
+  },
+
+  openBranch: function(e) {
+    var node=Event.element(e);
+    this.clickOnFolderRec(this.foldersTree, node.name)
+    this.timeOutId = setTimeout(this.redrawTree.bind(this),100)
+  },
+
+  getChildren: function(e) {
+    var node=Event.element(e);
+    this.loadXMLDoc(node.name)
+    this.openBranch(e)
+  }
+
+}
+
+Rico.includeLoaded('ricoTree.js');
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_de.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_de.js
new file mode 100644 (file)
index 0000000..3f14ded
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************
+ Page : livegrid_DE.js
+ Description : LiveGrid text for German menus
+ Translator: rainer@langheiter@.com
+ Version 0.1 - please send corrections to dowdybrown@yahoo.com
+******************************************************************/
+// 2007-02-09, made some improvements - debach@gmx.de
+
+RicoTranslate.addPhrase("Sort by","Sortiert nach")
+RicoTranslate.addPhrase("Filter by","Gefiltert nach")
+RicoTranslate.addPhrase("Hide","Verbergen")
+RicoTranslate.addPhrase("Show","Zeige")
+RicoTranslate.addPhrase("Show All","Alle zeigen")
+RicoTranslate.addPhrase("Ascending","Aufsteigend")
+RicoTranslate.addPhrase("Descending","Absteigend")
+
+RicoTranslate.addPhrase("Include only this value","Nur diesen Wert einbeziehen")
+RicoTranslate.addPhrase("Exclude this value","Diesen Wert ausschließen")
+RicoTranslate.addPhrase("Exclude this value also","Diesen Wert ebenfalls ausschließen")
+RicoTranslate.addPhrase("Greater than or equal to this value","Größer oder gleich diesem Wert")
+RicoTranslate.addPhrase("Less than or equal to this value","Kleiner oder gleich diesem wert")
+RicoTranslate.addPhrase("Contains keyword","Enthält Schlüsselwort")
+RicoTranslate.addPhrase("Change keyword","Schlüsselwort ändern ")
+RicoTranslate.addPhrase("Enter keyword to search for","Schlüsselwort eintragen, nach dem gesucht werden soll")
+RicoTranslate.addPhrase("use * as a wildcard","verwende * als Wildcard")
+RicoTranslate.addPhrase("Remove filter","Entferne Filter")
+
+RicoTranslate.addPhrase("Waiting for data","Warte auf Daten")
+RicoTranslate.addPhrase("Request for data timed out","Zeitüberschreitung")
+
+RicoTranslate.addPhrase("No matching records","Keine übereinstimmenden Einträge")
+RicoTranslate.addPhrase("Listing records","Zeige Einträge")
+RicoTranslate.addPhrase("of","von")
+RicoTranslate.addPhrase("of about","von ungefähr")
+
+RicoTranslate.monthNames=["Januar", "Februar", "März", "April", "Mai","Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
+RicoTranslate.dayNames=["Sonntag", "Montag","Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]
+
+RicoTranslate.thouSep="."
+RicoTranslate.decPoint=","
+RicoTranslate.dateFmt="dd.mm.yyyy"
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Druck")
+RicoTranslate.addPhrase("Export","Exportiert")
+RicoTranslate.addPhrase("Visible rows","Sichtbare Zeilen")
+RicoTranslate.addPhrase("All rows","Alle Zeilen")
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Lade")
+RicoTranslate.addPhrase("minutes before your session expires","Minuten, bevor Ihre Sitzung abläuft") // formal
+//RicoTranslate.addPhrase("minutes before your session expires","Minuten, bevor deine Sitzung abläuft") // informal
+//RicoTranslate.addPhrase("minutes before your session expires","Minuten, bevor die Sitzung abläuft") // indirect
+RicoTranslate.addPhrase("EXPIRED","ABGELAUFEN")
+RicoTranslate.addPhrase("Close","Schließen")
+RicoTranslate.addPhrase("Cancel","Abbrechen")
+RicoTranslate.addPhrase("Save","Speichere")
+RicoTranslate.addPhrase("Add","Erstelle")
+RicoTranslate.addPhrase("Edit","Bearbeite")
+RicoTranslate.addPhrase("Delete","Lösche")
+RicoTranslate.addPhrase("Are you sure you want to delete","Möchten Sie dies wirklich löschen:") // formal
+//RicoTranslate.addPhrase("Are you sure you want to delete","Möchtest du das wirklich löschen:") // informal
+//RicoTranslate.addPhrase("Are you sure you want to delete","Wirklich löschen:") // indirect
+RicoTranslate.addPhrase("record","Eintrag")
+RicoTranslate.addPhrase("this record","diesen Eintrag") // "dieser"?
+RicoTranslate.addPhrase("new record","neuen Eintrag") // "neuer"?
+RicoTranslate.addPhrase("Please enter","Bitte eingeben")
+RicoTranslate.addPhrase("a value for","einen Wert für")
+RicoTranslate.addPhrase("an integer value for","einen ganzzahligen Wert für")
+RicoTranslate.addPhrase("a positive integer value for","einen positiven ganzzahligen Wert für")
+RicoTranslate.addPhrase("The request returned an error","Die Anfrage ergab einen Fehler")
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Zeige Bestellungen für")
+RicoTranslate.addPhrase("Show order detail","Zeige Bestelldetails")
+RicoTranslate.addPhrase("order","Bestellung")
+RicoTranslate.addPhrase("this order","diese Bestellung")
+RicoTranslate.addPhrase("new order","neue Bestellung")
+
+// add your own here:
+
+RicoTranslate.addPhrase("Visible rows to web page","Sichtbare Zeilen auf eine Webseite")
+RicoTranslate.addPhrase("All rows to web page","Alle Zeilen auf eine Webseite")
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_es.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_es.js
new file mode 100644 (file)
index 0000000..104ed1a
--- /dev/null
@@ -0,0 +1,79 @@
+/*****************************************************************
+ Page : livegrid_es.js
+ Description : LiveGrid text for Spanish menus
+ Version 0.2 (by Marco Scarnatto)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","Ordenar por")
+RicoTranslate.addPhrase("Filter by","Filtrar por")
+RicoTranslate.addPhrase("Hide","Ocultar")
+RicoTranslate.addPhrase("Show","Mostrar")
+RicoTranslate.addPhrase("Show All","Mostrar todo")
+RicoTranslate.addPhrase("Ascending","Ascendente")
+RicoTranslate.addPhrase("Descending","Descendente")
+
+RicoTranslate.addPhrase("Include only this value","Incluir solo este valor")
+RicoTranslate.addPhrase("Exclude this value","Excluir este valor")
+RicoTranslate.addPhrase("Exclude this value also","Excluir este valor también")
+RicoTranslate.addPhrase("Greater than or equal to this value","Mayor o igual a este valor")
+RicoTranslate.addPhrase("Less than or equal to this value","Menor o igual a este valor")
+RicoTranslate.addPhrase("Contains keyword","Contiene el texto")
+RicoTranslate.addPhrase("Change keyword","Cambiar texto")
+RicoTranslate.addPhrase("Enter keyword to search for","Ingrese texto a buscar")
+RicoTranslate.addPhrase("use * as a wildcard","use * como un comodín")
+RicoTranslate.addPhrase("Remove filter","Quitar filtro")
+
+RicoTranslate.addPhrase("Waiting for data","Esperando datos")
+RicoTranslate.addPhrase("Request for data timed out","Tiempo excedido en recibir datos ")
+
+RicoTranslate.addPhrase("No matching records","No hay datos coincidentes")
+RicoTranslate.addPhrase("Listing records","Mostrando datos")
+RicoTranslate.addPhrase("of","de")
+RicoTranslate.addPhrase("of about","de alrededor de")
+
+RicoTranslate.thouSep=","
+RicoTranslate.decPoint="."
+RicoTranslate.dateFmt="dd/mm/yyyy"
+
+RicoTranslate.monthNames=['Enero','Febrero', 'Marzo', 'Abril', 'Mayo','Junio', 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre']
+RicoTranslate.dayNames=['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado']
+
+// added for Aug 2006 release
+
+RicoTranslate.addPhrase("Print","Imprimir")
+RicoTranslate.addPhrase("Export","Exportar")
+RicoTranslate.addPhrase("Visible rows","Filas visibles")
+RicoTranslate.addPhrase("All rows","Todas las filas")
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Cargar")
+RicoTranslate.addPhrase("minutes before your session expires","minutos antes de su sesión expiran")
+RicoTranslate.addPhrase("EXPIRED","EXPIRADO")
+RicoTranslate.addPhrase("Close","Cerrar")
+RicoTranslate.addPhrase("Cancel","Cancelar")
+RicoTranslate.addPhrase("Save","Guardar")
+RicoTranslate.addPhrase("Add","Añadir")
+RicoTranslate.addPhrase("Edit","Editar")
+RicoTranslate.addPhrase("Delete","Borrar")
+RicoTranslate.addPhrase("Are you sure you want to delete","¿Está seguro de que quiere borrar")
+RicoTranslate.addPhrase("record","expediente")
+RicoTranslate.addPhrase("this record","este expediente")
+RicoTranslate.addPhrase("new record","expediente nuevo")
+RicoTranslate.addPhrase("Please enter","Introduzca")
+RicoTranslate.addPhrase("a value for","un valor para")
+RicoTranslate.addPhrase("an integer value for","un valor del número entero para")
+RicoTranslate.addPhrase("a positive integer value for","un valor positivo del número entero para")
+RicoTranslate.addPhrase("The request returned an error","Un error ocurrió mientras que recibía datos")
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Mostrar las ordenes de")
+RicoTranslate.addPhrase("Show order detail","Mostrar detalle de la orden")
+RicoTranslate.addPhrase("order","la orden")
+RicoTranslate.addPhrase("this order","esta orden")
+RicoTranslate.addPhrase("new order","nueva orden")
+
+// add your own here:
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_fr.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_fr.js
new file mode 100644 (file)
index 0000000..a8e9e04
--- /dev/null
@@ -0,0 +1,79 @@
+/*****************************************************************
+ Page : livegrid_FR.js
+ Description : LiveGrid text for French menus
+ Version 0.3 (revisions by Pierre Grellet)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","Trier par")
+RicoTranslate.addPhrase("Filter by","Filtrer par")
+RicoTranslate.addPhrase("Hide","Masquer")
+RicoTranslate.addPhrase("Show","Afficher")
+RicoTranslate.addPhrase("Show All","Afficher tous")
+RicoTranslate.addPhrase("Ascending","Croissant")
+RicoTranslate.addPhrase("Descending","Décroissant")
+
+RicoTranslate.addPhrase("Include only this value","Inclure seulement cette valeur")
+RicoTranslate.addPhrase("Exclude this value","Exclure cette valeur aussi")
+RicoTranslate.addPhrase("Exclude this value also","Exclure cette valeur")
+RicoTranslate.addPhrase("Greater than or equal to this value","Supérieur ou égal à cette valeur")
+RicoTranslate.addPhrase("Less than or equal to this value","Inférieur ou égal à cette valeur")
+RicoTranslate.addPhrase("Contains keyword","Contenant le mot-clé")
+RicoTranslate.addPhrase("Change keyword","Changer le mot-clé")
+RicoTranslate.addPhrase("Enter keyword to search for","Écrivez le mot-clé à rechercher")
+RicoTranslate.addPhrase("use * as a wildcard","utiliser * comme caractère générique")
+RicoTranslate.addPhrase("Remove filter","Enlever le filtre")
+
+RicoTranslate.addPhrase("Waiting for data","En attente des données")
+RicoTranslate.addPhrase("Request for data timed out","La requête a atteint sa limite de temps ")
+
+RicoTranslate.addPhrase("No matching records","Aucun articles ne correspond")
+RicoTranslate.addPhrase("Listing records","Résultats")
+RicoTranslate.addPhrase("of","de")
+RicoTranslate.addPhrase("of about","sur un total d'environ")
+
+RicoTranslate.thouSep="'"
+RicoTranslate.decPoint="."
+RicoTranslate.dateFmt="dd.mm.yyyy"
+
+RicoTranslate.monthNames=['Janvier','Février', 'Mars', 'Avril', 'Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
+RicoTranslate.dayNames=['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi']
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Imprimer")
+RicoTranslate.addPhrase("Export","Exporter")
+RicoTranslate.addPhrase("Visible rows","Rangs visible")
+RicoTranslate.addPhrase("All rows","Tous les rangs")
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Chargement")
+RicoTranslate.addPhrase("minutes before your session expires","minutes avant votre session expire")
+RicoTranslate.addPhrase("EXPIRED","EXPIRÉ")
+RicoTranslate.addPhrase("Close","Fermer")
+RicoTranslate.addPhrase("Cancel","Annuler")
+RicoTranslate.addPhrase("Save","Sauvegarder")
+RicoTranslate.addPhrase("Add","Ajouter")
+RicoTranslate.addPhrase("Edit","Éditer")
+RicoTranslate.addPhrase("Delete","Supprimer")
+RicoTranslate.addPhrase("Are you sure you want to delete","Êtes-vous sûr de vouloir supprimer")
+RicoTranslate.addPhrase("record","enregistrement")
+RicoTranslate.addPhrase("this record","cet enregistrement")
+RicoTranslate.addPhrase("new record","nouvel enregistrement")
+RicoTranslate.addPhrase("Please enter","Veuillez saisir")
+RicoTranslate.addPhrase("a value for","une valeur pour")
+RicoTranslate.addPhrase("an integer value for","un nombre entier pour")
+RicoTranslate.addPhrase("a positive integer value for","un nombre positif pour")
+RicoTranslate.addPhrase("The request returned an error","La requête a renvoyé une erreur")
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Montrer les commandes pour")
+RicoTranslate.addPhrase("Show order detail","Montrer les détails de la commande")
+RicoTranslate.addPhrase("order","la commande")
+RicoTranslate.addPhrase("this order","cette commande")
+RicoTranslate.addPhrase("new order","nouvelle commande")
+
+// add your own here:
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_it.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_it.js
new file mode 100644 (file)
index 0000000..8a7154e
--- /dev/null
@@ -0,0 +1,80 @@
+/*****************************************************************
+ Page : livegrid_IT.js
+ Description : LiveGrid text for Italian menus
+ Version 0.1 (these are guesses based mostly on babelfish results)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","Ordina per")
+RicoTranslate.addPhrase("Filter by","Filtra per")
+RicoTranslate.addPhrase("Hide","Nascondi")
+RicoTranslate.addPhrase("Show","Mostra")
+RicoTranslate.addPhrase("Show All","Mostra Tutte")
+RicoTranslate.addPhrase("Ascending","Crescente")
+RicoTranslate.addPhrase("Descending","Decrescente")
+
+RicoTranslate.addPhrase("Include only this value","Ritieni soltanto questo valore")
+RicoTranslate.addPhrase("Exclude this value","Escludi questo valore")
+RicoTranslate.addPhrase("Exclude this value also","Escludi questo valore anche")
+RicoTranslate.addPhrase("Greater than or equal to this value","Superiore o uguale a questo valore")
+RicoTranslate.addPhrase("Less than or equal to this value","Inferiore o uguale a questo valore")
+RicoTranslate.addPhrase("Contains keyword","Contiene la parola chiave")
+RicoTranslate.addPhrase("Change keyword","Cambia la parola chiave")
+RicoTranslate.addPhrase("Enter keyword to search for","Entra la parola chiave da cercare")
+RicoTranslate.addPhrase("use * as a wildcard","usa * come \"jolly\"")
+RicoTranslate.addPhrase("Remove filter","Rimuovi filtro")
+
+RicoTranslate.addPhrase("Waiting for data","Attendere per i dati")
+RicoTranslate.addPhrase("Request for data timed out","La richiesta dei dati ha raggiunto il limite di tempo")
+
+RicoTranslate.addPhrase("No matching records","Nessun articoli corrispondenti")
+RicoTranslate.addPhrase("Listing records","Risultati")
+RicoTranslate.addPhrase("of","di")
+RicoTranslate.addPhrase("of about","di circa")
+
+RicoTranslate.monthNames=["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"]
+RicoTranslate.dayNames=["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"]
+
+RicoTranslate.thouSep="."
+RicoTranslate.decPoint=","
+RicoTranslate.dateFmt="dd/mm/yyyy"
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Caricamento")
+RicoTranslate.addPhrase("minutes before your session expires","minuti prima che la vostra sessione termini")
+RicoTranslate.addPhrase("EXPIRED","TERMINATA")
+RicoTranslate.addPhrase("Close","Chiudi")
+RicoTranslate.addPhrase("Cancel","Annulla")
+RicoTranslate.addPhrase("Save","Salva")
+RicoTranslate.addPhrase("Add","Aggiungi")
+RicoTranslate.addPhrase("Edit","Modifica")
+RicoTranslate.addPhrase("Delete","Cancella")
+RicoTranslate.addPhrase("Are you sure you want to delete","Siete sicuri che volete cancellare")
+RicoTranslate.addPhrase("record","registrazione")
+RicoTranslate.addPhrase("this record","qesta registrazione")
+RicoTranslate.addPhrase("new record","nuova registrazione")
+RicoTranslate.addPhrase("Please enter","Per favore inserire")
+RicoTranslate.addPhrase("a value for","un valore per")
+RicoTranslate.addPhrase("an integer value for","un numero intero per")
+RicoTranslate.addPhrase("a positive integer value for","un numero intero positivo per")
+RicoTranslate.addPhrase("The request returned an error","La richiesta ha generato un errore")
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Mostra gli ordini per")
+RicoTranslate.addPhrase("Show order detail","Mostra i dettagli dell'ordine")
+RicoTranslate.addPhrase("order","ordine")
+RicoTranslate.addPhrase("this order","questo ordine")
+RicoTranslate.addPhrase("new order","nuovo ordine")
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Stampa")
+RicoTranslate.addPhrase("Export","Esporta")
+RicoTranslate.addPhrase("Visible rows","Righe visibili")
+RicoTranslate.addPhrase("All rows","Tutte le righe")
+
+// add your own here:
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ja.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ja.js
new file mode 100644 (file)
index 0000000..7eff4c4
--- /dev/null
@@ -0,0 +1,49 @@
+/*****************************************************************
+ Page : livegrid_ja.js
+ Description : LiveGrid text for Japanese menus
+ Translator: hsur
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","ソート")
+RicoTranslate.addPhrase("Filter by","絞込み")
+RicoTranslate.addPhrase("Hide","隠す")
+RicoTranslate.addPhrase("Show","表示")
+RicoTranslate.addPhrase("Ascending","昇順")
+RicoTranslate.addPhrase("Descending","降順")
+
+RicoTranslate.addPhrase("Include only this value","この値を含む")
+RicoTranslate.addPhrase("Exclude this value","この値を除く")
+RicoTranslate.addPhrase("Greater than or equal to this value","これ以上の値")
+RicoTranslate.addPhrase("Less than or equal to this value","これ以下の値")
+RicoTranslate.addPhrase("Contains keyword","このキーワードを含む")
+RicoTranslate.addPhrase("Change keyword","キーワードを変更")
+RicoTranslate.addPhrase("Enter keyword to search for","キーワードを入力してください")
+RicoTranslate.addPhrase("use * as a wildcard","ワイルドカードとして*を使います")
+RicoTranslate.addPhrase("also","も")
+RicoTranslate.addPhrase("Remove filter","絞込みを削除")
+
+RicoTranslate.addPhrase("Waiting for data","データ取得中")
+RicoTranslate.addPhrase("Request for data timed out","タイムアウトしました")
+
+RicoTranslate.addPhrase("No matching records","一致するレコードはありません")
+RicoTranslate.addPhrase("Listing records","")
+RicoTranslate.addPhrase("of","of")
+RicoTranslate.addPhrase("of about","of about")
+
+RicoTranslate.monthNames=["1月", "2月", "3月", "4月", "5月","6月", "7月", "8月", "9月", "10月", "11月", "12月"]
+RicoTranslate.dayNames=["月","火", "水","木", "金", "土", "日"]
+
+RicoTranslate.thouSep="."
+RicoTranslate.decPoint=","
+RicoTranslate.dateFmt="yyyy/mm/dd"
+RicoTranslate.timeFmt="HH:nn:ss"
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","印刷")
+RicoTranslate.addPhrase("Export","抽出")
+RicoTranslate.addPhrase("Visible rows","Visible rows")
+RicoTranslate.addPhrase("All rows","全ての行")
+
+// add your own here:
+
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_pt.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_pt.js
new file mode 100644 (file)
index 0000000..f3ff27d
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************
+ Page : livegrid_pt.js (brazilian)
+ Description : LiveGrid text for Brazilian Portuguese menus
+ Version 0.1 (by Adriano Accorsi - adriano@token.com.br)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+RicoTranslate.addPhrase("Sort by","Ordenar por")
+RicoTranslate.addPhrase("Filter by","Filtrar por")
+RicoTranslate.addPhrase("Hide","Ocultar")
+RicoTranslate.addPhrase("Show","Exibir")
+RicoTranslate.addPhrase("Show All","Exibir tudo")
+RicoTranslate.addPhrase("Ascending","Ascendente")
+RicoTranslate.addPhrase("Descending","Descendente")
+RicoTranslate.addPhrase("Include only this value","Incluir apenas este valor")
+RicoTranslate.addPhrase("Exclude this value","Excluir este valor")
+RicoTranslate.addPhrase("Greater than or equal to this value","Maior ou igual a este valor")
+RicoTranslate.addPhrase("Less than or equal to this value","Menor ou igual a este valor")
+RicoTranslate.addPhrase("Contains keyword","Contém texto")
+RicoTranslate.addPhrase("Change keyword","Alterar texto")
+RicoTranslate.addPhrase("Enter keyword to search for","Informe texto a ser pesquisado")
+RicoTranslate.addPhrase("use * as a wildcard","use * como 'coringa'")
+RicoTranslate.addPhrase("also","também")
+RicoTranslate.addPhrase("Remove filter","Remover filtro")
+RicoTranslate.addPhrase("Waiting for data","Aguardando dados")
+RicoTranslate.addPhrase("Request for data timed out","Tempo esgotado para espera de dados")
+RicoTranslate.addPhrase("No matching records","Nenhum registro encontrado.")
+RicoTranslate.addPhrase("Listing records","Listar registros")
+RicoTranslate.addPhrase("of","de")
+RicoTranslate.addPhrase("of about","de aproximadamente")
+RicoTranslate.thouSep="."
+RicoTranslate.decPoint=","
+RicoTranslate.dateFmt="dd/mm/yyyy"
+RicoTranslate.monthNames=["Janeiro", "Fevereiro", "Março", "Abril", "Maio","Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"]
+RicoTranslate.dayNames=["Domingo", "Segunda","Terça", "Quarta", "Quinta", "Sexta", "Sábado"]
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Imprimir")
+RicoTranslate.addPhrase("Export","Exportar")
+RicoTranslate.addPhrase("Visible rows","Fileiras visíveis")
+RicoTranslate.addPhrase("All rows","Todas as fileiras")
+
+// for demo only:
+RicoTranslate.addPhrase("Show orders for","Exibir pedidos de")
+RicoTranslate.addPhrase("Show order detail","Exibir detalhes do pedido")
+// add your own here:
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ru.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ru.js
new file mode 100644 (file)
index 0000000..4a265d4
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************
+ Page : livegrid_ru.js
+ Description : LiveGrid text for Russian menus
+ Version 0.2 (by Illiya Gannitskiy,Alexey Uvarov)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","Ñîðòèðîâêà ïî")
+RicoTranslate.addPhrase("Filter by","Ôèëüòðàöèÿ ïî")
+RicoTranslate.addPhrase("Hide","Ñïðÿòàòü")
+RicoTranslate.addPhrase("Show","Ïîêàçàòü")
+RicoTranslate.addPhrase("Show All","Ïîêàçàòü âñå")
+RicoTranslate.addPhrase("Ascending","Âîçðàñòàþùàÿ")
+RicoTranslate.addPhrase("Descending","Óáûâàþùàÿ")
+
+RicoTranslate.addPhrase("Include only this value","Âêëþ÷èòü òîëüêî ýòî çíà÷åíèå")
+RicoTranslate.addPhrase("Exclude this value","Èñêëþ÷èòü ýòî çíà÷åíèå")
+RicoTranslate.addPhrase("Greater than or equal to this value","Áîëüøå èëè ðàâíî äàííîìó çíà÷åíèþ")
+RicoTranslate.addPhrase("Less than or equal to this value","Ìåíüøå èëè ðàâíî äàííîìó çíà÷åíèþ")
+RicoTranslate.addPhrase("Contains keyword","Ñîäåðæèò çíà÷åíèå")
+RicoTranslate.addPhrase("Change keyword","Èçìåíèòü çíà÷åíèå")
+RicoTranslate.addPhrase("Enter keyword to search for","Èñêàòü ïî êëþ÷ó")
+RicoTranslate.addPhrase("use * as a wildcard","Èñïîëüçîâàòü * äëÿ âñåõ çàïèñåé")
+RicoTranslate.addPhrase("also","òàêæå")
+RicoTranslate.addPhrase("Remove filter","Óáðàòü ôèëüòð")
+
+RicoTranslate.addPhrase("Waiting for data","Îæèäàíèå äàííûõ")
+RicoTranslate.addPhrase("Request for data timed out","Ïðåâûøåí èíòåðâàë îæèäàíèÿ äàííûõ")
+
+RicoTranslate.addPhrase("No matching records","Íåò ñîâïàäåíèé")
+RicoTranslate.addPhrase("Listing records","Ïðîñìîòð çàïèñåé")
+RicoTranslate.addPhrase("of","èç")
+RicoTranslate.addPhrase("of about","èç î")
+
+RicoTranslate.thouSep=","
+RicoTranslate.decPoint="."
+RicoTranslate.dateFmt="dd/mm/yyyy"
+
+RicoTranslate.monthNames=['ßíâàðü','Ôåâðàëü', 'Ìàðò', 'Àïðåëü', 'Ìàé','Èþíü', 'Èþëü','Àâãóñò','Ñåíòÿáðü','Îòêòÿáðü','Íîÿáðü','Äåêàáðü']
+RicoTranslate.dayNames=['Ïîíåäåëüíèê','Âòîðíèê','Ñðåäà','×åòâåðã','Ïÿòíèöà','Ñóááîòà','Âîñêðåñåíüå']
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Ïå÷àòü")
+RicoTranslate.addPhrase("Export","Ýêñïîðò")
+RicoTranslate.addPhrase("Visible rows","Âèäèìûå çàïèñè")
+RicoTranslate.addPhrase("All rows","Âñå çàïèñè")
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Çàãðóçêà")
+RicoTranslate.addPhrase("minutes before your session expires","ìèíóò äî èñòå÷åíèÿ ñåññèè")
+RicoTranslate.addPhrase("EXPIRED","ÈÑÒÅÊËÎ")
+RicoTranslate.addPhrase("Close","Çàêðûòî")
+RicoTranslate.addPhrase("Cancel","Îòìåíà")
+RicoTranslate.addPhrase("Save","Ñîõðàíèòü")
+RicoTranslate.addPhrase("Add","Äîáàâèòü")
+RicoTranslate.addPhrase("Edit","Ðåäàêòèðîâàòü")
+RicoTranslate.addPhrase("Delete","Óäàëèòü")
+RicoTranslate.addPhrase("Are you sure you want to delete","Âû óâåðåííû,÷òî õîòèòå óäàëèòü")
+RicoTranslate.addPhrase("record","çàïèñü")
+RicoTranslate.addPhrase("this record","ýòà çàïèñü")
+RicoTranslate.addPhrase("new record","íîâàÿ çàïèñü")
+RicoTranslate.addPhrase("Please enter","Ïîæàëóéñòà ââåäèòå")
+RicoTranslate.addPhrase("a value for","çíà÷åíèå äëÿ")
+RicoTranslate.addPhrase("an integer value for","öåëîå çíà÷åíèå äëÿ")
+RicoTranslate.addPhrase("a positive integer value for","ïîëîæèòåëüíîå öåëîå çíà÷åíèå äëÿ")
+RicoTranslate.addPhrase("The request returned an error","Çàïðîñ âîçâðàòèë îøèáêó")
+
+
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Ïîêàçàòü çíà÷åíèÿ äëÿ")
+RicoTranslate.addPhrase("Show order detail","Ïîêàçàòü çíà÷åíèÿ ïîäðîáíî")
+RicoTranslate.addPhrase("order","çíà÷åíèå")
+RicoTranslate.addPhrase("this order","ýòî çíà÷åíèå")
+RicoTranslate.addPhrase("new order","íîâîå çíà÷åíèå")
+
+
+// add your own here:
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ua.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_ua.js
new file mode 100644 (file)
index 0000000..459d5ef
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************
+ Page : livegrid_ua.js
+ Description : LiveGrid text for Ukrainian menus
+ Version 0.1 (by Illiya Gannitskiy,Alexey Uvarov)
+ If you have better translations, or would like to include
+ translations for another language, please send them to dowdybrown@yahoo.com
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","Cîðòóâàííÿ ïî")
+RicoTranslate.addPhrase("Filter by","Ô³ëüòðàö³ÿ ïî")
+RicoTranslate.addPhrase("Hide","Ñõîâàòè")
+RicoTranslate.addPhrase("Show","Ïîêàçàòè")
+RicoTranslate.addPhrase("Show All","Ïîêàçàòè âñå")
+RicoTranslate.addPhrase("Ascending","Çðîñòàþ÷à")
+RicoTranslate.addPhrase("Descending","Óáóâàþ÷à")
+
+RicoTranslate.addPhrase("Include only this value","Âêëþ÷èòè ò³ëüêè öå çíà÷åííÿ")
+RicoTranslate.addPhrase("Exclude this value","Âèêëþ÷èòè öå çíà÷åííÿ")
+RicoTranslate.addPhrase("Greater than or equal to this value","Á³ëüøå àáî ð³âíî äàíîìó çíà÷åííþ")
+RicoTranslate.addPhrase("Less than or equal to this value","Ìåíøå àáî ð³âíî äàíîìó çíà÷åííþ")
+RicoTranslate.addPhrase("Contains keyword","̳ñòèòü çíà÷åííÿ")
+RicoTranslate.addPhrase("Change keyword","Çì³íèòè çíà÷åííÿ")
+RicoTranslate.addPhrase("Enter keyword to search for","Øóêàòè ïî êëþ÷ó")
+RicoTranslate.addPhrase("use * as a wildcard","Âèêîðèñòîâóâàòè * äëÿ âñ³õ çàïèñ³â")
+RicoTranslate.addPhrase("also","òàêîæ")
+RicoTranslate.addPhrase("Remove filter","Ïðèáðàòè ô³ëüòð")
+
+RicoTranslate.addPhrase("Waiting for data","Î÷³êóâàííÿ äàíèõ")
+RicoTranslate.addPhrase("Request for data timed out","Ïåðåâèùåíèé ³íòåðâàë î÷³êóâàííÿ äàíèõ")
+
+RicoTranslate.addPhrase("No matching records","Íåìຠçá³ã³â")
+RicoTranslate.addPhrase("Listing records","Ïåðåãëÿä çàïèñ³â")
+RicoTranslate.addPhrase("of","ç")
+RicoTranslate.addPhrase("of about","ç î")
+
+RicoTranslate.thouSep=","
+RicoTranslate.decPoint="."
+RicoTranslate.dateFmt="dd/mm/yyyy"
+
+RicoTranslate.monthNames=['ѳ÷åíü','Ëþòèé', 'Áåðåçåíü', 'Êâ³òåíü', 'Òðàâåíü','×åðâåíü', 'Ëèïåíü','Ñåðïåíü','Âåðåñåíü','Æîâòåíü','Ëèñòîïàä','Ãðóäåíü']
+RicoTranslate.dayNames=['Ïîíåä³ëîê','³âòîðîê','Ñåðåäà','×åòâåð','Ï'ÿòíèöÿ','Ñóáîòà','Íåä³ëÿ']
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","Äðóê")
+RicoTranslate.addPhrase("Export","Åêñïîðò")
+RicoTranslate.addPhrase("Visible rows","Âèäèì³ çàïèñè")
+RicoTranslate.addPhrase("All rows","Âñ³ çàïèñè")
+
+// added for Feb 2007 release
+
+RicoTranslate.addPhrase("Loading","Çàâàíòàæåííÿ")
+RicoTranslate.addPhrase("minutes before your session expires","õâèëèí äî çàê³í÷åííÿ ñåñ³¿")
+RicoTranslate.addPhrase("EXPIRED","ÇÀʲÍ×ÈËÎÑß")
+RicoTranslate.addPhrase("Close","Çàêðèòî")
+RicoTranslate.addPhrase("Cancel","³äì³íà")
+RicoTranslate.addPhrase("Save","Çáåðåãòè")
+RicoTranslate.addPhrase("Add","Äîäàòè")
+RicoTranslate.addPhrase("Edit","Ðåäàãóâàòè")
+RicoTranslate.addPhrase("Delete","Âèäàëèòè")
+RicoTranslate.addPhrase("Are you sure you want to delete","Âè óïåâíåí³,ùî áàæàºòå âèäàëèòè")
+RicoTranslate.addPhrase("record","çàïèñ")
+RicoTranslate.addPhrase("this record","öåé çàïèñ")
+RicoTranslate.addPhrase("new record","íîâèé çàïèñ")
+RicoTranslate.addPhrase("Please enter","Áóäü ëàñêà, ââåä³òü")
+RicoTranslate.addPhrase("a value for","çíà÷åííÿ äëÿ")
+RicoTranslate.addPhrase("an integer value for","ö³ëå çíà÷åííÿ äëÿ")
+RicoTranslate.addPhrase("a positive integer value for","ïîçèòèâíå ö³ëå çíà÷åííÿ äëÿ")
+RicoTranslate.addPhrase("The request returned an error","Çàïèò ïîâåðíóâ ïîìèëêó")
+
+
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","Ïîêàçàòè çíà÷åííÿ")
+RicoTranslate.addPhrase("Show order detail","Ïîêàçàòè çíà÷åííÿ äåòàëüíî")
+RicoTranslate.addPhrase("order","Çíà÷åííÿ")
+RicoTranslate.addPhrase("this order","öå çíà÷åííÿ")
+RicoTranslate.addPhrase("new order","íîâå çíà÷åííÿ")
+
+
+// add your own here:
diff --git a/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_zh.js b/trunk/NP_TrackBack/trackback/js/rico/translations/livegrid_zh.js
new file mode 100644 (file)
index 0000000..96b9a78
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************
+ Page : livegrid_zh.js
+ Description : LiveGrid text for CHINA menus
+ Translator: Sam Shan at gz_shanming@yahoo.com
+ Version 0.1 - please send corrections to dowdybrown@yahoo.com
+ Version 0.2 - Updated based on Xinjun liu's comments.
+******************************************************************/
+
+RicoTranslate.addPhrase("Sort by","排序")
+RicoTranslate.addPhrase("Filter by","过滤")
+RicoTranslate.addPhrase("Hide","隐藏")
+RicoTranslate.addPhrase("Show","显示")
+RicoTranslate.addPhrase("Ascending","升序")
+RicoTranslate.addPhrase("Descending","降序")
+
+RicoTranslate.addPhrase("Include only this value","只包含此值")
+RicoTranslate.addPhrase("Exclude this value","不包含此值")
+RicoTranslate.addPhrase("Greater than or equal to this value","大于等于")
+RicoTranslate.addPhrase("Less than or equal to this value","小于等于")
+RicoTranslate.addPhrase("Contains keyword","包含关键字")
+RicoTranslate.addPhrase("Change keyword","更改关键字")
+RicoTranslate.addPhrase("Enter keyword to search for","输入关键字")
+RicoTranslate.addPhrase("use * as a wildcard","使用*通配符")
+RicoTranslate.addPhrase("also","也")
+RicoTranslate.addPhrase("Remove filter","移除过滤器")
+
+RicoTranslate.addPhrase("Waiting for data","等待接收数据")
+RicoTranslate.addPhrase("Request for data timed out","等待数据超时")
+
+RicoTranslate.addPhrase("No matching records","没有匹配的数据")
+RicoTranslate.addPhrase("Listing records","列出纪录")
+RicoTranslate.addPhrase("of","共")
+RicoTranslate.addPhrase("of about","大约")
+
+RicoTranslate.monthNames=["一月", "二月", "三月", "四月", "五月","六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]
+RicoTranslate.dayNames=["星期日","星期一", "星期二","星期三", "星期四", "星期五", "星期六"]
+
+RicoTranslate.thouSep="."
+RicoTranslate.decPoint=","
+RicoTranslate.dateFmt="yyyy/mm/dd"
+
+// added for 22 August release
+
+RicoTranslate.addPhrase("Print","打印")
+RicoTranslate.addPhrase("Export","输出")
+RicoTranslate.addPhrase("Visible rows","当前显示记录")
+RicoTranslate.addPhrase("All rows","所有记录")
+
+// for demo only:
+
+RicoTranslate.addPhrase("Show orders for","显示订单")
+RicoTranslate.addPhrase("Show order detail","显示订单详情")
+
+// add your own here:
+
index 452c2b1..cb19843 100644 (file)
        All trackbacks
 </h2>
 
-<div id="showingLabel">Showing 1 - 5 of <?php echo $count ; ?></div>
+<div id="message" style="color: red;"></div>
 
-<div style="width: 100%">
-<div id="viewPort" style="float:left; width: 420px">
-<table id="tb_grid" style="border:0; margin:0; width: 400px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
+With selected: 
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
+<a href="#" onclick="javascript: doBlock()"><img alt="Block" border="0" src="<?php echo $plugindirurl?>silk/delete.png" /></a>
 </div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = "Showing " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + " of " + liveGrid.metaData.getTotalRows();
-    }
-
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width  + 'px';
-       $('tb_grid').style.width =  ( width - 40 ) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=all','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=all',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=doblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
index af73395..394a603 100644 (file)
 </h2>
 
 <ul>
-       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_clear&next=blocked'),ENT_QUOTES); ?>">ç¹\9dæ\82¶Î\9fç¹\9d�繧ッ縺è¼\94ï½\8c縺æº\98ã\83¨ç¹\9dゥç¹\9d�繧ッç¹\9dè\88\8cã\83£ç¹§ï½¯ç¸ºï½®ç¹§ï½¯ç¹\9dェ繧「</a></li>
-       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_spamclear&next=blocked'),ENT_QUOTES); ?>">spamè\9b»ï½¤è\9e³å£¹ï¼\86繧å¾\8câ\97\86ç¹\9då\8c»Î\9bç¹\9d�繧ッç¹\9dè\88\8cã\83£ç¹§ï½¯ç¸ºï½®ç¹§ï½¯ç¹\9dェ繧「</a></li> 
+       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_clear&next=blocked'),ENT_QUOTES); ?>">ã\83\96ã\83­ã\83\83ã\82¯ã\81\95ã\82\8cã\81\9fã\83\88ã\83©ã\83\83ã\82¯ã\83\90ã\83\83ã\82¯ã\81®ã\82¯ã\83ªã\82¢</a></li>
+       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_spamclear&next=blocked'),ENT_QUOTES); ?>">spamå\88¤å®\9aã\81\95ã\82\8cã\81\9fã\83\88ã\83©ã\83\83ã\82¯ã\83\90ã\83\83ã\82¯ã\81®ã\82¯ã\83ªã\82¢</a></li> 
 </ul>
 
-<div id="showingLabel">Showing 1 - 5 of <?php echo $count ; ?></div>
+<div id="message" style="color: red;"></div>
 
-<div style="float:left; width: 100%">
-<div id="viewPort" style="float:left; width: 620px">
-<table id="tb_grid" style="border:0; margin:0; width: 600px">
+<div style="width: 95%">
+<span id="tb_grid_bookmark"></span>
+
+<table id="tb_grid" style="border:0; margin:0;">
+       <colgroup>
+               <col style="width:25px;" />
+               <col style="width:40px;" />
+               <col style="width:70px;" />
+               <col style="width:150px;" />
+               <col style="width:200px;"/>
+               <col style="width:25px;" />
+       </colgroup>
        <thead>
                <tr>
-                       <th style="width:80px">Date</th>
-                       <th style="width:120px">Story</th>
-                       <th >Title, Blog and Excerpt</th>
-                       <th style="width:20px">&#160;</th>
-                       <th style="width:20px">&#160;</th>
+                       <th>&#160;</th>
+                       <th>id</th>
+                       <th>Date</th>
+                       <th>Story</th>
+                       <th>Title, Blog and Excerpt</th>
+                       <th>&#160;</th>
                </tr>
        </thead>
-       <tbody>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-               <tr style="height:110px"  onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
-                       <td style="width:80px">&#160;</td>
-                       <td style="width:120px">&#160;</td>
-                       <td >&#160;</td>
-                       <td style="width:20px">&#160;</td>
-                       <td style="width:20px">&#160;</td>
-               </tr>
-       </tbody>
 </table>
+With selected: 
+<a href="#" onclick="javascript: doUnblock()"><img alt="Unblock" border="0" src="<?php echo $plugindirurl;?>silk/accept.png" /></a>
+<a href="#" onclick="javascript: doDelete()"><img alt="Delete" border="0" src="<?php echo $plugindirurl?>silk/cross.png" /></a>
 </div>
-</div>
-<div style="clear:both"></div>
 
-<script>
-//<![CDATA[
-    function updateHeader( liveGrid, offset ) {
-       $('showingLabel').innerHTML = "Showing " + (offset+1) + " - " + (offset+liveGrid.metaData.getPageSize()) + " of " + liveGrid.metaData.getTotalRows();
-    }
-
-    function loadGrid() {
-       var width = $('content').offsetWidth
-       $('viewPort').style.width = width + 'px';
-       $('tb_grid').style.width = (width - 40) + 'px';
+<!--
+<textarea id='tb_grid_debugmsgs' rows='5' cols='80' style='font-size:smaller;'></textarea>
+-->
 
-       var max = <?php echo $count; ?>;
-       var params = ['action=ajax','type=blocked','ticket=' + '<?php echo $ticket ;?>']; 
-        var opts = { 
-               prefetchBuffer: true
-               ,prefetchOffset: 50
-               ,onscroll: updateHeader
-               ,requestParameters: params
-               ,sortAscendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_asc.gif'
-               ,sortDescendImg: '<?php echo $CONF['PluginURL'].'trackback/';?>images/sort_desc.gif'                   
-               ,columns: [ ["date", true], ["item", true], ["title", true], ["ban", false], ["del", false] ]
-       };
-        var liveGrid = new Rico.LiveGrid('tb_grid',5 , max, '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php', opts);
-    }
+<script type="text/javascript">
+//<![CDATA[
+       Rico.loadModule('LiveGridAjax');
+       Rico.loadModule('LiveGridMenu');
+       Rico.include('translations/livegrid_ja.js');
+       Rico.include('ricoAjaxEngine.js');
+       
+       Rico.onLoad( function() {
+               var params = [
+                       'action=ajax',
+                       'type=blocked',
+                       'ticket=<?php echo $ticket ;?>'
+               ]; 
+               
+               var cb = new Rico.TableColumn.checkbox('1','0');
+               var colspec = [
+                       {canHide:false, type:'control', control:cb, ClassName:'aligncenter'},
+                       {type:'raw'},
+                       {type:'raw'},
+                       ,
+                       ,
+                       ,
+               ];
+               
+               var opts = {
+                       saveColumnInfo   : {width:true, filter:false, sort:false}, 
+                       menuEvent       : 'none',
+                       frozenColumns   : 2,
+                       canSortDefault  : true,
+                       canHideDefault  : true,
+                       allowColResize  : true,
+                       canFilterDefault: false,
+                       highlightElem   : 'none',
+                       columnSpecs     : colspec
+               };
+               
+               buffer = new Rico.Buffer.AjaxSQL('<?php echo $CONF['PluginURL'].'trackback/';?>grid.php',
+                               {TimeOut:10, requestParameters:params, sortParmFmt: 'displayName'}
+               );
+               orderGrid=new Rico.LiveGrid ('tb_grid', buffer, opts);
+               orderGrid.menu=new Rico.GridMenu({});
+               
+               // ajaxEngine
+               ajaxEngine = new Rico.AjaxEngine;
+               ajaxEngine.registerRequest('updateData', '<?php echo $CONF['PluginURL'].'trackback/';?>grid.php' );
+               ajaxEngine.registerAjaxElement('message');
+       });
 
-    window.onload = loadGrid;
+       function checkUpdateIds(){
+               var updateIds = [];
+               Rico.writeDebugMsg('check updated rows');
+               for(var i = 0; i < buffer.size; i++){
+                       row = buffer.rows[i];
+                       if( row[0].content && row[0].content == '1' ){
+                               updateIds.push(row[1].content);
+                               Rico.writeDebugMsg('id: '+row[1].content+' updated');
+                       }
+               }
+               return updateIds;
+       }
+       
+       function doUnBlock(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               var params = [
+                       'action=dounblock',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ]; 
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
+       
+       function doDelete(){
+               var ids = checkUpdateIds();
+               if( !(ids.length && ids.length > 0) ) return ;
+               
+               var params = [
+                       'action=dodelete',
+                       'ticket=<?php echo $ticket ;?>',
+                       'ids='+ids.join(',')
+               ];
+               ajaxEngine.sendRequest('updateData', {parameters: ajaxEngine._createQueryString(params, 0)});
+               orderGrid.resetContents('tb_grid');
+               buffer.fetch(-1);
+       }
 //]]>
 </script>
diff --git a/trunk/NP_TrackBack/trackback/templates/response_all.xml b/trunk/NP_TrackBack/trackback/templates/response_all.xml
new file mode 100644 (file)
index 0000000..7a160ad
--- /dev/null
@@ -0,0 +1,35 @@
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+       <response type="object" id="tb_grid_updater">
+               <rowcount><?php echo $count; ?></rowcount>
+               <rows update_ui="true" offset="<?php echo $start; ?>" >
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
+               </rows> 
+       </response>
+</ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/templates/response_blocked.xml b/trunk/NP_TrackBack/trackback/templates/response_blocked.xml
new file mode 100644 (file)
index 0000000..d085390
--- /dev/null
@@ -0,0 +1,41 @@
+<?php echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+       <response type="object" id='tb_grid_updater'>
+               <rowcount><?php echo $count; ?></rowcount>
+               <rows update_ui='true' >
+                       <?php while (list(,$item) = each ($items)): ?>
+                       <tr>
+                               <td>0</td>
+                               <td><?php echo $item['id'];?></td>
+                               <td>
+                                       <?php echo date("Y-m-d H:i:s",$item['timestamp']);?>
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
+                                       -->
+                               </td>
+                               <td>
+                                       <!--
+                                       <a href="<?php echo $item['url'];?>">
+                                               <img alt="Visit" border="0" src="<?php echo $plugindirurl?>silk/house_go.png" />
+                                       </a>
+                                       <strong><?php echo $item['title'];?></strong>
+                                       <?php echo $item['spam'] ? 
+                                               '<img alt="spam" border="0" src="' . $plugindirurl . 'silk/delete.png" />' : 
+                                               '';?>
+                                       <?php echo $item['link'] ? 
+                                               '' : 
+                                               '<img alt="NOT Linked" border="0" src="' . $plugindirurl . 'silk/link_break.png" />';?>
+                                       <?php echo $item['excerpt'];?>
+                                       <em>(<?php echo $item['blog_name'];?>)</em>
+                                       -->
+                               </td>
+                               <td></td>
+                       </tr>
+                       <?php endwhile; ?>
+               </rows> 
+       </response>
+</ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/templates/response_doblock.xml b/trunk/NP_TrackBack/trackback/templates/response_doblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/templates/response_dodelete.xml b/trunk/NP_TrackBack/trackback/templates/response_dodelete.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file
diff --git a/trunk/NP_TrackBack/trackback/templates/response_dounblock.xml b/trunk/NP_TrackBack/trackback/templates/response_dounblock.xml
new file mode 100644 (file)
index 0000000..a53f37c
--- /dev/null
@@ -0,0 +1,8 @@
+<?echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>';?>
+<?php global $manager; ?>
+
+<ajax-response>
+   <response type="element" id="message">
+               <?php echo $message; ?>
+   </response>
+</ajax-response>
\ No newline at end of file