Textpattern CMS support forum
You are not logged in. Register | Login | Help
- Topics: Active | Unanswered
Re: jmd_rate: A CSS star rater
Oops, I forgot to fix the link – the star image is here. For the HTML output, you’ll get a raw list if you don’t have any CSS linked to it.
- Head to Extensions>jmd_rate and create your CSS. Enter the path to your star image (or hotlink mine)
- Place the CSS in a CSS file
- Link to it in your
head
For the rating, are you redirected to /page?rating=1 (and then to /page)?
Last edited by jm (2008-03-31 16:59:44)
Offline
Re: jmd_rate: A CSS star rater
Got most of it working but the display of the current score doesn’t seem to work.
Also, i think the CSS conflicts with my extensive use of CSS for layout. I can’t place things where I want them to be.
I’ll give it a go when I have more time.
Thanks.
Last edited by lozmatic (2008-03-31 23:33:02)
Offline
Re: jmd_rate: A CSS star rater
That is strange – you should have <li class="current_rating" style="width: Xpx;">Currently rated Y</li> immediately after the ul in your source code. I’ll see if I can replicate it – can you post the jmd_rate section from your template?
Off topic: Any reason for using a span to wrap a ul? Might want to close some of those tags too :).
Offline
Re: jmd_rate: A CSS star rater
ah, i got rid of the ‘Currently rated’ bit because i wanted to have the stars fit nicely next to the page’s title.
Yeah, it’s all a bot messy there. I tried wrapping things in nasty nasty ways to try and position the stars.
Offline
Re: jmd_rate: A CSS star rater
Tsk, tsk! The li[class=current_rating] is responsible for the current score display (half-filled stars, etc). If the CSS and HTML is correct (and not too invalid), it’ll draw the stars and not display the text (text-indent: -9999px). I suggest grabbing a new copy of the plugin :).
Offline
Offline
Re: jmd_rate: A CSS star rater
Ok, now it works wonderfully and beautifully – i’ve positioned elements exactly where I want them.
Thanks.
Offline
Re: jmd_rate: A CSS star rater
Cool – glad you got it working.
I’m planning on adding read-only display (for jmd_rate_article and jmd_article_cf use) next (probably this week), then I’ll work on Ajax (this weekend?).
Offline
Re: jmd_rate: A CSS star rater
Cool, well, as is… it’s very cool.
One thing I’ve noticed, though. When I rate using firefox the new rating only displays when I click shift and the refresh button. Until I do that I can continue voting… is this the case with anyone else?
Offline
Re: jmd_rate: A CSS star rater
Strange – does it happen to you here too?
- Does the page redirect at all? My votes are already recorded, so I couldn’t test the site (I don’t remember it hanging). Could you head to Extensions>jmd_rate and uninstall then install it?
- Is PHP under fast-cgi or installed as an Apache module?
Offline
Re: jmd_rate: A CSS star rater
Yes, and I’ve just tested using my work PC that has a different version of FireFox (and a different connnection).
To answer your questions…
1. The page seems to load up again after clicking to vote
2. Not quite sure. How can I check this… in txp or on my server?
Offline
#27 2008-04-08 03:34:31
- nardo
- Member

