prettify admin featured apps tool (bug 763700)

This commit is contained in:
Davor Spasovski 2012-11-15 11:53:13 -08:00
Родитель 2395baa437
Коммит 7d8ae4990b
5 изменённых файлов: 346 добавлений и 231 удалений

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

@ -592,7 +592,9 @@ MINIFY_BUNDLES = {
'zamboni/admin': (
'css/zamboni/admin-django.css',
'css/zamboni/admin-mozilla.css',
'css/zamboni/admin_features.css'
'css/zamboni/admin_features.css',
# Datepicker styles and jQuery UI core.
'css/zamboni/jquery-ui/custom-1.7.2.css',
),
},
'js': {

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

@ -95,3 +95,130 @@ th {
#features tr:hover a.remove:hover {
background-color: #2a4364;
}
#featured-webapps {
margin-top: 15px;
}
.app-container {
background-color: #eee;
border-radius: 5px;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
}
.featured-app {
border-radius: 5px;
float: left;
margin: 0;
}
.featured-app .dashboard {
display: inline-block;
border-radius: 5px;
background: #fff;
padding: 1px 5px;
}
.featured-app .dashboard em {
margin-left: 4px;
vertical-align: middle;
}
.featured-app .dashboard a {
position: relative;
top: 3px;
}
.featured-app .dashboard a:hover {
text-decoration: none;
}
.featured-app h2 {
font-size: 16px;
display: inline-block;
line-height: 32px;
margin: 0 15px 0 10px;
}
.featured-app li {
vertical-align: middle;
}
.featured-app img.logo {
position: relative;
top: 10px;
}
.app-intro p {
font-size: 10px;
}
.featured-app p {
display: inline-block;
margin: 0;
}
.featured-app .icon {
display: inline-block;
background: url(../../img/mkt/icons/mkt-reviewer-icons.png) no-repeat 0 0;
height: 16px;
width: 16px;
}
.featured-app .icon.warning {background-position: 0 -32px;}
.featured-app .icon.sponsored {background-position: -32px 0;}
#featured-webapps .side {
float: right;
padding: 10px;
border-radius: 5px;
background-color: #fff;
width: 250px;
}
#featured-webapps .side p {
float: right;
margin: 0;
}
#featured-webapps .side li {
font-size: 10px;
}
#featured-webapps .side label {
display: block;
font-size: 12px;
}
#featured-webapps .side .devicelist {
float: left;
margin: 0 10px 0 0;
}
.featured-app .dates {
padding-top: 10px;
}
.featured-app .dates label {
display: inline-block;
margin-right: 15px;
}
.featured-app input[type=date], #featured-webapps input.placeholder {
border: 0;
line-height: 22px;
height: 22px;
border-radius: 5px;
}
#featured-webapps input.placeholder {
border: 1px solid #ccc;
width: 350px;
}
.featured-app .app-intro {
padding-bottom: 15px;
}
a.remove {
margin-left: 10px;
text-indent: -99999px;
width: 22px;
height: 22px;
background: #999 url(../../img/mkt/header-icons.png) no-repeat -1px -26px;
border-radius: 50%;
}
a.remove:last-child {
margin-right: 10px;
}
li.ui-menu-item .ui-corner-all.ui-state-hover {
border: 0;
}
ul.ui-autocomplete {
border-radius: 5px;
}
#ui-datepicker-div {
display: none;
}
.ui-datepicker .ui-datepicker-header {
height: 25px;
}

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

