From b284341e28904af75f4246ceb5184dec27770cd1 Mon Sep 17 00:00:00 2001 From: Jude Anthony Date: Mon, 11 Feb 2008 02:12:07 +0000 Subject: [PATCH] Simplify and beautify code; allow admin config to override most text options; graphical rating bars (at last!) --- plugins/serendipity_event_karma/ChangeLog | 5 + .../UTF-8/lang_bg.inc.php | 11 +- .../UTF-8/lang_de.inc.php | 22 +- .../UTF-8/lang_es.inc.php | 8 +- .../UTF-8/lang_fr.inc.php | 8 +- .../UTF-8/lang_ja.inc.php | 8 +- .../UTF-8/lang_ko.inc.php | 8 +- .../UTF-8/lang_pl.inc.php | 8 +- .../UTF-8/lang_pt_PT.inc.php | 8 +- .../UTF-8/lang_ru.inc.php | 8 +- .../UTF-8/lang_tn.inc.php | 8 +- .../UTF-8/lang_zh.inc.php | 97 +- .../serendipity_event_karma/lang_cn.inc.php | 8 +- .../serendipity_event_karma/lang_cs.inc.php | 8 +- .../serendipity_event_karma/lang_cz.inc.php | 8 +- .../serendipity_event_karma/lang_de.inc.php | 21 +- .../serendipity_event_karma/lang_en.inc.php | 88 +- .../serendipity_event_karma/lang_zh.inc.php | 8 +- .../serendipity_event_karma.php | 1247 +++++++++++++++-- 19 files changed, 1315 insertions(+), 272 deletions(-) diff --git a/plugins/serendipity_event_karma/ChangeLog b/plugins/serendipity_event_karma/ChangeLog index 5dcf9145..136462f8 100644 --- a/plugins/serendipity_event_karma/ChangeLog +++ b/plugins/serendipity_event_karma/ChangeLog @@ -1,5 +1,10 @@ # $Id: ChangeLog,v 1.27 2007/10/25 13:56:39 brockhaus Exp $ +------------------------------------------------------------------------ +Version 2.0 (gregman): + + * Included new option to change to animated voting based on images. + ------------------------------------------------------------------------ Version 1.4 (brockhaus): diff --git a/plugins/serendipity_event_karma/UTF-8/lang_bg.inc.php b/plugins/serendipity_event_karma/UTF-8/lang_bg.inc.php index c961067e..4fa82616 100644 --- a/plugins/serendipity_event_karma/UTF-8/lang_bg.inc.php +++ b/plugins/serendipity_event_karma/UTF-8/lang_bg.inc.php @@ -10,11 +10,11 @@ @define('PLUGIN_KARMA_BLAHBLAH', 'Дава възможност посетителите да оценяват качеството на вашите статии'); @define('PLUGIN_KARMA_VOTETEXT', 'Карма за тази статия: '); @define('PLUGIN_KARMA_RATE', 'Оецнете тази статия: %s'); -@define('PLUGIN_KARMA_VOTEPOINT_1', 'Много добра!'); -@define('PLUGIN_KARMA_VOTEPOINT_2', 'Добра'); +@define('PLUGIN_KARMA_VOTEPOINT_5', 'Много добра!'); +@define('PLUGIN_KARMA_VOTEPOINT_4', 'Добра'); @define('PLUGIN_KARMA_VOTEPOINT_3', 'Неутрална'); -@define('PLUGIN_KARMA_VOTEPOINT_4', 'Безинтересна'); -@define('PLUGIN_KARMA_VOTEPOINT_5', 'Лоша'); +@define('PLUGIN_KARMA_VOTEPOINT_2', 'Безинтересна'); +@define('PLUGIN_KARMA_VOTEPOINT_1', 'Лоша'); @define('PLUGIN_KARMA_VOTED', 'Вашата оценка "%s" беше записана.'); @define('PLUGIN_KARMA_INVALID', 'Вашето гласуване е невалидно.'); @define('PLUGIN_KARMA_ALREADYVOTED', 'Вашата оецнка вече е записана.'); @@ -48,6 +48,3 @@ @define('PLUGIN_KARMA_STATISTICS_POINTS_NO', 'точки'); @define('PLUGIN_KARMA_STARRATING', 'Разрешаване на индивидуална оценка на тази статия?'); - -@define('PLUGIN_KARMA_VISITS_LOGGEDIN_USERS', 'Следене на визитите на регистрираните посетители?'); -@define('PLUGIN_KARMA_VISITS_LOGGEDIN_USERS_BLAHBLAH', 'При избор \'Да\', посещенията на регистрираните посетители (потребители) ще бъдат броени.'); diff --git a/plugins/serendipity_event_karma/UTF-8/lang_de.inc.php b/plugins/serendipity_event_karma/UTF-8/lang_de.inc.php index 24674278..25594995 100644 --- a/plugins/serendipity_event_karma/UTF-8/lang_de.inc.php +++ b/plugins/serendipity_event_karma/UTF-8/lang_de.inc.php @@ -1,26 +1,31 @@ # +# http://www.jannis.to/programming/serendipity.html # +# # +# Translated by # +# (c) 2006 Aphonex Li # +# http://www.exten.cn # +########################################################################## -@define('PLUGIN_KARMA_NAME', '文章打分'); -@define('PLUGIN_KARMA_BLAHBLAH', '允许访客通过打分的方式评价你的文章质量'); -@define('PLUGIN_KARMA_VOTETEXT', '对此文章进行打分: '); -@define('PLUGIN_KARMA_RATE', '对此文章的打分: %s'); -@define('PLUGIN_KARMA_VOTEPOINT_1', '非常好'); -@define('PLUGIN_KARMA_VOTEPOINT_2', '还不错'); -@define('PLUGIN_KARMA_VOTEPOINT_3', '一般般'); -@define('PLUGIN_KARMA_VOTEPOINT_4', '没兴趣'); -@define('PLUGIN_KARMA_VOTEPOINT_5', '挺糟糕'); -@define('PLUGIN_KARMA_VOTED', '你打的分“ %s ”已被保存。'); -@define('PLUGIN_KARMA_INVALID', '你的打分无效。'); -@define('PLUGIN_KARMA_ALREADYVOTED', '你已经打过分了。'); -@define('PLUGIN_KARMA_NOCOOKIE', '你的浏览器必须支持cookies才能对文章进行打分。'); -@define('PLUGIN_KARMA_CLOSED', '请对 %s 天内更新的文章进行打分'); -@define('PLUGIN_KARMA_ENTRYTIME', '文章发表后允许访客打分的时间'); -@define('PLUGIN_KARMA_VOTINGTIME', '打分的时间间隔'); -@define('PLUGIN_KARMA_ENTRYTIME_BLAHBLAH', '文章发布多长时间(按分钟计算)以后就允许无限制的打分? 默认: 1440 (一天)'); -@define('PLUGIN_KARMA_VOTINGTIME_BLAHBLAH', '每次打分后要间隔多长时间(按分钟计算)以后才能进行下次打分?此设置仅对上述设置“文章发表后允许访客打分的时间”所设置的时间到期后的文章有效。默认: 5'); -@define('PLUGIN_KARMA_TIMEOUT', '灌水保护:其它访客刚刚提交了打分,请等待 %s 分钟后再提交你的打分。'); -@define('PLUGIN_KARMA_CURRENT', '当前分数: %2$s 。 %3$s 次打分。'); -@define('PLUGIN_KARMA_EXTENDEDONLY', '仅限于文章的扩展内容'); -@define('PLUGIN_KARMA_EXTENDEDONLY_BLAHBLAH', '仅在文章的扩展内容浏览中打分工具'); -@define('PLUGIN_KARMA_MAXKARMA', '允许打分的时限'); -@define('PLUGIN_KARMA_MAXKARMA_BLAHBLAH', '只允许对 X 天更新的文章进行打分 (默认:7)'); -@define('PLUGIN_KARMA_LOGGING', '记录打分信息'); -@define('PLUGIN_KARMA_LOGGING_BLAHBLAH', '是否要记录打分信息?'); -@define('PLUGIN_KARMA_ACTIVE', '允许打分'); -@define('PLUGIN_KARMA_ACTIVE_BLAHBLAH', '允许对文章打分吗?'); -@define('PLUGIN_KARMA_VISITS', '是否跟踪记录访问信息?'); -@define('PLUGIN_KARMA_VISITS_BLAHBLAH', '是否把对扩展内容的访问也计算在内并显示出来呢?'); -@define('PLUGIN_KARMA_VISITSCOUNT', ' %4$s 次点击'); -@define('PLUGIN_KARMA_STATISTICS_VISITS_TOP', '访问次数最多的文章'); -@define('PLUGIN_KARMA_STATISTICS_VISITS_BOTTOM', '访问次数最少的文章'); -@define('PLUGIN_KARMA_STATISTICS_VOTES_TOP', '总分最高的文章'); -@define('PLUGIN_KARMA_STATISTICS_VOTES_BOTTOM', '总分最低的文章'); -@define('PLUGIN_KARMA_STATISTICS_POINTS_TOP', '均分最高的文章'); -@define('PLUGIN_KARMA_STATISTICS_POINTS_BOTTOM', '均分最低的文章'); -@define('PLUGIN_KARMA_STATISTICS_VISITS_NO', '访问'); -@define('PLUGIN_KARMA_STATISTICS_VOTES_NO', '次数'); -@define('PLUGIN_KARMA_STATISTICS_POINTS_NO', '分数'); -@define('PLUGIN_KARMA_STARRATING', '对这篇文章使用单独的打分方式吗?'); + @define('PLUGIN_KARMA_VERSION', '1.3'); + @define('PLUGIN_KARMA_NAME', '评价'); + @define('PLUGIN_KARMA_BLAHBLAH', '允许访客评论文章'); + @define('PLUGIN_KARMA_VOTETEXT', '评价值: '); + @define('PLUGIN_KARMA_RATE', '评价值: %s'); + @define('PLUGIN_KARMA_VOTEPOINT_5', '很好'); + @define('PLUGIN_KARMA_VOTEPOINT_4', '好'); + @define('PLUGIN_KARMA_VOTEPOINT_3', '没意见'); + @define('PLUGIN_KARMA_VOTEPOINT_2', '没意见'); + @define('PLUGIN_KARMA_VOTEPOINT_1', '不好'); + @define('PLUGIN_KARMA_VOTED', '你的评价 "%s" 已送出。'); + @define('PLUGIN_KARMA_INVALID', '你的评价错误。'); + @define('PLUGIN_KARMA_ALREADYVOTED', '你已经提交评价。'); + @define('PLUGIN_KARMA_NOCOOKIE', '你的浏览器必须支持 cookies 才能进行评价。'); + @define('PLUGIN_KARMA_CLOSED', '请评价 %s 天内的文章'); + @define('PLUGIN_KARMA_ENTRYTIME', '公开文章后可以评价的时间'); + @define('PLUGIN_KARMA_VOTINGTIME', '评价时间'); + @define('PLUGIN_KARMA_ENTRYTIME_BLAHBLAH', '公开文章后多久 (分钟) 可允许无限制的评价?预设:1440 (一天)'); + @define('PLUGIN_KARMA_VOTINGTIME_BLAHBLAH', '要等多久 (分钟) 才能进行下一个评价?必须等输入的时候后才生效。预设:5'); + @define('PLUGIN_KARMA_TIMEOUT', '灌水保护:其它访客刚提交评价,请稍等 %s 分钟在提交您的评价。'); + @define('PLUGIN_KARMA_CURRENT', '评价值: %2$s, %3$s 次评价'); + @define('PLUGIN_KARMA_EXTENDEDONLY', '显示文章的副内容'); + @define('PLUGIN_KARMA_EXTENDEDONLY_BLAHBLAH', '只在文章的副内容显示评价'); + @define('PLUGIN_KARMA_MAXKARMA', '评价天数'); + @define('PLUGIN_KARMA_MAXKARMA_BLAHBLAH', '只允许小于 X 天的文章进行评价 (预设:7)'); + @define('PLUGIN_KARMA_LOGGING', '记录评价'); + @define('PLUGIN_KARMA_LOGGING_BLAHBLAH', '要记录评价值吗?'); + @define('PLUGIN_KARMA_ACTIVE', '允许评价'); + @define('PLUGIN_KARMA_ACTIVE_BLAHBLAH', '允许文章评价吗?'); + @define('PLUGIN_KARMA_VISITS', '记录访问次数?'); + @define('PLUGIN_KARMA_VISITS_BLAHBLAH', '要记录和显示访客浏览副文章的次数吗?'); + @define('PLUGIN_KARMA_VISITSCOUNT', ' %4$s 次浏览'); + @define('PLUGIN_KARMA_STATISTICS_VISITS_TOP', '浏览最多的文章'); + @define('PLUGIN_KARMA_STATISTICS_VISITS_BOTTOM', '浏览最少的文章'); + @define('PLUGIN_KARMA_STATISTICS_VOTES_TOP', '最多评价值的文章'); + @define('PLUGIN_KARMA_STATISTICS_VOTES_BOTTOM', '最少评价值的文章'); + @define('PLUGIN_KARMA_STATISTICS_POINTS_TOP', '最多评价值的文章'); + @define('PLUGIN_KARMA_STATISTICS_POINTS_BOTTOM', '最少评价值的文章'); + @define('PLUGIN_KARMA_STATISTICS_VISITS_NO', '浏览'); + @define('PLUGIN_KARMA_STATISTICS_VOTES_NO', '评价'); + @define('PLUGIN_KARMA_STATISTICS_POINTS_NO', '评价值'); +?> diff --git a/plugins/serendipity_event_karma/lang_cn.inc.php b/plugins/serendipity_event_karma/lang_cn.inc.php index 3a7694f4..0e3e1624 100644 --- a/plugins/serendipity_event_karma/lang_cn.inc.php +++ b/plugins/serendipity_event_karma/lang_cn.inc.php @@ -4,11 +4,11 @@ @define('PLUGIN_KARMA_BLAHBLAH', '允许访客通过打分的方式评价你的文章质量'); @define('PLUGIN_KARMA_VOTETEXT', '对此文章进行打分: '); @define('PLUGIN_KARMA_RATE', '对此文章的打分: %s'); -@define('PLUGIN_KARMA_VOTEPOINT_1', '非常好'); -@define('PLUGIN_KARMA_VOTEPOINT_2', '还不错'); +@define('PLUGIN_KARMA_VOTEPOINT_5', '非常好'); +@define('PLUGIN_KARMA_VOTEPOINT_4', '还不错'); @define('PLUGIN_KARMA_VOTEPOINT_3', '一般般'); -@define('PLUGIN_KARMA_VOTEPOINT_4', '没兴趣'); -@define('PLUGIN_KARMA_VOTEPOINT_5', '挺糟糕'); +@define('PLUGIN_KARMA_VOTEPOINT_2', '没兴趣'); +@define('PLUGIN_KARMA_VOTEPOINT_1', '挺糟糕'); @define('PLUGIN_KARMA_VOTED', '你打的分“ %s ”已被保存。'); @define('PLUGIN_KARMA_INVALID', '你的打分无效。'); @define('PLUGIN_KARMA_ALREADYVOTED', '你已经打过分了。'); diff --git a/plugins/serendipity_event_karma/lang_cs.inc.php b/plugins/serendipity_event_karma/lang_cs.inc.php index 0a63c085..77b7d1a7 100644 --- a/plugins/serendipity_event_karma/lang_cs.inc.php +++ b/plugins/serendipity_event_karma/lang_cs.inc.php @@ -10,11 +10,11 @@ @define('PLUGIN_KARMA_BLAHBLAH', 'teni hodnot kvalitu Vaich pspvk'); @define('PLUGIN_KARMA_VOTETEXT', 'Karma tohoto lnku: '); @define('PLUGIN_KARMA_RATE', 'Ohodno tento lnek: %s'); -@define('PLUGIN_KARMA_VOTEPOINT_1', 'Dost dobr!'); -@define('PLUGIN_KARMA_VOTEPOINT_2', 'Dobr'); +@define('PLUGIN_KARMA_VOTEPOINT_5', 'Dost dobr!'); +@define('PLUGIN_KARMA_VOTEPOINT_4', 'Dobr'); @define('PLUGIN_KARMA_VOTEPOINT_3', 'Prmer'); -@define('PLUGIN_KARMA_VOTEPOINT_4', 'Nezajmav'); -@define('PLUGIN_KARMA_VOTEPOINT_5', 'Mizern'); +@define('PLUGIN_KARMA_VOTEPOINT_2', 'Nezajmav'); +@define('PLUGIN_KARMA_VOTEPOINT_1', 'Mizern'); @define('PLUGIN_KARMA_VOTED', 'Vye hodnocen "%s" bylo zaznamenno.'); @define('PLUGIN_KARMA_INVALID', 'Vae hlasovn je neplatn.'); @define('PLUGIN_KARMA_ALREADYVOTED', 'Ji jste hlasoval.'); diff --git a/plugins/serendipity_event_karma/lang_cz.inc.php b/plugins/serendipity_event_karma/lang_cz.inc.php index cad35266..335fb699 100644 --- a/plugins/serendipity_event_karma/lang_cz.inc.php +++ b/plugins/serendipity_event_karma/lang_cz.inc.php @@ -10,11 +10,11 @@ @define('PLUGIN_KARMA_BLAHBLAH', 'teni hodnot kvalitu Vaich pspvk'); @define('PLUGIN_KARMA_VOTETEXT', 'Karma tohoto lnku: '); @define('PLUGIN_KARMA_RATE', 'Ohodno tento lnek: %s'); -@define('PLUGIN_KARMA_VOTEPOINT_1', 'Dost dobr!'); -@define('PLUGIN_KARMA_VOTEPOINT_2', 'Dobr'); +@define('PLUGIN_KARMA_VOTEPOINT_5', 'Dost dobr!'); +@define('PLUGIN_KARMA_VOTEPOINT_4', 'Dobr'); @define('PLUGIN_KARMA_VOTEPOINT_3', 'Prmer'); -@define('PLUGIN_KARMA_VOTEPOINT_4', 'Nezajmav'); -@define('PLUGIN_KARMA_VOTEPOINT_5', 'Mizern'); +@define('PLUGIN_KARMA_VOTEPOINT_2', 'Nezajmav'); +@define('PLUGIN_KARMA_VOTEPOINT_1', 'Mizern'); @define('PLUGIN_KARMA_VOTED', 'Vye hodnocen "%s" bylo zaznamenno.'); @define('PLUGIN_KARMA_INVALID', 'Vae hlasovn je neplatn.'); @define('PLUGIN_KARMA_ALREADYVOTED', 'Ji jste hlasoval.'); diff --git a/plugins/serendipity_event_karma/lang_de.inc.php b/plugins/serendipity_event_karma/lang_de.inc.php index ace88647..4f40e0ec 100644 --- a/plugins/serendipity_event_karma/lang_de.inc.php +++ b/plugins/serendipity_event_karma/lang_de.inc.php @@ -1,26 +1,31 @@ add('name', PLUGIN_KARMA_NAME); $propbag->add('description', PLUGIN_KARMA_BLAHBLAH); $propbag->add('stackable', false); - $propbag->add('author', 'Garvin Hicking','Grischa Brockhaus'); - $propbag->add('version', '1.9'); + $propbag->add('author', 'Garvin Hicking, Grischa Brockhaus, Gregor Vltz, Judebert'); + $propbag->add('version', '2.0'); $propbag->add('requirements', array( 'serendipity' => '0.8', 'smarty' => '2.6.7', 'php' => '4.1.0' )); - $propbag->add('event_hooks', array('frontend_configure' => true, 'entry_display' => true, 'css' => true, 'event_additional_statistics' => true)); + $propbag->add('event_hooks', array( + 'frontend_configure' => true, + 'entry_display' => true, + 'css' => true, + 'backend_header' => true, + 'event_additional_statistics' => true + )); $propbag->add('groups', array('STATISTICS')); - $propbag->add('configuration', array('karma_active', 'visits_active', 'track_visits_of_loggedin_users', 'exits_active', 'max_entrytime', 'max_votetime', 'extended_only', 'max_karmatime', 'logging')); + $propbag->add('configuration', array( + // Functionality options + 'options_tab', + 'karma_active', + 'extended_only', + 'max_karmatime', + 'max_votetime', + 'max_entrytime', + 'min_disp_votes', + 'visits_active', + 'track_visits_of_loggedin_users', + 'min_disp_visits', + 'exits_active', + 'logging', + // Appearance options + 'appearance_tab', + //--JAM:'alignment', + 'rate_with_words', + 'textual_msg', + 'textual_current', + 'textual_visits', + 'preview_bg', + 'base_image', + // Text/Language optins + 'text_tab', + 'rate_msg', + 'curr_msg', + 'rate_best', + 'rate_good', + 'rate_okay', + 'rate_poor', + 'rate_vile', + 'text_best', + 'text_good', + 'text_okay', + 'text_poor', + 'text_vile', + // Close divs + 'end_tabs', + )); } function introspect_config_item($name, &$propbag) { switch($name) { + // Top of tab bar + case 'options_tab': + $propbag->add('type', 'content'); + $propbag->add('default', ' + +' . PLUGIN_KARMA_TAB_OPTIONS . ' | +' . PLUGIN_KARMA_TAB_APPEARANCE . ' | +' . PLUGIN_KARMA_TAB_TEXT . ' + +
+' . PLUGIN_KARMA_TAB_OPTIONS . '
+'); + break; + case 'appearance_tab': + $propbag->add('type', 'content'); + $propbag->add('default', ' + +
+
+' . PLUGIN_KARMA_TAB_APPEARANCE . '
+'); + break; + case 'text_tab': + $propbag->add('type', 'content'); + $propbag->add('default', ' + +
+
+' . PLUGIN_KARMA_TAB_TEXT . '
+'); + break; + case 'end_tabs': + $propbag->add('type', 'content'); + $propbag->add('default', ' +
+'); + break; + // Oldest entry age still valid for unrestricted voting case 'max_entrytime': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_KARMA_ENTRYTIME); @@ -52,6 +158,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 1440); break; + // Min time between votes case 'max_votetime': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_KARMA_VOTINGTIME); @@ -59,6 +166,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 5); break; + // Oldest entry age still valid for karma voting (normal, restricted voting) case 'max_karmatime': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_KARMA_MAXKARMA); @@ -66,6 +174,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 7); break; + // Is karma voting allowed? case 'karma_active': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_KARMA_ACTIVE); @@ -73,6 +182,15 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'true'); break; + // Min votes to display + case 'min_disp_votes': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_MIN_DISPLAYABLE_VOTES); + $propbag->add('description', PLUGIN_KARMA_MIN_DISPLAYABLE_VOTES_BLAHBLAH); + $propbag->add('default', '0'); + break; + + // Is extended article visit tracking allowed? case 'visits_active': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_KARMA_VISITS); @@ -80,6 +198,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'true'); break; + // Keep or ignore visits for logged in users (like admins/authors)? case 'track_visits_of_loggedin_users': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_KARMA_VISITS_LOGGEDIN_USERS); @@ -87,6 +206,15 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'true'); break; + // Min visits to display + case 'min_disp_visits': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_MIN_DISPLAYABLE_VISITS); + $propbag->add('description', PLUGIN_KARMA_MIN_DISPLAYABLE_VISITS_BLAHBLAH); + $propbag->add('default', '0'); + break; + + // Are we tracking exits? case 'exits_active': $propbag->add('type', 'boolean'); $propbag->add('name', SHOWS_TOP_EXIT); @@ -94,6 +222,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'false'); break; + // Show karma voting on article summary, or only extended page? case 'extended_only': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_KARMA_EXTENDEDONLY); @@ -101,6 +230,7 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'false'); break; + // Log karma votes? case 'logging': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_KARMA_LOGGING); @@ -108,16 +238,144 @@ class serendipity_event_karma extends serendipity_event $propbag->add('default', 'false'); break; + /*--JAM: + // Alignment to use for rating bars + case 'alignment': + $select = array( + //--JAM: 'detect' => PLUGIN_KARMA_ALIGNMENT_DETECT, + 'left' => LEFT, + 'center' => CENTER, + 'right' => RIGHT); + $propbag->add('type', 'select'); + $propbag->add('name', PLUGIN_KARMA_ALIGNMENT); + $propbag->add('description', PLUGIN_KARMA_ALIGNMENT_BLAHBLAH); + $propbag->add('select_values', $select); + $propbag->add('default', 'right'); + break; + */ + // Use words for ratings? + case 'rate_with_words': + $propbag->add('type', 'boolean'); + $propbag->add('name', PLUGIN_KARMA_WORDRATING); + $propbag->add('description', PLUGIN_KARMA_WORDRATING_BLAHBLAH); + $propbag->add('default', 'false'); + break; + case 'textual_msg': + $propbag->add('type', 'boolean'); + $propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_MESSAGE); + $propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_MESSAGE_BLAHBLAH); + $propbag->add('default', 'true'); + break; + case 'textual_current': + $propbag->add('type', 'boolean'); + $propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_CURR); + $propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_CURR_BLAHBLAH); + $propbag->add('default', 'true'); + break; + case 'textual_visits': + $propbag->add('type', 'boolean'); + $propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_VISITS); + $propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_VISITS_BLAHBLAH); + $propbag->add('default', 'true'); + break; + // Background of admin preview table + case 'preview_bg': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_PREVIEW_BG); + $propbag->add('description', PLUGIN_KARMA_PREVIEW_BG_BLAHBLAH); + $propbag->add('default', ''); + break; + // Image to use for graphical rating bar + case 'base_image': + $propbag->add('type', 'content'); + $propbag->add('default', $this->createRatingSelector()); + break; + case 'rate_msg': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_NAME_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT); + break; + case 'curr_msg': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_CURRENT_NAME); + $propbag->add('description', PLUGIN_KARMA_CURRENT_NAME_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_CURRENT); + break; + case 'rate_best': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTEPOINT_5_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTEPOINT_5_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTEPOINT_5); + break; + case 'rate_good': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTEPOINT_4_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTEPOINT_4_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTEPOINT_4); + break; + case 'rate_okay': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTEPOINT_3_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTEPOINT_3_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTEPOINT_3); + break; + case 'rate_poor': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTEPOINT_2_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTEPOINT_2_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTEPOINT_2); + break; + case 'rate_vile': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTEPOINT_1_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTEPOINT_1_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTEPOINT_1); + break; + case 'text_best': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_5_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_5_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT_5); + break; + case 'text_good': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_4_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_4_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT_4); + break; + case 'text_okay': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_3_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_3_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT_3); + break; + case 'text_poor': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_2_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_2_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT_2); + break; + case 'text_vile': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_KARMA_VOTETEXT_1_NAME); + $propbag->add('description', PLUGIN_KARMA_VOTETEXT_1_BLAHBLAH); + $propbag->add('default', PLUGIN_KARMA_VOTETEXT_1); + break; + default: return false; } return true; } + /** + * Updates database schema when upgrading from older versions. + */ function checkScheme() { global $serendipity; - $version = $this->get_config('version', '0.9'); + $version = $this->get_config('version', '0.9'); if ($version == '1.1') { $q = "ALTER TABLE {$serendipity['dbPrefix']}karma ADD visits INT(11) default 0"; @@ -166,11 +424,24 @@ class serendipity_event_karma extends serendipity_event return true; } + /** + * Unused; would create sidebar content. + */ function generate_content(&$title) { $title = $this->title; } + /** + * Creates an array of entries and their exit counts. + * + * @param array entries The entries to get exit counts for + * @param boolean get optional Whether to return the array (otherwise + * does all the calculations, but returns only true) default:false + * + * @return Boolean true when $get is false; otherwise the array of + * entries with their exit counts. + */ function prepareExits($entries, $get = false) { static $exits = null; global $serendipity; @@ -220,65 +491,83 @@ class serendipity_event_karma extends serendipity_event function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; + $hooks = &$bag->get('event_hooks'); if (isset($hooks[$event])) { + + // Moved from above: only get image data if we're actually going to do something + $this->set_valid_image_data(); + // Get dimensions of image, only if not text-only + if ($this->image_name) { + // Is this a single-image bar, or a single segment? + $ratio = $this->image_width / $this->image_height; + if ($ratio < $max_segment_ratio) { + // This is probably a single segment. Square segments + // will have a ratio of 0.3; long, flat segments won't + // get up to 1.0 unless they're 3 times as wide as they + // are tall; full-bar images with square segments will + // be 1.666; and full-bar images with tall, narrow + // segments will be greater than 1.0 unless they're + // nearly twice as high as they are wide. + $this->image_width = $this->image_width * 5; + } + } + switch($event) { + // Early hook, before any page is displayed case 'frontend_configure': + + // Make sure the karmaVote cookie is set, even if empty if (!isset($serendipity['COOKIE']['karmaVote'])) { serendipity_setCookie('karmaVote', serialize(array())); } - if (isset($serendipity['GET']['id'])) { - $entryid = (int)serendipity_db_escape_string($serendipity['GET']['id']); - } elseif (preg_match(PAT_COMMENTSUB, $_SERVER['REQUEST_URI'], $matches)) { - $entryid = (int)$matches[1]; - } else { - $entryid = false; - } - - if ($entryid && empty($serendipity['GET']['adminAction'])) { - $track_clicks = serendipity_db_bool($this->get_config('visits_active', true)) && $this->track_clicks_allowed_by_user(); - if ($track_clicks) { - $sql = serendipity_db_query('UPDATE ' . $serendipity['dbPrefix'] . 'karma SET visits = visits + 1 WHERE entryid = ' . $entryid, true); - if (serendipity_db_affected_rows() < 1) { - serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}karma (entryid, points, votes, lastvote, visits) VALUES ('$entryid', 0, 0, 0, 1)"); - } - } - } - + // If user didn't vote, we're done. if (!isset($serendipity['GET']['karmaId']) || !isset($serendipity['GET']['karmaVote'])) { return; } + // Get URL vote data $this->karmaId = (int)$serendipity['GET']['karmaId']; $this->karmaVoting = (int)$serendipity['GET']['karmaVote']; - if (!isset($serendipity['COOKIE']['karmaVote'])) { + // karmaVote cookie was just set (see name="#1"); this boils down to + // "if check cookie isn't 1, there's no real cookie". + // The check cookie gets set when a rater is displayed, + // so you've got no business voting if you haven't even + // seen the rater yet. + if (!isset($serendipity['COOKIE']['karmaVote']) OR $serendipity['COOKIE']['check'] != '1') { $this->karmaVote = 'nocookie'; return; } + // Everything is ready. Get the cookie vote data. $karma = unserialize($serendipity['COOKIE']['karmaVote']); + // Stop on invalid votes (cookie invalid, or URL data incorrect) if (!is_array($karma) || !is_numeric($this->karmaVoting) || !is_numeric($this->karmaId) || $this->karmaVoting > 2 || $this->karmaVoting < -2) { $this->karmaVote = 'invalid1'; return; } + // Stop if the cookie says we already voted if (!empty($karma[$this->karmaId])) { $this->karmaVote = 'alreadyvoted'; return ; } + // We don't want googlebots hitting the karma-voting if (stristr($_SERVER['HTTP_USER_AGENT'], 'google')) { - // We don't want googlebots hitting the karma-voting $this->karmaVote = 'invalid1'; return ; } // Voting takes place here. + // + // Get voting data from the database (keeps all entries, + // even if no karma match) $q = 'SELECT * FROM ' . $serendipity['dbPrefix'] . 'entries AS e LEFT OUTER JOIN ' . $serendipity['dbPrefix'] . 'karma AS k @@ -286,6 +575,9 @@ class serendipity_event_karma extends serendipity_event WHERE e.id = ' . serendipity_db_escape_string($this->karmaId) . ' LIMIT 1'; $row = serendipity_db_query($q, true); + // If there's no entry with this ID, we're done + // + // --TODO: Modify the plugin to allow arbitrary voting with generated IDs if (!isset($row) || !is_array($row)) { $this->karmaVote = 'invalid2'; return; @@ -297,12 +589,20 @@ class serendipity_event_karma extends serendipity_event $max_entrytime = $this->get_config('max_entrytime', 1440) * 60; $max_votetime = $this->get_config('max_votetime', 5) * 60; $max_karmatime = $this->get_config('max_karmatime', 7) * 24 * 60 * 60; + // Allow infinite voting when 0 or negative + if ($max_karmatime <= 0) { + $max_karmatime = $now; + } + // If the entry's timestamp is too old for voting, + // we're done. if ($row['timestamp'] < ($now - $max_karmatime)) { $this->karmaVote = 'timeout2'; return; } + // If the entry is in the grace period, or votes + // aren't too close together, record the vote. if (($row['timestamp'] > ($now - $max_entrytime)) || ($row['lastvote'] + $max_votetime < $now) || $row['lastvote'] == 0) { // Update votes $q = sprintf( @@ -319,25 +619,29 @@ class serendipity_event_karma extends serendipity_event serendipity_db_query($q); } else { + // Entry was too recently voted upon. Figure out + // how long until voting will be allowed (in minutes). $this->karmaVote = 'timeout'; - $this->karmaTimeOut = abs(round(($now - ($row['lastvote'] + $max_votetime)) / 60, 1)); + $this->karmaTimeOut = abs(ceil(($now - ($row['lastvote'] + $max_votetime)) / 60)); return; } } else { - // No Votes. Just insert it. + // No row. Use INSERT instead of UPDATE. $q = sprintf( "INSERT INTO {$serendipity['dbPrefix']}karma - (entryid, points, votes, lastvote) - VALUES (%s, %s, %s, %s)", + (entryid, points, votes, lastvote, visits) + VALUES (%s, %s, %s, %s, %s)", $this->karmaId, $this->karmaVoting, 1, - $now + $now, + 0 ); $sql = serendipity_db_query($q); } + // Log the vote if (serendipity_db_bool($this->get_config('logging', false))) { $q = sprintf( "INSERT INTO {$serendipity['dbPrefix']}karmalog @@ -355,6 +659,7 @@ class serendipity_event_karma extends serendipity_event } } + // Set the cookie that we already voted for this entry $karma[$this->karmaId] = $this->karmaVoting; $this->karmaVote = 'voted'; serendipity_setCookie('karmaVote', serialize($karma)); @@ -362,21 +667,127 @@ class serendipity_event_karma extends serendipity_event return true; break; - case 'css': - if (strpos($eventData, '.serendipity_karmaVoting')) { - // class exists in CSS, so a user has customized it and we don't need default - return true; - } -?> + // CSS generation hooks + case 'backend_header': + // Generate the CSS for the graphical rating bar selector + // + // The CSS appears to be generated in a completely + // different instance of Serendipity, as if index.php gets + // called separately for the CSS. + // + // Note that the css_backend hook adds properties to the + // serendipity_admin.css, but that file is *always* + // cached. We use backend_header and add the CSS to the + // HEAD styles to make it dynamic. + + // Get the CSS, set $this->image_name so we'll output the + // standard graphical CSS prologue if any images are found. + $this->createRatingSelector(); + print ("\n"); + } return true; break; + //--TODO: Comment the functionality of this event hook. case 'event_additional_statistics': $sql = array(); $sql['visits_top'] = array('visits', 'DESC'); @@ -441,43 +949,80 @@ class serendipity_event_karma extends serendipity_event return true; break; + // Add voting information to entries case 'entry_display': + // Update database if necessary if ($this->get_config('version') != PLUGIN_KARMA_VERSION) { $this->checkScheme(); } + + // Find the ID of this entry + if (isset($serendipity['GET']['id'])) { + $entryid = (int)serendipity_db_escape_string($serendipity['GET']['id']); + } elseif (preg_match(PAT_COMMENTSUB, $_SERVER['REQUEST_URI'], $matches)) { + $entryid = (int)$matches[1]; + } else { + $entryid = false; + } - // Check whether the cache plugin is used. If so, we need to append our karma-voting output - // to the cached version, since that one is used instead of the 'extended' key later on. - $extended_key = &$this->getFieldReference('add_footer', $eventData); + // If we're actually reading the entry, not voting or editing it... + if ($entryid && empty($serendipity['GET']['adminAction']) && !$serendipity['GET']['karmaVote']) { + // Update the number of visits + // Are we supposed to track visits? + $track_clicks = serendipity_db_bool($this->get_config('visits_active', true)) && $this->track_clicks_allowed_by_user(); + if ($track_clicks) { + $sql = serendipity_db_query( + "UPDATE {$serendipity['dbPrefix']}karma + SET visits = visits + 1 + WHERE entryid = $entryid", + true); + if (serendipity_db_affected_rows() < 1) { + serendipity_db_query( + "INSERT INTO {$serendipity['dbPrefix']}karma (entryid, points, votes, lastvote, visits) + VALUES ('$entryid', 0, 0, 0, 1)" + ); + } + } + } + + // Set a cookie to look for later, verifying that cookies are enabled + serendipity_setCookie('check', '1'); switch($this->karmaVote) { case 'nocookie': // Users with no cookies won't be able to vote. $msg = '
' . PLUGIN_KARMA_NOCOOKIE . '
'; + // Continue until output case 'timeout2': if (!isset($msg)) { $msg = '
' . PLUGIN_KARMA_CLOSED . '
'; } + // Continue until output case 'timeout': if (!isset($msg)) { $msg = '
' . sprintf(PLUGIN_KARMA_TIMEOUT, $this->karmaTimeOut) . '
'; } + // Continue until output case 'alreadyvoted': if (!isset($msg)) { $msg = '
' . PLUGIN_KARMA_ALREADYVOTED . '
'; } + // Continue until output case 'invalid1': case 'invalid2': case 'invalid': + // Set message if (!isset($msg)) { $msg = '
' . PLUGIN_KARMA_INVALID . '
'; } + // Continue until output /* OUTPUT MESSAGE */ + //--TODO: Shouldn't this work with the cache plugin, too? if ($addData['extended']) { $eventData[0]['exflag'] = 1; $eventData[0]['add_footer'] .= $msg; @@ -494,130 +1039,179 @@ class serendipity_event_karma extends serendipity_event case 'voted': default: + // If there's no data, there's no need to go on + if (!is_array($eventData)) return; + + // Find out what the admin wants $track_clicks = serendipity_db_bool($this->get_config('visits_active', true)); $track_karma = serendipity_db_bool($this->get_config('karma_active', true)); $track_exits = serendipity_db_bool($this->get_config('exits_active', true)); - $karma_active = $track_karma; - - if (!is_array($eventData)) return; + // Get the limits + $now = time(); $karmatime = $this->get_config('max_karmatime', 7); $max_karmatime = $karmatime * 24 * 60 * 60; - $now = time(); - - $url = serendipity_currentURL() . '&'; - - $karma = (isset($serendipity['COOKIE']['karmaVote']) ? unserialize($serendipity['COOKIE']['karmaVote']) : array()); - - $link_1 = '++'; - $link_2 = '+'; - $link_3 = '0'; - $link_4 = '-'; - $link_5 = '--'; - - if ($addData['extended'] && $eventData[0]['timestamp'] < ($now - $max_karmatime)) { - $karma_active = false; + // Accept infinite voting + if ($max_karmatime <= 0) { + $max_karmatime = $now; } - $karma_voting = '

' - . ($karma_active ? '' . PLUGIN_KARMA_VOTETEXT . ' ' . $link_1 . ' | ' . $link_2 . ' | ' . $link_3 . ' | ' . $link_4 . ' | ' . $link_5 . '
' - . '' . PLUGIN_KARMA_CURRENT . '' : '') . ($track_clicks ? '' . PLUGIN_KARMA_VISITSCOUNT . '': '') . '
'; - - $karma_current = '

' - . ($karma_active ? '
' . PLUGIN_KARMA_VOTED . '
' - . '' . PLUGIN_KARMA_CURRENT . '' : '') . ($track_clicks ? '' . PLUGIN_KARMA_VISITSCOUNT . '': '') . '
'; - - $karma_timeout = '

' - . ($track_karma ? '
' . sprintf(PLUGIN_KARMA_CLOSED, $karmatime) . '
' - . '' . PLUGIN_KARMA_CURRENT . '' : '') . ($track_clicks ? '' . PLUGIN_KARMA_VISITSCOUNT . '': '') . '
'; + //--TODO: Ensure that this works with the Custom Permalinks plugin + // (We've seen trouble; it votes correctly, but redirects to the front page) + $url = serendipity_currentURL() . '&'; + //$uri = $_SERVER['REQUEST_URI']; + // Get the cookie data (past votes, etc) + $karma = (isset($serendipity['COOKIE']['karmaVote']) ? unserialize($serendipity['COOKIE']['karmaVote']) : array()); + // Get all required entry IDs, making keys match keys in eventData + $entries = array(); if ($addData['extended'] || $addData['preview']) { - $entryid = (int)serendipity_db_escape_string($eventData[0]['id']); - $q = 'SELECT SUM(votes) AS votes, SUM(points) AS points, SUM(visits) AS visits - FROM ' . $serendipity['dbPrefix'] . 'karma AS k - WHERE k.entryid = ' . $entryid . ' GROUP BY k.entryid LIMIT 1'; - $row = serendipity_db_query($q, true); + // We're in extended or preview mode, we only need the current ID + $eventData[0]['exflag'] = 1; + $entries[0] = (int)($eventData[0]['id']); + } elseif (!serendipity_db_bool($this->get_config('extended_only', false))) { + // We're in overview mode, and we want rating bars for all the entry IDs + foreach(array_keys($eventData) as $key) { + $entries[$key] = (int)$eventData[$key]['id']; + } + } - if (empty($row['votes'])) { - $row['votes'] = 0; + // Fetch votes for all entry IDs. Store them in an array for later usage. + $q = 'SELECT k.entryid, SUM(votes) AS votes, SUM(points) AS points, SUM(visits) AS visits + FROM ' . $serendipity['dbPrefix'] . 'karma AS k + WHERE k.entryid IN (' . implode(', ', $entries) . ') GROUP BY k.entryid'; + + $sql = serendipity_db_query($q); + + $rows = array(); + if ($sql && is_array($sql)) { + foreach($sql AS $row) { + $rows[$row['entryid']] = array( + 'votes' => $row['votes'], + 'points' => $row['points'], + 'visits' => $row['visits'] + ); + } + } + + $this->prepareExits($entries); + + // Add karma block to the footer of each entry + // + // The entries array was populated, above, so its keys match the eventData array, + // and overview entries are skipped if "extended only" is enabled + foreach (array_keys($entries) as $i) { + // Get the statistics + $entryid = $eventData[$i]['id']; + $votes = (!empty($rows[$entryid]['votes']) ? $rows[$entryid]['votes'] : 0); + $points = (!empty($rows[$entryid]['points']) ? $rows[$entryid]['points'] : 0); + $visits = (!empty($rows[$entryid]['visits']) ? $rows[$entryid]['visits'] : 0); + $enough_votes = $track_karma && ($votes >= $this->get_config('min_disp_votes', 0)); + $enough_visits = $track_clicks && ($visits >= $this->get_config('min_disp_visits', 0)); + $textual_msg = true; + $textual_current = true; + $textual_visits = true; + if ($this->image_name != '0') { + $textual_msg = $this->get_config('textual_msg', 'true'); + $textual_current = $this->get_config('textual_current', 'true'); + $textual_visits = $this->get_config('textual_visits', 'true'); } - if (empty($row['points'])) { - $row['points'] = 0; - } - - if (empty($row['visits'])) { - $row['visits'] = 0; + // Where's the footer? Normally it would be + // in addData['extended']; but if the cache + // plugin is used, it's elsewhere. This + // method retrieves it either way. + $footer = &$this->getFieldReference('add_footer', $eventData[$i]); + /*--JAM: Probably time to delete this + // Create a footer if one doesn't already exist + if (!isset($eventData[$i]['add_footer'])) { + $eventData[$i]['add_footer'] = ''; } + */ if ($track_exits) { - $extended_key .= $this->getExits($entryid); + $footer .= $this->getExits($entryid, true); } - $eventData[0]['exflag'] = 1; - if (isset($karma[$entryid])) { - $extended_key .= sprintf($karma_current, $karma[$entryid], $row['points'], $row['votes'], $row['visits'], $url); - } elseif ($eventData[0]['timestamp'] < ($now - $max_karmatime)) { - $extended_key .= sprintf($karma_timeout, $entryid, $row['points'], $row['votes'], $row['visits'], $url); - } else { - $extended_key .= sprintf($karma_voting, $entryid, $row['points'], $row['votes'], $row['visits'], $url); - } - } elseif (!serendipity_db_bool($this->get_config('extended_only', false))) { - $elements = count($eventData); - - // Get all existing entry IDs - $entries = array(); - for ($i = 0; $i < $elements; $i++) { - $entries[] = (int)$eventData[$i]['id']; - } - - // Fetch votes for all entry IDs. Store them in an array for later usage. - $q = 'SELECT k.entryid, SUM(votes) AS votes, SUM(points) AS points, SUM(visits) AS visits - FROM ' . $serendipity['dbPrefix'] . 'karma AS k - WHERE k.entryid IN (' . implode(', ', $entries) . ') GROUP BY k.entryid'; - - $sql = serendipity_db_query($q); - - $rows = array(); - if ($sql && is_array($sql)) { - foreach($sql AS $idx => $row) { - $rows[$row['entryid']] = array('votes' => $row['votes'], 'points' => $row['points'], 'visits' => $row['visits']); - } - } - - $this->prepareExits($entries); - - // Walk entry array and insert karma voting line. - for ($i = 0; $i < $elements; $i++) { - $entryid = $eventData[$i]['id']; - $votes = (!empty($rows[$entryid]['votes']) ? $rows[$entryid]['votes'] : 0); - $points = (!empty($rows[$entryid]['points']) ? $rows[$entryid]['points'] : 0); - $visits = (!empty($rows[$entryid]['visits']) ? $rows[$entryid]['visits'] : 0); - - if (!isset($eventData[$i]['add_footer'])) { - $eventData[$i]['add_footer'] = ''; - } - - if ($track_exits) { - $eventData[$i]['add_footer'] .= $this->getExits($entryid, true); - } - + // Pick the appropriate intro msg and rating bar + // No msg or bar if karma is disabled + if ($track_karma) { if (isset($karma[$entryid])) { - $eventData[$i]['add_footer'] .= sprintf($karma_current, $karma[$entryid], $points, $votes, $visits, $url); + // We already voted for this one + $msg = + '
' . PLUGIN_KARMA_VOTED . '
'; + $myvote = $karma[$entryid]; + if ($this->get_config('rate_with_words', false)) { + $myvote = $this->wordRating($myvote, 1); + } + elseif ($this->image_name != '0') { + $myvote = $this->imageRating($myvote, 1); + } + // Just a current rating bar, if any + $bar = $this->createRatingBar(null, $points, $votes); } elseif ($eventData[$i]['timestamp'] < ($now - $max_karmatime)) { - $eventData[$i]['add_footer'] .= sprintf($karma_timeout, $entryid, $points, $votes, $visits, $url); + // Too late to vote for this one + $msg = + '
' . sprintf(PLUGIN_KARMA_CLOSED, $karmatime) . '
'; + // Just a current rating bar, if any + $bar = $this->createRatingBar(null, $points, $votes); } else { - $eventData[$i]['add_footer'] .= sprintf($karma_voting, $entryid, $points, $votes, $visits, $url); + // We can vote for this; make the whole voting block + $rate_msg = $this->get_config('rate_msg', PLUGIN_KARMA_VOTETEXT); + $msg = + '
' . $rate_msg . '
'; + // Full voting bar + $bar = $this->createRatingBar($entryid, $points, $votes); } } - } - } + // Create the karma block + $image_class = ''; + if ($this->image_name != '0') { + $image_class = ' serendipity_karmaVoting_images'; + } + $karma_block = +"
"; + if ($textual_msg) { + $karma_block .= + $msg; + } + $karma_block .= + $bar; + if ($enough_votes && $textual_current) { + $curr_msg = $this->get_config('curr_msg', PLUGIN_KARMA_CURRENT); + $karma_block .= + '' . $curr_msg . ''; + } + if ($enough_visits && $textual_visits) { + $karma_block .= + '' . PLUGIN_KARMA_VISITSCOUNT . ''; + } + $karma_block .= +"\n
\n"; + // Adjust rating points + if ($this->get_config('rate_with_words', false)) { + $points = $this->wordRating($points, $votes); + } + elseif ($this->image_name != '0') { + $points = $this->imageRating($points, $votes); + } + + /* + print("

