mobile personas previewer (bug 654307) + details page (bug 654310)
This commit is contained in:
Родитель
2305d58019
Коммит
b30b42424e
|
@ -218,6 +218,24 @@ def persona_preview(context, persona, size='large', linked=True, extra=None,
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
@register.inclusion_tag('addons/mobile/persona_preview.html')
|
||||||
|
@jinja2.contextfunction
|
||||||
|
def mobile_persona_preview(context, persona):
|
||||||
|
addon = persona.addon
|
||||||
|
c = dict(context.items())
|
||||||
|
c.update({'persona': persona, 'addon': addon})
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
@register.inclusion_tag('addons/mobile/persona_confirm.html')
|
||||||
|
@jinja2.contextfunction
|
||||||
|
def mobile_persona_confirm(context, persona, size='large'):
|
||||||
|
addon = persona.addon
|
||||||
|
c = dict(context.items())
|
||||||
|
c.update({'persona': persona, 'addon': addon, 'size': size})
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
@register.inclusion_tag('addons/persona_grid.html')
|
@register.inclusion_tag('addons/persona_grid.html')
|
||||||
@jinja2.contextfunction
|
@jinja2.contextfunction
|
||||||
def persona_grid(context, addons):
|
def persona_grid(context, addons):
|
||||||
|
|
|
@ -40,18 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if addon.total_reviews %}
|
{{ mobile_reviews_link(addon) }}
|
||||||
<a class="listview" href="{{ url('reviews.list', addon.slug) }}">
|
|
||||||
<div class="icon">
|
|
||||||
{{ addon.average_rating|stars }}
|
|
||||||
</div>
|
|
||||||
{% trans num=addon.total_reviews, cnt=addon.total_reviews|numberfmt %}
|
|
||||||
See All Reviews
|
|
||||||
{% pluralize %}
|
|
||||||
See All {{ cnt }} Reviews
|
|
||||||
{% endtrans %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<table>
|
<table>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<header id="home-header">
|
<header id="home-header">
|
||||||
{% include "mobile/header.html" %}
|
{% include "mobile/header.html" %}
|
||||||
<div class="get-fx-message">
|
<div class="get-fx-message">
|
||||||
{{ _('You need Firefox to install addons. <a href="http://mozilla.com/firefox">Learn More »</a>') }}
|
{{ _('You need Firefox to install add-ons. <a href="http://mozilla.com/firefox">Learn More »</a>') }}
|
||||||
</div>
|
</div>
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h1 class="site-title">
|
<h1 class="site-title">
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="persona-confirm{% if size == 'small' %} persona-slider{% endif %}">
|
||||||
|
{% if size == 'large' %}
|
||||||
|
<a href="#" class="button preview">{{ _('Try it on!') }}</a>
|
||||||
|
{% endif %}
|
||||||
|
<div class="confirm-buttons">
|
||||||
|
{{ mobile_install_button(addon, show_warning=False) }}
|
||||||
|
<a href="#" class="button cancel">{{ _('Cancel') }}</a>
|
||||||
|
</div>
|
||||||
|
{% if size == 'small' %}
|
||||||
|
<a href="{{ addon.get_url_path() }}"
|
||||||
|
class="more">{{ _('Persona Info »') }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -1,18 +1,66 @@
|
||||||
{% extends "mobile/base.html" %}
|
{% extends "mobile/base.html" %}
|
||||||
|
|
||||||
|
|
||||||
{% block title %}{{ page_title(addon.name) }}{% endblock %}
|
{% block title %}{{ page_title(addon.name) }}{% endblock %}
|
||||||
|
|
||||||
{% block page %}
|
{% block back_link %}
|
||||||
{% set persona = addon.persona %}
|
<a href="{{ url('browse.personas') }}" id="home">
|
||||||
|
{{ _('« All Personas') }}</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<div class="listview">
|
{% block page %}
|
||||||
{{ persona_preview(addon.persona, size='small') }}
|
{% set author = users_list(addon.listed_authors) or persona.display_username %}
|
||||||
{# TODO: button #}
|
|
||||||
|
<div id="persona" class="persona-previewer infobox item">
|
||||||
|
{{ mobile_persona_preview(persona) }}
|
||||||
|
<h3>{{ addon.name }}</h3>
|
||||||
|
<h4 class="author">{{ _('by') }} {{ author }}</h4>
|
||||||
|
<p id="summary"{{ addon.summary|locale_html }}>{{ addon.summary|nl2br }}</p>
|
||||||
|
{{ mobile_persona_confirm(persona) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table>
|
{{ mobile_reviews_link(addon) }}
|
||||||
{% include "addons/persona_detail_table.html" %}
|
|
||||||
</table>
|
<details>
|
||||||
|
<table>
|
||||||
|
{% include "addons/mobile/persona_detail_table.html" %}
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<div id="more-personas">
|
||||||
|
{% cache author_personas %}
|
||||||
|
{% if author_personas %}
|
||||||
|
<div id="more-artist" class="listview item">
|
||||||
|
<ul>
|
||||||
|
{% for other in author_personas %}
|
||||||
|
<li class="persona-previewer">
|
||||||
|
{{ mobile_persona_preview(other.persona) }}
|
||||||
|
{{ mobile_persona_confirm(other.persona, size='small') }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
<li><a href="{{ author_gallery }}">
|
||||||
|
{{ _('See all Personas by this Artist') }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
{% cache category_personas %}
|
||||||
|
{% if category_personas %}
|
||||||
|
<div id="more-category" class="listview item">
|
||||||
|
<ul>
|
||||||
|
{% for other in category_personas %}
|
||||||
|
<li class="persona-previewer">
|
||||||
|
{{ mobile_persona_preview(other.persona) }}
|
||||||
|
{{ mobile_persona_confirm(other.persona, size='small') }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{# L10n: {0} is a category name, such as Nature #}
|
||||||
|
<li><a href="{{ categories[0].get_url_path() }}">
|
||||||
|
{{ _('See all {0} Personas')|f(categories[0].name) }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endcache %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<tbody>
|
||||||
|
<tr class="artist">
|
||||||
|
<th>{{ _('Artist') }}</th>
|
||||||
|
<td>{{ author }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _('Updated') }}</th>
|
||||||
|
<td>
|
||||||
|
<time datetime="{{ addon.modified|isotime }}">{{
|
||||||
|
addon.modified|datetime }}</time>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="meta-stats">
|
||||||
|
<th>{{ _('Daily Users') }}</th>
|
||||||
|
<td>
|
||||||
|
<strong class="downloads">{{
|
||||||
|
persona.popularity|numberfmt }}</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if persona.license %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ _('License') }}</th>
|
||||||
|
<td>{{ license_link(persona.license) }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="persona persona-large persona-preview">
|
||||||
|
<div style="background-image:url('{{ persona.preview_url }}')"
|
||||||
|
data-browsertheme="{{ persona.json_data }}"><p></p></div>
|
||||||
|
</div>
|
|
@ -5,13 +5,14 @@ from pyquery import PyQuery
|
||||||
|
|
||||||
import amo
|
import amo
|
||||||
from addons.helpers import (statusflags, flag, support_addon, contribution,
|
from addons.helpers import (statusflags, flag, support_addon, contribution,
|
||||||
performance_note)
|
performance_note, mobile_persona_preview,
|
||||||
|
mobile_persona_confirm)
|
||||||
from addons.models import Addon
|
from addons.models import Addon
|
||||||
|
|
||||||
|
|
||||||
class TestHelpers(test_utils.TestCase):
|
class TestHelpers(test_utils.TestCase):
|
||||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_4664_twitterbar',
|
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_4664_twitterbar',
|
||||||
'addons/featured.json']
|
'addons/featured', 'addons/persona']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Addon._feature keeps an in-process cache we need to clear.
|
# Addon._feature keeps an in-process cache we need to clear.
|
||||||
|
@ -95,6 +96,48 @@ class TestHelpers(test_utils.TestCase):
|
||||||
doc = PyQuery(s)
|
doc = PyQuery(s)
|
||||||
eq_(doc('input[name=source]').attr('value'), 'browse')
|
eq_(doc('input[name=source]').attr('value'), 'browse')
|
||||||
|
|
||||||
|
def test_mobile_persona_preview(self):
|
||||||
|
ctx = {'APP': amo.FIREFOX, 'LANG': 'en-US'}
|
||||||
|
persona = Addon.objects.get(pk=15663).persona
|
||||||
|
s = mobile_persona_preview(ctx, persona)
|
||||||
|
doc = PyQuery(s)
|
||||||
|
bt = doc('.persona-preview div[data-browsertheme]')
|
||||||
|
assert bt
|
||||||
|
assert persona.preview_url in bt.attr('style')
|
||||||
|
eq_(persona.json_data, bt.attr('data-browsertheme'))
|
||||||
|
assert bt.find('p')
|
||||||
|
|
||||||
|
def _test_mobile_persona_ctx(self):
|
||||||
|
request = Mock()
|
||||||
|
request.APP = amo.FIREFOX
|
||||||
|
request.GET = {}
|
||||||
|
request.user.is_authenticated.return_value = False
|
||||||
|
request.amo_user.mobile_addons = []
|
||||||
|
return {'APP': amo.FIREFOX, 'LANG': 'en-US', 'request': request}
|
||||||
|
|
||||||
|
def test_mobile_persona_confirm_large(self):
|
||||||
|
persona = Addon.objects.get(id=15663).persona
|
||||||
|
s = mobile_persona_confirm(self._test_mobile_persona_ctx(), persona)
|
||||||
|
doc = PyQuery(s)
|
||||||
|
assert not doc('.persona-slider')
|
||||||
|
assert doc('.preview')
|
||||||
|
assert doc('.confirm-buttons .add')
|
||||||
|
assert doc('.confirm-buttons .cancel')
|
||||||
|
assert not doc('.more')
|
||||||
|
|
||||||
|
def test_mobile_persona_confirm_small(self):
|
||||||
|
persona = Addon.objects.get(id=15663).persona
|
||||||
|
s = mobile_persona_confirm(self._test_mobile_persona_ctx(), persona,
|
||||||
|
size='small')
|
||||||
|
doc = PyQuery(s)
|
||||||
|
assert doc('.persona-slider')
|
||||||
|
assert not doc('.persona-slider .preview')
|
||||||
|
assert doc('.confirm-buttons .add')
|
||||||
|
assert doc('.confirm-buttons .cancel')
|
||||||
|
more = doc('.more')
|
||||||
|
assert more
|
||||||
|
eq_(more.attr('href'), persona.addon.get_url_path())
|
||||||
|
|
||||||
|
|
||||||
class TestPerformanceNote(test_utils.TestCase):
|
class TestPerformanceNote(test_utils.TestCase):
|
||||||
listing = '<div class="performance-note">'
|
listing = '<div class="performance-note">'
|
||||||
|
|
|
@ -571,6 +571,12 @@ class TestDetailPage(test_utils.TestCase):
|
||||||
assert '<script>alert("fff")</script>' in html
|
assert '<script>alert("fff")</script>' in html
|
||||||
assert '<script>' not in html
|
assert '<script>' not in html
|
||||||
|
|
||||||
|
def test_personas_context(self):
|
||||||
|
response = self.client.get(reverse('addons.detail', args=['a15663']))
|
||||||
|
assert 'review_form' in response.context
|
||||||
|
assert 'reviews' in response.context
|
||||||
|
assert 'get_replies' in response.context
|
||||||
|
|
||||||
def test_unreviewed_robots(self):
|
def test_unreviewed_robots(self):
|
||||||
"""Check that unreviewed add-ons do not get indexed."""
|
"""Check that unreviewed add-ons do not get indexed."""
|
||||||
addon = Addon.objects.get(id=3615)
|
addon = Addon.objects.get(id=3615)
|
||||||
|
@ -1266,11 +1272,14 @@ class TestMobileDetails(TestMobile):
|
||||||
eq_(r.status_code, 200)
|
eq_(r.status_code, 200)
|
||||||
self.assertTemplateUsed(r, 'addons/mobile/details.html')
|
self.assertTemplateUsed(r, 'addons/mobile/details.html')
|
||||||
|
|
||||||
def _test_persona(self):
|
def test_persona(self):
|
||||||
addon = Addon.objects.filter(type=amo.ADDON_PERSONA)[0]
|
addon = Addon.objects.get(id=15679)
|
||||||
r = self.client.get(addon.get_url_path())
|
r = self.client.get(addon.get_url_path())
|
||||||
eq_(r.status_code, 200)
|
eq_(r.status_code, 200)
|
||||||
self.assertTemplateUsed(r, 'addons/mobile/persona_detail.html')
|
self.assertTemplateUsed(r, 'addons/mobile/persona_detail.html')
|
||||||
|
assert 'review_form' not in r.context
|
||||||
|
assert 'reviews' not in r.context
|
||||||
|
assert 'get_replies' not in r.context
|
||||||
|
|
||||||
def test_release_notes(self):
|
def test_release_notes(self):
|
||||||
a = Addon.objects.get(id=3615)
|
a = Addon.objects.get(id=3615)
|
||||||
|
|
|
@ -18,7 +18,7 @@ import jinja2
|
||||||
import commonware.log
|
import commonware.log
|
||||||
import session_csrf
|
import session_csrf
|
||||||
from tower import ugettext as _, ugettext_lazy as _lazy
|
from tower import ugettext as _, ugettext_lazy as _lazy
|
||||||
from mobility.decorators import mobilized
|
from mobility.decorators import mobilized, mobile_template
|
||||||
|
|
||||||
import amo
|
import amo
|
||||||
from amo import messages
|
from amo import messages
|
||||||
|
@ -238,7 +238,8 @@ def _category_personas(qs, limit):
|
||||||
return caching.cached(f, key)
|
return caching.cached(f, key)
|
||||||
|
|
||||||
|
|
||||||
def persona_detail(request, addon):
|
@mobile_template('addons/{mobile/}persona_detail.html')
|
||||||
|
def persona_detail(request, addon, template=None):
|
||||||
"""Details page for Personas."""
|
"""Details page for Personas."""
|
||||||
persona = addon.persona
|
persona = addon.persona
|
||||||
|
|
||||||
|
@ -250,9 +251,6 @@ def persona_detail(request, addon):
|
||||||
else:
|
else:
|
||||||
category_personas = None
|
category_personas = None
|
||||||
|
|
||||||
# tags
|
|
||||||
dev_tags, user_tags = addon.tags_partitioned_by_developer
|
|
||||||
|
|
||||||
# other personas from the same author(s)
|
# other personas from the same author(s)
|
||||||
author_personas = Addon.objects.valid().filter(
|
author_personas = Addon.objects.valid().filter(
|
||||||
persona__author=persona.author,
|
persona__author=persona.author,
|
||||||
|
@ -265,25 +263,23 @@ def persona_detail(request, addon):
|
||||||
'categories': categories,
|
'categories': categories,
|
||||||
'author_personas': author_personas,
|
'author_personas': author_personas,
|
||||||
'category_personas': category_personas,
|
'category_personas': category_personas,
|
||||||
|
# Remora uses persona.author despite there being a display_username.
|
||||||
|
'author_gallery': settings.PERSONAS_USER_ROOT % persona.author,
|
||||||
|
}
|
||||||
|
if not request.MOBILE:
|
||||||
|
# tags
|
||||||
|
dev_tags, user_tags = addon.tags_partitioned_by_developer
|
||||||
|
data.update({
|
||||||
'dev_tags': dev_tags,
|
'dev_tags': dev_tags,
|
||||||
'user_tags': user_tags,
|
'user_tags': user_tags,
|
||||||
'review_form': ReviewForm(),
|
'review_form': ReviewForm(),
|
||||||
'reviews': Review.objects.latest().filter(addon=addon),
|
'reviews': Review.objects.latest().filter(addon=addon),
|
||||||
'get_replies': Review.get_replies,
|
'get_replies': Review.get_replies,
|
||||||
# Remora users persona.author despite there being a display_username
|
'search_cat': 'personas'
|
||||||
'author_gallery': settings.PERSONAS_USER_ROOT % persona.author,
|
})
|
||||||
'search_cat': 'personas',
|
|
||||||
}
|
|
||||||
if settings.REPORT_ABUSE:
|
if settings.REPORT_ABUSE:
|
||||||
data['abuse_form'] = AbuseForm(request=request)
|
data['abuse_form'] = AbuseForm(request=request)
|
||||||
|
return jingo.render(request, template, data)
|
||||||
return jingo.render(request, 'addons/persona_detail.html', data)
|
|
||||||
|
|
||||||
|
|
||||||
# @mobilized(persona_detail)
|
|
||||||
# def persona_detail(request, addon):
|
|
||||||
# return jingo.render(request, 'addons/mobile/persona_detail.html',
|
|
||||||
# {'addon': addon})
|
|
||||||
|
|
||||||
|
|
||||||
class BaseFilter(object):
|
class BaseFilter(object):
|
||||||
|
|
|
@ -28,6 +28,12 @@ def reviews_link(addon, collection_uuid=None, link_to_list=False):
|
||||||
collection_uuid=collection_uuid))
|
collection_uuid=collection_uuid))
|
||||||
|
|
||||||
|
|
||||||
|
@jingo.register.function
|
||||||
|
def mobile_reviews_link(addon):
|
||||||
|
t = jingo.env.get_template('reviews/mobile/reviews_link.html')
|
||||||
|
return jinja2.Markup(t.render(addon=addon))
|
||||||
|
|
||||||
|
|
||||||
@jingo.register.inclusion_tag('reviews/report_review.html')
|
@jingo.register.inclusion_tag('reviews/report_review.html')
|
||||||
@jinja2.contextfunction
|
@jinja2.contextfunction
|
||||||
def report_review_popup(context):
|
def report_review_popup(context):
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% if addon.total_reviews %}
|
||||||
|
<a class="listview" href="{{ url('reviews.list', addon.slug) }}">
|
||||||
|
<div class="icon">
|
||||||
|
{{ addon.average_rating|stars }}
|
||||||
|
</div>
|
||||||
|
{% trans num=addon.total_reviews, cnt=addon.total_reviews|numberfmt %}
|
||||||
|
See All Reviews
|
||||||
|
{% pluralize %}
|
||||||
|
See All {{ cnt }} Reviews
|
||||||
|
{% endtrans %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="listview" href="{{ url('reviews.add', addon.slug) }}">
|
||||||
|
{{ _('Be the first to write a review.') }}</a>
|
||||||
|
{% endif %}
|
|
@ -56,3 +56,25 @@ def test_reviews_link():
|
||||||
s = render('{{ reviews_link(myaddon, link_to_list=True) }}',
|
s = render('{{ reviews_link(myaddon, link_to_list=True) }}',
|
||||||
{'myaddon': a})
|
{'myaddon': a})
|
||||||
eq_(PyQuery(s)('a').attr('href'), u)
|
eq_(PyQuery(s)('a').attr('href'), u)
|
||||||
|
|
||||||
|
|
||||||
|
def test_mobile_reviews_link():
|
||||||
|
s = lambda a: PyQuery(render('{{ mobile_reviews_link(myaddon) }}',
|
||||||
|
{'myaddon': a}))
|
||||||
|
|
||||||
|
a = Addon(total_reviews=0, id=1, type=1, slug='xx')
|
||||||
|
doc = s(a)
|
||||||
|
eq_(doc('a').attr('href'), reverse('reviews.add', args=['xx']))
|
||||||
|
|
||||||
|
u = reverse('reviews.list', args=['xx'])
|
||||||
|
|
||||||
|
a = Addon(average_rating=4, total_reviews=37, id=1, type=1, slug='xx')
|
||||||
|
doc = s(a)
|
||||||
|
eq_(doc('a').attr('href'), u)
|
||||||
|
eq_(doc('a').text(), 'Rated 4 out of 5 stars See All 37 Reviews')
|
||||||
|
|
||||||
|
a = Addon(average_rating=4, total_reviews=1, id=1, type=1, slug='xx')
|
||||||
|
doc = s(a)
|
||||||
|
doc.remove('div')
|
||||||
|
eq_(doc('a').attr('href'), u)
|
||||||
|
eq_(doc('a').text(), 'See All Reviews')
|
||||||
|
|
|
@ -65,7 +65,8 @@ i {
|
||||||
header:after,
|
header:after,
|
||||||
section:after,
|
section:after,
|
||||||
.menu:after,
|
.menu:after,
|
||||||
.grouped_ratings:after {
|
.grouped_ratings:after,
|
||||||
|
.persona-confirm:after {
|
||||||
content: ".";
|
content: ".";
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
@ -488,7 +489,7 @@ header #home, header .back-link {
|
||||||
|
|
||||||
.listview,
|
.listview,
|
||||||
.infobox {
|
.infobox {
|
||||||
margin: 14px 14px 0;
|
margin: 14px 14px 1em;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
-moz-border-radius: 6px;
|
-moz-border-radius: 6px;
|
||||||
-webkit-border-radius: 6px;
|
-webkit-border-radius: 6px;
|
||||||
|
@ -497,7 +498,6 @@ header #home, header .back-link {
|
||||||
/* background-image: -moz-linear-gradient(#fff, rgba(255,255,255,0) 12px);
|
/* background-image: -moz-linear-gradient(#fff, rgba(255,255,255,0) 12px);
|
||||||
-moz-box-shadow: 0 -3px rgba(0,0,0,.1) inset;
|
-moz-box-shadow: 0 -3px rgba(0,0,0,.1) inset;
|
||||||
-webkit-box-shadow: 0 -3px rgba(0,0,0,.1) inset;*/
|
-webkit-box-shadow: 0 -3px rgba(0,0,0,.1) inset;*/
|
||||||
margin-bottom: 1em;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.infobox {
|
.infobox {
|
||||||
|
@ -512,7 +512,7 @@ header #home, header .back-link {
|
||||||
}
|
}
|
||||||
.listview li > a,
|
.listview li > a,
|
||||||
a.listview {
|
a.listview {
|
||||||
padding: 14px 10px;
|
padding: 14px;
|
||||||
color: #444;
|
color: #444;
|
||||||
font-family: Georgia, serif;
|
font-family: Georgia, serif;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
|
@ -521,6 +521,10 @@ a.listview {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.html-rtl li > a,
|
||||||
|
.html-rtl a.listview {
|
||||||
|
padding-left: 34px;
|
||||||
|
}
|
||||||
.listview .item > a,
|
.listview .item > a,
|
||||||
.listview div.item {
|
.listview div.item {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -816,7 +820,6 @@ a.listview:before {
|
||||||
-webkit-transition: .5s opacity ease;
|
-webkit-transition: .5s opacity ease;
|
||||||
}
|
}
|
||||||
#lightbox .close {
|
#lightbox .close {
|
||||||
font-family: sans;
|
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
@ -906,6 +909,170 @@ td .versions li a {
|
||||||
line-height: 12px;
|
line-height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************/
|
||||||
|
/* PERSONAS */
|
||||||
|
/************************************/
|
||||||
|
|
||||||
|
#persona h3,
|
||||||
|
#persona .author {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona h3 {
|
||||||
|
color: #444;
|
||||||
|
font-family: "Droid Sans", Helvetica, sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona .author,
|
||||||
|
#persona .persona-large {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona .badges {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona .badges li {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.license {
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
}
|
||||||
|
ul.license li {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
list-style: none;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
.html-rtl ul.license li {
|
||||||
|
float: right;
|
||||||
|
margin: 0 0 0 2px;
|
||||||
|
}
|
||||||
|
ul.license li.text {
|
||||||
|
font-size: 90%;
|
||||||
|
line-height: 15px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
.html-rtl ul.license li.text {
|
||||||
|
margin: 0 4px 0 0;
|
||||||
|
}
|
||||||
|
ul.license li.icon {
|
||||||
|
background: url(../../img/zamboni/licenses.png) no-repeat top left;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
ul.license li.cc-attrib { background-position: 0 0; }
|
||||||
|
ul.license li.cc-noderiv { background-position: 0 -65px; }
|
||||||
|
ul.license li.cc-noncom { background-position: 0 -130px; }
|
||||||
|
ul.license li.cc-share { background-position: 0 -195px; }
|
||||||
|
ul.license li.copyr { background-position: 0 -260px; }
|
||||||
|
|
||||||
|
.persona-preview [data-browsertheme] {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-large [data-browsertheme],
|
||||||
|
.persona-large p {
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-large {
|
||||||
|
max-width: 680px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-large [data-browsertheme] {
|
||||||
|
background: transparent no-repeat right top;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
|
||||||
|
display: table;
|
||||||
|
height: 64px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-large p {
|
||||||
|
background-image: url(../../img/zamboni/mobile/loading-white.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
-moz-background-size: auto 32px;
|
||||||
|
-wekbkit-background-size: auto 32px;
|
||||||
|
background-size: auto 32px;
|
||||||
|
color: #fff;
|
||||||
|
display: none;
|
||||||
|
font: 18px Georgia, serif;
|
||||||
|
pointer-events: none;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-hover p {
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-previewing p,
|
||||||
|
.persona-installed p {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona .confirm-buttons,
|
||||||
|
.persona-slider .badges {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-previewer .confirm-buttons .add {
|
||||||
|
float: left;
|
||||||
|
width: -moz-calc(50% - 63px); /* 63px = 39px + 24px (for plus-sign icon) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-previewer .confirm-buttons .cancel {
|
||||||
|
float: right;
|
||||||
|
width: -moz-calc(50% - 39px); /* 39px = 32px + 14px / 2 (margin) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-previewer .persona-installed p:before {
|
||||||
|
background: url(../../img/zamboni/mobile/checkmark.png) no-repeat top left;
|
||||||
|
content: " ";
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 3px -3px 0;
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
height: 25px;
|
||||||
|
width: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.persona-previewer {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-slider {
|
||||||
|
background-color: #ccc;
|
||||||
|
border-top: #999 1px solid;
|
||||||
|
box-shadow: 0 -1px 1px rgba(0,0,0,.5);
|
||||||
|
display: none;
|
||||||
|
padding: 14px;
|
||||||
|
position: relative;
|
||||||
|
left: -14px;
|
||||||
|
bottom: -14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-slider .more {
|
||||||
|
clear: both;
|
||||||
|
color: #447bc4;
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
padding-top: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************/
|
/************************************/
|
||||||
/* VERSIONS */
|
/* VERSIONS */
|
||||||
/************************************/
|
/************************************/
|
||||||
|
@ -969,11 +1136,26 @@ td .versions li a {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infobox .install-wrapper {
|
.infobox .install-wrapper,
|
||||||
|
#persona .persona-confirm {
|
||||||
border-top: 2px solid #fff;
|
border-top: 2px solid #fff;
|
||||||
box-shadow: 0 -1px #ccc;
|
box-shadow: 0 -1px #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#persona .persona-confirm {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.persona-confirm .install-wrapper {
|
||||||
|
margin: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#persona .persona-confirm .install-wrapper {
|
||||||
|
border-top-width: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
.button, a.button {
|
.button, a.button {
|
||||||
-moz-transition: -moz-box-shadow 0.3s ease 0s;
|
-moz-transition: -moz-box-shadow 0.3s ease 0s;
|
||||||
background-color: #669BE1;
|
background-color: #669BE1;
|
||||||
|
@ -1039,6 +1221,7 @@ td .versions li a {
|
||||||
0 0 100px rgba(255, 255, 255, 0.2) inset;
|
0 0 100px rgba(255, 255, 255, 0.2) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button.preview,
|
||||||
.button.affirmative,
|
.button.affirmative,
|
||||||
.button.add {
|
.button.add {
|
||||||
background-color: #84C63C;
|
background-color: #84C63C;
|
||||||
|
@ -1064,6 +1247,9 @@ td .versions li a {
|
||||||
);*/
|
);*/
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
.button.cancel {
|
||||||
|
background-color: #b25951;
|
||||||
|
}
|
||||||
.button.add {
|
.button.add {
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
}
|
}
|
||||||
|
@ -1312,9 +1498,7 @@ td .versions li a {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
}
|
}
|
||||||
.num_ratings {
|
.num_ratings {
|
||||||
font-size: .9em;
|
|
||||||
color: #888;
|
color: #888;
|
||||||
line-height: 22px;
|
|
||||||
width: 1px;
|
width: 1px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -6px;
|
right: -6px;
|
||||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.4 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 32 KiB |
|
@ -201,6 +201,15 @@ $(function() {
|
||||||
$("#eula .negative").click(_pd(z.eula.dismiss));
|
$("#eula .negative").click(_pd(z.eula.dismiss));
|
||||||
$("#eula .affirmative").click(_pd(z.eula.dismiss));
|
$("#eula .affirmative").click(_pd(z.eula.dismiss));
|
||||||
|
|
||||||
|
$(".persona-previewer .preview").click(_pd(function() {
|
||||||
|
var persona = new MobilePersona(this);
|
||||||
|
persona.triggers().preview();
|
||||||
|
}));
|
||||||
|
$(".persona-previewer .cancel").click(_pd(function() {
|
||||||
|
var persona = new MobilePersona(this);
|
||||||
|
persona.triggers().cancel();
|
||||||
|
}));
|
||||||
|
|
||||||
//review truncation
|
//review truncation
|
||||||
if ($(".review").length) {
|
if ($(".review").length) {
|
||||||
$(".review p").each(function() {
|
$(".review p").each(function() {
|
||||||
|
@ -258,3 +267,99 @@ z.eula = (function(){
|
||||||
acceptButton: $("#eula-menu .affirmative")
|
acceptButton: $("#eula-menu .affirmative")
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MobilePersona: controls for mobile-friendly Persona previewer.
|
||||||
|
* Configuration:
|
||||||
|
* el: .button, .persona-preview, or any element in the .persona-previewer
|
||||||
|
*/
|
||||||
|
function MobilePersona(el) {
|
||||||
|
this.el = el;
|
||||||
|
this.outer = $(el).closest('.persona-previewer');
|
||||||
|
this.persona = this.outer.find('.persona');
|
||||||
|
this.personaPreview = this.persona.find('[data-browsertheme]');
|
||||||
|
}
|
||||||
|
MobilePersona.prototype.buttons = function() {
|
||||||
|
var $slider = this.outer.find('.persona-slider'),
|
||||||
|
$preview = this.outer.find('.button.preview'),
|
||||||
|
$confirm = this.outer.find('.confirm-buttons'),
|
||||||
|
$badges = this.outer.closest('#persona').find('.badges'),
|
||||||
|
that = this;
|
||||||
|
return {
|
||||||
|
show: function(force) {
|
||||||
|
if ($slider.length) {
|
||||||
|
$slider.slideDown();
|
||||||
|
} else {
|
||||||
|
$confirm.show();
|
||||||
|
}
|
||||||
|
$preview.hide();
|
||||||
|
$badges.hide();
|
||||||
|
},
|
||||||
|
hide: function(force) {
|
||||||
|
if ($slider.length) {
|
||||||
|
$slider.slideUp();
|
||||||
|
} else {
|
||||||
|
$confirm.hide();
|
||||||
|
}
|
||||||
|
$preview.show();
|
||||||
|
$badges.show();
|
||||||
|
},
|
||||||
|
disable: function() {
|
||||||
|
$preview.addClass('disabled');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MobilePersona.prototype.states = function() {
|
||||||
|
var btns = this.buttons(),
|
||||||
|
that = this;
|
||||||
|
return {
|
||||||
|
loading: function() {
|
||||||
|
that.persona.find('p').show();
|
||||||
|
},
|
||||||
|
previewing: function() {
|
||||||
|
that.persona.addClass('persona-previewing');
|
||||||
|
that.persona.find('p').text(gettext("You're trying it on!"));
|
||||||
|
btns.show();
|
||||||
|
},
|
||||||
|
installed: function() {
|
||||||
|
var $installed = $('.persona-installed');
|
||||||
|
if ($installed.length) {
|
||||||
|
// If a different persona has already been installed, then
|
||||||
|
// that persona should be able to be previewed again.
|
||||||
|
$installed.removeClass('persona-installed').find('p').text('').hide();
|
||||||
|
$('#persona .preview.disabled').removeClass('disabled');
|
||||||
|
$installed.find('[data-browsertheme]').trigger('click');
|
||||||
|
}
|
||||||
|
that.persona.find('p').text(gettext('Added to Firefox'));
|
||||||
|
that.persona.removeClass('persona-previewing').addClass('persona-installed');
|
||||||
|
btns.hide();
|
||||||
|
btns.disable();
|
||||||
|
},
|
||||||
|
cancelled: function() {
|
||||||
|
that.persona.removeClass('persona-previewing');
|
||||||
|
that.persona.find('p').text('').hide();
|
||||||
|
btns.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MobilePersona.prototype.triggers = function() {
|
||||||
|
// Trigger events for Persona previews.
|
||||||
|
var btns = this.buttons(),
|
||||||
|
that = this;
|
||||||
|
return {
|
||||||
|
preview: function() {
|
||||||
|
// Check if "Try it" button is disabled.
|
||||||
|
if (that.outer.find('.button.preview').hasClass('disabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
that.personaPreview.trigger('click');
|
||||||
|
btns.show();
|
||||||
|
},
|
||||||
|
cancel: function() {
|
||||||
|
// Clicking again will cancel the Persona preview.
|
||||||
|
that.personaPreview.trigger('click');
|
||||||
|
btns.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,54 @@
|
||||||
|
$(document).ready(function() {
|
||||||
|
var personas = $('.persona-preview');
|
||||||
|
if (!personas.length) return;
|
||||||
|
personas.previewPersona();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds Personas preview events to the element.
|
||||||
|
* Click - bubbles up PreviewPersona
|
||||||
|
* Click again - bubbles up ResetPersona
|
||||||
|
**/
|
||||||
|
$.fn.previewPersona = function(o) {
|
||||||
|
if (!$.hasPersonas()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
o = $.extend({
|
||||||
|
activeClass: 'persona-hover',
|
||||||
|
disabledClass: 'persona-installed'
|
||||||
|
}, o || {});
|
||||||
|
$(this).click(function(e) {
|
||||||
|
var $outer = $(this).closest('.persona-previewer'),
|
||||||
|
$persona = $outer.find('.persona');
|
||||||
|
if ($persona.hasClass(o.disabledClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var mp = new MobilePersona(this),
|
||||||
|
states = mp.states();
|
||||||
|
if ($persona.hasClass(o.activeClass)) {
|
||||||
|
// Hide persona.
|
||||||
|
$persona.removeClass(o.activeClass);
|
||||||
|
dispatchPersonaEvent('ResetPersona', e.target,
|
||||||
|
states.cancelled);
|
||||||
|
} else {
|
||||||
|
// Hide other active personas.
|
||||||
|
$('.' + o.activeClass).each(function() {
|
||||||
|
$(this).find('[data-browsertheme]').trigger('click');
|
||||||
|
});
|
||||||
|
// Load persona.
|
||||||
|
$persona.addClass(o.activeClass);
|
||||||
|
states.loading();
|
||||||
|
dispatchPersonaEvent('PreviewPersona', e.target, states.previewing);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Should be called on an anchor. */
|
||||||
|
$.fn.personasButton = function(trigger, callback) {
|
||||||
|
$(this).closest('.persona').click(function(e) {
|
||||||
|
dispatchPersonaEvent('SelectPersona', e.currentTarget, callback);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
|
@ -47,7 +47,9 @@
|
||||||
'lite': gettext("Experimental <span>(Learn More)</span>"),
|
'lite': gettext("Experimental <span>(Learn More)</span>"),
|
||||||
'badApp': format(gettext("Not Available for {0}"), z.appName),
|
'badApp': format(gettext("Not Available for {0}"), z.appName),
|
||||||
'badPlatform': format(gettext("Not Available for {0}"), z.platformName),
|
'badPlatform': format(gettext("Not Available for {0}"), z.platformName),
|
||||||
'experimental': gettext("Experimental")
|
'experimental': gettext("Experimental"),
|
||||||
|
'personasTooOld': format(gettext("Personas Require Newer Version of {0}"), z.appName),
|
||||||
|
'personasLearnMore': format(gettext("Personas Require {0}"), z.appName)
|
||||||
};
|
};
|
||||||
|
|
||||||
function Button(el) {
|
function Button(el) {
|
||||||
|
@ -86,6 +88,9 @@
|
||||||
versionPlatformCheck();
|
versionPlatformCheck();
|
||||||
|
|
||||||
this.actionQueue.push([0, function() {
|
this.actionQueue.push([0, function() {
|
||||||
|
if (self.classes.persona) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var href = activeInstaller.attr('href'),
|
var href = activeInstaller.attr('href'),
|
||||||
hash = hashes[href],
|
hash = hashes[href],
|
||||||
attr = self.attr,
|
attr = self.attr,
|
||||||
|
@ -187,9 +192,7 @@
|
||||||
platformer = !!b.find('.platform').length,
|
platformer = !!b.find('.platform').length,
|
||||||
platformSupported = !platformer || dom.buttons.filter("." + z.platform).length,
|
platformSupported = !platformer || dom.buttons.filter("." + z.platform).length,
|
||||||
appSupported = z.appMatchesUserAgent && attr.min && attr.max,
|
appSupported = z.appMatchesUserAgent && attr.min && attr.max,
|
||||||
olderBrowser, newerBrowser,
|
|
||||||
canInstall = true;
|
canInstall = true;
|
||||||
|
|
||||||
if (!attr.search) {
|
if (!attr.search) {
|
||||||
// min and max only exist if the add-on is compatible with request[APP].
|
// min and max only exist if the add-on is compatible with request[APP].
|
||||||
if (appSupported && platformSupported) {
|
if (appSupported && platformSupported) {
|
||||||
|
@ -202,13 +205,16 @@
|
||||||
if (self.tooOld) errors.push("tooOld");
|
if (self.tooOld) errors.push("tooOld");
|
||||||
if (self.tooNew) errors.push("tooNew");
|
if (self.tooNew) errors.push("tooNew");
|
||||||
} else {
|
} else {
|
||||||
if (!appSupported && !z.badBrowser) errors.push("badApp");
|
if (!z.appMatchesUserAgent && !z.badBrowser) {
|
||||||
|
errors.push("badApp");
|
||||||
|
canInstall = false;
|
||||||
|
}
|
||||||
if (!platformSupported) {
|
if (!platformSupported) {
|
||||||
errors.push("badPlatform");
|
errors.push("badPlatform");
|
||||||
dom.buttons.hide().eq(0).show();
|
dom.buttons.hide().eq(0).show();
|
||||||
}
|
|
||||||
canInstall = false;
|
canInstall = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (platformer) {
|
if (platformer) {
|
||||||
dom.self.find(format(".platform:not(.{0})", z.platform)).hide();
|
dom.self.find(format(".platform:not(.{0})", z.platform)).hide();
|
||||||
|
@ -226,6 +232,25 @@
|
||||||
self.actionQueue.push([1,z.eula.show]);
|
self.actionQueue.push([1,z.eula.show]);
|
||||||
z.eula.acceptButton.click(_pd(self.resumeInstall));
|
z.eula.acceptButton.click(_pd(self.resumeInstall));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (classes.persona) {
|
||||||
|
dom.buttons.removeClass("download").addClass("add");
|
||||||
|
var persona = new MobilePersona(b);
|
||||||
|
if ($.hasPersonas()) {
|
||||||
|
dom.buttons.text(gettext("Keep it"));
|
||||||
|
dom.buttons.personasButton("click",
|
||||||
|
persona.states().installed);
|
||||||
|
} else {
|
||||||
|
persona.buttons().disable();
|
||||||
|
dom.buttons.addClass("disabled");
|
||||||
|
if (z.appMatchesUserAgent) {
|
||||||
|
// Need upgrade.
|
||||||
|
errors.push("personasTooOld");
|
||||||
|
} else {
|
||||||
|
errors.push("personasLearnMore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (z.badBrowser) {
|
if (z.badBrowser) {
|
||||||
|
|
|
@ -1,35 +1,9 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var personas = $('.persona-preview');
|
var personas = $('.persona-preview');
|
||||||
if (!personas.length) return;
|
if (!personas.length) return;
|
||||||
|
personas.previewPersona();
|
||||||
personas.previewPersona(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Bubbles up persona event to tell Firefox to load a persona
|
|
||||||
**/
|
|
||||||
function dispatchPersonaEvent(aType, aNode)
|
|
||||||
{
|
|
||||||
var aliases = {'PreviewPersona': 'PreviewBrowserTheme',
|
|
||||||
'ResetPersona': 'ResetBrowserThemePreview',
|
|
||||||
'SelectPersona': 'InstallBrowserTheme'};
|
|
||||||
try {
|
|
||||||
if (!aNode.hasAttribute("data-browsertheme"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$(aNode).attr("persona", $(aNode).attr("data-browsertheme"));
|
|
||||||
|
|
||||||
var aliasEvent = aliases[aType];
|
|
||||||
var events = [aType, aliasEvent];
|
|
||||||
|
|
||||||
for (var i=0; i<events.length; i++) {
|
|
||||||
var event = events[i];
|
|
||||||
var eventObject = document.createEvent("Events");
|
|
||||||
eventObject.initEvent(event, true, false);
|
|
||||||
aNode.dispatchEvent(eventObject);
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds Personas preview events to the element.
|
* Binds Personas preview events to the element.
|
||||||
|
@ -37,29 +11,36 @@ function dispatchPersonaEvent(aType, aNode)
|
||||||
* Mouseenter - bubbles up PreviewPersona
|
* Mouseenter - bubbles up PreviewPersona
|
||||||
* Mouseleave - bubbles up ResetPersona
|
* Mouseleave - bubbles up ResetPersona
|
||||||
**/
|
**/
|
||||||
$.fn.previewPersona = function(resetOnClick) {
|
$.fn.previewPersona = function(o) {
|
||||||
if (resetOnClick) {
|
if (!$.hasPersonas()) {
|
||||||
$(this).click(function(e) {
|
return;
|
||||||
dispatchPersonaEvent('ResetPersona', e.originalTarget);
|
}
|
||||||
|
o = $.extend({
|
||||||
|
resetOnClick: true,
|
||||||
|
activeClass: 'persona-hover'
|
||||||
|
}, o || {});
|
||||||
|
var $this = $(this);
|
||||||
|
if (o.resetOnClick) {
|
||||||
|
$this.click(function(e) {
|
||||||
|
dispatchPersonaEvent('ResetPersona', e.target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
$this.hoverIntent({
|
||||||
$(this).hoverIntent({
|
|
||||||
interval: 100,
|
interval: 100,
|
||||||
over: function(e) {
|
over: function(e) {
|
||||||
$(this).closest('.persona').addClass('persona-hover');
|
$(this).closest('.persona').addClass(o.activeClass);
|
||||||
dispatchPersonaEvent('PreviewPersona', e.originalTarget);
|
dispatchPersonaEvent('PreviewPersona', e.target);
|
||||||
},
|
},
|
||||||
out: function(e) {
|
out: function(e) {
|
||||||
$(this).closest('.persona').removeClass('persona-hover');
|
$(this).closest('.persona').removeClass(o.activeClass);
|
||||||
dispatchPersonaEvent('ResetPersona', e.originalTarget);
|
dispatchPersonaEvent('ResetPersona', e.target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Should be called on an anchor. */
|
/* Should be called on an anchor. */
|
||||||
$.fn.personasButton = function(options) {
|
$.fn.personasButton = function(trigger, callback) {
|
||||||
var persona_wrapper = $(this).closest('.persona');
|
var persona_wrapper = $(this).closest('.persona');
|
||||||
persona_wrapper.hoverIntent({
|
persona_wrapper.hoverIntent({
|
||||||
interval: 100,
|
interval: 100,
|
||||||
|
@ -71,31 +52,12 @@ $.fn.personasButton = function(options) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
persona_wrapper.click(function(e) {
|
persona_wrapper.click(function(e) {
|
||||||
dispatchPersonaEvent('SelectPersona', e.currentTarget);
|
dispatchPersonaEvent('SelectPersona', e.currentTarget, callback);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
$.hasPersonas = function() {
|
|
||||||
if (!jQuery.browser.mozilla) return false;
|
|
||||||
|
|
||||||
// Fx 3.6 has lightweight themes (aka personas)
|
|
||||||
if (VersionCompare.compareVersions(
|
|
||||||
$.browser.version, '1.9.2') > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var body = document.getElementsByTagName("body")[0];
|
|
||||||
try {
|
|
||||||
var event = document.createEvent("Events");
|
|
||||||
event.initEvent("CheckPersonas", true, false);
|
|
||||||
body.dispatchEvent(event);
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
return body.getAttribute("personas") == "true";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vertical carousel component
|
// Vertical carousel component
|
||||||
// Based on jQuery Infinite Carousel
|
// Based on jQuery Infinite Carousel
|
||||||
// http://jqueryfordesigners.com/jquery-infinite-carousel/
|
// http://jqueryfordesigners.com/jquery-infinite-carousel/
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* Bubbles up persona event to tell Firefox to load a persona
|
||||||
|
**/
|
||||||
|
function dispatchPersonaEvent(aType, aNode, callback)
|
||||||
|
{
|
||||||
|
var aliases = {'PreviewPersona': 'PreviewBrowserTheme',
|
||||||
|
'ResetPersona': 'ResetBrowserThemePreview',
|
||||||
|
'SelectPersona': 'InstallBrowserTheme'};
|
||||||
|
try {
|
||||||
|
if (!aNode.hasAttribute("data-browsertheme"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$(aNode).attr("persona", $(aNode).attr("data-browsertheme"));
|
||||||
|
|
||||||
|
var aliasEvent = aliases[aType];
|
||||||
|
var events = [aType, aliasEvent];
|
||||||
|
|
||||||
|
for (var i=0; i<events.length; i++) {
|
||||||
|
var event = events[i];
|
||||||
|
var eventObject = document.createEvent("Events");
|
||||||
|
eventObject.initEvent(event, true, false);
|
||||||
|
aNode.dispatchEvent(eventObject);
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$.hasPersonas = function() {
|
||||||
|
if (!jQuery.browser.mozilla) return false;
|
||||||
|
|
||||||
|
// Fx 3.6 has lightweight themes (aka personas)
|
||||||
|
if (VersionCompare.compareVersions(
|
||||||
|
$.browser.version, '1.9.2') > -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = document.getElementsByTagName("body")[0];
|
||||||
|
try {
|
||||||
|
var event = document.createEvent("Events");
|
||||||
|
event.initEvent("CheckPersonas", true, false);
|
||||||
|
body.dispatchEvent(event);
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
return body.getAttribute("personas") == "true";
|
||||||
|
};
|
|
@ -468,6 +468,7 @@ MINIFY_BUNDLES = {
|
||||||
|
|
||||||
# Personas
|
# Personas
|
||||||
'js/lib/jquery.hoverIntent.min.js',
|
'js/lib/jquery.hoverIntent.min.js',
|
||||||
|
'js/zamboni/personas_core.js',
|
||||||
'js/zamboni/personas.js',
|
'js/zamboni/personas.js',
|
||||||
|
|
||||||
# Collections
|
# Collections
|
||||||
|
@ -520,6 +521,7 @@ MINIFY_BUNDLES = {
|
||||||
|
|
||||||
# Personas
|
# Personas
|
||||||
'js/lib/jquery.hoverIntent.min.js',
|
'js/lib/jquery.hoverIntent.min.js',
|
||||||
|
'js/zamboni/personas_core.js',
|
||||||
'js/zamboni/personas.js',
|
'js/zamboni/personas.js',
|
||||||
|
|
||||||
# Collections
|
# Collections
|
||||||
|
@ -548,6 +550,7 @@ MINIFY_BUNDLES = {
|
||||||
|
|
||||||
# Personas
|
# Personas
|
||||||
'js/lib/jquery.hoverIntent.min.js',
|
'js/lib/jquery.hoverIntent.min.js',
|
||||||
|
'js/zamboni/personas_core.js',
|
||||||
'js/zamboni/personas.js',
|
'js/zamboni/personas.js',
|
||||||
|
|
||||||
'js/zamboni/debouncer.js',
|
'js/zamboni/debouncer.js',
|
||||||
|
@ -598,7 +601,9 @@ MINIFY_BUNDLES = {
|
||||||
'js/zamboni/format.js',
|
'js/zamboni/format.js',
|
||||||
'js/zamboni/mobile_buttons.js',
|
'js/zamboni/mobile_buttons.js',
|
||||||
'js/zamboni/truncation.js',
|
'js/zamboni/truncation.js',
|
||||||
'js/zamboni/mobile.js',
|
'js/zamboni/personas_core.js',
|
||||||
|
'js/zamboni/mobile/personas.js',
|
||||||
|
'js/zamboni/mobile/general.js',
|
||||||
),
|
),
|
||||||
'zamboni/stats': (
|
'zamboni/stats': (
|
||||||
'js/lib/jquery-datepicker.js',
|
'js/lib/jquery-datepicker.js',
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<div class="get-fx-message">
|
<div class="get-fx-message">
|
||||||
{{ _('You need Firefox to install addons. <a href="http://mozilla.com/firefox">Learn More »</a>') }}
|
{{ _('You need Firefox to install add-ons. <a href="http://mozilla.com/firefox">Learn More »</a>') }}
|
||||||
</div>
|
</div>
|
||||||
{% block back_link %}
|
{% block back_link %}
|
||||||
<a href="{{ url('home') }}" id="home">
|
<a href="{{ url('home') }}" id="home">
|
||||||
|
|
Загрузка…
Ссылка в новой задаче