@ -1,177 +1,167 @@
function registerAddonAutocomplete(node) {
var $td = node.closest('td');
node.autocomplete({
minLength: 3,
width: 300,
source: function(request, response) {
$.getJSON($(node).attr('data-src'), {
q: request.term,
category: $("#categories").val()
}, response);
},
focus: function(event, ui) {
$(node).val(ui.item.name);
return false;
},
select: function(event, ui) {
updateAppsList($("#categories"),
ui.item.id).then(
function(x) {
registerDatepickers($("#featured-webapps"));
});
return false;
}
}).data('autocomplete')._renderItem = function(ul, item) {
var html = format('<a>{0}<b>ID: {1}</b></a>', [item.name, item.id]);
return $('<li>').data('item.autocomplete', item).append(html).appendTo(ul);
};
}
(function() {
var $featured = $('#featured-webapps');
function registerDatepickers() {
$("#featured-webapps .featured-app").each(function (i, n) { registerDatepicker($(n));});
}
function registerAddonAutocomplete(node) {
var $node = $(node);
function registerDatepicker(node) {
var $startPicker = node.find('.start-date-picker');
var $tabl = $startPicker.closest('table').last();
var url = $tabl.data('url');
var appid = $tabl.data('app-id');
var $start = node.find('.date-range-start');
var $end = node.find('.date-range-end');
$startPicker.datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function(dateText) {
$start.val(dateText);
saveFeaturedDate(url, appid, dateText, $end.val());
}
});
var $endPicker = node.find('.end-date-picker');
$endPicker.datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function(dateText) {
$end.val(dateText);
saveFeaturedDate(url, appid, $start.val(), dateText);
}
});
$node.autocomplete({
'minLength': 3,
'width': 300,
'source': function(request, response) {
$.getJSON($node.attr('data-src'), {
'q': request.term,
'category': $('#categories').val()
}, response);
},
'focus': function(event, ui) {
$node.val(ui.item.name);
return false;
},
'select': function(event, ui) {
updateAppsList($('#categories'), ui.item.id).then(function() {
registerDatepickers();
});
return false;
}
}).data('autocomplete')._renderItem = function(ul, item) {
var html = format('<a href="#">{0}<b>ID: {1}</b></a>', [item.name, item.id]);
return $('<li>').data('item.autocomplete', item).append(html)
.appendTo(ul);
};
}
$start.change(
function (e) {
saveFeaturedDate($tabl.data('url'), $tabl.data('app-id'), $start.val(), $end.val());
});
$end.change(
function (e) {
saveFeaturedDate($tabl.data('url'), $tabl.data('app-id'), $start.val(), $end.val());
});
function registerDatepickers() {
$('#featured-webapps input[type=date]').each(function(i, elm) {
var $this = $(elm);
var $app = $this.closest('.featured-app');
var $siblingDate = $this.siblings('input[type=date]');
var url = $app.data('url');
var appid = $app.data('app-id');
var isStartDate = $siblingDate.hasClass('date-range-start');
$this.datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function(dateText) {
if (isStartDate) {
saveFeaturedDate(url, appid, dateText, $siblingDate.val());
} else {
saveFeaturedDate(url, appid, $siblingDate.val(), dateText);
}
}
});
$this.change(function(e) {
if (isStartDate) {
saveFeaturedDate($app.data('url'), $app.data('app-id'),
$this.val(), $siblingDate.val());
} else {
saveFeaturedDate($app.data('url'), $app.data('app-id'),
$siblingDate.val(), $this.val());
}
});
});
}
}
function saveFeaturedDate(url, appid, start, end) {
var data = {};
data.startdate = start;
data.enddate = end;
data.app = appid;
$.ajax({'type': 'POST', 'url': url, 'data': data});
}
function saveFeaturedDate(url, appid, start, end) {
var data = {};
data["startdate"] = start;
data["enddate"] = end;
data.app = appid;
$.ajax({type: 'POST', url: url, data: data});
}
function newAddonSlot(id) {
var $container = $featured;
var $next = $container.next();
var $form = $next.children().clone();
function newAddonSlot(id) {
var $tbody = $("#featured-webapps");
var $form = $tbody.next().children("tr").clone();
var $input = $form.find('input.placeholder');
registerAddonAutocomplete($input);
$tbody.append($form);
}
// This seems to be the best way to send the input for autocompletion.
registerAddonAutocomplete($form[1]);
$container.append($form);
}
function showAppsList(cat) {
return appslistXHR('GET', {
category: cat.val()
});
}
function showAppsList(cat) {
return appslistXHR('GET', {
'category': cat.val()
});
}
function updateAppsList(cat, newItem) {
return appslistXHR('POST', {
category: cat.val(),
add: newItem
});
}
function updateAppsList(cat, newItem) {
return appslistXHR('POST', {
'category': cat.val(),
'add': newItem
});
}
function deleteFromAppsList(cat, oldItem) {
return appslistXHR('POST', {
category: cat.val(),
delete: oldItem
});
}
function deleteFromAppsList(cat, oldItem) {
return appslistXHR('POST', {
'category': cat.val(),
'delete': oldItem
});
}
function appslistXHR(verb, data) {
var appslist = $("#featured-webapps");
var q = $.ajax({type: verb, url: appslist.data("src"), data: data});
q.then(function (data) {
appslist.html(data);
});
return q;
}
var region_carrier_update = _pd(
function (e) {
function appslistXHR(verb, data) {
var appslist = $featured;
var q = $.ajax({'type': verb, 'url': appslist.data('src'), 'data': data});
q.then(function(data) {
appslist.html(data);
});
return q;
}
var region_carrier_update = _pd(function(e) {
var $choices = $(e.target);
var $tabl = $choices.closest('table');
var $appParent = $choices.closest('ul');
function carrierName(v) {
var x = v.split(".");
if (x[0] == "carrier") {
var x = v.split('.');
if (x[0] == 'carrier') {
return x[1];
} else {
return null;
}
};
var regions = $choices.children('option')
.filter(function(i, opt) {return opt.selected && !carrierName(opt.value);})
.map(function(i, sopt) {return sopt.value;});
var carriers = $choices.children('option')
.map(function(i, opt) {
if (opt.selected) {
return carrierName(opt.value);
};
});
}
var regions = $choices.children('option').filter(function(i, opt) {
return opt.selected && !carrierName(opt.value);
}).map(function(i, sopt) {return sopt.value;});
var carriers = $choices.children('option').map(function(i, opt) {
if (opt.selected) {
return carrierName(opt.value);
}
});
$.ajax({
type: 'POST',
url: $tabl.data('url'),
data: {
'region': $.makeArray(regions),
'carrier': $.makeArray(carriers),
'app': $tabl.data('app-id')
}
});
'type': 'POST',
'url': $appParent.data('url'),
'data': {
'region': $.makeArray(regions),
'carrier': $.makeArray(carriers),
'app': $appParent.data('app-id')
}
});
});
$(document).ready(function(){
$("#featured-webapps").delegate(
'.remove',
'click',
_pd(function() {
deleteFromAppsList($("#categories"), $(this).data("id"));
})
);
$('#featured-webapps').delegate(
'select.localepicker',
'change',
region_carrier_update);
$('#featured-webapps').delegate(
'select.carrierpicker',
'change',
region_carrier_update);
var categories = $("#categories");
var p = $.ajax({type: 'GET',
url: categories.data("src")});
$featured.delegate('.remove', 'click', _pd(function() {
deleteFromAppsList($('#categories'), $(this).data('id'));
})).delegate('select.localepicker', 'change', region_carrier_update)
.delegate('select.carrierpicker', 'change', region_carrier_update);
var categories = $('#categories');
var p = $.ajax({'type': 'GET', 'url': categories.data('src')});
p.then(function(data) {
categories.html(data);
showAppsList(categories).then(
function () {
registerDatepickers();
});
showAppsList(categories).then(function() {
registerDatepickers();
});
});
categories.change(function (e) {
showAppsList(categories).then(
function () {
registerDatepickers();
});
categories.change(function(e) {
showAppsList(categories).then(function() {
registerDatepickers();
});
});
$('#featured-add').click(_pd(function() { newAddonSlot(); }));
});
$('#featured-add').click(_pd(function() {newAddonSlot();}));
})();

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

@ -1,61 +1,64 @@
{% block content %}
{% for row, selected_regions, excluded_regions, selected_carriers in apps_regions_carriers -%}
<tr>
<td>
<table class="featured-app" data-app-id="{{ row.pk }}" data-url="{{ url('zadmin.set_attrs_ajax') }}">
<tr>
<td><img src="{{ row.app.icon_url }}"></td>
<td>{{ row.app.name }}</td>
<td>{% for dt in row.app.device_types %}
{{ dt.name }}{% if not loop.last %}, {% endif%}
{% endfor %}</td>
</tr>
<tr>
<td>{% if row.app.promo %}
<a href="{{ row.app.get_dev_url() }}">Manage featured graphics</a>
{% else %}
<a href="{{ row.app.get_dev_url() }}">No featured graphics</a>
{% endif %}
</td>
<td>{% if row.is_sponsor %}Sponsored{% else %}Not sponsored{% endif %}</td>
<td>
<select class="localepicker" multiple>
{% for row, selected_regions, excluded_regions, selected_carriers in apps_regions_carriers -%}
<div class="app-container c">
<ul class="featured-app" data-app-id="{{ row.pk }}"
data-url="{{ url('zadmin.set_attrs_ajax') }}">
<li class="app-intro">
<img src="{{ row.app.icon_url }}" class="logo">
<h2>{{ row.app.name }}</h2>
<div class="dashboard">
<a href="{{ row.app.get_dev_url() }}">
<img alt="{{ _('Manage featured graphics') }}"
title="{{ _('Manage featured graphics') }}"
src="{{ MEDIA_URL }}img/mkt/icons/settings.png">
</a>
{% if not row.app.promo %}
<em class="icon warning"
title="{{ _('No featured graphics found.') }}"></em>
{% endif %}
{% if row.is_sponsor %}
<em class="icon sponsored" title="{{ _('Sponsored') }}"></em>
{% endif %}
</div>
</li>
<li class="dates">
<label>
{{ _('Start date') }}
<input type="date" class="date-range-start"
value="{{ row.start_date }}">
</label>
<label>
{{ _('End date') }}
<input type="date" class="date-range-end" value="{{ row.end_date }}">
</label>
</li>
</ul>
<a class="remove" data-id="{{ row.app.id }}">&times;</a>
<div class="side">
<ul class="devicelist">
{%- for dt in row.app.device_types -%}
<li>{{ dt.name }}</li>
{%- endfor -%}
</ul>
<p>
<label for="localepicker">{{ _('Locale') }}</label>
<select class="localepicker" multiple id="localepicker">
{%- for locName, loc in regions -%}
<option value="{{ loc.id }}"
{%- if loc.id in selected_regions %} selected{%- endif -%}
{%- if loc.id in excluded_regions %} disabled{%- endif -%}
>{{ loc.name }}</option>
{{- " selected" if loc.id in selected_regions -}}
{{- " disabled" if loc.id in excluded_regions -}}>
{{ loc.name }}
</option>
{%- endfor -%}
{%- for carrier in carriers -%}
<option value="carrier.{{ carrier }}"
{%- if carrier in selected_carriers %} selected{%- endif -%}
>{{ carrier }}</option>
{{- " selected" if carrier in selected_carriers -}}>
{{ carrier }}
</option>
{%- endfor -%}
</select>
</td>
</tr>
<tr>
<td>
{{ _('Start date') }}
</td>
<td>
<input type="date" class="date-range-start" value="{{ row.start_date }}">
<div class="start-date-picker"></div>
</td>
</tr>
<tr>
<td>
{{ _('End date') }}
</td>
<td>
<input type="date" class="date-range-end" value="{{ row.end_date }}">
<div class="end-date-picker"></div>
</td>
</tr>
</table>
</td>
<td><input type="hidden"><a class="remove" data-id="{{ row.app.id }}">×</a></td>
</tr>
{% endfor %}
</p>
</div>
</div>
{% endfor %}
{% endblock %}

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

