Personalized Recommendations for discopane (bug 606386)
This commit is contained in:
Родитель
921dc55c4e
Коммит
db9c53362f
|
@ -1,6 +1,6 @@
|
|||
<li class="panel">
|
||||
<div class="feature collection {{ cls }}">
|
||||
<h2>{{ title }}</h2>
|
||||
<h2>{{ title }}</h2>
|
||||
<ul class="addons">
|
||||
{% for addon in addons %}
|
||||
<li>
|
||||
|
|
|
@ -11,36 +11,40 @@
|
|||
{{ css('zamboni/discovery-pane') }}
|
||||
<base target="_blank" href="{{ settings.SITE_URL }}">
|
||||
</head>
|
||||
<body class="html-{{ DIR }} discovery-pane {{ request.APP.short }}"
|
||||
<body class="html-{{ DIR }} pane {{ request.APP.short }}"
|
||||
data-app="{{ request.APP.short }}"
|
||||
data-appname="{{ app }}"
|
||||
data-appid="{{ request.APP.id }}"
|
||||
data-anonymous="{{ (not request.user.is_authenticated())|json }}"
|
||||
data-readonly="{{ settings.READ_ONLY|json }}"
|
||||
data-media-url="{{ MEDIA_URL }}">
|
||||
data-media-url="{{ MEDIA_URL }}"
|
||||
data-services-url="{{ settings.SERVICES_URL }}"
|
||||
data-recs-url="{{ url('discovery.recs') }}">
|
||||
<header>
|
||||
<section id="intro">
|
||||
<h1><img src="{{ MEDIA_URL }}img/zamboni/discovery_pane/logo-addons.png"
|
||||
width="87" height="82">{{ _('What are Add-ons?') }}</h1>
|
||||
<p>
|
||||
{% trans %}
|
||||
Add-ons are applications that let you personalize {{ app }} with extra
|
||||
functionality or style. Try a time-saving sidebar, a weather notifier,
|
||||
or a themed look to make {{ app }} your own.
|
||||
{% endtrans %}
|
||||
<a href="{{ url('home') }}" class="button">{{ _('Learn More') }}</a>
|
||||
</p>
|
||||
<h1><img src="{{ MEDIA_URL }}img/zamboni/discovery_pane/logo-addons.png"
|
||||
width="87" height="82">{{ _('What are Add-ons?') }}</h1>
|
||||
<p>
|
||||
{% trans %}
|
||||
Add-ons are applications that let you personalize {{ app }} with
|
||||
extra functionality or style. Try a time-saving sidebar, a weather
|
||||
notifier, or a themed look to make {{ app }} your own.
|
||||
{% endtrans %}
|
||||
<a href="{{ url('home') }}" class="button">{{ _('Learn More') }}</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{% if user.is_authenticated() %}
|
||||
<section id="my-account">
|
||||
<p>{{ _('Welcome, {0}')|f(request.amo_user.welcome_name) }}</p>
|
||||
<div>
|
||||
<a href="{{ url('users.edit') }}">{{ _('My Profile') }}</a>
|
||||
•
|
||||
<a href="{{ url('collections.user', request.amo_user.username) }}">
|
||||
{{ _('My Collections') }}</a>
|
||||
</div>
|
||||
<p>{{ _('Hi, {0} ({1})')|f(request.amo_user.welcome_name,
|
||||
request.amo_user.username) }}</p>
|
||||
<ul>
|
||||
<li><a href="{{ url('users.edit') }}">{{ _('Your Profile') }}</a></li>
|
||||
<li><a href="{{ url('collections.detail', request.amo_user.username,
|
||||
'favorites') }}">{{ _('Your Favorites') }}</a></li>
|
||||
<li><a href="{{ url('collections.user', request.amo_user.username) }}">{{ _('My Collections') }}</a></li>
|
||||
</ul>
|
||||
<p id="logout"><a href="{{ remora_url('/users/logout') }}">{{ _('Log out') }}</a></p>
|
||||
</section>
|
||||
{% else %}
|
||||
<section id="mission">
|
||||
|
@ -60,6 +64,26 @@
|
|||
|
||||
<section id="main">
|
||||
|
||||
<section id="recs">
|
||||
<div class="header">
|
||||
<h2>
|
||||
{{ _('Recommended for You') }}
|
||||
<a href="{{ url('pages.faq')|
|
||||
urlparams('personal-recommendations') }}">
|
||||
{{ _('What is this?') }}</a>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="gallery-wrap">
|
||||
<ul id="nav-recs">
|
||||
<li class="nav-prev"><a href="#" class="prev">{{ _('Previous') }}</a></li>
|
||||
<li class="nav-next"><a href="#" class="next">{{ _('Next') }}</a></li>
|
||||
</ul>
|
||||
<div class="gallery">
|
||||
<ul class="slider rec-addons"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="main-feature">
|
||||
<ul id="nav-features">
|
||||
<li class="nav-prev"><a href="#" class="prev">{{ _('Previous') }}</a></li>
|
||||
|
@ -104,20 +128,11 @@
|
|||
{{ _('See all themes and Personas') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="help">
|
||||
This page isn't finished quite yet; look for more
|
||||
improvements coming soon!
|
||||
<!--
|
||||
{% trans -%}
|
||||
Need help with an add-on?
|
||||
<a href="#"><strong>Get support</strong></a>
|
||||
{%- endtrans %}
|
||||
-->
|
||||
</p>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<script src="{{ url('jsi18n') }}/build:{{ BUILD_ID_JS }}"></script>
|
||||
{{ js('zamboni/discovery-pane') }}
|
||||
|
||||
</body>
|
||||
|
|
|
@ -181,7 +181,6 @@ class TestModuleAdmin(test_utils.TestCase):
|
|||
form = DiscoveryModuleForm(d)
|
||||
assert form.errors['locales']
|
||||
|
||||
|
||||
def test_discovery_module_form_dedupe(self):
|
||||
d = dict(app=amo.FIREFOX.id, module='xx', locales='en-US he he fa fa')
|
||||
form = DiscoveryModuleForm(d)
|
||||
|
|
|
@ -12,6 +12,7 @@ import jingo
|
|||
import amo.utils
|
||||
import api.utils
|
||||
import api.views
|
||||
from amo.decorators import post_required
|
||||
from addons.decorators import addon_view_factory
|
||||
from addons.models import Addon
|
||||
from browse.views import personas_listing
|
||||
|
@ -111,6 +112,7 @@ def _sync_db_and_registry(qs, app):
|
|||
|
||||
|
||||
@csrf_exempt
|
||||
@post_required
|
||||
def recommendations(request, limit=5):
|
||||
"""
|
||||
Figure out recommended add-ons for an anonymous user based on POSTed guids.
|
||||
|
@ -118,9 +120,6 @@ def recommendations(request, limit=5):
|
|||
POST body looks like {"guids": [...]} with an optional "token" key if
|
||||
they've been here before.
|
||||
"""
|
||||
if request.method != 'POST':
|
||||
return http.HttpResponseNotAllowed(['POST'])
|
||||
|
||||
try:
|
||||
POST = json.loads(request.raw_post_data)
|
||||
guids = POST['guids']
|
||||
|
|
|
@ -17,7 +17,7 @@ html {
|
|||
|
||||
body {
|
||||
font: 12px/1.33 "Lucida Grande", "Lucida Sans", Helvetica, Arial, sans-serif;
|
||||
padding: 0 10px 3em;
|
||||
padding: 10px 10px 3em;
|
||||
margin: 0 auto;
|
||||
color: #373d48;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.3);
|
||||
|
@ -66,7 +66,8 @@ section > section {
|
|||
float: right;
|
||||
}
|
||||
|
||||
#main > section {
|
||||
#main > section,
|
||||
#sub > section {
|
||||
padding: 10px;
|
||||
margin: 0 0 10px;
|
||||
border-radius: 8px;
|
||||
|
@ -81,20 +82,24 @@ section > section {
|
|||
float: left;
|
||||
}
|
||||
|
||||
#sub > section {
|
||||
padding: 10px;
|
||||
margin: 0 0 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
margin: 0 0 10px;
|
||||
border: solid #a8b8d1;
|
||||
border-width: 0 1px;
|
||||
border-radius: 0 0 8px 8px;
|
||||
border: 1px solid #a8b8d1;
|
||||
border-bottom-width: 0;
|
||||
border-radius: 8px;
|
||||
background: -moz-linear-gradient(top, #fff 0, #ecf1f7 100%);
|
||||
box-shadow: inset 0 -3px 0 rgba(58,78,103,0.05), 0 3px 0 rgba(175,195,220,.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.recs header {
|
||||
float: right;
|
||||
margin-top: -1px;
|
||||
width: 24%;
|
||||
width: -moz-calc(24% - 2px);
|
||||
}
|
||||
|
||||
.html-rtl .recs header {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* @Clear floats *********/
|
||||
|
@ -124,6 +129,10 @@ header:after,
|
|||
border-left: 1px inset rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
.recs #intro {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#intro h1 {
|
||||
margin: .5em 0 .25em;
|
||||
clear: right;
|
||||
|
@ -159,12 +168,79 @@ header:after,
|
|||
left: 0;
|
||||
}
|
||||
|
||||
/* @group Recommendations */
|
||||
#main #recs {
|
||||
display: none;
|
||||
min-height: 200px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.recs #main #recs {
|
||||
display: block;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.recs #recs .gallery-wrap {
|
||||
background-color: #d4edea;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.recs #recs .msg {
|
||||
display: table;
|
||||
height: 160px;
|
||||
width: 100%;
|
||||
}
|
||||
.recs #recs .msg p {
|
||||
display: table-cell;
|
||||
font-size: 15px;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.recs #recs .loading p {
|
||||
margin-bottom: 0;
|
||||
padding-top: 78px;
|
||||
}
|
||||
.recs #recs .loading p > span {
|
||||
background: url(../../img/zamboni/discovery_pane/loading.gif) 0 0 no-repeat;
|
||||
display: inline-block;
|
||||
opacity: 0.25;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
position: absolute;
|
||||
top: 63px;
|
||||
left: 50%;
|
||||
left: -moz-calc(50% - 48px);
|
||||
}
|
||||
/* @end */
|
||||
|
||||
/* @Mission, @My-account *********/
|
||||
#mission, #my-account {
|
||||
padding: 30px 2% 10px;
|
||||
margin: 0;
|
||||
background: -moz-linear-gradient(top, #fff 0, #ecf1f7 100%);
|
||||
margin: 0 0 0 -10px;
|
||||
padding: 10px;
|
||||
float: right;
|
||||
width: 20%;
|
||||
width: 22%;
|
||||
width: -moz-calc(24% - 22px);
|
||||
}
|
||||
|
||||
#my-account {
|
||||
background:
|
||||
url(../../img/zamboni/discovery_pane/bg-home.png) no-repeat 100% 100%,
|
||||
-moz-linear-gradient(top, #fff 0, #ecf1f7 100%);
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
.no-recs #my-account {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.recs #mission,
|
||||
.recs #my-account {
|
||||
border-left-width: 0;
|
||||
float: left;
|
||||
margin-left: 0;
|
||||
padding-left: 10px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.html-rtl #mission,
|
||||
|
@ -172,22 +248,41 @@ header:after,
|
|||
float: left;
|
||||
}
|
||||
|
||||
.html-rtl .recs #mission,
|
||||
.html-rtl .recs #my-account {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#mission p,
|
||||
#my-account p {
|
||||
font-size: 15px;
|
||||
line-height: 1.1;
|
||||
margin: 0 0 .5em;
|
||||
}
|
||||
|
||||
#mission p,
|
||||
#my-account p,
|
||||
#my-account ul {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
#my-account ul {
|
||||
color: #76787b;
|
||||
line-height: 1.5;
|
||||
list-style: disc inside;
|
||||
}
|
||||
|
||||
#my-account p#logout {
|
||||
font-size: 11px;
|
||||
margin: 0 0 0 13px;
|
||||
}
|
||||
|
||||
#mission a,
|
||||
#mission strong,
|
||||
#my-account a,
|
||||
#my-account strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#mission #download-count,
|
||||
#my-account #download-count {
|
||||
#mission #download-count {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
@ -230,28 +325,26 @@ header:after,
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
.slider {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panel {
|
||||
width: 100%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#nav-features {
|
||||
#nav-features,
|
||||
#nav-recs {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
display: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#main-feature.js #nav-features {
|
||||
#main-feature.js #nav-features,
|
||||
.recs #recs #nav-recs.js {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#nav-features a {
|
||||
#nav-features a,
|
||||
#nav-recs a {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin: 1px;
|
||||
|
@ -268,8 +361,14 @@ header:after,
|
|||
-moz-transition-timing-function: ease-out;
|
||||
}
|
||||
|
||||
#nav-recs a {
|
||||
height: 161px;
|
||||
}
|
||||
|
||||
#nav-features a:hover,
|
||||
#nav-features a:active {
|
||||
#nav-features a:active,
|
||||
#nav-recs a:hover,
|
||||
#nav-recs a:active {
|
||||
opacity: 1;
|
||||
width: 7%;
|
||||
-moz-transition-property: opacity, width, background-color;
|
||||
|
@ -277,7 +376,8 @@ header:after,
|
|||
-moz-transition-timing-function: ease-out;
|
||||
}
|
||||
|
||||
#nav-features a:focus {
|
||||
#nav-features a:focus,
|
||||
#nav-recs a:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
@ -356,11 +456,18 @@ header:after,
|
|||
|
||||
/* @Collection *********/
|
||||
.collection h2,
|
||||
#featured-addons h2 {
|
||||
#featured-addons h2,
|
||||
#recs .header h2,
|
||||
#recs .gallery {
|
||||
max-width: 650px;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
#recs .header h2,
|
||||
#recs .gallery {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.collection .more {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -400,7 +507,8 @@ ul.addons {
|
|||
margin-right: 0;
|
||||
}
|
||||
|
||||
.addons li > a {
|
||||
.addons li > a,
|
||||
.rec-addons li > a {
|
||||
display: block;
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
|
@ -431,7 +539,8 @@ ul.addons {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.addons h3 {
|
||||
.addons h3,
|
||||
.rec-addons h3 {
|
||||
font-size: 14px;
|
||||
line-height: 1.1;
|
||||
font-weight: bold;
|
||||
|
@ -441,12 +550,16 @@ ul.addons {
|
|||
|
||||
.addons li > a:hover h3,
|
||||
.addons li > a:focus h3,
|
||||
.addons li > a:active h3 {
|
||||
.addons li > a:active h3,
|
||||
.rec-addons li > a:hover h3,
|
||||
.rec-addons li > a:focus h3,
|
||||
.rec-addons li > a:active h3 {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.addons p.desc {
|
||||
-moz-box-flex:1;
|
||||
.addons p.desc,
|
||||
.rec-addons p.desc {
|
||||
-moz-box-flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 11px;
|
||||
text-align: left;
|
||||
|
@ -454,11 +567,13 @@ ul.addons {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.html-rtl .addons p.desc {
|
||||
.html-rtl .addons p.desc,
|
||||
.html-rtl .rec-addons p.desc {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.addons img {
|
||||
.addons img,
|
||||
.rec-addons img {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
|
@ -467,10 +582,11 @@ ul.addons {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
#recs .header,
|
||||
#sub .featured h2,
|
||||
#more-ways h2 {
|
||||
margin: -10px -10px 0;
|
||||
padding: .45em 10px .45em 10px;
|
||||
padding: 0.45em 10px;
|
||||
background: -moz-linear-gradient(top, #fff 0, #ecf1f7 100%);
|
||||
box-shadow: inset 0 -3px 0 rgba(58,78,103,0.05), 0 3px 0 rgba(175,195,220,.3);
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
@ -478,7 +594,14 @@ ul.addons {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#sub .featured ul {
|
||||
#recs .header {
|
||||
margin: 0;
|
||||
padding: 0.45em 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#sub .featured ul,
|
||||
#more-ways ul {
|
||||
margin: 0 0 -10px;
|
||||
}
|
||||
|
||||
|
@ -491,7 +614,8 @@ ul.addons {
|
|||
#sub #featured-personas li {
|
||||
border-bottom-color: #666;
|
||||
}
|
||||
#sub .featured li:last-child {
|
||||
#sub .featured li:last-child,
|
||||
#more-ways ul li:last-child {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
|
@ -562,12 +686,28 @@ ul.addons {
|
|||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
#sub .featured .all {
|
||||
float: right;
|
||||
display: block;
|
||||
#sub .featured .all,
|
||||
#recs .header h2 a {
|
||||
line-height: 24px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#sub .featured .all {
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#recs .header h2 a {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.html-rtl #recs .header h2 a {
|
||||
float: left;
|
||||
height: 18px;
|
||||
line-height: 25px;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Personas */
|
||||
|
@ -588,7 +728,6 @@ ul.addons {
|
|||
|
||||
/* @More ways to customize *********/
|
||||
#more-ways ul {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
clear: right;
|
||||
}
|
||||
|
@ -622,14 +761,6 @@ ul.addons {
|
|||
background: transparent url("../../img/zamboni/discovery_pane/bg-morepersonas.jpg") 70% 50% no-repeat;
|
||||
}
|
||||
|
||||
#more-ways .help {
|
||||
margin: 0 -10px -10px;
|
||||
padding: .75em 12px;
|
||||
background: -moz-linear-gradient(top, #fff 0, #ecf1f7 100%);
|
||||
box-shadow: inset 0 -3px 0 rgba(58,78,103,0.05);
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
|
||||
/* @Narrow *********/
|
||||
@media (max-width: 980px) {
|
||||
body {
|
||||
|
@ -637,10 +768,37 @@ ul.addons {
|
|||
min-width: 620px;
|
||||
}
|
||||
|
||||
#main,
|
||||
#sub {
|
||||
width: 100%;
|
||||
.no-recs header #mission,
|
||||
.no-recs header #my-account {
|
||||
}
|
||||
.no-recs header #my-account {
|
||||
border-radius: 0 0 8px 8px;
|
||||
border-top: 1px inset rgba(0,0,0,0.15);
|
||||
margin-left: 0;
|
||||
margin-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
width: -moz-calc(100% - 20px);
|
||||
}
|
||||
.recs header #my-account {
|
||||
border-radius: 8px;
|
||||
border-top-width: 0;
|
||||
margin-top: 0;
|
||||
padding-bottom: 10px;
|
||||
width: -moz-calc(100% - 20px);
|
||||
}
|
||||
|
||||
.recs header {
|
||||
float: none;
|
||||
width: auto;
|
||||
width: -moz-calc(100% - 2px);
|
||||
}
|
||||
|
||||
#main,
|
||||
#sub,
|
||||
#mission,
|
||||
#my-account {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#main #main-feature {
|
||||
|
@ -651,11 +809,6 @@ ul.addons {
|
|||
height: 270px;
|
||||
}
|
||||
|
||||
#mission,
|
||||
#my-account {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#intro {
|
||||
border: 0;
|
||||
width: auto;
|
||||
|
@ -674,7 +827,6 @@ ul.addons {
|
|||
margin-right: 0;
|
||||
width: -moz-calc(100% / 3 - 22px - 1%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* @Detail page *********/
|
||||
|
@ -1020,6 +1172,11 @@ a#lightbox-secNav-btnClose {
|
|||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.recs #recs .gallery {
|
||||
overflow: hidden;
|
||||
height: 163px;
|
||||
}
|
||||
|
||||
#images + .addon-info {
|
||||
margin-top: 158px;
|
||||
}
|
||||
|
@ -1033,11 +1190,11 @@ a#lightbox-secNav-btnClose {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#images .panel {
|
||||
#images .panel,
|
||||
.recs #recs .panel {
|
||||
width: 33%;
|
||||
float: left;
|
||||
margin: 0 0 10px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#images.js .panel {
|
||||
|
@ -1051,6 +1208,14 @@ a#lightbox-secNav-btnClose {
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
.recs #recs .gallery .panel {
|
||||
width: 30%;
|
||||
margin: 10px 5% 10px 0;
|
||||
}
|
||||
.recs #recs .gallery .panel:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#images a img {
|
||||
border: 1px solid #a9a9a9;
|
||||
max-width: 95%;
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 728 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 14 KiB |
|
@ -1,14 +1,148 @@
|
|||
$(document).ready(function(){
|
||||
$("body").addClass("no-recs");
|
||||
initRecs();
|
||||
initDescs();
|
||||
});
|
||||
|
||||
// How many add-ons they need to have before we start revealing more.
|
||||
var MIN_ADDONS = 3;
|
||||
|
||||
var guids = JSON.parse(location.hash.slice(1));
|
||||
|
||||
/* Move Featured Add-ons in place of What Are Add-ons, reveal Recs. */
|
||||
if (guids.length > MIN_ADDONS) {
|
||||
$('#featured-addons').insertBefore('#what-are-addons');
|
||||
$('#what-are-addons, #recs').toggle();
|
||||
function initDescs() {
|
||||
// Trim the description text to fit.
|
||||
$("p.desc").vtruncate();
|
||||
$(window).resize(debounce(function() {
|
||||
$("p.desc").vtruncate();
|
||||
}, 200));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function initRecs() {
|
||||
var services_url = document.body.getAttribute("data-services-url");
|
||||
|
||||
// Where all the current recommendations data is kept.
|
||||
var datastore = {};
|
||||
|
||||
// How many add-ons they need to have before we start revealing more.
|
||||
var MIN_ADDONS = 3;
|
||||
|
||||
// GUIDs of installed add-ons.
|
||||
var guids = [],
|
||||
token;
|
||||
if (location.hash) {
|
||||
guids = JSON.parse(location.hash.slice(1));
|
||||
} else {
|
||||
// If the user has opted out of recommendations, clear out any
|
||||
// existing recommendations.
|
||||
localStorage.removeItem("discopane-recs");
|
||||
localStorage.removeItem("discopane-guids");
|
||||
}
|
||||
|
||||
function populateRecs() {
|
||||
if (datastore.addons.length) {
|
||||
$.each(datastore.addons, function(i, addon) {
|
||||
var li = ['<li class="panel">'];
|
||||
var url = addon.learnmore;
|
||||
url = services_url + url.slice(url.indexOf("/", 7));
|
||||
li.push(
|
||||
'<a href="' + url + '" target="_self">',
|
||||
'<img src="' + addon.icon + '" width="32" height="32">',
|
||||
"<h3>" + addon.name + "</h3>",
|
||||
'<p class="desc">' + addon.summary + "</p>",
|
||||
"</a></li>");
|
||||
$("#recs .slider").append(li.join(""));
|
||||
});
|
||||
$("#recs .gallery").fadeIn("slow").addClass("js").jCarouselLite({
|
||||
btnNext: "#recs .nav-next a",
|
||||
btnPrev: "#recs .nav-prev a",
|
||||
visible: 3,
|
||||
circular: false,
|
||||
});
|
||||
$("#recs #nav-recs").fadeIn("slow").addClass("js");
|
||||
var galleryWidth = $("#recs .gallery").width();
|
||||
$("#recs .gallery .panel").css({
|
||||
'width': 0.3 * galleryWidth,
|
||||
'margin-right': 0.05 * galleryWidth
|
||||
});
|
||||
initDescs();
|
||||
} else {
|
||||
var addons_url = $("#more-addons a").attr("href");
|
||||
var msg = format(gettext(
|
||||
"Sorry, we couldn't find any recommendations for you.<br>" +
|
||||
'Please visit the <a href="{0}">add-ons site</a> to ' +
|
||||
"find an add-on that's right for you."), [addons_url]);
|
||||
$("#recs .gallery").hide();
|
||||
$("#recs").append('<div class="msg"><p>' + msg + "</p></div>");
|
||||
}
|
||||
}
|
||||
|
||||
// Hide "What are Add-ons?" and show "Recommended for You" module.
|
||||
if (guids.length > MIN_ADDONS) {
|
||||
$("body").removeClass("no-recs").addClass("recs");
|
||||
|
||||
var cacheObject = localStorage.getItem("discopane-recs");
|
||||
if (cacheObject) {
|
||||
// Load local data.
|
||||
cacheObject = JSON.parse(cacheObject);
|
||||
if (cacheObject) {
|
||||
datastore = cacheObject;
|
||||
token = cacheObject.token;
|
||||
}
|
||||
}
|
||||
|
||||
// Get new recommendations if there are no saved recommendations or
|
||||
// if the user has new installed add-ons.
|
||||
var findRecs = !cacheObject;
|
||||
var updateRecs = (
|
||||
cacheObject &&
|
||||
localStorage.getItem("discopane-guids") != guids.toString()
|
||||
);
|
||||
if (findRecs || updateRecs) {
|
||||
var msg;
|
||||
if (findRecs) {
|
||||
msg = gettext("Finding recommendations…");
|
||||
} else if (updateRecs) {
|
||||
msg = gettext("Updating recommendations…");
|
||||
}
|
||||
$("#recs .gallery").hide();
|
||||
$("#recs").append('<div class="msg loading"><p><span></span>' +
|
||||
msg + "</p></div>");
|
||||
|
||||
var data = {"guids": guids};
|
||||
if (token) {
|
||||
data["token"] = token;
|
||||
}
|
||||
$.ajax({
|
||||
url: document.body.getAttribute("data-recs-url"),
|
||||
type: "post",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "text",
|
||||
success: function(raw_data) {
|
||||
$("#recs .loading").remove();
|
||||
datastore = JSON.parse(raw_data);
|
||||
populateRecs();
|
||||
localStorage.setItem("discopane-recs", raw_data);
|
||||
localStorage.setItem("discopane-guids", guids);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
populateRecs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Python(ish) string formatting:
|
||||
* >>> format('{0}', ['zzz'])
|
||||
* "zzz"
|
||||
* >>> format('{0}{1}', 1, 2)
|
||||
* "12"
|
||||
* >>> format('{x}', {x: 1})
|
||||
* "1"
|
||||
*/
|
||||
var format = (function() {
|
||||
var re = /\{([^}]+)\}/g;
|
||||
return function(s, args) {
|
||||
if (!args) return;
|
||||
if (!(args instanceof Array || args instanceof Object))
|
||||
args = Array.prototype.slice.call(arguments, 1);
|
||||
return s.replace(re, function(_, match){ return args[match]; });
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -49,18 +49,22 @@ $.fn.jCarouselLite = function(o) {
|
|||
var li = $(".panel", ul), itemLength = li.size(), curr = o.start;
|
||||
div.css("visibility", "visible");
|
||||
|
||||
li.css({overflow: "hidden", "float": o.vertical ? "none" : "left"});
|
||||
li.css({"float": o.vertical ? "none" : "left"});
|
||||
ul.css({margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1"});
|
||||
div.css({overflow: "hidden", position: "relative", "z-index": "2", left: "0"});
|
||||
|
||||
var liSize = o.vertical ? height(li) : width(li); // Full li size(incl margin)-Used for animation
|
||||
var ulSize = liSize * itemLength; // size of full ul(total length, not just for the visible items)
|
||||
var divSize = liSize * v; // size of entire div(total length for just the visible items)
|
||||
// Full li size (including margin, used for animation).
|
||||
var liSize = o.vertical ? outHeight(li) : outWidth(li);
|
||||
// Size of full ul (total length, not just for the visible items).
|
||||
var ulSize = liSize * itemLength;
|
||||
// Size of entire div (total length, for only the visible items).
|
||||
var divSize = liSize * v;
|
||||
|
||||
li.css({width: li.width(), height: li.height()});
|
||||
ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
|
||||
|
||||
div.css(sizeCss, divSize+"px"); // Width of the DIV. length of visible images
|
||||
// Width of the DIV. length of visible images.
|
||||
div.css(sizeCss, divSize+"px");
|
||||
|
||||
if(o.btnPrev) {
|
||||
$(o.btnPrev).click(function() {
|
||||
|
@ -151,8 +155,16 @@ $.fn.jCarouselLite = function(o) {
|
|||
$(window).resize(function(){
|
||||
panelWidth = $("#main").width();
|
||||
$("#main-feature, #main-feature .panel, #images").css({width: panelWidth});
|
||||
$("#images .panel").css({width: panelWidth/3 - 10});
|
||||
liSize = o.vertical ? height(li) : width(li);
|
||||
$("#recs .gallery").css({width: panelWidth - 2});
|
||||
$("#recs .gallery .panel, #images .panel").css({width: panelWidth / 3 - 10});
|
||||
if ($(".pane").length) {
|
||||
var galleryWidth = $("#recs .gallery").width();
|
||||
$("#recs .gallery .panel").css({
|
||||
'width': 0.3 * galleryWidth,
|
||||
'margin-right': 0.05 * galleryWidth
|
||||
});
|
||||
}
|
||||
liSize = o.vertical ? outHeight(li) : outWidth(li);
|
||||
ul.css(sizeCss, ulSize+"px").css(animCss, -(curr*liSize));
|
||||
});
|
||||
|
||||
|
@ -162,10 +174,14 @@ $.fn.jCarouselLite = function(o) {
|
|||
function css(el, prop) {
|
||||
return parseInt($.css(el[0], prop)) || 0;
|
||||
};
|
||||
function width(el) {
|
||||
|
||||
// jQuery's .outerWidth() and .outerWidth() methods include padding,
|
||||
// which we don't want.
|
||||
function outWidth(el) {
|
||||
return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
|
||||
};
|
||||
function height(el) {
|
||||
|
||||
function outHeight(el) {
|
||||
return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
|
||||
};
|
||||
|
||||
|
@ -177,13 +193,13 @@ $(document).ready(function(){
|
|||
|
||||
// Set up the carousel.
|
||||
$("#main-feature").fadeIn("slow").addClass("js").jCarouselLite({
|
||||
btnNext: ".nav-next a",
|
||||
btnPrev: ".nav-prev a",
|
||||
btnNext: "#main-feature .nav-next a",
|
||||
btnPrev: "#main-feature .nav-prev a",
|
||||
visible: 1
|
||||
});
|
||||
$("#images").fadeIn("slow").addClass("js").jCarouselLite({
|
||||
btnNext: ".nav-next a",
|
||||
btnPrev: ".nav-prev a",
|
||||
btnNext: "#images .nav-next a",
|
||||
btnPrev: "#images .nav-prev a",
|
||||
visible: 3,
|
||||
circular: false
|
||||
});
|
||||
|
@ -191,10 +207,13 @@ $(document).ready(function(){
|
|||
|
||||
// Set up the lightbox.
|
||||
var lb_baseurl = document.body.getAttribute("data-media-url") + "img/jquery-lightbox/";
|
||||
$("li.panel a[rel=jquery-lightbox]").lightBox({
|
||||
$("#images li.panel a[rel=jquery-lightbox]").lightBox({
|
||||
overlayOpacity: 0.6,
|
||||
imageBlank: lb_baseurl + "lightbox-blank.gif",
|
||||
imageLoading: lb_baseurl + "lightbox-ico-loading.gif",
|
||||
imageBtnClose: "",
|
||||
imageBtnPrev: "",
|
||||
imageBtnNext: "",
|
||||
containerResizeSpeed: 350
|
||||
});
|
||||
|
||||
|
@ -202,16 +221,9 @@ $(document).ready(function(){
|
|||
// is liquid, so we'll set the width in px on pageload and on resize).
|
||||
var panelWidth = $("#main").width();
|
||||
$("#main-feature, #main-feature .panel, #images").css({width: panelWidth});
|
||||
// We show three images at a time, so the width of each is roughly 1/3.
|
||||
$("#images .panel").css({width: panelWidth/3 - 10});
|
||||
|
||||
if ($(".discovery-pane").length) {
|
||||
// Trim the description text to fit.
|
||||
$("p.desc").vtruncate();
|
||||
$(window).resize(debounce(function() {
|
||||
$("p.desc").vtruncate();
|
||||
}, 200));
|
||||
}
|
||||
// We show three images at a time, so the width of each is 1/3 minus a
|
||||
// right margin of 10px.
|
||||
$("#images .panel").css({width: panelWidth / 3 - 10});
|
||||
});
|
||||
|
||||
|
||||
|
@ -223,6 +235,6 @@ function debounce(fn, ms, ctxt) {
|
|||
clearTimeout(to);
|
||||
to = setTimeout(function() {
|
||||
fun.apply(ctx, args);
|
||||
},del);
|
||||
}, del);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -439,6 +439,7 @@ MINIFY_BUNDLES = {
|
|||
'js/zamboni/personas.js',
|
||||
|
||||
'js/zamboni/discovery_pane.js',
|
||||
'js/zamboni/discovery.js',
|
||||
),
|
||||
'zamboni/discovery-addons': (
|
||||
'js/zamboni/truncation.js',
|
||||
|
|
Загрузка…
Ссылка в новой задаче