This commit is contained in:
Alex Buchanan 2010-07-15 10:21:38 -07:00
Родитель 641cb4acc5
Коммит ae81a7c368
71 изменённых файлов: 39 добавлений и 4396 удалений

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

@ -1,78 +1,53 @@
{# TODO set fxcup to true on June 10th #}
{% set fxcup = true %}
{% if promobox %}
{% cache promobox.features() %}
<div class="section-teaser featured">
<div class="featured-inner">
<div class="teaser-header">
<ol>
{# TODO remove if blocks after the Firefox Cup promo ends #}
{% if fxcup %}
<li><a href="#t-firefox-cup">{{ _('Firefox Cup') }}</a></li>
{% else %}
<li><a href="#t-introduction">{{ _('Introduction') }}</a></li>
{% endif %}
<li><a href="#t-introduction">{{ _('Introduction') }}</a></li>
{% for feature in promobox.features() %}
<li><a href="#t-{{ feature.title|slugify }}">{{ feature.title }}</a></li>
{% endfor %}
</ol>
</div> {# teaser-header #}
<ol class="teaser-items">
{# TODO remove if blocks after the Firefox Cup promo ends #}
{% if fxcup %}
<li id="t-firefox-cup">
<div class="cta">
<h2>{{ _('Support your team in the Firefox Cup') }}</h2>
<li id="t-introduction">
<h2>{{ _('What are Add-ons?') }}</h2>
<div class="column-wrapper">
<div class="first column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/extras.gif"
alt="{{ _('Extras') }}">
</h3>
<p>
{% trans url=url('firefoxcup.index') %}
Dress up your Firefox in a Persona that shows off team spirit
and keep up with game scores using the FootieFox Add-on. See
it all on <a href="{{ url }}">Firefox Cup</a>.
{% endtrans %}
{% trans %}
<strong>Over 5000 free extras</strong> that let you customize and
extend Firefox to meet your needs.
{% endtrans %}
</p>
</div>
<a class="cover" href="{{ url('firefoxcup.index') }}">&nbsp;</a>
</li>
{% else %}
<li id="t-introduction">
<h2>{{ _('What are Add-ons?') }}</h2>
<div class="column-wrapper">
<div class="first column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/extras.gif"
alt="{{ _('Extras') }}">
</h3>
<p>
{% trans %}
<strong>Over 5000 free extras</strong> that let you customize and
extend Firefox to meet your needs.
{% endtrans %}
</p>
</div>
<div class="column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/themes.gif"
alt="{{ _('Themes') }}">
</h3>
<p>
{% trans %}
Toolbars, themes and search providers that
<strong>help you perform common tasks.</strong>
{% endtrans %}
</p>
</div>
<div class="column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/install.gif"
alt="{{ _('Install') }}">
</h3>
<p>
{% trans %}
<strong>Easy to install</strong> and keep up-to-date.
{% endtrans %}
</p>
</div>
<div class="column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/themes.gif"
alt="{{ _('Themes') }}">
</h3>
<p>
{% trans %}
Toolbars, themes and search providers that
<strong>help you perform common tasks.</strong>
{% endtrans %}
</p>
</div>
</li>
{% endif %}
<div class="column">
<h3><img src="{{ MEDIA_URL }}img/amo2009/illustrations/install.gif"
alt="{{ _('Install') }}">
</h3>
<p>
{% trans %}
<strong>Easy to install</strong> and keep up-to-date.
{% endtrans %}
</p>
</div>
</div>
</li>
{% set collections = promobox.collections() %}
{% for feature in promobox.features() %}
<li id="t-{{ feature.title|slugify }}" class="addon-view">

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

@ -1,202 +0,0 @@
# coding=utf8
from django.conf import settings
from tower import ugettext_lazy as _
tags = {
'all': [
'#firefoxcup',
'#fxcup',
'#worldcup',
'#football',
'#soccer',
'#south africa2010',
'#wcup2010'],
'af': [u'#Wêreldbeker'],
'ar': [u'كأس العالم', u'مونديال', u'المونديال', u'كأس العالم لكرة القدم'],
'da': ['#vm', 'Fodbold VM'],
'de': ['#wm'],
'es': ['#mundial'],
'fr': ['#mondial', '#coupedumonde'],
'it': ['#IlMondiale'],
'ja': [u'#W杯'],
'ko': [u'#월드컵'],
'nl': ['#wk', '#wereldbeker', '#oranje'],
'ru': [u'ЧМ'],
'sr': [u'Светско првенство'],
'sk': [u'Svetový pohár'],
'sl': [u'Svetovni pokal'],
}
# generic persona ID
# bug 569734
generic_persona = 223469
teams = [
{
'id': 'algeria',
'name': _('Algeria'),
'persona_id': 216601,
},
{
'id': 'argentina',
'name': _('Argentina'),
'persona_id': 216091,
},
{
'id': 'australia',
'name': _('Australia'),
'persona_id': 216602,
},
{
'id': 'brazil',
'name': _('Brazil'),
'persona_id': 216603,
},
{
'id': 'cameroon',
'name': _('Cameroon'),
'persona_id': 216605,
},
{
'id': 'chile',
'name': _('Chile'),
'persona_id': 216606,
},
{
'id': 'cote',
'name': _("Cote d'Ivoire"),
'persona_id': 216626,
},
{
'id': 'denmark',
'name': _('Denmark'),
'persona_id': 216608,
},
{
'id': 'england',
'name': _('England'),
'persona_id': 215499,
},
{
'id': 'france',
'name': _('France'),
'persona_id': 215503,
},
{
'id': 'germany',
'name': _('Germany'),
'persona_id': 215502,
},
{
'id': 'ghana',
'name': _('Ghana'),
'persona_id': 216610,
},
{
'id': 'greece',
'name': _('Greece'),
'persona_id': 216618,
},
{
'id': 'honduras',
'name': _('Honduras'),
'persona_id': 216624,
},
{
'id': 'italy',
'name': _('Italy'),
'persona_id': 215504,
},
{
'id': 'japan',
'name': _('Japan'),
'persona_id': 215506,
},
{
'id': 'mexico',
'name': _('Mexico'),
'persona_id': 216597,
},
{
'id': 'netherlands',
'name': _('Netherlands'),
'persona_id': 216093,
},
{
'id': 'korea-dpr',
'name': _('North Korea'),
'persona_id': 216630,
},
{
'id': 'new-zealand',
'name': _('New Zealand'),
'persona_id': 216627,
},
{
'id': 'nigeria',
'name': _('Nigeria'),
'persona_id': 216629,
},
{
'id': 'paraguay',
'name': _('Paraguay'),
'persona_id': 216631,
},
{
'id': 'portugal',
'name': _('Portugal'),
'persona_id': 216635,
},
{
'id': 'serbia',
'name': _('Serbia'),
'persona_id': 216641,
},
{
'id': 'slovakia',
'name': _('Slovakia'),
'persona_id': 216646,
},
{
'id': 'slovenia',
'name': _('Slovenia'),
'persona_id': 216648,
},
{
'id': 'south-africa',
'name': _('South Africa'),
'persona_id': 216652,
},
{
'id': 'korea-republic',
'name': _('South Korea'),
'persona_id': 216668,
},
{
'id': 'spain',
'name': _('Spain'),
'persona_id': 215498,
},
{
'id': 'switzerland',
'name': _('Switzerland'),
'persona_id': 216670,
},
{
'id': 'usa',
'name': _('United States'),
'persona_id': 215507,
},
{
'id': 'uruguay',
'name': _('Uruguay'),
'persona_id': 216672,
}]
for team in teams:
team['flag'] = '%simg/firefoxcup/flags/%s.png' % (settings.MEDIA_URL,
team['id'])
team['persona'] = None
twitter_languages = """
ar da de en es fa fi fr hu is it ja nl no pl pt ru sv th""".split()

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

@ -1,25 +0,0 @@
from django.core.cache import cache
import cronjobs
from addons.models import Persona
from .models import Stats
from . import tags, teams as teams_config
from . import twitter
@cronjobs.register
def firefoxcup_stats():
ids = [t['persona_id'] for t in teams_config]
for p in Persona.objects.filter(persona_id__in=ids):
Stats.objects.create(persona_id=p.persona_id, popularity=p.popularity)
@cronjobs.register
def firefoxcup_might_be_a_social_media_expert():
# A hacky lock for this job that expires after 5 minutes.
lock = 'fxcup-twitter-lock'
if cache.add(lock, 1, 60 * 5):
for lang in tags:
twitter.cache_tweets(lang)
cache.delete(lock)

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

@ -1,15 +0,0 @@
from django.db import models
from amo.models import ModelBase
class Stats(ModelBase):
"""
Keeps record of daily ADU counts for Firefox Cup personas.
Used to calculate 'Average Fans' over time of Firefox Cup campaign
"""
persona_id = models.PositiveIntegerField(db_index=True)
popularity = models.PositiveIntegerField()
class Meta(ModelBase.Meta):
db_table = 'stats_firefoxcup'

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

@ -1,183 +0,0 @@
{% extends 'base.html' %}
{% block title %}{{ _('Firefox Cup') }}{% endblock %}
{% block site_header %}{% endblock %}
{% block site_css %}
{{ css('firefoxcup/f') }}
{% endblock %}
{% block main_content %}
<div id="wrapper">
<div id="doc">
<ul id="header">
<li class="first"><a href="http://www.mozilla.com/">{{ _('Mozilla') }}</a></li>
<li><a href="http://addons.mozilla.org/">{{ _('Add-ons') }}</a></li>
<li><a href="http://support.mozilla.com/">{{ _('Support') }}</a></li>
<li>{% include 'includes/lang_switcher.html' %}</li>
</ul>
<div id="main-feature">
<h1><img src="{{ MEDIA_URL }}img/firefoxcup/logo.png" alt="{{ _('Firefox Cup') }}" /></h1>
<h2>{{ _('Install Personas to support your team and compete for the Firefox Cup.') }}</h2>
<div id="download">
<a href="http://www.mozilla.com/firefox/">
<span class="title">{{ _('Get Firefox') }}</span>
<span>{{ _('Upgrade to Firefox 3.6 and experience the best of the Web and Firefox Cup.') }}</span>
</a>
</div>
</div>
<div id="main-content">
<h2>{{ _('Personas show your passion as your team plays for glory.') }}</h2>
<div id="personas" class="pager pager-with-tabs">
<div id="personas-header">
<h3>{{ _('Roll over to try, click to apply') }}</h3>
<ul id="personas-nav" class="pager-tabs">
<li class="first"><a href="#p1">{{ _('1') }}</a></li>
<li><a href="#p2">{{ _('2') }}</a></li>
<li><a href="#p3">{{ _('3') }}</a></li>
<li><a href="#p4">{{ _('4') }}</a></li>
<li><a href="#p5">{{ _('5') }}</a></li>
</ul>
</div>
<div class="pager-content">
{% for batch in personas|batch(8) %}
<div class="personas-contents {% if loop.index == 1 %}default-page{% endif %}" id="feature-p{{ loop.index }}">
<ul class="personas-list">
{% for persona in batch %}
<li>{{ persona_preview(persona, size='small', linked=True) if persona else 'Persona not found' }}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
<p>{{ _('Dress up your Firefox with team spirit and share the love with friends. The team with the most fans using Personas wins the Firefox Cup!') }}</p>
</div>
</div>
<div id="sidebar">
<ul class="subfeatures">
{# this email block does not get localized. en-us only #}
{% if LANG == 'en-US' %}
<li id="email">
<a href="#" id="email-start">
<span class="title">{{ _('Sign Up!') }}</span>
<span>Get the Mozilla newsletter for news, tips &amp; tricks.</span>
</a>
<div id="email-form">
<p>Subscribe to our email Newsletter to receive special Mozilla news, Firefox tips &amp; tricks, and other Mozilla information.</p>
<p id="error-box" class="form-error"></p>
<form action="{{ url('firefoxcup.signup') }}" method="POST">
<input type="email" name="email" placeholder="Your Email Address" size="30">
<label for="privacy"><input type="checkbox" name="privacy" id="privacy"> I agree to the <a href="http://www.mozilla.com/en-US/privacy-policy.html">privacy policy</a></label>
<input type="hidden" name="campaign" value="Mainstream News">
<input type="hidden" name="locale" value="en-US">
<input type="hidden" name="source" value="addons.mozilla.org/firefoxcup">
<input type="submit" value="Subscribe">
</form>
<p id="footnote">We will only send you Mozilla-related information.</p>
</div>
<div id="email-finish">
<h3>Thanks for subscribing!</h3>
<p>We look forward to soon begin sharing tips &amp; tricks on getting the most out of Firefox, as well as exciting news about Mozilla and how were working to create a better Web.</p>
</div>
</li>
{% endif %}
<li id="featured">
<a href="{{ url('addons.detail', 725)|urlparams(src='external-firefoxcup') }}" id="featured-footiefox">
<span class="title">{{ _('FootieFox') }}</span>
<span>{{ _("Don't miss a moment of action. FootieFox shows latest scores in your Firefox.") }}</span>
</a>
<a href="http://rockyourfirefox.com/" id="featured-rockyourfirefox">
<span class="title">{{ _('Rock Your Firefox') }}</span>
<span>{{ _("Discover new add-ons to brighten your day.") }}</span>
</a>
<a href="https://addons.mozilla.org/" id="featured-amo">
<span class="title">{{ _('Get Personal') }}</span>
<span>{{ _("Adapt Firefox to the way you browse with 1,000s of free add-ons.") }}</span>
</a>
</li>
<li id="facebook">
<a href="http://www.facebook.com/#!/Firefox">
<span class="title">{{ _('Stay Connected!') }}</span>
<span>{{ _('Become a Fan') }}</span>
</a>
</li>
</ul>
</div>
<div id="secondary-content">
<div id="teams-section">
<h2>{{ _('Find Your Team Persona') }}</h2>
<p>{{ _("Rollover your country's flag to preview Personas, then click to install. At the end of the tournament, the team whose fans used Personas the most wins the Firefox Cup.") }}</p>
</div>
<table id="teams">
<thead>
<tr>
<th>{{ _('Flag') }}</th>
<th>{{ _('Country') }}</th>
<th>{{ _('Fans') }}</th>
</tr>
<tr><td colspan="3"></td></tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td class="persona"><div class="persona-preview flag flag-{{ team.id }}" data-browsertheme="{{ team.persona.json_data if team.persona }}"></div></td>
<td>{{ team.name }}</td>
<td class="fans"><span class="inlinesparkline">{{ team.stats }}</span>{{ team.persona.popularity|numberfmt if team.persona else 0 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="tweets">
<thead>
<tr>
<th><a href="http://twitter.com/firefox">{{ _('Follow our tweets') }}</a></th>
</tr>
<tr><td></td></tr>
</thead>
<tbody>
{% for tweet in tweets %}
<tr><td>{{ tweet }}</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div><!-- end #doc -->
</div><!-- end #wrapper -->
{% endblock %}
{% block footer %}{% endblock %}
{% block site_js %}{% endblock %}
{% block js %}
<script type="text/javascript">
media_url = '{{ MEDIA_URL }}';
</script>
{{ js('firefoxcup') }}
{% endblock %}

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

@ -1,57 +0,0 @@
import json
from StringIO import StringIO
import urllib2
from mock import patch
from nose.tools import eq_
from pyquery import PyQuery as pq
import test_utils
from firefoxcup import twitter
class TestFirefoxCup(test_utils.TestCase):
fixtures = ['addons/persona']
def twitter_results(self):
return StringIO(json.dumps({'results': [{'text': 'text'}]}))
def test_prepare_lang(self):
"""Always use short lang code (e.g. en-US -> en)"""
eq_(twitter._prepare_lang('es-ES'), 'es')
"""Bad lang codes should fall back to 'all'"""
eq_(twitter._prepare_lang('bad-lang-code'), 'all')
def test_process_tweet(self):
"""URLs and tags are linkified"""
a = map(twitter._process_tweet,
['http://www.mozilla.com', '#hash', '@person'])
for v in a:
# use PyQuery to check for <a> tag
assert pq(v).is_('a')
def test_search_query_encoded(self):
"""Search query string is URL encoded"""
a = twitter._search_query(['foo', '#bar'], 'en')
eq_(a, 'ors=foo+%23bar')
@patch('firefoxcup.twitter.urllib2.urlopen')
def test_search_data_decoded(self, urlopen):
"""Search results are JSON decoded,
and only the tweet content is returned"""
urlopen.return_value = self.twitter_results()
twitter.cache_tweets(lang='es-ES')
a = twitter.search(lang='es-ES')
eq_(a, ['text'])
@patch('firefoxcup.twitter.urllib2.urlopen')
def test_twitter_search_returns_list_on_error(self, urlopen):
"""If the call to the Twitter Search API fails,
twitter.search() should not return None. It should
always return a list"""
urlopen.side_effect = urllib2.URLError('Boom')
eq_(twitter.search(lang='all'), [])

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

@ -1,79 +0,0 @@
from hashlib import md5
import json
import urllib2
from django.conf import settings
from django.core.cache import cache
from django.utils.http import urlencode
import commonware.log
import jinja2
import ttp
from translations.models import LinkifiedTranslation
import firefoxcup as fxcup
from . import twitter_languages
log = commonware.log.getLogger('z.firefoxcup')
parser = ttp.Parser()
def _prepare_lang(lang):
lang = lang.split('-')[0]
if lang not in fxcup.tags:
lang = 'all'
return lang
def _search_query(tags, lang):
return urlencode({'ors': ' '.join(tags)})
def search(lang, limit=15):
key = _cache_key(_prepare_lang(lang))
tweets = cache.get(key, [])
if len(tweets) < limit and key != 'all':
tweets.extend(cache.get(_cache_key('all'), []))
return tweets[:limit]
def _cache_key(lang):
return '%s:fxcup-twitter:%s' % (settings.CACHE_PREFIX, lang)
def cache_tweets(lang):
lang = _prepare_lang(lang)
tags = fxcup.tags[lang]
url = "http://search.twitter.com/search.json?" + _search_query(tags, lang)
# build cache key
hash = md5(url).hexdigest()
cache_key = _cache_key(lang)
try:
json_data = urllib2.urlopen(url)
except urllib2.URLError, e:
log.error("Couldn't open (%s): %s" % (url, e))
return []
try:
# decode JSON
data = json.load(json_data)['results']
except (ValueError, KeyError):
return []
# we only want the text, throw the other data away
tweets = [tweet['text'] for tweet in data]
tweets = map(_process_tweet, tweets)
log.debug('Caching %s tweets for %s' % (len(tweets), lang))
cache.set(cache_key, tweets, 0)
def _process_tweet(tweet):
# linkify urls, tags (e.g. #hashtag, @someone)
tweet = parser.parse(tweet).html
s = LinkifiedTranslation(localized_string=tweet)
s.clean()
return jinja2.Markup(s.localized_string_clean)

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

@ -1,8 +0,0 @@
from django.conf.urls.defaults import patterns, url
from . import views
urlpatterns = patterns('',
url('^$', views.index, name='firefoxcup.index'),
url('^signup/', views.signup, name='firefoxcup.signup'),
)

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

@ -1,62 +0,0 @@
import httplib
import json
import jingo
from django.http import HttpResponse
from django.utils.http import urlencode
from django.views.decorators.csrf import csrf_exempt
from addons.models import Persona
from . import tags, generic_persona, teams as teams_config
from .models import Stats
from .twitter import search
def index(request):
tweets = search(lang=request.LANG, limit=15)
persona_ids = [t['persona_id'] for t in teams_config]
persona_ids.append(generic_persona)
personas = {}
for persona in Persona.objects.filter(persona_id__in=persona_ids):
personas[persona.persona_id] = persona
stats = {}
for stat in Stats.objects.all():
stats.setdefault(stat.persona_id, []).append(str(stat.popularity))
teams = []
for t in teams_config:
id = t['persona_id']
if id not in personas:
continue
t['persona'] = personas[id]
if id in stats:
# we need at least 2 data points
while len(stats[id]) < 2:
stats[id].insert(0, '0')
t['stats'] = ','.join(stats[id])
else:
t['stats'] = '0,0'
teams.append(t)
# sort by most fans
teams.sort(key=lambda x: x['persona'].popularity, reverse=True)
return jingo.render(request, 'firefoxcup/index.html', {
'tweets': tweets,
'teams': teams,
'personas': personas.values(),
})
@csrf_exempt
def signup(request):
conn = httplib.HTTPConnection("basket.mozilla.com")
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text-plain"}
conn.request("POST", "/subscriptions/subscribe/", request.raw_post_data, headers)
resp = conn.getresponse()
conn.close()
return HttpResponse(str(resp.status))

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

@ -1,739 +0,0 @@
/* {{{ Layout */
a,
a:link,
a:visited {
color: #0080be;
}
a:hover,
a:active {
color: #005580;
}
body {
background: #fff url(../../img/firefoxcup/background-repeat.jpg) top center repeat-x;
}
body, h1, h2, h3, h4, h5, h6 {
font-family: "helvetica neue",arial,helvetica,sans-serif;
}
#wrapper {
background: url(../../img/firefoxcup/background.jpg) top center no-repeat;
}
#doc {
width: 990px;
overflow: auto;
}
[dir="rtl"] #doc,
[dir="rtl"] td,
[dir="rtl"] th {
text-align:right;
}
.section {
max-width: none;
min-height: 0;
min-width: 0;
padding: 0;
width: auto;
}
#footer .section {
width: 990px;
text-align: left;
}
/* }}}
/* {{{ Header */
#header {
float: right;
padding-top: 10px;
}
#header li {
display: inline;
border-left: 1px solid #209b1e;
padding: 0 10px;
}
#header li.first {
padding-left: 0;
border-left: 0;
}
#header a,
#header a:link,
#header a:visited,
#header a:hover,
#header a:active {
color: #fff;
text-decoration: underline;
}
#header form {
display: inline;
}
#header .languages label {
color: #fff;
font-weight: normal;
}
#header .languages button,
#header .languages select {
vertical-align: middle;
}
/* }}} */
/* {{{ Main Feature */
#main-feature {
color: #fff;
}
#main-feature h1 {
float: left;
}
#main-feature h2 {
float: left;
font-size: 24px;
color: #fff;
width: 330px;
margin-top: 60px;
margin-right: 35px;
line-height: 1.5;
}
/* }}} */
/* {{{ Download */
#download {
float: left;
width: 280px;
margin-top: 45px;
background: url(../../img/firefoxcup/background-download.png) top right no-repeat;
}
#download a,
#download a span {
display: block;
color: #fff;
}
#download a span.title {
font-size: 24px;
line-height: 1.5;
padding: 15px 90px 0 5px;
color: #fff;
}
#download a span {
padding: 0 90px 5px 5px;
}
#download a:link,
#download a:visited,
#download a:hover,
#download a:active {
text-decoration: none;
}
#download a:hover span.title,
#download a:active span.title {
text-decoration: underline;
}
/* }}} */
/* {{{ Main Content */
#main-content {
clear: both;
float: left;
display: inline;
width: 575px;
padding: 35px 15px 15px 35px;
margin: 0 35px 25px 25px;
background: #fff;
color: #333;
border: 1px solid #eee;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
min-height: 300px;
background: #fff url(../../img/firefoxcup/generic-mac.jpg) -60px 100% no-repeat;
}
#main-content h2 {
color: #333;
float: left;
width: 235px;
font-size: 20px;
margin: 0 15px 290px 0;
line-height: 1.3;
}
#personas {
float: left;
width: 325px;
}
#personas-header h3 {
color: #666;
font-size: 13px;
float: left;
margin-left: 5px;
margin-top: 5px;
padding-right: 25px;
background: url(../../img/firefoxcup/arrow.png) 100% 50% no-repeat;
}
#personas-nav {
float: right;
}
#personas-nav li {
float: left;
}
#personas-nav li a {
border-left: 1px solid #13a5ff;
padding: 0 8px;
display: block;
}
#personas-nav li a.selected {
color: #666;
}
#personas-nav li.first a {
border-left: 0;
}
.pager-content {
clear: both;
}
ul.personas-list {
}
.personas-list li {
float: left;
width: 150px;
margin: 5px;
}
.persona-small .persona-preview [data-browsertheme] {
width: 150px;
height: 50px;
border: none !important;
}
.persona-inner {
padding: 0;
}
.persona-hover .persona-inner {
background: none;
}
#personas p {
margin: 0 0 0 5px;
padding: 20px 0;
clear: both;
}
/* }}} */
/* {{{ Sidebar */
#sidebar {
float: left;
width: 275px;
}
#sidebar .subfeatures li {
}
#sidebar .subfeatures li a:link,
#sidebar .subfeatures li a:visited,
#sidebar .subfeatures li a:hover,
#sidebar .subfeatures li a:active {
color: #333;
text-decoration: none;
}
#sidebar .subfeatures li a:hover,
#sidebar .subfeatures li a:active {
color: #000;
border-color: #ccc;
}
#email-form,
#email-finish,
#sidebar .subfeatures li a {
display: block;
padding: 17px 20px 20px 20px;
padding-left: 75px;
background: #fff;
background-repeat: no-repeat;
background-position: 10px 20px;
margin: 0 0 20px 0;
border: 1px solid #eee;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
}
#sidebar .subfeatures span.title {
font-size: 22px;
}
#sidebar .subfeatures span {
display: block;
}
#sidebar .subfeatures li#featured a {
display: block;
min-height: 80px;
}
#sidebar .subfeatures li a#featured-footiefox {
background-image: url(../../img/firefoxcup/footiefox.png);
}
#sidebar .subfeatures li a#featured-rockyourfirefox {
background-image: url(../../img/firefoxcup/rockyourfirefox.png);
background-position: 0 0;
}
#sidebar .subfeatures li a#featured-amo {
background-image: url(../../img/firefoxcup/addons.png);
background-position: 10px 20px;
}
#sidebar a#email-start {
background-image: url(../../img/firefoxcup/email.png);
min-height: 62px;
}
#sidebar #email-form form a {
display: inline;
padding: 0;
margin: 0;
background: none;
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-moz-border-radius: none;
-webkit-border-radius: none;
text-decoration: underline;
color: blue;
}
#email-form,
#email-finish {
padding-left: 20px;
}
#email-form input {
display: block;
margin: 5px 0;
}
#email-form input#privacy {
display: inline;
margin-right: 5px;
}
#email-form #footnote {
color: #999;
}
#email-form,
#email-finish,
#error-box {
display: none;
}
.form-error {
-moz-border-radius: 5px;
border: 2px solid #cc4927;
padding: 2px 5px;
}
#sidebar #facebook a {
background-image: url(../../img/firefoxcup/facebook.png);
min-height: 54px;
}
.default #sidebar .subfeatures li a#featured-rockyourfirefox,
.default #sidebar .subfeatures li a#featured-amo { display: none; }
.rockyourfirefox #sidebar .subfeatures li a#featured-rockyourfirefox { display: block; }
.rockyourfirefox #sidebar .subfeatures li a#featured-amo { display: none; }
.rockyourfirefox #sidebar .subfeatures li a#featured-footiefox { display: none; }
.amo #sidebar .subfeatures li a#featured-amo { display: block; }
.amo #sidebar .subfeatures li a#featured-rockyourfirefox { display: none; }
.amo #sidebar .subfeatures li a#featured-footiefox { display: none; }
/* }}} */
/* {{{ Teams Personas */
#secondary-content {
clear: both;
padding-left: 25px;
}
#secondary-content h2 {
font-size: 22px;
color: #333;
}
#teams-section {
width: 625px;
float: left;
}
#teams {
width: 625px;
float: left;
border-collapse: separate;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
margin: 25px 35px 25px 0;
}
#teams th,
#teams td {
padding: 8px 12px;
}
#teams thead th {
text-align: center;
background-color: #48b4d5;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(87,200,231)), color-stop(1, rgb(54,168,206)));
background-image: -moz-linear-gradient(center top, rgb(87,200,231) 0%, rgb(54,168,206) 100%);
color: #fff;
font-size: 16px;
padding: 12px;
border-left: 1px solid #4cb8d8;
border-right: 1px solid #71c7e0;
}
#teams thead th:first-child {
-webkit-border-top-left-radius: 10px;
-moz-border-radius-topleft: 10px;
border-top-left-radius: 10px;
border-left: 0;
}
#teams thead th:last-child {
-webkit-border-top-right-radius: 10px;
-moz-border-radius-topright: 10px;
border-top-right-radius: 10px;
border-right: 0;
}
[dir="rtl"] #teams thead th:first-child {
-webkit-border-top-right-radius: 10px;
-moz-border-radius-topright: 10px;
border-top-right-radius: 10px;
-webkit-border-top-left-radius: 0px;
-moz-border-radius-topleft: 0px;
border-top-left-radius: 0px;
}
[dir="rtl"] #teams thead th:last-child {
-webkit-border-top-left-radius: 10px;
-moz-border-radius-topleft: 10px;
border-top-left-radius: 10px;
-webkit-border-top-right-radius: 0px;
-moz-border-radius-topright: 0px;
border-top-right-radius: 0px;
}
#teams thead td {
background: #a8e3f6;
padding: 1px;
}
#teams tbody td {
background: #fff;
border-left: 1px solid #fff;
border-right: 1px solid #c0e2ec;
vertical-align: middle;
}
#teams tbody tr:nth-child(even) td {
background: #dff4fa;
}
#teams tbody td:first-child {
border-left: 1px solid #eee;
}
[dir="rtl"] #teams tbody td:first-child {
border-right: 1px solid #eee;
border-left: 1px solid #fff;
}
#teams tbody td:last-child {
border-right: 1px solid #eee;
}
[dir="rtl"] #teams tbody td:last-child {
border-left: 1px solid #eee;
border-right: 1px solid #c0e2ec;
}
#teams tbody tr:last-child td {
border-bottom: 1px solid #eee;
}
#teams tbody tr:last-child td:first-child {
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-bottomleft: 10px;
border-bottom-left-radius: 10px;
}
[dir="rtl"] #teams tbody tr:last-child td:first-child {
-webkit-border-bottom-right-radius: 10px;
-moz-border-radius-bottomright: 10px;
border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 0px;
-moz-border-radius-bottomleft: 0px;
border-bottom-left-radius: 0px;
}
#teams tbody tr:last-child td:last-child {
-webkit-border-bottom-right-radius: 10px;
-moz-border-radius-bottomright: 10px;
border-bottom-right-radius: 10px;
}
[dir="rtl"] #teams tbody tr:last-child td:last-child {
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-bottomleft: 10px;
border-bottom-left-radius: 10px;
-webkit-border-bottom-right-radius: 0px;
-moz-border-radius-bottomright: 0px;
border-bottom-right-radius: 0px;
}
#teams tfoot { display: none; }
#teams tfoot td {
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-moz-border-radius-bottomleft: 10px;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
background: #fff;
padding: 5px;
}
#teams img {
display: block;
margin: 0 auto;
}
/* }}} */
/* {{{ Tweets */
#tweets {
width: 275px;
float: left;
border-collapse: separate;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -20px 45px rgba(0,0,0,0.08) inset;
margin: 25px 0;
table-layout: fixed;
}
#tweets th,
#tweets td {
padding: 8px 12px;
word-wrap: break-word;
}
#tweets thead th {
background-color: #58cf50;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(95,219,87)), color-stop(1, rgb(82,196,74)));
background-image: -moz-linear-gradient(center top, rgb(95,219,87) 0%, rgb(82,196,74) 100%);
color: #fff;
font-size: 16px;
padding: 4px 12px;
-webkit-border-top-left-radius: 10px;
-moz-border-radius-topleft: 10px;
border-top-left-radius: 10px;
-webkit-border-top-right-radius: 10px;
-moz-border-radius-topright: 10px;
border-top-right-radius: 10px;
}
#tweets thead th a {
display: block;
background: url(../../img/firefoxcup/twitter.png) 0 50% no-repeat;
padding: 12px 0;
padding-left: 50px;
}
[dir="rtl"] #tweets thead th a {
background-position: 100% 50%;
padding-left: 0;
padding-right: 50px;
}
#tweets thead th a:link,
#tweets thead th a:visited,
#tweets thead th a:hover,
#tweets thead th a:active {
color: #fff;
}
#tweets thead th a:hover,
#tweets thead th a:active {
text-decoration: underline;
}
#tweets thead th img {
vertical-align: middle;
margin-right: 8px;
}
#tweets thead td {
background: #d5ead5;
padding: 1px;
}
#tweets tbody td {
background: #fff;
border-width: 1px;
border-style: solid;
border-color: #f2fcf1 #eee #e3f8df #eee;
}
#tweets tbody tr:nth-child(even) td {
background: #e3f8df;
}
#tweets tbody td:first-child {
border-left: 1px solid #eee;
}
#tweets tbody td:last-child {
border-right: 1px solid #eee;
}
#tweets tbody tr:last-child td {
border-bottom: 1px solid #eee;
}
#tweets tbody tr:last-child td:first-child {
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-bottomleft: 10px;
border-bottom-left-radius: 10px;
}
#tweets tbody tr:last-child td:last-child {
-webkit-border-bottom-right-radius: 10px;
-moz-border-radius-bottomright: 10px;
border-bottom-right-radius: 10px;
}
#tweets tfoot { display: none; }
#tweets tfoot td {
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-moz-border-radius-bottomleft: 10px;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
background: #fff;
padding: 5px;
}
/* }}} */
/* {{{ Reset AMO Styles */
table {
border-bottom: 0;
}
thead th {
border: 0;
}
tbody {
border: 0;
}
tbody tr th, tbody tr td {
border-top: 0;
}
/* }}} */
/* {{{ Sparkline */
td.fans {
text-align: center;
}
.inlinesparkline {
display: none;
margin: 0 15px;
}
/* }}} */
.flag {
background: url(../../img/firefoxcup/flags-sprite.png) no-repeat top left;
width: 33px;
height: 33px;
}
.flag-algeria { background-position: 0 0; }
.flag-argentina { background-position: 0 -63px; }
.flag-australia { background-position: 0 -126px; }
.flag-brazil { background-position: 0 -189px; }
.flag-cameroon { background-position: 0 -252px; }
.flag-chile { background-position: 0 -315px; }
.flag-cote { background-position: 0 -378px; }
.flag-denmark { background-position: 0 -441px; }
.flag-england { background-position: 0 -504px; }
.flag-france { background-position: 0 -567px; }
.flag-germany { background-position: 0 -630px; }
.flag-ghana { background-position: 0 -693px; }
.flag-greece { background-position: 0 -756px; }
.flag-honduras { background-position: 0 -819px; }
.flag-italy { background-position: 0 -882px; }
.flag-japan { background-position: 0 -945px; }
.flag-korea-dpr { background-position: 0 -1008px; }
.flag-korea-republic { background-position: 0 -1071px; }
.flag-mexico { background-position: 0 -1134px; }
.flag-netherlands { background-position: 0 -1197px; }
.flag-new-zealand { background-position: 0 -1260px; }
.flag-nigeria { background-position: 0 -1323px; }
.flag-paraguay { background-position: 0 -1386px; }
.flag-portugal { background-position: 0 -1449px; }
.flag-serbia { background-position: 0 -1512px; }
.flag-slovakia { background-position: 0 -1575px; }
.flag-slovenia { background-position: 0 -1638px; }
.flag-south-africa { background-position: 0 -1701px; }
.flag-spain { background-position: 0 -1764px; }
.flag-switzerland { background-position: 0 -1827px; }
.flag-uruguay { background-position: 0 -1890px; }
.flag-usa { background-position: 0 -1953px; }

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -2119,57 +2119,6 @@ form .error .note.error {
border-top-color: #0471ed;
}
/**
* Firefox Cup promo styles
* TODO remove these when promo is pulled
**/
#t-firefox-cup,
#t-firefox-cup div.cta p,
#t-firefox-cup div.cta h2 {
font-family: "Geneva", "Lucida Sans Unicode", "Lucida Sans", "Trebuchet", sans-serif;
}
#t-firefox-cup {
padding-top: 10px;
background-image: url("../../img/zamboni/promos/FirefoxCup_AddsOn_banner.jpg");
background-repeat: no-repeat;
background-position: 33% top;
height: 260px;
position:relative;
}
#t-firefox-cup div.cta {
margin-left: 280px;
}
#t-firefox-cup div.cta h2 {
color: #bcffbb;
font-size: 200%;
margin: 1.3em 50px 1em 0;
word-spacing: -.1em;
}
#t-firefox-cup div.cta p {
color: #FFFFFD;
font-size: 120%;
margin-right: 50px;
margin-left: 0;
}
#t-firefox-cup div.cta a {
color: #FFFFFD;
text-decoration: underline;
}
#t-firefox-cup a.cover {
position:absolute;
height:100%;
width:100%;
top:0;
left:0;
display:block;
}
/**
* End Firefox Cup promo styles
* TODO remove these when promo is pulled
**/
.other-note {
display: none;
clear: left;
@ -2296,4 +2245,4 @@ ul.review-options > li:not(:first-child) {
}
.reply-form input[type='text'] {
width: 60%;
}
}