- From: tuvalahiti
- Registered: 2004-04-22
- Posts: 743
Re: jmd_rate: A CSS star rater
for a review site … would it be possible for the article author to add a star rating, and each commenter to add a star rating… and their personal ratings were displayed beside their name… but also the total user rating was displayed in a sidebox?
Offline
Re: jmd_rate: A CSS star rater
lozmatic wrote:
- The page seems to load up again after clicking to vote
- Not quite sure. How can I check this… in txp or on my server?
- Strange. I’m having a hard time replicating the bug (I’ve experienced it though). Could you post your jmd_rate code from your article form?
- Admin>Diagnostics: High – if you see something like “PHP Server API: cgi” or “mod_fastcgi” anywhere, you’re running fastcgi. The first two versions had a header redirect bug I though I’d solved, at least for my server.
nardo wrote:
for a review site … would it be possible for the article author to add a star rating, and each commenter to add a star rating… and their personal ratings were displayed beside their name… but also the total user rating was displayed in a sidebox?
I think it would be, but I haven’t had a chance to work with comments yet. For the article author rating, it could be done with a custom field (“author_rating”) and a small amount of PHP – something like:
<txp:php>
// number of stars
$stars = 5;
// width of stars
$starWidth = 30;
// width of the ul
$ulWidth = ($stars * $starWidth);
// custom field name == author_rating
$authorRating = custom_field(array(
'name' => 'author_rating'
));
$rating = ($stars/$authorRating);
// rating width
$ratingWidth = ($rating * $starWidth);
// HTML output
echo '<ul class="rating" style="width: '. $ulWidth .'px">
<li style="width: '. $ratingWidth .'px" id="current_rating">
'. $rating .'
</li>
</ul>';
</txp:php>
OK, so that’s probably enough PHP to be added to the plugin. YAVT: <txp:jmd_rate_author_rating/>
Last edited by jm (2008-04-08 06:47:06)
Offline
Re: jmd_rate: A CSS star rater
Hi,
Would this be it?
PHP Server API: cgi-fcgi
Code is…
--------------------------------------
// admin
if (@txpinterface == 'admin')
{
add_privs('jmd_rate_prefs', '1');
register_tab('extensions', 'jmd_rate_prefs', 'jmd_rate');
register_callback('jmd_rate_prefs', 'jmd_rate_prefs');
}
function jmd_rate_prefs($event, $step)
{
ob_start('jmd_rate_prefs_head');
pagetop('jmd_rate_prefs');
echo '<div id="jmd_rate_prefs">';
if (!$step)
{
echo fieldset(
form(
(
fInput('submit', 'install', 'Install', 'publish').
eInput('jmd_rate_prefs').
sInput('install')
)
).
form(
(
fInput('submit', 'uninstall', 'Uninstall', 'publish').
eInput('jmd_rate_prefs').
sInput('uninstall')
), '', "verify('Are you sure you want to delete all ratings?');"
), 'Setup', 'setup'
);
echo fieldset(
form(
'<label>Quantity '.fInput('text', 'qty', 4).'</label><br/>
<label>Path and filename of star image '.fInput('text', 'path', '/stars.png').'</label><br/>
<label>Star width'.fInput('text', 'width', 19).'</label><br/>
<label>Star height'.fInput('text', 'height', 18).'</label><br/>
<label>Container class name'.fInput('text', 'class', 'rating').'</label><br/>'.
fInput('submit', 'generate', 'Generate CSS', 'publish').
eInput('jmd_rate_prefs').
sInput('builder')
), 'CSS builder'
);
}
elseif ($step == 'install')
{
$sql = "CREATE TABLE ".safe_pfx('jmd_rate')."(
parentid INT,
value INT,
max_value INT,
ip INT UNSIGNED,
PRIMARY KEY(parentid, ip)
)";
$create = safe_query($sql);
if ($create)
{
echo tag('Table created successfully. '.eLink('jmd_rate_prefs', '', '', '', 'Back to preferences?'), 'p', ' class="ok"');
}
else
{
echo tag('Database exists. '.eLink('jmd_rate_prefs', '', '', '', 'Back to preferences?'), 'p', ' class="not-ok"');
}
}
elseif ($step == 'uninstall')
{
safe_query("DROP TABLE IF EXISTS ".safe_pfx('jmd_rate'));
echo tag('Table dropped. '.eLink('jmd_rate_prefs', '', '', '', 'Back to preferences?'), 'p', ' class="ok"');
}
elseif ($step == 'builder')
{
if (is_numeric(gps('qty')) && is_numeric(gps('width')) && is_numeric(gps('height')))
{
$qty = gps('qty');
$w = round(gps('width'));
$h = round(gps('height'));
$path = htmlentities(gps('path'));
$class = '.'.gps('class');
echo tag('CSS', 'h1');
echo "
<textarea class=\"code\" cols=\"78\" rows=\"32\" id=\"jmd_rate_css\">
$class {}
$class, $class * {
margin: 0;
border: 0;
padding: 0;
}
$class ul {
height: ".$h."px;
position: relative;
}
$class ul, $class .current_rating, $class a:hover {
background: url($path);
}
$class li {
list-style: none;
text-indent: -9999px;
}
$class .current_rating {
background-position: 0 -".$h."px;
z-index: 1;
}
$class .current_rating, $class a {
height: ".$h."px;
position: absolute;
top: 0;
left: 0;
}
$class a {
width: ".$w."px;
height: ".$h."px;
overflow: hidden;
z-index: 3;
}
$class a:hover{
background-position: left center;
left: 0;
z-index: 2;
}
".$class."_1 a:hover { width: ".$w."px }
";
for ($i = 2; $i <= $qty; $i++)
{
echo '
'.$class.'_'.$i.' a { left: '.($i - 1) * $w.'px }
'.$class.'_'.$i.' a:hover { width: '.$w * $i.'px }
';
}
echo '</textarea>';
}
echo tag(eLink('jmd_rate_prefs', '', '', '', 'Try again?'), 'p');
}
else
{
echo tag('Error.', 'h1');
}
echo '</div><!--//jmd_rate_prefs-->';
}
// courtesy of upm_savenew <http://utterplush.com/txp-plugins/upm-savenew>
function jmd_rate_prefs_head($buffer)
{
$find = '</head>';
$replace = '
<script type="text/javascript">
function jmd_rate() {
var input = document.getElementById("jmd_rate_prefs").getElementsByTagName("input");
for (i = 0; i < input.length; i++) {
if (input[i].getAttribute("type") == "text") {
input[i].onfocus = function() {
this.select();
};
}
}
var cssOutput = document.getElementById("jmd_rate_css");
if (cssOutput) {
cssOutput.onclick = function() {
this.select();
};
}
}
addEvent(window, "load", jmd_rate);
</script>
<style type="text/css">
#jmd_rate_prefs {
width: 500px;
margin: 20px auto;
}
fieldset label {
display: block;
}
#setup form {
display: inline;
}
p.not-ok {
margin-top: 10px;
}
</style>
';
return str_replace($find, $replace.$find, $buffer);
}
//--------------------------------------
// public
// instantiates jmd_rate class
function jmd_rate($atts, $thing)
{
extract(lAtts(array(
'class' => 'rating',
'stars' => 4,
'star_width' => 19,
'wraptag' => 'div',
), $atts));
global $jmd_rate_instance;
$jmd_rate_instance = new jmd_rate($stars, $star_width);
$out = $jmd_rate_instance->getRating().parse($thing);
return ($wraptag) ? doTag($out, $wraptag, $class) : $out;
}
// displays rater
function jmd_rate_display($atts)
{
return $GLOBALS['jmd_rate_instance']->display();
}
// checks for votes
function if_jmd_rate_votes($atts, $thing)
{
$condition = ($GLOBALS['jmd_rate_instance']->votes > 0);
$out = EvalElse($thing, $condition);
return parse($out);
}
// Max rating possible
function jmd_rate_max($atts)
{
return $GLOBALS['jmd_rate_instance']->maxValue;
}
// returns current rating
function jmd_rate_rating($atts)
{
return $GLOBALS['jmd_rate_instance']->rating;
}
// returns number of votes
function jmd_rate_votes($atts)
{
extract(lAtts(array(
'singular' => '',
'plural' => '',
), $atts));
$votes = $GLOBALS['jmd_rate_instance']->votes;
$out = $votes.' ';
if ($singular && $plural)
{
$out .= (($votes > 1) ? $plural : $singular);
}
return $out;
}
// checks if the user has voted
function if_jmd_rate_voted($atts, $thing)
{
$condition = $GLOBALS['jmd_rate_instance']->voted;
$out = EvalElse($thing, $condition);
return parse($out);
}
// article_custom with sort by rating
function jmd_rate_article($atts)
{
extract(lAtts(array(
'author' => '',
'category' => '',
'form' => 'default',
'keywords' => '',
'limit' => '10',
'max_rating' => '',
'min_rating' => '',
'month' => '',
'section' => '',
'sort' => 'DESC',
), $atts));
$matching = getRows("SELECT parentid, avg(value) AS rating FROM ".safe_pfx('jmd_rate')." GROUP BY parentid HAVING rating BETWEEN $min_rating and $max_rating ORDER BY rating $sort LIMIT $limit");
// if no articles match the criteria, exit
if (!$matching)
{
return;
}
$out = '';
foreach ($matching as $article)
{
$out .= article_custom(array(
'author' => $author,
'category' => $category,
'form' => $form,
'id' => $article['parentid'],
'keywords' => $keywords,
'limit' => $limit,
'month' => $month,
'section' => $section,
));
}
return $out;
}
class jmd_rate
{
// input
private $starWidth;
public $maxValue;
// helpers
private $dbTable, $parentid, $ip, $uri;
// rating
private $value, $usedIps;
public $votes, $voted, $rating;
public function __construct($stars, $star_width)
{
ob_start();
$this->dbTable = 'jmd_rate';
$this->parentid = $GLOBALS['thisarticle']['thisid'];
$this->uri = permlinkurl_id($this->parentid);
$this->ip = $_SERVER['REMOTE_ADDR'];
$this->maxValue = $stars;
$this->starWidth = $star_width;
if (gps('rating'))
{
$this->setRating();
}
}
public function getRating()
{
$query = "SELECT sum(value) AS total_value, count(value) AS total_votes, max_value FROM ".safe_pfx($this->dbTable)." WHERE parentid=$this->parentid GROUP BY max_value";
$row = getRows($query);
// if the query was empty, exit
if (!$row)
{
return;
}
foreach($row as $r)
{
extract($r);
}
$this->value = $r['total_value'];
$this->votes = $r['total_votes'];
// if the # of stars has changed, adjust previous votes
if ($r['max_value'] != $this->maxValue)
{
$scalar = ($this->maxValue/$r['max_value']);
// adjust display value
$this->value *= $scalar;
// adjust previous votes
safe_update($this->dbTable, "value=(value*$scalar), max_value=$this->maxValue", "parentid=$this->parentid");
}
$this->rating = @number_format($this->value/$this->votes, 2);
// see if the visitor has voted
$this->voted = safe_field("ip", $this->dbTable, "ip=INET_ATON('$this->ip') AND parentid=$this->parentid");
}
private function setRating()
{
$userRating = intval(gps('rating'));
if ($this->voted)
{
echo tag('You have already voted!', 'p', ' class="error"');
}
elseif ($userRating > $this->maxValue)
{
echo tag('Cheater!', 'p', ' class="error"');
}
else
{
safe_insert($this->dbTable, "parentid=$this->parentid, value=$userRating, max_value=$this->maxValue, ip=INET_ATON('$this->ip')");
// redirect - thanks to zem_contact_reborn
while (@ob_end_clean());
txp_status_header('303 See Other');
header('Location: '.$this->uri);
}
}
public function display()
{
$out = '<ul style="width: '.$this->maxValue * $this->starWidth.'px">';
$out .= '<li class="current_rating" style="width: '.$this->rating * $this->starWidth.'px;">Currently rated '.$this->rating.'</li>';
// if they haven't voted and voting is open, link the stars
if (!$this->voted)
{
$getUri = ($GLOBALS['permlink_mode'] == 'messy') ? '&rating=' : '?rating=';
for ($i = 1; $i <= $this->maxValue; $i++)
{
$out .= '<li class="rating_'.$i.'">
<a href="'.$this->uri.$getUri.$i.'" rel="nofollow">
'.$i.'/'.$this->maxValue.'
</a>
</li>';
}
}
$out .= '</ul>';
return $out;
}
}@
Offline
#30 2008-04-14 15:07:25
- bluemonkay
- New Member
- Registered: 2004-08-12
- Posts: 2
Re: jmd_rate: A CSS star rater
love the plugin, i’m looking at using it on a departmental intranet.
however we are all stuck on the same ip and so i get to rate and nobody else is able- does anybody know of a way to hack out the ip checking or a way of allowing the same ip to vote multiple ways.
in a perfect world for my use i’d base it on cookies and not ip, sadly my skils aren’t up to the job.
still i love the customisation elements of this plugin and it’s good to see the community still thriving.
(i’ve been away from txp for a while)
Offline