bug 578087, kill fxcup
|
@ -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') }}"> </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 & tricks.</span>
|
||||
</a>
|
||||
<div id="email-form">
|
||||
<p>Subscribe to our email Newsletter to receive special Mozilla news, Firefox tips & 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 & tricks on getting the most out of Firefox, as well as exciting news about Mozilla and how we’re 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 |
Двоичные данные
media/img/zamboni/promos/FirefoxCup_AddsOn_banner.jpg
До Ширина: | Высота: | Размер: 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&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&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();
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
|
@ -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
|
||||
|
|
36
settings.py
|
@ -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',
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|