Двоичные данные
media/img/firefoxcup/addons.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/arrow.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
media/img/firefoxcup/background-download.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
media/img/firefoxcup/background-repeat.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 6.7 KiB

Двоичные данные
media/img/firefoxcup/background.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 73 KiB

Двоичные данные
media/img/firefoxcup/email.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/facebook.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags-sprite.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 100 KiB

Двоичные данные
media/img/firefoxcup/flags/algeria.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Двоичные данные
media/img/firefoxcup/flags/argentina.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
media/img/firefoxcup/flags/australia.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags/brazil.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.4 KiB

Двоичные данные
media/img/firefoxcup/flags/cameroon.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/chile.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
media/img/firefoxcup/flags/cote.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичные данные
media/img/firefoxcup/flags/denmark.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
media/img/firefoxcup/flags/england.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичные данные
media/img/firefoxcup/flags/france.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичные данные
media/img/firefoxcup/flags/germany.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичные данные
media/img/firefoxcup/flags/ghana.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/greece.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/honduras.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
media/img/firefoxcup/flags/italy.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичные данные
media/img/firefoxcup/flags/japan.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/korea-dpr.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags/korea-republic.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/mexico.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
media/img/firefoxcup/flags/netherlands.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичные данные
media/img/firefoxcup/flags/new-zealand.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags/nigeria.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичные данные
media/img/firefoxcup/flags/paraguay.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
media/img/firefoxcup/flags/portugal.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.4 KiB

