[editpage] Basic information (Bug 604151)
This commit is contained in:
Родитель
50f3714460
Коммит
7aa9ca34c3
|
@ -3,7 +3,24 @@ from django import forms
|
|||
import happyforms
|
||||
|
||||
from addons.models import Addon
|
||||
from translations.widgets import TranslationTextInput
|
||||
from amo.utils import slug_validator
|
||||
from tower import ugettext as _
|
||||
from translations.widgets import TranslationTextInput, TranslationTextarea
|
||||
|
||||
|
||||
class AddonFormBasic(happyforms.ModelForm):
|
||||
name = forms.CharField(widget=TranslationTextInput, max_length=70)
|
||||
slug = forms.CharField(max_length=30)
|
||||
summary = forms.CharField(widget=TranslationTextarea, max_length=250)
|
||||
|
||||
def clean_slug(self):
|
||||
target = self.cleaned_data['slug']
|
||||
slug_validator(target, lower=False)
|
||||
|
||||
if self.cleaned_data['slug'] != self.instance.slug:
|
||||
if Addon.objects.filter(slug=target).exists():
|
||||
raise forms.ValidationError(_('This slug is already in use.'))
|
||||
return target
|
||||
|
||||
|
||||
class AddonForm(happyforms.ModelForm):
|
||||
|
|
|
@ -7,6 +7,7 @@ import time
|
|||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.db.models import Q, Sum, Max
|
||||
from django.utils.translation import trans_real as translation
|
||||
|
||||
import caching.base as caching
|
||||
import commonware.log
|
||||
|
@ -92,6 +93,8 @@ class AddonManager(amo.models.ManagerBase):
|
|||
|
||||
class Addon(amo.models.ModelBase):
|
||||
STATUS_CHOICES = amo.STATUS_CHOICES.items()
|
||||
LOCALES = [(translation.to_language(k), v) for k, v in
|
||||
settings.LANGUAGES.items()]
|
||||
|
||||
guid = models.CharField(max_length=255, unique=True, null=True)
|
||||
slug = models.CharField(max_length=30)
|
||||
|
|
|
@ -28,283 +28,11 @@
|
|||
|
||||
<section class="primary" role="main">
|
||||
<div id="edit-addon">
|
||||
<h3>
|
||||
{{ _('Basic Information') }}
|
||||
<input type="submit" value="{{ _('Edit') }}">
|
||||
</h3>
|
||||
<div class="item">
|
||||
<table>
|
||||
<caption>{{ _('Basic Information for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<td> {{ addon.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Add-on URL"),
|
||||
_("Choose a short, unique URL slug for your add-on.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{# TODO: Eventually this needs a slug. #}
|
||||
<a href="{{ addon.get_url_path() }}">
|
||||
{{ settings.SITE_URL }}/…/
|
||||
{{ addon.id }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Summary"),
|
||||
_("A short explanation of your add-on's basic functionality
|
||||
that is displayed in search and browse listings, as well as
|
||||
at the top of your add-on's details page.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{{ addon.summary|nl2br }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Categories"),
|
||||
_("Categories are the primary way users browse through add-ons.
|
||||
Choose any that fit your add-on's functionality for the most
|
||||
exposure.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{{ addon.categories.all()|join(' · ')|safe }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
|
||||
|
||||
{{ tip(_("Tags"),
|
||||
_("Tags help users find your add-on and should be short
|
||||
descriptors such as tabs, toolbar, or twitter.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(tags_dev) %}
|
||||
{{ tags_dev|join(', ') }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ _('User Tags') }}</th>
|
||||
<td>
|
||||
{% call empty_unless(tags_user) %}
|
||||
{{ tags_user|join(', ') }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
{{ _('Images and Videos') }} <input type="submit" value="{{ _('Edit') }}">
|
||||
</h3>
|
||||
<div class="item">
|
||||
<table>
|
||||
<caption>{{ _('Add-on Details for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Add-on Icon"),
|
||||
_("Upload an icon for your add-on or choose from one of ours.
|
||||
The icon is displayed nearly everywhere your add-on is.
|
||||
Uploaded images will be resized to 32 x 32 pixels and must be
|
||||
one of the following image types: .png, .jpg, .gif")) }}
|
||||
</th>
|
||||
<td>
|
||||
<img src="{{ addon.icon_url }}">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>{{ _('Screenshots and Videos') }}</th>
|
||||
<td>
|
||||
{% if previews %}
|
||||
{% for preview in preview %}
|
||||
<img src="{{ preview.thumbnail_url }}">
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="edit-addon-section" id="edit-addon-basic">
|
||||
{% include 'devhub/includes/addon_edit_basic.html' %}
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
{{ _('Add-on Details') }} <input type="submit" value="{{ _('Edit') }}">
|
||||
</h3>
|
||||
<div class="item">
|
||||
<table>
|
||||
<caption>{{ _('Add-on Details for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Description"),
|
||||
_("A longer explanation of features, functionality, and other
|
||||
relevant information. This field is only displayed on the
|
||||
add-on's details page.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(addon.description) %}
|
||||
{{ addon.description }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Default Locale"),
|
||||
_("Information about your add-on is displayed in this locale
|
||||
unless you override it with a locale-specific translation.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{{ addon.default_locale }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Homepage"),
|
||||
_("If your add-on has another homepage, enter its address here.
|
||||
If your website is localized into other languages, multiple
|
||||
translations of this field can be added.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(addon.homepage) %}
|
||||
{{ addon.homepage }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
{{ _('Support Information') }} <input type="submit" value="{{ _('Edit') }}">
|
||||
</h3>
|
||||
<div class="item">
|
||||
<table>
|
||||
<caption>{{ _('Support Information for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Email"),
|
||||
_("If you wish to display an e-mail address for support inquiries,
|
||||
enter it here. If you have different addresses for each language,
|
||||
multiple translations of this field can be added.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(addon.support_email) %}
|
||||
{{ addon.support_email }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Website"),
|
||||
_("If your add-on has a support website or forum, enter its
|
||||
address here. If your website is localized into other
|
||||
languages, multiple translations of this field can be added.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(addon.support_url) %}
|
||||
{{ addon.support_url }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ _('Get Satisfaction') }}</th>
|
||||
<td>
|
||||
{% if addon.get_satisfaction_company %}
|
||||
{{ addon.get_satisfaction_company }}
|
||||
{% if addon.get_satisfaction_product %}
|
||||
» {{ addon.get_satisfaction_product }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="empty">{{ _('Not Used') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
{{ _('Technical Details') }} <input type="submit" value="{{ _('Edit') }}">
|
||||
</h3>
|
||||
<div class="item">
|
||||
<table>
|
||||
<caption>{{ _('Technical Details for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Developer Comments"),
|
||||
_("Any information end users may want to know that isn't
|
||||
necessarily applicable to the add-on summary or description.
|
||||
Common uses include listing known major bugs, information on
|
||||
how to report bugs, anticipated release date of a new version,
|
||||
etc.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% call empty_unless(addon.developer_comments) %}
|
||||
{{ addon.developer_comments|nl2br }}
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ _('Required Add-ons') }}</th>
|
||||
<td>
|
||||
{# TODO(gkoberger) #}
|
||||
<strong>{{ _('Coming Soon') }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Add-on flags"),
|
||||
_("These flags are used to classify add-ons.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{# TODO(gkoberger) #}
|
||||
<strong>{{ _('Coming Soon') }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("View source?"),
|
||||
_("Whether the source of your add-on can be displayed in our
|
||||
online viewer.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% if addon.view_source %}
|
||||
{{ _("Yes, this add-on's source code is publicly viewable") }}
|
||||
{% else %}
|
||||
{{ _("No, this add-on's source code is not publicly viewable") }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>
|
||||
<abbr title="{{ _('Universally unique identifier') }}" class="label">
|
||||
{{ _('UUID') }}
|
||||
</abbr>
|
||||
<span class="help tooltip" title="{% trans -%}The UUID of your
|
||||
add-on is specified in its install manifest and uniquely
|
||||
identifies it. You cannot change your UUID once it has been
|
||||
submitted.{%- endtrans %}">?</span>
|
||||
</th>
|
||||
<td>
|
||||
{{ addon.guid }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
{% from "devhub/includes/macros.html" import tip, empty_unless %}
|
||||
|
||||
<form method="post" action="{{ url('devhub.addons.section', addon.id, 'basic', 'edit') }}">
|
||||
<h3>
|
||||
{{ _('Basic Information') }}
|
||||
{% if not editable %}
|
||||
<a href="{{ url('devhub.addons.section', addon.id, 'basic', 'edit') }}" class="button">
|
||||
{{ _('Edit') }}</a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<div class="item">
|
||||
<div class="item_wrapper">
|
||||
<table>
|
||||
{# L10n: {0} is the addon name #}
|
||||
<caption>{{ _('Basic Information for {0}')|f(addon.name) }}</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{ _("Name") }}</th>
|
||||
<td>
|
||||
{% if editable %}
|
||||
{{ form.name|safe }}
|
||||
{{ form.name.errors|safe }}
|
||||
{% else %}
|
||||
{{ addon.name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Add-on URL"),
|
||||
_("Choose a short, unique URL slug for your add-on.")) }}
|
||||
</th>
|
||||
<td id="slug_edit">
|
||||
{% if editable %}
|
||||
<span>{{ settings.SITE_URL }}/…/</span>{{ form.slug|safe }}
|
||||
{{ form.slug.errors|safe }}
|
||||
{% else %}
|
||||
<a href="{{ addon.get_url_path() }}">
|
||||
{{ settings.SITE_URL }}/…/{{ addon.slug }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Summary"),
|
||||
_("A short explanation of your add-on's basic functionality
|
||||
that is displayed in search and browse listings, as well as
|
||||
at the top of your add-on's details page.")) }}
|
||||
</th>
|
||||
<td>
|
||||
{% if editable %}
|
||||
{{ form.summary|safe }}
|
||||
{{ form.summary.errors|safe }}
|
||||
{% else %}
|
||||
{{ addon.summary|nl2br }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Categories"),
|
||||
_("Categories are the primary way users browse through add-ons.
|
||||
Choose any that fit your add-on's functionality for the most
|
||||
exposure.")) }}
|
||||
</th>
|
||||
<td id="addon_categories_edit">
|
||||
{% if editable %}
|
||||
{# TODO(gkoberger): Add categories #}
|
||||
<strong>Coming Soon</strong>
|
||||
{% else %}
|
||||
{{ addon.categories.all()|join(' · ')|safe }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_("Tags"),
|
||||
_("Tags help users find your add-on and should be short
|
||||
descriptors such as tabs, toolbar, or twitter. You
|
||||
may have a maximum of {0} tags.").format(amo.MAX_TAGS)) }}
|
||||
</th>
|
||||
<td>
|
||||
{% if editable %}
|
||||
{# TODO(gkoberger): Add tags #}
|
||||
<strong>Coming Soon</strong>
|
||||
{% else %}
|
||||
{% call empty_unless(tags) %}
|
||||
{{ tags|join(', ') }}
|
||||
{% endcall %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if editable %}
|
||||
<div class="listing-footer">
|
||||
<button type="submit">{{ _('Save Changes') }}</button> {{ _('or') }}
|
||||
<a href="{{ url('devhub.addons.section', addon.id, 'basic') }}"
|
||||
class="addon-edit-cancel">
|
||||
{{ _('Cancel') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{% macro tip(name, tip) %}
|
||||
<span class="label">{{ name }}</span>
|
||||
<span class="help tooltip" title="{{ tip }}">?</span>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro empty_unless(truthy) %}
|
||||
{% if truthy %}
|
||||
{{ caller() }}
|
||||
{% else %}
|
||||
<span class="empty">{{ _('None') }}</span>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro flags(text, element, editable, alt_text=False) %}
|
||||
{% if editable %}
|
||||
<div>
|
||||
{{ element|safe }}
|
||||
{{ element.errors|safe }}
|
||||
<label for="id_{{ element.html_name }}">{{ text }}
|
||||
</div>
|
||||
{% elif element %}
|
||||
{{ text }}
|
||||
{% elif alt_text %}
|
||||
{# This is what's shown if the element is false #}
|
||||
{# Defaults to nothing #}
|
||||
{{ alt_text }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
|
@ -525,7 +525,6 @@ class TestEditPayments(test_utils.TestCase):
|
|||
eq_(ContribForm.initial(self.addon)['annoying'], amo.CONTRIB_AFTER)
|
||||
|
||||
|
||||
|
||||
class TestDisablePayments(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615']
|
||||
|
||||
|
@ -553,10 +552,19 @@ class TestDisablePayments(test_utils.TestCase):
|
|||
|
||||
|
||||
class TestEdit(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615']
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615',
|
||||
'base/addon_5579']
|
||||
|
||||
def setUp(self):
|
||||
super(TestEdit, self).setUp()
|
||||
self.addon = self.get_addon()
|
||||
assert self.client.login(username='del@icio.us', password='password')
|
||||
self.url = reverse('devhub.addons.edit', args=[self.addon.id])
|
||||
self.url_section = reverse('devhub.addons.section',
|
||||
args=[self.addon.id, 'basic', 'edit'])
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.no_cache().get(id=3615)
|
||||
|
||||
def test_redirect(self):
|
||||
# /addon/:id => /addon/:id/edit
|
||||
|
@ -564,6 +572,46 @@ class TestEdit(test_utils.TestCase):
|
|||
url = reverse('devhub.addons.edit', args=[3615])
|
||||
self.assertRedirects(r, url, 301)
|
||||
|
||||
def test_edit_basic(self):
|
||||
old_name = self.addon.name
|
||||
|
||||
data = dict(name='new name',
|
||||
slug='test_addon',
|
||||
summary='new summary')
|
||||
|
||||
r = self.client.post(self.url_section, data)
|
||||
eq_(r.status_code, 200)
|
||||
addon = self.get_addon()
|
||||
|
||||
eq_(unicode(addon.name), data['name'])
|
||||
eq_(addon.name.id, old_name.id)
|
||||
|
||||
eq_(unicode(addon.slug), data['slug'])
|
||||
eq_(unicode(addon.summary), data['summary'])
|
||||
|
||||
def test_edit_basic_slugs_unique(self):
|
||||
Addon.objects.get(id=5579).update(slug='test_slug')
|
||||
|
||||
data = dict(name='new name',
|
||||
slug='test_slug',
|
||||
summary='new summary')
|
||||
|
||||
r = self.client.post(self.url_section, data)
|
||||
eq_(r.status_code, 200)
|
||||
|
||||
self.assertFormError(r, 'form', 'slug', 'This slug is already in use.')
|
||||
|
||||
def test_edit_basic_name_not_empty(self):
|
||||
|
||||
data = dict(name='',
|
||||
slug=self.addon.slug,
|
||||
summary=self.addon.summary)
|
||||
|
||||
r = self.client.post(self.url_section, data)
|
||||
eq_(r.status_code, 200)
|
||||
|
||||
self.assertFormError(r, 'form', 'name', 'This field is required.')
|
||||
|
||||
|
||||
class TestProfile(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615']
|
||||
|
|
|
@ -17,7 +17,8 @@ detail_patterns = patterns('',
|
|||
url('^payments/disable$', views.disable_payments,
|
||||
name='devhub.addons.payments.disable'),
|
||||
url('^profile$', views.profile, name='devhub.addons.profile'),
|
||||
)
|
||||
url('^edit_(?P<section>[^/]+)(?:/(?P<editable>[^/]+))?$',
|
||||
views.addons_section, name='devhub.addons.section'))
|
||||
|
||||
urlpatterns = decorate(write, patterns('',
|
||||
url('^$', views.index, name='devhub.index'),
|
||||
|
@ -25,7 +26,8 @@ urlpatterns = decorate(write, patterns('',
|
|||
# URLs for a single add-on.
|
||||
('^addon/(?P<addon_id>\d+)/', include(detail_patterns)),
|
||||
# Redirect people who have /addons/ instead of /addon/.
|
||||
('^addons/\d+/.*', lambda r: redirect(r.path.replace('addons', 'addon', 1))),
|
||||
('^addons/\d+/.*',
|
||||
lambda r: redirect(r.path.replace('addons', 'addon', 1))),
|
||||
|
||||
# Redirect to /addons/ at the base.
|
||||
url('^addon$', lambda r: redirect('devhub.addons', permanent=True)),
|
||||
|
@ -34,5 +36,4 @@ urlpatterns = decorate(write, patterns('',
|
|||
name='devhub.addons.activity'),
|
||||
url('^upload$', views.upload, name='devhub.upload'),
|
||||
url('^upload/([^/]+)$', views.upload_detail,
|
||||
name='devhub.upload_detail'),
|
||||
))
|
||||
name='devhub.upload_detail')))
|
||||
|
|
|
@ -4,6 +4,7 @@ import uuid
|
|||
from django import http
|
||||
from django.conf import settings
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.translation import trans_real as translation
|
||||
|
||||
import commonware.log
|
||||
import jingo
|
||||
|
@ -13,6 +14,7 @@ from tower import ugettext_lazy as _lazy
|
|||
import amo.utils
|
||||
from amo.decorators import login_required, post_required
|
||||
from access import acl
|
||||
from addons.forms import AddonFormBasic
|
||||
from addons.models import Addon, AddonUser, AddonLog
|
||||
from addons.views import BaseFilter
|
||||
from files.models import FileUpload
|
||||
|
@ -90,15 +92,13 @@ def activity(request):
|
|||
|
||||
@dev_required
|
||||
def edit(request, addon_id, addon):
|
||||
tags_dev, tags_user = addon.tags_partitioned_by_developer
|
||||
|
||||
data = {
|
||||
'page': 'edit',
|
||||
'addon': addon,
|
||||
'tags_user': [tag.tag_text for tag in tags_dev],
|
||||
'tags_dev': [tag.tag_text for tag in tags_user],
|
||||
'previews': addon.previews.all(),
|
||||
}
|
||||
'page': 'edit',
|
||||
'addon': addon,
|
||||
'tags': addon.tags.not_blacklisted().values_list('tag_text', flat=True),
|
||||
'previews': addon.previews.all(),
|
||||
}
|
||||
|
||||
return jingo.render(request, 'devhub/addons/edit.html', data)
|
||||
|
||||
|
@ -202,6 +202,7 @@ def profile(request, addon_id, addon):
|
|||
return jingo.render(request, 'devhub/addons/profile.html',
|
||||
dict(addon=addon, profile_form=profile_form))
|
||||
|
||||
|
||||
def upload(request):
|
||||
if request.method == 'POST' and 'upload' in request.FILES:
|
||||
upload = request.FILES['upload']
|
||||
|
@ -228,3 +229,38 @@ def upload_detail(request, uuid):
|
|||
upload = get_object_or_404(FileUpload.uncached, uuid=uuid)
|
||||
return jingo.render(request, 'devhub/validation.html',
|
||||
dict(upload=upload))
|
||||
|
||||
|
||||
@dev_required
|
||||
def addons_section(request, addon_id, addon, section, editable=False):
|
||||
|
||||
models = {'basic': AddonFormBasic}
|
||||
|
||||
if section not in models:
|
||||
return http.HttpResponseNotFound()
|
||||
|
||||
if editable:
|
||||
if request.method == 'POST':
|
||||
form = models[section](request.POST, request.FILES,
|
||||
instance=addon)
|
||||
if form.is_valid():
|
||||
addon = form.save(addon)
|
||||
editable = False
|
||||
|
||||
AddonLog.log(models[section], request, addon=addon,
|
||||
action='edit '+section)
|
||||
else:
|
||||
form = models[section](instance=addon)
|
||||
else:
|
||||
form = False
|
||||
|
||||
tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True)
|
||||
|
||||
data = {'addon': addon,
|
||||
'form': form,
|
||||
'lang': lang,
|
||||
'editable': editable,
|
||||
'tags': tags}
|
||||
|
||||
return jingo.render(request,
|
||||
'devhub/includes/addon_edit_%s.html' % section, data)
|
||||
|
|
|
@ -131,7 +131,6 @@
|
|||
/** This is so they match up size-wise **/
|
||||
}
|
||||
|
||||
|
||||
#edit-addon label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ header hgroup h3 {
|
|||
ul.errorlist {
|
||||
margin-bottom: 0;
|
||||
color: #c00;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.html-ltr a.more-link:after {
|
||||
|
@ -759,8 +760,6 @@ div.popup-shim {
|
|||
#tooltip span {
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
max-height: 3.8em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#tooltip:before {
|
||||
|
@ -2632,12 +2631,6 @@ label > .optional {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#slug_edit {
|
||||
display: none;
|
||||
}
|
||||
#slug_value {
|
||||
font-weight: bold;
|
||||
}
|
||||
#ajax_collections_list li {
|
||||
cursor: pointer;
|
||||
padding-left: 30px;
|
||||
|
|
|
@ -6,6 +6,25 @@ $(document).ready(function() {
|
|||
return {pointTo: $(obj.click_target)};
|
||||
}
|
||||
});
|
||||
|
||||
$('#edit-addon').delegate('h3 a', 'click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
parent_div = $(this).closest('.edit-addon-section');
|
||||
a = $(this);
|
||||
|
||||
(function(parent_div, a){
|
||||
parent_div.load($(a).attr('href'), addonFormSubmit);
|
||||
})(parent_div, a);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.addon-edit-cancel').live('click', function(){
|
||||
parent_div = $(this).closest('.edit-addon-section');
|
||||
parent_div.load($(this).attr('href'));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
function addonFormSubmit() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче