2 rcs_id('$Id: RateIt.php,v 1.5 2004-04-11 10:42:02 rurban Exp $');
4 Copyright 2004 $ThePhpWikiProgrammingTeam
6 This file is (not yet) 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');
24 define('RATING_STORAGE','SQL');
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)
83 * - finish mysuggest.c (external engine with data from mysql)
84 * - add php_prediction
85 * - add the various show modes (esp. TopN queries in PHP)
89 dimension INT(4) NOT NULL,
90 raterpage INT(11) NOT NULL,
91 rateepage INT(11) NOT NULL,
92 ratingvalue FLOAT NOT NULL,
93 rateeversion INT(11) NOT NULL,
94 tstamp TIMESTAMP(14) NOT NULL,
95 PRIMARY KEY (dimension, raterpage, rateepage)
99 require_once("lib/WikiPlugin.php");
101 class WikiPlugin_RateIt
107 function getDescription() {
108 return _("Rating system. Store user ratings per page");
110 function getVersion() {
111 return preg_replace("/[Revision: $]/", '',
112 "\$Revision: 1.5 $");
115 function RatingWidgetJavascript() {
117 $img = substr($Theme->_findData("images/RateItNk0.png"),0,-7);
118 $urlprefix = WikiUrl("",0,1);
120 function displayRating(imgPrefix, ratingvalue, pred) {
121 var cancel = imgPrefix + 'Cancel';
122 for (i=1; i<=10; i++) {
123 var imgName = imgPrefix + i;
124 var imgSrc = '".$img."';
126 document[imgName].title = '"._("Predicted rating ")."'+ratingvalue;
128 document[imgName].title = '"._("Your rating ")."'+ratingvalue;
129 if (i<=(ratingvalue*2)) {
131 document[imgName].src = imgSrc + ((i%2) ? 'Rk1' : 'Rk0') + '.png';
133 document[imgName].src = imgSrc + ((i%2) ? 'Ok1' : 'Ok0') + '.png';
135 document[imgName].src = imgSrc + ((i%2) ? 'Nk1' : 'Nk0') + '.png';
138 if ((pred == 0) && (ratingvalue > 0))
139 document[cancel].src = imgSrc + 'Cancel.png';
141 document[cancel].src = imgSrc + 'CancelN.png';
143 function click(actionImg, pagename, version, imgPrefix, dimension, rating) {
145 deleteRating(actionImg, pagename, dimension);
146 displayRating(imgPrefix, 0, 0);
148 submitRating(actionImg, pagename, version, dimension, rating);
149 displayRating(imgPrefix, rating, 0);
152 function submitRating(actionImg, page, version, dimension, rating) {
153 var myRand = Math.round(Math.random()*(1000000));
154 var imgSrc = page + '?version=' + version + '&action=".urlencode(_("RateIt"))."&mode=add&rating=' + rating + '&dimension=' + dimension + '&nopurge=cache&rand=' + myRand;
155 //alert('submitRating(' + page + ', ' + version + ', ' + dimension + ', ' + rating + ') => '+imgSrc);
156 document[actionImg].src= imgSrc;
158 function deleteRating(actionImg, page, dimension) {
159 var myRand = Math.round(Math.random()*(1000000));
160 var imgSrc = '".$urlprefix."' + page + '?action=".urlencode(_("RateIt"))."&mode=delete&dimension=' + dimension + '&nopurge=cache&rand=' + myRand;
161 //alert('deleteRating(' + page + ', ' + version + ', ' + dimension + ')');
162 document[actionImg].src= imgSrc;
165 return JavaScript($js);
168 function actionImgPath() {
170 return $Theme->_findFile("images/RateItAction.png");
174 * Take a string and quote it sufficiently to be passed as a Javascript
177 function _javascript_quote_string($s) {
178 return str_replace("'", "\'", $s);
181 function getDefaultArguments() {
182 return array( 'pagename' => '[pagename]',
186 'dimension' => false,
193 function head() { // early side-effects (before body)
195 $Theme->addMoreHeaders($this->RatingWidgetJavascript());
198 // todo: only for signed users
199 // todo: set rating dbi for external rating database
200 function run($dbi, $argstr, $request, $basepage) {
202 $this->_request = & $request;
203 $this->_dbi = & $dbi;
204 $user = & $request->getUser();
205 $this->userid = $user->UserName();
206 $args = $this->getArgs($argstr, $request);
207 $this->dimension = $args['dimension'];
208 if ($this->dimension == '') {
209 $this->dimension = 0;
210 $args['dimension'] = 0;
212 if ($args['pagename']) {
213 // Expand relative page names.
214 $page = new WikiPageName($args['pagename'], $basepage);
215 $args['pagename'] = $page->name;
217 if (empty($args['pagename'])) {
218 return $this->error(_("no page specified"));
220 $this->pagename = $args['pagename'];
222 if (RATING_STORAGE == 'SQL') {
223 $dbi = &$this->_dbi->_backend;
224 if (isa($dbi,'WikiDB_backend_PearDB'))
225 $this->dbtype = "PearDB";
227 $this->dbtype = "ADODB";
228 $this->iter_class = "WikiDB_backend_".$this->dbtype."_generic_iter";
229 extract($dbi->_table_names);
230 if (empty($rating_tbl)) {
231 $rating_tbl = (!empty($GLOBALS['DBParams']['prefix'])
232 ? $GLOBALS['DBParams']['prefix'] : '') . 'rating';
233 $dbi->_table_names['rating_tbl'] = $rating_tbl;
237 if ($args['mode'] === 'add') {
238 if (!$user->isSignedIn())
239 return $this->error(_("You must sign in"));
241 $actionImg = $Theme->_path . $this->actionImgPath();
242 $this->addRating($request->getArg('rating'));
243 ob_end_clean(); // discard any previous output
245 $page = $request->getPage();
246 $page->set('_cached_html', false);
247 $request->cacheControl('MUST-REVALIDATE');
249 //fake validators without args
250 $request->appendValidators(array('wikiname' => WIKI_NAME,
251 'args' => hash('')));
252 header('Content-type: image/png');
253 readfile($actionImg);
255 } elseif ($args['mode'] === 'delete') {
256 if (!$user->isSignedIn())
257 return $this->error(_("You must sign in"));
259 $actionImg = $Theme->_path . $this->actionImgPath();
260 $this->deleteRating();
261 ob_end_clean(); // discard any previous output
263 $page = $request->getPage();
264 $page->set('_cached_html', false);
265 $request->cacheControl('MUST-REVALIDATE');
267 //fake validators without args
268 $request->appendValidators(array('wikiname' => WIKI_NAME,
269 'args' => hash('')));
270 header('Content-type: image/png');
271 readfile($actionImg);
273 } elseif (! $args['show'] ) {
274 // we must use the head method instead, because <body> is already printed.
275 // $Theme->addMoreHeaders($this->RatingWidgetJavascript());
276 // or we change the header in the ob_buffer.
278 //Todo: add a validator based on the users last rating mtime
279 $rating = $this->getRating();
281 static $validated = 0;
283 //$page = $request->getPage();
284 //$page->set('_cached_html', false);
285 $request->cacheControl('REVALIDATE');
289 $args['rating'] = $rating;
290 return $this->RatingWidgetHtml($args);
292 if (!$user->isSignedIn())
293 return $this->error(_("You must sign in"));
295 $rating = $this->getRating();
296 $html = HTML::p(sprintf(_("Rated by %d users | Average rating %.1f stars"),
297 $this->getNumUsers($this->pagename,$this->dimension),
298 $this->getAvg($this->pagename,$this->dimension)),
300 if ($rating !== false)
301 $html->pushContent(sprintf(_("Your rating was %.1f"),
304 $pred = $this->getPrediction($this->userid,$this->pagename,$this->dimension);
305 if (is_string($pred))
306 $html->pushContent(sprintf(_("%s prediction for you is %s stars"),
309 $html->pushContent(sprintf(_("%s prediction for you is %.1f stars"),
312 $html->pushContent(HTML::p());
313 $html->pushContent(HTML::em("(Experimental: This is entirely bogus data)"));
318 // box is used to display a fixed-width, narrow version with common header
319 function box($args=false, $request=false, $basepage=false) {
320 if (!$request) $request =& $GLOBALS['request'];
321 if (!$request->_user->isSignedIn()) return;
322 if (!isset($args)) $args = array();
325 foreach ($args as $key => $value)
326 $argstr .= $key."=".$value;
327 $widget = $this->run($request->_dbi, $argstr, $request, $basepage);
329 return $this->makeBox(WikiLink(_("RateIt"),'',_("Rate It")),
333 function addRating($rating, $userid=null, $pagename=null, $dimension=null) {
334 if (is_null($dimension)) $dimension = $this->dimension;
335 if (is_null($userid)) $userid = $this->userid;
336 if (is_null($pagename)) $pagename = $this->pagename;
337 if (RATING_STORAGE == 'SQL') {
338 $page = $this->_dbi->getPage($this->pagename);
339 $current = $page->getCurrentRevision();
340 $rateeversion = $current->getVersion();
341 $this->sql_rate($userid, $pagename, $rateeversion, $dimension, $rating);
343 $this->metadata_set_rating($userid, $pagename, $dimension, $rating);
347 function deleteRating($userid=null, $pagename=null, $dimension=null) {
348 if (is_null($dimension)) $dimension = $this->dimension;
349 if (is_null($userid)) $userid = $this->userid;
350 if (is_null($pagename)) $pagename = $this->pagename;
351 if (RATING_STORAGE == 'SQL') {
352 $this->sql_delete_rating($userid, $pagename, $dimension);
354 $this->metadata_set_rating($userid, $pagename, $dimension, -1);
358 function getRating($userid=null, $pagename=null, $dimension=null) {
359 if (is_null($dimension)) $dimension = $this->dimension;
360 if (is_null($userid)) $userid = $this->userid;
361 if (is_null($pagename)) $pagename = $this->pagename;
362 if (RATING_STORAGE == 'SQL') {
363 $ratings_iter = $this->sql_get_rating($dimension, $userid, $pagename);
364 if ($rating = $ratings_iter->next()) {
365 return $rating['ratingvalue'];
369 return $this->metadata_get_rating($userid, $pagename, $dimension);
374 // Currently we have to call the "suggest" CGI
375 // http://www-users.cs.umn.edu/~karypis/suggest/
376 // until we implement a simple recommendation engine.
377 // Note that "suggest" is only free for non-profit organizations.
378 // I am currently writing a binary CGI using suggest, which loads
380 function getPrediction($userid=null, $pagename=null, $dimension=null) {
381 if (is_null($dimension)) $dimension = $this->dimension;
382 if (is_null($userid)) $userid = $this->userid;
383 if (is_null($pagename)) $pagename = $this->pagename;
384 $dbi = &$this->_dbi->_backend;
385 if (isset($pagename))
386 $page = $dbi->_get_pageid($pagename);
389 $user = $dbi->_get_pageid($userid);
394 if (defined('RATING_EXTERNAL')) {
395 // how call suggest.exe? as CGI or natively
396 //$rating = HTML::Raw("<!--#include virtual=".RATING_ENGINE." -->");
397 $args = "-u$user -p$page -malpha"; // --top 10
398 if (isset($dimension))
399 $args .= " -d$dimension";
400 $rating = passthru(RATING_EXTERNAL . " $args");
402 $rating = $this->php_prediction($userid, $pagename, $dimension);
408 * TODO: slow item-based recommendation engine, similar to suggest RType=2.
409 * Only the SUGGEST_EstimateAlpha part
411 function php_prediction($userid=null, $pagename=null, $dimension=null) {
412 if (is_null($dimension)) $dimension = $this->dimension;
413 if (is_null($userid)) $userid = $this->userid;
414 if (is_null($pagename)) $pagename = $this->pagename;
415 if (RATING_STORAGE == 'SQL') {
423 function getNumUsers($pagename=null, $dimension=null) {
424 if (is_null($dimension)) $dimension = $this->dimension;
425 if (is_null($pagename)) $pagename = $this->pagename;
426 if (RATING_STORAGE == 'SQL') {
427 $ratings_iter = $this->sql_get_rating($dimension, null, $pagename,
429 return $ratings_iter->count();
431 $page = $this->_dbi->getPage($pagename);
432 $data = $page->get('rating');
433 if (!empty($data[$dimension]))
434 return count($data[$dimension]);
439 // TODO: metadata method
440 function getAvg($pagename=null, $dimension=null) {
441 if (is_null($dimension)) $dimension = $this->dimension;
442 if (is_null($pagename)) $pagename = $this->pagename;
443 if (RATING_STORAGE == 'SQL') {
444 $dbi = &$this->_dbi->_backend;
446 if (isset($pagename)) {
447 $raterid = $dbi->_get_pageid($pagename, true);
448 $where .= " AND raterpage=$raterid";
450 if (isset($dimension)) {
451 $where .= " AND dimension=$dimension";
453 //$dbh = &$this->_dbi;
454 extract($dbi->_table_names);
455 $query = "SELECT AVG(ratingvalue) as avg"
456 . " FROM $rating_tbl r, $page_tbl p "
457 . $where. " GROUP BY raterpage";
458 $result = $dbi->_dbh->query($query);
459 $iter = new $this->iter_class($this,$result);
460 $row = $iter->next();
470 * @param dimension The rating dimension id.
473 * If this is null (or left off), the search for ratings
474 * is not restricted by dimension.
476 * @param rater The page id of the rater, i.e. page doing the rating.
477 * This is a Wiki page id, often of a user page.
480 * If this is null (or left off), the search for ratings
481 * is not restricted by rater.
482 * TODO: Support an array
484 * @param ratee The page id of the ratee, i.e. page being rated.
485 * Example: "DudeWheresMyCar"
487 * If this is null (or left off), the search for ratings
488 * is not restricted by ratee.
489 * TODO: Support an array
491 * @param orderby An order-by clause with fields and (optionally) ASC
493 * Example: "ratingvalue DESC"
495 * If this is null (or left off), the search for ratings
496 * has no guaranteed order
498 * @param pageinfo The type of page that has its info returned (i.e.,
499 * 'pagename', 'hits', and 'pagedata') in the rows.
502 * If this is null (or left off), the info returned
503 * is for the 'ratee' page (i.e., thing being rated).
505 * @return DB iterator with results
507 function sql_get_rating($dimension=null, $rater=null, $ratee=null,
508 $orderby=null, $pageinfo = "ratee") {
509 if (empty($dimension)) $dimension=null;
510 $result = $this->_sql_get_rating_result($dimension, $rater, $ratee, $orderby, $pageinfo);
511 return new $this->iter_class($this, $result);
515 * Like get_rating(), but return a result suitable for WikiDB_PageIterator
517 function _sql_get_rating_page($dimension=null, $rater=null, $ratee=null,
518 $orderby=null, $pageinfo = "ratee") {
519 if (empty($dimension)) $dimension=null;
520 $result = $this->_sql_get_rating_result($dimension, $rater, $ratee, $orderby, $pageinfo);
522 return new $this->iter_class($this, $result);
527 * @return DB iterator with results
529 function _sql_get_rating_result($dimension=null, $rater=null, $ratee=null,
530 $orderby=null, $pageinfo = "ratee") {
531 // pageinfo must be 'rater' or 'ratee'
532 if (($pageinfo != "ratee") && ($pageinfo != "rater"))
535 $dbi = &$this->_dbi->_backend;
536 //$dbh = &$this->_dbi;
537 extract($dbi->_table_names);
538 $where = "WHERE r." . $pageinfo . "page = p.id";
539 if (isset($dimension)) {
540 $where .= " AND dimension=$dimension";
543 $raterid = $dbi->_get_pageid($rater, true);
544 $where .= " AND raterpage=$raterid";
547 $rateeid = $dbi->_get_pageid($ratee, true);
548 $where .= " AND rateepage=$rateeid";
551 if (isset($orderby)) {
552 $orderbyStr = " ORDER BY " . $orderby;
556 . " FROM $rating_tbl r, $page_tbl p "
560 $result = $dbi->_dbh->query($query);
567 * @param rater The page id of the rater, i.e. page doing the rating.
568 * This is a Wiki page id, often of a user page.
569 * @param ratee The page id of the ratee, i.e. page being rated.
570 * @param dimension The rating dimension id.
574 * @return true upon success
576 function sql_delete_rating($rater, $ratee, $dimension) {
577 //$dbh = &$this->_dbi;
578 $dbi = &$this->_dbi->_backend;
579 extract($dbi->_table_names);
582 $raterid = $dbi->_get_pageid($rater, true);
583 $rateeid = $dbi->_get_pageid($ratee, true);
584 $where = "WHERE raterpage=$raterid and rateepage=$rateeid";
585 if (isset($dimension)) {
586 $where .= " AND dimension=$dimension";
588 $dbi->_dbh->query("DELETE FROM $rating_tbl $where");
596 * @param rater The page id of the rater, i.e. page doing the rating.
597 * This is a Wiki page id, often of a user page.
598 * @param ratee The page id of the ratee, i.e. page being rated.
599 * @param rateeversion The version of the ratee page.
600 * @param dimension The rating dimension id.
601 * @param rating The rating value (a float).
605 * @return true upon success
607 //$this->userid, $this->pagename, $this->dimension, $rating);
608 function sql_rate($rater, $ratee, $rateeversion, $dimension, $rating) {
609 $dbi = &$this->_dbi->_backend;
610 extract($dbi->_table_names);
611 if (empty($rating_tbl))
612 $rating_tbl = (!empty($GLOBALS['DBParams']['prefix']) ? $GLOBALS['DBParams']['prefix'] : '') . 'rating';
615 $raterid = $dbi->_get_pageid($rater, true);
616 $rateeid = $dbi->_get_pageid($ratee, true);
617 $where = "WHERE raterpage=$raterid AND rateepage=$rateeid";
618 if (isset($dimension)) $where .= " AND dimension=$dimension";
619 $dbi->_dbh->query("DELETE FROM $rating_tbl $where");
620 // NOTE: Leave tstamp off the insert, and MySQL automatically updates it (only if MySQL is used)
621 $dbi->_dbh->query("INSERT INTO $rating_tbl (dimension, raterpage, rateepage, ratingvalue, rateeversion) VALUES ('$dimension', $raterid, $rateeid, '$rating', '$rateeversion')");
626 function metadata_get_rating($userid, $pagename, $dimension) {
627 $page = $this->_dbi->getPage($pagename);
628 $data = $page->get('rating');
629 if (!empty($data[$dimension][$userid]))
630 return (float)$data[$dimension][$userid];
635 function metadata_set_rating($userid, $pagename, $dimension, $rating = -1) {
636 $page = $this->_dbi->getPage($pagename);
637 $data = $page->get('rating');
639 unset($data[$dimension][$userid]);
641 if (empty($data[$dimension][$userid]))
642 $data[$dimension] = array($userid => (float)$rating);
644 $data[$dimension][$userid] = $rating;
646 $page->set('rating',$data);
650 * HTML widget display
652 * This needs to be put in the <body> section of the page.
654 * @param pagename Name of the page to rate
655 * @param version Version of the page to rate (may be "" for current)
656 * @param imgPrefix Prefix of the names of the images that display the rating
657 * You can have two widgets for the same page displayed at
658 * once iff the imgPrefix-s are different.
659 * @param dimension Id of the dimension to rate
660 * @param small Makes a smaller ratings widget if non-false
662 * Limitations: Currently this can only print the current users ratings.
663 * And only the widget, but no value (for buddies) also.
665 function RatingWidgetHtml($args) {
666 global $Theme, $request;
668 if (!$request->_user->isSignedIn()) return;
669 $imgPrefix = $pagename . $imgPrefix;
670 $actionImgName = $imgPrefix . 'RateItAction';
671 $dbi =& $GLOBALS['request']->getDbh();
672 $version = $dbi->_backend->get_latest_version($pagename);
674 // Protect against 's, though not \r or \n
675 $reImgPrefix = $this->_javascript_quote_string($imgPrefix);
676 $reActionImgName = $this->_javascript_quote_string($actionImgName);
677 $rePagename = $this->_javascript_quote_string($pagename);
678 //$dimension = $args['pagename'] . "rat";
680 $html = HTML::span(array("id" => $id));
681 for ($i=0; $i < 2; $i++) {
682 $nk[$i] = $Theme->_findData("images/RateItNk$i.png");
683 $none[$i] = $Theme->_findData("images/RateItRk$i.png");
686 $html->pushContent(Button(_("RateIt"),_("RateIt"),$pagename));
687 $html->pushContent(HTML::raw(' '));
691 $user = $request->getUser();
692 $userid = $user->getId();
693 if (!isset($args['rating']))
694 $rating = $this->getRating($userid, $pagename, $dimension);
696 $pred = $this->getPrediction($userid,$pagename,$dimension);
698 for ($i = 1; $i <= 10; $i++) {
699 $a1 = HTML::a(array('href' => 'javascript:click(\'' . $reActionImgName . '\',\'' . $rePagename . '\',\'' . $version . '\',\'' . $reImgPrefix . '\',\'' . $dimension . '\',' . ($i/2) . ')'));
701 $img_attr['src'] = $nk[$i%2];
702 if (!$rating and !$pred)
703 $img_attr['src'] = $none[$i%2];
704 $img_attr['name'] = $imgPrefix . $i;
705 $img_attr['border'] = 0;
706 $a1->pushContent(HTML::img($img_attr));
707 $a1->addToolTip(_("Rate the topic of this page"));
708 $html->pushContent($a1);
709 //This adds a space between the rating smilies:
710 // if (($i%2) == 0) $html->pushContent(' ');
712 $html->pushContent(HTML::Raw(' '));
713 $a0 = HTML::a(array('href' => 'javascript:click(\'' . $reActionImgName . '\',\'' . $rePagename . '\',\'' . $version . '\',\'' . $reImgPrefix . '\',\'' . $dimension . '\',\'X\')'));
715 $msg = _("Cancel rating");
716 $a0->pushContent(HTML::img(array('src' => $Theme->getImageUrl("RateItCancel"),
717 'name'=> $imgPrefix.'Cancel',
719 $a0->addToolTip($msg);
720 $html->pushContent($a0);
722 $msg = _("No opinion");
723 $html->pushContent(HTML::img(array('src' => $Theme->getImageUrl("RateItCancelN"),
724 'name'=> $imgPrefix.'Cancel',
726 //$a0->addToolTip($msg);
727 //$html->pushContent($a0);
730 $img_attr['src'] = $Theme->_findData("images/RateItAction.png");
731 $img_attr['name'] = $actionImgName;
732 //$img_attr['class'] = 'k' . $i;
733 $img_attr['border'] = 0;
734 $html->pushContent(HTML::img($img_attr));
735 // Display the current rating if there is one
737 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\','.$rating .',0)'));
739 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\','.$pred .',1)'));
741 $html->pushContent(JavaScript('displayRating(\'' . $reImgPrefix . '\',0,0)'));
748 // $Log: not supported by cvs2svn $
749 // Revision 1.4 2004/04/06 20:00:11 rurban
750 // Cleanup of special PageList column types
751 // Added support of plugin and theme specific Pagelist Types
752 // Added support for theme specific UserPreferences
753 // Added session support for ip-based throttling
754 // sql table schema change: ALTER TABLE session ADD sess_ip CHAR(15);
755 // Enhanced postgres schema
756 // Added DB_Session_dba support
758 // Revision 1.3 2004/04/01 06:29:51 rurban
760 // RateIt also for ADODB
762 // Revision 1.2 2004/03/31 06:22:22 rurban
763 // shorter javascript,
764 // added prediction buttons and display logic,
765 // empty HTML if not signed in.
766 // fixed deleting (empty dimension => 0)
768 // Revision 1.1 2004/03/30 02:38:06 rurban
769 // RateIt support (currently no recommendation engine yet)
777 // c-hanging-comment-ender-p: nil
778 // indent-tabs-mode: nil