Двоичные данные
media/img/firefoxcup/flags/serbia.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Двоичные данные
media/img/firefoxcup/flags/slovakia.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags/slovenia.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
media/img/firefoxcup/flags/south-africa.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
media/img/firefoxcup/flags/spain.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
media/img/firefoxcup/flags/switzerland.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
media/img/firefoxcup/flags/uruguay.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Двоичные данные
media/img/firefoxcup/flags/usa.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Двоичные данные
media/img/firefoxcup/footiefox.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.7 KiB

Двоичные данные
media/img/firefoxcup/generic-mac.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 35 KiB

Двоичные данные
media/img/firefoxcup/generic-pc.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 29 KiB

Двоичные данные
media/img/firefoxcup/logo.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 125 KiB

Двоичные данные
media/img/firefoxcup/preview-uk.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 11 KiB

Двоичные данные
media/img/firefoxcup/rockyourfirefox.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 8.4 KiB

Двоичные данные
media/img/firefoxcup/twitter.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.1 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 70 KiB

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,119 +0,0 @@
// Browser detection
// http://www.quirksmode.org/js/detect.html
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();

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

@ -1,600 +0,0 @@
$(document).ready(function () {
// if user has Firefox 3.6, hide the 'Get Firefox' download block
if (BrowserDetect.browser == 'Firefox' && BrowserDetect.version == '3.6')
$('#download').hide();
firefoxcup_random_promo();
firefoxcup_random_screenshot(media_url);
$('[data-browsertheme]').personasButton();
$('.inlinesparkline').show().sparkline('html', {width: '150px'});
// Set up input placeholders.
$('input[placeholder]').placeholder();
});
function firefoxcup_random_promo() {
// randomize sidebar promos
var classOptions = ['amo', 'rockyourfirefox', 'default'];
var choice = Math.floor(Math.random() * classOptions.length);
$('body').addClass(classOptions[choice]);
}
function firefoxcup_random_screenshot(media_url) {
var platform = (navigator.appVersion.indexOf('Mac') !== -1) ? 'mac' : 'pc';
var bg = 'url("' + media_url + 'img/firefoxcup/generic-'+ platform +'.jpg")';
$('#main-content').css('background-image', bg);
}
// the original version of this function doesn't yet handle
// installing via clicking on a preview image
// so we have to redefine this here
$.fn.personasButton = function(options) {
$(this).hoverIntent({
interval: 100,
over: function(e) {
dispatchPersonaEvent('PreviewPersona', e.currentTarget);
},
out: function(e) {
dispatchPersonaEvent('ResetPersona', e.currentTarget);
}
});
$(this).click(function(e) {
dispatchPersonaEvent('SelectPersona', e.currentTarget);
return false;
});
};
// Submit on locale choice
jQuery(function($) {
var f = $('form.languages');
f.find('select').change(function(){ this.form.submit(); });
});
/**
* Initializes pagers on this page after the document has been loaded
*/
YAHOO.util.Event.onDOMReady(function ()
{
var pagers = YAHOO.util.Dom.getElementsByClassName('pager');
for (var i = 0; i < pagers.length; i++) {
new Mozilla.Pager(pagers[i]);
}
});
// create namespace
if (typeof Mozilla == 'undefined') {
var Mozilla = {};
}
/**
* Pager widget
*
* @param DOMElement container
*/
Mozilla.Pager = function(container)
{
this.container = container;
if (!this.container.id) {
YAHOO.util.Dom.generateId(this.container, 'mozilla-pager-');
}
var pager_content_nodes = YAHOO.util.Dom.getElementsByClassName(
'pager-content', 'div', this.container);
this.id = this.container.id;
this.page_container = pager_content_nodes[0];
this.pages_by_id = {};
this.pages = [];
this.previous_page = null;
this.current_page = null;
this.in_animation = null;
this.out_animation = null;
this.random_start_page = (YAHOO.util.Dom.hasClass(this.container, 'pager-random'));
if (YAHOO.util.Dom.hasClass(this.container, 'pager-with-tabs')) {
var pager_tab_nodes = YAHOO.util.Dom.getElementsByClassName(
'pager-tabs', 'ul', this.container);
this.tabs = pager_tab_nodes[0];
} else {
this.tabs = null;
}
if (YAHOO.util.Dom.hasClass(this.container, 'pager-with-nav')) {
this.drawNav();
} else {
this.nav = null;
}
this.history =
(!YAHOO.util.Dom.hasClass(this.container, 'pager-no-history'));
// add pages
var page_nodes = YAHOO.util.Dom.getChildrenBy(this.page_container,
function (n) { return (n.nodeName == 'DIV'); });
if (this.tabs) {
// initialize pages with tabs
var tab_nodes = YAHOO.util.Dom.getChildrenBy(this.tabs,
function (n)
{
return (!YAHOO.util.Dom.hasClass(n, 'pager-not-tab'));
});
var index = 0;
for (var i = 0; i < page_nodes.length; i++) {
if (i < tab_nodes.length) {
var tab_node = YAHOO.util.Dom.getFirstChildBy(tab_nodes[i],
function(n) { return (n.nodeName == 'A'); });
if (tab_node) {
this.addPage(new Mozilla.Page(page_nodes[i], index,
tab_node));
index++;
}
}
}
} else {
// initialize pages without tabs
for (var i = 0; i < page_nodes.length; i++) {
this.addPage(new Mozilla.Page(page_nodes[i], i));
}
}
// initialize current page
var current_page = null;
if (this.history) {
var hash = location.hash;
hash = (hash.substring(0, 1) == '#') ? hash.substring(1) : hash;
if (hash.length) {
current_page = this.pages_by_id[hash];
if (current_page) {
this.setPage(current_page);
}
}
// check if window location changes from back/forward button use
// this doesn't matter in IE and Opera but is nice for Firefox and
// recent Safari users.
function setupInterval(pager)
{
var interval_function = function()
{
pager.checkLocation();
}
setInterval(interval_function,
(Mozilla.Pager.LOCATION_INTERVAL * 1000), pager);
}
setupInterval(this);
}
if (!current_page && this.pages.length > 0) {
if (this.random_start_page) {
this.setPage(this.getPseudoRandomPage());
} else {
var def_page = YAHOO.util.Dom.getFirstChildBy(this.page_container,
function(n){return YAHOO.util.Dom.hasClass(n, 'default-page')});
if (def_page) {
var def_id;
if (def_page.id.substring(0, 5) == 'page-') {
def_id = def_page.id.substring(5);
} else {
def_id = def_page.id;
}
this.setPage(this.pages_by_id[def_id]);
} else {
this.setPage(this.pages[0]);
}
}
}
}
Mozilla.Pager.prototype.getPseudoRandomPage = function()
{
var page = null;
if (this.pages.length > 0) {
var now = new Date();
page = this.pages[now.getSeconds() % this.pages.length];
}
return page;
}
Mozilla.Pager.PAGE_DURATION = 0.15; // seconds
Mozilla.Pager.LOCATION_INTERVAL = 0.20; // seconds
Mozilla.Pager.NEXT_TEXT = 'Next';
Mozilla.Pager.PREV_TEXT = 'Previous';
Mozilla.Pager.PAGE_NUMBER_TEXT = '%s / %s';
Mozilla.Pager.prototype.prevPageWithAnimation = function()
{
var index = this.current_page.index - 1;
if (index < 0) {
index = this.pages.length - 1;
}
this.setPageWithAnimation(this.pages[index]);
}
Mozilla.Pager.prototype.nextPageWithAnimation = function()
{
var index = this.current_page.index + 1;
if (index >= this.pages.length) {
index = 0;
}
this.setPageWithAnimation(this.pages[index]);
}
Mozilla.Pager.prototype.drawNav = function()
{
// create previous link
this.prev = document.createElement('a');
this.prev.href = '#';
YAHOO.util.Dom.addClass(this.prev, 'pager-prev');
this.prev.title = Mozilla.Pager.PREV_TEXT;
this.prev.appendChild(document.createTextNode(''));
this.prev_insensitive = document.createElement('span');
this.prev_insensitive.style.display = 'none';
YAHOO.util.Dom.addClass(this.prev_insensitive, 'pager-prev-insensitive');
YAHOO.util.Event.on(this.prev, 'click',
function (e)
{
YAHOO.util.Event.preventDefault(e);
this.prevPageWithAnimation();
},
this, true);
YAHOO.util.Event.on(this.prev, 'dblclick',
function (e)
{
YAHOO.util.Event.preventDefault(e);
},
this, true);
// create next link
this.next = document.createElement('a');
this.next.href = '#';
YAHOO.util.Dom.addClass(this.next, 'pager-next');
this.next.title = Mozilla.Pager.NEXT_TEXT;
this.next.appendChild(document.createTextNode(''));
this.next_insensitive = document.createElement('span');
this.next_insensitive.style.display = 'none';
YAHOO.util.Dom.addClass(this.next_insensitive, 'pager-next-insensitive');
YAHOO.util.Event.on(this.next, 'click',
function (e)
{
YAHOO.util.Event.preventDefault(e);
this.nextPageWithAnimation();
},
this, true);
YAHOO.util.Event.on(this.next, 'dblclick',
function (e)
{
YAHOO.util.Event.preventDefault(e);
},
this, true);
// create navigation element
var divider = document.createElement('span');
divider.appendChild(document.createTextNode('|'));
YAHOO.util.Dom.addClass(divider, 'pager-nav-divider');
this.page_number = document.createElement('span');
YAHOO.util.Dom.addClass(this.page_number, 'pager-nav-page-number');
this.nav = document.createElement('div');
YAHOO.util.Dom.addClass(this.nav, 'pager-nav');
this.nav.appendChild(this.page_number);
this.nav.appendChild(this.prev_insensitive);
this.nav.appendChild(this.prev);
this.nav.appendChild(divider);
this.nav.appendChild(this.next);
this.nav.appendChild(this.next_insensitive);
this.container.insertBefore(this.nav, this.page_container);
}
Mozilla.Pager.prototype.checkLocation = function()
{
var hash = location.hash;
hash = (hash.substring(0, 1) == '#') ? hash.substring(1) : hash;
var current_hash = this.current_page.id;
if (hash && hash !== current_hash) {
var page = this.pages_by_id[hash];
if (page) {
this.setPageWithAnimation(page);
this.current_page.focusTab(); // for accessibility
}
}
}
Mozilla.Pager.prototype.addPage = function(page)
{
this.pages_by_id[page.id] = page;
this.pages.push(page);
if (page.tab) {
YAHOO.util.Event.on(page.tab, 'click',
function (e)
{
YAHOO.util.Event.preventDefault(e);
this.setPageWithAnimation(page);
},
this, true);
}
}
Mozilla.Pager.prototype.update = function()
{
if (this.tabs) {
this.updateTabs();
}
if (this.nav) {
this.updateNav();
}
}
Mozilla.Pager.prototype.updateTabs = function()
{
var class_name = this.tabs.className;
class_name = class_name.replace(/pager-selected-[\w-]+/g, '');
class_name = class_name.replace(/^\s+|\s+$/g,'');
this.tabs.className = class_name;
this.current_page.selectTab();
YAHOO.util.Dom.addClass(this.tabs,
'pager-selected-' + this.current_page.id);
}
Mozilla.Pager.prototype.updateNav = function()
{
// update page number
var page_number = this.current_page.index + 1;
var page_count = this.pages.length;
var text = Mozilla.Pager.PAGE_NUMBER_TEXT.replace(/%s/, page_number);
text = text.replace(/%s/, page_count);
if (this.page_number.firstChild) {
this.page_number.replaceChild(document.createTextNode(text),
this.page_number.firstChild);
} else {
this.page_number.appendChild(document.createTextNode(text));
}
// update previous link
this.setPrevSensitivity(this.current_page.index != 0);
// update next link
this.setNextSensitivity(this.current_page.index != this.pages.length - 1);
}
Mozilla.Pager.prototype.setPrevSensitivity = function(sensitive)
{
if (sensitive) {
this.prev_insensitive.style.display = 'none';
this.prev.style.display = 'inline';
} else {
this.prev_insensitive.style.display = 'inline';
this.prev.style.display = 'none';
}
}
Mozilla.Pager.prototype.setNextSensitivity = function(sensitive)
{
if (sensitive) {
this.next_insensitive.style.display = 'none';
this.next.style.display = 'inline';
} else {
this.next_insensitive.style.display = 'inline';
this.next.style.display = 'none';
}
}
Mozilla.Pager.prototype.setPage = function(page)
{
if (this.current_page !== page) {
if (this.current_page) {
this.current_page.deselectTab();
this.current_page.hide();
}
if (this.previous_page) {
this.previous_page.hide();
}
this.previous_page = this.current_page;
this.current_page = page;
this.current_page.show();
this.update();
}
}
Mozilla.Pager.prototype.setPageWithAnimation = function(page)
{
if (this.current_page !== page) {
if (this.history) {
// set address bar to current page
var base_location = location.href.split('#')[0];
location.href = base_location + '#' + page.id;
}
// deselect last selected page (not necessarily previous page)
if (this.current_page) {
this.current_page.deselectTab();
}
// start opacity at current opacity if page was changed while another
// page was fading in
if (this.in_animation && this.in_animation.isAnimated()) {
var start_opacity = parseFloat(YAHOO.util.Dom.getStyle(
this.page_container, 'opacity'));
this.in_animation.stop(false);
} else {
var start_opacity = 1.0;
}
// fade out if we're not already fading out
if (!this.out_animation || !this.out_animation.isAnimated()) {
// only set previous page if we are not already fading out
this.previous_page = this.current_page;
this.out_animation = new YAHOO.util.Anim(this.page_container,
{ opacity: { from: start_opacity, to: 0 } },
Mozilla.Pager.PAGE_DURATION, YAHOO.util.Easing.easeOut);
this.out_animation.onComplete.subscribe(this.fadeInPage,
this, true);
this.out_animation.animate();
}
// always set current page
this.current_page = page;
this.update();
}
// for Safari 1.5.x bug setting window.location.
return false;
}
Mozilla.Pager.prototype.fadeInPage = function()
{
if (this.previous_page) {
this.previous_page.hide();
}
this.current_page.show();
this.in_animation = new YAHOO.util.Anim(this.page_container,
{ opacity: { from: 0, to: 1 } }, Mozilla.Pager.PAGE_DURATION,
YAHOO.util.Easing.easeIn);
this.in_animation.animate();
}
/**
* Page in a pager
*
* @param DOMElement element
* @param DOMElement tab_element
*/
Mozilla.Page = function(element, index, tab_element)
{
this.element = element;
if (!this.element.id) {
YAHOO.util.Dom.generateId(this.element, 'mozilla-pager-page-');
}
// Change element id so updating the window.location does not navigate to
// the page. This is mostly for IE.
if (this.element.id.substring(0, 5) == 'page-') {
this.id = this.element.id.substring(5);
} else {
this.id = this.element.id;
}
this.element.id = 'page-' + this.id;
this.index = index;
if (tab_element) {
this.tab = tab_element;
this.tab.href = '#' + this.id;
} else {
this.tab = null;
}
this.hide();
}
Mozilla.Page.prototype.selectTab = function()
{
if (this.tab) {
YAHOO.util.Dom.addClass(this.tab, 'selected');
}
}
Mozilla.Page.prototype.deselectTab = function()
{
if (this.tab) {
YAHOO.util.Dom.removeClass(this.tab, 'selected');
}
}
Mozilla.Page.prototype.focusTab = function()
{
if (this.tab) {
this.tab.focus();
}
}
Mozilla.Page.prototype.hide = function()
{
this.element.style.display = 'none';
}
Mozilla.Page.prototype.show = function()
{
this.element.style.display = 'block';
}
/* Fake the placeholder attribute since Firefox doesn't support it. */
jQuery.fn.placeholder = function(new_value) {
if (new_value) {
this.attr('placeholder', new_value);
}
/* Bail early if we have built-in placeholder support. */
if ('placeholder' in document.createElement('input')) {
return this;
}
if (new_value && this.hasClass('placeholder')) {
this.val('').blur();
}
return this.focus(function() {
var $this = $(this),
text = $this.attr('placeholder');
if ($this.val() == text) {
$this.val('').removeClass('placeholder');
}
}).blur(function() {
var $this = $(this),
text = $this.attr('placeholder');
if ($this.val() == '') {
$this.val(text).addClass('placeholder');
}
}).each(function(){
/* Remove the placeholder text before submitting the form. */
var self = $(this);
self.closest('form').submit(function() {
if (self.hasClass('placeholder')) {
self.val('');
}
});
}).blur();
};

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

