OSDN Git Service

v1.6.0
authorhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Sat, 17 May 2008 19:11:11 +0000 (19:11 +0000)
committerhsur <hsur@1ca29b6e-896d-4ea0-84a5-967f57386b96>
Sat, 17 May 2008 19:11:11 +0000 (19:11 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/plugin@625 1ca29b6e-896d-4ea0-84a5-967f57386b96

141 files changed:
trunk/NP_Clap/NP_Clap.php [new file with mode: 0644]
trunk/NP_Clap/clap/chart/canvaschart.css [new file with mode: 0644]
trunk/NP_Clap/clap/chart/canvaschartpainter.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/chart.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/demo.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/excanvas.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/iecanvas.htc [new file with mode: 0644]
trunk/NP_Clap/clap/chart/iecanvas.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/jgchartpainter.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/svgchartpainter.js [new file with mode: 0644]
trunk/NP_Clap/clap/chart/wz_jsgraphics.js [new file with mode: 0644]
trunk/NP_Clap/clap/help.html [new file with mode: 0644]
trunk/NP_Clap/clap/index.php [new file with mode: 0644]
trunk/NP_Clap/clap/js/chart.js [new file with mode: 0644]
trunk/NP_Clap/clap/js/prototype-1.4.0.js [new file with mode: 0644]
trunk/NP_Clap/clap/language/japanese-euc.php [new file with mode: 0644]
trunk/NP_Clap/clap/language/japanese-utf8.php [new file with mode: 0644]
trunk/NP_Clap/clap/mkeuc.sh [new file with mode: 0644]
trunk/NP_Clap/clap/silk/application_edit.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/application_view_list.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/bug_link.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/chart_line.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/coins.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/comment.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/comments.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/computer.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/cross.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/database_delete.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/database_refresh.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/key.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/layout.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/magnifier.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_add.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_delete.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_edit.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_magnify.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_stack.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/page_white_text.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/picture.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/picture_empty.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/plugin_edit.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/readme.txt [new file with mode: 0644]
trunk/NP_Clap/clap/silk/time.png [new file with mode: 0644]
trunk/NP_Clap/clap/silk/user.png [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/chart_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/chart_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/convert_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/convert_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/doconvert_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/doconvert_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/doreset_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/doreset_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/error_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/error_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/menu_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/menu_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/reset_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/reset_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksedit_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksedit_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/button_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/button_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/list_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-euc.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-utf8.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-euc.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-utf8.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/thanks_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap/thanks_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-euc.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-utf8.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-euc.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-utf8.txt [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-euc.html [new file with mode: 0644]
trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-utf8.html [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon/Decoder.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon/Decoder/Tokenizer.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon/Encoder.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon/Error.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/Jsphon/Exception.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/cles/Feedback.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/cles/Template.php [new file with mode: 0644]
trunk/NP_Clap/sharedlibs/sharedlibs.php [new file with mode: 0644]

diff --git a/trunk/NP_Clap/NP_Clap.php b/trunk/NP_Clap/NP_Clap.php
new file mode 100644 (file)
index 0000000..edc1008
--- /dev/null
@@ -0,0 +1,860 @@
+<?php
+// vim: tabstop=2:shiftwidth=2
+
+/**
+  * NP_Clap ($Revision: 1.1 $)
+  * by hsur ( http://blog.cles.jp/np_cles )
+  * 
+  * $Id: NP_Clap.php,v 1.1 2008-05-17 19:11:11 hsur Exp $
+*/
+
+/*
+  * Copyright (C) 2006-2008 CLES. All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+  * 
+  * In addition, as a special exception, cles( http://blog.cles.jp/np_cles ) gives
+  * permission to link the code of this program with those files in the PEAR
+  * library that are licensed under the PHP License (or with modified versions
+  * of those files that use the same license as those files), and distribute
+  * linked combinations including the two. You must obey the GNU General Public
+  * License in all respects for all of the code used other than those files in
+  * the PEAR library that are licensed under the PHP License. If you modify
+  * this file, you may extend this exception to your version of the file,
+  * but you are not obligated to do so. If you do not wish to do so, delete
+  * this exception statement from your version.
+*/
+
+// load class
+require_once(dirname(__FILE__).'/sharedlibs/sharedlibs.php');
+require_once('cles/Template.php');
+require_once('Jsphon.php');
+
+define('NP_CLAP_GLOBALKEY', 'global');
+
+class NP_Clap extends NucleusPlugin {
+
+       // name of plugin
+       function getName() {
+               return 'Clap';
+       }
+
+       // author of plugin
+       function getAuthor() {
+               return 'hsur';
+       }
+
+       // an URL to the plugin website
+       // can also be of the form mailto:foo@bar.com
+       function getURL() {
+               return 'http://blog.cles.jp/np_cles/category/31/subcatid/13';
+       }
+
+       // version of the plugin
+       function getVersion() {
+               return '1.6.0';
+       }
+
+       function install() {
+               $this->createOption('mailaddr', NP_CLAP_mailaddr, 'text', '');
+               $this->createOption('commentedOnly', NP_CLAP_commentedOnly, 'yesno', 'yes');
+               
+               $this->createOption('antispam_limit', NP_CLAP_antispam_limit, 'text', '10/86400');
+               $this->createOption('antispam_check', NP_CLAP_antispam_check, 'yesno', 'yes');
+               
+               $this->createOption('deleteData', NP_CLAP_deleteData, 'yesno', 'no');
+               
+               /* Create tables */
+               sql_query("
+                       CREATE TABLE IF NOT EXISTS 
+                               ".sql_table('plugin_clap').'
+                       (
+                               `id`        INT(11) NOT NULL AUTO_INCREMENT,
+                               `itemkey`   CHAR(11), 
+                               `timestamp` DATETIME, 
+                               `ipaddr`    CHAR(15), 
+                               PRIMARY KEY (`id`),
+                               INDEX itemkey_timestamp (`itemkey`, `timestamp`),
+                               INDEX ipaddr_timestamp (`ipaddr`, `timestamp`)
+                       )
+               ');
+               sql_query("
+                       CREATE TABLE IF NOT EXISTS 
+                               ".sql_table('plugin_clap_comment').'
+                       (
+                               `id` INT(11) NOT NULL,
+                               `user` VARCHAR(255),                            
+                               `mail_or_url` VARCHAR(255), 
+                               `comment` TEXT, 
+                               PRIMARY KEY (`id`)
+                       )
+               ');
+               sql_query("
+                       CREATE TABLE IF NOT EXISTS 
+                               ".sql_table('plugin_clap_thanks').'
+                       (
+                               `id` INT(11) NOT NULL AUTO_INCREMENT,
+                               `image` TEXT, 
+                               `comment` TEXT, 
+                               PRIMARY KEY (`id`)
+                       )
+               ');
+               
+               sql_query("
+                       CREATE TABLE IF NOT EXISTS 
+                               ".sql_table('plugin_clap_thanks_category').'
+                       (
+                               `category` VARCHAR(255),
+                               `thanksid` INT(11),
+                               INDEX category_idx (`category`),
+                               INDEX thanksid_idx (`thanksid`)
+                       )
+               ');
+       }
+       
+       function uninstall() {
+               if($this->getOption('deleteData') == "yes") {
+                       sql_query("DROP TABLE ".sql_table('plugin_clap'));
+                       sql_query("DROP TABLE ".sql_table('plugin_clap_comment'));
+                       sql_query("DROP TABLE ".sql_table('plugin_clap_thanks'));
+                       sql_query("DROP TABLE ".sql_table('plugin_clap_thanks_category'));
+               }
+       }
+       
+       function getTableList() {
+               return array(   
+                       sql_table('plugin_clap'),
+                       sql_table('plugin_clap_comment'),
+                       sql_table('plugin_clap_thanks'),
+                       sql_table('plugin_clap_thanks_category'),
+               );
+       }
+       
+       function getEventList() {
+               return array('QuickMenu');
+       }
+
+       function getMinNucleusVersion() { return 320; }
+       function getMinNucleusPatchLevel() { return 0; }
+       
+       // a description to be shown on the installed plugins listing
+       function getDescription() {
+               return '[$Revision: 1.1 $]<br />'.NP_CLAP_description ;
+       }
+       
+       function supportsFeature($what) {
+               switch($what){
+                       case 'SqlTablePrefix':
+                       case 'HelpPage':
+                               return 1;
+                                       default:
+                               return 0;
+               }
+       }
+
+       function hasAdminArea() { return 1; }
+
+       function event_QuickMenu(&$data) {
+               global $member, $nucleus, $blogid;
+               
+               // only show to admins
+               if (!$member->isLoggedIn() || !$member->isAdmin()) return;
+
+               array_push(
+                       $data['options'],
+                       array(
+                               'title' => 'Clap',
+                               'url' => $this->getAdminURL(),
+                               'tooltip' => 'Manage your clap'
+                       )
+               );
+       }
+       
+    function init(){
+               // include language file for this plugin 
+               $language = ereg_replace( '[\\|/]', '', getLanguageName()); 
+               if (file_exists($this->getDirectory().'language/'.$language.'.php')) 
+                       @ include_once($this->getDirectory().'language/'.$language.'.php');
+    }
+       
+       function doAction($type) {
+               global $itemid, $member, $manager;
+               $aActionsNotToCheck = array(
+                       '',
+                       'clap',
+                       'preview',
+               );
+               if (!in_array($type, $aActionsNotToCheck)) {
+                       if (!$manager->checkTicket()) return _ERROR_BADTICKET;
+               }
+               
+               $key = requestVar('key') ? requestVar('key') : false;
+               if(!$key){
+                       # $key = $itemid  ? $itemid : NP_CLAP_GLOBALKEY;
+               }
+               switch ($type) {
+                       case 'preview':
+                               if( $member->isLoggedIn() ){
+                                       $id = requestVar('id');
+                                       if( ! is_numeric($id) ){
+                                               $id = null;
+                                       }
+                                       $this->showPreview($id);
+                               } else {
+                                       return _ERROR_DISALLOWED;
+                               }
+                               break;
+                       break;
+                       case 'clap':
+                               $this->doClap($key);
+                               break;
+                               
+                       case 'chart':
+                               $year = intRequestVar('year');
+                               $month = intRequestVar('month');
+                               $this->echoChartJs($year, $month);
+                               break;
+                               
+                       // other actions result in an error
+                       case '':
+                       default:
+                               return 'Unexisting action: ' . $type;
+               }
+               return '';
+       }
+       
+       function doTemplateVar(&$item, $what = '', $key = '') {
+               $key = $key ? $key : $item->itemid;
+               $this->doSkinVar('template', $what, $key);
+       }
+
+       function doSkinVar($skinType, $type = '') {
+               global $itemid;
+               if( $type != 'list'){
+                       list(,,$key) = func_get_args();
+                       if( ! $key ){
+                               $key = $itemid  ? $itemid : NP_CLAP_GLOBALKEY;
+                       }
+               } else {
+                       list(,,$count,$blog,$order,$numOfDays) = func_get_args();
+                       $count = $count ? $count : 10;
+                       if( $blog ){
+                               $blog = strtr($blog, '/', ',');
+                       }
+                       $order = $order ? $order : 'DESC';
+                       $numOfDays = is_numeric($numOfDays) ? $numOfDays : false;
+               }
+               
+               switch ($type) {
+                       case 'button':
+                       case '':
+                               $this->showButton($key);
+                               break;
+                       case 'count':
+                               echo $this->getCount($key);
+                               break;
+                       case 'list':
+                               $this->showList($blog,$count,$order,$numOfDays);
+                               break;
+                       case 'actionurl':
+                               echo $this->getActionUrl($key);
+                               break;
+                       default:
+                               return 'Unexisting type: ' . $type;
+               }
+       }
+       
+       function echoChartJs($year = null, $month = null){
+               $year = intval($year) ? intval($year) : date('Y');
+               $month = intval($month) ? intval($month) : date('m');
+               
+               $fromDate = date("Y-m-d H:i:s", mktime( 0, 0, 0, $month, 1 , $year));
+               $toDate = date("Y-m-d H:i:s", mktime( 23, 59, 59, $month+1, 0 , $year));
+               
+               $param = array();
+               
+               // keys
+               $param['key'] = array();
+               $query = sprintf('SELECT itemkey, count(*) as count, count(DISTINCT ipaddr) as ipcount, count(c.id) as msgcount FROM ' . sql_table('plugin_clap') 
+                       . " LEFT OUTER JOIN " . sql_table('plugin_clap_comment')  . " c USING( id )  "
+                       . " WHERE `timestamp` between '%s' and '%s' "
+                       . " GROUP BY itemkey ORDER BY count DESC LIMIT 20"
+                       , mysql_real_escape_string( $fromDate )
+                       , mysql_real_escape_string( $toDate )
+               );
+               $res = sql_query($query);
+
+               while( $row = mysql_fetch_array($res) ){
+                       $param['key']['label'][] = $row['itemkey'];
+                       $param['key']['count'][] = $row['count'];
+                       $param['key']['ipcount'][] = $row['ipcount'];
+                       $param['key']['msgcount'][] = $row['msgcount'];
+                       if(!$param['key']['max'])
+                               $param['key']['max'] = $row['count'];
+               }
+               $param['key']['length'] = count($param['key']['label']);
+               if(!$param['key']['length']){
+                       $param['key']['label'][] = "";
+                       $param['key']['count'][] = 0;
+                       $param['key']['ipcount'][] = 0;
+                       $param['key']['msgcount'][] = 0;
+                       $param['key']['max'] = 10;
+               }
+
+               // dayOfMonth
+               $param['dayOfMonth'] = array();
+               $query = sprintf('SELECT DAYOFMONTH(`timestamp`) as day_of_month, count(*) as count, count(DISTINCT ipaddr) as ipcount, count(c.id) as msgcount FROM ' . sql_table('plugin_clap') 
+                       . " LEFT OUTER JOIN " . sql_table('plugin_clap_comment')  . " c USING( id )  "
+                       . " WHERE `timestamp` between '%s' and '%s' "
+                       . " GROUP BY day_of_month ORDER BY count"
+                       , mysql_real_escape_string( $fromDate )
+                       , mysql_real_escape_string( $toDate )
+               );
+               $res = sql_query($query);
+               
+               $lastDay = date("d", mktime( 23, 59, 59, $month+1, 0 , $year));
+               $param['dayOfMonth']['label'] = range(1, $lastDay );
+               $param['dayOfMonth']['count'] = array_fill(0, $lastDay, 0);
+               $param['dayOfMonth']['ipcount'] = array_fill(0, $lastDay, 0);
+               $param['dayOfMonth']['msgcount'] = array_fill(0, $lastDay, 0);
+               $param['dayOfMonth']['length'] = $lastDay;
+               while( $row = mysql_fetch_array($res) ){
+                       $idx = $row['day_of_month'] - 1;
+                       $param['dayOfMonth']['count'][$idx] = $row['count'];
+                       $param['dayOfMonth']['ipcount'][$idx] = $row['ipcount'];
+                       $param['dayOfMonth']['msgcount'][$idx] = $row['msgcount'];
+                       $param['dayOfMonth']['max'] = $row['count'];
+               }
+
+               // dayOfWeek
+               $param['dayOfWeek'] = array();
+               $query = sprintf('SELECT DAYOFWEEK(`timestamp`) as day_of_week, count(*) as count, count(DISTINCT ipaddr) as ipcount, count(c.id) as msgcount FROM ' . sql_table('plugin_clap') 
+                       . " LEFT OUTER JOIN " . sql_table('plugin_clap_comment')  . " c USING( id )  "
+                       . " WHERE `timestamp` between '%s' and '%s' "
+                       . " GROUP BY day_of_week ORDER BY count"
+                       , mysql_real_escape_string( $fromDate )
+                       , mysql_real_escape_string( $toDate )
+               );
+               $res = sql_query($query);
+               
+               $param['dayOfWeek']['label'] = explode(',', NP_CLAP_DAYOFWEEK);
+               $param['dayOfWeek']['count'] = array_fill(0, 7, 0);
+               $param['dayOfWeek']['ipcount'] = array_fill(0, 7, 0);
+               $param['dayOfWeek']['msgcount'] = array_fill(0, 7, 0);
+               $param['dayOfWeek']['length'] = 7;
+               while( $row = mysql_fetch_array($res) ){
+                       $idx = $row['day_of_week'] - 1;
+                       $param['dayOfWeek']['count'][$idx] = $row['count'];
+                       $param['dayOfWeek']['ipcount'][$idx] = $row['ipcount'];
+                       $param['dayOfWeek']['msgcount'][$idx] = $row['msgcount'];
+                       $param['dayOfWeek']['max'] = $row['count'];
+               }
+               
+               // hours
+               $param['hours'] = array();
+               $query = sprintf('SELECT HOUR(`timestamp`) as hour, count(*) as count, count(DISTINCT ipaddr) as ipcount, count(c.id) as msgcount FROM ' . sql_table('plugin_clap') 
+                       . " LEFT OUTER JOIN " . sql_table('plugin_clap_comment')  . " c USING( id )  "
+                       . " WHERE `timestamp` between '%s' and '%s' "
+                       . " GROUP BY hour ORDER BY count"
+                       , mysql_real_escape_string( $fromDate )
+                       , mysql_real_escape_string( $toDate )
+               );
+               $res = sql_query($query);
+               
+               $param['hours']['label'] = range(0, 24);
+               $param['hours']['count'] = array_fill(0, 24, 0);
+               $param['hours']['ipcount'] = array_fill(0, 24, 0);
+               $param['hours']['msgcount'] = array_fill(0, 24, 0);
+               $param['hours']['length'] = 24;
+               while( $row = mysql_fetch_array($res) ){
+                       $idx = $row['hour'];
+                       $param['hours']['count'][$idx] = $row['count'];
+                       $param['hours']['ipcount'][$idx] = $row['ipcount'];
+                       $param['hours']['msgcount'][$idx] = $row['msgcount'];
+                       $param['hours']['max'] = $row['count'];
+               }
+
+               // convert
+               mb_convert_variables('UTF-8', _CHARSET, $param);
+               echo Jsphon::encode($param);
+       }
+       
+       function doClap($key){
+               global $member;
+               
+               // spam check
+               $limit = !$key || $this->_spamcheck( requestVar('comment') . "\n" . requestVar('mail_or_url'). "\n" . requestVar('user')  );
+               if($limit){
+                       $this->showThanks($key, true);
+                       return;
+               }
+
+               list($maxcount, $lifetime) = explode('/', $this->getOption('antispam_limit'), 2);
+               if( !(is_numeric($maxcount) && is_numeric($lifetime)) ){
+                       $maxcount = 10;
+                       $lifetime = 86400;
+               }
+               
+               // count
+               $query = sprintf('SELECT count(id) as result FROM ' . sql_table('plugin_clap') 
+                               . " where ipaddr = '%s' and timestamp >  DATE_SUB(NOW(),INTERVAL %s SECOND);"
+                               , mysql_real_escape_string( serverVar('REMOTE_ADDR') )
+                               , mysql_real_escape_string( intval($lifetime) )
+               );
+               $count = quickQuery($query);
+               
+               if( (!$member->isLoggedIn()) && $count < $maxcount ){
+                       $query = sprintf('INSERT INTO ' . sql_table('plugin_clap') 
+                                       . '( itemkey, timestamp, ipaddr ) '
+                                       . "values('%s', NOW(), '%s')"
+                                       , mysql_real_escape_string( $key )
+                                       , mysql_real_escape_string( serverVar('REMOTE_ADDR') )
+                       );
+                       sql_query($query);
+                       
+                       if( trim(requestVar('comment')) ){
+                               $query = sprintf('INSERT INTO ' . sql_table('plugin_clap_comment') 
+                                               . '( id, user, mail_or_url, comment ) '
+                                               . "values(LAST_INSERT_ID(), '%s', '%s', '%s')"
+                                               , mysql_real_escape_string( trim(requestVar('user')))
+                                               , mysql_real_escape_string( trim(requestVar('mail_or_url')))
+                                               , mysql_real_escape_string( trim(requestVar('comment')))
+                               );
+                               sql_query($query);
+                       }
+               }
+               if( $count >= $maxcount ){
+                       $limit = true;
+               }
+               
+               // thanks page
+               $this->showThanks($key, $limit);
+               
+               // send mail
+               if( ($this->getOption('commentedOnly') == 'yes') && (!trim(requestVar('comment'))) ){
+                       return;
+               }
+               
+               if(!$limit){
+                       $vars = array(
+                               'user' => requestVar('user'),
+                               'comment' => requestVar('comment'),
+                               'mail_or_url' => requestVar('mail_or_url'),
+                               'key' => $key,
+                               'ipaddr' => serverVar('REMOTE_ADDR'),
+                               'hostname' => gethostbyaddr(serverVar('REMOTE_ADDR')),                  
+                               'useragent' => serverVar('HTTP_USER_AGENT'),
+                               'referer' => serverVar('HTTP_REFERER'),
+                       );
+                       $this->_notify($vars);
+               }
+       }
+       
+       function showThanks($key, $limit, $contentid = null){
+               global $blog, $CONF, $manager;
+               $cat = $this->getCatnameByKey($key);
+               $content = null;
+               $thanksids = array();
+               
+               if( !$contentid ){
+                       // random fetch
+                       $query = sprintf('SELECT thanksid FROM ' . sql_table('plugin_clap_thanks_category')
+                                       . " WHERE category = '%s'"
+                                       , mysql_real_escape_string( $cat )
+                       );
+                       $res = sql_query($query);
+                       while( $row = mysql_fetch_array($res) ){
+                               $thanksids[] = $row['thanksid'];
+                       }
+                       if($thanksids){
+                               shuffle($thanksids);
+                               $contentid = array_pop($thanksids);
+                       }
+               }
+               
+               $content = $this->getThanksMsg($contentid);
+               if( !$content ){
+                       while( $contentid = array_pop($thanksids) ){
+                               $content = $this->getThanksMsg($contentid);
+                               if( $content ){
+                                       $this->_correctBrokenThanksCategory();
+                                       break;
+                               }
+                       }
+                       
+                       if( !$content ){
+                               $content['comment'] = NP_CLAP_NOCONTENT;
+                       }
+               }
+               
+               $returnurl = requestVar('returnurl') ? trim(requestVar('returnurl')) : serverVar('HTTP_REFERER');
+               if( ! $returnurl ){
+                       if ($blog) { 
+                               $b =& $blog; 
+                       } else { 
+                               $b =& $manager->getBlog($CONF['DefaultBlog']); 
+                       } 
+                       $returnurl = $b->getURL();
+               }
+               
+               $vars = array(
+                       'charset' => _CHARSET,
+                       'img' => ($content['image']) ? $content['image'] : '',
+                       'text' => $content['comment'],
+                       'returnurl' => htmlspecialchars($returnurl, ENT_QUOTES),
+                       'actionurl' => $this->getActionUrl($key, false),
+                       'key' => htmlspecialchars($key, ENT_QUOTES),
+                       'type' => ($key == 'preview') ? 'preview' : 'clap',
+                       'contentid' => $content['id'],
+               );
+               
+               $tpl = $this->_getTemplateEngine();
+               if(!$limit)
+                       $page = $tpl->fetch('thanks', 'clap_'.$cat) 
+                               or $page = $tpl->fetch('thanks', strtolower(__CLASS__));
+               else
+                       $page = $tpl->fetch('forbidden', 'clap_'.$cat)
+                               or $page = $tpl->fetch('forbidden', strtolower(__CLASS__));
+                       
+               echo $tpl->fill($page, $vars, false);
+       }
+       
+       function getCatnameByKey($key){
+               $dir = '';
+               if( is_numeric($key) ){
+                       $dir .= $this->getCategoryIDFromItemID($key);
+               } else {
+                       $dir .= preg_replace('/[^A-Za-z0-9_.-]+/','', $key);
+               }
+               return $dir;
+       }
+       
+       function getCategoryIDFromItemID($itemid) {
+               return quickQuery('SELECT icat as result FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid) );
+       }
+               
+       function showPreview($id){
+               $this->showThanks('preview', false, $id);
+       }
+       
+       function showButton($key){
+               $tpl = $this->_getTemplateEngine();
+               $vars = array(
+                       'actionurl' => $this->getActionUrl($key),
+                       'actionurl_wo_key' => $this->getActionUrl($key,true,false),
+                       'key' => htmlspecialchars($key, ENT_QUOTES),
+                       'count' => $this->getCount($key),
+               );
+               $button = $tpl->fetch('button', strtolower(__CLASS__));
+               echo $tpl->fill($button, $vars, false);
+       }
+       
+       function getCount($key){
+               $query = sprintf('SELECT count(id) as result FROM ' . sql_table('plugin_clap') 
+                               . " where itemkey = '%s'"
+                               , mysql_real_escape_string( $key )
+               );
+               return quickQuery($query);
+       }
+       
+       function getBloglist(){
+               $query = 'SELECT bnumber, bname FROM ' . sql_table('blog');
+               $res = sql_query($query);
+               $list = array();
+               while( $row = mysql_fetch_array($res) ){
+                       list($blogid, $blogname) = $row;
+                       $list[$blogid] = $blogname; 
+               }
+               return $list;
+       }
+       
+       function getOverview($blog = null, $offset = '0', $itemperpage = '20'){         
+               if(! $blog ){
+                       $query = sprintf('SELECT itemkey as `key`, ititle as title, inumber as itemid, iblog as blog, count(id) as count FROM ' . sql_table('plugin_clap') . ' left outer join ' . sql_table('item')
+                                       . " on itemkey = inumber group by `key`, title, itemid order by count DESC limit %s,%s"
+                                       , mysql_real_escape_string( intval($offset) )
+                                       , mysql_real_escape_string( intval($itemperpage) )              
+                       );
+               } elseif( $blog == 'global' ){
+                       $query = sprintf('SELECT itemkey as `key`, ititle as title, inumber as itemid, iblog as blog, count(id) as count FROM ' . sql_table('plugin_clap') . ' left outer join ' . sql_table('item')
+                                       . " on itemkey = inumber where inumber is null group by `key`, title, itemid order by blog, count DESC limit %s,%s"
+                                       , mysql_real_escape_string( intval($offset) )
+                                       , mysql_real_escape_string( intval($itemperpage) )              
+                       );
+               } else {
+                       $query = sprintf('SELECT itemkey as `key`, ititle as title, inumber as itemid, iblog as blog, count(id) as count FROM ' . sql_table('plugin_clap') . ' left outer join ' . sql_table('item')
+                                       . " on itemkey = inumber where iblog = %s group by `key`, title, itemid order by blog, count DESC limit %s,%s"
+                                       , mysql_real_escape_string( intval($blog) )
+                                       , mysql_real_escape_string( intval($offset) )
+                                       , mysql_real_escape_string( intval($itemperpage) )              
+                       );
+               }
+               return sql_query($query);
+       }
+
+       function getDetail($key, $offset = '0', $itemperpage = '20'){           
+               $query = sprintf('SELECT c.id, `timestamp`, ipaddr, user, mail_or_url, comment FROM ' . sql_table('plugin_clap') . ' as c left outer join ' . sql_table('plugin_clap_comment')
+                               . " as m on c.id = m.id where itemkey = '%s' order by `timestamp` DESC limit %s,%s"
+                               , mysql_real_escape_string( $key )
+                               , mysql_real_escape_string( intval($offset) )
+                               , mysql_real_escape_string( intval($itemperpage) )              
+               );
+               return sql_query($query);
+       }
+       
+       function deleteClap($id){
+               $query = sprintf('DELETE FROM ' . sql_table('plugin_clap')
+                               . " where id = %s limit 1"
+                               , mysql_real_escape_string( intval($id) )
+               );
+               sql_query($query);
+               $query = sprintf('DELETE FROM ' . sql_table('plugin_clap_comment')
+                               . " where id = %s limit 1"
+                               , mysql_real_escape_string( intval($id) )
+               );
+               sql_query($query);
+       }
+       
+       function getMessagelist($offset = '0', $itemperpage = '20'){            
+               $query = sprintf('SELECT itemkey as `key`,`timestamp`, ipaddr, user, mail_or_url, comment FROM ' . sql_table('plugin_clap') . ' as c, ' . sql_table('plugin_clap_comment')
+                               . " as m where c.id = m.id order by `timestamp` DESC limit %s,%s"
+                               , mysql_real_escape_string( intval($offset) )
+                               , mysql_real_escape_string( intval($itemperpage) )              
+               );
+               return sql_query($query);
+       }
+       \r       function getThanksMsgList($offset = '0', $itemperpage = '20'){          
+               $query = sprintf('SELECT * FROM ' . sql_table('plugin_clap_thanks')
+                               . " order by id DESC limit %s,%s"
+                               , mysql_real_escape_string( intval($offset) )
+                               , mysql_real_escape_string( intval($itemperpage) )              
+               );
+               return sql_query($query);
+       }
+       
+       function getAssociatedCategoriesByThanksId($thanksid){
+               $query = sprintf('SELECT category FROM ' . sql_table('plugin_clap_thanks_category')
+                               . " WHERE thanksid = %s"
+                               , mysql_real_escape_string( intval($thanksid) )
+               );
+               $res = sql_query($query);
+               
+               $list = array();
+               while( $row = mysql_fetch_assoc($res) ){
+                       $list[] = $row['category']; 
+               }
+               return $list;
+       }
+       \r       function getThanksMsg($id){
+               $query = sprintf('SELECT * FROM ' . sql_table('plugin_clap_thanks') 
+                               . " where id = %s limit 1"
+                               , mysql_real_escape_string( intval($id) )
+               );
+               $res = sql_query($query);
+               return mysql_fetch_assoc($res);
+       }
+
+       function deleteThanksMsg($id){
+               $query = sprintf('DELETE FROM ' . sql_table('plugin_clap_thanks')
+                               . " where id = %s limit 1"
+                               , mysql_real_escape_string( intval($id) )
+               );
+               sql_query($query);
+               $query = sprintf('DELETE FROM ' . sql_table('plugin_clap_thanks_category')
+                               . " where thanksid = %s"
+                               , mysql_real_escape_string( intval($id) )
+               );
+               sql_query($query);
+       }
+
+       function setThanksMsg($msg){
+               if( $msg['id'] == 'new'){               \r                       $query = sprintf('INSERT INTO ' . sql_table('plugin_clap_thanks') 
+                                               . ' ( image, comment ) '
+                                               . " values('%s', '%s')"
+                                               , mysql_real_escape_string( $msg['image'] )
+                                               , mysql_real_escape_string( $msg['comment']  )
+                       );
+               } else {
+                       $query = sprintf('UPDATE ' . sql_table('plugin_clap_thanks') 
+                                               . " SET image = '%s', comment = '%s' where id = %s limit 1"
+                                               , mysql_real_escape_string( $msg['image'] )
+                                               , mysql_real_escape_string( $msg['comment'] )
+                                               , mysql_real_escape_string( intval($msg['id']) )
+                       );
+               }
+               sql_query($query);
+       }
+       
+       function setAssociatedCategories($thanksid, $assoc, $assoc_etc = ''){
+               $query = sprintf('DELETE FROM ' . sql_table('plugin_clap_thanks_category')
+                               . " where thanksid = %s"
+                               , mysql_real_escape_string( intval($thanksid) )
+               );
+               sql_query($query);
+               
+               $etc = explode(',', $assoc_etc);
+               if($etc) $assoc = array_merge($assoc, $etc);
+               
+               $assoc = array_map("trim", $assoc);
+               $assoc = array_filter($assoc);
+               
+               foreach ($assoc as $c) {
+                       $query = sprintf('INSERT INTO ' . sql_table('plugin_clap_thanks_category') 
+                                               . ' ( category, thanksid ) '
+                                               . " values('%s', %s)"
+                                               , mysql_real_escape_string( $c )
+                                               , mysql_real_escape_string( intval($thanksid) )
+                       );
+                       sql_query($query);
+               }
+       }
+       
+       function showList($bloglist = null, $count = '10', $order = 'DESC', $numOfDays = false){
+               
+               $where = '';
+               if( $numOfDays){
+                       $where .= sprintf(' and `timestamp` > DATE_ADD(now(), INTERVAL -%s DAY)'
+                               , mysql_real_escape_string( intval($numOfDays) )
+                       );
+               }
+               if( $bloglist ){
+                       $where .= sprintf(" and iblog in (%s) and itemkey <> '%s'"
+                               , mysql_real_escape_string( $bloglist )
+                               , mysql_real_escape_string( NP_CLAP_GLOBALKEY )
+                       );
+               } else {
+                       $where .= sprintf(" and itemkey <> '%s'"
+                               , mysql_real_escape_string( NP_CLAP_GLOBALKEY )
+                       );              
+               }
+               
+               $query = sprintf('SELECT itemkey as `key`, ititle as title, inumber as itemid, count(id) as count FROM ' . sql_table('plugin_clap') . ', ' . sql_table('item')
+                               . " where itemkey = inumber %s group by `key`, title, itemid order by count %s limit %s"
+                               , $where 
+                               , mysql_real_escape_string( $order )
+                               , mysql_real_escape_string( intval($count) )
+               );
+               $res = sql_query($query);
+               
+               $tpl = $this->_getTemplateEngine();
+               echo $tpl->fetch('list_header', strtolower(__CLASS__));
+               
+               $item = $tpl->fetch('list_item', strtolower(__CLASS__));
+               while( $row = mysql_fetch_assoc($res) ){
+                       $row['title'] = shorten(strip_tags($row['title']),30,'...');
+                       $row['itemlink'] = createItemLink($row['itemid'], '');
+                       echo $tpl->fill($item, $row, false);
+               }
+               
+               echo $tpl->fetch('list_footer', strtolower(__CLASS__));
+       }
+       
+       function getActionUrl($key, $withQuery = true, $withKey = true){
+               global $CONF;
+               $url = $CONF['ActionURL'];
+               if($withQuery){
+                       $url .= '?action=plugin&amp;name=Clap&amp;type=clap';
+                       if($withKey){
+                               $url .= '&amp;key='.htmlspecialchars($key, ENT_QUOTES);
+                       }
+               }
+               return $url;
+       }
+       
+       function _getTemplateEngine(){
+               if( ! $this->templateEngine )
+                       $this->templateEngine =& new cles_Template(dirname(__FILE__).'/clap/template');
+               return $this->templateEngine;
+       }
+       
+       function _notify($vars){
+               global $CONF, $DIR_LIBS, $member;
+               $destAddress = trim($this->getOption('mailaddr'));
+               if ( ! $destAddress ) return;
+               
+               if (!class_exists('notification'))
+                       include($DIR_LIBS . 'NOTIFICATION.php');
+                       
+               $tpl = $this->_getTemplateEngine();
+               
+               $msg = $tpl->fetch('mail_body', strtolower(__CLASS__), 'txt');
+               $msg = $tpl->fill($msg, $vars, null);
+               
+               $subject = $tpl->fetch('mail_subject', strtolower(__CLASS__), 'txt');
+               $subject = $tpl->fill($subject, $vars, false);
+               
+               $notify =& new NOTIFICATION($destAddress);
+               $notify->notify($subject, $msg , $CONF['AdminEmail']);
+       }
+       
+       function _spamcheck($text = ''){
+               if($this->getOption('antispam_check') == "yes") {
+                       global $itemid, $manager;
+                       
+                       $spamcheck = array (
+                           'type' => 'clap',
+                           'body' => $text,
+                           'author' => '',
+                           'url' => '',
+                           'id' => $itemid,
+                               'return'        => true,
+                               'live'          => true,
+                               
+                               /* Backwards compatibility with SpamCheck API 1*/
+                               'data'          => $text,
+                               'ipblock'   => true,
+                       );
+                       
+                       $manager->notify('SpamCheck', array ('spamcheck' => & $spamcheck));
+                       if (isset($spamcheck['result']) && $spamcheck['result'] == true){
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       function _correctBrokenThanksCategory(){
+               $query = 'SELECT tc.* FROM ' . sql_table('plugin_clap_thanks_category') . ' tc'
+                               . ' LEFT OUTER JOIN ' . sql_table('plugin_clap_thanks') . ' t ON tc.thanksid = t.id'
+                               . ' WHERE id IS NULL';
+               $res = sql_query($query);
+               
+               $count = 0;
+               while( $row = mysql_fetch_assoc($res) ){
+                       $query = sprintf('DELETE FROM ' . sql_table('plugin_clap_thanks_category')
+                                       . " WHERE category = %s and thanksid = %s limit 1"
+                                       , mysql_real_escape_string( intval($row['category']) )
+                                       , mysql_real_escape_string( intval($row['thanksid']) )
+                       );
+                       sql_query($query);
+                       $count++;
+               }
+               
+               $msg = sprintf(NP_CLAP_corrected, $count);
+               $this->_warn($msg);
+               return $msg;
+       }
+       
+       function _info($msg) {
+               if ($this->getOption('debug') == 'yes') {
+                       ACTIONLOG :: add(INFO, 'Clap: '.$msg);
+               }
+       }
+
+       function _warn($msg) {
+               ACTIONLOG :: add(WARNING, 'Clap: '.$msg);
+       }
+}
+
diff --git a/trunk/NP_Clap/clap/chart/canvaschart.css b/trunk/NP_Clap/clap/chart/canvaschart.css
new file mode 100644 (file)
index 0000000..d55811e
--- /dev/null
@@ -0,0 +1,33 @@
+.chart {
+       font: menu;
+       background: white;
+       color: black;
+       overflow: hidden;
+       position: relative;
+       line-height: normal;
+       font-size: x-small;
+}
+
+.chart .legend {
+       float: left;
+       border: 1px solid black;
+       background: white;
+       padding: 5px 10px 5px 10px;
+       line-height: normal;
+}
+
+.chart .legend ul {
+       margin: 0px;
+       padding: 0px 0px 0px 20px;
+       line-height: normal;
+}
+
+.chart .legend ul li {
+       list-style: square;
+       line-height: normal;
+}
+
+.chart .legend ul li span {
+       color: black;
+       line-height: normal;
+}
diff --git a/trunk/NP_Clap/clap/chart/canvaschartpainter.js b/trunk/NP_Clap/clap/chart/canvaschartpainter.js
new file mode 100644 (file)
index 0000000..0750637
--- /dev/null
@@ -0,0 +1,339 @@
+/*----------------------------------------------------------------------------\
+|                                  Chart 1.0                                  |
+|                            Canvas Chart Painter                             |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|-----------------------------------------------------------------------------|
+| Canvas implementation of the chart painter API. A canvas element is used to |
+| draw the chart,  html elements are used for the legend and  axis labels as, |
+| at the time being, there is no text support in canvas.                      |
+|-----------------------------------------------------------------------------|
+|                      Copyright (c) 2006 Emil A Eklund                       |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| 2006-01-03 | Work started.                                                  |
+| 2006-01-05 | Added legend and axis labels. Changed the painter api slightly |
+|            | to allow two-stage initialization (required for ie/canvas) and |
+|            | added legend/axis related methods. Also updated bar chart type |
+|            | and added a few options, mostly related to bar charts.         |
+| 2006-01-07 | Updated chart size calculations to take legend and axis labels |
+|            | into consideration.  Split painter implementations to separate |
+|            | files.                                                         |
+| 2006-04-16 | Updated to use the  ExplorerCanvas ie emulation  layer instead |
+|            | of the, now deprecated, IECanvas one.                          |
+|-----------------------------------------------------------------------------|
+| Created 2006-01-03 | All changes are in the log above. | Updated 2006-04-16 |
+\----------------------------------------------------------------------------*/
+
+function CanvasChartPainterFactory() {
+       return new CanvasChartPainter();
+}
+
+
+function CanvasChartPainter() {
+       this.base = AbstractChartPainter;
+};
+
+
+CanvasChartPainter.prototype = new AbstractChartPainter;
+
+
+CanvasChartPainter.prototype.create = function(el) {
+       while (el.firstChild) { el.removeChild(el.lastChild); }
+
+       this.el = el;
+       this.w = el.clientWidth;
+       this.h = el.clientHeight;
+
+       this.canvas = document.createElement('canvas');
+       this.canvas.width  = this.w;
+       this.canvas.height = this.h;
+       this.canvas.style.width  = this.w + 'px';
+       this.canvas.style.height = this.h + 'px';
+
+       el.appendChild(this.canvas);
+       
+       /* Init explorercanvas emulation for IE */
+       if ((!this.canvas.getContext) && (typeof G_vmlCanvasManager != "undefined")) {
+               this.canvas = G_vmlCanvasManager.initElement(this.canvas);
+       }
+};
+
+
+CanvasChartPainter.prototype.init = function(xlen, ymin, ymax, xgd, ygd, bLegendLabels) {
+       this.ctx = this.canvas.getContext('2d');
+
+       this.chartx = 0;
+       this.chartw     = this.w;
+       this.charth     = this.h;
+       this.charty = 0;
+       
+       this.xlen = xlen;
+       this.ymin = ymin;
+       this.ymax = ymax;
+       this.xgd  = xgd;
+       this.ygd  = ygd;
+
+       this.calc(this.chartw, this.charth, xlen, ymin, ymax, xgd, ygd);
+};
+
+
+CanvasChartPainter.prototype.drawLegend = function(series) {
+       var legend, list, item, label;
+
+       legend = document.createElement('div');
+       legend.className = 'legend';
+       legend.style.position = 'absolute';
+       list = document.createElement('ul');
+
+       for (i = 0; i < series.length; i++) {
+               item = document.createElement('li');
+               item.style.color = series[i].color;
+               label = document.createElement('span');
+               label.appendChild(document.createTextNode(series[i].label));
+               label.style.color = 'black';
+               item.appendChild(label);
+               list.appendChild(item);
+       }
+       legend.appendChild(list);
+       this.el.appendChild(legend);
+       legend.style.right = '0px';
+       legend.style.top  = this.charty + (this.charth / 2) - (legend.offsetHeight / 2) + 'px';
+       this.legend = legend;
+       
+       /* Recalculate chart width and position based on labels and legend */
+       this.chartw     = this.w - (this.legend.offsetWidth + 5);
+       
+       this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
+};
+
+
+CanvasChartPainter.prototype.drawVerticalAxis = function(ygd, precision) {
+       var axis, item, step, y, ty, n, yoffset, value, multiplier, w, items, pos;
+
+       /* Calculate step size and rounding precision */
+       multiplier = Math.pow(10, precision);
+       step       = this.range / (ygd - 1);
+
+       /* Create container */
+       axis = document.createElement('div');
+       axis.style.position = 'absolute';
+       axis.style.left  = '0px';
+       axis.style.top   = '0px';
+       axis.style.textAlign = 'right';
+       this.el.appendChild(axis);
+
+       /* Draw labels and points */
+       this.ctx.fillStyle = 'black';
+       w = 0;
+       items = new Array();
+       for (n = 0, i = this.ymax; (i > this.ymin) && (n < ygd - 1); i -= step, n++) {
+               item = document.createElement('span');
+               value = parseInt(i * multiplier) / multiplier;
+               item.appendChild(document.createTextNode(value));
+               axis.appendChild(item);
+               items.push([i, item]);
+               if (item.offsetWidth > w) { w = item.offsetWidth; }
+       }
+
+       /* Draw last label and point (lower left corner of chart) */
+       item = document.createElement('span');
+       item.appendChild(document.createTextNode(this.ymin));
+       axis.appendChild(item);
+       items.push([this.ymin, item]);
+       if (item.offsetWidth > w) { w = item.offsetWidth; }
+       
+       /* Set width of container to width of widest label */
+       axis.style.width = w + 'px';
+       
+       /* Recalculate chart width and position based on labels and legend */
+       this.chartx = w + 5;
+       this.charty = item.offsetHeight / 2;
+       this.charth = this.h - ((item.offsetHeight * 1.5) + 5);
+       this.chartw     = this.w - (((this.legend)?this.legend.offsetWidth:0) + w + 10);
+       this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
+       
+       /* Position labels on the axis */
+       n          = this.range / this.charth;
+       yoffset    = (this.ymin / n);
+       for (i = 0; i < items.length; i++) {
+               item = items[i][1];
+               pos = items[i][0];
+               if (pos == this.ymin) { y = this.charty + this.charth - 1; }
+               else { y = this.charty + (this.charth - (pos / n) + yoffset); }
+               this.ctx.fillRect(this.chartx - 5, y, 5, 1);
+               ty = y - (item.offsetHeight/2);
+               item.style.position = 'absolute';
+               item.style.right = '0px';
+               item.style.top   = ty + 'px';
+}      };
+
+
+CanvasChartPainter.prototype.drawHorizontalAxis = function(xlen, labels, xgd, precision) {
+       var axis, item, step, x, tx, n, multiplier;
+
+       /* Calculate offset, step size and rounding precision */
+       multiplier = Math.pow(10, precision);
+       n          = this.chartw / (xgd - 1);
+
+       /* Create container */
+       axis = document.createElement('div');
+       axis.style.position = 'absolute';
+       axis.style.left   = '0px';
+       axis.style.top    = (this.charty + this.charth + 5) + 'px';
+       axis.style.width  = this.w + 'px';
+       this.el.appendChild(axis);
+
+       /* Draw labels and points */
+       this.ctx.fillStyle = 'black';
+       for (i = 0; i < xgd; i++) {
+               item = document.createElement('span');
+               item.appendChild(document.createTextNode(labels[i]));
+               axis.appendChild(item);
+               x = this.chartx + (n * i);
+               tx = x - (item.offsetWidth/2)
+               item.style.position = 'absolute';
+               item.style.left = tx + 'px';
+               item.style.top  = '0px';
+               this.ctx.fillRect(x, this.charty + this.charth, 1, 5);
+}      };
+
+
+CanvasChartPainter.prototype.drawAxis = function() {
+       this.ctx.fillStyle = 'black';
+       this.ctx.fillRect(this.chartx, this.charty, 1, this.charth-1);
+       this.ctx.fillRect(this.chartx, this.charty + this.charth - 1, this.chartw+1, 1);
+};
+
+
+CanvasChartPainter.prototype.drawBackground = function() {
+       this.ctx.fillStyle = 'white';
+       this.ctx.fillRect(0, 0, this.w, this.h);
+};
+
+
+CanvasChartPainter.prototype.drawChart = function() {
+       this.ctx.fillStyle = 'silver';
+       if (this.xgrid) {
+               for (i = this.xgrid; i < this.chartw; i += this.xgrid) {
+                       this.ctx.fillRect(this.chartx + i, this.charty, 1, this.charth-1);
+       }       }
+       if (this.ygrid) {
+               for (i = this.charth - this.ygrid; i > 0; i -= this.ygrid) {
+                       this.ctx.fillRect(this.chartx + 1, this.charty + i, this.chartw, 1);
+}      }       };
+
+
+CanvasChartPainter.prototype.drawArea = function(color, values) {
+       var i, len, x, y, n, yoffset;
+
+       /* Determine distance between points and offset */
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+               this.ctx.fillStyle = color;
+
+               /* Begin line in lower left corner */
+               x = this.chartx + 1;
+               this.ctx.beginPath();
+               this.ctx.moveTo(x, this.charty + this.charth - 1);
+
+               /* Determine position of first point and draw it */
+               y = this.charty + this.charth - (values[0] / n) + yoffset;
+               this.ctx.lineTo(x, y);
+
+               /* Draw lines to succeeding points */
+               for (i = 1; i < len; i++) {
+                       y = this.charty + this.charth - (values[i] / n) + yoffset;
+                       x += this.xstep;
+                       this.ctx.lineTo(x, y);
+               }
+
+               /* Close path and fill it */
+               this.ctx.lineTo(x, this.charty + this.charth - 1);
+               this.ctx.closePath();
+               this.ctx.fill();
+}      };
+
+
+CanvasChartPainter.prototype.drawLine = function(color, values) {
+       var i, len, x, y, n, yoffset;
+
+       /* Determine distance between points and offset */
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+               this.ctx.lineWidth   = 1;
+               this.ctx.strokeStyle = color;
+
+               /* Determine position of first point and draw it */
+               x = this.chartx + 1;
+               y = this.charty + this.charth - (values[0] / n) + yoffset;
+               this.ctx.beginPath();
+               this.ctx.moveTo(x, y);
+
+               /* Draw lines to succeeding points */
+               for (i = 1; i < len; i++) {
+                       y = this.charty + this.charth - (values[i] / n) + yoffset;
+                       x += this.xstep;
+                       this.ctx.lineTo(x, y);
+               }
+
+               /* Stroke path */
+               this.ctx.stroke();
+}      };
+
+
+CanvasChartPainter.prototype.drawBars = function(color, values, xlen, xoffset, width) {
+       var i, len, x, y, n, yoffset;
+
+       /* Determine distance between points and offset */
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len > xlen) { len = xlen; }
+       if (len) {
+               this.ctx.fillStyle = color;
+
+               /* Determine position of each bar and draw it */
+               x = this.chartx + xoffset + 1;
+               for (i = 0; i < len; i++) {
+                       y = this.charty + this.charth - (values[i] / n) + yoffset;
+
+                       this.ctx.beginPath();
+                       this.ctx.moveTo(x, this.charty + this.charth-1);
+                       this.ctx.lineTo(x, y );
+                       this.ctx.lineTo(x+width, y);
+                       this.ctx.lineTo(x+width, this.charty + this.charth-1);
+                       this.ctx.closePath();
+                       this.ctx.fill();
+
+                       x += this.xstep;
+}      }       };
diff --git a/trunk/NP_Clap/clap/chart/chart.js b/trunk/NP_Clap/clap/chart/chart.js
new file mode 100644 (file)
index 0000000..17e6090
--- /dev/null
@@ -0,0 +1,309 @@
+/*----------------------------------------------------------------------------\
+|                                  Chart 1.0                                  |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|-----------------------------------------------------------------------------|
+| Client side chart painter, supports line, area and bar charts and stacking, |
+| uses Canvas (mozilla,  safari,  opera) or SVG (mozilla, opera) for drawing. |
+| Can be used with IECanvas to allow the canvas painter to be used in IE.     |
+|-----------------------------------------------------------------------------|
+|                      Copyright (c) 2006 Emil A Eklund                       |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| Dependencies: canvaschartpainter.js  - Canvas chart painter implementation. |
+|               canvaschart.css        - Canvas chart painter styles.         |
+|           or: svgchartpainter.js     - SVG chart painter implementation.    |
+|-----------------------------------------------------------------------------|
+| 2006-01-03 | Work started.                                                  |
+| 2006-01-05 | Added legend and axis labels. Changed the painter api slightly |
+|            | to allow two-stage initialization (required for ie/canvas) and |
+|            | added legend/axis related methods. Also updated bar chart type |
+|            | and added a few options, mostly related to bar charts.         |
+| 2006-01-07 | Updated chart size calculations to take legend and axis labels |
+|            | into consideration.  Split painter implementations to separate |
+|            | files.                                                         |
+| 2006-01-10 | Fixed bug in automatic range calculation.  Also added explicit |
+|            | cast to float for stacked series.                              |
+| 2006-04-16 | Updated constructor to set painter factory  based on available |
+|            | and supported implementations.                                 |
+|-----------------------------------------------------------------------------|
+| Created 2006-01-03 | All changes are in the log above. | Updated 2006-04-16 |
+\----------------------------------------------------------------------------*/
+
+var CHART_LINE    =  1;
+var CHART_AREA    =  2;
+var CHART_BAR     =  3;
+var CHART_STACKED =  4;
+
+/*----------------------------------------------------------------------------\
+|                                    Chart                                    |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Chart class, control class that's used to represent a chart. Uses a painter |
+| class for the actual drawing.  This is the only  class that should be  used |
+| directly, the other ones are internal.                                      |
+\----------------------------------------------------------------------------*/
+
+function Chart(el) {
+       this._cont             = el;
+       this._yMin             = null;
+       this._yMax             = null;
+       this._xGridDensity     = 0;
+       this._yGridDensity     = 0;
+       this._flags            = 0;
+       this._series           = new Array();
+       this._labelPrecision   = 0;
+       this._horizontalLabels = new Array();
+       this._barWidth         = 10;
+       this._barDistance      = 2;
+       this._bars             = 0;
+       this._showLegend       = true;
+       
+       /*
+        * Determine painter implementation to use based on what's available and
+        * supported. CanvasChartPainter is the prefered one, JsGraphicsChartPainter
+        * the fallback one as it works in pretty much any browser. The
+        * SVGChartPainter implementation one will only be used if set explicitly as
+        * it's not up to pair with the other ones.
+        */
+       if ((typeof CanvasChartPainterFactory != 'undefined') && (window.CanvasRenderingContext2D)) {
+               this._painterFactory = CanvasChartPainterFactory;
+       }
+       else if (typeof JsGraphicsChartPainterFactory != 'undefined') {
+               this._painterFactory = JsGraphicsChartPainterFactory;
+       }
+       else { this._painterFactory = null; }
+}
+
+
+Chart.prototype.setPainterFactory = function(f) {
+       this._painterFactory = f;
+};
+
+
+Chart.prototype.setVerticalRange = function(min, max) {
+       this._yMin = min;
+       this._yMax = max;
+};
+
+
+Chart.prototype.setLabelPrecision = function(precision) {
+       this._labelPrecision = precision;
+};
+
+
+Chart.prototype.setShowLegend = function(b) {
+       this._showLegend = b;
+};
+
+
+Chart.prototype.setGridDensity = function(horizontal, vertical) {
+       this._xGridDensity = horizontal;
+       this._yGridDensity = vertical;
+};
+
+
+Chart.prototype.setHorizontalLabels = function(labels) {
+       this._horizontalLabels = labels;
+};
+
+
+Chart.prototype.setDefaultType = function(flags) {
+       this._flags = flags;
+};
+
+
+Chart.prototype.setBarWidth = function(width) {
+       this._barWidth = width;
+};
+
+
+Chart.prototype.setBarDistance = function(distance) {
+       this._barDistance = distance;
+};
+
+
+Chart.prototype.add = function(label, color, values, flags) {
+       var o, offset;
+
+       if (!flags) { flags = this._flags; }
+       if ((flags & CHART_BAR) == CHART_BAR) { offset = this._barDistance + this._bars * (this._barWidth + this._barDistance); this._bars++; }
+       else { offset = 0; }
+       o = new ChartSeries(label, color, values, flags, offset);
+
+       this._series.push(o);
+};
+
+
+Chart.prototype.draw = function() {
+       var painter, i, o, o2, len, xlen, ymin, ymax, series, type, self, bLabels;
+       
+       if (!this._painterFactory) { return; }
+
+       /* Initialize */
+       series = new Array();
+       stackedSeries = new Array();
+       xlen = 0;
+       ymin = this._yMin;
+       ymax = this._yMax;
+
+       /* Separate stacked series (as they need processing). */
+       for (i = 0; i < this._series.length; i++) {
+               o = this._series[i]
+               if ((o.flags & CHART_STACKED) == CHART_STACKED) { series.push(o); }
+       }
+
+       /* Calculate values for stacked series */
+       for (i = series.length - 2; i >= 0; i--) {
+               o  = series[i].values;
+               o2 = series[i+1].values;
+               len = (o2.length > o.length)?o2.length:o.length;
+               for (j = 0; j < len; j++) {
+                       if ((o[j]) && (!o2[j])) { continue; }
+                       if ((!o[j]) && (o2[j])) { o[j] = o2[j]; }
+                       else { o[j] = parseInt(o[j]) + parseFloat(o2[j]); }
+       }       }
+
+       /* Append non-stacked series to list */
+       for (i = 0; i < this._series.length; i++) {
+               o = this._series[i]
+               if ((o.flags & CHART_STACKED) != CHART_STACKED) { series.push(o); }
+       }
+
+       /* Determine maximum number of values, ymin and ymax */
+       for (i = 0; i < series.length; i++) {
+               o = series[i]
+               if (o.values.length > xlen) { xlen = o.values.length; }
+               for (j = 0; j < o.values.length; j++) {
+                       if ((o.values[j] < ymin) || (ymin == null))  { ymin = o.values[j]; }
+                       if (o.values[j] > ymax) { ymax = o.values[j]; }
+       }       }
+
+       /*
+        * For bar only charts the number of charts is the same as the length of the
+        * longest series, for others combinations it's one less. Compensate for that
+        * for bar only charts.
+        */
+       if (this._series.length == this._bars) {
+               xlen++;
+               this._xGridDensity++;
+       }
+
+       /*
+        * Determine whatever or not to show the legend and axis labels
+        * Requires density and labels to be set.
+        */
+       bLabels = ((this._xGridDensity) && (this._yGridDensity) && (this._horizontalLabels.length >= this._xGridDensity));
+
+       /* Create painter object */
+       painter = this._painterFactory();
+       painter.create(this._cont);
+
+       /* Initialize painter object */
+       painter.init(xlen, ymin, ymax, this._xGridDensity, this._yGridDensity, bLabels);
+
+       /* Draw chart */
+       painter.drawBackground();
+
+       /*
+        * If labels and grid density where specified, draw legend and labels.
+        * It's drawn prior to the chart as the size of the legend and labels
+        * affects the size of the chart area.
+        */
+       if (this._showLegend) { painter.drawLegend(series); }
+       if (bLabels) {
+               painter.drawVerticalAxis(this._yGridDensity, this._labelPrecision);
+               painter.drawHorizontalAxis(xlen, this._horizontalLabels, this._xGridDensity, this._labelPrecision);
+       }
+
+       /* Draw chart */
+       painter.drawChart();
+
+       /* Draw series */
+       for (i = 0; i < series.length; i++) {
+               type = series[i].flags & ~CHART_STACKED;
+               switch (type) {
+                       case CHART_LINE: painter.drawLine(series[i].color, series[i].values); break;
+                       case CHART_AREA: painter.drawArea(series[i].color, series[i].values); break;
+                       case CHART_BAR:  painter.drawBars(series[i].color, series[i].values, xlen-1, series[i].offset, this._barWidth); break;
+                       default: ;
+               };
+       }
+
+       /*
+        * Draw axis (after the series since the anti aliasing of the lines may
+        * otherwise be drawn on top of the axis)
+        */
+       painter.drawAxis();
+
+};
+
+
+/*----------------------------------------------------------------------------\
+|                                 ChartSeries                                 |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Internal class for representing a series.                                   |
+\----------------------------------------------------------------------------*/
+
+function ChartSeries(label, color, values, flags, offset) {
+       this.label  = label;
+       this.color  = color;
+       this.values = values;
+       this.flags  = flags;
+       this.offset = offset;
+}
+
+
+/*----------------------------------------------------------------------------\
+|                            AbstractChartPainter                             |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Abstract base class defining the painter API. Can not be used directly.     |
+\----------------------------------------------------------------------------*/
+
+function AbstractChartPainter() {
+
+};
+
+
+AbstractChartPainter.prototype.calc = function(w, h, xlen, ymin, ymax, xgd, ygd) {
+       this.range = ymax - ymin;
+       this.xstep = w / (xlen - 1);
+       this.xgrid = (xgd)?w / (xgd - 1):0;
+       this.ygrid = (ygd)?h / (ygd - 1):0;
+       this.ymin  = ymin;
+       this.ymax  = ymax;
+};
+
+
+AbstractChartPainter.prototype.create = function(el) {};
+AbstractChartPainter.prototype.init = function(xlen, ymin, ymax, xgd, ygd, bLabels) {};
+AbstractChartPainter.prototype.drawLegend = function(series) {};
+AbstractChartPainter.prototype.drawVerticalAxis = function(ygd, precision) {};
+AbstractChartPainter.prototype.drawHorizontalAxis = function(xlen, labels, xgd, precision) {};
+AbstractChartPainter.prototype.drawAxis = function() {};
+AbstractChartPainter.prototype.drawBackground = function() {};
+AbstractChartPainter.prototype.drawChart = function() {};
+AbstractChartPainter.prototype.drawArea = function(color, values) {};
+AbstractChartPainter.prototype.drawLine = function(color, values) {};
+AbstractChartPainter.prototype.drawBars = function(color, values, xlen, xoffset, width) {};
diff --git a/trunk/NP_Clap/clap/chart/demo.js b/trunk/NP_Clap/clap/chart/demo.js
new file mode 100644 (file)
index 0000000..5a51389
--- /dev/null
@@ -0,0 +1,65 @@
+function demo() {
+       demo1();
+       demo2();
+       demo3();
+       demo4();        
+}
+
+
+function demo1(painterType) {
+       var c = new Chart(document.getElementById('chart'));
+       if (painterType == 'svg') { c.setPainterFactory(SVGChartPainterFactory); }
+       c.setDefaultType(CHART_AREA | CHART_STACKED);
+       c.setGridDensity(10, 10);
+       c.setVerticalRange(-100, 300);
+       c.setHorizontalLabels(['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'mon', 'tue', 'wed']);
+       c.setBarWidth(10);
+       c.add('Spam',            '#4040FF', [ 5,  10,  20,  10,  40,  52,  68,  70,  70,  60]);
+       c.add('Innocent',        '#8080FF', [ 8,   7,  12,  20,  24,  16,  36,  28,  28,  45]);
+       c.add('Missed Spam',     '#A5A5FF', [ 8,   7,  12,  20,  24,  16,  36,  36,  18,   5]);
+       c.add('False Positives', '#DEDEFF', [ 1, -20,   3,   2,   1,   4, -80,  12,   8, -10]);
+       c.add('SMTP Rejects',    'red',     [45,  54,  65, 150, 280, 120,  86,  65,  74,  12], CHART_LINE);
+       c.add('System Load',     '#008800', [-8,  -7, -12, -20, -24, -16, -36, -36, -18],      CHART_BAR);
+       c.add('Memory Usage',    '#009900', [-1, -20,  -3,  -2,  -1,  -4, -80, -12,  -8],      CHART_BAR);
+       c.draw();
+}
+
+function demo2() {
+       var c = new Chart(document.getElementById('chart2'));
+       c.setDefaultType(CHART_AREA | CHART_STACKED);
+       c.setGridDensity(5, 5);
+       c.setVerticalRange(-100, 300);
+       c.setHorizontalLabels(['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'mon', 'tue', 'wed']);
+       c.add('Spam',            '#4040FF', [ 5,  10,  20,  10,  40,  52,  68,  70,  70,  60]);
+       c.add('Innocent',        '#8080FF', [ 8,   7,  12,  20,  24,  16,  36,  28,  28,  45]);
+       c.add('Missed Spam',     '#A5A5FF', [ 8,   7,  12,  20,  24,  16,  36,  36,  18,   5]);
+       c.add('False Positives', '#DEDEFF', [ 1, -20,   3,   2,   1,   4, -80,  12,   8, -10]);
+       c.add('SMTP Rejects',    'red',     [45,  54,  65, 150, 280, 120,  86,  65,  74,  12], CHART_LINE);
+       c.draw();
+}
+
+function demo3() {
+       var c = new Chart(document.getElementById('chart3'));
+       c.setDefaultType(CHART_LINE);
+       c.setGridDensity(10, 10);
+       c.setHorizontalLabels(['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'mon', 'tue', 'wed']);
+       c.setShowLegend(false);
+       c.add('', '#4040FF', [ 5, 10, 20, 10, 40, 52, 68, 70, 70, 60]);
+       c.add('', '#8080FF', [ 8,  7, 12, 20, 24, 16, 36, 28, 28, 45]);
+       c.add('', '#FF8080', [ 3, 12,  5, 18, 20, 13, 28, 36, 18,  5]);
+       c.add('', '#FF00FF', [ 1, 20,  3,  2,  1,  4, 10, 12,  8, 10]);
+       c.draw();
+}
+
+function demo4() {
+       var c = new Chart(document.getElementById('chart4'));
+       c.setDefaultType(CHART_BAR);
+       c.setGridDensity(0, 0);
+       c.setBarWidth(10);
+       c.setBarDistance(1);
+       c.setShowLegend(false);
+       c.add('', 'blue',  [6, 3, 9, 6, 1, 3]);
+       c.add('', 'red',   [7, 1, 2, 9, 3, 6]);
+       c.add('', 'green', [2, 7, 1, 3, 7, 2]);
+       c.draw();
+}
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/chart/excanvas.js b/trunk/NP_Clap/clap/chart/excanvas.js
new file mode 100644 (file)
index 0000000..ca77da2
--- /dev/null
@@ -0,0 +1,723 @@
+// Copyright 2006 Google Inc.
+//
+// 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.
+
+// TODO: Patterns
+// TODO: Radial gradient
+// TODO: Clipping paths
+// TODO: Coordsize (still need to support stretching)
+// TODO: Painting mode
+// TODO: Optimize
+// TODO: canvas width/height sets content size in moz, border size in ie
+
+// only add this code if we do not already have a canvas implementation
+if (!window.CanvasRenderingContext2D) {
+
+(function () {
+
+  // alias some functions to make (compiled) code shorter
+  var m = Math;
+  var mr = m.round;
+  var ms = m.sin;
+  var mc = m.cos;
+
+  var G_vmlCanvasManager_ = {
+    init: function (opt_doc) {
+      var doc = opt_doc || document;
+      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
+        var self = this;
+        doc.attachEvent("onreadystatechange", function () {
+          self.init_(doc);
+        });
+      }
+    },
+
+    init_: function (doc, e) {
+      if (doc.readyState == "complete") {
+        // create xmlns
+        if (!doc.namespaces["g_vml_"]) {
+          doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml");
+        }
+
+        // setup default css
+        var ss = doc.createStyleSheet();
+        ss.cssText = "canvas{display:inline-block;overflow:hidden;" +
+            "text-align:left;}" +
+            "g_vml_\\:*{behavior:url(#default#VML)}";
+
+        // find all canvas elements
+        var els = doc.getElementsByTagName("canvas");
+        for (var i = 0; i < els.length; i++) {
+          if (!els[i].getContext) {
+            this.initElement(els[i]);
+          }
+        }
+      }
+    },
+
+    fixElement_: function (el) {
+      // in IE before version 5.5 we would need to add HTML: to the tag name
+      // but we do not care about IE before version 6
+      var outerHTML = el.outerHTML;
+      var newEl = document.createElement(outerHTML);
+      // if the tag is still open IE has created the children as siblings and
+      // it has also created a tag with the name "/FOO"
+      if (outerHTML.slice(-2) != "/>") {
+        var tagName = "/" + el.tagName;
+        var ns;
+        // remove content
+        while ((ns = el.nextSibling) && ns.tagName != tagName) {
+          ns.removeNode();
+        }
+        // remove the incorrect closing tag
+        if (ns) {
+          ns.removeNode();
+        }
+      }
+      el.parentNode.replaceChild(newEl, el);
+      return newEl;
+    },
+
+    /**
+     * Public initializes a canvas element so that it can be used as canvas
+     * element from now on. This is called automatically before the page is
+     * loaded but if you are creating elements using createElement you need to
+     * make sure this is called on the element.
+     * @param {HTMLElement} el The canvas element to initialize.
+     * @return {HTMLElement} the element that was created.
+     */
+    initElement: function (el) {
+      el = this.fixElement_(el);
+      el.getContext = function () {
+        if (this.context_) {
+          return this.context_;
+        }
+        return this.context_ = new CanvasRenderingContext2D_(this);
+      };
+
+      // do not use inline function because that will leak memory
+      // el.attachEvent('onpropertychange', onPropertyChange)
+      el.attachEvent('onresize', onResize);
+
+      var attrs = el.attributes;
+      if (attrs.width && attrs.width.specified) {
+        // TODO: use runtimeStyle and coordsize
+        // el.getContext().setWidth_(attrs.width.nodeValue);
+        el.style.width = attrs.width.nodeValue + "px";
+      }
+      if (attrs.height && attrs.height.specified) {
+        // TODO: use runtimeStyle and coordsize
+        // el.getContext().setHeight_(attrs.height.nodeValue);
+        el.style.height = attrs.height.nodeValue + "px";
+      }
+      //el.getContext().setCoordsize_()
+      return el;
+    }
+  };
+
+  function onPropertyChange(e) {
+    // we need to watch changes to width and height
+    switch (e.propertyName) {
+      case 'width':
+      case 'height':
+        // TODO: coordsize and size
+        break;
+    }
+  }
+
+  function onResize(e) {
+    var el = e.srcElement;
+    if (el.firstChild) {
+      el.firstChild.style.width =  el.clientWidth + 'px';
+      el.firstChild.style.height = el.clientHeight + 'px';
+    }
+  }
+
+  G_vmlCanvasManager_.init();
+
+  // precompute "00" to "FF"
+  var dec2hex = [];
+  for (var i = 0; i < 16; i++) {
+    for (var j = 0; j < 16; j++) {
+      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
+    }
+  }
+
+  function createMatrixIdentity() {
+    return [
+      [1, 0, 0],
+      [0, 1, 0],
+      [0, 0, 1]
+    ];
+  }
+
+  function matrixMultiply(m1, m2) {
+    var result = createMatrixIdentity();
+
+    for (var x = 0; x < 3; x++) {
+      for (var y = 0; y < 3; y++) {
+        var sum = 0;
+
+        for (var z = 0; z < 3; z++) {
+          sum += m1[x][z] * m2[z][y];
+        }
+
+        result[x][y] = sum;
+      }
+    }
+    return result;
+  }
+
+  function copyState(o1, o2) {
+    o2.fillStyle     = o1.fillStyle;
+    o2.lineCap       = o1.lineCap;
+    o2.lineJoin      = o1.lineJoin;
+    o2.lineWidth     = o1.lineWidth;
+    o2.miterLimit    = o1.miterLimit;
+    o2.shadowBlur    = o1.shadowBlur;
+    o2.shadowColor   = o1.shadowColor;
+    o2.shadowOffsetX = o1.shadowOffsetX;
+    o2.shadowOffsetY = o1.shadowOffsetY;
+    o2.strokeStyle   = o1.strokeStyle;
+  }
+
+  function processStyle(styleString) {
+    var str, alpha = 1;
+
+    styleString = String(styleString);
+    if (styleString.substring(0, 3) == "rgb") {
+      var start = styleString.indexOf("(", 3);
+      var end = styleString.indexOf(")", start + 1);
+      var guts = styleString.substring(start + 1, end).split(",");
+
+      str = "#";
+      for (var i = 0; i < 3; i++) {
+        str += dec2hex[parseInt(guts[i])];
+      }
+
+      if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) {
+        alpha = guts[3];
+      }
+    } else {
+      str = styleString;
+    }
+
+    return [str, alpha];
+  }
+
+  function processLineCap(lineCap) {
+    switch (lineCap) {
+      case "butt":
+        return "flat";
+      case "round":
+        return "round";
+      case "square":
+      default:
+        return "square";
+    }
+  }
+
+  /**
+   * This class implements CanvasRenderingContext2D interface as described by
+   * the WHATWG.
+   * @param {HTMLElement} surfaceElement The element that the 2D context should
+   * be associated with
+   */
+   function CanvasRenderingContext2D_(surfaceElement) {
+    this.m_ = createMatrixIdentity();
+
+    this.mStack_ = [];
+    this.aStack_ = [];
+    this.currentPath_ = [];
+
+    // Canvas context properties
+    this.strokeStyle = "#000";
+    this.fillStyle = "#ccc";
+
+    this.lineWidth = 1;
+    this.lineJoin = "miter";
+    this.lineCap = "butt";
+    this.miterLimit = 10;
+    this.globalAlpha = 1;
+
+    var el = document.createElement('div');
+    el.style.width =  surfaceElement.clientWidth + 'px';
+    el.style.height = surfaceElement.clientHeight + 'px';
+    el.style.overflow = 'hidden';
+    el.style.position = 'absolute';
+    surfaceElement.appendChild(el);
+
+    this.element_ = el;
+    this.arcScaleX_ = 1;
+    this.arcScaleY_ = 1;
+  };
+
+  var contextPrototype = CanvasRenderingContext2D_.prototype;
+  contextPrototype.clearRect = function() {
+    this.element_.innerHTML = "";
+    this.currentPath_ = [];
+  };
+
+  contextPrototype.beginPath = function() {
+    // TODO: Branch current matrix so that save/restore has no effect
+    //       as per safari docs.
+
+    this.currentPath_ = [];
+  };
+
+  contextPrototype.moveTo = function(aX, aY) {
+    this.currentPath_.push({type: "moveTo", x: aX, y: aY});
+  };
+
+  contextPrototype.lineTo = function(aX, aY) {
+    this.currentPath_.push({type: "lineTo", x: aX, y: aY});
+  };
+
+  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+                                            aCP2x, aCP2y,
+                                            aX, aY) {
+    this.currentPath_.push({type: "bezierCurveTo",
+                           cp1x: aCP1x,
+                           cp1y: aCP1y,
+                           cp2x: aCP2x,
+                           cp2y: aCP2y,
+                           x: aX,
+                           y: aY});
+  };
+
+  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
+    // VML's qb produces different output to Firefox's
+    // FF's behaviour seems to have changed in 1.5.0.1, check this
+    this.bezierCurveTo(aCPx, aCPy, aCPx, aCPy, aX, aY);
+  };
+
+  contextPrototype.arc = function(aX, aY, aRadius,
+                                  aStartAngle, aEndAngle, aClockwise) {
+    aRadius *= 10;
+    var arcType = aClockwise ? "at" : "wa";
+
+    var xStart = aX + (mc(aStartAngle) * aRadius) - 5;
+    var yStart = aY + (ms(aStartAngle) * aRadius) - 5;
+
+    var xEnd = aX + (mc(aEndAngle) * aRadius) - 5;
+    var yEnd = aY + (ms(aEndAngle) * aRadius) - 5;
+
+    this.currentPath_.push({type: arcType,
+                           x: aX,
+                           y: aY,
+                           radius: aRadius,
+                           xStart: xStart,
+                           yStart: yStart,
+                           xEnd: xEnd,
+                           yEnd: yEnd});
+
+  };
+
+  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+  };
+
+  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
+    // Will destroy any existing path (same as FF behaviour)
+    this.beginPath();
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+    this.stroke();
+  };
+
+  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+    // Will destroy any existing path (same as FF behaviour)
+    this.beginPath();
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+    this.fill();
+  };
+
+  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+    var gradient = new CanvasGradient_("gradient");
+    return gradient;
+  };
+
+  contextPrototype.createRadialGradient = function(aX0, aY0,
+                                                   aR0, aX1,
+                                                   aY1, aR1) {
+    var gradient = new CanvasGradient_("gradientradial");
+    gradient.radius1_ = aR0;
+    gradient.radius2_ = aR1;
+    gradient.focus_.x = aX0;
+    gradient.focus_.y = aY0;
+    return gradient;
+  };
+
+  contextPrototype.drawImage = function (image, var_args) {
+    var dx, dy, dw, dh, sx, sy, sw, sh;
+    var w = image.width;
+    var h = image.height;
+
+    if (arguments.length == 3) {
+      dx = arguments[1];
+      dy = arguments[2];
+      sx = sy = 0;
+      sw = dw = w;
+      sh = dh = h;
+    } else if (arguments.length == 5) {
+      dx = arguments[1];
+      dy = arguments[2];
+      dw = arguments[3];
+      dh = arguments[4];
+      sx = sy = 0;
+      sw = w;
+      sh = h;
+    } else if (arguments.length == 9) {
+      sx = arguments[1];
+      sy = arguments[2];
+      sw = arguments[3];
+      sh = arguments[4];
+      dx = arguments[5];
+      dy = arguments[6];
+      dw = arguments[7];
+      dh = arguments[8];
+    } else {
+      throw "Invalid number of arguments";
+    }
+
+    var d = this.getCoords_(dx, dy);
+
+    var w2 = (sw / 2);
+    var h2 = (sh / 2);
+
+    var vmlStr = [];
+
+    // For some reason that I've now forgotten, using divs didn't work
+    vmlStr.push(' <g_vml_:group',
+                ' coordsize="1000,1000"',
+                ' coordorigin="0, 0"' ,
+                ' style="width:100px;height:100px;position:absolute;');
+
+    // If filters are necessary (rotation exists), create them
+    // filters are bog-slow, so only create them if abbsolutely necessary
+    // The following check doesn't account for skews (which don't exist
+    // in the canvas spec (yet) anyway.
+
+    if (this.m_[0][0] != 1 || this.m_[0][1]) {
+      var filter = [];
+
+      // Note the 12/21 reversal
+      filter.push("M11='", this.m_[0][0], "',",
+                  "M12='", this.m_[1][0], "',",
+                  "M21='", this.m_[0][1], "',",
+                  "M22='", this.m_[1][1], "',",
+                  "Dx='", d.x, "',",
+                  "Dy='", d.y, "'");
+
+      // Bounding box calculation (need to minimize displayed area so that
+      // filters don't waste time on unused pixels.
+      var max = d;
+      var c2 = this.getCoords_(dx+dw, dy);
+      var c3 = this.getCoords_(dx, dy+dh);
+      var c4 = this.getCoords_(dx+dw, dy+dh);
+
+      max.x = Math.max(max.x, c2.x, c3.x, c4.x);
+      max.y = Math.max(max.y, c2.y, c3.y, c4.y);
+
+      vmlStr.push(" padding:0 ", mr(max.x), "px ", mr(max.y),
+                  "px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
+                  filter.join(""), ", sizingmethod='clip');")
+    } else {
+      vmlStr.push(" top:", d.y, "px;left:", d.x, "px;")
+    }
+
+    vmlStr.push(' ">' ,
+                '<g_vml_:image src="', image.src, '"',
+                ' style="width:', dw, ';',
+                ' height:', dh, ';"',
+                ' cropleft="', sx / w, '"',
+                ' croptop="', sy / h, '"',
+                ' cropright="', (w - sx - sw) / w, '"',
+                ' cropbottom="', (h - sy - sh) / h, '"',
+                ' />',
+                '</g_vml_:group>');
+
+    this.element_.insertAdjacentHTML("BeforeEnd",
+                                    vmlStr.join(""));
+  };
+
+  contextPrototype.stroke = function(aFill) {
+    var lineStr = [];
+    var lineOpen = false;
+    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
+    var color = a[0];
+    var opacity = a[1] * this.globalAlpha;
+
+    lineStr.push('<g_vml_:shape',
+                 ' fillcolor="', color, '"',
+                 ' filled="', Boolean(aFill), '"',
+                 ' style="position:absolute;width:10;height:10;"',
+                 ' coordorigin="0 0" coordsize="100 100"',
+                 ' stroked="', !aFill, '"',
+                 ' strokeweight="', this.lineWidth, '"',
+                 ' strokecolor="', color, '"',
+                 ' path="');
+
+    var newSeq = false;
+    var min = {x: null, y: null};
+    var max = {x: null, y: null};
+
+    for (var i = 0; i < this.currentPath_.length; i++) {
+      var p = this.currentPath_[i];
+
+      if (p.type == "moveTo") {
+        lineStr.push(" m ");
+        var c = this.getCoords_(p.x, p.y);
+        lineStr.push(mr(c.x), ",", mr(c.y));
+      } else if (p.type == "lineTo") {
+        lineStr.push(" l ");
+        var c = this.getCoords_(p.x, p.y);
+        lineStr.push(mr(c.x), ",", mr(c.y));
+      } else if (p.type == "close") {
+        lineStr.push(" x ");
+      } else if (p.type == "bezierCurveTo") {
+        lineStr.push(" c ");
+        var c = this.getCoords_(p.x, p.y);
+        var c1 = this.getCoords_(p.cp1x, p.cp1y);
+        var c2 = this.getCoords_(p.cp2x, p.cp2y);
+        lineStr.push(mr(c1.x), ",", mr(c1.y), ",",
+                     mr(c2.x), ",", mr(c2.y), ",",
+                     mr(c.x), ",", mr(c.y));
+      } else if (p.type == "at" || p.type == "wa") {
+        lineStr.push(" ", p.type, " ");
+        var c  = this.getCoords_(p.x, p.y);
+        var cStart = this.getCoords_(p.xStart, p.yStart);
+        var cEnd = this.getCoords_(p.xEnd, p.yEnd);
+
+        lineStr.push(mr(c.x - this.arcScaleX_ * p.radius), ",",
+                     mr(c.y - this.arcScaleY_ * p.radius), " ",
+                     mr(c.x + this.arcScaleX_ * p.radius), ",",
+                     mr(c.y + this.arcScaleY_ * p.radius), " ",
+                     mr(cStart.x), ",", mr(cStart.y), " ",
+                     mr(cEnd.x), ",", mr(cEnd.y));
+      }
+
+
+      // TODO: Following is broken for curves due to
+      //       move to proper paths.
+
+      // Figure out dimensions so we can do gradient fills
+      // properly
+      if(c) {
+        if (min.x == null || c.x < min.x) {
+          min.x = c.x;
+        }
+        if (max.x == null || c.x > max.x) {
+          max.x = c.x;
+        }
+        if (min.y == null || c.y < min.y) {
+          min.y = c.y;
+        }
+        if (max.y == null || c.y > max.y) {
+          max.y = c.y;
+        }
+      }
+    }
+    lineStr.push(' ">');
+
+    if (typeof this.fillStyle == "object") {
+      var focus = {x: "50%", y: "50%"};
+      var width = (max.x - min.x);
+      var height = (max.y - min.y);
+      var dimension = (width > height) ? width : height;
+
+      focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + "%";
+      focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + "%";
+
+      var colors = [];
+
+      // inside radius (%)
+      if (this.fillStyle.type_ == "gradientradial") {
+        var inside = (this.fillStyle.radius1_ / dimension * 100);
+
+        // percentage that outside radius exceeds inside radius
+        var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside;
+      } else {
+        var inside = 0;
+        var expansion = 100;
+      }
+
+      var insidecolor = {offset: null, color: null};
+      var outsidecolor = {offset: null, color: null};
+
+      // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie
+      // won't interpret it correctly
+      this.fillStyle.colors_.sort(function (cs1, cs2) {
+        return cs1.offset - cs2.offset;
+      });
+
+      for (var i = 0; i < this.fillStyle.colors_.length; i++) {
+        var fs = this.fillStyle.colors_[i];
+
+        colors.push( (fs.offset * expansion) + inside, "% ", fs.color, ",");
+
+        if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
+          insidecolor.offset = fs.offset;
+          insidecolor.color = fs.color;
+        }
+
+        if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
+          outsidecolor.offset = fs.offset;
+          outsidecolor.color = fs.color;
+        }
+      }
+      colors.pop();
+
+      lineStr.push('<g_vml_:fill',
+                   ' color="', outsidecolor.color, '"',
+                   ' color2="', insidecolor.color, '"',
+                   ' type="', this.fillStyle.type_, '"',
+                   ' focusposition="', focus.x, ', ', focus.y, '"',
+                   ' colors="', colors.join(""), '"',
+                   ' opacity="', opacity, '" />');
+    } else if (aFill) {
+      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity, '" />');
+    } else {
+      lineStr.push(
+        '<g_vml_:stroke',
+        ' opacity="', opacity,'"',
+        ' joinstyle="', this.lineJoin, '"',
+        ' miterlimit="', this.miterLimit, '"',
+        ' endcap="', processLineCap(this.lineCap) ,'"',
+        ' weight="', this.lineWidth, 'px"',
+        ' color="', color,'" />'
+      );
+    }
+
+    lineStr.push("</g_vml_:shape>");
+
+    this.element_.insertAdjacentHTML("beforeEnd", lineStr.join(""));
+
+    this.currentPath_ = [];
+  };
+
+  contextPrototype.fill = function() {
+    this.stroke(true);
+  }
+
+  contextPrototype.closePath = function() {
+    this.currentPath_.push({type: "close"});
+  };
+
+  /**
+   * @private
+   */
+  contextPrototype.getCoords_ = function(aX, aY) {
+    return {
+      x: 10 * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - 5,
+      y: 10 * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - 5
+    }
+  };
+
+  contextPrototype.save = function() {
+    var o = {};
+    copyState(this, o);
+    this.aStack_.push(o);
+    this.mStack_.push(this.m_);
+    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
+  };
+
+  contextPrototype.restore = function() {
+    copyState(this.aStack_.pop(), this);
+    this.m_ = this.mStack_.pop();
+  };
+
+  contextPrototype.translate = function(aX, aY) {
+    var m1 = [
+      [1,  0,  0],
+      [0,  1,  0],
+      [aX, aY, 1]
+    ];
+
+    this.m_ = matrixMultiply(m1, this.m_);
+  };
+
+  contextPrototype.rotate = function(aRot) {
+    var c = mc(aRot);
+    var s = ms(aRot);
+
+    var m1 = [
+      [c,  s, 0],
+      [-s, c, 0],
+      [0,  0, 1]
+    ];
+
+    this.m_ = matrixMultiply(m1, this.m_);
+  };
+
+  contextPrototype.scale = function(aX, aY) {
+    this.arcScaleX_ *= aX;
+    this.arcScaleY_ *= aY;
+    var m1 = [
+      [aX, 0,  0],
+      [0,  aY, 0],
+      [0,  0,  1]
+    ];
+
+    this.m_ = matrixMultiply(m1, this.m_);
+  };
+
+  /******** STUBS ********/
+  contextPrototype.clip = function() {
+    // TODO: Implement
+  };
+
+  contextPrototype.arcTo = function() {
+    // TODO: Implement
+  };
+
+  contextPrototype.createPattern = function() {
+    return new CanvasPattern_;
+  };
+
+  // Gradient / Pattern Stubs
+  function CanvasGradient_(aType) {
+    this.type_ = aType;
+    this.radius1_ = 0;
+    this.radius2_ = 0;
+    this.colors_ = [];
+    this.focus_ = {x: 0, y: 0};
+  }
+
+  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
+    aColor = processStyle(aColor);
+    this.colors_.push({offset: 1-aOffset, color: aColor});
+  };
+
+  function CanvasPattern_() {}
+
+  // set up externs
+  G_vmlCanvasManager = G_vmlCanvasManager_;
+  CanvasRenderingContext2D = CanvasRenderingContext2D_;
+  CanvasGradient = CanvasGradient_;
+  CanvasPattern = CanvasPattern_;
+
+})();
+
+} // if
diff --git a/trunk/NP_Clap/clap/chart/iecanvas.htc b/trunk/NP_Clap/clap/chart/iecanvas.htc
new file mode 100644 (file)
index 0000000..b87427b
--- /dev/null
@@ -0,0 +1,380 @@
+/*----------------------------------------------------------------------------\
+|                                IE Canvas 1.0                                |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|-----------------------------------------------------------------------------|
+| Implementation of the canvas API for Internet Explorer. Uses VML.           |
+|-----------------------------------------------------------------------------|
+|                      Copyright (c) 2005 Emil A Eklund                       |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| Dependencies: canvas.js           - For initialization of canvas elements   |
+|-----------------------------------------------------------------------------|
+| 2005-12-27 | Work started.                                                  |
+| 2005-12-29 | First version posted.                                          |
+| 2006-01-03 | Fixed bug in moveTo and lineTo,  arguments where not converted |
+|            | to int which could cause IE to enter an endless loop. Disabled |
+|            | antalias for fillRect to better comply with the Mozilla, Opera |
+|            | and possibly  Safari  implementations where  using fillRect is |
+|            | about the only way to raw non antialiased lines.               |
+|-----------------------------------------------------------------------------|
+| Created 2005-12-27 | All changes are in the log above. | Updated 2006-01-03 |
+\----------------------------------------------------------------------------*/
+
+<public:component>
+       <public:method name="getContext" />
+       <public:attach event="oncontentready" onevent="initCanvas()"/>
+</public:component>
+
+<script language="JScript">
+
+       function getContext() {
+               return element.context;
+       }
+
+       function initCanvas() {
+               element.context = new IECanvasContext();
+               element.style.position = 'relative';
+               element.style.display  = 'block';
+               element.style.overflow = 'hidden';
+       }
+
+
+
+       function IECanvasContext() {
+               this.fillStyle = 'black';
+               this.globalAlpha = 1.0;
+               this.globalCompositeOperation = '';
+               this.lineCap = '';
+               this.lineJoin = '';
+               this.lineWidth = '0';
+               this.miterLimit = '';
+               this.shadowBlur = '';
+               this.shadowColor = '';
+               this.shadowOffsetX = '';
+               this.shadowOffsetY = '';
+               this.strokeStyle = 'black';
+               this._path = '';
+               this._stateStack = new Array();
+               this._offsetX = 0;
+               this._offsetY = 0;
+               this._rotation = 0;
+       };
+
+       IECanvasContext.prototype.save = function() {
+               var o;
+
+               o = new Object();
+               this._copyState(this, o);
+               this._stateStack.push(o);
+       };
+
+       IECanvasContext.prototype.restore = function() {
+               var o, n;
+
+               n = this._stateStack.length - 1;
+               if (n < 0) { return; }
+
+               o = this._stateStack[n];
+               this._copyState(o, this);
+               this._stateStack.splice(n, 1);
+       };
+
+       IECanvasContext.prototype._copyState = function(oFrom, oTo) {
+               oTo.fillStyle     = oFrom.fillStyle;
+               oTo.lineCap       = oFrom.lineCap;
+               oTo.lineJoin      = oFrom.lineJoin;
+               oTo.lineWidth     = oFrom.lineWidth;
+               oTo.miterLimit    = oFrom.miterLimit;
+               oTo.shadowBlur    = oFrom.shadowBlur;
+               oTo.shadowColor   = oFrom.shadowColor;
+               oTo.shadowOffsetX = oFrom.shadowOffsetX;
+               oTo.shadowOffsetY = oFrom.shadowOffsetY;
+               oTo._offsetX      = oFrom._offsetX;
+               oTo._offsetY      = oFrom._offsetY;
+               oTo._rotation     = oFrom._rotation;
+       };
+
+       IECanvasContext.prototype.rotate = function(r) {
+               var MAX = Math.PI * 2;
+
+               this._rotation += r;
+               while (this._rotation > MAX) { this._rotation = MAX - this._rotation; }
+       };
+
+       IECanvasContext.prototype.scale = function() { };
+
+       IECanvasContext.prototype.translate = function(x, y) {
+               this._offsetX += x;
+               this._offsetY += y;
+       };
+
+       IECanvasContext.prototype.bezierCurveTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
+               if (this._path) { this._path += ' '; }
+
+               this._path += 'qb' + cp1x + ',' + cp1y + ',' + cp2x + ',' + cp2y + ',' + x + ',' + y;
+       };
+
+
+       IECanvasContext.prototype.clip = function() { };
+
+       IECanvasContext.prototype.beginPath = function() {
+               this._path = '';
+       };
+
+       IECanvasContext.prototype.closePath = function() {
+               if (this._path) { this._path += ' '; }
+               this._path += 'x';
+       };
+
+       IECanvasContext.prototype.lineTo = function(x, y) {
+               if (this._path) { this._path += ' '; }
+               this._path += 'l' + parseInt(x) + ',' + parseInt(y);
+       };
+
+       IECanvasContext.prototype.moveTo = function(x, y) {
+               if (this._path) { this._path += ' '; }
+               this._path += 'm' + parseInt(x) + ',' + parseInt(y);
+       };
+
+       IECanvasContext.prototype.stroke = function() {
+               var o, s, cosa, sina, cx, cy, x, y;
+
+               if (!this._path) { return; }
+
+               this._path += ' e';
+
+               o = element.ownerDocument.createElement('v:shape');
+               o.fillColor = 'none';
+               o.filled = false;
+               o.strokeColor = this.strokeStyle;
+               o.stroked = true;
+               o.weight = this.lineWidth;
+               o.coordsize = element.offsetWidth + ',' + element.offsetHeight;
+               o.style.position = 'absolute';
+               o.style.left = this._offsetX;
+               o.style.top = this._offsetY;
+               o.style.width = element.offsetWidth;
+               o.style.height = element.offsetHeight;
+               o.path = this._path;
+
+               s = element.ownerDocument.createElement('v:stroke');
+               s.opacity = this.globalAlpha;
+               o.appendChild(s);
+
+               if (this._rotation) {
+                       r = element.ownerDocument.createElement('v:group');
+                       r.style.position = 'absolute';
+                       r.style.left = 0;
+                       r.style.top = 0;
+                       r.style.width = element.offsetWidth;
+                       r.style.height = element.offsetHeight;
+                       r.coordsize = o.coordsize;
+                       r.style.rotation = Math.round((this._rotation * 180) / Math.PI);
+                       r.style.rotationCenter = '0,0';
+                       r.appendChild(o);
+                       element.appendChild(r);
+
+                       cosa = Math.cos(this._rotation);
+                       sina = Math.sin(this._rotation);
+                       cx = element.offsetWidth / 2;
+                       cy = element.offsetHeight / 2;
+
+                       x = ( cx*(1-cosa) + cy*sina);
+                       y = (-cx*sina     + cy*(1-cosa));
+
+                       r.style.left = x * -1;
+                       r.style.top = y * -1;
+               }
+               else { element.appendChild(o); }
+       };
+
+       IECanvasContext.prototype.fill = function() {
+               var o, f, r;
+
+               if (!this._path) { return; }
+
+               this._path += ' e';
+
+               o = element.ownerDocument.createElement('v:shape');
+               o.fillColor = this.fillStyle;
+               o.strokeColor = this.strokeStyle;
+               o.stroked = false;
+               o.weight = this.lineWidth;
+               o.coordsize = element.offsetWidth + ',' + element.offsetHeight;
+               o.style.position = 'absolute';
+               o.style.left = this._offsetX;
+               o.style.top = this._offsetY;
+               o.style.width = element.offsetWidth;
+               o.style.height = element.offsetHeight;
+               o.path = this._path;
+
+               f = element.ownerDocument.createElement('v:fill');
+               f.opacity = this.globalAlpha;
+               o.appendChild(f);
+
+               if (this._rotation) {
+                       r = element.ownerDocument.createElement('v:group');
+                       r.style.position = 'absolute';
+                       r.style.left = 0;
+                       r.style.top = 0;
+                       r.style.width = element.offsetWidth;
+                       r.style.height = element.offsetHeight;
+                       r.coordsize = o.coordsize;
+                       r.style.rotation = Math.round((this._rotation * 180) / Math.PI);
+                       r.style.rotationCenter = '0,0';
+                       r.appendChild(o);
+                       element.appendChild(r);
+
+                       cosa = Math.cos(this._rotation);
+                       sina = Math.sin(this._rotation);
+                       cx = (element.offsetWidth) / 2;
+                       cy = (element.offsetHeight) / 2;
+                       x = ( cx*(1-cosa) + cy*sina);
+                       y = (-cx*sina     + cy*(1-cosa));
+
+                       r.style.left = x * -1;
+                       r.style.top = y * -1;
+               }
+               else { element.appendChild(o); }
+       };
+
+       IECanvasContext.prototype.arcTo = function(x1, y1, x2, y2, radius) {
+               // not implemented in gecko, not implemented here
+       };
+
+       IECanvasContext.prototype.quadraticCurveTo = function(cpx, cpy, x, y) {
+               if (this._path) { this._path += ' '; }
+
+               this._path += 'qb' + cpx + ',' + cpy + ',' + x + ',' + y;
+       };
+
+       IECanvasContext.prototype.arc = function(x, y, radius, startAngle, endAngle, clockwise) {
+               var xi, yi, x1, y1, x2, y2, x3, y3, x4, y4;
+
+               if (this._path) { this._path += ' '; }
+
+               xi = parseFloat(x);
+               yi = parseFloat(y);
+
+               x1 = xi - radius;
+               y1 = yi - radius;
+
+               x2 = xi + radius;
+               y2 = yi + radius;
+
+               x3 = xi + (Math.cos(startAngle) * radius);
+               y3 = yi + (Math.sin(startAngle) * radius);
+
+               x4 = xi + (Math.cos(endAngle) * radius);
+               y4 = yi + (Math.sin(endAngle) * radius);
+
+               x3 = Math.round(x3);
+               y3 = Math.round(y3);
+               x4 = Math.round(x4);
+               y4 = Math.round(y4);
+
+               this._path += 'ar' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' + x3 + ',' + y3 + ',' + x4 + ',' + y4;
+       };
+
+
+       IECanvasContext.prototype.rect = function(x, y, w, h) {
+               var x1, y1, x2, y2;
+
+               x2 = x + w;
+               y2 = y + h;
+
+               x1 = Math.round(x);
+               y1 = Math.round(y);
+               x2 = Math.round(x2);
+               y2 = Math.round(y2);
+
+               this._path += 'm' + x1 + ',' + y1;
+               this._path += ' l' + x2 + ',' + y1;
+               this._path += ' l' + x2 + ',' + y2;
+               this._path += ' l' + x1 + ',' + y2;
+               this._path += ' x'
+       };
+
+       IECanvasContext.prototype.strokeRect = function(x, y, w, h) {
+               var o, s;
+
+               o = element.ownerDocument.createElement('v:rect');
+               o.fillColor = 'none';
+               o.filled = false;
+               o.strokeColor = this.strokeStyle;
+               o.stroked = true;
+               o.weight = this.lineWidth;
+               o.style.position = 'absolute';
+               o.style.left = this._offsetX + x;
+               o.style.top = this._offsetY + y;
+               o.style.width = w;
+               o.style.height = h;
+
+               s = element.ownerDocument.createElement('v:fill');
+               s.opacity = this.globalAlpha;
+               o.appendChild(s);
+
+               element.appendChild(o);
+       };
+
+       IECanvasContext.prototype.clearRect = function(x, y, w, h) { };
+
+
+       IECanvasContext.prototype.fillRect = function(x, y, w, h) {
+               var o, f;
+               
+               if ((x == 0) && (y == 0) && (w == element.offsetWidth) && (h == element.offsetHeight) && (this._offsetX == 0) && (this._offsetY == 0) && (this.globalAlpha == 1)) {
+                       while (element.firstChild) { element.removeChild(element.lastChild); }
+               }
+
+               o = element.ownerDocument.createElement('v:rect');
+               o.fillColor = this.fillStyle;
+               o.filled = true;
+               o.stroked = false;
+               o.weight = 0;
+               o.style.position = 'absolute';
+               o.style.left = this._offsetX + x;
+               o.style.top = this._offsetY + y;
+               o.style.width = w;
+               o.style.height = h;
+               o.style.antialias = 'false';
+
+               f = element.ownerDocument.createElement('v:fill');
+               f.opacity = this.globalAlpha;
+               o.appendChild(f);
+
+               element.appendChild(o);
+       };
+
+       IECanvasContext.prototype.addColorStop = function() { };
+       IECanvasContext.prototype.createLinearGradient = function() { };
+       IECanvasContext.prototype.createPattern = function() { };
+       IECanvasContext.prototype.createRadialGradient = function() { };
+
+       IECanvasContext.prototype.drawImage = function() { };
+       IECanvasContext.prototype.drawImageFromRect = function() { };
+
+</script>
diff --git a/trunk/NP_Clap/clap/chart/iecanvas.js b/trunk/NP_Clap/clap/chart/iecanvas.js
new file mode 100644 (file)
index 0000000..64c791c
--- /dev/null
@@ -0,0 +1,89 @@
+/*----------------------------------------------------------------------------\
+|                                IE Canvas 1.0                                |
+|                       Emulation Initialization Script                       |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|-----------------------------------------------------------------------------|
+| Implementation of the canvas API for Internet Explorer. Uses VML.           |
+|-----------------------------------------------------------------------------|
+|                      Copyright (c) 2005 Emil A Eklund                       |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| Dependencies: canvas.htc          - Actual implementation                   |
+|-----------------------------------------------------------------------------|
+| 2005-12-27 | Work started.                                                  |
+| 2005-12-29 | First version posted.                                          |
+| 2006-01-03 | Added htcFile argument to ieCanvasInit method.                 |
+|-----------------------------------------------------------------------------|
+| Created 2005-12-27 | All changes are in the log above. | Updated 2006-01-03 |
+\----------------------------------------------------------------------------*/
+
+
+function ieCanvasInit(htcFile) {
+       var ie, opera, a, nodes, i, oVml, oStyle, newNode;
+
+       /*
+        * Only proceed if browser is IE 6 or later (as all other major browsers
+        * support canvas out of the box there is no need to try to emulate for
+        * them, and besides only IE supports VML anyway.
+        */
+       ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
+       opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+       if ((!ie) || (ie[1] < 6) || (opera)) {
+               return;
+       }
+
+       /*
+        * Recreate elements, as there is no canvas tag in HTML
+        * The canvas tag is replaced by a new one created using createElement,
+        * even though the same tag name is given the generated tag is slightly
+        * different, it's created prefixed with a XML namespace declaration
+        * <?XML:NAMESPACE PREFIX ="PUBLIC" NS="URN:COMPONENT" />
+        */
+       nodes = document.getElementsByTagName('canvas');
+       for (i = 0; i < nodes.length; i++) {
+               node = nodes[i];
+               if (node.getContext) { return; } // Other implementation, abort
+               newNode = document.createElement('canvas');
+               newNode.id = node.id;
+               newNode.style.width  = node.width;
+               newNode.style.height = node.height;
+               node.parentNode.replaceChild(newNode, node);
+       }
+
+       /* Add VML includes and namespace */
+       document.namespaces.add("v");
+       oVml = document.createElement('object');
+       oVml.id = 'VMLRender';
+       oVml.codebase = 'vgx.dll';
+       oVml.classid = 'CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E';
+       document.body.appendChild(oVml);
+
+       /* Add required css rules */
+       if ((!htcFile) || (htcFile == '')) { htcFile = 'iecanvas.htc'; }
+       oStyle = document.createStyleSheet();
+       oStyle.addRule('canvas', "behavior: url('" + htcFile + "');");
+       oStyle.addRule('v\\:*', "behavior: url(#VMLRender);");
+}
diff --git a/trunk/NP_Clap/clap/chart/jgchartpainter.js b/trunk/NP_Clap/clap/chart/jgchartpainter.js
new file mode 100644 (file)
index 0000000..10a1b60
--- /dev/null
@@ -0,0 +1,330 @@
+/*----------------------------------------------------------------------------\
+|                                  Chart 1.0                                  |
+|                       JavaScript Graphics Chart Painter                     |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|                           Modified by Ma Bingyao                            |
+|                          (http://www.coolcode.cn)                           |
+|-----------------------------------------------------------------------------|
+| JavaScript Graphics implementation of the chart painter API.  jsGraphics is |
+| used to  draw the chart,  html elements are used for  the legend  and  axis |
+| labels as, at the time being.                                               |
+|-----------------------------------------------------------------------------|
+|                Copyright (c) 2006 Emil A Eklund & Ma Bingyao                |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| 2006-01-03 | Work started.                                                  |
+| 2006-01-05 | Added legend and axis labels. Changed the painter api slightly |
+|            | to allow two-stage initialization (required for ie/canvas) and |
+|            | added legend/axis related methods. Also updated bar chart type |
+|            | and added a few options, mostly related to bar charts.         |
+| 2006-01-07 | Updated chart size calculations to take legend and axis labels |
+|            | into consideration.  Split painter implementations to separate |
+|            | files.                                                         |
+| 2006-02-03 | Modified to use wz_jsgraphics instead of canvas by Ma Bingyao. |
+|-----------------------------------------------------------------------------|
+| Created 2006-01-03 | All changes are in the log above. | Updated 2006-02-03 |
+\----------------------------------------------------------------------------*/
+
+function JsGraphicsChartPainterFactory() {
+       return new JsGraphicsChartPainter();
+}
+
+
+function JsGraphicsChartPainter() {
+       this.base = AbstractChartPainter;
+};
+
+
+JsGraphicsChartPainter.prototype = new AbstractChartPainter;
+
+
+JsGraphicsChartPainter.prototype.create = function(el) {
+       while (el.firstChild) { el.removeChild(el.lastChild); }
+
+       this.el = el;
+       this.w = el.clientWidth;
+       this.h = el.clientHeight;
+
+       this.canvas = document.createElement('div');
+       this.canvas.width  = this.w;
+       this.canvas.height = this.h;
+       this.canvas.style.width  = this.w + 'px';
+       this.canvas.style.height = this.h + 'px';
+       this.canvas.style.position = "relative";
+       this.canvas.id = "canvas_" + el.id;
+       this.canvas.onselectstart = function () { return false; };
+
+       el.appendChild(this.canvas);
+};
+
+
+JsGraphicsChartPainter.prototype.init = function(xlen, ymin, ymax, xgd, ygd, bLegendLabels) {
+       this.ctx = new jsGraphics(this.canvas.id);
+
+       this.chartx = 0;
+       this.chartw     = this.w;
+       this.charth     = this.h;
+       this.charty = 0;
+       
+       this.xlen = xlen;
+       this.ymin = ymin;
+       this.ymax = ymax;
+       this.xgd  = xgd;
+       this.ygd  = ygd;
+
+       this.calc(this.chartw, this.charth, xlen, ymin, ymax, xgd, ygd);
+};
+
+
+JsGraphicsChartPainter.prototype.drawLegend = function(series) {
+       var legend, list, item, label;
+
+       legend = document.createElement('div');
+       legend.className = 'legend';
+       legend.style.position = 'absolute';
+       list = document.createElement('ul');
+
+       for (i = 0; i < series.length; i++) {
+               item = document.createElement('li');
+               item.style.color = series[i].color;
+               label = document.createElement('span');
+               label.appendChild(document.createTextNode(series[i].label));
+               label.style.color = 'black';
+               item.appendChild(label);
+               list.appendChild(item);
+       }
+       legend.appendChild(list);
+       this.el.appendChild(legend);
+       legend.style.right = '0px';
+       legend.style.top  = this.charty + (this.charth / 2) - (legend.offsetHeight / 2) + 'px';
+       this.legend = legend;
+       
+       /* Recalculate chart width and position based on labels and legend */
+       this.chartw     = this.w - (this.legend.offsetWidth + 5);
+       
+       this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
+};
+
+
+JsGraphicsChartPainter.prototype.drawVerticalAxis = function(ygd, precision) {
+       var axis, item, step, y, ty, n, yoffset, value, multiplier, w, items, pos;
+
+       /* Calculate step size and rounding precision */
+       multiplier = Math.pow(10, precision);
+       step       = this.range / (ygd - 1);
+
+       /* Create container */
+       axis = document.createElement('div');
+       axis.style.position = 'absolute';
+       axis.style.left  = '0px';
+       axis.style.top   = '0px';
+       axis.style.textAlign = 'right';
+       this.el.appendChild(axis);
+
+       /* Draw labels and points */
+       this.ctx.setColor('black');
+       w = 0;
+       items = new Array();
+       for (n = 0, i = this.ymax; (i > this.ymin) && (n < ygd - 1); i -= step, n++) {
+               item = document.createElement('span');
+               value = parseInt(i * multiplier) / multiplier;
+               item.appendChild(document.createTextNode(value));
+               axis.appendChild(item);
+               items[items.length] = new Array(i, item);
+               if (item.offsetWidth > w) { w = item.offsetWidth; }
+       }
+
+       /* Draw last label and point (lower left corner of chart) */
+       item = document.createElement('span');
+       item.appendChild(document.createTextNode(this.ymin));
+       axis.appendChild(item);
+       items[items.length] = new Array(this.ymin, item);
+       if (item.offsetWidth > w) { w = item.offsetWidth; }
+       
+       /* Set width of container to width of widest label */
+       axis.style.width = w + 'px';
+       
+       /* Recalculate chart width and position based on labels and legend */
+       this.chartx = w + 5;
+       this.charty = item.offsetHeight / 2;
+       this.charth = this.h - ((item.offsetHeight * 1.5) + 5);
+       this.chartw     = this.w - (((this.legend)?this.legend.offsetWidth:0) + w + 10);
+       this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
+       
+       /* Position labels on the axis */
+       n          = this.range / this.charth;
+       yoffset    = (this.ymin / n);
+       for (i = 0; i < items.length; i++) {
+               item = items[i][1];
+               pos = items[i][0];
+               if (pos == this.ymin) { y = this.charty + this.charth - 1; }
+               else { y = this.charty + (this.charth - (pos / n) + yoffset); }
+               this.ctx.drawLine(this.chartx - 5, y, this.chartx, y);
+               ty = y - (item.offsetHeight/2);
+               item.style.position = 'absolute';
+               item.style.right = '0px';
+               item.style.top   = ty + 'px';
+}      };
+
+JsGraphicsChartPainter.prototype.drawHorizontalAxis = function(xlen, labels, xgd, precision) {
+       var axis, item, step, x, tx, y1, y2, n, multiplier;
+
+       /* Calculate offset, step size and rounding precision */
+       multiplier = Math.pow(10, precision);
+       n          = this.chartw / (xgd - 1);
+
+       /* Create container */
+       axis = document.createElement('div');
+       axis.style.position = 'absolute';
+       axis.style.left   = '0px';
+       axis.style.top    = (this.charty + this.charth + 5) + 'px';
+       axis.style.width  = this.w + 'px';
+       this.el.appendChild(axis);
+
+       /* Draw labels and points */
+       this.ctx.setColor('black');
+       y1 = this.charty + this.charth;
+       y2 = this.charty + this.charth + 5;
+       for (i = 0; i < xgd; i++) {
+               item = document.createElement('span');
+               item.appendChild(document.createTextNode(labels[i]));
+               axis.appendChild(item);
+               x = this.chartx + (n * i);
+               tx = x - (item.offsetWidth/2)
+               item.style.position = 'absolute';
+               item.style.left = tx + 'px';
+               item.style.top  = '0px';
+               this.ctx.drawLine(x, y1, x, y2);
+}      };
+
+
+JsGraphicsChartPainter.prototype.drawAxis = function() {
+    var x1, x2, y1, y2;
+       this.ctx.setColor('black');
+       x1 = this.chartx;
+       x2 = this.chartx + this.chartw + 1;
+       y1 = this.charty;
+       y2 = this.charty + this.charth - 1;
+       this.ctx.drawLine(x1, y1, x1, y2);
+       this.ctx.drawLine(x1, y2, x2, y2);
+       this.ctx.paint();
+};
+
+
+JsGraphicsChartPainter.prototype.drawBackground = function() {
+       this.ctx.setColor('white');
+       this.ctx.fillRect(0, 0, this.w, this.h);
+};
+
+
+JsGraphicsChartPainter.prototype.drawChart = function() {
+       this.ctx.setColor('silver');
+       if (this.xgrid) {
+               for (i = this.xgrid; i < this.chartw; i += this.xgrid) {
+                       this.ctx.drawLine(this.chartx + i, this.charty, this.chartx + i, this.charty + this.charth - 1);
+       }       }
+       if (this.ygrid) {
+               for (i = this.charth - this.ygrid; i > 0; i -= this.ygrid) {
+                       this.ctx.drawLine(this.chartx + 1, this.charty + i, this.chartx + this.chartw + 1, this.charty + i);
+}      }       };
+
+
+JsGraphicsChartPainter.prototype.drawArea = function(color, values) {
+       var i, len, x, y, n, yoffset;
+       var XPoints = new Array();
+       var YPoints = new Array();
+
+       /* Determine distance between points and offset */
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+               this.ctx.setColor(color);
+
+               x = this.chartx + 1;
+               y = this.charty + this.charth - 1;
+               XPoints[XPoints.length] = x;
+               YPoints[YPoints.length] = y;
+
+               y = this.charty + this.charth - (values[0] / n) + yoffset;
+               XPoints[XPoints.length] = x;
+               YPoints[YPoints.length] = y;
+
+               for (i = 1; i < len; i++) {
+                       y = this.charty + this.charth - (values[i] / n) + yoffset;
+                       x += this.xstep;
+                       XPoints[XPoints.length] = x;
+                       YPoints[YPoints.length] = y;
+               }
+
+               XPoints[XPoints.length] = x;
+               YPoints[YPoints.length] = this.charty + this.charth - 1;
+               
+               this.ctx.fillPolygon(XPoints, YPoints);
+}      };
+
+
+JsGraphicsChartPainter.prototype.drawLine = function(color, values) {
+       var i, len, x1, y1, x2, y2, n, yoffset;
+
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+               this.ctx.setStroke(1);
+               this.ctx.setColor(color);
+               x1 = this.chartx + 1;
+               y1 = this.charty + this.charth - (values[0] / n) + yoffset;
+
+               for (i = 1; i < len; i++) {
+                       y2 = this.charty + this.charth - (values[i] / n) + yoffset;
+                       x2 = x1 + this.xstep;
+                       this.ctx.drawLine(x1, y1, x2, y2);
+                       x1 = x2;
+                       y1 = y2;
+               }
+
+}      };
+
+
+JsGraphicsChartPainter.prototype.drawBars = function(color, values, xlen, xoffset, width) {
+       var i, len, x, y, n, yoffset;
+
+       n = this.range / this.charth;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len > xlen) { len = xlen; }
+       if (len) {
+               this.ctx.setColor(color);
+               x = this.chartx + xoffset + 1;
+               for (i = 0; i < len; i++) {
+                       y = this.charty + this.charth - (values[i] / n) + yoffset;
+                       this.ctx.fillRect(x, y, width, this.charty + this.charth - y);
+                       x += this.xstep;
+}      }       };
diff --git a/trunk/NP_Clap/clap/chart/svgchartpainter.js b/trunk/NP_Clap/clap/chart/svgchartpainter.js
new file mode 100644 (file)
index 0000000..c82241b
--- /dev/null
@@ -0,0 +1,192 @@
+/*----------------------------------------------------------------------------\
+|                                  Chart 1.0                                  |
+|                              SVG Chart Painter                              |
+|-----------------------------------------------------------------------------|
+|                          Created by Emil A Eklund                           |
+|                        (http://eae.net/contact/emil)                        |
+|-----------------------------------------------------------------------------|
+| SVG implementation of the chart painter API.  A svg element is used to draw |
+| draw the chart.  This implementation is not complete and is provided mostly |
+| as a reference at this stage.                                               |
+|-----------------------------------------------------------------------------|
+|                      Copyright (c) 2006 Emil A Eklund                       |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| This program is  free software;  you can redistribute  it and/or  modify it |
+| under the terms of the MIT License.                                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| Permission  is hereby granted,  free of charge, to  any person  obtaining a |
+| copy of this software and associated documentation files (the "Software"),  |
+| to deal in the  Software without restriction,  including without limitation |
+| the  rights to use, copy, modify,  merge, publish, distribute,  sublicense, |
+| and/or  sell copies  of the  Software, and to  permit persons to  whom  the |
+| Software is  furnished  to do  so, subject  to  the  following  conditions: |
+| The above copyright notice and this  permission notice shall be included in |
+| all copies or substantial portions of the Software.                         |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+| THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
+| IMPLIED,  INCLUDING BUT NOT LIMITED TO  THE WARRANTIES  OF MERCHANTABILITY, |
+| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
+| AUTHORS OR  COPYRIGHT  HOLDERS BE  LIABLE FOR  ANY CLAIM,  DAMAGES OR OTHER |
+| LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT OR  OTHERWISE,  ARISING |
+| FROM,  OUT OF OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE  USE OR  OTHER |
+| DEALINGS IN THE SOFTWARE.                                                   |
+|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
+|                         http://eae.net/license/mit                          |
+|-----------------------------------------------------------------------------|
+| 2006-01-03 | Work started.                                                  |
+| 2006-01-05 | Added legend and axis labels. Changed the painter api slightly |
+|            | to allow two-stage initialization (required for ie/canvas) and |
+|            | added legend/axis related methods. Also updated bar chart type |
+|            | and added a few options, mostly related to bar charts.         |
+| 2006-01-07 | Split painter implementations to separate files.               |
+|-----------------------------------------------------------------------------|
+| Created 2006-01-03 | All changes are in the log above. | Updated 2006-01-07 |
+\----------------------------------------------------------------------------*/
+
+function SVGChartPainterFactory() {
+       return new SVGChartPainter();
+}
+
+
+function SVGChartPainter() {
+       this.base = AbstractChartPainter;
+};
+
+
+SVGChartPainter.prototype = new AbstractChartPainter;
+
+
+SVGChartPainter.prototype.create = function(el) {
+       this.svg = el;
+       this.w = this.svg.getAttribute('width');
+       this.h = this.svg.getAttribute('height');
+};
+
+
+SVGChartPainter.prototype.init = function(xlen, ymin, ymax, xgd, ygd, bLegendLabels) {
+       this.calc(this.w, this.h, xlen, ymin, ymax, xgd, ygd);
+};
+
+
+SVGChartPainter.prototype.drawBackground = function() {
+       while (this.svg.firstChild) { this.svg.removeChild(this.svg.lastChild); }
+       this._drawRect('white', 0, 0, this.w, this.h);
+};
+
+
+SVGChartPainter.prototype.drawChart = function() {
+       if (this.xgrid) {
+               for (i = this.xgrid; i < this.w; i += this.xgrid) {
+                       this._drawRect('silver', 0 + i, 0, 1, this.h-1);
+       }       }
+       if (this.ygrid) {
+               for (i = this.h - this.ygrid; i > 0; i -= this.ygrid) {
+                       this._drawRect('silver', 1, 0 + i, this.w, 1);
+}      }       };
+
+
+SVGChartPainter.prototype.drawAxis = function() {
+       this._drawRect('black', 0, 0, 1, this.h);
+       this._drawRect('black', 0, this.h-1, this.w, 1);
+};
+
+
+SVGChartPainter.prototype.drawArea = function(color, values) {
+       var i, len, x, y, n, yoffset, path, o;
+
+       /* Determine distance between points and offset */
+       n = this.range/this.h;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+
+               /* Begin line in lower left corner */
+               x = 1;
+               path = 'M' + x + ',' + (this.h-1);
+
+               /* Determine position of first point and append line to command */
+               y = this.h - (values[0] / n) + yoffset;
+               path += ' L' + x + ',' + y;
+
+               /* Append commands for succeeding points */
+               for (i = 1; i < len; i++) {
+                       y = this.h - (values[i] / n) + yoffset;
+                       x += this.xstep;
+                       path += ' L' + x + ',' + y;
+               }
+
+               /* Close path and fill it */
+               path += ' L' + x + ',' + (this.h-1) + ' Z';
+               o = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+               o.setAttribute('stroke', color);
+               o.setAttribute('fill', color);
+               o.setAttribute('d', path);
+               this.svg.appendChild(o);
+}      };
+
+
+SVGChartPainter.prototype.drawLine = function(color, values) {
+       var i, len, x, y, n, yoffset, path, o;
+
+       /* Determine distance between points and offset */
+       n = this.range/this.h;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+
+               /* Determine position of first point and start path */
+               x = 1;
+               y = this.h - (values[0] / n) + yoffset;
+               path = 'M' + x + ',' + y;
+
+               /* Append line to commands for succeeding points */
+               for (i = 1; i < len; i++) {
+                       y = this.h - (values[i] / n) + yoffset;
+                       x += this.xstep;
+                       path += ' L' + x + ',' + y;
+               }
+
+               /* Draw path */
+               o = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+               o.setAttribute('stroke', color);
+               o.setAttribute('fill', 'none');
+               o.setAttribute('stroke-width', '1px');
+               o.setAttribute('d', path);
+               this.svg.appendChild(o);
+}      };
+
+
+SVGChartPainter.prototype.drawBars = function(color, values, xoffset, width) {
+       var i, len, x, y, n, yoffset;
+
+       /* Determine distance between points and offset */
+       n = this.range/this.h;
+       yoffset = (this.ymin / n);
+
+       len = values.length;
+       if (len) {
+
+               /* Determine position of each bar and draw it */
+               x = xoffset + 1;
+               for (i = 0; i < len; i++) {
+                       y = this.h - (values[i] / n);
+                       this._drawRect(color, x, y, width, this.h - y);
+                       x += this.xstep;
+}      }       };
+
+
+SVGChartPainter.prototype._drawRect = function(color, x, y, w, h) {
+       var rect;
+
+       rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
+       rect.setAttribute('stroke', 'none');
+       rect.setAttribute('fill', color);
+       rect.setAttribute('x', x + 'px');
+       rect.setAttribute('y', y + 'px');
+       rect.setAttribute('width', w + 'px');
+       rect.setAttribute('height', h + 'px');
+
+       this.svg.appendChild(rect);
+};
diff --git a/trunk/NP_Clap/clap/chart/wz_jsgraphics.js b/trunk/NP_Clap/clap/chart/wz_jsgraphics.js
new file mode 100644 (file)
index 0000000..c0ed67c
--- /dev/null
@@ -0,0 +1,943 @@
+/* This notice must be untouched at all times.
+
+wz_jsgraphics.js    v. 2.33
+The latest version is available at
+http://www.walterzorn.com
+or http://www.devira.com
+or http://www.walterzorn.de
+
+Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
+Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
+Last modified: 24. 10. 2005
+
+Performance optimizations for Internet Explorer
+by Thomas Frank and John Holdsworth.
+fillPolygon method implemented by Matthieu Haller.
+
+High Performance JavaScript Graphics Library.
+Provides methods
+- to draw lines, rectangles, ellipses, polygons
+       with specifiable line thickness,
+- to fill rectangles and ellipses
+- to draw text.
+NOTE: Operations, functions and branching have rather been optimized
+to efficiency and speed than to shortness of source code.
+
+LICENSE: LGPL
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License (LGPL) as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
+or see http://www.gnu.org/copyleft/lesser.html
+*/
+
+
+var jg_ihtm, jg_ie, jg_fast, jg_dom, jg_moz,
+jg_n4 = (document.layers && typeof document.classes != "undefined");
+
+
+function chkDHTM(x, i)
+{
+       x = document.body || null;
+       jg_ie = x && typeof x.insertAdjacentHTML != "undefined";
+       jg_dom = (x && !jg_ie &&
+               typeof x.appendChild != "undefined" &&
+               typeof document.createRange != "undefined" &&
+               typeof (i = document.createRange()).setStartBefore != "undefined" &&
+               typeof i.createContextualFragment != "undefined");
+       jg_ihtm = !jg_ie && !jg_dom && x && typeof x.innerHTML != "undefined";
+       jg_fast = jg_ie && document.all && !window.opera;
+       jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
+}
+
+
+function pntDoc()
+{
+       this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);
+       this.htm = '';
+}
+
+
+function pntCnvDom()
+{
+       var x = document.createRange();
+       x.setStartBefore(this.cnv);
+       x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);
+       this.cnv.appendChild(x);
+       this.htm = '';
+}
+
+
+function pntCnvIe()
+{
+       this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);
+       this.htm = '';
+}
+
+
+function pntCnvIhtm()
+{
+       this.cnv.innerHTML += this.htm;
+       this.htm = '';
+}
+
+
+function pntCnv()
+{
+       this.htm = '';
+}
+
+
+function mkDiv(x, y, w, h)
+{
+       this.htm += '<div style="position:absolute;'+
+               'left:' + x + 'px;'+
+               'top:' + y + 'px;'+
+               'width:' + w + 'px;'+
+               'height:' + h + 'px;'+
+               'clip:rect(0,'+w+'px,'+h+'px,0);'+
+               'background-color:' + this.color +
+               (!jg_moz? ';overflow:hidden' : '')+
+               ';"><\/div>';
+}
+
+
+function mkDivIe(x, y, w, h)
+{
+       this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
+}
+
+
+function mkDivPrt(x, y, w, h)
+{
+       this.htm += '<div style="position:absolute;'+
+               'border-left:' + w + 'px solid ' + this.color + ';'+
+               'left:' + x + 'px;'+
+               'top:' + y + 'px;'+
+               'width:0px;'+
+               'height:' + h + 'px;'+
+               'clip:rect(0,'+w+'px,'+h+'px,0);'+
+               'background-color:' + this.color +
+               (!jg_moz? ';overflow:hidden' : '')+
+               ';"><\/div>';
+}
+
+
+function mkLyr(x, y, w, h)
+{
+       this.htm += '<layer '+
+               'left="' + x + '" '+
+               'top="' + y + '" '+
+               'width="' + w + '" '+
+               'height="' + h + '" '+
+               'bgcolor="' + this.color + '"><\/layer>\n';
+}
+
+
+var regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
+function htmRpc()
+{
+       return this.htm.replace(
+               regex,
+               '<div style="overflow:hidden;position:absolute;background-color:'+
+               '$1;left:$2;top:$3;width:$4;height:$5"></div>\n');
+}
+
+
+function htmPrtRpc()
+{
+       return this.htm.replace(
+               regex,
+               '<div style="overflow:hidden;position:absolute;background-color:'+
+               '$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');
+}
+
+
+function mkLin(x1, y1, x2, y2)
+{
+       if (x1 > x2)
+       {
+               var _x2 = x2;
+               var _y2 = y2;
+               x2 = x1;
+               y2 = y1;
+               x1 = _x2;
+               y1 = _y2;
+       }
+       var dx = x2-x1, dy = Math.abs(y2-y1),
+       x = x1, y = y1,
+       yIncr = (y1 > y2)? -1 : 1;
+
+       if (dx >= dy)
+       {
+               var pr = dy<<1,
+               pru = pr - (dx<<1),
+               p = pr-dx,
+               ox = x;
+               while ((dx--) > 0)
+               {
+                       ++x;
+                       if (p > 0)
+                       {
+                               this.mkDiv(ox, y, x-ox, 1);
+                               y += yIncr;
+                               p += pru;
+                               ox = x;
+                       }
+                       else p += pr;
+               }
+               this.mkDiv(ox, y, x2-ox+1, 1);
+       }
+
+       else
+       {
+               var pr = dx<<1,
+               pru = pr - (dy<<1),
+               p = pr-dy,
+               oy = y;
+               if (y2 <= y1)
+               {
+                       while ((dy--) > 0)
+                       {
+                               if (p > 0)
+                               {
+                                       this.mkDiv(x++, y, 1, oy-y+1);
+                                       y += yIncr;
+                                       p += pru;
+                                       oy = y;
+                               }
+                               else
+                               {
+                                       y += yIncr;
+                                       p += pr;
+                               }
+                       }
+                       this.mkDiv(x2, y2, 1, oy-y2+1);
+               }
+               else
+               {
+                       while ((dy--) > 0)
+                       {
+                               y += yIncr;
+                               if (p > 0)
+                               {
+                                       this.mkDiv(x++, oy, 1, y-oy);
+                                       p += pru;
+                                       oy = y;
+                               }
+                               else p += pr;
+                       }
+                       this.mkDiv(x2, oy, 1, y2-oy+1);
+               }
+       }
+}
+
+
+function mkLin2D(x1, y1, x2, y2)
+{
+       if (x1 > x2)
+       {
+               var _x2 = x2;
+               var _y2 = y2;
+               x2 = x1;
+               y2 = y1;
+               x1 = _x2;
+               y1 = _y2;
+       }
+       var dx = x2-x1, dy = Math.abs(y2-y1),
+       x = x1, y = y1,
+       yIncr = (y1 > y2)? -1 : 1;
+
+       var s = this.stroke;
+       if (dx >= dy)
+       {
+               if (dx > 0 && s-3 > 0)
+               {
+                       var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
+                       _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
+               }
+               else var _s = s;
+               var ad = Math.ceil(s/2);
+
+               var pr = dy<<1,
+               pru = pr - (dx<<1),
+               p = pr-dx,
+               ox = x;
+               while ((dx--) > 0)
+               {
+                       ++x;
+                       if (p > 0)
+                       {
+                               this.mkDiv(ox, y, x-ox+ad, _s);
+                               y += yIncr;
+                               p += pru;
+                               ox = x;
+                       }
+                       else p += pr;
+               }
+               this.mkDiv(ox, y, x2-ox+ad+1, _s);
+       }
+
+       else
+       {
+               if (s-3 > 0)
+               {
+                       var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
+                       _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
+               }
+               else var _s = s;
+               var ad = Math.round(s/2);
+
+               var pr = dx<<1,
+               pru = pr - (dy<<1),
+               p = pr-dy,
+               oy = y;
+               if (y2 <= y1)
+               {
+                       ++ad;
+                       while ((dy--) > 0)
+                       {
+                               if (p > 0)
+                               {
+                                       this.mkDiv(x++, y, _s, oy-y+ad);
+                                       y += yIncr;
+                                       p += pru;
+                                       oy = y;
+                               }
+                               else
+                               {
+                                       y += yIncr;
+                                       p += pr;
+                               }
+                       }
+                       this.mkDiv(x2, y2, _s, oy-y2+ad);
+               }
+               else
+               {
+                       while ((dy--) > 0)
+                       {
+                               y += yIncr;
+                               if (p > 0)
+                               {
+                                       this.mkDiv(x++, oy, _s, y-oy+ad);
+                                       p += pru;
+                                       oy = y;
+                               }
+                               else p += pr;
+                       }
+                       this.mkDiv(x2, oy, _s, y2-oy+ad+1);
+               }
+       }
+}
+
+
+function mkLinDott(x1, y1, x2, y2)
+{
+       if (x1 > x2)
+       {
+               var _x2 = x2;
+               var _y2 = y2;
+               x2 = x1;
+               y2 = y1;
+               x1 = _x2;
+               y1 = _y2;
+       }
+       var dx = x2-x1, dy = Math.abs(y2-y1),
+       x = x1, y = y1,
+       yIncr = (y1 > y2)? -1 : 1,
+       drw = true;
+       if (dx >= dy)
+       {
+               var pr = dy<<1,
+               pru = pr - (dx<<1),
+               p = pr-dx;
+               while ((dx--) > 0)
+               {
+                       if (drw) this.mkDiv(x, y, 1, 1);
+                       drw = !drw;
+                       if (p > 0)
+                       {
+                               y += yIncr;
+                               p += pru;
+                       }
+                       else p += pr;
+                       ++x;
+               }
+               if (drw) this.mkDiv(x, y, 1, 1);
+       }
+
+       else
+       {
+               var pr = dx<<1,
+               pru = pr - (dy<<1),
+               p = pr-dy;
+               while ((dy--) > 0)
+               {
+                       if (drw) this.mkDiv(x, y, 1, 1);
+                       drw = !drw;
+                       y += yIncr;
+                       if (p > 0)
+                       {
+                               ++x;
+                               p += pru;
+                       }
+                       else p += pr;
+               }
+               if (drw) this.mkDiv(x, y, 1, 1);
+       }
+}
+
+
+function mkOv(left, top, width, height)
+{
+       var a = width>>1, b = height>>1,
+       wod = width&1, hod = (height&1)+1,
+       cx = left+a, cy = top+b,
+       x = 0, y = b,
+       ox = 0, oy = b,
+       aa = (a*a)<<1, bb = (b*b)<<1,
+       st = (aa>>1)*(1-(b<<1)) + bb,
+       tt = (bb>>1) - aa*((b<<1)-1),
+       w, h;
+       while (y > 0)
+       {
+               if (st < 0)
+               {
+                       st += bb*((x<<1)+3);
+                       tt += (bb<<1)*(++x);
+               }
+               else if (tt < 0)
+               {
+                       st += bb*((x<<1)+3) - (aa<<1)*(y-1);
+                       tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
+                       w = x-ox;
+                       h = oy-y;
+                       if (w&2 && h&2)
+                       {
+                               this.mkOvQds(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);
+                               this.mkOvQds(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);
+                       }
+                       else this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);
+                       ox = x;
+                       oy = y;
+               }
+               else
+               {
+                       tt -= aa*((y<<1)-3);
+                       st -= (aa<<1)*(--y);
+               }
+       }
+       this.mkDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);
+       this.mkDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);
+}
+
+
+function mkOv2D(left, top, width, height)
+{
+       var s = this.stroke;
+       width += s-1;
+       height += s-1;
+       var a = width>>1, b = height>>1,
+       wod = width&1, hod = (height&1)+1,
+       cx = left+a, cy = top+b,
+       x = 0, y = b,
+       aa = (a*a)<<1, bb = (b*b)<<1,
+       st = (aa>>1)*(1-(b<<1)) + bb,
+       tt = (bb>>1) - aa*((b<<1)-1);
+
+       if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
+       {
+               var ox = 0, oy = b,
+               w, h,
+               pxl, pxr, pxt, pxb, pxw;
+               while (y > 0)
+               {
+                       if (st < 0)
+                       {
+                               st += bb*((x<<1)+3);
+                               tt += (bb<<1)*(++x);
+                       }
+                       else if (tt < 0)
+                       {
+                               st += bb*((x<<1)+3) - (aa<<1)*(y-1);
+                               tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
+                               w = x-ox;
+                               h = oy-y;
+
+                               if (w-1)
+                               {
+                                       pxw = w+1+(s&1);
+                                       h = s;
+                               }
+                               else if (h-1)
+                               {
+                                       pxw = s;
+                                       h += 1+(s&1);
+                               }
+                               else pxw = h = s;
+                               this.mkOvQds(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);
+                               ox = x;
+                               oy = y;
+                       }
+                       else
+                       {
+                               tt -= aa*((y<<1)-3);
+                               st -= (aa<<1)*(--y);
+                       }
+               }
+               this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
+               this.mkDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);
+       }
+
+       else
+       {
+               var _a = (width-((s-1)<<1))>>1,
+               _b = (height-((s-1)<<1))>>1,
+               _x = 0, _y = _b,
+               _aa = (_a*_a)<<1, _bb = (_b*_b)<<1,
+               _st = (_aa>>1)*(1-(_b<<1)) + _bb,
+               _tt = (_bb>>1) - _aa*((_b<<1)-1),
+
+               pxl = new Array(),
+               pxt = new Array(),
+               _pxb = new Array();
+               pxl[0] = 0;
+               pxt[0] = b;
+               _pxb[0] = _b-1;
+               while (y > 0)
+               {
+                       if (st < 0)
+                       {
+                               st += bb*((x<<1)+3);
+                               tt += (bb<<1)*(++x);
+                               pxl[pxl.length] = x;
+                               pxt[pxt.length] = y;
+                       }
+                       else if (tt < 0)
+                       {
+                               st += bb*((x<<1)+3) - (aa<<1)*(y-1);
+                               tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
+                               pxl[pxl.length] = x;
+                               pxt[pxt.length] = y;
+                       }
+                       else
+                       {
+                               tt -= aa*((y<<1)-3);
+                               st -= (aa<<1)*(--y);
+                       }
+
+                       if (_y > 0)
+                       {
+                               if (_st < 0)
+                               {
+                                       _st += _bb*((_x<<1)+3);
+                                       _tt += (_bb<<1)*(++_x);
+                                       _pxb[_pxb.length] = _y-1;
+                               }
+                               else if (_tt < 0)
+                               {
+                                       _st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);
+                                       _tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);
+                                       _pxb[_pxb.length] = _y-1;
+                               }
+                               else
+                               {
+                                       _tt -= _aa*((_y<<1)-3);
+                                       _st -= (_aa<<1)*(--_y);
+                                       _pxb[_pxb.length-1]--;
+                               }
+                       }
+               }
+
+               var ox = 0, oy = b,
+               _oy = _pxb[0],
+               l = pxl.length,
+               w, h;
+               for (var i = 0; i < l; i++)
+               {
+                       if (typeof _pxb[i] != "undefined")
+                       {
+                               if (_pxb[i] < _oy || pxt[i] < oy)
+                               {
+                                       x = pxl[i];
+                                       this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);
+                                       ox = x;
+                                       oy = pxt[i];
+                                       _oy = _pxb[i];
+                               }
+                       }
+                       else
+                       {
+                               x = pxl[i];
+                               this.mkDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);
+                               this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
+                               ox = x;
+                               oy = pxt[i];
+                       }
+               }
+               this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
+               this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
+       }
+}
+
+
+function mkOvDott(left, top, width, height)
+{
+       var a = width>>1, b = height>>1,
+       wod = width&1, hod = height&1,
+       cx = left+a, cy = top+b,
+       x = 0, y = b,
+       aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
+       st = (aa2>>1)*(1-(b<<1)) + bb,
+       tt = (bb>>1) - aa2*((b<<1)-1),
+       drw = true;
+       while (y > 0)
+       {
+               if (st < 0)
+               {
+                       st += bb*((x<<1)+3);
+                       tt += (bb<<1)*(++x);
+               }
+               else if (tt < 0)
+               {
+                       st += bb*((x<<1)+3) - aa4*(y-1);
+                       tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
+               }
+               else
+               {
+                       tt -= aa2*((y<<1)-3);
+                       st -= aa4*(--y);
+               }
+               if (drw) this.mkOvQds(cx, cy, -x, x+wod, -y, y+hod, 1, 1);
+               drw = !drw;
+       }
+}
+
+
+function mkRect(x, y, w, h)
+{
+       var s = this.stroke;
+       this.mkDiv(x, y, w, s);
+       this.mkDiv(x+w, y, s, h);
+       this.mkDiv(x, y+h, w+s, s);
+       this.mkDiv(x, y+s, s, h-s);
+}
+
+
+function mkRectDott(x, y, w, h)
+{
+       this.drawLine(x, y, x+w, y);
+       this.drawLine(x+w, y, x+w, y+h);
+       this.drawLine(x, y+h, x+w, y+h);
+       this.drawLine(x, y, x, y+h);
+}
+
+
+function jsgFont()
+{
+       this.PLAIN = 'font-weight:normal;';
+       this.BOLD = 'font-weight:bold;';
+       this.ITALIC = 'font-style:italic;';
+       this.ITALIC_BOLD = this.ITALIC + this.BOLD;
+       this.BOLD_ITALIC = this.ITALIC_BOLD;
+}
+var Font = new jsgFont();
+
+
+function jsgStroke()
+{
+       this.DOTTED = -1;
+}
+var Stroke = new jsgStroke();
+
+
+function jsGraphics(id, wnd)
+{
+       this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');
+
+       this.setStroke = function(x)
+       {
+               this.stroke = x;
+               if (!(x+1))
+               {
+                       this.drawLine = mkLinDott;
+                       this.mkOv = mkOvDott;
+                       this.drawRect = mkRectDott;
+               }
+               else if (x-1 > 0)
+               {
+                       this.drawLine = mkLin2D;
+                       this.mkOv = mkOv2D;
+                       this.drawRect = mkRect;
+               }
+               else
+               {
+                       this.drawLine = mkLin;
+                       this.mkOv = mkOv;
+                       this.drawRect = mkRect;
+               }
+       };
+
+
+       this.setPrintable = function(arg)
+       {
+               this.printable = arg;
+               if (jg_fast)
+               {
+                       this.mkDiv = mkDivIe;
+                       this.htmRpc = arg? htmPrtRpc : htmRpc;
+               }
+               else this.mkDiv = jg_n4? mkLyr : arg? mkDivPrt : mkDiv;
+       };
+
+
+       this.setFont = function(fam, sz, sty)
+       {
+               this.ftFam = fam;
+               this.ftSz = sz;
+               this.ftSty = sty || Font.PLAIN;
+       };
+
+
+       this.drawPolyline = this.drawPolyLine = function(x, y, s)
+       {
+               for (var i=0 ; i<x.length-1 ; i++ )
+                       this.drawLine(x[i], y[i], x[i+1], y[i+1]);
+       };
+
+
+       this.fillRect = function(x, y, w, h)
+       {
+               this.mkDiv(x, y, w, h);
+       };
+
+
+       this.drawPolygon = function(x, y)
+       {
+               this.drawPolyline(x, y);
+               this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
+       };
+
+
+       this.drawEllipse = this.drawOval = function(x, y, w, h)
+       {
+               this.mkOv(x, y, w, h);
+       };
+
+
+       this.fillEllipse = this.fillOval = function(left, top, w, h)
+       {
+               var a = (w -= 1)>>1, b = (h -= 1)>>1,
+               wod = (w&1)+1, hod = (h&1)+1,
+               cx = left+a, cy = top+b,
+               x = 0, y = b,
+               ox = 0, oy = b,
+               aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
+               st = (aa2>>1)*(1-(b<<1)) + bb,
+               tt = (bb>>1) - aa2*((b<<1)-1),
+               pxl, dw, dh;
+               if (w+1) while (y > 0)
+               {
+                       if (st < 0)
+                       {
+                               st += bb*((x<<1)+3);
+                               tt += (bb<<1)*(++x);
+                       }
+                       else if (tt < 0)
+                       {
+                               st += bb*((x<<1)+3) - aa4*(y-1);
+                               pxl = cx-x;
+                               dw = (x<<1)+wod;
+                               tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
+                               dh = oy-y;
+                               this.mkDiv(pxl, cy-oy, dw, dh);
+                               this.mkDiv(pxl, cy+y+hod, dw, dh);
+                               ox = x;
+                               oy = y;
+                       }
+                       else
+                       {
+                               tt -= aa2*((y<<1)-3);
+                               st -= aa4*(--y);
+                       }
+               }
+               this.mkDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);
+       };
+
+
+/* fillPolygon method, implemented by Matthieu Haller.
+This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
+C source of GD 1.8.4 found at http://www.boutell.com/gd/
+
+THANKS to Kirsten Schulz for the polygon fixes!
+
+The intersection finding technique of this code could be improved
+by remembering the previous intertersection, and by using the slope.
+That could help to adjust intersections to produce a nice
+interior_extrema. */
+       this.fillPolygon = function(array_x, array_y)
+       {
+               var i;
+               var y;
+               var miny, maxy;
+               var x1, y1;
+               var x2, y2;
+               var ind1, ind2;
+               var ints;
+
+               var n = array_x.length;
+
+               if (!n) return;
+
+
+               miny = array_y[0];
+               maxy = array_y[0];
+               for (i = 1; i < n; i++)
+               {
+                       if (array_y[i] < miny)
+                               miny = array_y[i];
+
+                       if (array_y[i] > maxy)
+                               maxy = array_y[i];
+               }
+               for (y = miny; y <= maxy; y++)
+               {
+                       var polyInts = new Array();
+                       ints = 0;
+                       for (i = 0; i < n; i++)
+                       {
+                               if (!i)
+                               {
+                                       ind1 = n-1;
+                                       ind2 = 0;
+                               }
+                               else
+                               {
+                                       ind1 = i-1;
+                                       ind2 = i;
+                               }
+                               y1 = array_y[ind1];
+                               y2 = array_y[ind2];
+                               if (y1 < y2)
+                               {
+                                       x1 = array_x[ind1];
+                                       x2 = array_x[ind2];
+                               }
+                               else if (y1 > y2)
+                               {
+                                       y2 = array_y[ind1];
+                                       y1 = array_y[ind2];
+                                       x2 = array_x[ind1];
+                                       x1 = array_x[ind2];
+                               }
+                               else continue;
+
+                                // modified 11. 2. 2004 Walter Zorn
+                               if ((y >= y1) && (y < y2))
+                                       polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
+
+                               else if ((y == maxy) && (y > y1) && (y <= y2))
+                                       polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
+                       }
+                       polyInts.sort(integer_compare);
+                       for (i = 0; i < ints; i+=2)
+                               this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
+               }
+       };
+
+
+       this.drawString = function(txt, x, y)
+       {
+               this.htm += '<div style="position:absolute;white-space:nowrap;'+
+                       'left:' + x + 'px;'+
+                       'top:' + y + 'px;'+
+                       'font-family:' +  this.ftFam + ';'+
+                       'font-size:' + this.ftSz + ';'+
+                       'color:' + this.color + ';' + this.ftSty + '">'+
+                       txt +
+                       '<\/div>';
+       };
+
+
+/* drawStringRect() added by Rick Blommers.
+Allows to specify the size of the text rectangle and to align the
+text both horizontally (e.g. right) and vertically within that rectangle */
+       this.drawStringRect = function(txt, x, y, width, halign)
+       {
+               this.htm += '<div style="position:absolute;overflow:hidden;'+
+                       'left:' + x + 'px;'+
+                       'top:' + y + 'px;'+
+                       'width:'+width +'px;'+
+                       'text-align:'+halign+';'+
+                       'font-family:' +  this.ftFam + ';'+
+                       'font-size:' + this.ftSz + ';'+
+                       'color:' + this.color + ';' + this.ftSty + '">'+
+                       txt +
+                       '<\/div>';
+       };
+
+
+       this.drawImage = function(imgSrc, x, y, w, h, a)
+       {
+               this.htm += '<div style="position:absolute;'+
+                       'left:' + x + 'px;'+
+                       'top:' + y + 'px;'+
+                       'width:' +  w + ';'+
+                       'height:' + h + ';">'+
+                       '<img src="' + imgSrc + '" width="' + w + '" height="' + h + '"' + (a? (' '+a) : '') + '>'+
+                       '<\/div>';
+       };
+
+
+       this.clear = function()
+       {
+               this.htm = "";
+               if (this.cnv) this.cnv.innerHTML = this.defhtm;
+       };
+
+
+       this.mkOvQds = function(cx, cy, xl, xr, yt, yb, w, h)
+       {
+               this.mkDiv(xr+cx, yt+cy, w, h);
+               this.mkDiv(xr+cx, yb+cy, w, h);
+               this.mkDiv(xl+cx, yb+cy, w, h);
+               this.mkDiv(xl+cx, yt+cy, w, h);
+       };
+
+       this.setStroke(1);
+       this.setFont('verdana,geneva,helvetica,sans-serif', String.fromCharCode(0x31, 0x32, 0x70, 0x78), Font.PLAIN);
+       this.color = '#000000';
+       this.htm = '';
+       this.wnd = wnd || window;
+
+       if (!(jg_ie || jg_dom || jg_ihtm)) chkDHTM();
+       if (typeof id != 'string' || !id) this.paint = pntDoc;
+       else
+       {
+               this.cnv = document.all? (this.wnd.document.all[id] || null)
+                       : document.getElementById? (this.wnd.document.getElementById(id) || null)
+                       : null;
+               this.defhtm = (this.cnv && this.cnv.innerHTML)? this.cnv.innerHTML : '';
+               this.paint = jg_dom? pntCnvDom : jg_ie? pntCnvIe : jg_ihtm? pntCnvIhtm : pntCnv;
+       }
+
+       this.setPrintable(false);
+}
+
+
+
+function integer_compare(x,y)
+{
+       return (x < y) ? -1 : ((x > y)*1);
+}
+
diff --git a/trunk/NP_Clap/clap/help.html b/trunk/NP_Clap/clap/help.html
new file mode 100644 (file)
index 0000000..248ebf4
--- /dev/null
@@ -0,0 +1,53 @@
+<h3>Plugin概要 <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13"></a>&nbsp;<a href="http://cles.jp/"><img border="0" src="http://blog.cles.jp/cles.png"  alt="Powered by CLES" /></a></h3>
+
+<h3>使い方</h3>
+<p>下記のURLを参考に設定を行ってください。</p>
+<ul>
+       <li><a href="http://blog.cles.jp/np_cles/category/31/subcatid/13">作者サイト</a></li>
+       <li><a href="http://japan.nucleuscms.org/wiki/plugins:clap">plugins:clap [Nucleus CMS Japan Wiki]</a></li>
+</ul>
+
+<h3>バージョン履歴</h3>
+<p>新バージョンは<a href="http://blog.cles.jp/np_cles/">NP_cles()</a>で確認してください。</p>
+<ul>
+       <li>Version 1.6: (2008/05/18)</li>
+       <li> [Fixed] カテゴリの関連付けがおかしくなる問題を再度修正</li>
+       
+       <li>Version 1.5: (2007/11/11)</li>
+       <li> [Added] メール内にhostname, useragent, refererを表示できるようにした</li>
+       <li> [Fixed] mysql_query()をsql_query()に変更</li>
+       <li> [Added] カテゴリごとに表示するコンテンツ・テンプレートが指定できるようにした</li>
+       <li> [Changed] ログインしている場合にカウントしないようにした</li>
+       <li> [Fixed] カテゴリの関連付けがおかしくなる問題に対応した (1.5.1)</li>
+       
+       <li>Version 1.4: (2007/03/17)</li>
+       <li> [Added] カウント表示の日付での絞り込み</li>
+       <li> [Fixed] カウント表示時にブログでの絞込みが効いていない不具合を修正</li>
+       <li> [Fixed] バックアップが正常に行われない不具合を修正</li>
+       <li> [Fixed] 拍手ボタンを押した後にエラーが表示される問題を修正</li>
+       <li> [Fixed] Thanksページのコンテンツごとのプレビューがランダムになっていた問題を修正</li>
+       
+       <li>Version 1.3: (2006/11/26)</li>
+       <li> [Added] Ticket処理を追加(CSRF対策)</li>
+       <li> [Added] グラフ表示機能を追加</li>
+       <li> [Added] 管理画面にアイコンを追加</li>
+       
+       <li>Version 1.2: (2005/09/30)</li>
+       <li> [Fixed] &lt;%Clap(actionurl)%&gt;の不具合を修正</li>
+       <li> [Fixed] 管理画面の不具合を修正</li>
+       <li> [Fixed] セキュリティの向上</li>
+       
+       <li>Version 1.1: (2006/05/20)</li>
+       <li> [Changed] Thanksページの内容の設定をプラグインオプションから、管理画面に移行</li>
+       <li> [Added]プレビュー機能を追加</li>
+       
+       <li>Version 1.0: (2006/05/05)</li>
+       <li> [NEW] 初版公開</li>
+</ul>
+
+<h3>開発者について</h3>
+
+<ul>
+  <li><a href="http://blog.cles.jp/member/1">hsur</a> (<a href="http://blog.cles.jp/">cles::blog</a>)</li>
+  <li>ドネーションや仕事のご依頼も歓迎します。</li>
+</ul>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/index.php b/trunk/NP_Clap/clap/index.php
new file mode 100644 (file)
index 0000000..8baaa50
--- /dev/null
@@ -0,0 +1,388 @@
+<?php
+// vim: tabstop=2:shiftwidth=2
+
+/**
+  * index.php ($Revision: 1.1 $)
+  * 
+  * by hsur ( http://blog.cles.jp/np_cles )
+  * $Id: index.php,v 1.1 2008-05-17 19:11:10 hsur Exp $
+*/
+
+/*
+  * Copyright (C) 2005-2007 CLES. All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+  * 
+  * In addition, as a special exception, cles( http://blog.cles.jp/np_cles ) gives
+  * permission to link the code of this program with those files in the PEAR
+  * library that are licensed under the PHP License (or with modified versions
+  * of those files that use the same license as those files), and distribute
+  * linked combinations including the two. You must obey the GNU General Public
+  * License in all respects for all of the code used other than those files in
+  * the PEAR library that are licensed under the PHP License. If you modify
+  * this file, you may extend this exception to your version of the file,
+  * but you are not obligated to do so. If you do not wish to do so, delete
+  * this exception statement from your version.
+*/
+
+$strRel = '../../../';
+include ($strRel.'config.php');
+include ($DIR_LIBS.'PLUGINADMIN.php');
+
+require_once($DIR_PLUGINS . 'sharedlibs/sharedlibs.php');
+require_once('cles/Feedback.php');
+require_once('cles/Template.php');
+
+sendContentType('application/xhtml+xml', 'admin-clap', _CHARSET);
+
+// create the admin area page
+$oPluginAdmin = new PluginAdmin('Clap');
+$oPluginAdmin->start();
+$fb =& new cles_Feedback($oPluginAdmin);
+
+if (!($member->isLoggedIn() && $member->isAdmin())){
+       echo '<p>' . _ERROR_DISALLOWED . '</p>';
+       $oPluginAdmin->end();
+       exit;
+}
+
+//action
+$action = requestVar('action');
+$aActionsNotToCheck = array(
+       '',
+       'report',
+);
+if (!in_array($action, $aActionsNotToCheck)) {
+       if (!$manager->checkTicket()) doError(_ERROR_BADTICKET);
+}
+
+$templateEngine =& new cles_Template(dirname(__FILE__).'/template');
+define('NP_CLAP_TEMPLATEDIR_INDEX', 'index');
+$tplVars = array(
+       'indexurl' => serverVar('PHP_SELF'),
+       'itemperpage' => '20',
+       'optionurl' => $CONF['AdminURL'] . 'index.php?action=pluginoptions&amp;plugid=' . $oPluginAdmin->plugin->getid(),
+       'actionurl' => $CONF['ActionURL'],
+       'ticket' => $manager->_generateTicket(),
+       'plugindirurl' => $oPluginAdmin->plugin->getAdminURL(),
+);
+
+// menu
+$menu = $templateEngine->fetch('menu', NP_CLAP_TEMPLATEDIR_INDEX);
+echo $templateEngine->fill($menu, $tplVars, false);
+
+switch ($action) {
+       case 'delete' :
+               if( is_numeric(requestVar('id')) ){
+                       $oPluginAdmin->plugin->deleteClap(intRequestVar('id'));
+               }
+               $action = 'detail';
+               break;
+       case 'thanksdelete' :
+               if( is_numeric(requestVar('id')) ){
+                       $oPluginAdmin->plugin->deleteThanksMsg(intRequestVar('id'));
+               }
+               $action = 'thanksmsg';
+               break;
+       case 'thankssave' :
+               if( is_numeric(requestVar('id')) || requestVar('id') == 'new' ){
+                       $msg['id'] = requestVar('id');
+                       $msg['comment'] = requestVar('comment');
+                       $msg['image'] = requestVar('image');
+                       $oPluginAdmin->plugin->setThanksMsg($msg);
+                       
+                       $oPluginAdmin->plugin->setAssociatedCategories(requestVar('id'), requestArray('assoc'), requestVar('assoc_etc'));
+               }
+               $action = 'thanksmsg';
+       case 'docorrect' :
+               $tplVars['message'] = $oPluginAdmin->plugin->_correctBrokenThanksCategory();
+               $action = 'thanksmsg';
+               break;
+}
+
+switch ($action) {
+       case 'convert' :
+               $content = $templateEngine->fetch('convert', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               break;
+               
+       case 'doconvert' :
+               $query = 'DELETE FROM ' . sql_table('plugin_clap') . ' where ipaddr = \'127.0.0.2\' ';
+               sql_query($query);
+               
+               $query = 'SELECT inumber, ikarmapos FROM ' . sql_table('item') . ' where ikarmapos > 0';
+               $res = sql_query($query);
+               
+               while( $row = mysql_fetch_assoc($res) ){
+                       for($i = $row['ikarmapos'] ; $i > 0 ; $i -= 1  ){
+                       $query = sprintf('INSERT INTO ' . sql_table('plugin_clap') 
+                                       . ' ( `itemkey`, `timestamp`, `ipaddr` ) '
+                                       . " values('%s', '1970-01-01 00:00:00', '127.0.0.2') "
+                                       , mysql_real_escape_string( $row['inumber'] )
+                       );
+                       sql_query($query);
+                       }
+               }               
+                       
+               $content = $templateEngine->fetch('doconvert', NP_CLAP_TEMPLATEDIR_INDEX);      \r       $templateEngine->fill($content, $tplVars, null);
+               echo $templateEngine->fill($content, $tplVars, null);
+               break;
+
+       case 'reset' :
+               $content = $templateEngine->fetch('reset', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               break;
+               
+       case 'doreset' :
+               $query = 'TRUNCATE TABLE ' . sql_table('plugin_clap');
+               sql_query($query);
+               
+               $query = 'TRUNCATE TABLE ' . sql_table('plugin_clap_comment');
+               sql_query($query);
+       
+               $content = $templateEngine->fetch('doreset', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               break;
+
+       case 'report' :
+               $fb->printForm('');
+               break;
+               
+       case 'detail' :
+               $tplVars['key'] = requestVar('key') ? requestVar('key') : null;
+               if( ! $tplVars['key'] ){
+                       $tplVars['message'] = '"key" is not set.';
+                       $content = $templateEngine->fetch('error', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $tplVars, null);
+                       break;
+               }
+               $tplVars['offset'] = intRequestVar('offset') ? intRequestVar('offset') : 0;
+               
+               $res = $oPluginAdmin->plugin->getDetail($tplVars['key'], $tplVars['offset'], 99999999);
+               $tplVars['rowcount'] = mysql_num_rows($res);
+
+               $res = $oPluginAdmin->plugin->getDetail($tplVars['key'], $tplVars['offset'], $tplVars['itemperpage']);
+               if( $tplVars['itemperpage'] + $tplVars['offset'] < $tplVars['rowcount'] ){
+                       $content = $templateEngine->fetch('detail_nextbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['next_offset'] = $tplVars['offset'] + $tplVars['itemperpage'];
+                       $tplVars['next_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+               if( $tplVars['offset'] > 0 ){
+                       $content = $templateEngine->fetch('detail_prevbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['prev_offset'] = $tplVars['offset'] - $tplVars['itemperpage'];
+                       $tplVars['prev_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+
+               $content = $templateEngine->fetch('detail_header', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               while( $row = mysql_fetch_assoc($res) ){
+                       $row = array_merge($tplVars, $row);
+                       $row['ipaddr'] = ( $row['ipaddr'] == '127.0.0.2' ) ? 'karma' : $row['ipaddr'];
+                       $row['comment'] = nl2br(htmlspecialchars($row['comment'], ENT_QUOTES));
+                       $content = $templateEngine->fetch('detail_item', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $row, null);                       
+               }               
+               
+               $content = $templateEngine->fetch('detail_footer', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               break;
+               
+       case 'messagelist' :
+               $tplVars['offset'] = intRequestVar('offset') ? intRequestVar('offset') : 0;
+               $res = $oPluginAdmin->plugin->getMessageList($tplVars['offset'], 99999999);
+               $tplVars['rowcount'] = mysql_num_rows($res);
+
+               $res = $oPluginAdmin->plugin->getMessageList($tplVars['offset'], $tplVars['itemperpage']);
+               if( $tplVars['itemperpage'] + $tplVars['offset'] < $tplVars['rowcount'] ){
+                       $content = $templateEngine->fetch('messagelist_nextbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['next_offset'] = $tplVars['offset'] + $tplVars['itemperpage'];
+                       $tplVars['next_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+               if( $tplVars['offset'] > 0 ){
+                       $content = $templateEngine->fetch('messagelist_prevbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['prev_offset'] = $tplVars['offset'] - $tplVars['itemperpage'];
+                       $tplVars['prev_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+
+               $content = $templateEngine->fetch('messagelist_header', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               while( $row = mysql_fetch_assoc($res) ){
+                       $row = array_merge($tplVars, $row);
+                       $row['comment'] = nl2br(htmlspecialchars($row['comment'], ENT_QUOTES));
+                       $content = $templateEngine->fetch('messagelist_item', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $row, null);                       
+               }               
+               
+               $content = $templateEngine->fetch('messagelist_footer', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               break;
+               
+       case 'thanksmsg' :
+               $tplVars['offset'] = intRequestVar('offset') ? intRequestVar('offset') : 0;
+               $res = $oPluginAdmin->plugin->getThanksMsgList($tplVars['offset'], 99999999);
+               $tplVars['rowcount'] = mysql_num_rows($res);
+               
+               $res = $oPluginAdmin->plugin->getThanksMsgList($tplVars['offset'], $tplVars['itemperpage']);
+               if( $tplVars['itemperpage'] + $tplVars['offset'] < $tplVars['rowcount'] ){
+                       $content = $templateEngine->fetch('thanksmsg_nextbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['next_offset'] = $tplVars['offset'] + $tplVars['itemperpage'];
+                       $tplVars['next_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+               if( $tplVars['offset'] > 0 ){
+                       $content = $templateEngine->fetch('thanksmsg_prevbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['prev_offset'] = $tplVars['offset'] - $tplVars['itemperpage'];
+                       $tplVars['prev_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+
+               $content = $templateEngine->fetch('thanksmsg_header', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               while( $row = mysql_fetch_assoc($res) ){
+                       $row = array_merge($tplVars, $row);
+                       if( trim($row['image']) )
+                               $row['image'] = '<img border="0" src="'.$oPluginAdmin->plugin->getAdminURL().'silk/picture.png" />';
+                       else
+                               $row['image'] = '<img border="0" src="'.$oPluginAdmin->plugin->getAdminURL().'silk/picture_empty.png" />';
+                       $row['comment'] = shorten(strip_tags($row['comment']),200,'...');
+                       
+                       $content = $templateEngine->fetch('thanksmsg_item', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $row, null);                       
+               }
+               
+               $content = $templateEngine->fetch('thanksmsg_footer', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               break;
+               
+       case 'thanksedit':
+               if( ! ( is_numeric(requestVar('id')) || requestVar('id') == 'new' ) ){
+                       $tplVars['message'] = '"id" is not set.';
+                       $content = $templateEngine->fetch('error', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $tplVars, null);
+                       break;
+               }
+               
+               $assoc = array();
+               if( requestVar('id') != 'new' ){
+                       $msg = $oPluginAdmin->plugin->getThanksMsg(intRequestVar('id'));
+                       $assoc = $oPluginAdmin->plugin->getAssociatedCategoriesByThanksId(intRequestVar('id'));
+               } else {
+                       $msg['id'] = 'new';
+                       $msg['image'] = '<img src="#" alt="" title="" />';
+                       $assoc[] = NP_CLAP_GLOBALKEY;
+               }
+               $msg = array_merge($tplVars, $msg);
+               
+               if( in_array(NP_CLAP_GLOBALKEY, $assoc) )
+                       $msg['assoc'] = '<input type="checkbox" name="assoc[]" value="'.NP_CLAP_GLOBALKEY.'" checked="checked" />'.NP_CLAP_GLOBALKEY.'<br />';
+               else
+                       $msg['assoc'] = '<input type="checkbox" name="assoc[]" value="'.NP_CLAP_GLOBALKEY.'" />'.NP_CLAP_GLOBALKEY.'<br />';
+               
+               $blogs = $oPluginAdmin->plugin->getBloglist();
+               $res = sql_query('SELECT catid, cname, cblog FROM '.sql_table('category').' ORDER BY cblog, catid');
+               if( @mysql_num_rows($res) > 0) {
+                       $currrentBlog = null;
+                       while( $o = mysql_fetch_object($res) ){
+                               if( $currrentBlog != $o->cblog){
+                                       $currrentBlog = $o->cblog;
+                                       $msg['assoc'] .= sprintf(NP_CLAP_ALLCHECK, $o->cblog, $o->cblog);
+                               }
+                               
+                               if( in_array($o->catid, $assoc) )
+                                       $tpl_checkbox = '<input id="%s" type="checkbox" name="assoc[]" value="%s" checked="checked" />%s<br />';
+                               else
+                                       $tpl_checkbox = '<input id="%s" type="checkbox" name="assoc[]" value="%s" />%s<br />';
+                               $msg['assoc'] .= sprintf($tpl_checkbox, 
+                                       htmlspecialchars($o->cblog.'_'.$o->catid, ENT_QUOTES),
+                                       htmlspecialchars($o->catid, ENT_QUOTES),
+                                       htmlspecialchars($o->cname.' ( '.$blogs[$o->cblog].' )', ENT_QUOTES)
+                               );
+                       }
+               }
+               
+               $assoc_etc = array();
+               foreach ( $assoc as $key) {
+                       if( $key == NP_CLAP_GLOBALKEY ) continue; 
+                       if( is_numeric($key) ) continue; 
+                       $assoc_etc[] = $key;
+               }
+               $msg['assoc_etc'] = implode(',', $assoc_etc);
+               
+               $content = $templateEngine->fetch('thanksedit', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $msg, null);
+               break;
+               
+       case 'chart' :
+               $content = $templateEngine->fetch('chart', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               break;
+
+       case 'overview' :
+       default :
+               $tplVars['offset'] = intRequestVar('offset') ? intRequestVar('offset') : 0;
+               $tplVars['blog'] = requestVar('blog') ? requestVar('blog') : '' ;
+               
+               $res = $oPluginAdmin->plugin->getOverview($tplVars['blog'], $tplVars['offset'], 99999999);
+               $tplVars['rowcount'] = mysql_num_rows($res);
+
+               $res = $oPluginAdmin->plugin->getOverview($tplVars['blog'], $tplVars['offset'], $tplVars['itemperpage']);
+               if( $tplVars['itemperpage'] + $tplVars['offset'] < $tplVars['rowcount'] ){
+                       $content = $templateEngine->fetch('overview_nextbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['next_offset'] = $tplVars['offset'] + $tplVars['itemperpage'];
+                       $tplVars['next_button'] = $templateEngine->fill($content, $tplVars, null);      
+               }
+               
+               if( $tplVars['offset'] > 0 ){
+                       $content = $templateEngine->fetch('overview_prevbutton', NP_CLAP_TEMPLATEDIR_INDEX);
+                       $tplVars['prev_offset'] = $tplVars['offset'] - $tplVars['itemperpage'];
+                       $tplVars['prev_button'] = $templateEngine->fill($content, $tplVars, null);
+               }
+               
+               $blogs = $oPluginAdmin->plugin->getBloglist();
+               $tplVars['blogselect'] .= '<form method="post" name="blogselect" action="'.$tplVars['indexurl'].'" style="display:inline" >';
+               $tplVars['blogselect'] .= '<input type="hidden" name="action" value="overview" />';
+               $tplVars['blogselect'] .= '<input type="hidden" name="offset" value="0" />';
+               $tplVars['blogselect'] .= '<input type="hidden" name="ticket" value="' . $tplVars['ticket'] . '" />';
+               $tplVars['blogselect'] .= '<select name="blog" onchange="javascript:submit()">';
+               $tplVars['blogselect'] .= '<option value="">ALL</option>';              
+               $tplVars['blogselect'] .= ( $tplVars['blog'] == 'global' ) ? '<option value="global" selected="selected">global</option>' : '<option value="global">global</option>';
+               foreach($blogs as $id => $name){
+                       $tplVars['blogselect'] .= ( $tplVars['blog'] == $id ) ? '<option value="'.intval($id).'" selected="selected">'.htmlspecialchars($name,ENT_QUOTES).'</option>' : '<option value="'.intval($id).'">'.htmlspecialchars($name,ENT_QUOTES).'</option>';
+               }               
+               $tplVars['blogselect'] .= '</select></form>';
+               
+               $content = $templateEngine->fetch('overview_header', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+               
+               while( $row = mysql_fetch_assoc($res) ){
+                       $row = array_merge($tplVars, $row);
+                       $row['blogname'] = $blogs[$row['blog']];
+                       $content = $templateEngine->fetch('overview_item', NP_CLAP_TEMPLATEDIR_INDEX);
+                       echo $templateEngine->fill($content, $row, null);                       
+               }               
+               
+               $content = $templateEngine->fetch('overview_footer', NP_CLAP_TEMPLATEDIR_INDEX);
+               echo $templateEngine->fill($content, $tplVars, null);
+                               
+               break;
+}
+
+echo '<div align="right">Powered by <a href="http://www.famfamfam.com/lab/icons/silk/">Silk icon</a></div>';
+
+$oPluginAdmin->end();
diff --git a/trunk/NP_Clap/clap/js/chart.js b/trunk/NP_Clap/clap/js/chart.js
new file mode 100644 (file)
index 0000000..57d3e5e
--- /dev/null
@@ -0,0 +1,76 @@
+function drawUsingKeyAndParam(key, param) {
+       var c = new Chart(document.getElementById(key));
+       c.setDefaultType(CHART_LINE);
+       c.setShowLegend(true);
+       
+       m = param['max'];
+       if( m > 30 ) m = 30;
+
+       c.setGridDensity(param['length']-0, m);
+       c.setVerticalRange(0, param['max']-0);
+
+       c.setHorizontalLabels( param['label']);
+       c.add('Total Count','#40ff40', param['count']);
+       c.add('IP Count','#4040FF', param['ipcount']);
+       c.add('Msg Count','#FF4040', param['msgcount']);
+       c.draw();
+}
+
+function updateMyChart(){
+       var yearSelect = $('year');
+       var monthSelect = $('month');
+
+       var pars = '&ajax=1&action=plugin&name=Clap&type=chart';
+       pars = pars + '&year=' + yearSelect.options[yearSelect.selectedIndex].value;
+       pars = pars + '&month=' + monthSelect.options[monthSelect.selectedIndex].value;
+       pars = pars + '&ticket=' + ticket;
+       var myAjax = new Ajax.Request(
+               actionurl, 
+               { method: 'get', parameters: pars, onSuccess: drawMyChart, onFailure: updateMyChartFailed }
+       );
+}
+
+function drawMyChart(originalRequest){
+       var param = eval( "(" + originalRequest.responseText + ")" );
+       
+       drawUsingKeyAndParam('key', param['key']);
+       drawUsingKeyAndParam('daysOfMonth', param['dayOfMonth']);
+       drawUsingKeyAndParam('daysOfWeek', param['dayOfWeek']);
+       drawUsingKeyAndParam('hours', param['hours']);
+
+       var yearSelect = $('year');
+       var monthSelect = $('month');   
+       var date = $('date');
+       date.innerHTML =  yearSelect.options[yearSelect.selectedIndex].value + '/' + monthSelect.options[monthSelect.selectedIndex].value
+}
+
+function updateMyChartFailed(originalRequest){
+       var d = $('message');
+       d.innerHTML = 'Update Failed';
+}
+
+function setList(select, list, selected){
+       for(i=0;i<list.length;i++){
+               select.options[i] = new Option(list[i],list[i]);
+       }
+       select.selectedIndex = selected-0;
+}
+
+window.onload = function() {
+       ieCanvasInit('chart/iecanvas.htc');
+       var yearSelect = $('year');
+       var monthSelect = $('month');
+
+       var now = new Date();
+       var yearArr = new Array();
+       for(i=0;i<5;i++){
+               yearArr.push( 1900 + now.getYear() - i + "" );
+       }       
+
+       setList(yearSelect, yearArr, 0);
+       setList(monthSelect, ["1","2","3","4","5","6","7","8","9","10","11","12"], now.getMonth() );
+       yearSelect.onchange = updateMyChart;
+       monthSelect.onchange = updateMyChart;
+
+       updateMyChart();
+};
diff --git a/trunk/NP_Clap/clap/js/prototype-1.4.0.js b/trunk/NP_Clap/clap/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_Clap/clap/language/japanese-euc.php b/trunk/NP_Clap/clap/language/japanese-euc.php
new file mode 100644 (file)
index 0000000..0854447
--- /dev/null
@@ -0,0 +1,21 @@
+<?php 
+
+// plugin description
+define('NP_CLAP_mailaddr', 'ÄÌÃÎÀè¥á¡¼¥ë¥¢¥É¥ì¥¹');            
+define('NP_CLAP_commentedOnly', '¥³¥á¥ó¥È¤¬½ñ¤«¤ì¤Æ¤¤¤ë¾ì¹ç¤Î¤ßÄÌÃΡ©');               
+define('NP_CLAP_antispam_limit', 'Ϣ³Åê¹ÆÀ©¸Â(¡Ö²ó¿ô/ÉáפǻØÄê¡£¡Ö10/600¡×¤Ç600É䢤¿¤ê10²ó¤Þ¤Ç)');          
+define('NP_CLAP_antispam_check', 'spam¥Á¥§¥Ã¥¯¤òÍ­¸ú¤Ë¤¹¤ë¤«¡©');              
+define('NP_CLAP_listThanksContent', 'Thanks¥Ú¡¼¥¸ÆâÍÆ(²èÁü¤ÎURL¤È¥³¥á¥ó¥È¤ò","¤Ç¶èÀÚ¤ê¤Ã¤ÆÆþÎϤ·¤Þ¤¹)');               
+define('NP_CLAP_deleteData', '¥¢¥ó¥¤¥ó¥¹¥È¡¼¥ë»þ¤Ë¥Ç¡¼¥¿¤òºï½ü¤¹¤ë');          
+
+define('NP_CLAP_description', 'Nucleus¤Ç¥¦¥§¥ÖÇï¼ê¤ò¼Â¸½¤·¤Þ¤¹');              
+define('NP_CLAP_corrected', '¥«¥Æ¥´¥ê¤Î´ØÏ¢ÉÕ¤±¤ò½¤Àµ¤·¤Þ¤·¤¿¡£(%s¸Ä¤Î¥¨¥é¡¼¤¬½¤Àµ¤µ¤ì¤Þ¤·¤¿¡£)');             
+
+define('NP_CLAP_1', '¡û');
+define('NP_CLAP_0', '¡Ý');
+
+define('NP_CLAP_NOCONTENT', '<font color="red">¥³¥ó¥Æ¥ó¥Ä¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£´ÉÍý²èÌ̤«¤é¥³¥ó¥Æ¥ó¥Ä¤òÄɲ䷤Ƥ¯¤À¤µ¤¤¡£</font>');                
+
+define('NP_CLAP_DAYOFWEEK', 'Æü,·î,²Ð,¿å,ÌÚ,¶â,ÅÚ');
+
+define('NP_CLAP_ALLCHECK', '¹àÌܤòÁ´¤Æ<a href="#" onclick="return checkAll(%s,true);">¥Á¥§¥Ã¥¯¤¹¤ë</a>/<a href="#" onclick="return checkAll(%s,false);">¥Á¥§¥Ã¥¯¤ò¤Ï¤º¤¹</a><br />');
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/language/japanese-utf8.php b/trunk/NP_Clap/clap/language/japanese-utf8.php
new file mode 100644 (file)
index 0000000..89bb3d9
--- /dev/null
@@ -0,0 +1,21 @@
+<?php 
+
+// plugin description
+define('NP_CLAP_mailaddr', '通知先メールアドレス');          
+define('NP_CLAP_commentedOnly', 'コメントが書かれている場合のみ通知?');             
+define('NP_CLAP_antispam_limit', '連続投稿制限(「回数/秒」で指定。「10/600」で600秒あたり10回まで)');         
+define('NP_CLAP_antispam_check', 'spamチェックを有効にするか?');          
+define('NP_CLAP_listThanksContent', 'Thanksページ内容(画像のURLとコメントを","で区切りって入力します)');              
+define('NP_CLAP_deleteData', 'アンインストール時にデータを削除する');                
+
+define('NP_CLAP_description', 'Nucleusでウェブ拍手を実現します');          
+define('NP_CLAP_corrected', 'カテゴリの関連付けを修正しました。(%s個のエラーが修正されました。)');              
+
+define('NP_CLAP_1', '○');
+define('NP_CLAP_0', '-');
+
+define('NP_CLAP_NOCONTENT', '<font color="red">コンテンツが見つかりません。管理画面からコンテンツを追加してください。</font>');             
+
+define('NP_CLAP_DAYOFWEEK', '日,月,火,水,木,金,土');
+
+define('NP_CLAP_ALLCHECK', '項目を全て<a href="#" onclick="return checkAll(%s,true);">チェックする</a>/<a href="#" onclick="return checkAll(%s,false);">チェックをはずす</a><br />');
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/mkeuc.sh b/trunk/NP_Clap/clap/mkeuc.sh
new file mode 100644 (file)
index 0000000..5f684ef
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash -x
+
+FILES=`find . -name '*japanese-utf8*'`
+
+for utf8file in $FILES
+do
+       eucfile=`echo $utf8file | sed 's/japanese-utf8/japanese-euc/'`
+       nkf -e -W -d < $utf8file > $eucfile
+done
diff --git a/trunk/NP_Clap/clap/silk/application_edit.png b/trunk/NP_Clap/clap/silk/application_edit.png
new file mode 100644 (file)
index 0000000..fb2efb8
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/application_edit.png differ
diff --git a/trunk/NP_Clap/clap/silk/application_view_list.png b/trunk/NP_Clap/clap/silk/application_view_list.png
new file mode 100644 (file)
index 0000000..acc30b8
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/application_view_list.png differ
diff --git a/trunk/NP_Clap/clap/silk/bug_link.png b/trunk/NP_Clap/clap/silk/bug_link.png
new file mode 100644 (file)
index 0000000..30e25ab
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/bug_link.png differ
diff --git a/trunk/NP_Clap/clap/silk/chart_line.png b/trunk/NP_Clap/clap/silk/chart_line.png
new file mode 100644 (file)
index 0000000..85020f3
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/chart_line.png differ
diff --git a/trunk/NP_Clap/clap/silk/coins.png b/trunk/NP_Clap/clap/silk/coins.png
new file mode 100644 (file)
index 0000000..0ca9074
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/coins.png differ
diff --git a/trunk/NP_Clap/clap/silk/comment.png b/trunk/NP_Clap/clap/silk/comment.png
new file mode 100644 (file)
index 0000000..7bc9233
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/comment.png differ
diff --git a/trunk/NP_Clap/clap/silk/comments.png b/trunk/NP_Clap/clap/silk/comments.png
new file mode 100644 (file)
index 0000000..39433cf
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/comments.png differ
diff --git a/trunk/NP_Clap/clap/silk/computer.png b/trunk/NP_Clap/clap/silk/computer.png
new file mode 100644 (file)
index 0000000..9bc37dc
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/computer.png differ
diff --git a/trunk/NP_Clap/clap/silk/cross.png b/trunk/NP_Clap/clap/silk/cross.png
new file mode 100644 (file)
index 0000000..1514d51
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/cross.png differ
diff --git a/trunk/NP_Clap/clap/silk/database_delete.png b/trunk/NP_Clap/clap/silk/database_delete.png
new file mode 100644 (file)
index 0000000..cce652e
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/database_delete.png differ
diff --git a/trunk/NP_Clap/clap/silk/database_refresh.png b/trunk/NP_Clap/clap/silk/database_refresh.png
new file mode 100644 (file)
index 0000000..ff803be
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/database_refresh.png differ
diff --git a/trunk/NP_Clap/clap/silk/key.png b/trunk/NP_Clap/clap/silk/key.png
new file mode 100644 (file)
index 0000000..4ec1a92
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/key.png differ
diff --git a/trunk/NP_Clap/clap/silk/layout.png b/trunk/NP_Clap/clap/silk/layout.png
new file mode 100644 (file)
index 0000000..ea086b0
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/layout.png differ
diff --git a/trunk/NP_Clap/clap/silk/magnifier.png b/trunk/NP_Clap/clap/silk/magnifier.png
new file mode 100644 (file)
index 0000000..cf3d97f
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/magnifier.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_add.png b/trunk/NP_Clap/clap/silk/page_white_add.png
new file mode 100644 (file)
index 0000000..aa23dde
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_add.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_delete.png b/trunk/NP_Clap/clap/silk/page_white_delete.png
new file mode 100644 (file)
index 0000000..af1ecaf
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_delete.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_edit.png b/trunk/NP_Clap/clap/silk/page_white_edit.png
new file mode 100644 (file)
index 0000000..b93e776
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_edit.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_magnify.png b/trunk/NP_Clap/clap/silk/page_white_magnify.png
new file mode 100644 (file)
index 0000000..f6b74cc
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_magnify.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_stack.png b/trunk/NP_Clap/clap/silk/page_white_stack.png
new file mode 100644 (file)
index 0000000..44084ad
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_stack.png differ
diff --git a/trunk/NP_Clap/clap/silk/page_white_text.png b/trunk/NP_Clap/clap/silk/page_white_text.png
new file mode 100644 (file)
index 0000000..813f712
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/page_white_text.png differ
diff --git a/trunk/NP_Clap/clap/silk/picture.png b/trunk/NP_Clap/clap/silk/picture.png
new file mode 100644 (file)
index 0000000..4a158fe
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/picture.png differ
diff --git a/trunk/NP_Clap/clap/silk/picture_empty.png b/trunk/NP_Clap/clap/silk/picture_empty.png
new file mode 100644 (file)
index 0000000..abd2b9b
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/picture_empty.png differ
diff --git a/trunk/NP_Clap/clap/silk/plugin_edit.png b/trunk/NP_Clap/clap/silk/plugin_edit.png
new file mode 100644 (file)
index 0000000..b6cb0ec
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/plugin_edit.png differ
diff --git a/trunk/NP_Clap/clap/silk/readme.txt b/trunk/NP_Clap/clap/silk/readme.txt
new file mode 100644 (file)
index 0000000..2cf67dc
--- /dev/null
@@ -0,0 +1,22 @@
+Silk icon set 1.3
+
+_________________________________________
+Mark James
+http://www.famfamfam.com/lab/icons/silk/
+_________________________________________
+
+This work is licensed under a
+Creative Commons Attribution 2.5 License.
+[ http://creativecommons.org/licenses/by/2.5/ ]
+
+This means you may use it for any purpose,
+and make any changes you like.
+All I ask is that you include a link back
+to this page in your credits.
+
+Are you using this icon set? Send me an email
+(including a link or picture if available) to
+mjames@gmail.com
+
+Any other questions about this icon set please
+contact mjames@gmail.com
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/silk/time.png b/trunk/NP_Clap/clap/silk/time.png
new file mode 100644 (file)
index 0000000..911da3f
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/time.png differ
diff --git a/trunk/NP_Clap/clap/silk/user.png b/trunk/NP_Clap/clap/silk/user.png
new file mode 100644 (file)
index 0000000..79f35cc
Binary files /dev/null and b/trunk/NP_Clap/clap/silk/user.png differ
diff --git a/trunk/NP_Clap/clap/template/index/chart_japanese-euc.html b/trunk/NP_Clap/clap/template/index/chart_japanese-euc.html
new file mode 100644 (file)
index 0000000..e58ca3b
--- /dev/null
@@ -0,0 +1,36 @@
+<script type="text/javascript">
+       actionurl = '{{actionurl}}';
+       ticket = '{{ticket|}}'
+</script>
+<script type="text/javascript" src="{{plugindirurl}}js/prototype-1.4.0.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}js/chart.js"></script>
+<!-- WebFX Chart -->
+<script type="text/javascript" src="{{plugindirurl}}chart/iecanvas.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/excanvas.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/wz_jsgraphics.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/chart.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/canvaschartpainter.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/jgchartpainter.js"></script>
+
+<link rel="stylesheet" type="text/css" href="{{plugindirurl}}chart/canvaschart.css" />
+
+<h2>¸¡º÷¾ò·ï</h2>
+
+<select id="year"></select>
+<select id="month"></select>
+
+<div id="message"></div>
+
+<h2>Åý·× [<span id="date"></span>]</h2>
+
+<h3>¥¨¥ó¥È¥êÊÌ</h3>
+<div id="key" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>ÆüÊÌ</h3>
+<div id="daysOfMonth" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>ÍËÆüÊÌ</h3>
+<div id="daysOfWeek" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>»þ´ÖÂÓÊÌ</h3>
+<div id="hours" class="chart" style="width: 600px; height: 300px;"></div>
diff --git a/trunk/NP_Clap/clap/template/index/chart_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/chart_japanese-utf8.html
new file mode 100644 (file)
index 0000000..8538c14
--- /dev/null
@@ -0,0 +1,36 @@
+<script type="text/javascript">
+       actionurl = '{{actionurl}}';
+       ticket = '{{ticket|}}'
+</script>
+<script type="text/javascript" src="{{plugindirurl}}js/prototype-1.4.0.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}js/chart.js"></script>
+<!-- WebFX Chart -->
+<script type="text/javascript" src="{{plugindirurl}}chart/iecanvas.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/excanvas.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/wz_jsgraphics.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/chart.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/canvaschartpainter.js"></script>
+<script type="text/javascript" src="{{plugindirurl}}chart/jgchartpainter.js"></script>
+
+<link rel="stylesheet" type="text/css" href="{{plugindirurl}}chart/canvaschart.css" />
+
+<h2>検索条件</h2>
+
+<select id="year"></select>
+<select id="month"></select>
+
+<div id="message"></div>
+
+<h2>統計 [<span id="date"></span>]</h2>
+
+<h3>エントリ別</h3>
+<div id="key" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>日別</h3>
+<div id="daysOfMonth" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>曜日別</h3>
+<div id="daysOfWeek" class="chart" style="width: 600px; height: 300px;"></div>
+
+<h3>時間帯別</h3>
+<div id="hours" class="chart" style="width: 600px; height: 300px;"></div>
diff --git a/trunk/NP_Clap/clap/template/index/convert_japanese-euc.html b/trunk/NP_Clap/clap/template/index/convert_japanese-euc.html
new file mode 100644 (file)
index 0000000..f60ace4
--- /dev/null
@@ -0,0 +1,9 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+¤³¤³¤«¤ékarma¤ÎÆâÍƤòNP_Clap¤ËÊÑ´¹¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹<br />
+
+<form method="post"><div>
+<input type="hidden" name="action" value="doconvert" />
+<input type="submit" tabindex="10" value="karma -> NP_Clap ÊÑ´¹¤ò¹Ô¤¦" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+</div></form>
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/convert_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/convert_japanese-utf8.html
new file mode 100644 (file)
index 0000000..34899f9
--- /dev/null
@@ -0,0 +1,9 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+ここからkarmaの内容をNP_Clapに変換することが可能です<br />
+
+<form method="post"><div>
+<input type="hidden" name="action" value="doconvert" />
+<input type="submit" tabindex="10" value="karma -> NP_Clap 変換を行う" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+</div></form>
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/detail_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/index/detail_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..7e51b54
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
diff --git a/trunk/NP_Clap/clap/template/index/detail_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/detail_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..7e51b54
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
diff --git a/trunk/NP_Clap/clap/template/index/detail_header_japanese-euc.html b/trunk/NP_Clap/clap/template/index/detail_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..61a6cad
--- /dev/null
@@ -0,0 +1,12 @@
+<h2>¥¢¥¤¥Æ¥à¾ÜºÙ ({{key}}¤Ë¤Ä¤¤¤Æ¡¢Á´{{rowcount}}·ïÃæ/{{offset}}·ïÌܤ«¤é{{itemperpage}}·ï¤òɽ¼¨Ãæ)</h2>
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/time.png" />»þ¹ï</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/computer.png" />IP¥¢¥É¥ì¥¹</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/comment.png" />¥á¥Ã¥»¡¼¥¸ÆâÍÆ<em>(<img border="0" src="{{plugindirurl}}silk/user.png" />¥æ¡¼¥¶Ì¾)</em></th>
+                       <th>ºï½ü</th>
+               </tr>
+       </thead>
+       <tbody>
diff --git a/trunk/NP_Clap/clap/template/index/detail_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/detail_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..fb2dac7
--- /dev/null
@@ -0,0 +1,12 @@
+<h2>アイテム詳細 ({{key}}について、全{{rowcount}}件中/{{offset}}件目から{{itemperpage}}件を表示中)</h2>
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/time.png" />時刻</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/computer.png" />IPアドレス</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/comment.png" />メッセージ内容<em>(<img border="0" src="{{plugindirurl}}silk/user.png" />ユーザ名)</em></th>
+                       <th>削除</th>
+               </tr>
+       </thead>
+       <tbody>
diff --git a/trunk/NP_Clap/clap/template/index/detail_item_japanese-euc.html b/trunk/NP_Clap/clap/template/index/detail_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..f61efe4
--- /dev/null
@@ -0,0 +1,9 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{timestamp|}}</td>
+                       <td>{{ipaddr}}</td>
+                       <td>
+                               {{comment}} 
+                               <em>(<a href="{{mail_or_url|}}">{{user|}}</a>)</em><br />
+                       </td>
+                       <td><a href="{{indexurl}}?action=delete&amp;key={{key|}}&amp;offset={{offset|}}&amp;id={{id}}&amp;ticket={{ticket|}}"><img alt="ºï½ü" border="0" src="{{plugindirurl}}silk/cross.png" /></a></td>                       
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/detail_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/detail_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..402f5ef
--- /dev/null
@@ -0,0 +1,9 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{timestamp|}}</td>
+                       <td>{{ipaddr}}</td>
+                       <td>
+                               {{comment}} 
+                               <em>(<a href="{{mail_or_url|}}">{{user|}}</a>)</em><br />
+                       </td>
+                       <td><a href="{{indexurl}}?action=delete&amp;key={{key|}}&amp;offset={{offset|}}&amp;id={{id}}&amp;ticket={{ticket|}}"><img alt="削除" border="0" src="{{plugindirurl}}silk/cross.png" /></a></td>                     
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..4a34207
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/detail_nextbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..4a34207
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..24f74b7
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/detail_prevbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..24f74b7
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/doconvert_japanese-euc.html b/trunk/NP_Clap/clap/template/index/doconvert_japanese-euc.html
new file mode 100644 (file)
index 0000000..cc0ec93
--- /dev/null
@@ -0,0 +1,3 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+ÊÑ´¹¤¬´°Î»¤·¤Þ¤·¤¿
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/doconvert_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/doconvert_japanese-utf8.html
new file mode 100644 (file)
index 0000000..c865846
--- /dev/null
@@ -0,0 +1,3 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+変換が完了しました
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/doreset_japanese-euc.html b/trunk/NP_Clap/clap/template/index/doreset_japanese-euc.html
new file mode 100644 (file)
index 0000000..e8bdd90
--- /dev/null
@@ -0,0 +1,3 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+¥ê¥»¥Ã¥È¤¬´°Î»¤·¤Þ¤·¤¿
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/doreset_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/doreset_japanese-utf8.html
new file mode 100644 (file)
index 0000000..52418c3
--- /dev/null
@@ -0,0 +1,3 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+リセットが完了しました
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/error_japanese-euc.html b/trunk/NP_Clap/clap/template/index/error_japanese-euc.html
new file mode 100644 (file)
index 0000000..4198243
--- /dev/null
@@ -0,0 +1,4 @@
+<h2>Error</h2>
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+{{message}}
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/error_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/error_japanese-utf8.html
new file mode 100644 (file)
index 0000000..4198243
--- /dev/null
@@ -0,0 +1,4 @@
+<h2>Error</h2>
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+{{message}}
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/menu_japanese-euc.html b/trunk/NP_Clap/clap/template/index/menu_japanese-euc.html
new file mode 100644 (file)
index 0000000..430f7f9
--- /dev/null
@@ -0,0 +1,31 @@
+<h2>NP_Clap menu</h2>
+
+<ul>
+       
+<li><img border="0" src="{{plugindirurl}}silk/application_view_list.png" />
+       <a href="{{indexurl}}?action=overview&amp;ticket={{ticket|}}">¥¢¥¤¥Æ¥à¤´¤È¤ÎClap¿ô°ìÍ÷</a>
+</li>
+<li>
+       <img border="0" src="{{plugindirurl}}silk/chart_line.png" />
+       <a href="{{indexurl}}?action=chart&amp;ticket={{ticket|}}">¥°¥é¥Õɽ¼¨</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/comments.png" />
+       <a href="{{indexurl}}?action=messagelist&amp;ticket={{ticket|}}">¥á¥Ã¥»¡¼¥¸°ìÍ÷</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/plugin_edit.png" />
+       <a href="{{optionurl}}">¥×¥é¥°¥¤¥ó¥ª¥×¥·¥ç¥óÀßÄê</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/application_edit.png" />
+       <a href="{{indexurl}}?action=thanksmsg&amp;ticket={{ticket|}}">Thanks¥Ú¡¼¥¸¥³¥ó¥Æ¥ó¥Ä°ìÍ÷</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/database_refresh.png" />
+       <a href="{{indexurl}}?action=convert&amp;ticket={{ticket|}}">karma¤«¤é¤Î°Ü¹Ô</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/database_delete.png" />
+       <a href="{{indexurl}}?action=reset&amp;ticket={{ticket|}}">ÃßÀѥǡ¼¥¿¤Î¥ê¥»¥Ã¥È</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/bug_link.png" />
+       <a href="{{indexurl}}?action=report"><span style="font-weight:bold; color:red">Æ°ºî³ÎǧÊó¹ð</span></a>
+</li>
+       
+</ul>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/menu_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/menu_japanese-utf8.html
new file mode 100644 (file)
index 0000000..074b281
--- /dev/null
@@ -0,0 +1,31 @@
+<h2>NP_Clap menu</h2>
+
+<ul>
+       
+<li><img border="0" src="{{plugindirurl}}silk/application_view_list.png" />
+       <a href="{{indexurl}}?action=overview&amp;ticket={{ticket|}}">アイテムごとのClap数一覧</a>
+</li>
+<li>
+       <img border="0" src="{{plugindirurl}}silk/chart_line.png" />
+       <a href="{{indexurl}}?action=chart&amp;ticket={{ticket|}}">グラフ表示</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/comments.png" />
+       <a href="{{indexurl}}?action=messagelist&amp;ticket={{ticket|}}">メッセージ一覧</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/plugin_edit.png" />
+       <a href="{{optionurl}}">プラグインオプション設定</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/application_edit.png" />
+       <a href="{{indexurl}}?action=thanksmsg&amp;ticket={{ticket|}}">Thanksページコンテンツ一覧</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/database_refresh.png" />
+       <a href="{{indexurl}}?action=convert&amp;ticket={{ticket|}}">karmaからの移行</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/database_delete.png" />
+       <a href="{{indexurl}}?action=reset&amp;ticket={{ticket|}}">蓄積データのリセット</a>
+</li>
+<li><img border="0" src="{{plugindirurl}}silk/bug_link.png" />
+       <a href="{{indexurl}}?action=report"><span style="font-weight:bold; color:red">動作確認報告</span></a>
+</li>
+       
+</ul>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..7e51b54
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/messagelist_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..7e51b54
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_header_japanese-euc.html b/trunk/NP_Clap/clap/template/index/messagelist_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..7aa5fec
--- /dev/null
@@ -0,0 +1,13 @@
+<h2>¥á¥Ã¥»¡¼¥¸°ìÍ÷ (Á´{{rowcount}}·ïÃæ/{{offset}}·ïÌܤ«¤é{{itemperpage}}·ï¤òɽ¼¨Ãæ)</h2>
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/time.png" />»þ¹ï</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/key.png" />¥­¡¼</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/computer.png" />IP¥¢¥É¥ì¥¹</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/comment.png" />¥á¥Ã¥»¡¼¥¸ÆâÍÆ<em>(<img border="0" src="{{plugindirurl}}silk/user.png" />¥æ¡¼¥¶Ì¾)</em></th>
+                       <th>¾ÜºÙ</th>
+               </tr>
+       </thead>
+       <tbody>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/messagelist_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..eb33c29
--- /dev/null
@@ -0,0 +1,13 @@
+<h2>メッセージ一覧 (全{{rowcount}}件中/{{offset}}件目から{{itemperpage}}件を表示中)</h2>
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/time.png" />時刻</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/key.png" />キー</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/computer.png" />IPアドレス</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/comment.png" />メッセージ内容<em>(<img border="0" src="{{plugindirurl}}silk/user.png" />ユーザ名)</em></th>
+                       <th>詳細</th>
+               </tr>
+       </thead>
+       <tbody>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_item_japanese-euc.html b/trunk/NP_Clap/clap/template/index/messagelist_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..fbeedbe
--- /dev/null
@@ -0,0 +1,10 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{timestamp|}}</td>
+                       <td>{{key|}}</td>
+                       <td>{{ipaddr}}</td>
+                       <td>
+                               {{comment}} 
+                               <em>(<a href="{{mail_or_url|}}">{{user|}}</a>)</em><br />
+                       </td>
+                       <td><a href="{{indexurl}}?action=detail&amp;key={{key|}}&amp;ticket={{ticket|}}"><img border="0" alt="¾ÜºÙ" src="{{plugindirurl}}silk/magnifier.png" /></a></td>                        
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/messagelist_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..22705ab
--- /dev/null
@@ -0,0 +1,10 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{timestamp|}}</td>
+                       <td>{{key|}}</td>
+                       <td>{{ipaddr}}</td>
+                       <td>
+                               {{comment}} 
+                               <em>(<a href="{{mail_or_url|}}">{{user|}}</a>)</em><br />
+                       </td>
+                       <td><a href="{{indexurl}}?action=detail&amp;key={{key|}}&amp;ticket={{ticket|}}"><img border="0" alt="詳細" src="{{plugindirurl}}silk/magnifier.png" /></a></td>                      
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..4a34207
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/messagelist_nextbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..4a34207
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..24f74b7
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/messagelist_prevbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..24f74b7
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="detail" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="key" value="{{key|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/overview_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/index/overview_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..b6eef1d
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/overview_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/overview_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..b6eef1d
--- /dev/null
@@ -0,0 +1,12 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/overview_header_japanese-euc.html b/trunk/NP_Clap/clap/template/index/overview_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..6ed8962
--- /dev/null
@@ -0,0 +1,13 @@
+<h2>¥¢¥¤¥Æ¥à¤´¤È¤ÎClap¿ô°ìÍ÷ (Á´{{rowcount}}·ïÃæ/{{offset}}·ïÌܤ«¤é{{itemperpage}}·ï¤òɽ¼¨Ãæ)</h2>
+blog¤Ç¹Ê¹þ¤ß¡§{{blogselect}}
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/key.png" />¥­¡¼</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/layout.png" />¥¿¥¤¥È¥ë¡Ê¥Ö¥í¥°Ì¾¡Ë</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/coins.png" />¥«¥¦¥ó¥È¿ô</th>
+                       <th>¾ÜºÙ</th>
+               </tr>
+       </thead>
+       <tbody>
diff --git a/trunk/NP_Clap/clap/template/index/overview_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/overview_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..c21d38a
--- /dev/null
@@ -0,0 +1,13 @@
+<h2>アイテムごとのClap数一覧 (全{{rowcount}}件中/{{offset}}件目から{{itemperpage}}件を表示中)</h2>
+blogで絞込み:{{blogselect}}
+
+<table>
+       <thead>
+               <tr>
+                       <th><img border="0" src="{{plugindirurl}}silk/key.png" />キー</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/layout.png" />タイトル(ブログ名)</th>
+                       <th><img border="0" src="{{plugindirurl}}silk/coins.png" />カウント数</th>
+                       <th>詳細</th>
+               </tr>
+       </thead>
+       <tbody>
diff --git a/trunk/NP_Clap/clap/template/index/overview_item_japanese-euc.html b/trunk/NP_Clap/clap/template/index/overview_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..620106b
--- /dev/null
@@ -0,0 +1,9 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{key|}}</td>
+                       <td>
+                               {{title|}} 
+                               <em>({{blogname|}})</em><br />
+                       </td>
+                       <td>{{count|}}</td>
+                       <td><a href="{{indexurl}}?action=detail&amp;key={{key|}}&amp;ticket={{ticket|}}"><img border="0" alt="¾ÜºÙ" src="{{plugindirurl}}silk/magnifier.png" /></a></td>
+               </tr>
diff --git a/trunk/NP_Clap/clap/template/index/overview_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/overview_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..61a9e70
--- /dev/null
@@ -0,0 +1,9 @@
+               <tr onmouseover="focusRow(this);" onmouseout="blurRow(this);">
+                       <td>{{key|}}</td>
+                       <td>
+                               {{title|}} 
+                               <em>({{blogname|}})</em><br />
+                       </td>
+                       <td>{{count|}}</td>
+                       <td><a href="{{indexurl}}?action=detail&amp;key={{key|}}&amp;ticket={{ticket|}}"><img border="0" alt="詳細" src="{{plugindirurl}}silk/magnifier.png" /></a></td>
+               </tr>
diff --git a/trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..eae9e6f
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="overview" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="blog" value="{{blog|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/overview_nextbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..eae9e6f
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="overview" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="blog" value="{{blog|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..8ed350a
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="overview" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="blog" value="{{blog|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/overview_prevbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..8ed350a
--- /dev/null
@@ -0,0 +1,9 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="overview" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="blog" value="{{blog|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/reset_japanese-euc.html b/trunk/NP_Clap/clap/template/index/reset_japanese-euc.html
new file mode 100644 (file)
index 0000000..080416a
--- /dev/null
@@ -0,0 +1,10 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+NP_Clap¤ËÃßÀѤµ¤ì¤¿ÆâÍƤò¥ê¥»¥Ã¥È¤·¤Þ¤¹<br />
+<strong>¥ê¥»¥Ã¥È¤·¤¿¾ðÊó¤Ï¸µ¤ËÌ᤻¤Þ¤»¤ó¤Î¤Ç¤´Ãí°Õ¤¯¤À¤µ¤¤</strong><br />
+
+<form method="post"><div>
+<input type="hidden" name="action" value="doreset" />
+<input type="submit" tabindex="10" value="NP_Clap¤Î¾ðÊó¤ò¥ê¥»¥Ã¥È" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+</div></form>
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/reset_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/reset_japanese-utf8.html
new file mode 100644 (file)
index 0000000..57c0ff2
--- /dev/null
@@ -0,0 +1,10 @@
+<blockquote style="color: red;border:1px solid red;padding:1em;">
+NP_Clapに蓄積された内容をリセットします<br />
+<strong>リセットした情報は元に戻せませんのでご注意ください</strong><br />
+
+<form method="post"><div>
+<input type="hidden" name="action" value="doreset" />
+<input type="submit" tabindex="10" value="NP_Clapの情報をリセット" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+</div></form>
+</blockquote>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksedit_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksedit_japanese-euc.html
new file mode 100644 (file)
index 0000000..173f1af
--- /dev/null
@@ -0,0 +1,52 @@
+<h2>¥³¥ó¥Æ¥ó¥Ä¤ÎÊÔ½¸¡¦¿·µ¬ÄɲÃ</h2>
+
+<form method="post" action="{{indexurl}}">
+<input type="hidden" name="action" value="thankssave" />
+<input type="hidden" name="id" value="{{id}}" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+
+<script language="JavaScript">
+//<![CDATA[
+       function checkAll(blogid, checked){
+               var tags = document.getElementsByTagName('input');
+               for(var i=0; i < tags.length; i++){
+                       var t = tags[i];
+                       if( t.type == 'checkbox' && t.name.indexOf('assoc') == 0 && t.id.indexOf(blogid+'_') == 0 ){
+                               t.checked = checked;
+                       }
+               }
+               return false;
+       }
+//]]>
+</script>
+
+<table>
+       <thead>
+               <tr>
+                       <th>¹àÌÜ</th>
+                       <th>ÃÍ</th>
+               </tr>
+       </thead>
+       <tbody>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>¥³¥á¥ó¥È</td>
+                       <td><textarea name="comment" rows="15" cols="70">{{comment|}}</textarea></td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>²èÁü¡Ê»ÈÍѤ·¤Ê¤¤¾ì¹ç¤Ë¤Ï¶õÍó¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡Ë</td>
+                       <td><input type="text" name="image" size="100" value="{{image|}}" /></td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>ɽ¼¨Âоݤˤ¹¤ë¥«¥Æ¥´¥ê</td>
+                       <td>{{assoc}}
+                       ¤½¤Î¾¤ÎKey:<input type="text" name="assoc_etc" size="80" value="{{assoc_etc|}}" /><br />
+                       ¢¨,(¥«¥ó¥Þ)¤Ç¶èÀڤäÆÊ£¿ô¤Îkey¤òÆþÎϤǤ­¤Þ¤¹¡£
+                       </td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>¥³¥ó¥Æ¥ó¥Ä¤ÎÊݸ</td>
+                       <td><input type="submit" value="¥³¥ó¥Æ¥ó¥Ä¤ÎÊݸ" /></td>
+               </tr>
+       </tbody>
+</table>
+</form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksedit_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksedit_japanese-utf8.html
new file mode 100644 (file)
index 0000000..48352d6
--- /dev/null
@@ -0,0 +1,52 @@
+<h2>コンテンツの編集・新規追加</h2>
+
+<form method="post" action="{{indexurl}}">
+<input type="hidden" name="action" value="thankssave" />
+<input type="hidden" name="id" value="{{id}}" />
+<input type="hidden" name="ticket" value="{{ticket|}}" />
+
+<script language="JavaScript">
+//<![CDATA[
+       function checkAll(blogid, checked){
+               var tags = document.getElementsByTagName('input');
+               for(var i=0; i < tags.length; i++){
+                       var t = tags[i];
+                       if( t.type == 'checkbox' && t.name.indexOf('assoc') == 0 && t.id.indexOf(blogid+'_') == 0 ){
+                               t.checked = checked;
+                       }
+               }
+               return false;
+       }
+//]]>
+</script>
+
+<table>
+       <thead>
+               <tr>
+                       <th>項目</th>
+                       <th>値</th>
+               </tr>
+       </thead>
+       <tbody>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>コメント</td>
+                       <td><textarea name="comment" rows="15" cols="70">{{comment|}}</textarea></td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>画像(使用しない場合には空欄にしてください)</td>
+                       <td><input type="text" name="image" size="100" value="{{image|}}" /></td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>表示対象にするカテゴリ</td>
+                       <td>{{assoc}}
+                       その他のKey:<input type="text" name="assoc_etc" size="80" value="{{assoc_etc|}}" /><br />
+                       ※,(カンマ)で区切って複数のkeyを入力できます。
+                       </td>
+               </tr>
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>コンテンツの保存</td>
+                       <td><input type="submit" value="コンテンツの保存" /></td>
+               </tr>
+       </tbody>
+</table>
+</form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..c297c5a
--- /dev/null
@@ -0,0 +1,16 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
+
+<h3>´ØÏ¢ÉÕ¤±¤Î½¤Àµ</h3>
+<p><img border="0" src="{{plugindirurl}}silk/database_refresh.png" /><a href="{{indexurl}}?action=docorrect&amp;id=new&amp;ticket={{ticket|}}">¥³¥ó¥Æ¥ó¥Ä¤Î´ØÏ¢ÉÕ¤±¤ò½¤Àµ¤·¤Þ¤¹</a></p>
+<p>¥³¥ó¥Æ¥ó¥Ä¤òÆþÎϤ·¤Æ¤¤¤ë¤Ë¤â¤«¤«¤ï¤é¤º¡Ö¥³¥ó¥Æ¥ó¥Ä¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£´ÉÍý²èÌ̤«¤é¥³¥ó¥Æ¥ó¥Ä¤òÄɲ䷤Ƥ¯¤À¤µ¤¤¡£¡×¤Èɽ¼¨¤µ¤ì¤ë¾ì¹ç¤Ë¼Â¹Ô¤·¤Æ¤¯¤À¤µ¤¤¡£</p>
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksmsg_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..50fb58f
--- /dev/null
@@ -0,0 +1,16 @@
+       </tbody>
+</table>
+<table class="navigation">
+       <tr>
+               <td style="padding: 0;">
+                       {{prev_button}}
+               </td>
+               <td style="padding: 0; text-align: right;">     
+                       {{next_button}}
+               </td>
+       </tr>
+</table>
+
+<h3>関連付けの修正</h3>
+<p><img border="0" src="{{plugindirurl}}silk/database_refresh.png" /><a href="{{indexurl}}?action=docorrect&amp;id=new&amp;ticket={{ticket|}}">コンテンツの関連付けを修正します</a></p>
+<p>コンテンツを入力しているにもかかわらず「コンテンツが見つかりません。管理画面からコンテンツを追加してください。」と表示される場合に実行してください。</p>
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..8eb57f8
--- /dev/null
@@ -0,0 +1,20 @@
+<div style="color: red;">{{message}}</div>
+
+<h2>Thanks¥Ú¡¼¥¸¥³¥ó¥Æ¥ó¥Ä°ìÍ÷</h2>
+
+<h3>¥³¥ó¥Æ¥ó¥Ä¤Î¿·µ¬ÄɲÃ</h3>
+<p><img border="0" src="{{plugindirurl}}silk/page_white_add.png" /><a href="{{indexurl}}?action=thanksedit&amp;id=new&amp;ticket={{ticket|}}">¥³¥ó¥Æ¥ó¥Ä¤òÄɲ乤ë</a></p>
+
+<h3>ÅÐÏ¿¤µ¤ì¤Æ¤¤¤ë¥³¥ó¥Æ¥ó¥Ä(Á´{{rowcount}}·ïÃæ/{{offset}}·ïÌܤ«¤é{{itemperpage}}·ï¤òɽ¼¨Ãæ)</h3>
+<table>
+       <thead>
+               <tr>
+                       <th>id</th>
+                       <th>¥³¥á¥ó¥È</th>
+                       <th>²èÁü</th>
+                       <th>¥×¥ì¥Ó¥å¡¼</th>
+                       <th>ÊÔ½¸</th>
+                       <th>ºï½ü</th>
+               </tr>
+       </thead>
+       <tbody>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksmsg_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..69e4889
--- /dev/null
@@ -0,0 +1,20 @@
+<div style="color: red;">{{message}}</div>
+
+<h2>Thanksページコンテンツ一覧</h2>
+
+<h3>コンテンツの新規追加</h3>
+<p><img border="0" src="{{plugindirurl}}silk/page_white_add.png" /><a href="{{indexurl}}?action=thanksedit&amp;id=new&amp;ticket={{ticket|}}">コンテンツを追加する</a></p>
+
+<h3>登録されているコンテンツ(全{{rowcount}}件中/{{offset}}件目から{{itemperpage}}件を表示中)</h3>
+<table>
+       <thead>
+               <tr>
+                       <th>id</th>
+                       <th>コメント</th>
+                       <th>画像</th>
+                       <th>プレビュー</th>
+                       <th>編集</th>
+                       <th>削除</th>
+               </tr>
+       </thead>
+       <tbody>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..4f2f79b
--- /dev/null
@@ -0,0 +1,8 @@
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>{{id}}</td>
+                       <td>{{comment}}</td>
+                       <td>{{image}}</td>
+                       <td><a href="{{actionurl}}?action=plugin&amp;name=Clap&amp;type=preview&amp;id={{id}}&amp;ticket={{ticket|}}" target="_blank"><img border="0" alt="¥×¥ì¥Ó¥å¡¼" src="{{plugindirurl}}silk/page_white_magnify.png" /></a></td>    
+                       <td><a href="{{indexurl}}?action=thanksedit&amp;id={{id}}&amp;ticket={{ticket|}}"><img border="0" alt="ÊÔ½¸" src="{{plugindirurl}}silk/page_white_edit.png" /></a></td> 
+                       <td><a href="{{indexurl}}?action=thanksdelete&amp;id={{id}}&amp;ticket={{ticket|}}"><img border="0" alt="ºï½ü" src="{{plugindirurl}}silk/page_white_delete.png" /></a></td>     
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksmsg_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..e11ec11
--- /dev/null
@@ -0,0 +1,8 @@
+               <tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>
+                       <td>{{id}}</td>
+                       <td>{{comment}}</td>
+                       <td>{{image}}</td>
+                       <td><a href="{{actionurl}}?action=plugin&amp;name=Clap&amp;type=preview&amp;id={{id}}&amp;ticket={{ticket|}}" target="_blank"><img border="0" alt="プレビュー" src="{{plugindirurl}}silk/page_white_magnify.png" /></a></td>       
+                       <td><a href="{{indexurl}}?action=thanksedit&amp;id={{id}}&amp;ticket={{ticket|}}"><img border="0" alt="編集" src="{{plugindirurl}}silk/page_white_edit.png" /></a></td>       
+                       <td><a href="{{indexurl}}?action=thanksdelete&amp;id={{id}}&amp;ticket={{ticket|}}"><img border="0" alt="削除" src="{{plugindirurl}}silk/page_white_delete.png" /></a></td>   
+               </tr>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..0189403
--- /dev/null
@@ -0,0 +1,8 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="thanksmsg" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksmsg_nextbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..0189403
--- /dev/null
@@ -0,0 +1,8 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="Next &gt;&gt;" />   
+                                       <input type="hidden" name="action" value="thanksmsg" />
+                                       <input type="hidden" name="offset" value="{{next_offset|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-euc.html b/trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-euc.html
new file mode 100644 (file)
index 0000000..07116d0
--- /dev/null
@@ -0,0 +1,8 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="thanksmsg" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-utf8.html b/trunk/NP_Clap/clap/template/index/thanksmsg_prevbutton_japanese-utf8.html
new file mode 100644 (file)
index 0000000..07116d0
--- /dev/null
@@ -0,0 +1,8 @@
+                       <form method="post" action="{{indexurl}}">
+                               <div>
+                                       <input type="submit" value="&lt;&lt; Prev" />
+                                       <input type="hidden" name="action" value="thanksmsg" />
+                                       <input type="hidden" name="offset" value="{{prev_offset|}}" />
+                                       <input type="hidden" name="ticket" value="{{ticket|}}" />
+                               </div>
+                       </form>
diff --git a/trunk/NP_Clap/clap/template/np_clap/button_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/button_japanese-euc.html
new file mode 100644 (file)
index 0000000..c77a5c5
--- /dev/null
@@ -0,0 +1 @@
+<form action="{{actionurl}}" method="POST" style="display:inline"><!--{{key}}:{{count}}--><input type="submit" value="Çï¼ê¡ª"></form>
diff --git a/trunk/NP_Clap/clap/template/np_clap/button_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/button_japanese-utf8.html
new file mode 100644 (file)
index 0000000..70ce702
--- /dev/null
@@ -0,0 +1 @@
+<form action="{{actionurl}}" method="POST" style="display:inline"><!--{{key}}:{{count}}--><input type="submit" value="拍手!"></form>
diff --git a/trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-euc.html
new file mode 100644 (file)
index 0000000..d57db69
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>Çï¼êÁ÷¿®´°Î» - NP_Clap</title>
+</head>
+<body>
+<center>
+<font size="2">Çï¼ê¤òÁ÷¿®¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£<br />
+¤·¤Ð¤é¤¯¤¿¤Ã¤Æ¤«¤é¤Þ¤¿¤ª»î¤·¤¯¤À¤µ¤¤¡£</font><br />
+<br />
+<a href="{{returnurl}}">¸µ¤Î¥Ú¡¼¥¸¤ËÌá¤ë</a>
+<br />
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/forbidden_japanese-utf8.html
new file mode 100644 (file)
index 0000000..81f86e6
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>拍手送信完了 - NP_Clap</title>
+</head>
+<body>
+<center>
+<font size="2">拍手を送信することができませんでした。<br />
+しばらくたってからまたお試しください。</font><br />
+<br />
+<a href="{{returnurl}}">元のページに戻る</a>
+<br />
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..3d3a44c
--- /dev/null
@@ -0,0 +1 @@
+</ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/list_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..3d3a44c
--- /dev/null
@@ -0,0 +1 @@
+</ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_header_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/list_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..625a9ba
--- /dev/null
@@ -0,0 +1 @@
+<ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/list_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..625a9ba
--- /dev/null
@@ -0,0 +1 @@
+<ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_item_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/list_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..42d0030
--- /dev/null
@@ -0,0 +1 @@
+<li><!--{{key}}--><a href="{{itemlink}}">{{title}}</a> ({{count}})</li>
diff --git a/trunk/NP_Clap/clap/template/np_clap/list_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/list_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..42d0030
--- /dev/null
@@ -0,0 +1 @@
+<li><!--{{key}}--><a href="{{itemlink}}">{{title}}</a> ({{count}})</li>
diff --git a/trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-euc.txt b/trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-euc.txt
new file mode 100644 (file)
index 0000000..fac4343
--- /dev/null
@@ -0,0 +1,6 @@
+̾Á°: {{user}}
+URL/¥á¡¼¥ë¥¢¥É¥ì¥¹: {{mail_or_url}}
+IP¥¢¥É¥ì¥¹: {{ipaddr}}({{hostname}})
+UserAgent: {{useragent}}
+Referer: {{referer}}
+¥³¥á¥ó¥È: {{comment}}
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-utf8.txt b/trunk/NP_Clap/clap/template/np_clap/mail_body_japanese-utf8.txt
new file mode 100644 (file)
index 0000000..fba124e
--- /dev/null
@@ -0,0 +1,6 @@
+名前: {{user}}
+URL/メールアドレス: {{mail_or_url}}
+IPアドレス: {{ipaddr}}({{hostname}})
+UserAgent: {{useragent}}
+Referer: {{referer}}
+コメント: {{comment}}
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-euc.txt b/trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-euc.txt
new file mode 100644 (file)
index 0000000..fed6b05
--- /dev/null
@@ -0,0 +1 @@
+Çï¼ê¤¬Á÷¿®¤µ¤ì¤Þ¤·¤¿ ({{key}})
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-utf8.txt b/trunk/NP_Clap/clap/template/np_clap/mail_subject_japanese-utf8.txt
new file mode 100644 (file)
index 0000000..c2b93e6
--- /dev/null
@@ -0,0 +1 @@
+拍手が送信されました ({{key}})
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/thanks_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap/thanks_japanese-euc.html
new file mode 100644 (file)
index 0000000..5360a15
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>Çï¼êÁ÷¿®´°Î» - NP_Clap</title>
+</head>
+<body>
+<center>
+{{img}}<br />
+<font size="2">{{text}}</font><br />
+<br />
+<a href="{{returnurl}}">¸µ¤Î¥Ú¡¼¥¸¤ËÌá¤ë</a><br />
+<br />
+<br />
+<form method="post" action="{{actionurl}}">
+
+<font size="2">¤ªÌ¾Á°:<input type="text" name="user" size="50" /></font><br />
+<font size="2">¥á¡¼¥ë¥¢¥É¥ì¥¹/£Õ£Ò£Ì:<input type="text" name="mail_or_url" size="50" /></font><br />
+<font size="2">¤Ä¤¤¤Ç¤Ë°ì¸À¤¢¤ì¤Ð¤É¤¦¤¾(Çï¼ê¤À¤±¤Ç¤âÁ÷¤ì¤Þ¤¹)</font><br />
+<textarea name="comment" rows="4" cols="50"></textarea><br />
+
+<input type="submit" value="¤â¤Ã¤ÈÁ÷¤ë" />
+
+<!-- hidden -->
+<!-- contentid: {{contentid}} -->
+<input type="hidden" name="key" value="{{key}}" />
+<input type="hidden" name="returnurl" value="{{returnurl}}" />
+<input type="hidden" name="action" value="plugin" />
+<input type="hidden" name="name" value="Clap" />
+<input type="hidden" name="type" value="{{type}}" />
+<!-- hidden -->
+
+</form>
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap/thanks_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap/thanks_japanese-utf8.html
new file mode 100644 (file)
index 0000000..b45cce0
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>拍手送信完了 - NP_Clap</title>
+</head>
+<body>
+<center>
+{{img}}<br />
+<font size="2">{{text}}</font><br />
+<br />
+<a href="{{returnurl}}">元のページに戻る</a><br />
+<br />
+<br />
+<form method="post" action="{{actionurl}}">
+
+<font size="2">お名前:<input type="text" name="user" size="50" /></font><br />
+<font size="2">メールアドレス/URL:<input type="text" name="mail_or_url" size="50" /></font><br />
+<font size="2">ついでに一言あればどうぞ(拍手だけでも送れます)</font><br />
+<textarea name="comment" rows="4" cols="50"></textarea><br />
+
+<input type="submit" value="もっと送る" />
+
+<!-- hidden -->
+<!-- contentid: {{contentid}} -->
+<input type="hidden" name="key" value="{{key}}" />
+<input type="hidden" name="returnurl" value="{{returnurl}}" />
+<input type="hidden" name="action" value="plugin" />
+<input type="hidden" name="name" value="Clap" />
+<input type="hidden" name="type" value="{{type}}" />
+<!-- hidden -->
+
+</form>
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-euc.html
new file mode 100644 (file)
index 0000000..5b025bf
--- /dev/null
@@ -0,0 +1,10 @@
+<form id="clap_{{key}}" action="{{actionurl_wo_key}}" method="POST" style="display:inline">
+<input type="submit" value="{{count}}¤Ø¤§" />
+</form>
+<script type="text/javascript">
+var k = document.createElement('input');
+k.type = 'hidden';
+k.name = 'key';
+k.value = '{{key}}';
+document.forms['clap_{{key}}'].appendChild(k);
+</script>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/button_japanese-utf8.html
new file mode 100644 (file)
index 0000000..5be4925
--- /dev/null
@@ -0,0 +1,10 @@
+<form id="clap_{{key}}" action="{{actionurl_wo_key}}" method="POST" style="display:inline">
+<input type="submit" value="{{count}}へぇ" />
+</form>
+<script type="text/javascript">
+var k = document.createElement('input');
+k.type = 'hidden';
+k.name = 'key';
+k.value = '{{key}}';
+document.forms['clap_{{key}}'].appendChild(k);
+</script>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-euc.html
new file mode 100644 (file)
index 0000000..925166f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>Çï¼êÁ÷¿®´°Î» - NP_Clap</title>
+</head>
+<body>
+<center>
+<font size="2">Çï¼ê¤òÁ÷¿®¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£<br />
+¤·¤Ð¤é¤¯¤¿¤Ã¤Æ¤«¤é¤Þ¤¿¤ª»î¤·¤¯¤À¤µ¤¤¡£</font><br />
+<br />
+<a href="{{returnurl}}">¸µ¤Î¥Ú¡¼¥¸¤ËÌá¤ë</a>
+<br />
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/forbidden_japanese-utf8.html
new file mode 100644 (file)
index 0000000..0d9132b
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>拍手送信完了 - NP_Clap</title>
+</head>
+<body>
+<center>
+<font size="2">拍手を送信することができませんでした。<br />
+しばらくたってからまたお試しください。</font><br />
+<br />
+<a href="{{returnurl}}">元のページに戻る</a>
+<br />
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-euc.html
new file mode 100644 (file)
index 0000000..3d3a44c
--- /dev/null
@@ -0,0 +1 @@
+</ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_footer_japanese-utf8.html
new file mode 100644 (file)
index 0000000..3d3a44c
--- /dev/null
@@ -0,0 +1 @@
+</ul>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-euc.html
new file mode 100644 (file)
index 0000000..da2924a
--- /dev/null
@@ -0,0 +1 @@
+<ul class="nobullets">
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_header_japanese-utf8.html
new file mode 100644 (file)
index 0000000..da2924a
--- /dev/null
@@ -0,0 +1 @@
+<ul class="nobullets">
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-euc.html
new file mode 100644 (file)
index 0000000..42d0030
--- /dev/null
@@ -0,0 +1 @@
+<li><!--{{key}}--><a href="{{itemlink}}">{{title}}</a> ({{count}})</li>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/list_item_japanese-utf8.html
new file mode 100644 (file)
index 0000000..42d0030
--- /dev/null
@@ -0,0 +1 @@
+<li><!--{{key}}--><a href="{{itemlink}}">{{title}}</a> ({{count}})</li>
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-euc.txt b/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-euc.txt
new file mode 100644 (file)
index 0000000..ab02f1a
--- /dev/null
@@ -0,0 +1,7 @@
+item: http://blog.cles.jp/item/{{key}}
+̾Á°: {{user}}
+URL/¥á¡¼¥ë¥¢¥É¥ì¥¹: {{mail_or_url}}
+IP¥¢¥É¥ì¥¹: {{ipaddr}}({{hostname}})
+UserAgent: {{useragent}}
+Referer: {{referer}}
+¥³¥á¥ó¥È: {{comment}}
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-utf8.txt b/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_body_japanese-utf8.txt
new file mode 100644 (file)
index 0000000..e38c237
--- /dev/null
@@ -0,0 +1,7 @@
+item: http://blog.cles.jp/item/{{key}}
+名前: {{user}}
+URL/メールアドレス: {{mail_or_url}}
+IPアドレス: {{ipaddr}}({{hostname}})
+UserAgent: {{useragent}}
+Referer: {{referer}}
+コメント: {{comment}}
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-euc.txt b/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-euc.txt
new file mode 100644 (file)
index 0000000..fed6b05
--- /dev/null
@@ -0,0 +1 @@
+Çï¼ê¤¬Á÷¿®¤µ¤ì¤Þ¤·¤¿ ({{key}})
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-utf8.txt b/trunk/NP_Clap/clap/template/np_clap_clesblog/mail_subject_japanese-utf8.txt
new file mode 100644 (file)
index 0000000..c2b93e6
--- /dev/null
@@ -0,0 +1 @@
+拍手が送信されました ({{key}})
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-euc.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-euc.html
new file mode 100644 (file)
index 0000000..5360a15
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>Çï¼êÁ÷¿®´°Î» - NP_Clap</title>
+</head>
+<body>
+<center>
+{{img}}<br />
+<font size="2">{{text}}</font><br />
+<br />
+<a href="{{returnurl}}">¸µ¤Î¥Ú¡¼¥¸¤ËÌá¤ë</a><br />
+<br />
+<br />
+<form method="post" action="{{actionurl}}">
+
+<font size="2">¤ªÌ¾Á°:<input type="text" name="user" size="50" /></font><br />
+<font size="2">¥á¡¼¥ë¥¢¥É¥ì¥¹/£Õ£Ò£Ì:<input type="text" name="mail_or_url" size="50" /></font><br />
+<font size="2">¤Ä¤¤¤Ç¤Ë°ì¸À¤¢¤ì¤Ð¤É¤¦¤¾(Çï¼ê¤À¤±¤Ç¤âÁ÷¤ì¤Þ¤¹)</font><br />
+<textarea name="comment" rows="4" cols="50"></textarea><br />
+
+<input type="submit" value="¤â¤Ã¤ÈÁ÷¤ë" />
+
+<!-- hidden -->
+<!-- contentid: {{contentid}} -->
+<input type="hidden" name="key" value="{{key}}" />
+<input type="hidden" name="returnurl" value="{{returnurl}}" />
+<input type="hidden" name="action" value="plugin" />
+<input type="hidden" name="name" value="Clap" />
+<input type="hidden" name="type" value="{{type}}" />
+<!-- hidden -->
+
+</form>
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-utf8.html b/trunk/NP_Clap/clap/template/np_clap_clesblog/thanks_japanese-utf8.html
new file mode 100644 (file)
index 0000000..b45cce0
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="{{charset}}"?> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
+<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={{charset}}" />
+<title>拍手送信完了 - NP_Clap</title>
+</head>
+<body>
+<center>
+{{img}}<br />
+<font size="2">{{text}}</font><br />
+<br />
+<a href="{{returnurl}}">元のページに戻る</a><br />
+<br />
+<br />
+<form method="post" action="{{actionurl}}">
+
+<font size="2">お名前:<input type="text" name="user" size="50" /></font><br />
+<font size="2">メールアドレス/URL:<input type="text" name="mail_or_url" size="50" /></font><br />
+<font size="2">ついでに一言あればどうぞ(拍手だけでも送れます)</font><br />
+<textarea name="comment" rows="4" cols="50"></textarea><br />
+
+<input type="submit" value="もっと送る" />
+
+<!-- hidden -->
+<!-- contentid: {{contentid}} -->
+<input type="hidden" name="key" value="{{key}}" />
+<input type="hidden" name="returnurl" value="{{returnurl}}" />
+<input type="hidden" name="action" value="plugin" />
+<input type="hidden" name="name" value="Clap" />
+<input type="hidden" name="type" value="{{type}}" />
+<!-- hidden -->
+
+</form>
+
+<br />
+<font size="2">Powered by <a href="http://blog.cles.jp/np_cles/category/31/subcatid/13" target="_blank">NP_Clap</a></font><br />
+</center>
+</body></html>
\ No newline at end of file
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon.php b/trunk/NP_Clap/sharedlibs/Jsphon.php
new file mode 100644 (file)
index 0000000..5ac2856
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+define('JSPHON_ERROR_DECODE_SYNTAX', 1);
+
+require_once(dirname(__FILE__) .'/Jsphon/Error.php');
+require_once(dirname(__FILE__) .'/Jsphon/Decoder.php');
+require_once(dirname(__FILE__) .'/Jsphon/Encoder.php');
+
+Jsphon_Error::singleton();
+
+/**
+ * Jsphon - JSON in PHP
+ * 
+ * example:
+ * <code>
+ * //encode
+ * $value = array('foo', 'bar', array('hoge' => array(1,2)));
+ * $json = Jsphon::encode($value);
+ * echo $json;
+ * 
+ * //decode
+ * $var =  Jsphon::decode($json);
+ * echo $var[2]['hoge'];
+ * 
+ * </code>
+ * 
+ * @author Hawk
+ */
+class Jsphon
+{
+    /**
+     * Encodes an arbitrary variables into JSON format.
+     * See Jsphon_Encoder::encode() for details.
+     * 
+     * @param  String    $value
+     * @param  boolean   $escapeNonASCII
+     * @param  boolean   $escapeOverUCS2
+     * @return String
+     */
+    function encode($value, $escapeNonASCII=true, $escapeOverUCS2=false)
+    {
+        $encoder = new Jsphon_Encoder($escapeNonASCII, $escapeOverUCS2);
+        return $encoder->encode($value);
+    }
+    
+
+    /**
+     * Decodes JSON-formatted string into appropriate PHP variable.
+     * See Jsphon_Decoder::decode() for details.
+     * 
+     * @param  String    $json
+     * @param  String    $decodeOverUCS2
+     * @return mixed
+     */
+    function decode($json, $decodeOverUCS2=false)
+    {
+        $decoder = new Jsphon_Decoder($decodeOverUCS2);
+        return $decoder->decode($json);
+    }
+
+}
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon/Decoder.php b/trunk/NP_Clap/sharedlibs/Jsphon/Decoder.php
new file mode 100644 (file)
index 0000000..9e60dc3
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+require_once(dirname(__FILE__) .'/Decoder/Tokenizer.php');
+
+/**
+ * Converts JSON-formatted string to appropriate PHP variable
+ * 
+ * example:
+ * <code>
+ * //create a new instance of Jsphon_Decoder
+ * $json =& new Jsphon_Decoder();
+ * 
+ * //convert JSON-formatted string to PHP variable
+ * $value = '["foo","bar",{"hoge":[1,2]}]';
+ * $var = $json->decode($value);
+ * 
+ * print_r($var);
+ * //array('foo', 'bar', array('hoge' => array(1,2)))
+ * </code>
+ * 
+ * @author Hawk
+ */
+class Jsphon_Decoder
+{
+    var $_mbstring;
+
+    var $_decodeOverUCS2;
+
+    var $_internalError;
+
+    var $_transTable = array(
+        '\b' => "\x08",
+        '\t' => "\x09",
+        '\n' => "\x0A",
+        '\f' => "\x0C",
+        '\r' => "\x0D",
+        '\"' => "\x22",
+        '\/' => "\x2F",
+         '\\\\' => "\x5C"
+        );
+
+    var $_allUESreg = '/\\\u([a-fA-F0-9]{4})/';
+
+    var $_utf16surUESreg = '/\\\u(D[89AB][A-F0-9]{2})\\\u(D[C-F][A-F0-9]{2})/i';
+
+    /**
+     * construct a new Jsphon_Decoder instance.
+     * 
+     * @param  bool   $decodeOverUCS2   If true, decodeString() converts the whole
+     *                                  Unicode escape sequences (\uXXXX) including surrogate pairs
+     *                                  to corresponding characters in UTF-8.
+     */
+    function Jsphon_Decoder($decodeOverUCS2=false)
+    {
+        $this->_decodeOverUCS2 = $decodeOverUCS2;
+        $this->_mbstring = extension_loaded('mbstring');
+    }
+
+    /**
+     * decodes a JSON string into appropriate variable
+     * 
+     * @param  String    $json
+     * @return mixed
+     */
+    function decode($json)
+    {
+        $tknz = new Jsphon_Decoder_Tokenizer($json,
+                                             array(&$this, 'handleInternalError'));
+        $this->_internalError = false;
+
+        $result = null;
+        if($tknz->nextToken()) {
+            $result = $this->_decodeJSValue($tknz);
+        }
+        
+        $this->_internalError = false;
+        return $result;
+    }
+
+    /**
+     * 
+     * @param  Object $tknz
+     * @return mixed
+     */
+    function _decodeJSValue(&$tknz)
+    {
+        switch($tknz->getToken()) {
+          case JSPHON_TOKEN_DATUM:
+            if(is_string($r = $tknz->getTokenValue())) {
+                $r = $this->decodeString($r);
+            }
+            return $r;
+            
+          case JSPHON_TOKEN_LBRACKET:
+            return $this->_decodeArray($tknz);
+
+          case JSPHON_TOKEN_LBRACE:
+            return $this->_decodeObject($tknz);
+
+          default:
+            $this->_error("syntax error: Expecting '{', '[' or DAUM.");
+            return null;
+        }
+    }
+
+    /**
+     * Decodes a JSON array format:
+     * [element, element2,...,elementN]
+     * 
+     * @param  Object $tknz
+     * @return array
+     */
+    function _decodeArray(&$tknz)
+    {
+        $ret = array();
+        if(!($token = $tknz->nextToken())) {
+            return null;
+            
+        } elseif($token == JSPHON_TOKEN_RBRACKET) {
+            return $ret;
+        }
+
+        //if false, break
+        while(  ($value = $this->_decodeJSValue($tknz) or true)
+            and !$this->_internalError
+            and ($ret[] = $value or true)
+            and $token = $tknz->nextToken()
+            and $token == JSPHON_TOKEN_COMMA
+            and $token = $tknz->nextToken()
+            );
+
+        if($this->_internalError) {
+            return null;
+            
+        } elseif($token == JSPHON_TOKEN_RBRACKET) {
+            return $ret;
+        } else {
+            $this->_error("Missing ',' or ']' in array encoding.");
+            return null;
+        }
+    }
+
+    /**
+     * Decodes an object of the form:
+     *  { "attribute: value, "attribute2" : value,...}
+     * 
+     * _decodeObject() always converts a JSON-object to an associative array,
+     * because you can't access empty property in PHP5.
+     * <code>
+     * // { "":"foo" }
+     * $obj->{""} = "foo"; //Fatal error: Cannot access empty property
+     * </code>
+     * 
+     * @param  Object $tknz
+     * @return array
+     */
+    function _decodeObject(&$tknz)
+    {
+        $ret = array();
+        if(!($token = $tknz->nextToken())) {
+            return null;
+            
+        } elseif($token == JSPHON_TOKEN_RBRACE) {
+            return $ret;
+        }
+
+        //if false, break
+        while(  ($key = $this->_decodeJSValue($tknz) or true)
+            and !$this->_internalError
+            and $this->_checkObjectKey($key)
+            and $token = $tknz->nextToken()
+            and $this->_checkKeyValueSep($token)
+            and $token = $tknz->nextToken()
+            and ($value = $this->_decodeJSValue($tknz) or true)
+            and !$this->_internalError
+            and ($ret[$key] = $value or true)
+            and $token = $tknz->nextToken()
+            and $token == JSPHON_TOKEN_COMMA
+            and $token = $tknz->nextToken()
+            );
+
+        if($this->_internalError) {
+            return null;
+            
+        } elseif($token == JSPHON_TOKEN_RBRACE) {
+            return $ret;
+        } else {
+            $this->_error("Missing ',' or '}' in object encoding.");
+            return null;
+        }
+    }
+
+    function _checkObjectKey($key)
+    {
+        if(!is_string($key)) {
+            $this->_error("Object's key must be a string, but is ". gettype($key));
+            return false;
+        }
+        return true;
+    }
+
+    function _checkKeyValueSep($token)
+    {
+        if($token != JSPHON_TOKEN_COLON) {
+            $this->_error("Missing ':' in object encoding.");
+            return false;
+        }
+        return true;
+    }
+    
+
+    /**
+     * 
+     * 
+     * @param  String    $encoded
+     * @return String
+     */
+    function decodeString($encoded)
+    {
+        $ret = strtr($encoded, $this->_transTable);
+        
+        if($this->_decodeOverUCS2) {
+            return $this->_decodeUESOverUCS2($ret);
+        } else {
+            //_decodeUESWithoutMbstring() fastar than _decodeUES()...
+            return $this->_decodeUESWithoutMbstring($ret);
+        }
+        
+        /*
+        if(!$this->_mbstring) {
+            return $this->_decodeUESWithoutMbstring($ret);
+        } elseif($this->_decodeOverUCS2) {
+            return $this->_decodeUESOverUCS2($ret);
+        } else {
+            return $this->_decodeUES($ret);
+        }
+        */
+    }
+
+    function _decodeUES($str)
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_allUESreg, $str, $matches)) {
+            return $str;
+        }
+
+        $codepoints = $matches[1];
+        foreach($matches[0] as $i => $escSeq) {
+            if(isset($transTable[$escSeq])) {
+                continue;
+            }
+            $codepoint = hexdec($codepoints[$i]);
+            $transTable[$escSeq] = (0xD800 <= $codepoint && $codepoint <= 0xDFFF) ? ""
+            : mb_convert_encoding(pack('n', $codepoint), 'UTF-8', 'UCS-2');
+        }
+        return strtr($str, $transTable);
+    }
+    
+    function _decodeUESOverUCS2($str)
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_allUESreg, $str, $u16)) {
+            return $str;
+        }
+        
+        if(preg_match_all($this->_utf16surUESreg, $str, $u16sur)) {
+            $sur1st = $u16sur[1];
+            $sur2nd = $u16sur[2];
+            
+            foreach($u16sur[0] as $i => $escSeq) {
+                if(isset($transTable[$escSeq])) {
+                    continue;
+                }
+                $transTable[$escSeq] = mb_convert_encoding(
+                    pack('n2', hexdec($sur1st[$i]), hexdec($sur2nd[$i])), 'UTF-8', 'UTF-16BE');
+            }
+        }
+
+        $codepoints = $u16[1];
+        foreach($u16[0] as $i => $escSeq) {
+            if(isset($transTable[$escSeq])) {
+                continue;
+            }
+            $codepoint = hexdec($codepoints[$i]);
+            $transTable[$escSeq] = (0xD800 <= $codepoint && $codepoint <= 0xDFFF) ? ""
+            : mb_convert_encoding(pack('n', $codepoint), 'UTF-8', 'UCS-2');
+        }
+        return strtr($str, $transTable);
+    }
+
+    function _decodeUESWithoutMbstring($str)
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_allUESreg, $str, $matches)) {
+            return $str;
+        }
+
+        $codepoints = $matches[1];
+        foreach($matches[0] as $i => $escSeq) {
+            if(isset($transTable[$escSeq])) {
+                continue;
+            }
+            
+            $utf8char = "";
+
+            $cp = hexdec($codepoints[$i]);
+            switch(true) {
+              case ($cp < 0x80):
+                $utf8char = chr($cp);
+                break;
+                
+              case (0xD800 <= $cp && $cp <= 0xDFFF):
+                break;
+
+              case ($cp < 0x800):
+                $utf8char = chr($cp >> 6 & 0x1F | 0xC0) . chr($cp & 0x3F | 0x80);
+                break;
+                
+              case ($cp < 0x10000):
+                $utf8char = chr($cp >> 12 & 0xF | 0xE0) .
+                chr($cp >> 6 & 0x3F | 0x80) . chr($cp & 0x3F | 0x80);
+                break;
+
+              default:
+            }
+            $transTable[$escSeq] = $utf8char;
+        }
+        return strtr($str, $transTable);
+    }
+    
+
+    /**
+     * a simple wrapper for PEAR_ErrorStack::push.
+     * 
+     * @param  String    $message
+     * @param  array     $param
+     * @param  string    $level
+     * @param  int       $code
+     * @return String
+     */
+    function _error($message,
+                    $param= array(),
+                    $level='error',
+                    $code=JSPHON_ERROR_DECODE_SYNTAX)
+    {
+        $e = Jsphon_Error::push(
+            $code, $level, $param, $message, false, debug_backtrace());
+        $this->_internalError = true;
+        return $e;
+    }
+    
+    function handleInternalError($err)
+    {
+        $this->_internalError = true;
+    }
+}
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon/Decoder/Tokenizer.php b/trunk/NP_Clap/sharedlibs/Jsphon/Decoder/Tokenizer.php
new file mode 100644 (file)
index 0000000..f422692
--- /dev/null
@@ -0,0 +1,143 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+define('JSPHON_TOKEN_EOF',      1);
+define('JSPHON_TOKEN_DATUM',    2);
+define('JSPHON_TOKEN_LBRACE',   3);
+define('JSPHON_TOKEN_LBRACKET', 4);
+define('JSPHON_TOKEN_RBRACE',   5);
+define('JSPHON_TOKEN_RBRACKET', 6);
+define('JSPHON_TOKEN_COMMA',    7);
+define('JSPHON_TOKEN_COLON',    8);
+
+/**
+ * Jsphon_Decoder_Tokenizer
+ * 
+ * @author Hawk
+ */
+class Jsphon_Decoder_Tokenizer
+{
+    var $_source;
+
+    var $_token;
+
+    var $_tokenValue;
+
+    var $_tokenTable = array(
+        '{' => JSPHON_TOKEN_LBRACE,
+        '}' => JSPHON_TOKEN_RBRACE,
+        '[' => JSPHON_TOKEN_LBRACKET,
+        ']' => JSPHON_TOKEN_RBRACKET,
+        ',' => JSPHON_TOKEN_COMMA,
+        ':' => JSPHON_TOKEN_COLON
+        );
+
+    var $_tokenValueTable = array(
+        'true'  => true,
+        'false' => false,
+        'null'  => null
+        );
+
+    var $_errorCallback;
+
+    /**
+     * constructs a new Jsphon_Decoder_Tokenizer instance.
+     * 
+     * @param  String    $source
+     */
+    function Jsphon_Decoder_Tokenizer($source, $internalErrorCallback=null)
+    {
+        $this->_source = $source;
+        $this->_errorCallback = $internalErrorCallback;
+    }
+
+    /**
+     * Retrieves the next token from the source stream.
+     * 
+     * @return int or false
+     */
+    function nextToken()
+    {
+        $src = ltrim($this->_source);
+
+        $this->_tokenValue = null;
+        $this->_token = JSPHON_TOKEN_EOF;
+
+        switch(true)
+        {
+          case $src === '':
+            break;
+            
+          case ($c = $src{0}) !== "" and isset($this->_tokenTable[$c]):
+            $this->_token = $this->_tokenTable[$c];
+            $src = substr($src, 1);
+            break;
+
+          case $c == '"' and preg_match('/^"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"/', $src, $m):
+            $this->_token = JSPHON_TOKEN_DATUM;
+            $this->_tokenValue = $m[1];
+            $src = substr($src, strlen($m[0]));
+            break;
+
+          case preg_match('/^(true|false|null)\b/', $src, $m):
+            $this->_token = JSPHON_TOKEN_DATUM;
+            $this->_tokenValue = $this->_tokenValueTable[$m[1]];
+            $src = substr($src, ($m[1]{0} == 'f' ? 5 : 4));
+            break;
+
+          case preg_match('/^-?(?:[1-9]\d+|\d)(?:\.\d+)?(?:[eE][-+]?\d+)?/', $src, $m):
+            $this->_token = JSPHON_TOKEN_DATUM;
+            $intV   = (int)$m[0];
+            $floatV = (float)$m[0];
+            $this->_tokenValue = ($intV == $floatV) ? $intV : $floatV;
+            $src = substr($src, strlen($m[0]));
+            break;
+
+          default:
+            $err = Jsphon_Error::push(
+                JSPHON_ERROR_DECODE_SYNTAX,
+                'error',
+                array(),
+                'Illegal Token',
+                false,
+                debug_backtrace());
+
+            if(is_callable($this->_errorCallback)) {
+                call_user_func($this->_errorCallback, $err);
+            }
+            return false;
+
+        }
+
+        $this->_source = $src;
+        return $this->_token;
+    }
+
+    function getToken()
+    {
+        return $this->_token;
+    }
+
+    function getTokenValue()
+    {
+        return $this->_tokenValue;
+    }
+
+}
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon/Encoder.php b/trunk/NP_Clap/sharedlibs/Jsphon/Encoder.php
new file mode 100644 (file)
index 0000000..7cf9689
--- /dev/null
@@ -0,0 +1,250 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+/**
+ * Converts to JSON format.
+ * 
+ * example:
+ * <code>
+ * //create a new instance of Jsphon_Encoder
+ * $json =& new Jsphon_Encoder();
+ * 
+ * //convert a complex value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array('hoge' => array(1,2)));
+ * $output = $json->encode($value);
+ * 
+ * print_r($output);
+ * //prints: ["foo","bar",{"hoge":[1,2]}]
+ * </code>
+ * 
+ * @author Hawk
+ */
+class Jsphon_Encoder
+{
+    var $_mbstring;
+    
+    var $_escapeNonASCII;
+    
+    var $_escapeOverUCS2;
+    
+    var $_transTable;
+    
+    var $_utf8UCS2reg;
+    
+    var $_utf8overUCS2reg;
+    
+    /**
+     * constructs a new Jsphon_Encoder instance.
+     * 
+     * @param bool $escapeNonASCII  If true, encode() converts non-ASCII characters 
+     *                              to Unicode escape sequence (\uXXXX).
+     * @param bool $escapeOverUCS2  If true, encode() converts all the non-ASCII characters 
+     *                              that is encodable in UTF-16 to Unicode escape sequence.
+     *                              This parameter affects the encoder's behavior 
+     *                              only if $escapeNonASCII is set to true and 
+     *                              the multibyte string extension is available.
+     * 
+     */
+    function Jsphon_Encoder($escapeNonASCII=true, $escapeOverUCS2=false)
+    {
+        $this->_escapeNonASCII = $escapeNonASCII;
+        $this->_escapeOverUCS2 = $escapeOverUCS2;
+        $this->_mbstring = extension_loaded('mbstring');
+
+        $this->_transTable = array(
+            "\x08" => '\b',
+            "\x09" => '\t',
+            "\x0A" => '\n',
+            "\x0C" => '\f',
+            "\x0D" => '\r',
+            "\x22" => '\"',
+            "\x2F" => '\/',
+            "\x5C" => '\\\\'
+        );
+        
+        $utf8ucs2 = '[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}';
+        $utf16sur = '[\xF0-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2}';
+        $this->_utf8UCS2reg = "/{$utf8ucs2}/";
+        $this->_utf8overUCS2reg = "/{$utf8ucs2}|{$utf16sur}/";
+    }
+    
+    /**
+     * encodes an arbitrary variables into JSON format.
+     * 
+     * If $_escapeNonASCII is set to true, 
+     * encode() removes all non-ASCII characters to make sure that 
+     * returning value dosen't contain any non-ASCII characters.
+     * 
+     * @param mixed $value
+     * @return string
+     */
+    function encode($value)
+    {
+        $json = $this->_encode($value);
+        if($this->_escapeNonASCII) {
+            $json = preg_replace('/[\x80-\xFF]/', '', $json);
+        }
+        return $json;
+    }
+    
+    function _encode($value)
+    {
+        if($value === null) {
+            return 'null';
+            
+        } elseif(is_bool($value)) {
+            return $value ? 'true' : 'false';
+            
+        } elseif(is_int($value)) {
+            return (int)$value;
+            
+        } elseif(is_float($value)) {
+            return (float)$value;
+            
+        } elseif(is_string($value)) {
+            return '"'. $this->_encodeString($value) .'"';
+
+        } elseif(is_array($value)) {
+            if(($len = count($value)) > 0 &&
+               array_keys($value) !== range(0, $len - 1)) {
+                return $this->_encodeObject($value);
+            } else {
+                return '['. join(',', array_map(array(&$this, '_encode'), $value)) .']';
+            }
+
+        } elseif(is_object($value)) {
+            return $this->_encodeObject($value);
+            
+        }
+        
+        return 'null';
+    }
+    
+    function _encodeObject($arr)
+    {
+        $result = array();
+        foreach($arr as $name => $value) {
+            $result[] = $this->_encode((string)$name) .':'. $this->_encode($value);
+        }
+        return '{'. join(',', $result) ."}";
+    }
+    
+    function _encodeString($str)
+    {
+        $str = strtr($str, $this->_transTable);
+        
+        if(!$this->_escapeNonASCII) {
+            return $str;
+        }
+        
+        if(!$this->_mbstring) {
+            return $this->_escapeNonASCIIWithoutMbstring($str);
+        }
+        
+        if($this->_escapeOverUCS2) {
+            return $this->_escapeNonASCIIOverUCS2($str);
+        } else {
+            return $this->_escapeNonASCII($str);
+        }
+    }
+    
+    function _escapeNonASCII($str) 
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_utf8UCS2reg, $str, $matches)) {
+            return $str;
+        }
+        
+        foreach($matches[0] as $utf8char) {
+            if(isset($transTable[$utf8char])) {
+                continue;
+            }
+            $transTable[$utf8char] = $this->_formatSeq(
+                mb_convert_encoding($utf8char, 'UTF-16', 'UTF-8'));
+        }
+        return strtr($str, $transTable);
+    }
+
+    function _escapeNonASCIIOverUCS2($str) 
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_utf8overUCS2reg, $str, $matches)) {
+            return $str;
+        }
+        
+        foreach($matches[0] as $utf8char) {
+            if(isset($transTable[$utf8char])) {
+                continue;
+            }
+            $utf16char = mb_convert_encoding($utf8char, 'UTF-16', 'UTF-8');
+            
+            if(($l = strlen($utf16char)) == 2) {
+                $transTable[$utf8char] = $this->_formatSeq($utf16char);
+            } elseif($l == 4) {
+                $transTable[$utf8char] = 
+                    $this->_formatSeq(substr($utf16char, 0, 2)) . $this->_formatSeq(substr($utf16char, 2));
+            }
+            
+        }
+        return strtr($str, $transTable);
+    }
+
+    function _escapeNonASCIIWithoutMbstring($str) 
+    {
+        $transTable = array();
+
+        if(!preg_match_all($this->_utf8UCS2reg, $str, $matches)) {
+            return $str;
+        }
+        
+        foreach($matches[0] as $utf8char) {
+            if(isset($transTable[$utf8char])) {
+                continue;
+            }
+            
+            switch(strlen($utf8char)) {
+            case 2:
+                $code = (
+                 ((ord($utf8char{0}) & 0x1F) << 6) |
+                  (ord($utf8char{1}) & 0x3F)
+                );
+                break;
+
+            case 3:
+                $code = (
+                 ((ord($utf8char{0}) & 0x0F) << 12) |
+                 ((ord($utf8char{1}) & 0x3F) << 6 ) |
+                  (ord($utf8char{2}) & 0x3F)
+                );
+                break;
+            default:
+            }
+            $transTable[$utf8char] = '\u'. substr('0000'. dechex($code), -4);
+        }
+        return strtr($str, $transTable);
+    }
+
+    function _formatSeq($u16)
+    {
+        return '\u'. substr('0000'. bin2hex($u16), -4);
+    }
+}
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon/Error.php b/trunk/NP_Clap/sharedlibs/Jsphon/Error.php
new file mode 100644 (file)
index 0000000..b2a5413
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+/**
+ * Jsphon_Error
+ * 
+ * @author Hawk
+ */
+class Jsphon_Error
+{
+    var $_isPHP5;
+
+    var $_existsPEAR;
+
+    var $_throwException = true;
+
+    var $_exceptionCreator;
+
+    /**
+     * Constructor
+     * 
+     * @access private
+     */
+    function Jsphon_Error()
+    {
+        $this->_isPHP5     = version_compare(phpversion(), '5', '>=');
+        $this->_existsPEAR = (@include_once "PEAR/ErrorStack.php");
+        
+        if($this->_isPHP5) {
+            if($this->_existsPEAR) {
+                require_once(dirname(__FILE__) .'/Exception.php');
+                $method = '_createJsphonException';
+            } else {
+                $method = '_createException';
+            }
+            $this->_exceptionCreator = array(__CLASS__, $method);
+        }
+    }
+
+    /**
+     * 
+     * 
+     * @since 06/09/05 13:21
+     * @return Jsphon_Error
+     */
+    function &singleton()
+    {
+        static $instance = null;
+        if($instance === null) {
+            $instance = new Jsphon_Error();
+        }
+        return $instance;
+    }
+
+    /**
+     * 
+     * @static
+     * @param  int      $code
+     * @param  string   $level
+     * @param  array    $params
+     * @param  string   $msg
+     * @param  mixed    $repackage
+     * @param  array    $backtrace
+     * @return array
+     */
+    function push($code, $level = 'error', $params = array(), $msg = false,
+                  $repackage = false, $backtrace = false)
+    {
+        if (!$backtrace) {
+            $backtrace = debug_backtrace();
+        }
+
+        $self  =& Jsphon_Error::singleton();
+
+        if(!$self->_isPHP5 || !$self->_throwException) {
+            return $self->_push(
+                $code, $level, $params, $msg, $repackage, $backtrace);
+        }
+
+        $pushOnly = true;
+        $err = $self->_push(
+                $code, $level, $params, $msg, $repackage, $backtrace, $pushOnly);
+
+        array_shift($backtrace);
+        throw (call_user_func($self->_exceptionCreator, $msg, $code, $backtrace));
+        return ;
+    }
+
+    /**
+     * 
+     * 
+     * @access private
+     * @static
+     * @param  int      $code
+     * @param  string   $level
+     * @param  array    $params
+     * @param  string   $msg
+     * @param  mixed    $repackage
+     * @param  array    $backtrace
+     * @param  bool     $pushOnly
+     * @return array or null unless PEAR_ErrorStack exists.
+     */
+    function _push($code, $level='error', $params=array(), $msg=false,
+                              $repackage=false, $backtrace=false, $pushOnly=false)
+    {
+        if(!$this->_existsPEAR) {
+            return;
+        }
+
+        $stack =& PEAR_ErrorStack::singleton('Jsphon');
+        if($pushOnly) {
+            $stack->pushCallback(array(__CLASS__, 'pushOnly'));
+        }
+        
+        $err = $stack->push($code, $level, $params, $msg, $repackage, $backtrace);
+
+        if($pushOnly) {
+            $stack->popCallback();
+        }
+        return $err;
+    }
+
+    /**
+     * 
+     * @since 06/09/05 13:34
+     * @param  String    $bool
+     * @param  String    $exceptionClass
+     * @return String
+     */
+    function setThrowException($bool)
+    {
+        $this->_throwException = $bool;
+    }
+
+    /**
+     * error handler which do nothing
+     * 
+     * @since 06/09/05 13:52
+     * @param  array    $err
+     * @return int
+     */
+    function pushOnly($err)
+    {
+        return PEAR_ERRORSTACK_PUSH;
+    }
+
+    /**
+     * 
+     * @static
+     * @param  String    $msg
+     * @param  int       $code
+     * @param  array    $trace
+     * @return Exception
+     */
+    function _createJsphonException($msg, $code, $trace)
+    {
+        return new Jsphon_Exception($msg, $code, $trace);
+    }
+
+    /**
+     * 
+     * @static
+     * @param  String    $msg
+     * @param  int       $code
+     * @param  array    $trace
+     * @return Exception
+     */
+    function _createException($msg, $code, $trace)
+    {
+        return new Exception($msg, $code);
+    }
+}
+
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/Jsphon/Exception.php b/trunk/NP_Clap/sharedlibs/Jsphon/Exception.php
new file mode 100644 (file)
index 0000000..3fc5f85
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5                                                |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk                                            |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License,    |
+// | that is available at http://www.php.net/license/3_0.txt.           |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp>                                 |
+// +--------------------------------------------------------------------+
+//
+//
+
+require_once('PEAR/Exception.php');
+
+/**
+ * Jsphon_Exception
+ * 
+ * @author Hawk
+ */
+class Jsphon_Exception extends PEAR_Exception
+{
+    private $_outerTrace;
+    
+    /**
+     * Constructor
+     * 
+     */
+    public function __construct($msg, $code, $outerTrace)
+    {
+        $this->_outerTrace = $outerTrace;
+        parent::__construct($msg, $code);
+    }
+    
+    /**
+     * 
+     * 
+     * @override
+     * @return array
+     */
+    public function getTraceSafe()
+    {
+        if(count($this->_outerTrace) > 0) {
+            return $this->_outerTrace;
+        }
+        return parent::getTraceSafe();
+    }
+
+}
+
+?>
diff --git a/trunk/NP_Clap/sharedlibs/cles/Feedback.php b/trunk/NP_Clap/sharedlibs/cles/Feedback.php
new file mode 100644 (file)
index 0000000..d900e9e
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+// vim: tabstop=2:shiftwidth=2
+
+/**
+  * Feedback.php ($Revision: 1.1 $)
+  * 
+  * by hsur ( http://blog.cles.jp/np_cles )
+  * $Id: Feedback.php,v 1.1 2008-05-17 19:11:11 hsur Exp $
+*/
+
+/*
+  * Copyright (C) 2006 CLES. All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+  * 
+  * In addition, as a special exception, cles( http://blog.cles.jp/np_cles ) gives
+  * permission to link the code of this program with those files in the PEAR
+  * library that are licensed under the PHP License (or with modified versions
+  * of those files that use the same license as those files), and distribute
+  * linked combinations including the two. You must obey the GNU General Public
+  * License in all respects for all of the code used other than those files in
+  * the PEAR library that are licensed under the PHP License. If you modify
+  * this file, you may extend this exception to your version of the file,
+  * but you are not obligated to do so. If you do not wish to do so, delete
+  * this exception statement from your version.
+*/
+
+class cles_Feedback {
+       var $oPluginAdmin;
+       function CLES_Feedback(&$pluginAdmin){
+               $this->oPluginAdmin = $pluginAdmin;
+       }
+       
+       function getMenuStr(){
+               return mb_convert_encoding('動作確認/不具合報告', _CHARSET, 'UTF-8');
+       }
+       
+       function printForm($extra = '') {
+               ob_start();
+               
+               global $nucleus, $CONF;
+               
+               echo "<h2>動作確認/不具合報告</h2>";
+               echo '<p>下記より、作者への動作確認/不具合の報告を行うことができます。</p>';
+
+               // js
+               echo '<script langage="JavaScript">
+                       function selectall(){
+                               var elements = document.getElementsByTagName(\'input\');
+                               for( var i=0; i < elements.length; i++){
+                                       var e = elements[i];
+                                       if( e.type == \'checkbox\' ){
+                                               e.checked = true;
+                                       }
+                               }
+                               return false;
+                       }
+               </script>';
+               
+               echo "<h3>収集する情報と公開について</h3>";
+               echo '<p>デフォルトで必要最低限の環境情報(赤字のもの)を開発者のサーバへ送信します。<br />
+                                                       <span style="font-weight:bold; color:red">差し支えない範囲で環境情報の提供にご協力ください。</span></p>
+                                                       <p>※ 収集した情報は統計処理、及びプラグインのBugFixのみに利用されます。また統計処理した結果については公表することがあります。</p>';
+               echo '<p><a href="#" onclick="javascript:selectall();return false;">全て送信する場合はここをクリック</a></p>';
+               
+               echo "<h3>サイト固有コードについて</h3>";
+               echo '<p>動作報告の重複を取り除くため、管理画面のURLのmd5を計算したものを送信しています。この情報から管理画面のURLを復元することはできないようになっています。<a href="http://computers.yahoo.co.jp/dict/security/hash/677.html" target="_blank">md5の解説についてはこちらをご覧ください。(Yahoo!コンピュータ用語辞典)</a></p>';
+               
+               // form 
+               echo '<form method="post" action="http://blog.cles.jp/support/report.php">' . "\n";
+
+               // table
+               echo "<table>\n";
+               echo "<tr>\n";
+               echo "<th>項目の説明</th>\n";
+               echo "<th>送信される値</th>\n";
+               echo "<th><a href=\"#\" onclick=\"javascript:selectall();return false;\">全て送信する</th>\n";
+               echo "</tr>\n";
+
+               $res = sql_query("show variables like 'version'");
+               $assoc = mysql_fetch_assoc($res);
+               $mysqlVersion = $assoc['Value'];
+               
+               if( function_exists('gd_info') )
+                       $gdinfo = @gd_info();
+               else
+                       $gdinfo['GD Version'] = 'GD is not supported';
+
+               global $CONF;
+
+               $this->_printtr('siteid', 'サイトの固有コード', md5(trim($CONF['AdminURL'])));
+               $this->_printtr('plugin_name', 'プラグイン名', $this->oPluginAdmin->plugin->getName());
+               $this->_printtr('plugin_version', 'プラグインのバージョン', $this->oPluginAdmin->plugin->getVersion());
+               $this->_printtr('plugin_info', 'プラグインの情報', $extra, true);
+               $this->_printtr('nucleus_version', 'Nucleusのバージョン', $nucleus['version'], true);
+               $this->_printtr('nucleus_charset', 'Nucleusのキャラクタセット', _CHARSET);
+               $this->_printtr('php_version', 'PHPのバージョン', PHP_VERSION, true);
+               $this->_printtr('php_sapi', 'PHPの種類', php_sapi_name());
+               $this->_printtr('php_os', 'OSの種類', PHP_OS, true);
+               $this->_printtr('php_safemode', 'セーフモードの有無', ini_get('safe_mode') ? 'on' : 'off');
+               $this->_printtr('php_gd_version', 'GDのバージョン', $gdinfo['GD Version'], true);
+               $this->_printtr('php_gd_support', 'サポートしているイメージタイプ', implode(',', $this->_supportedImageTypes()) );
+               $this->_printtr('mysql_version', 'MySQLのバージョン', $mysqlVersion, true);
+
+               echo "<tr>\n";
+               echo "<td>このプラグインは機能しましたか?</td>\n";
+               echo '<td colsan="2"><input type="radio" name="user_intention" value="ok" />はい <br/> <input type="radio" name="intention" value="ng" />いいえ'."</td>\n";
+               echo "</tr>\n";
+
+               echo "<tr>\n";
+               echo "<td>不具合の内容をお寄せください<br /><em>必ず回答が必要な質問については、<a href=\"http://japan.nucleuscms.org/bb/\">Nucleusサポートフォーラム</a>もしくは<a href=\"http://blog.cles.jp/np_cles/\">作者ページ</a>でご質問ください。</em></td>\n";
+               echo '<td colspan="2"><textarea name="user_freetext" rows="10" cols="70"></textarea>'."</td>\n";
+               echo "</tr>\n";
+
+               echo "<tr>\n";
+               echo "<td>よろしければサイトのURLを教えてください</td>\n";
+               echo '<td colspan="2"><textarea name="user_url" rows="1" cols="70"></textarea>'."</td>\n";
+               echo "</tr>\n";
+               
+               echo "<tr>\n";
+               echo "<td>リンク集作成の際、リンクをはらせていただけますか?</td>\n";
+               echo '<td colspan="2"><input type="radio" name="user_disclose" value="yes" />はい <br/> <input type="radio" name="intention" value="no" />いいえ'."</td>\n";
+               echo "</tr>\n";
+
+               echo '<tr><td colspan="3"><div align="right"><input type="submit" name="submit" value="動作確認を送信する" /></div></td></tr>';
+               echo "</table>\n";
+               echo "</form>\n";
+               
+               $contents = ob_get_contents();
+               ob_end_clean();
+               echo mb_convert_encoding($contents, _CHARSET, 'UTF-8');
+       }
+       
+       function _printtr($name, $desc, $value, $canDisable = false) {
+               echo "<tr>\n";
+       
+               if ($canDisable) {
+                       echo "<td>".$desc."</td>\n";
+                       echo "<td>".htmlspecialchars($value)."</td>\n";
+                       echo '<td><input type="checkbox" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" /></td>'."\n";
+               } else {
+                       echo '<td><span style="font-weight:bold; color:red">'.$desc."</span></td>\n";
+                       echo '<td><span style="font-weight:bold; color:red">'.htmlspecialchars($value)."</span></td>\n";
+                       echo '<td><input type="checkbox" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" readonly="readonly" checked="checked"/></span></td>'."\n";
+               }
+               echo "</tr>\n";
+       }
+       
+       function _supportedImageTypes() {
+               if( !function_exists('gd_info') ) return "";
+               
+               $aSupportedTypes = array ();
+               $aPossibleImageTypeBits = array (IMG_GIF => 'GIF', IMG_JPG => 'JPG', IMG_PNG => 'PNG', IMG_WBMP => 'WBMP');
+       
+               foreach ($aPossibleImageTypeBits as $iImageTypeBits => $sImageTypeString) {
+                       if (imagetypes() & $iImageTypeBits) {
+                               $aSupportedTypes[] = $sImageTypeString;
+                       }
+               }
+       
+               return $aSupportedTypes;
+       }
+
+}
diff --git a/trunk/NP_Clap/sharedlibs/cles/Template.php b/trunk/NP_Clap/sharedlibs/cles/Template.php
new file mode 100644 (file)
index 0000000..028f783
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+// vim: tabstop=2:shiftwidth=2
+
+/**
+  * Template.php ($Revision: 1.1 $)
+  * 
+  * by hsur ( http://blog.cles.jp/np_cles )
+  * $Id: Template.php,v 1.1 2008-05-17 19:11:11 hsur Exp $
+*/
+
+/*
+  * Copyright (C) 2006 CLES. All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+  * 
+  * In addition, as a special exception, cles( http://blog.cles.jp/np_cles ) gives
+  * permission to link the code of this program with those files in the PEAR
+  * library that are licensed under the PHP License (or with modified versions
+  * of those files that use the same license as those files), and distribute
+  * linked combinations including the two. You must obey the GNU General Public
+  * License in all respects for all of the code used other than those files in
+  * the PEAR library that are licensed under the PHP License. If you modify
+  * this file, you may extend this exception to your version of the file,
+  * but you are not obligated to do so. If you do not wish to do so, delete
+  * this exception statement from your version.
+*/
+
+class cles_Template {
+       var $defaultLang = 'japanese-utf8';
+       var $defalutPattern = '#{{(.*?)(\|)?}}#ie';
+       var $lang;
+       var $templateDir;
+
+       function cles_Template($templateDir) {
+               global $CONF;
+               $this->templateDir = $templateDir;
+               $this->lang = ereg_replace( '[\\|/]', '', getLanguageName());
+       }
+
+       function fetch($name, $dir = null, $suffix = 'html') {
+               $path = $this->templateDir.'/'.( $dir ? strtolower($dir) . '/' : '' ).strtolower($name).'_'.$this->lang.( $suffix ? '.'.strtolower($suffix) : '' );
+               if ( ! file_exists($path) ){
+                       $path = $this->templateDir.'/'.( $dir ? strtolower($dir) . '/' : '' ).strtolower($name).'_'.$this->defaultLang.( $suffix ? '.'.strtolower($suffix) : '' );
+                       if ( ! file_exists($path) )
+                               return '';
+               }
+               
+               $fsize = filesize($path);
+               if ($fsize <= 0) return '';
+               
+               $fd = fopen($path, 'r');
+               $contents = fread($fd, $fsize);
+               fclose($fd);
+               return $contents;
+       }
+       
+       function fill($template, $values, $default = null) {
+               if( $default )
+                       return preg_replace($this->defalutPattern, 'isset($values["$1"]) ? ("$2" ? htmlspecialchars($values["$1"], ENT_QUOTES) : $values["$1"]) : $default', $template);
+               if( $default === null )
+                       return preg_replace($this->defalutPattern, '("$2") ? htmlspecialchars($values["$1"], ENT_QUOTES) : $values["$1"]', $template);
+               return preg_replace($this->defalutPattern, 'isset($values["$1"]) ? ("$2" ? htmlspecialchars($values["$1"], ENT_QUOTES) : $values["$1"]) : "{{$1}}" ', $template);
+       }
+}
diff --git a/trunk/NP_Clap/sharedlibs/sharedlibs.php b/trunk/NP_Clap/sharedlibs/sharedlibs.php
new file mode 100644 (file)
index 0000000..3213ab4
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+// vim: tabstop=2:shiftwidth=2
+
+/**
+  * sharedlibs.php ($Revision: 1.1 $)
+  * 
+  * by hsur ( http://blog.cles.jp/np_cles )
+  * $Id: sharedlibs.php,v 1.1 2008-05-17 19:11:11 hsur Exp $
+*/
+
+/*
+  * Copyright (C) 2006 CLES. All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  * 
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  * 
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+  * 
+  * In addition, as a special exception, cles( http://blog.cles.jp/np_cles ) gives
+  * permission to link the code of this program with those files in the PEAR
+  * library that are licensed under the PHP License (or with modified versions
+  * of those files that use the same license as those files), and distribute
+  * linked combinations including the two. You must obey the GNU General Public
+  * License in all respects for all of the code used other than those files in
+  * the PEAR library that are licensed under the PHP License. If you modify
+  * this file, you may extend this exception to your version of the file,
+  * but you are not obligated to do so. If you do not wish to do so, delete
+  * this exception statement from your version.
+*/
+
+if (!defined('NP_SHAREDLIBS_LOADED')) {
+       if (!defined('PATH_SEPARATOR')) {
+               if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+                       define('PATH_SEPARATOR', ';');
+               } else {
+                       define('PATH_SEPARATOR', ':');
+               }
+       }
+       ini_set('include_path', dirname(__FILE__).PATH_SEPARATOR.ini_get('include_path'));
+
+       define('NP_SHAREDLIBS_LOADED', true);
+}