OSDN Git Service

2.0.3 jp8
authorhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Tue, 6 Mar 2007 20:55:20 +0000 (20:55 +0000)
committerhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Tue, 6 Mar 2007 20:55:20 +0000 (20:55 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/plugin@537 1ca29b6e-896d-4ea0-84a5-967f57386b96

28 files changed:
trunk/NP_TrackBack/NP_TrackBack.php
trunk/NP_TrackBack/trackback/grid.php [new file with mode: 0644]
trunk/NP_TrackBack/trackback/images/sort_asc.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/images/sort_desc.gif [new file with mode: 0644]
trunk/NP_TrackBack/trackback/index.php
trunk/NP_TrackBack/trackback/japanese-euc.help.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/all.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/menu.html
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_all.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-euc.templates/response_blocked.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.help.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/all.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/all_ajax.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.templates/blocked_ajax.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.templates/menu.html
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_all.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_blocked.xml [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/js/rico.js [new file with mode: 0644]
trunk/NP_TrackBack/trackback/language/english.php
trunk/NP_TrackBack/trackback/language/japanese-euc.php
trunk/NP_TrackBack/trackback/language/japanese-utf8.php
trunk/NP_TrackBack/trackback/mkeuc.sh
trunk/NP_TrackBack/trackback/template.php
trunk/NP_TrackBack/trackback/templates/all.html
trunk/NP_TrackBack/trackback/templates/all_ajax.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/blocked_ajax.html [new file with mode: 0644]
trunk/NP_TrackBack/trackback/templates/menu.html

index 6bb3c3d..8eac40d 100644 (file)
                                                'ipblock'   => true,
                                        );
                                        global $manager;
-                                       $manager->notify('SpamCheck', array ('spamcheck' => & $spamcheck));
+                                       //$manager->notify('SpamCheck', array ('spamcheck' => & $spamcheck));
                                        $spam = false;
                                        if (isset($spamcheck['result']) && $spamcheck['result'] == true){
                                                $spam = true;
                        );
                        
                        if ($member->isLoggedIn() && $member->isAdmin()){
-                               $adminurl = $manager->addTicketToUrl($CONF['PluginURL'] . 'trackback/index.php?action=list&amp;id=' . intval($tb_id));
-                               $pingformurl = $manager->addTicketToUrl($CONF['PluginURL'] . 'trackback/index.php?action=ping&amp;id=' . intval($tb_id));
+                               $adminurl = htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'] . 'trackback/index.php?action=list&id=' . intval($tb_id)), ENT_QUOTES);
+                               $pingformurl = htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'] . 'trackback/index.php?action=ping&id=' . intval($tb_id)), ENT_QUOTES);
                                $gVars['admin'] = '<a href="' . $adminurl . '" target="_blank">[admin]</a>';
                                $gVars['pingform'] = '<a href="' . $pingformurl . '" target="_blank">[pingform]</a>';
                        }
                        $desc   = $this->_cut_string($desc, 200);
                        $desc   = htmlspecialchars($desc, ENT_QUOTES);
                        
-                       $timestamp = time();
-                       $sourceaddr = ip2long(serverVar('REMOTE_ADDR'));
-                       $key = md5( sprintf("%u %u %u %s", $timestamp, $sourceaddr, $itemid, __FILE__));
                        ?>
                        <!--
                        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                        }
 //mod by cles
                        // check: accept pings.
-                       if( $this->getBlogOption(getBlogIDFromItemID($tb_id), "AllowTrackBack") == 'yes' )
+                       $blogId = getBlogIDFromItemID($tb_id);
+                       
+                       if( $this->getBlogOption($blogId, "AllowTrackBack") == 'yes' )
                                $isAcceptPing = ( $this->getItemOption($tb_id, 'ItemAcceptPing') == 'yes' ) ? true : false ;
                        else
                                $isAcceptPing = false;
 
                        // 1. Get attributes
 //modify start+++++++++
-                       $b =& $manager->getBlog(getBlogIDFromItemID($tb_id));
+                       $b =& $manager->getBlog($blogId);
 //modify end+++++++++
                        $url            = requestVar('url');
                        $title          = requestVar('title');
                        }
        
                        // 7. Send notification e-mail if needed