@ -1,675 +0,0 @@
/*!
* jQuery Form Plugin
* version: 2.43 (12-MAR-2010)
* @requires jQuery v1.3.2 or later
*
* Examples and documentation at: http://malsup.com/jquery/form/
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
;(function($) {
/*
Usage Note:
-----------
Do not use both ajaxSubmit and ajaxForm on the same form. These
functions are intended to be exclusive. Use ajaxSubmit if you want
to bind your own submit handler to the form. For example,
$(document).ready(function() {
$('#myForm').bind('submit', function() {
$(this).ajaxSubmit({
target: '#output'
});
return false; // <-- important!
});
});
Use ajaxForm when you want the plugin to manage all the event binding
for you. For example,
$(document).ready(function() {
$('#myForm').ajaxForm({
target: '#output'
});
});
When using ajaxForm, the ajaxSubmit function will be invoked for you
at the appropriate time.
*/
/**
* ajaxSubmit() provides a mechanism for immediately submitting
* an HTML form using AJAX.
*/
$.fn.ajaxSubmit = function(options) {
// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
if (!this.length) {
log('ajaxSubmit: skipping submit process - no element selected');
return this;
}
if (typeof options == 'function')
options = { success: options };
var url = $.trim(this.attr('action'));
if (url) {
// clean url (don't include hash vaue)
url = (url.match(/^([^#]+)/)||[])[1];
}
url = url || window.location.href || '';
options = $.extend({
url: url,
type: this.attr('method') || 'GET',
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
}, options || {});
// hook for manipulating the form data before it is extracted;
// convenient for use with rich editors like tinyMCE or FCKEditor
var veto = {};
this.trigger('form-pre-serialize', [this, options, veto]);
if (veto.veto) {
log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
return this;
}
// provide opportunity to alter form data before it is serialized
if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
log('ajaxSubmit: submit aborted via beforeSerialize callback');
return this;
}
var a = this.formToArray(options.semantic);
if (options.data) {
options.extraData = options.data;
for (var n in options.data) {
if(options.data[n] instanceof Array) {
for (var k in options.data[n])
a.push( { name: n, value: options.data[n][k] } );
}
else
a.push( { name: n, value: options.data[n] } );
}
}
// give pre-submit callback an opportunity to abort the submit
if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
log('ajaxSubmit: submit aborted via beforeSubmit callback');
return this;
}
// fire vetoable 'validate' event
this.trigger('form-submit-validate', [a, this, options, veto]);
if (veto.veto) {
log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
return this;
}
var q = $.param(a);
if (options.type.toUpperCase() == 'GET') {
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
options.data = null; // data is null for 'get'
}
else
options.data = q; // data is the query string for 'post'
var $form = this, callbacks = [];
if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
// perform a load on the target only if dataType is not provided
if (!options.dataType && options.target) {
var oldSuccess = options.success || function(){};
callbacks.push(function(data) {
var fn = options.replaceTarget ? 'replaceWith' : 'html';
$(options.target)[fn](data).each(oldSuccess, arguments);
});
}
else if (options.success)
callbacks.push(options.success);
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
for (var i=0, max=callbacks.length; i < max; i++)
callbacks[i].apply(options, [data, status, xhr || $form, $form]);
};
// are there files to upload?
var files = $('input:file', this).fieldValue();
var found = false;
for (var j=0; j < files.length; j++)
if (files[j])
found = true;
var multipart = false;
// var mp = 'multipart/form-data';
// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
// options.iframe allows user to force iframe mode
// 06-NOV-09: now defaulting to iframe mode if file input is detected
if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
// hack to fix Safari hang (thanks to Tim Molendijk for this)
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
if (options.closeKeepAlive)
$.get(options.closeKeepAlive, fileUpload);
else
fileUpload();
}
else
$.ajax(options);
// fire 'notify' event
this.trigger('form-submit-notify', [this, options]);
return this;
// private function for handling file uploads (hat tip to YAHOO!)
function fileUpload() {
var form = $form[0];
if ($(':input[name=submit]', form).length) {
alert('Error: Form elements must not be named "submit".');
return;
}
var opts = $.extend({}, $.ajaxSettings, options);
var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
var id = 'jqFormIO' + (new Date().getTime());
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" onload="(jQuery(this).data(\'form-plugin-onload\'))()" />');
var io = $io[0];
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
var xhr = { // mock object
aborted: 0,
responseText: null,
responseXML: null,
status: 0,
statusText: 'n/a',
getAllResponseHeaders: function() {},
getResponseHeader: function() {},
setRequestHeader: function() {},
abort: function() {
this.aborted = 1;
$io.attr('src', opts.iframeSrc); // abort op in progress
}
};
var g = opts.global;
// trigger ajax global events so that activity/block indicators work like normal
if (g && ! $.active++) $.event.trigger("ajaxStart");
if (g) $.event.trigger("ajaxSend", [xhr, opts]);
if (s.beforeSend && s.beforeSend(xhr, s) === false) {
s.global && $.active--;
return;
}
if (xhr.aborted)
return;
var cbInvoked = false;
var timedOut = 0;
// add submitting element to data if we know it
var sub = form.clk;
if (sub) {
var n = sub.name;
if (n && !sub.disabled) {
opts.extraData = opts.extraData || {};
opts.extraData[n] = sub.value;
if (sub.type == "image") {
opts.extraData[n+'.x'] = form.clk_x;
opts.extraData[n+'.y'] = form.clk_y;
}
}
}
// take a breath so that pending repaints get some cpu time before the upload starts
function doSubmit() {
// make sure form attrs are set
var t = $form.attr('target'), a = $form.attr('action');
// update form attrs in IE friendly way
form.setAttribute('target',id);
if (form.getAttribute('method') != 'POST')
form.setAttribute('method', 'POST');
if (form.getAttribute('action') != opts.url)
form.setAttribute('action', opts.url);
// ie borks in some cases when setting encoding
if (! opts.skipEncodingOverride) {
$form.attr({
encoding: 'multipart/form-data',
enctype: 'multipart/form-data'
});
}
// support timout
if (opts.timeout)
setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
// add "extra" data to form if provided in options
var extraInputs = [];
try {
if (opts.extraData)
for (var n in opts.extraData)
extraInputs.push(
$('<input type="hidden" name="'+n+'" value="'+opts.extraData[n]+'" />')
.appendTo(form)[0]);
// add iframe to doc and submit the form
$io.appendTo('body');
$io.data('form-plugin-onload', cb);
form.submit();
}
finally {
// reset attrs and remove "extra" input elements
form.setAttribute('action',a);
t ? form.setAttribute('target', t) : $form.removeAttr('target');
$(extraInputs).remove();
}
};
if (opts.forceSync)
doSubmit();
else
setTimeout(doSubmit, 10); // this lets dom updates render
var domCheckCount = 100;
function cb() {
if (cbInvoked)
return;
var ok = true;
try {
if (timedOut) throw 'timeout';
// extract the server response from the iframe
var data, doc;
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
log('isXml='+isXml);
if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
if (--domCheckCount) {
// in some browsers (Opera) the iframe DOM is not always traversable when
// the onload callback fires, so we loop a bit to accommodate
log('requeing onLoad callback, DOM not available');
setTimeout(cb, 250);
return;
}
log('Could not access iframe DOM after 100 tries.');
return;
}
log('response detected');
cbInvoked = true;
xhr.responseText = doc.body ? doc.body.innerHTML : null;
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
xhr.getResponseHeader = function(header){
var headers = {'content-type': opts.dataType};
return headers[header];
};
if (opts.dataType == 'json' || opts.dataType == 'script') {
// see if user embedded response in textarea
var ta = doc.getElementsByTagName('textarea')[0];
if (ta)
xhr.responseText = ta.value;
else {
// account for browsers injecting pre around json response
var pre = doc.getElementsByTagName('pre')[0];
if (pre)
xhr.responseText = pre.innerHTML;
}
}
else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
xhr.responseXML = toXml(xhr.responseText);
}
data = $.httpData(xhr, opts.dataType);
}
catch(e){
log('error caught:',e);
ok = false;
xhr.error = e;
$.handleError(opts, xhr, 'error', e);
}
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
if (ok) {
opts.success(data, 'success');
if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
}
if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
if (g && ! --$.active) $.event.trigger("ajaxStop");
if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
// clean up
setTimeout(function() {
$io.removeData('form-plugin-onload');
$io.remove();
xhr.responseXML = null;
}, 100);
};
function toXml(s, doc) {
if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = 'false';
doc.loadXML(s);
}
else
doc = (new DOMParser()).parseFromString(s, 'text/xml');
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
};
};
};
/**
* ajaxForm() provides a mechanism for fully automating form submission.
*
* The advantages of using this method instead of ajaxSubmit() are:
*
* 1: This method will include coordinates for <input type="image" /> elements (if the element
* is used to submit the form).
* 2. This method will include the submit element's name/value data (for the element that was
* used to submit the form).
* 3. This method binds the submit() method to the form for you.
*
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
* passes the options argument along after properly binding events for submit elements and
* the form itself.
*/
$.fn.ajaxForm = function(options) {
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
e.preventDefault();
$(this).ajaxSubmit(options);
}).bind('click.form-plugin', function(e) {
var target = e.target;
var $el = $(target);
if (!($el.is(":submit,input:image"))) {
// is this a child element of the submit el? (ex: a span within a button)
var t = $el.closest(':submit');
if (t.length == 0)
return;
target = t[0];
}
var form = this;
form.clk = target;
if (target.type == 'image') {
if (e.offsetX != undefined) {
form.clk_x = e.offsetX;
form.clk_y = e.offsetY;
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
var offset = $el.offset();
form.clk_x = e.pageX - offset.left;
form.clk_y = e.pageY - offset.top;
} else {
form.clk_x = e.pageX - target.offsetLeft;
form.clk_y = e.pageY - target.offsetTop;
}
}
// clear form vars
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
});
};
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
return this.unbind('submit.form-plugin click.form-plugin');
};
/**
* formToArray() gathers form element data into an array of objects that can
* be passed to any of the following ajax functions: $.get, $.post, or load.
* Each object in the array has both a 'name' and 'value' property. An example of
* an array for a simple login form might be:
*
* [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
*
* It is this array that is passed to pre-submit callback functions provided to the
* ajaxSubmit() and ajaxForm() methods.
*/
$.fn.formToArray = function(semantic) {
var a = [];
if (this.length == 0) return a;
var form = this[0];
var els = semantic ? form.getElementsByTagName('*') : form.elements;
if (!els) return a;
for(var i=0, max=els.length; i < max; i++) {
var el = els[i];
var n = el.name;
if (!n) continue;
if (semantic && form.clk && el.type == "image") {
// handle image inputs on the fly when semantic == true
if(!el.disabled && form.clk == el) {
a.push({name: n, value: $(el).val()});
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
}
continue;
}
var v = $.fieldValue(el, true);
if (v && v.constructor == Array) {
for(var j=0, jmax=v.length; j < jmax; j++)
a.push({name: n, value: v[j]});
}
else if (v !== null && typeof v != 'undefined')
a.push({name: n, value: v});
}
if (!semantic && form.clk) {
// input type=='image' are not found in elements array! handle it here
var $input = $(form.clk), input = $input[0], n = input.name;
if (n && !input.disabled && input.type == 'image') {
a.push({name: n, value: $input.val()});
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
}
}
return a;
};
/**
* Serializes form data into a 'submittable' string. This method will return a string
* in the format: name1=value1&amp;name2=value2
*/
$.fn.formSerialize = function(semantic) {
//hand off to jQuery.param for proper encoding
return $.param(this.formToArray(semantic));
};
/**
* Serializes all field elements in the jQuery object into a query string.
* This method will return a string in the format: name1=value1&amp;name2=value2
*/
$.fn.fieldSerialize = function(successful) {
var a = [];
this.each(function() {
var n = this.name;
if (!n) return;
var v = $.fieldValue(this, successful);
if (v && v.constructor == Array) {
for (var i=0,max=v.length; i < max; i++)
a.push({name: n, value: v[i]});
}
else if (v !== null && typeof v != 'undefined')
a.push({name: this.name, value: v});
});
//hand off to jQuery.param for proper encoding
return $.param(a);
};
/**
* Returns the value(s) of the element in the matched set. For example, consider the following form:
*
* <form><fieldset>
* <input name="A" type="text" />
* <input name="A" type="text" />
* <input name="B" type="checkbox" value="B1" />
* <input name="B" type="checkbox" value="B2"/>
* <input name="C" type="radio" value="C1" />
* <input name="C" type="radio" value="C2" />
* </fieldset></form>
*
* var v = $(':text').fieldValue();
* // if no values are entered into the text inputs
* v == ['','']
* // if values entered into the text inputs are 'foo' and 'bar'
* v == ['foo','bar']
*
* var v = $(':checkbox').fieldValue();
* // if neither checkbox is checked
* v === undefined
* // if both checkboxes are checked
* v == ['B1', 'B2']
*
* var v = $(':radio').fieldValue();
* // if neither radio is checked
* v === undefined
* // if first radio is checked
* v == ['C1']
*
* The successful argument controls whether or not the field element must be 'successful'
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
* The default value of the successful argument is true. If this value is false the value(s)
* for each element is returned.
*
* Note: This method *always* returns an array. If no valid value can be determined the
* array will be empty, otherwise it will contain one or more values.
*/
$.fn.fieldValue = function(successful) {
for (var val=[], i=0, max=this.length; i < max; i++) {
var el = this[i];
var v = $.fieldValue(el, successful);
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
continue;
v.constructor == Array ? $.merge(val, v) : val.push(v);
}
return val;
};
/**
* Returns the value of the field element.
*/
$.fieldValue = function(el, successful) {
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
if (typeof successful == 'undefined') successful = true;
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
(t == 'checkbox' || t == 'radio') && !el.checked ||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
tag == 'select' && el.selectedIndex == -1))
return null;
if (tag == 'select') {
var index = el.selectedIndex;
if (index < 0) return null;
var a = [], ops = el.options;
var one = (t == 'select-one');
var max = (one ? index+1 : ops.length);
for(var i=(one ? index : 0); i < max; i++) {
var op = ops[i];
if (op.selected) {
var v = op.value;
if (!v) // extra pain for IE...
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
if (one) return v;
a.push(v);
}
}
return a;
}
return el.value;
};
/**
* Clears the form data. Takes the following actions on the form's input fields:
* - input text fields will have their 'value' property set to the empty string
* - select elements will have their 'selectedIndex' property set to -1
* - checkbox and radio inputs will have their 'checked' property set to false
* - inputs of type submit, button, reset, and hidden will *not* be effected
* - button elements will *not* be effected
*/
$.fn.clearForm = function() {
return this.each(function() {
$('input,select,textarea', this).clearFields();
});
};
/**
* Clears the selected form elements.
*/
$.fn.clearFields = $.fn.clearInputs = function() {
return this.each(function() {
var t = this.type, tag = this.tagName.toLowerCase();
if (t == 'text' || t == 'password' || tag == 'textarea')
this.value = '';
else if (t == 'checkbox' || t == 'radio')
this.checked = false;
else if (tag == 'select')
this.selectedIndex = -1;
});
};
/**
* Resets the form data. Causes all form elements to be reset to their original value.
*/
$.fn.resetForm = function() {
return this.each(function() {
// guard against an input with the name of 'reset'
// note that IE reports the reset function as an 'object'
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
this.reset();
});
};
/**
* Enables or disables any matching elements.
*/
$.fn.enable = function(b) {
if (b == undefined) b = true;
return this.each(function() {
this.disabled = !b;
});
};
/**
* Checks/unchecks any matching checkboxes or radio buttons and
* selects/deselects and matching option elements.
*/
$.fn.selected = function(select) {
if (select == undefined) select = true;
return this.each(function() {
var t = this.type;
if (t == 'checkbox' || t == 'radio')
this.checked = select;
else if (this.tagName.toLowerCase() == 'option') {
var $sel = $(this).parent('select');
if (select && $sel[0] && $sel[0].type == 'select-one') {
// deselect all other options
$sel.find('option').selected(false);
}
this.selected = select;
}
});
};
// helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
if ($.fn.ajaxSubmit.debug) {
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
if (window.console && window.console.log)
window.console.log(msg);
else if (window.opera && window.opera.postError)
window.opera.postError(msg);
}
};
})(jQuery);

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

