This commit is contained in:
Matt Claypotch 2012-05-21 18:12:55 -07:00
Родитель 967ee1b63e
Коммит 4d7e0533cb
6 изменённых файлов: 159 добавлений и 44 удалений

Просмотреть файл

@ -16,6 +16,9 @@
min-width: (@cols * (@column + @gutter) - @gutter) * @px;
}
//Magic numbers
@spacing: @gutter * @px;
//Breakpoints
@3col: 0px;
@4col: 480px;

Просмотреть файл

@ -1,41 +1,79 @@
@import 'lib';
.reviews {
position: relative;
ul {
padding: 0;
margin: 0;
}
> div {
.border-box;
width: 50%;
float: left;
}
h3 {
text-align: center;
span {
background: url(../../img/icons/thumbs.png) no-repeat;
display: inline-block;
line-height: 16px;
padding-left: 30px;
figure {
display: block;
background: fade(#fff, 50%);
margin-right: @spacing;
padding: @spacing;
margin-bottom: 2em;
}
figcaption {
margin-bottom: 10px;
font-size: 22px;
}
canvas {
margin-top: 10px;
width: 100%;
height: 72px;
}
a[data-review-filter] {
display: block;
color: #666;
&:hover {
text-decoration: none;
}
&.selected {
background: fade(#fff, 50%);
}
padding: 5px 0;
}
h3 {
padding-left: 36px;
&.upvotes {
background: url(../../img/icons/thumbs.png) no-repeat;
background-position: 8px 8px;
color: #00b960;
}
&.downvotes {
background: url(../../img/icons/thumbs.png) no-repeat;
color: #d93a40;
span {
background-position: 100% -86px;
padding: 0 30px 0 0;
}
background-position: 8px -78px;
}
}
.filter-all .review:nth-child(5) ~ .review {
display: none;
}
.filter-positive .review.negative,
.filter-negative .review.positive {
display: none;
}
#review-list {
background: fade(#fff, 50%);
}
.review {
padding: @spacing;
list-style-type: none;
p {
font-size: 120%;
margin: 0 0 10px;
}
margin: 0 0 @spacing;
}
#submit-review {
margin: 10px 0;
text-align: center;
position: absolute;
bottom: 0;
}
}

Просмотреть файл

@ -0,0 +1,73 @@
function ratingHistory(el, history) {
// init to win it
el.width = el.offsetWidth;
el.height = el.offsetHeight;
var ctx = el.getContext('2d'),
size = el.height / 2,
i, row, x, y;
// normalize values
var max = 0;
for (i=0; i<history.length; i++) {
max = Math.max(max, history[i][0], history[i][1]);
}
var yscale = (size / max),
xscale = (el.width / history.length),
cpx = xscale / 2;
// positive ratings
ctx.fillStyle = 'rgba(0, 200, 0, .2)';
ctx.strokeStyle = 'green';
plotSeries(0, -1);
// negative ratings
ctx.fillStyle = 'rgba(200, 0, 0, .2)';
ctx.strokeStyle = 'red';
plotSeries(1, 1);
function plotSeries(idx, dir) {
ctx.beginPath();
// start outside viewport to hide stroke
ctx.moveTo(-2, size);
ox = 0;
oy = size + history[0][idx] * yscale * dir;
ctx.lineTo(-2, oy);
ctx.lineTo(0, oy);
for (i=1; i<history.length; i++) {
row = history[i];
x = i * xscale + xscale;
y = size + row[idx] * yscale * dir;
ctx.bezierCurveTo(x-cpx, oy, ox+cpx, y, x, y);
oy = y;
ox = x;
}
// finish outside viewport to hide stroke
ctx.lineTo(ox+2, oy);
ctx.lineTo(ox+2, size);
ctx.fill();
ctx.stroke();
}
}
(function() {
z.page.on('fragmentloaded', function() {
var $reviewEl = $('#reviews'),
data = $reviewEl.data('review-history');
if ($reviewEl.exists() && data) {
$reviewEl.find('div:first-child')
.prepend('<figure><figcaption>Reviews, last 30 days</figcaption>' +
'<canvas id="review-spark"></canvas></figure>');
ratingHistory($('#review-spark')[0], data);
}
});
})();
z.page.on('click', '[data-review-filter]', function(e) {
e.preventDefault();
var filter = $(this).data('review-filter');
$('#review-list').removeClass('filter-positive filter-negative filter-all');
$('#review-list').addClass('filter-' + filter);
$('[data-review-filter]').removeClass('selected');
$(this).addClass('selected');
});

Просмотреть файл

@ -213,6 +213,7 @@ JS = {
# Detail page.
'js/mkt/detail.js',
'js/mkt/lightbox.js',
'js/mkt/reviewsparks.js',
# Ratings.
'js/mkt/ratings.js',

Просмотреть файл

@ -250,36 +250,35 @@
</section>
{% if waffle.switch('ratings') %}
<section class="reviews c" id="reviews">
{% if product.can_review(request.amo_user if
request.user.is_authenticated() else None) %}
<p id="submit-review">
<a href="{{ product.get_ratings_url('add') }}" class="button good">
{{ _('Review This App') }}</a></p>
{% endif %}
<div class="thumbs-up">
<h3 class="upvotes">
<span>Positive Reviews <b>({{ product.rating_counts.positive }})</b></span>
</h3>
{% if positive_ratings %}
<ul>
{% for rating in positive_ratings %}
{% include 'ratings/rating.html' %}
{% endfor %}
</ul>
{% else %}
{{ no_results() }}
<section class="reviews c" id="reviews"
data-review-history="{{ review_history|json }}">
<div id="reviews-info">
<a href="#" class="selected" data-review-filter="all">
<h3 class="all">
All Reviews <b>({{ product._ratings.count() }})</b>
</h3>
</a>
<a href="#" data-review-filter="positive">
<h3 class="upvotes">
Positive Reviews <b>({{ product.rating_counts.positive }})</b>
</h3>
</a>
<a href="#" data-review-filter="negative">
<h3 class="downvotes">
Negative Reviews <b>({{ product.rating_counts.negative }})</b>
</h3>
</a>
{% if product.can_review(request.amo_user if
request.user.is_authenticated() else None) %}
<p id="submit-review">
<a href="{{ product.get_ratings_url('add') }}" class="button good">
{{ _('Review This App') }}</a></p>
{% endif %}
<p><a href="{{ product.get_ratings_url() }}" class="button">
{{ _('Read More') }}</a></p>
</div>
<div class="thumbs-down">
<h3 class="downvotes">
<span>Negative Reviews <b>({{ product.rating_counts.negative }})</b></span>
</h3>
{% if negative_ratings %}
<ul>
{% for rating in negative_ratings %}
<div class="thumbs-up">
{% if ratings %}
<ul id="review-list" class="filter-all">
{% for rating in ratings %}
{% include 'ratings/rating.html' %}
{% endfor %}
</ul>

Просмотреть файл

@ -30,13 +30,14 @@ def detail(request, addon):
"""Product details page."""
ratings = Rating.objects.latest().filter(addon=addon).order_by('-created')
positive_ratings = ratings.filter(score=1)[:5]
negative_ratings = ratings.filter(score=-1)[:5]
positive_ratings = list(ratings.filter(score=1)[:5])
negative_ratings = list(ratings.filter(score=-1)[:5])
sorted_ratings = sorted(positive_ratings + negative_ratings, key=lambda x: x.created, reverse=True)
ctx = {
'product': addon,
'ratings': ratings,
'positive_ratings': positive_ratings,
'negative_ratings': negative_ratings,
'ratings': sorted_ratings,
'review_history': [[2,1],[50,2],[3,0],[4,1]]
}
if addon.is_public():
ctx['abuse_form'] = AbuseForm(request=request)