-                       if ($this->getOption('Notify') == 'yes' && $spam == false) 
+                       $notifyAddrs = $this->getOption('NotifyEmail');
+                       $notifyAddrs = ( $notifyAddrs ? $notifyAddrs . ';' : '') 
+                                                       . $this->getBlogOption($blogId ,'NotifyEmailBlog');
+                                               
+                       if ($notifyAddrs && $spam == false) 
                        {
-                               $destAddress = $this->getOption('NotifyEmail');
-
                                
                                $vars = array (
                                        'tb_id'    => $tb_id,
                                if (!class_exists('notification'))
                                        include($DIR_LIBS . 'NOTIFICATION.php');
                                
-                               $notify = new NOTIFICATION($destAddress);
+                               $notify = new NOTIFICATION($notifyAddrs);
                                $notify->notify($mailto_title, $mailto_msg , $CONF['AdminEmail']);
+                               
 //mod by cles+++++++++++       
                                if ($manager->pluginInstalled('NP_Cache')){
                                        $p =& $manager->getPlugin('NP_Cache');
                                }
 //mod by cles end +++++++++++  
                        }
+
+                       if( $block )
+                               return 'Sorry, trackback ping is not accepted.';
                        return '';
                }       
 
                {
                        $links = array();
                        
-                       if (preg_match_all('/<([^>]+)>/', $text, $array, PREG_SET_ORDER))
+                       if (preg_match_all('/<[aA] +([^>]+)>/', $text, $array, PREG_SET_ORDER))
                        {
                                for ($i = 0; $i < count($array); $i++)
                                {
-                                       preg_match('/href="http:\/\/(.+?)"/', $array[$i][1], $matches);
-                                       $links['http://'.$matches[1]] = 1;
+                                       //if( preg_match('/s?https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+/', $array[$i][1], $matches) )
+                                       if( preg_match('/s?https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/:@&=+$,%]+/', $array[$i][1], $matches) )
+                                               $links[$matches[0]] = 1;
                                }
                        }
                        
@@ -2605,7 +2611,7 @@ function _strip_controlchar($string){\r    $string = preg_replace("/[\x01-\x08\x0b\x
                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 jp7'; }
+               function getVersion()     {             return '2.0.3 jp8'; }
                function getDescription() {             return _TB_DESCRIPTION; }
        
 //modify start+++++++++
@@ -2673,15 +2679,16 @@ function _strip_controlchar($string){\r  $string = preg_replace("/[\x01-\x08\x0b\x
                        $this->createOption('tplTbMore',   _TB_tplTbMore, 'text', "<%number%> Trackbacks");
                        $this->createOption('dateFormat',  _TB_dateFormat, 'text', _TB_dateFormat_VAL);
        
-                       $this->createOption('Notify',      _TB_Notify,'yesno','no');
-                       $this->createOption('NotifyEmail', _TB_NotifyEmail,'text','');  
-
+                       $this->createOption('NotifyEmail', _TB_NotifyEmail,'text','');
                        $this->createOption('DropTable',   _TB_DropTable,'yesno','no');
 //mod by cles
                        $this->createOption('HideUrl',_TB_HideUrl,'yesno','yes');
+                       $this->createOption('ajaxEnabled',_TB_ajaxEnabled,'yesno','no');
+
                        $this->createItemOption('ItemAcceptPing',_TB_ItemAcceptPing,'yesno','yes');
                        $this->createItemOption('isAcceptW/OLink',_TB_isAcceptWOLink,'select','default', _TB_isAcceptWOLink_VAL);
 
+                       $this->createBlogOption('NotifyEmailBlog', _TB_NotifyEmailBlog,'text','');      
                        $this->createBlogOption('isAcceptW/OLinkDef',_TB_isAcceptWOLinkDef,'select','block', _TB_isAcceptWOLinkDef_VAL);
                        $this->createBlogOption('AllowTrackBack',_TB_AllowTrackBack,'yesno','yes');
 //mod by cles end
@@ -2742,5 +2749,3 @@ function _strip_controlchar($string){\r    $string = preg_replace("/[\x01-\x08\x0b\x
                $this->notificationMailTitle = _TB_NORTIFICATION_MAIL_TITLE;
          }
        }
-
-?>
diff --git a/trunk/NP_TrackBack/trackback/grid.php b/trunk/NP_TrackBack/trackback/grid.php
new file mode 100644 (file)
index 0000000..9c8d8a5
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+
+       $strRel = '../../../'; 
+       include($strRel . 'config.php');
+       include($DIR_LIBS . 'PLUGINADMIN.php');
+       include('template.php');
+
+       // Send out Content-type
+       header('Pragma: no-cache');     
+       header("Content-Type: text/xml");
+       sendContentType('text/xml', 'admin-trackback', _CHARSET);       
+
+       $oPluginAdmin = new PluginAdmin('TrackBack');
+
+       if (!($member->isLoggedIn() && $member->isAdmin()))
+       {
+               $oPluginAdmin->start();
+               echo '<p>' . _ERROR_DISALLOWED . '</p>';
+               $oPluginAdmin->end();
+               exit;
+       }
+       
+       // Actions
+       $action = requestVar('action');
+       $aActionsNotToCheck = array(
+               '',
+       );
+       if (!in_array($action, $aActionsNotToCheck)) {
+               if (!$manager->checkTicket()) doError(_ERROR_BADTICKET);
+       }
+       
+//modify start+++++++++
+               $plug =& $oPluginAdmin->plugin;
+               $tableVersion = $plug->checkTableVersion();
+
+               // include language file for this plugin 
+               $language = ereg_replace( '[\\|/]', '', getLanguageName()); 
+               if (file_exists($plug->getDirectory().'language/'.$language.'.php')) 
+                       include_once($plug->getDirectory().'language/'.$language.'.php'); 
+               else 
+                       include_once($plug->getDirectory().'language/'.'english.php');
+//modify end+++++++++
+
+       $oTemplate = new Trackback_Template();
+       $oTemplate->set ('CONF', $CONF);
+       $oTemplate->set ('plugindirurl', $oPluginAdmin->plugin->getAdminURL());
+       $oTemplate->set ('ticket', $manager->_generateTicket());
+       
+       // Pages 
+       switch($action) {
+               
+               case 'ajax':
+                       $type = requestVar('type') == 'all' ? 'all' : 'blocked' ;
+                       $filter['all'] = 't.block = 0';
+                       $filter['blocked'] = 't.block = 1';
+
+                       $start  = intRequestVar('offset') ? intRequestVar('offset') : 0;
+                       $amount = intRequestVar('page_size') ? intRequestVar('page_size') : 25;
+
+                       $colname = array();
+                       $colname['date'] = 'timestamp';
+                       $colname['item'] = 'story_id';
+                       $colname['title'] = 'title';
+                       
+                       $sort_col = requestVar('sort_col');
+                       $sort_col = $colname[$sort_col];
+                       if( !$sort_col ) $sort_col = $colname['date'];
+
+                       $sort_dir = ( requestVar('sort_dir') == 'ASC' ) ? 'ASC' : 'DESC';
+                       
+                       $rres = mysql_query ("
+                       SELECT
+                       i.ititle AS story,
+                       i.inumber AS story_id,
+                       t.id AS id,
+                       t.title AS title,
+                       t.blog_name AS blog_name,
+                       t.excerpt AS excerpt,
+                       t.url AS url,
+                       t.spam AS spam,
+                       UNIX_TIMESTAMP(t.timestamp) AS timestamp
+                       FROM
+                       ".sql_table('plugin_tb')." AS t,
+                       ".sql_table('item')." AS i
+                       WHERE
+                       t.tb_id = i.inumber AND
+                       ".$filter[$type]."
+                       ORDER BY
+                       ".$sort_col." ".$sort_dir." 
+                       LIMIT
+                       ".$start.",".$amount."
+                       ");
+                       
+                       $items = array();
+                       
+                       while ($rrow = mysql_fetch_array($rres))
+                       {
+                               $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['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['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['url']            = htmlspecialchars($rrow['url'], ENT_QUOTES);
+                               
+                               $blog = & $manager->getBlog(getBlogIDFromItemID($rrow['story_id']));
+                               $rrow['story_url'] = $oPluginAdmin->plugin->_createItemLink($rrow['story_id'], $blog);
+                               $rrow['story'] = htmlspecialchars(strip_tags($rrow['story']), ENT_QUOTES);
+                               
+                               $items[] = $rrow;
+                       }
+                       
+                       $oTemplate->set ('amount', $amount);
+                       $oTemplate->set ('count', $count);
+                       $oTemplate->set ('start', $start);
+                       $oTemplate->set ('items', $items);
+                       $oTemplate->template('templates/response_'.$type.'.xml');                       
+                       break;
+       }
+
+       // Create the admin area page
+       echo $oTemplate->fetch();
+       
diff --git a/trunk/NP_TrackBack/trackback/images/sort_asc.gif b/trunk/NP_TrackBack/trackback/images/sort_asc.gif
new file mode 100644 (file)
index 0000000..53a6dcf
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/images/sort_asc.gif differ
diff --git a/trunk/NP_TrackBack/trackback/images/sort_desc.gif b/trunk/NP_TrackBack/trackback/images/sort_desc.gif
new file mode 100644 (file)
index 0000000..4fd1346
Binary files /dev/null and b/trunk/NP_TrackBack/trackback/images/sort_desc.gif differ
index 14fb332..0dd0b7c 100644 (file)
@@ -9,11 +9,6 @@
        // Send out Content-type
        sendContentType('application/xhtml+xml', 'admin-trackback', _CHARSET);  
 
-       // Compatiblity with Nucleus < = 2.0
-       if (!function_exists('sql_table')) { function sql_table($name) { return 'nucleus_' . $name; } }
-       
-
-
        $oPluginAdmin = new PluginAdmin('TrackBack');
 
        if (!($member->isLoggedIn() && $member->isAdmin()))
 
        $mTemplate = new Trackback_Template();
        $mTemplate->set ('CONF', $CONF);
-       $mTemplate->set ('plugid', $plug->getID());\r    $mTemplate->set ('plugindirurl', $oPluginAdmin->plugin->getAdminURL());
+       $mTemplate->set ('plugid', $plug->getID());
+       $mTemplate->set ('plugindirurl', $oPluginAdmin->plugin->getAdminURL());
        $mTemplate->template('templates/menu.html');
        echo $mTemplate->fetch();
 
        $oTemplate = new Trackback_Template();
        $oTemplate->set ('CONF', $CONF);
        $oTemplate->set ('plugindirurl', $oPluginAdmin->plugin->getAdminURL());
+       $oTemplate->set ('ticket', $manager->_generateTicket());
+       \r       $ajaxEnabled = ($oPluginAdmin->plugin->getOption('ajaxEnabled') == 'yes') ? true : false;
+       $oTemplate->set ('ajaxEnabled', $ajaxEnabled);
 
        switch($action) {
 
                        break;
 
                case 'blocked':
-                       $start  = intRequestVar('start') ? intRequestVar('start') : 0;
-                       $amount = intRequestVar('amount') ? intRequestVar('amount') : 25;
-
+               case 'all':     
                        $rres = mysql_query ("
                                SELECT
                                        COUNT(*) AS count
                                        ".sql_table('item')." AS i
                                WHERE
                                        t.tb_id = i.inumber AND
-                                       t.block = 1
-                       ");                             
+                                       t.block = " . (( $action == 'all') ? 0 : 1) );                          
                                                
                        if ($row = mysql_fetch_array($rres))
                                $count = $row['count'];
                        else
                                $count = 0;
-                                       
-                       $rres = mysql_query ("
-                               SELECT
+                       $oTemplate->set('count', $count);
+
+                       if($ajaxEnabled){
+                               if( $action == 'all') 
+                                       $oTemplate->template('templates/all_ajax.html');
+                               else                    
+                                       $oTemplate->template('templates/blocked_ajax.html');
+                       } else {\r                               $start  = intRequestVar('start') ? intRequestVar('start') : 0;
+                               $amount = intRequestVar('amount') ? intRequestVar('amount') : 25;
+
+                               $rres = mysql_query ("
+                                       SELECT
                                        i.ititle AS story,
                                        i.inumber AS story_id,
                                        t.id AS id,
                                        t.blog_name AS blog_name,
                                        t.excerpt AS excerpt,
                                        t.url AS url,
-                                       -- UNIX_TIMESTAMP(t.timestamp) AS timestamp,
                                        t.timestamp AS timestamp,
                                        t.spam AS spam,
                                        t.link AS link
-                               FROM
+                                       FROM
                                        ".sql_table('plugin_tb')." AS t,
                                        ".sql_table('item')." AS i
-                               WHERE
+                                       WHERE
                                        t.tb_id = i.inumber AND
-                                       t.block = 1
-                               ORDER BY
+                                       t.block = " . (( $action == 'all') ? 0 : 1) ."
+                                       ORDER BY
                                        timestamp DESC
-                               LIMIT
-                                       ".$start.",".$amount."
-                       ");                             
-                       
-                       $items = array();
-
-                       while ($rrow = mysql_fetch_array($rres))
-                       {
-                               $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['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['excerpt']        = $oPluginAdmin->plugin->_cut_string($rrow['excerpt'], 800);
-                               $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['url']            = htmlspecialchars($rrow['url'], ENT_QUOTES);
-                               $rrow['timestamp']              = htmlspecialchars($rrow['timestamp'], ENT_QUOTES);
+                                       LIMIT
+                                       ".$start.",".$amount);                          
                                
-                               $blog = & $manager->getBlog(getBlogIDFromItemID($item['itemid']));
-                               $rrow['story_url'] = $oPluginAdmin->plugin->_createItemLink($rrow['story_id'], $blog);
-                               $rrow['story'] = htmlspecialchars(strip_tags($rrow['story']), ENT_QUOTES);
-
-                               $items[] = $rrow;
-                       }
-                       
-                       $oTemplate->set ('amount', $amount);
-                       $oTemplate->set ('count', $count);
-                       $oTemplate->set ('start', $start);
-                       $oTemplate->set ('items', $items);
-                       $oTemplate->template('templates/blocked.html');                 
-                       break;
-
-               case 'all':
-                       $start  = intRequestVar('start') ? intRequestVar('start') : 0;
-                       $amount = intRequestVar('amount') ? intRequestVar('amount') : 25;
-
-                       $rres = mysql_query ("
-                               SELECT
-                                       COUNT(*) AS count
-                               FROM
-                                       ".sql_table('plugin_tb')." AS t,
-                                       ".sql_table('item')." AS i
-                               WHERE
-                                       t.tb_id = i.inumber AND
-                                       t.block = 0
-                       ");                             
-                                               
-                       if ($row = mysql_fetch_array($rres))
-                               $count = $row['count'];
-                       else
-                               $count = 0;
+                               $items = array();
+                               
+                               while ($rrow = mysql_fetch_array($rres)){
+                                       $rrow['title']          = $oPluginAdmin->plugin->_cut_string($rrow['title'], 50);
+                                       $rrow['title']          = $oPluginAdmin->plugin->_strip_controlchar($rrow['title']);
+                                       $rrow['title']          = htmlspecialchars($rrow['title']);
                                        
-                       $rres = mysql_query ("
-                               SELECT
-                                       i.ititle AS story,
-                                       i.inumber AS story_id,
-                                       t.id AS id,
-                                       t.title AS title,
-                                       t.blog_name AS blog_name,
-                                       t.excerpt AS excerpt,
-                                       t.url AS url,
-                                       UNIX_TIMESTAMP(t.timestamp) AS timestamp
-                               FROM
-                                       ".sql_table('plugin_tb')." AS t,
-                                       ".sql_table('item')." AS i
-                               WHERE
-                                       t.tb_id = i.inumber AND
-                                       t.block = 0
-                               ORDER BY
-                                       timestamp DESC
-                               LIMIT
-                                       ".$start.",".$amount."
-                       ");                             
-                       
-                       $items = array();
-
-                       while ($rrow = mysql_fetch_array($rres))
-                       {
-                               $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['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['excerpt']        = $oPluginAdmin->plugin->_cut_string($rrow['excerpt'], 800);
-                               $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['url']            = htmlspecialchars($rrow['url'], ENT_QUOTES);
-
-                               $blog = & $manager->getBlog(getBlogIDFromItemID($item['itemid']));
-                               $rrow['story_url'] = $oPluginAdmin->plugin->_createItemLink($rrow['story_id'], $blog);
-                               $rrow['story'] = htmlspecialchars(strip_tags($rrow['story']), ENT_QUOTES);
-
-                               $items[] = $rrow;
+                                       $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['excerpt']        = $oPluginAdmin->plugin->_cut_string($rrow['excerpt'], 800);
+                                       $rrow['excerpt']        = $oPluginAdmin->plugin->_strip_controlchar($rrow['excerpt']);
+                                       $rrow['excerpt']        = htmlspecialchars($rrow['excerpt']);
+                                       
+                                       $rrow['url']            = htmlspecialchars($rrow['url'], ENT_QUOTES);
+                                       $rrow['timestamp']              = htmlspecialchars($rrow['timestamp'], ENT_QUOTES);
+                                       
+                                       $blog = & $manager->getBlog(getBlogIDFromItemID($item['itemid']));
+                                       $rrow['story_url'] = $oPluginAdmin->plugin->_createItemLink($rrow['story_id'], $blog);
+                                       $rrow['story'] = htmlspecialchars(strip_tags($rrow['story']), ENT_QUOTES);
+                                       
+                                       $items[] = $rrow;
+                               }
+                               
+                               $oTemplate->set('amount', $amount);
+                               $oTemplate->set('start', $start);
+                               $oTemplate->set('items', $items);
+                               
+                               if( $action == 'all') 
+                                       $oTemplate->template('templates/all.html');
+                               else                    
+                                       $oTemplate->template('templates/blocked.html');
                        }
+                       break;
                        
-                       $oTemplate->set ('amount', $amount);
-                       $oTemplate->set ('count', $count);
-                       $oTemplate->set ('start', $start);
-                       $oTemplate->set ('items', $items);
-                       $oTemplate->template('templates/all.html');                     
-                       break;          
-               
                case 'list':
                        $id     = requestVar('id');
                        $start  = intRequestVar('start') ? intRequestVar('start') : 0;
        // Create the admin area page
        echo $oTemplate->fetch();
        
-       echo '<hr noshade="noshade" size="1" /><div align="right">Powered by <a href="http://www.famfamfam.com/lab/icons/silk/">Silk icon</a></div>';
+       echo '<div align="right">Powered by <a href="http://www.famfamfam.com/lab/icons/silk/">Silk icon</a></div>';
        $oPluginAdmin->end();   
 
-?>
index 89aa181..2b36c62 100644 (file)
@@ -125,10 +125,18 @@ div.tb div.info {
 <h3>ÆüËܸìÈǹ¹¿·ÍúÎò</h3>
 
 <ul>
-       <li>Version 2.0.3jp7 : (2006/*/*)</li>
+       <li>Version 2.0.3jp8 : (2006/**/**)</li>
+       <li>¡¡[Fixed] ´ÉÍý²èÌ̤ÇStory¤Î¥ê¥ó¥¯¤ÎÉÔ¶ñ¹ç¤ò½¤Àµ</li>
+       <li>¡¡[Changed] URLÃê½Ð¥ë¡¼¥Á¥ó¤ò²þÎÉ</li>
+       <li>¡¡[Changed] ´ÉÍý²èÌ̤ؤΥê¥ó¥¯¤ò½¤Àµ</li>
+       <li>¡¡[Changed] ´ÉÍý²èÌ̤Υڡ¼¥¸¥ó¥°¤òAjaxÂбþ¤Ë¤·¤¿</li>
+       <li>¡¡[Changed] ¥È¥é¥Ã¥¯¥Ð¥Ã¥¯ÄÌÃÎ¥¢¥É¥ì¥¹¤ò¥Ö¥í¥°¤´¤È¤ËÀßÄê¤Ç¤­¤ë¤è¤¦¤Ë¤·¤¿</li>
+       
+       <li>Version 2.0.3jp7 : (2006/11/26)</li>
        <li>¡¡[Changed] SpamChek¤Ë¤Ä¤¤¤ÆÈùÄ´À°</li>
        <li>¡¡[Added] Ticket½èÍý¤òÄɲÃ(CSRFÂкö)</li>
        <li>¡¡[Fixed] URL¤Ë&amp;¤¬Æþ¤Ã¤Æ¤¤¤ë¤È¤­¤ÎÆ°ºî¤òÊѹ¹</li>
+       <li>¡¡[Added] ´ÉÍý²èÌ̤˥¢¥¤¥³¥ó¤òÄɲÃ</li>
        
        <li>Version 2.0.3jp6 : (2006/09/30)</li>
        <li>¡¡[Fixed] ¥»¥­¥å¥ê¥Æ¥£¤Î¸þ¾å</li>
index 8de415b..d6a22d9 100644 (file)
@@ -41,9 +41,9 @@
 <table>
        <thead>
                <tr>
+                       <th>Date</th>
                        <th>Story</th>
                        <th>Title, Blog and Excerpt</th>
-                       <th>Date</th>
                        <th colspan="2">Actions</th>
                </tr>
        </thead>
@@ -51,6 +51,9 @@
                <?php while (list(,$item) = each ($items)): ?>
                <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
                        <td>
+                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
+                       </td>
+                       <td>
                                <a href="<? echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
                        </td>
                        <td>
@@ -60,9 +63,6 @@
                                <?php echo $item['excerpt'];?>
                        </td>
                        <td>
-                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
-                       </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>
index a16a2d5..64c8983 100644 (file)
@@ -1,6 +1,8 @@
 <?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>
 <ul>
        <li>
                <img border="0" src="<?php echo $plugindirurl?>silk/application_view_list.png" />
@@ -26,4 +28,4 @@
                <img border="0" src="<?php echo $plugindirurl?>silk/plugin_edit.png" />
                <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['AdminURL'].'index.php?action=pluginoptions&plugid='.$plugid),ENT_QUOTES);?>">¥×¥é¥°¥¤¥ó¥ª¥×¥·¥ç¥óÀßÄê</a>
        </li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_all.xml b/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_all.xml
new file mode 100644 (file)
index 0000000..18d3782
--- /dev/null
@@ -0,0 +1,31 @@
+<?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="<? 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; ?>
+               </rows> 
+       </response>
+</ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_blocked.xml b/trunk/NP_TrackBack/trackback/japanese-euc.templates/response_blocked.xml
new file mode 100644 (file)
index 0000000..ded63ce
--- /dev/null
@@ -0,0 +1,38 @@
+<?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="<? 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; ?>
+               </rows> 
+       </response>
+</ajax-response>
index c3bccdf..25ac3ab 100644 (file)
@@ -125,6 +125,13 @@ div.tb div.info {
 <h3>日本語版更新履歴</h3>
 
 <ul>
+       <li>Version 2.0.3jp8 : (2006/**/**)</li>
+       <li> [Fixed] 管理画面でStoryのリンクの不具合を修正</li>
+       <li> [Changed] URL抽出ルーチンを改良</li>
+       <li> [Changed] 管理画面へのリンクを修正</li>
+       <li> [Changed] 管理画面のページングをAjax対応にした</li>
+       <li> [Changed] トラックバック通知アドレスをブログごとに設定できるようにした</li>
+       
        <li>Version 2.0.3jp7 : (2006/11/26)</li>
        <li> [Changed] SpamChekについて微調整</li>
        <li> [Added] Ticket処理を追加(CSRF対策)</li>
index 8de415b..d6a22d9 100644 (file)
@@ -41,9 +41,9 @@
 <table>
        <thead>
                <tr>
+                       <th>Date</th>
                        <th>Story</th>
                        <th>Title, Blog and Excerpt</th>
-                       <th>Date</th>
                        <th colspan="2">Actions</th>
                </tr>
        </thead>
@@ -51,6 +51,9 @@
                <?php while (list(,$item) = each ($items)): ?>
                <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
                        <td>
+                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
+                       </td>
+                       <td>
                                <a href="<? echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
                        </td>
                        <td>
@@ -60,9 +63,6 @@
                                <?php echo $item['excerpt'];?>
                        </td>
                        <td>
-                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
-                       </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>
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/all_ajax.html b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/all_ajax.html
new file mode 100644 (file)
index 0000000..cc8bd98
--- /dev/null
@@ -0,0 +1,124 @@
+<?php global $manager; ?>
+<h2>
+       All trackbacks
+</h2>
+
+<div id="showingLabel"><?php echo $count ; ?>件中 1 - 5 件目を表示しています</div>
+
+<div style="width: 100%">
+<div id="viewPort" style="float:left; width: 420px">
+<table id="tb_grid" style="border:0; margin:0; width: 400px">
+       <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>
+               </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()) + "件目を表示しています。";
+    }
+
+    function loadGrid() {
+       var width = $('content').offsetWidth
+       $('viewPort').style.width = width  + 'px';
+       $('tb_grid').style.width =  ( width - 40 ) + 'px';
+
+       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);
+    }
+
+    window.onload = loadGrid;
+//]]>
+</script>
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/blocked_ajax.html b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/blocked_ajax.html
new file mode 100644 (file)
index 0000000..a292651
--- /dev/null
@@ -0,0 +1,129 @@
+<?php global $manager; ?>
+<h2>
+       ブロックされたトラックバック
+</h2>
+
+<ul>
+       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_clear&next=blocked'),ENT_QUOTES); ?>">ブロックされたトラックバックのクリア</a></li>
+       <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 style="float:left; width: 100%">
+<div id="viewPort" style="float:left; width: 620px">
+<table id="tb_grid" style="border:0; margin:0; width: 600px">
+       <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>
+               </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()) + "件目を表示しています。";
+    }
+
+    function loadGrid() {
+       var width = $('content').offsetWidth
+       $('viewPort').style.width = width + 'px';
+       $('tb_grid').style.width = (width - 40) + 'px';
+
+       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);
+    }
+
+    window.onload = loadGrid;
+//]]>
+</script>
index a689a5c..6b9c742 100644 (file)
@@ -1,6 +1,8 @@
 <?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>
 <ul>
        <li>
                <img border="0" src="<?php echo $plugindirurl?>silk/application_view_list.png" />
@@ -26,4 +28,4 @@
                <img border="0" src="<?php echo $plugindirurl?>silk/plugin_edit.png" />
                <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['AdminURL'].'index.php?action=pluginoptions&plugid='.$plugid),ENT_QUOTES);?>">プラグインオプション設定</a>
        </li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_all.xml b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_all.xml
new file mode 100644 (file)
index 0000000..18d3782
--- /dev/null
@@ -0,0 +1,31 @@
+<?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="<? 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; ?>
+               </rows> 
+       </response>
+</ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_blocked.xml b/trunk/NP_TrackBack/trackback/japanese-utf8.templates/response_blocked.xml
new file mode 100644 (file)
index 0000000..ded63ce
--- /dev/null
@@ -0,0 +1,38 @@
+<?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="<? 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; ?>
+               </rows> 
+       </response>
+</ajax-response>
diff --git a/trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js b/trunk/NP_TrackBack/trackback/js/prototype-1.4.0.js
new file mode 100644 (file)
index 0000000..0e85338
--- /dev/null
@@ -0,0 +1,1781 @@
+/*  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/rico.js b/trunk/NP_TrackBack/trackback/js/rico.js
new file mode 100644 (file)
index 0000000..535e0de
--- /dev/null
@@ -0,0 +1,2819 @@
+/**
+  *
+  *  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;
+   }
+
+};
index 5be9e33..54f2aaf 100644 (file)
@@ -37,8 +37,10 @@ define('_TB_tplTbMore', 'Trackback count (more)');
 define('_TB_dateFormat', 'Date format');
 define('_TB_dateFormat_VAL', "%e/%m/%g");
 
-define('_TB_Notify', 'Send e-mail notification on ping receipt');
+define('_TB_ajaxEnabled', 'Enable Ajax ?');
 define('_TB_NotifyEmail', 'Which e-mail address to send these notification to?');
+define('_TB_NotifyEmailBlog', 'Which e-mail address to send these notification to?');
+
 define('_TB_DropTable', 'Clear the database when uninstalling');
 define('_TB_HideUrl', 'Hide external URL');
 define('_TB_ItemAcceptPing', 'Accept pings');
@@ -48,4 +50,3 @@ define('_TB_AllowTrackBack', 'Accept pings to this blog');
 
 define('_TB_isAcceptWOLink_VAL', 'default|default|yes|yes|no|no');
 define('_TB_isAcceptWOLinkDef_VAL', 'yes|yes|no (block)|block|no (ignore)|ignore');
-?>
\ No newline at end of file
index b5affb6..38467a3 100644 (file)
@@ -36,8 +36,10 @@ define('_TB_tplTbMore', 'TB
 define('_TB_dateFormat', 'ÆüÉդηÁ¼°');
 define('_TB_dateFormat_VAL', "%Y/%m/%d %H:%I");
 
-define('_TB_Notify', 'ping¼õÉÕ»þ¤Ë¥á¡¼¥ëÁ÷¿®¤¹¤ë¤«?');
-define('_TB_NotifyEmail', 'ping¼õÉÕ»þ¤Î¥á¡¼¥ëÁ÷¿®Àè');
+define('_TB_ajaxEnabled', '´ÉÍý²èÌ̤ÇAjax¤òÍ­¸ú¤Ë¤¹¤ë¤«');
+define('_TB_NotifyEmail', 'ping¼õÉÕ»þ¤Î¥á¡¼¥ëÁ÷¿®Àè(;¤Ç¶èÀڤäÆÊ£¿ôÆþÎϲÄǽ)');
+define('_TB_NotifyEmailBlog', 'ping¼õÉÕ»þ¤Î¥á¡¼¥ëÁ÷¿®Àè(;¤Ç¶èÀڤäÆÊ£¿ôÆþÎϲÄǽ)');
+
 define('_TB_DropTable', '¥×¥é¥°¥¤¥ó¤Îºï½ü»þ¤Ë¥Ç¡¼¥¿¤òºï½ü¤¹¤ë¤«?');
 define('_TB_HideUrl', '°ìÍ÷ɽ¼¨¤ÎºÝ¤Ë³°Éô¤ÎURL¤ò¥ê¥À¥¤¥ì¥¯¥È¤ËÊÑ´¹¤¹¤ë¤«?');
 define('_TB_ItemAcceptPing', 'TB¤ò¼õÉÕ¤¹¤ë¤«?');
@@ -47,4 +49,3 @@ define('_TB_AllowTrackBack', '
 
 define('_TB_isAcceptWOLink_VAL', '¥Ö¥í¥°¥Ç¥Õ¥©¥ë¥È¤Ë½¾¤¦|default|¤Ï¤¤|yes|¤¤¤¤¤¨|no');
 define('_TB_isAcceptWOLinkDef_VAL', '¤Ï¤¤|yes|¤¤¤¤¤¨(ÊÝα)|block|¤¤¤¤¤¨(̵»ë)|ignore');
-?>
\ No newline at end of file
index 8367168..1d18999 100644 (file)
@@ -36,8 +36,11 @@ define('_TB_tplTbMore', 'TB数表示形式(2件以上)');
 define('_TB_dateFormat', '日付の形式');
 define('_TB_dateFormat_VAL', "%Y/%m/%d %H:%I");
 
-define('_TB_Notify', 'ping受付時にメール送信するか?');
-define('_TB_NotifyEmail', 'ping受付時のメール送信先');
+
+define('_TB_ajaxEnabled', '管理画面でAjaxを有効にするか');
+define('_TB_NotifyEmail', 'ping受付時のメール送信先(;で区切って複数入力可能)');
+define('_TB_NotifyEmailBlog', 'ping受付時のメール送信先(;で区切って複数入力可能)');
+
 define('_TB_DropTable', 'プラグインの削除時にデータを削除するか?');
 define('_TB_HideUrl', '一覧表示の際に外部のURLをリダイレクトに変換するか?');
 define('_TB_ItemAcceptPing', 'TBを受付するか?');
@@ -47,4 +50,3 @@ define('_TB_AllowTrackBack', 'このブログでTBを受付するか?');
 
 define('_TB_isAcceptWOLink_VAL', 'ブログデフォルトに従う|default|はい|yes|いいえ|no');
 define('_TB_isAcceptWOLinkDef_VAL', 'はい|yes|いいえ(保留)|block|いいえ(無視)|ignore');
-?>
\ No newline at end of file
index 1f82275..75f54d9 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash -x
 
-FILES=`find japanese-utf8.templates -name '*html'`
+FILES=`find japanese-utf8.templates -name '*ml'`
 
 for utf8file in $FILES
 do
index 1ee817e..64ffe8a 100644 (file)
@@ -33,5 +33,3 @@ class Trackback_Template {
                }
     }
 }
-
-?>
\ No newline at end of file
index 8de415b..d6a22d9 100644 (file)
@@ -41,9 +41,9 @@
 <table>
        <thead>
                <tr>
+                       <th>Date</th>
                        <th>Story</th>
                        <th>Title, Blog and Excerpt</th>
-                       <th>Date</th>
                        <th colspan="2">Actions</th>
                </tr>
        </thead>
@@ -51,6 +51,9 @@
                <?php while (list(,$item) = each ($items)): ?>
                <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
                        <td>
+                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
+                       </td>
+                       <td>
                                <a href="<? echo $item['story_url']; ?>"><?php echo $item['story'];?></a>
                        </td>
                        <td>
@@ -60,9 +63,6 @@
                                <?php echo $item['excerpt'];?>
                        </td>
                        <td>
-                               <?php echo str_replace(' ', '&nbsp;', date("Y-m-d @ H:i",$item['timestamp']));?>
-                       </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>
diff --git a/trunk/NP_TrackBack/trackback/templates/all_ajax.html b/trunk/NP_TrackBack/trackback/templates/all_ajax.html
new file mode 100644 (file)
index 0000000..452c2b1
--- /dev/null
@@ -0,0 +1,124 @@
+<?php global $manager; ?>
+<h2>
+       All trackbacks
+</h2>
+
+<div id="showingLabel">Showing 1 - 5 of <?php echo $count ; ?></div>
+
+<div style="width: 100%">
+<div id="viewPort" style="float:left; width: 420px">
+<table id="tb_grid" style="border:0; margin:0; width: 400px">
+       <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>
+               </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 = "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';
+
+       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);
+    }
+
+    window.onload = loadGrid;
+//]]>
+</script>
diff --git a/trunk/NP_TrackBack/trackback/templates/blocked_ajax.html b/trunk/NP_TrackBack/trackback/templates/blocked_ajax.html
new file mode 100644 (file)
index 0000000..af73395
--- /dev/null
@@ -0,0 +1,129 @@
+<?php global $manager; ?>
+<h2>
+       Blocked Trackbacks
+</h2>
+
+<ul>
+       <li><a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['PluginURL'].'trackback/index.php?action=blocked_clear&next=blocked'),ENT_QUOTES); ?>">繝悶Ο繝�繧ッ縺輔l縺溘ヨ繝ゥ繝�繧ッ繝舌ャ繧ッ縺ョ繧ッ繝ェ繧「</a></li>
+       <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">Showing 1 - 5 of <?php echo $count ; ?></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">
+       <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>
+               </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 = "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';
+
+       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);
+    }
+
+    window.onload = loadGrid;
+//]]>
+</script>
index 9a5e1e8..92fa7e1 100644 (file)
@@ -1,4 +1,8 @@
 <?php global $manager?>
+
+<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.js"></script>
+
 <h2>Trackback</h2>
 
 <ul>
@@ -24,6 +28,6 @@
        </li>
     <li>
                <img border="0" src="<?php echo $plugindirurl?>silk/plugin_edit.png" />
-               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['AdminURL'].'index.php?action=pluginoptions&plugid='.$plugid);?>">Plugin Options</a>
+               <a href="<?php echo htmlspecialchars($manager->addTicketToUrl($CONF['AdminURL'].'index.php?action=pluginoptions&plugid='.$plugid),ENT_QUOTES);?>">Plugin Options</a>
        </li>
 </ul>
\ No newline at end of file