@ -1,86 +0,0 @@
// set up newsletter signup widget
$(document).ready(function() {
$("#email").show()
var error = $('#error-box');
var errorMessages = {
'email': 'Whoops! Be sure to enter a valid email address.',
'privacy': 'Please read the Mozilla Privacy Policy and agree ' +
'by checking the box.',
'email-privacy': 'Please enter your email address and review the ' +
'Mozilla Privacy Policy.'
}
function showError(message)
{
error.empty();
error.append(message);
error.fadeIn();
}
function hideError()
{
error.empty();
error.fadeOut();
}
function validateEmail(email)
{
return /^([\w\-.+])+@([\w\-.])+\.[A-Za-z]{2,4}$/.test(email);
}
function validateForm(formData, jqForm, options)
{
form = jqForm[0];
var valid = true;
var privacy = form.privacy.checked;
var email = validateEmail(form.email.value);
if (email) {
$(form.email).removeClass('form-error');
} else {
$(form.email).addClass('form-error');
valid = false;
}
if (privacy) {
$(form.privacy).parent().removeClass('form-error');
} else {
$(form.privacy).parent().addClass('form-error');
valid = false;
}
// show or hide error messages
if (!email && !privacy) {
showError(errorMessages['email-privacy']);
} else if (!email) {
showError(errorMessages['email']);
} else if (!privacy) {
showError(errorMessages['privacy']);
} else {
hideError();
}
return valid;
}
$('#email-start').click(function(e) {
e.preventDefault();
$(this).fadeOut(function () {
$('#email-form').fadeIn();
});
});
$("#email-form form").ajaxForm({
beforeSubmit: validateForm,
type: 'POST',
success: function () {
$("#email-form").fadeOut(function () {
$("#email-finish").fadeIn();
})
}
});
});

