2 rcs_id('$Id: RateIt.php,v 1.6 2004-04-12 14:07:12 rurban Exp $');
4 Copyright 2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
8 PhpWiki is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 PhpWiki is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //define('RATING_STORAGE','WIKIPAGE'); // not fully supported yet
24 define('RATING_STORAGE','SQL'); // only for mysql yet.
25 // leave undefined for internal, slow php engine.
26 //define('RATING_EXTERNAL',PHPWIKI_DIR . 'suggest.exe');
29 * RateIt: A recommender system, based on MovieLens and suggest.
30 * Store user ratings per pagename. The wikilens theme displays a navbar image bar
31 * with some nice javascript magic and this plugin shows various recommendations.
33 * There should be two methods to store ratings:
34 * In a SQL database as in wikilens http://dickens.cs.umn.edu/dfrankow/wikilens
36 * The most important fact: A page has more than one rating. There can
37 * be (and will be!) many ratings per page (ratee): different raters
38 * (users), in different dimensions. Are those stored per page
39 * (ratee)? Then what if I wish to access the ratings per rater
41 * wikilens plans several user-centered applications like:
43 * b) show my buddies' ratings
44 * c) show how my ratings are like my buddies'
45 * d) show where I agree/disagree with my buddy
46 * e) show what this group of people agree/disagree on
48 * If the ratings are stored in a real DB in a table, we can index the
49 * ratings by rater and ratee, and be confident in
50 * performance. Currently MovieLens has 80,000 users, 7,000 items,
51 * 10,000,000 ratings. This is an average of 1400 ratings/page if each
52 * page were rated equally. However, they're not: the most popular
53 * things have tens of thousands of ratings (e.g., "Pulp Fiction" has
54 * 42,000 ratings). If ratings are stored per page, you would have to
55 * save/read huge page metadata every time someone submits a
56 * rating. Finally, the movie domain has an unusually small number of
57 * items-- I'd expect a lot more in music, for example.
59 * For a simple rating system one can also store the rating in the page
62 * Recommender Engines:
63 * Recommendation/Prediction is a special field of "Data Mining"
64 * For a list of (also free) software see
65 * http://www.the-data-mine.com/bin/view/Software/WebIndex
66 * - movielens: (Java Server) will be gpl'd in summer 2004 (weighted)
67 * - suggest: is free for non-commercial use, available as compiled library
69 * - Autoclass: simple public domain C library
70 * - MLC++: C++ library http://www.sgi.com/tech/mlc/
72 * Usage: <?plugin RateIt ?> to enable rating on this page
73 * Note: The wikilens theme must be enabled, to enable this plugin!
74 * Or use a sidebar based theme with the box method.
75 * <?plugin RateIt show=ratings ?> to show my ratings
76 * <?plugin RateIt show=buddies ?> to show my buddies
77 * <?plugin RateIt show=ratings dimension=1 ?>
79 * @author: Dan Frankowski (wikilens author), Reini Urban (as plugin)
82 * - fix RATING_STORAGE = WIKIPAGE
84 * - finish mysuggest.c (external engine with data from mysql)
85 * - add php_prediction
86 * - add the various show modes (esp. TopN queries in PHP)
90 dimension INT(4) NOT NULL,
91 raterpage INT(11) NOT NULL,
92 rateepage INT(11) NOT NULL,
93 ratingvalue FLOAT NOT NULL,
94 rateeversion INT(11) NOT NULL,
95 tstamp TIMESTAMP(14) NOT NULL,
96 PRIMARY KEY (dimension, raterpage, rateepage)
100 require_once("lib/WikiPlugin.php");
102 class WikiPlugin_RateIt
108 function getDescription() {
109 return _("Rating system. Store user ratings per page");
111 function getVersion() {
112 return preg_replace("/[Revision: $]/", '',
113 "\$Revision: 1.6 $");
116 function RatingWidgetJavascript() {
118 $img = substr($Theme->_findData("images/RateItNk0.png"),0,-7);
119 $urlprefix = WikiUrl("",0,1);
121 function displayRating(imgPrefix, ratingvalue, pred) {
122 var cancel = imgPrefix + 'Cancel';
123 for (i=1; i<=10; i++) {
124 var imgName = imgPrefix + i;
125 var imgSrc = '".$img."';
127 document[imgName].title = '"._("Predicted rating ")."'+ratingvalue;
129 document[imgName].title = '"._("Your rating ")."'+ratingvalue;
130 if (i<=(ratingvalue*2)) {
132 document[imgName].src = imgSrc + ((i%2) ? 'Rk1' : 'Rk0') + '.png';
134 document[imgName].src = imgSrc + ((i%2) ? 'Ok1' : 'Ok0') + '.png';
136 document[imgName].src = imgSrc + ((i%2) ? 'Nk1' : 'Nk0') + '.png';
139 if ((pred == 0) && (ratingvalue > 0))
140 document[cancel].src = imgSrc + 'Cancel.png';
142 document[cancel].src = imgSrc + 'CancelN.png';
144 function click(actionImg, pagename, version, imgPrefix, dimension, rating) {
146 deleteRating(actionImg, pagename, dimension);
147 displayRating(imgPrefix, 0, 0);
149 submitRating(actionImg, pagename, version, dimension, rating);
150 displayRating(imgPrefix, rating, 0);
153 function submitRating(actionImg, page, version, dimension, rating) {
154 var myRand = Math.round(Math.random()*(1000000));
155 var imgSrc = page + '?version=' + version + '&action=".urlencode(_("RateIt"))."&mode=add&rating=' + rating + '&dimension=' + dimension + '&nopurge=cache&rand=' + myRand;
156 //alert('submitRating(' + page + ', ' + version + ', ' + dimension + ', ' + rating + ') => '+imgSrc);
157 document[actionImg].src= imgSrc;
159 function deleteRating(actionImg, page, dimension) {
160 var myRand = Math.round(Math.random()*(1000000));
161 var imgSrc = '".$urlprefix."' + page + '?action=".urlencode(_("RateIt"))."&mode=delete&dimension=' + dimension + '&nopurge=cache&rand=' + myRand;
162 //alert('deleteRating(' + page + ', ' + version + ', ' + dimension + ')');
163 document[actionImg].src= imgSrc;
166 return JavaScript($js);
169 function actionImgPath() {
171 return $Theme->_findFile("images/RateItAction.png");
175 * Take a string and quote it sufficiently to be passed as a Javascript
178 function _javascript_quote_string($s) {
179 return str_replace("'", "\'", $s);
182 function getDefaultArguments() {
183 return array( 'pagename' => '[pagename]',
187 'dimension' => false,
194 function head() { // early side-effects (before body)
196 $Theme->addMoreHeaders($this->RatingWidgetJavascript());
199 // todo: only for signed users
200 // todo: set rating dbi for external rating database
201 function run($dbi, $argstr, $request, $basepage) {
203 $this->_request = & $request;
204 $this->_dbi = & $dbi;
205 $user = & $request->getUser();
206 $this->userid = $user->UserName();
207 $args = $this->getArgs($argstr, $request);
208 $this->dimension = $args['dimension'];
209 if ($this->dimension == '') {
210 $this->dimension = 0;
211 $args['dimension'] = 0;
213 if ($args['pagename']) {
214 // Expand relative page names.
215 $page = new WikiPageName($args['pagename'], $basepage);
216 $args['pagename'] = $page->name;
218 if (empty($args['pagename'])) {
219 return $this->error(_("no page specified"));
221 $this->pagename = $args['pagename'];
223 if (RATING_STORAGE == 'SQL') {
224 $dbi = &$this->_dbi->_backend;
225 if (isa($dbi,'WikiDB_backend_PearDB'))
226 $this->dbtype = "PearDB";
228 $this->dbtype = "ADODB";
229 $this->iter_class = "WikiDB_backend_".$this->dbtype."_generic_iter";
230 extract($dbi->_table_names);
231 if (empty($rating_tbl)) {
232 $rating_tbl = (!empty($GLOBALS['DBParams']['prefix'])
233 ? $GLOBALS['DBParams']['prefix'] : '') . 'rating';
234 $dbi->_table_names['rating_tbl'] = $rating_tbl;
238 if ($args['mode'] === 'add') {
239 if (!$user->isSignedIn())
240 return $this->error(_("You must sign in"));
242 $actionImg = $Theme->_path . $this->actionImgPath();
243 $this->addRating($request->getArg('rating'));
244 ob_end_clean(); // discard any previous output
246 $page = $request->getPage();
247 $page->set('_cached_html', false);
248 $request->cacheControl('MUST-REVALIDATE');
250 //fake validators without args
251 $request->appendValidators(array('wikiname' => WIKI_NAME,
252 'args' => hash('')));
253 header('Content-type: image/png');
254 readfile($actionImg);
256 } elseif ($args['mode'] === 'delete') {
257 if (!$user->isSignedIn())
258 return $this->error(_("You must sign in"));
260 $actionImg = $Theme->_path . $this->actionImgPath();
261 $this->deleteRating();
262 ob_end_clean(); // discard any previous output
264 $page = $request->getPage();
265 $page->set('_cached_html', false);
266 $request->cacheControl('MUST-REVALIDATE');
268 //fake validators without args
269 $request->appendValidators(array('wikiname' => WIKI_NAME,
270 'args' => hash('')));
271 header('Content-type: image/png');
272 readfile($actionImg);
274 } elseif (! $args['show'] ) {
275 // we must use the head method instead, because <body> is already printed.
276 // $Theme->addMoreHeaders($this->RatingWidgetJavascript());
277 // or we change the header in the ob_buffer.
279 //Todo: add a validator based on the users last rating mtime
280 $rating = $this->getRating();
282 static $validated = 0;
284 //$page = $request->getPage();
285 //$page->set('_cached_html', false);
286 $request->cacheControl('REVALIDATE');
290 $args['rating'] = $rating;
291 return $this->RatingWidgetHtml($args);
293 if (!$user->isSignedIn())
294 return $this->error(_("You must sign in"));
296 $rating = $this->getRating();
297 $html = HTML::p(sprintf(_("Rated by %d users | Average rating %.1f stars"),
298 $this->getNumUsers($this->pagename,$this->dimension),
299 $this->getAvg($this->pagename,$this->dimension)),
301 if ($rating !== false)
302 $html->pushContent(sprintf(_("Your rating was %.1f"),
305 $pred = $this->getPrediction($this->userid,$this->pagename,$this->dimension);
306 if (is_string($pred))
307 $html->pushContent(sprintf(_("%s prediction for you is %s stars"),
310 $html->pushContent(sprintf(_("%s prediction for you is %.1f stars"),
313 $html->pushContent(HTML::p());
314 $html->pushContent(HTML::em("(Experimental: This is entirely bogus data)"));
319 // box is used to display a fixed-width, narrow version with common header
320 function box($args=false, $request=false, $basepage=false) {
321 if (!$request) $request =& $GLOBALS['request'];
322 if (!$request->_user->isSignedIn()) return;
323 if (!isset($args)) $args = array();
326 foreach ($args as $key => $value)
327 $argstr .= $key."=".$value;
328 $widget = $this->run($request->_dbi, $argstr, $request, $basepage);
330 return $this->makeBox(WikiLink(_("RateIt"),'',_("Rate It")),
334 function addRating($rating, $userid=null, $pagename=null, $dimension=null) {
335 if (is_null($dimension)) $dimension = $this->dimension;
336 if (is_null($userid)) $userid = $this->userid;
337 if (is_null($pagename)) $pagename = $this->pagename;
338 if (RATING_STORAGE == 'SQL') {
339 $page = $this->_dbi->getPage($this->pagename);
340 $current = $page->getCurrentRevision();
341 $rateeversion = $current->getVersion();
342 $this->sql_rate($userid, $pagename, $rateeversion, $dimension, $rating);
344 $this->metadata_set_rating($userid, $pagename, $dimension, $rating);
348 function deleteRating($userid=null, $pagename=null, $dimension=null) {
349 if (is_null($dimension)) $dimension = $this->dimension;
350 if (is_null($userid)) $userid = $this->userid;
351 if (is_null($pagename)) $pagename = $this->pagename;
352 if (RATING_STORAGE == 'SQL') {
353 $this->sql_delete_rating($userid, $pagename, $dimension);
355 $this->metadata_set_rating($userid, $pagename, $dimension, -1);
359 function getRating($userid=null, $pagename=null, $dimension=null) {
360 if (is_null($dimension)) $dimension = $this->dimension;
361 if (is_null($userid)) $userid = $this->userid;
362 if (is_null($pagename)) $pagename = $this->pagename;
363 if (RATING_STORAGE == 'SQL') {
364 $ratings_iter = $this->sql_get_rating($dimension, $userid, $pagename);
365 if ($rating = $ratings_iter->next()) {
366 return $rating['ratingvalue'];
370 return $this->metadata_get_rating($userid, $pagename, $dimension);
375 // Currently we have to call the "suggest" CGI
376 // http://www-users.cs.umn.edu/~karypis/suggest/
377 // until we implement a simple recommendation engine.
378 // Note that "suggest" is only free for non-profit organizations.
379 // I am currently writing a binary CGI using suggest, which loads
381 function getPrediction($userid=null, $pagename=null, $dimension=null) {
382 if (is_null($dimension)) $dimension = $this->dimension;
383 if (is_null($userid)) $userid = $this->userid;
384 if (is_null($pagename)) $pagename = $this->pagename;
385 $dbi = &$this->_dbi->_backend;
386 if (isset($pagename))
387 $page = $dbi->_get_pageid($pagename);
390 $user = $dbi->_get_pageid($userid);
395 if (defined('RATING_EXTERNAL')) {
396 // how call suggest.exe? as CGI or natively
397 //$rating = HTML::Raw("<!--#include virtual=".RATING_ENGINE." -->");
398 $args = "-u$user -p$page -malpha"; // --top 10
399 if (isset($dimension))
400 $args .= " -d$dimension";
401 $rating = passthru(RATING_EXTERNAL . " $args");
403 $rating = $this->php_prediction($userid, $pagename, $dimension);
409 * TODO: slow item-based recommendation engine, similar to suggest RType=2.
410 * Only the SUGGEST_EstimateAlpha part
412 function php_prediction($userid=null, $pagename=null, $dimension=null) {
413 if (is_null($dimension)) $dimension = $this->dimension;
414 if (is_null($userid)) $userid = $this->userid;
415 if (is_null($pagename)) $pagename = $this->pagename;
416 if (RATING_STORAGE == 'SQL') {
424 function getNumUsers($pagename=null, $dimension=null) {
425 if (is_null($dimension)) $dimension = $this->dimension;
426 if (is_null($pagename)) $pagename = $this->pagename;
427 if (RATING_STORAGE == 'SQL') {
428 $ratings_iter = $this->sql_get_rating($dimension, null, $pagename,
430 return $ratings_iter->count();
432 $page = $this->_dbi->getPage($pagename);
433 $data = $page->get('rating');
434 if (!empty($data[$dimension]))
435 return count($data[$dimension]);
440 // TODO: metadata method
441 function getAvg($pagename=null, $dimension=null) {
442 if (is_null($dimension)) $dimension = $this->dimension;
443 if (is_null($pagename)) $pagename = $this->pagename;
444 if (RATING_STORAGE == 'SQL') {
445 $dbi = &$this->_dbi->_backend;
447 if (isset($pagename)) {
448 $raterid = $dbi->_get_pageid($pagename, true);
449 $where .= " AND raterpage=$raterid";
451 if (isset($dimension)) {
452 $where .= " AND dimension=$dimension";
454 //$dbh = &$this->_dbi;
455 extract($dbi->_table_names);
456 $query = "SELECT AVG(ratingvalue) as avg"
457 . " FROM $rating_tbl r, $page_tbl p "
458 . $where. " GROUP BY raterpage";
459 $result = $dbi->_dbh->query($query);
460 $iter = new $this->iter_class($this,$result);
461 $row = $iter->next();
471 * @param dimension The rating dimension id.
474 * If this is null (or left off), the search for ratings
475 * is not restricted by dimension.
477 * @param rater The page id of the rater, i.e. page doing the rating.
478 * This is a Wiki page id, often of a user page.
481 * If this is null (or left off), the search for ratings
482 * is not restricted by rater.
483 * TODO: Support an array
485 * @param ratee The page id of the ratee, i.e. page being rated.
486 * Example: "DudeWheresMyCar"
488 * If this is null (or left off), the search for ratings
489 * is not restricted by ratee.
490 * TODO: Support an array
492 * @param orderby An order-by clause with fields and (optionally) ASC
494 * Example: "ratingvalue DESC"
496 * If this is null (or left off), the search for ratings
497 * has no guaranteed order
499 * @param pageinfo The type of page that has its info returned (i.e.,
500 * 'pagename', 'hits', and 'pagedata') in the rows.
503 * If this is null (or left off), the info returned
504 * is for the 'ratee' page (i.e., thing being rated).
506 * @return DB iterator with results
508 function sql_get_rating($dimension=null, $rater=null, $ratee=null,
509 $orderby=null, $pageinfo = "ratee") {
510 if (empty($dimension)) $dimension=null;
511 $result = $this->_sql_get_rating_result($dimension, $rater, $ratee, $orderby, $pageinfo);
512 return new $this->iter_class($this, $result);
516 * Like get_rating(), but return a result suitable for WikiDB_PageIterator
518 function _sql_get_rating_page($dimension=null, $rater=null, $ratee=null,
519 $orderby=null, $pageinfo = "ratee") {
520 if (empty($dimension)) $dimension=null;
521 $result = $this->_sql_get_rating_result($dimension, $rater, $ratee, $orderby, $pageinfo);
523 return new $this->iter_class($this, $result);
528 * @return DB iterator with results
530 function _sql_get_rating_result($dimension=null, $rater=null, $ratee=null,
531 $orderby=null, $pageinfo = "ratee") {
532 // pageinfo must be 'rater' or 'ratee'
533 if (($pageinfo != "ratee") && ($pageinfo != "rater"))
536 $dbi = &$this->_dbi->_backend;
537 //$dbh = &$this->_dbi;
538 extract($dbi->_table_names);
539 $where = "WHERE r." . $pageinfo . "page = p.id";
540 if (isset($dimension)) {
541 $where .= " AND dimension=$dimension";
544 $raterid = $dbi->_get_pageid($rater, true);
545 $where .= " AND raterpage=$raterid";
548 $rateeid = $dbi->_get_pageid($ratee, true);
549 $where .= " AND rateepage=$rateeid";
552 if (isset($orderby)) {
553 $orderbyStr = " ORDER BY " . $orderby;
557 . " FROM $rating_tbl r, $page_tbl p "
561 $result = $dbi->_dbh->query($query);
568 * @param rater The page id of the rater, i.e. page doing the rating.
569 * This is a Wiki page id, often of a user page.
570 * @param ratee The page id of the ratee, i.e. page being rated.
571 * @param dimension The rating dimension id.
575 * @return true upon success
577 function sql_delete_rating($rater, $ratee, $dimension) {
578 //$dbh = &$this->_dbi;
579 $dbi = &$this->_dbi->_backend;
580 extract($dbi->_table_names);
583 $raterid = $dbi->_get_pageid($rater, true);
584 $rateeid = $dbi->_get_pageid($ratee, true);
585 $where = "WHERE raterpage=$raterid and rateepage=$rateeid";
586 if (isset($dimension)) {
587 $where .= " AND dimension=$dimension";
589 $dbi->_dbh->query("DELETE FROM $rating_tbl $where");
597 * @param rater The page id of the rater, i.e. page doing the rating.
598 * This is a Wiki page id, often of a user page.
599 * @param ratee The page id of the ratee, i.e. page being rated.
600 * @param rateeversion The version of the ratee page.
601 * @param dimension The rating dimension id.
602 * @param rating The rating value (a float).
606 * @return true upon success
608 //$this->userid, $this->pagename, $this->dimension, $rating);
609 function sql_rate($rater, $ratee, $rateeversion, $dimension, $rating) {
610 $dbi = &$this->_dbi->_backend;
611 extract($dbi->_table_names);
612 if (empty($rating_tbl))
613 $rating_tbl = (!empty($GLOBALS['DBParams']['prefix']) ? $GLOBALS['DBParams']['prefix'] : '') . 'rating';
616 $raterid = $dbi->_get_pageid($rater, true);
617 $rateeid = $dbi->_get_pageid($ratee, true);
618 $where = "WHERE raterpage=$raterid AND rateepage=$rateeid";
619 if (isset($dimension)) $where .= " AND dimension=$dimension";
620 $dbi->_dbh->query("DELETE FROM $rating_tbl $where");
621 // NOTE: Leave tstamp off the insert, and MySQL automatically updates it (only if MySQL is used)
622 $dbi->_dbh->query("INSERT INTO $rating_tbl (dimension, raterpage, rateepage, ratingvalue, rateeversion) VALUES ('$dimension', $raterid, $rateeid, '$rating', '$rateeversion')");
627 function metadata_get_rating($userid, $pagename, $dimension) {
628 $page = $this->_dbi->getPage($pagename);
629 $data = $page->get('rating');
630 if (!empty($data[$dimension][$userid]))
631 return (float)$data[$dimension][$userid];
636 function metadata_set_rating($userid, $pagename, $dimension, $rating = -1) {
637 $page = $this->_dbi->getPage($pagename);
638 $data = $page->get('rating');
640 unset($data[$dimension][$userid]);
642 if (empty($data[$dimension][$userid]))
643 $data[$dimension] = array($userid => (float)$rating);
645 $data[$dimension][$userid] = $rating;
647 $page->set('rating',$data);
651 * HTML widget display
653 * This needs to be put in the <body> section of the page.
655 * @param pagename Name of the page to rate
656 * @param version Version of the page to rate (may be "" for current)
657 * @param imgPrefix Prefix of the names of the images that display the rating
658 * You can have two widgets for the same page displayed at
659 * once iff the imgPrefix-s are different.
660 * @param dimension Id of the dimension to rate
661 * @param small Makes a smaller ratings widget if non-false
663 * Limitations: Currently this can only print the current users ratings.
664 * And only the widget, but no value (for buddies) also.
666 function RatingWidgetHtml($args) {
667 global $Theme, $request;
669 if (!$request->_user->isSignedIn()) return;
670 $imgPrefix = $pagename . $imgPrefix;
671 $actionImgName = $imgPrefix . 'RateItAction';
672 $dbi =& $GLOBALS['request']->getDbh();
673 $version = $dbi->_backend->get_latest_version($pagename);
675 // Protect against 's, though not \r or \n
676 $reImgPrefix = $this->_javascript_quote_string($imgPrefix);
677 $reActionImgName = $this->_javascript_quote_string($actionImgName);
678 $rePagename = $this->_javascript_quote_string($pagename);
679 //$dimension = $args['pagename'] . "rat";
681 $html = HTML::span(array("id" => $id));
682 for ($i=0; $i < 2; $i++) {
683 $nk[$i] = $Theme->_findData("images/RateItNk$i.png");
684 $none[$i] = $Theme->_findData("images/RateItRk$i.png");
687 $html->pushContent(Button(_("RateIt"),_("RateIt"),$pagename));
688 $html->pushContent(HTML::raw(' '));
692 $user = $request->getUser();
693 $userid = $user->getId();
694 if (!isset($args['rating']))
695 $rating = $this->getRating($userid, $pagename, $dimension);
697 $pred = $this->getPrediction($userid,$pagename,$dimension);
699 for ($i = 1; $i <= 10; $i++) {
700 $a1 = HTML::a(array('href' => 'javascript:click(\'' . $reActionImgName . '\',\'' . $rePagename . '\',\'' . $version . '\',\'' . $reImgPrefix . '\',\'' . $dimension . '\',' . ($i/2) . ')'));
702 $img_attr['src'] = $nk[$i%2];
703 if (!$rating and !$pred)
704 $img_attr['src'] = $none[$i%2];
705 $img_attr['name'] = $imgPrefix . $i;
706 $img_attr['border'] = 0;
707 $a1->pushContent(HTML::img($img_attr));
708 $a1->addToolTip(_("Rate the topic of this page"));
709 $html->pushContent($a1);
710 //This adds a space between the rating smilies:
711 // if (($i%2) == 0) $html->pushContent(' ');
713 $html->pushContent(HTML::Raw(' '));
714 $a0 = HTML::a(array('href' => 'javascript:click(\'' . $reActionImgName . '\',\'' . $rePagename . '\',\'' . $version . '\',\'' . $reImgPrefix . '\',\'' . $dimension . '\',\'X\')'));
716 $msg = _("Cancel rating");
717 $a0->pushContent(HTML::img(array('src' => $Theme->getImageUrl("RateItCancel"),
718 'name'=> $imgPrefix.'Cancel',
720 $a0->addToolTip($msg);
721 $html->pushContent($a0);
723 $msg = _("No opinion");
724 $html->pushContent(HTML::img(array('src' => $Theme->getImageUrl("RateItCancelN"),
725 'name'=> $imgPrefix.'Cancel',
727 //$a0->addToolTip($msg);
728 //$html->pushContent($a0);
731 $img_attr['src'] = $Theme->_findData("images/RateItAction.png");
732 $img_attr['name'] = $actionImgName;
733 //$img_attr['class'] = 'k' . $i;
734 $img_attr['border'] = 0;
735 $html->pushContent(HTML::img($img_attr));
736 // Display the current rating if there is one
738 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\','.$rating .',0)'));
740 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\','.$pred .',1)'));
742 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\',0,0)'));
749 // $Log: not supported by cvs2svn $
750 // Revision 1.5 2004/04/11 10:42:02 rurban
751 // pgsrc/CreatePagePlugin
753 // Revision 1.4 2004/04/06 20:00:11 rurban
754 // Cleanup of special PageList column types
755 // Added support of plugin and theme specific Pagelist Types
756 // Added support for theme specific UserPreferences
757 // Added session support for ip-based throttling
758 // sql table schema change: ALTER TABLE session ADD sess_ip CHAR(15);
759 // Enhanced postgres schema
760 // Added DB_Session_dba support
762 // Revision 1.3 2004/04/01 06:29:51 rurban
764 // RateIt also for ADODB
766 // Revision 1.2 2004/03/31 06:22:22 rurban
767 // shorter javascript,
768 // added prediction buttons and display logic,
769 // empty HTML if not signed in.
770 // fixed deleting (empty dimension => 0)
772 // Revision 1.1 2004/03/30 02:38:06 rurban
773 // RateIt support (currently no recommendation engine yet)
781 // c-hanging-comment-ender-p: nil
782 // indent-tabs-mode: nil