--DEBUG: Karma block code:

\n
\n");
+                                   print_r(htmlspecialchars($karma_block));
+                                   print("\n
\n"); + */ + + // Substitute the % stuff and add it to the footer + $footer .= sprintf($karma_block, $myvote, $points, $votes, $visits, $url); + } // foreach key in entries + }// End switch on karma voting status return true; break; default: return false; - } + }// End switch on event hooks } else { return false; } @@ -632,6 +1226,369 @@ class serendipity_event_karma extends serendipity_event } return true; } + + /** + * Creates an HTML snippet with images of all the available rating bars. + * + * @return string an HTML string including working images of all the rating bars in the img/ directory. + */ + function createRatingSelector() { + // Since the inputs are set up with the proper names, the config item + // gets saved automatically, with no need for magic + + // Get the filename to be automatically selected + $this->set_valid_image_data(); + $cursel = $this->image_name; + + $this->select_css = ''; + $this->select_html = ''; + // We will be wrapped in a + $this->select_html .= " +" . PLUGIN_KARMA_IMAGE . "
+ ".PLUGIN_KARMA_IMAGE_DESC." + + + + + +"; + // Add the 'text-only' selection and its CSS + if ($cursel == '0') { + $checked = 'checked="checked" '; + } else { + $checked = ''; + } + $this->image_name = '0'; + $bar = $this->createRatingBar('', 0, 0, 'textbar'); + $this->select_html .= " + +\n"; + $this->select_css .= " +.textbar, .textbar a, .textbar a:hover { + font-size: 100%; + position: relative; + background: none; +} +.serendipityAdminContent span.textbar { + color: black !important; +} +"; + // Retrieve all the *valid* images from the image directory + $files = $this->getImageFiles(); + // Add an
    for each rating bar, and add its CSS overrides + $n = 0; + foreach ($files as $fdata) { + // Columnize + if (($n % 3) == 0) { + // Time to start a new row + $this->select_html .= "
\n\n"; + } + + // Set the image data + $fname = $fdata['fname']; + $height = $fdata['height']; + $width = $fdata['width']; + $ratio = $width / $height; + // If this is a single segment, adjust width + if ($ratio < $max_segment_ratio) { + $width = $width * 5; + } + $height = $height / 3; + // Set up class variables correctly + $this->image_name = $fname; + $this->image_width = $width; + $this->image_height = $height; + + // Create a rating bar of this image + // + // What would be a good CSS class for this image? + $css_class = str_replace(array('.',' '), array('_','_'), $fname); + $checked = ''; + if ($fname == $cursel) { + $checked = 'checked="checked" '; + } + $bar_html = +"\n"; + $bar_html = sprintf($bar_html, '', '2.5 of 5', '1'); + $this->select_html .= $bar_html; + // Add the necessary CSS to the stylesheet (will be added when css hooks are called) + // Sorry to interrupt your regularly scheduled HTML; I need to + // use the $css_class while it's still here. + $this->select_css .= " +/* Overrides for $css_class */ +.$css_class +{ + width: ${width}px; + height: ${height}px; +} +.$css_class, +.$css_class a:hover, +.$css_class .serendipity_karmaVoting_current-rating +{ + background-image: url({$serendipity['baseURL']}plugins/serendipity_event_karma/img/${fname}); +} +.$css_class, +.$css_class a, +.$css_class .serendipity_karmaVoting_current-rating +{ + line-height: ${height}px; + height: ${height}px; } -/* vim: set sts=4 ts=4 expandtab : */ +"; + $n++; + } // Go back up for another image + + // Check for nothing displayed + if ($n == 0) { + // There were no images! + $this->select_html .= "\n"; + } + + // End the table, with a config-item bottom-border separator + $this->select_html .= +"\n
" . PLUGIN_KARMA_STATISTICS_POINTS_NO . "
$bar
+ + $fname
\n" . + $this->createRatingBar('', -1, 2, $css_class) . +"
" . PLUGIN_KARMA_NO_IMAGES . "
+ \n"; + // The config item and row are closed by the core code + + return $this->select_html; + } + + /** + * Retrieves all the images from the img/ directory + * + * @return array an array with 'fname', 'width', and 'height' entries for + * each valid image file in the img/ directory + */ + function getImageFiles() { + $path = dirname(__FILE__) . "/img"; + $images = array(); + $folder = opendir($path); + while (false !== ($filename = readdir($folder))) { + $parts = serendipity_parseFileName($filename); + $img_data = serendipity_getimagesize($path . '/' . $filename); + if (!isset($img_data['noimage'])) { + // Curly braces are just a different syntax of associative array assignment + $images{$filename} = array('fname'=>$filename, 'width'=>$img_data[0], 'height'=>$img_data[1]); + } + } + closedir($folder); + ksort($images); + return $images; + } + + /** + * Creates the HTML snippet for the currently defined rating bar, with + * appropriate links (and current rating indication for graphical bars). + * Automatically detects from $this->image_name whether to create text + * links or a graphical bar. + * + * @param string id optional The ID of the bar we're creating; an empty + * id ('' or 0) creates a bar with dummy links; null creates a bar with + * no voting links at all (shows only current configuration). + * @param int karma optional The current total karma (default: 0 points) + * @param int votes optional The total number of votes (default: 0 votes)) + * @param string extra_class optional Any additional CSS classes to be added to the bar container + */ + function createRatingBar($id = null, $karma = 0, $votes = 0, $extra_class = '') { + // Are there enough votes to display the current rating? + $enough_votes = ($votes >= $this->get_config('min_disp_votes', 0)); + // Do I need to create links? + if ($id !== null) { + // Create the rating tooltips and texts + $vilestr = $this->get_config('rate_vile', PLUGIN_KARMA_VOTEPOINT_1); + $poorstr = $this->get_config('rate_poor', PLUGIN_KARMA_VOTEPOINT_2); + $okaystr = $this->get_config('rate_okay', PLUGIN_KARMA_VOTEPOINT_3); + $goodstr = $this->get_config('rate_good', PLUGIN_KARMA_VOTEPOINT_4); + $beststr = $this->get_config('rate_best', PLUGIN_KARMA_VOTEPOINT_5); + $vile = sprintf(PLUGIN_KARMA_RATE, $vilestr); + $poor = sprintf(PLUGIN_KARMA_RATE, $poorstr); + $okay = sprintf(PLUGIN_KARMA_RATE, $okaystr); + $good = sprintf(PLUGIN_KARMA_RATE, $goodstr); + $best = sprintf(PLUGIN_KARMA_RATE, $beststr); + $vilestr = $this->get_config('text_vile', PLUGIN_KARMA_VOTETEXT_1); + $poorstr = $this->get_config('text_poor', PLUGIN_KARMA_VOTETEXT_2); + $okaystr = $this->get_config('text_okay', PLUGIN_KARMA_VOTETEXT_3); + $goodstr = $this->get_config('text_good', PLUGIN_KARMA_VOTETEXT_4); + $beststr = $this->get_config('text_best', PLUGIN_KARMA_VOTETEXT_5); + + if (empty($id)) { + // Create dummy links + $link_1 = +'' . $vilestr . ''; + $link_2 = +'' . $poorstr . ''; + $link_3 = +'' . $okaystr . ''; + $link_4 = +'' . $goodstr . ''; + $link_5 = +'' . $beststr . ''; + // There *are* enough votes for a dummy rating bar + $enough_votes = true; + } else { + // Create ordinary links + $link_1 = "$vilestr"; + $link_2 = "$poorstr"; + $link_3 = " $okaystr"; + $link_4 = "$goodstr"; + $link_5 = "$beststr"; + } + } + + // Normalize the CSS class + if (!empty($extra_class)) { + $extra_class = " $extra_class"; + } + + // Create the rating bar + if ($this->image_name == '0') { + // Text bar + // + if ($id === null) { + // No need for a "current rating" bar, like with graphics + $karma_display = ''; + } else { + // Show the links + $karma_display = " + $link_1 | $link_2 | $link_3 | $link_4 | $link_5
"; + } + } else { + // Graphic bar + // + + // No need to create a bar if there's nothing to display + if (($id !== null) || $enough_votes) { + // Start the bar + $karma_display = " +
    "; + // Only display the current rating if there are enough votes + if ($enough_votes) { + // Figure out the image-based rating and width + $rating = $this->imageRating($karma, $votes); + $cr_width = ($rating * $this->image_width) / 5; + // Get current karma text + $curr_msg = $this->get_config('curr_msg', PLUGIN_KARMA_CURRENT); + $karma_display .= " +
  1. + "; + } + // Only create voting links if required + if ($id !== null) { + $karma_display .= " +
  2. $link_1
  3. +
  4. $link_2
  5. +
  6. $link_3
  7. +
  8. $link_4
  9. +
  10. $link_5
  11. + "; + } + // Close the
      + $karma_display .= " +
    +"; + } + } + return $karma_display; + } + + /** + * Sets $this->image_name to the name of a valid image, or to '0' to + * indicate text-only rating bars should be used. + */ + function set_valid_image_data() { + $base_image = $this->get_config('base_image', false); + if ($base_image !== false) { + // Definitely configured + if ($base_image == '0') { + // Configured to text-only + $this->image_name = $base_image; + } else { + $imagesize = serendipity_getimagesize(dirname(__FILE__) . "/img/" . $base_image); + if ($imagesize['noimage']) { + // Leave as default + } else { + // Set to valid image name + $this->image_name = $base_image; + } + } + } + // Is the (possibly default) image valid? + if ($this->image_name) { + $imagesize = serendipity_getimagesize(dirname(__FILE__) . "/img/" . $this->image_name); + if ($imagesize['noimage']) { + // No valid image; use text-only + $this->image_name = '0'; + } else { + // Valid graphical image; set the dimensions, too + $this->image_width = $imagesize[0]; + $this->image_height = $imagesize[1]; + } + } + } + + /** + * Compute the equivalent graphical points rating for a karma rating. + * + * @param int points The total karma points + * @param int votes The total number of votes + * + * @return string A string indicating the number of points "of 5", + * or PLUGIN_KARMA_IMAGE_NONE_RATING if no votes have been recorded. + */ + function imageRating($points, $votes) { + if ($votes == 0) { + $rating = PLUGIN_KARMA_IMAGE_NONE_RATING; + } else { + // Find average karma (-2 to +2) + $rating = ((float)$points) / ((float)$votes); + // Remap into [1,5] + $rating = $rating + 3; + // Put it into the language-specific string format + if ($rating == (int)$rating) { + $rating = sprintf(PLUGIN_KARMA_IMAGE_INT_RATING, $rating); + } else { + $rating = sprintf(PLUGIN_KARMA_IMAGE_RATING, $rating); + } + } + return $rating; + } + + /* Compute the equivalent word rating for a karma rating. + * + * @param mixed points The total karma points + * @param mixed votes The total number of votes + * + * @return string A word corresponding to the article rating, + * or PLUGIN_KARMA_IMAGE_NONE_RATING if no votes have been recorded. + */ + function wordRating($points, $votes) { + if ($votes == 0) { + $rating = PLUGIN_KARMA_IMAGE_NONE_RATING; + } else { + // Find average karma (-2 to +2) + $rating = ((float)$points) / ((float)$votes); + // Put it into the language-specific string format, rounding up + // I'm mapping invalid cases (rating > 5 and rating < -2) to the extremes + $rating = (int)($rating + 0.5); + if ($rating <= -2) { + $rating = PLUGIN_KARMA_VOTEPOINT_1; + } elseif ($rating <= -1) { + $rating = PLUGIN_KARMA_VOTEPOINT_2; + } elseif ($rating <= 0) { + $rating = PLUGIN_KARMA_VOTEPOINT_3; + } elseif ($rating <= 1) { + $rating = PLUGIN_KARMA_VOTEPOINT_4; + } else { + $rating = PLUGIN_KARMA_VOTEPOINT_5; + } + } + return $rating; + } +} + +/* vim: set sts=4 ts=4 sw=4 expandtab : */