12
media/js/firefoxcup/yahoo-dom-event.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -0,0 +1 @@
DROP TABLE `stats_firefoxcup`;

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

@ -26,4 +26,3 @@ django-pylibmc==0.2.1
-e git://github.com/clouserw/tower.git#egg=tower
-e git://github.com/jbalogh/django-queryset-transform.git#egg=django-queryset-transform
-e git://github.com/jsocol/commonware.git#egg=commonware
-e git://github.com/abuchanan/twitter-text-python.git#egg=twitter-text-python

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

@ -45,7 +45,6 @@ HOME = /tmp
40 21 * * * cd /data/amo/www/addons.mozilla.org-preview/bin; /usr/bin/python26 maintenance.py weekly
35 22 * * * cd /data/amo_python/src/preview/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron update_global_totals
40 22 * * * cd /data/amo_python/src/preview/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron update_addon_average_daily_users
40 23 * * * cd /data/amo_python/src/preview/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron firefoxcup_stats
# Once per week
45 23 * * 4 cd /data/amo/www/addons.mozilla.org-preview/bin; php -f maintenance.php unconfirmed

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

@ -43,7 +43,6 @@ MAILTO=amo-developers@mozilla.org
40 21 * * * apache cd /data/amo/www/addons.mozilla.org-remora/bin; /usr/bin/python26 maintenance.py weekly
35 22 * * * apache cd /data/amo_python/src/prod/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron update_global_totals
40 22 * * * apache cd /data/amo_python/src/prod/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron update_addon_average_daily_users
40 23 * * * apache cd /data/amo_python/src/prod/zamboni; /data/virtualenvs/zamboni/bin/python manage.py cron firefoxcup_stats
# Once per week
45 23 * * 4 apache cd /data/amo/www/addons.mozilla.org-remora/bin; php -f maintenance.php unconfirmed

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