@ -20,7 +20,7 @@
</script>
{% endblock %}
{% set title = 'Feature Manager' %}
{% set title = _('Feature Manager') %}
{% block title %}{{ mkt_page_title(title) }}{% endblock %}
{% block content %}
@ -28,28 +28,21 @@
<form method="post">
{{ csrf() }}
<h3>Featured Apps</h3>
Section: <select id="categories"
data-src="{{ url('zadmin.featured_categories_ajax') }}"
></select>
<table>
<thead>
<th>App</th>
<th>Delete</th>
</thead>
<tbody id="featured-webapps"
data-src="{{ url('zadmin.featured_apps_ajax') }}">
</tbody>
<tfoot class="hidden">
<tr><td>
<div class="current-webapp js-hidden" style="display: block;"></div>
<input placeholder="{{ _('Enter the name of the webapp to include') }}"
class="placeholder addon-ac large"
data-src="{{ url('search.apps_ajax') }}">
<input type="hidden"><a class="remove">×</a>
</td></tr>
</tfoot>
</table>
<p><a href="#" id="featured-add">Add an app</a></p>
<h3>{{ _('Featured Apps') }}</h3>
{{ _('Section') }}:
<select id="categories"
data-src="{{ url('zadmin.featured_categories_ajax') }}">
</select>
<div id="featured-webapps" data-src="{{ url('zadmin.featured_apps_ajax') }}">
</div>
<div class="hidden">
<div class="current-webapp js-hidden"></div>
<input placeholder="{{ _('Enter the name of the webapp to include') }}"
class="placeholder addon-ac large"
data-src="{{ url('search.apps_ajax') }}">
<a class="remove">×</a>
</div>
<p><a href="#" id="featured-add">{{ _('Add an app') }}</a></p>
</form>
{% endblock %}