@ -65,9 +65,9 @@ LANGUAGE_CODE = 'en-US'
# Accepted locales
AMO_LANGUAGES = (
'af', 'ar', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', 'en-US', 'es-ES',
'af', 'ar', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en-US', 'es-ES',
'eu', 'fa', 'fi', 'fr', 'ga-IE', 'he', 'hu', 'id', 'it', 'ja', 'ko', 'mn',
'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sl', 'sk', 'sq', 'sr', 'sv-SE',
'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sq', 'sr', 'sv-SE',
'uk', 'vi', 'zh-CN', 'zh-TW',
)
@ -122,7 +122,7 @@ UPLOADS_PATH = NETAPP_STORAGE + '/uploads'
ADMIN_MEDIA_PREFIX = '/admin-media/'
# paths that don't require an app prefix
SUPPORTED_NONAPPS = ('admin', 'developers', 'editors', 'firefoxcup', 'img',
SUPPORTED_NONAPPS = ('admin', 'developers', 'editors', 'img',
'jsi18n', 'localizers', 'media', 'statistics', 'services')
DEFAULT_APP = 'firefox'
@ -227,7 +227,6 @@ INSTALLED_APPS = (
'discovery',
'editors',
'files',
'firefoxcup',
'jingo_minify',
'nick',
'pages',
@ -274,15 +273,7 @@ SELENIUM_CONFIG = {}
# Tells the extract script what files to look for l10n in and what function
# handles the extraction. The Tower library expects this.
DOMAIN_METHODS = {
'firefoxcup': [
('apps/firefoxcup/**.py',
'tower.management.commands.extract.extract_tower_python'),
('apps/firefoxcup/templates/firefoxcup/**.html',
'tower.management.commands.extract.extract_tower_template'),
],
'messages': [
('apps/firefoxcup/**',
'ignore'),
('apps/**.py',
'tower.management.commands.extract.extract_tower_python'),
('**/templates/**.html',
@ -306,7 +297,6 @@ DOMAIN_METHODS = {
# files.
STANDALONE_DOMAINS = [
'javascript',
'firefoxcup',
]
# Bundles is a dictionary of two dictionaries, css and js, which list css files
@ -328,13 +318,6 @@ MINIFY_BUNDLES = {
'zamboni/discovery-pane': (
'css/zamboni/discovery-pane.css',
),
# CSS files specific to /firefoxcup/
'firefoxcup/f': (
'css/firefoxcup/reset-fonts-grids.css',
'css/main.css',
'css/zamboni/zamboni.css',
'css/firefoxcup/firefoxcup.css',
),
},
'js': {
# JS files common to the entire site.
@ -368,19 +351,6 @@ MINIFY_BUNDLES = {
# Collections
'js/zamboni/collections.js',
),
# JS files specific to /firefoxcup/
'firefoxcup': (
'js/zamboni/jquery-1.4.2.min.js',
'js/firefoxcup/browserdetect.js',
'js/firefoxcup/yahoo-dom-event.js',
'js/firefoxcup/animation.js',
'js/zamboni/jquery.hoverIntent.min.js',
'js/zamboni/personas.js',
'js/zamboni/jquery.sparkline.min.js',
'js/firefoxcup/jquery.form.js',
'js/firefoxcup/newsletter_form.js',
'js/firefoxcup/firefoxcup.js',
),
}
}