manager: revamp assets management page (#11491)
This commit is contained in:
parent
ee04f9f1e5
commit
be2a10e460
|
@ -188,52 +188,103 @@ p#redirection {
|
|||
float: right;
|
||||
}
|
||||
|
||||
div#assets-thumbs {
|
||||
width: 50%;
|
||||
float: left;
|
||||
#assets-browser {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
div#asset-show {
|
||||
width: 48%;
|
||||
float: right;
|
||||
padding-top: 1em;
|
||||
#assets-browser #assets-listing {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
div#assets-thumbs ul {
|
||||
-moz-column-width: 100px;
|
||||
list-style: none;
|
||||
#assets-browser #assets-listing table th,
|
||||
#assets-browser #assets-listing table td {
|
||||
text-align: left;
|
||||
padding-left: 1ex;
|
||||
}
|
||||
|
||||
div#assets-thumbs ul li {
|
||||
padding: 5px;
|
||||
#assets-browser #assets-listing table td.image {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div#assets-thumbs a {
|
||||
#assets-browser #assets-listing table td.actions {
|
||||
width: 3em;
|
||||
}
|
||||
|
||||
#assets-browser #assets-listing table td.actions a.delete {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
div#assets-thumbs a:hover {
|
||||
opacity: 1.0;
|
||||
#assets-browser #assets-listing table td.actions a.delete::before {
|
||||
text-align: center;
|
||||
font-family: FontAwesome;
|
||||
content: "\f057"; /* remove-sign */
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
div#assets-thumbs img {
|
||||
padding: 5px;
|
||||
border: 1px solid #aaa;
|
||||
#assets-browser tr::before {
|
||||
font-family: FontAwesome;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
display: table-cell;
|
||||
width: 2em;
|
||||
border: 1px solid #bcbcbc;
|
||||
content: "";
|
||||
}
|
||||
|
||||
div#asset-img {
|
||||
#assets-browser td img {
|
||||
max-width: 50px;
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
#assets-browser tr.asset-ext-html::before {
|
||||
content: "\f0f6"; /* -file-text-o */
|
||||
}
|
||||
|
||||
#assets-browser tr.asset-ext-png::before,
|
||||
#assets-browser tr.asset-ext-gif::before,
|
||||
#assets-browser tr.asset-ext-jpg::before,
|
||||
#assets-browser tr.asset-ext-jpeg::before {
|
||||
content: "\f1c5"; /* -file-image-o */
|
||||
}
|
||||
|
||||
#assets-browser tr.asset-ext-mp3::before,
|
||||
#assets-browser tr.asset-ext-ogg::before,
|
||||
#assets-browser tr.asset-ext-flac::before,
|
||||
#assets-browser tr.asset-ext-wav::before {
|
||||
content: "\f1c7"; /* -file-audio-o */
|
||||
}
|
||||
|
||||
#assets-browser tr.asset-ext-pdf::before {
|
||||
content: "\f1c1"; /* -file-pdf-o */
|
||||
}
|
||||
|
||||
div#asset-preview {
|
||||
width: 20%;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#asset-img img {
|
||||
max-width: 90%;
|
||||
padding: 5px;
|
||||
border: 1px solid #aaa;
|
||||
div#asset-preview:empty::before {
|
||||
font-family: FontAwesome;
|
||||
color: #ddd;
|
||||
font-size: 100px;
|
||||
content: "\f03e"; /* picture-o */
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div#asset-cmds {
|
||||
text-align: right;
|
||||
div#asset-preview img {
|
||||
padding: 5px;
|
||||
background: white;
|
||||
border: 1px solid #aaa;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ul.multisort {
|
||||
|
|
|
@ -198,22 +198,16 @@ $(function() {
|
|||
$(style).appendTo('head');
|
||||
$(this).addClass('untoggled');
|
||||
});
|
||||
$('#assets-thumbs a').on('click', function() {
|
||||
$('#asset-img').empty().append($('<img src="' + $(this).attr('href') + '"/>'));
|
||||
$('#asset-cmds').show();
|
||||
return false;
|
||||
});
|
||||
$('#asset-delete').on('click', function() {
|
||||
var img_src = $('#asset-img img').attr('src');
|
||||
var thumb_item = $('#assets-thumbs a[href="' + img_src + '"]').parent();
|
||||
var img_orig = $(thumb_item).data('orig');
|
||||
$(thumb_item).hide();
|
||||
$('#asset-img').empty();
|
||||
$('#asset-cmds').hide();
|
||||
$.ajax({
|
||||
url: $(this).data('asset-delete-url'),
|
||||
data: {'img_orig': img_orig}
|
||||
});
|
||||
$('#assets-browser table tr').on('hover mouseenter', function() {
|
||||
var $img = $(this).find('img');
|
||||
if ($img.data('href')) {
|
||||
$('#asset-preview').empty().append($('<img src="' + $img.data('href') + '"/>'));
|
||||
} else {
|
||||
$('#asset-preview').empty();
|
||||
}
|
||||
return true;
|
||||
}).on('mouseleave', function() {
|
||||
$('#asset-preview').empty();
|
||||
});
|
||||
$('.manager-add-new-cell a').on('click', function() {
|
||||
$(this).next().toggle();
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "combo/manager_base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Delete Asset' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% blocktrans %}Are you sure you want to delete this?{% endblocktrans %}
|
||||
<div class="buttons">
|
||||
<button class="delete-button">{% trans 'Delete' %}</button>
|
||||
<a class="cancel" href="{% url 'combo-manager-assets' %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
{% if not files %}
|
||||
{% if not object_list %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans %}
|
||||
This site doesn't have any asset yet. You can add some directly when editing
|
||||
|
@ -23,31 +23,57 @@
|
|||
{% else %}
|
||||
|
||||
<div id="assets-browser">
|
||||
<div id="assets-thumbs" class="navigation">
|
||||
<ul>
|
||||
{% for file in files %}
|
||||
<li data-orig="{{ file.orig }}">
|
||||
<a {% if file.is_image %}class="thumb"{% endif %} href="{{ file.src }}">
|
||||
{% if file.is_image %}
|
||||
<img src="{{ file.thumb }}" style="max-width: 75px;"/>
|
||||
{% else %}
|
||||
{{ file.thumb }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div id="assets-listing">
|
||||
<table class="main">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Filename" %}</th>
|
||||
<th>{% trans "Size" %}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in object_list %}
|
||||
<tr class="{{ asset.css_classes }}">
|
||||
<td><a href="{{ asset.src }}">{{ asset.filename }}</a></td>
|
||||
<td>{{ asset.size|filesizeformat }}</td>
|
||||
<td class="image">{% if asset.is_image %}<img data-href="{{ asset.src }}" src="{{ asset.thumb }}"/>{% endif %}</td>
|
||||
<td class="actions">
|
||||
<a href="{% url 'combo-manager-asset-delete' %}?img={{asset.filepath|iriencode}}"
|
||||
class="delete" rel="popup">{% trans 'Delete' %}</a>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="asset-preview"></div>
|
||||
</div>
|
||||
|
||||
<div id="asset-show">
|
||||
<div id="asset-img">
|
||||
</div>
|
||||
<div id="asset-cmds" style="display: none;">
|
||||
<button data-asset-delete-url="{% url 'combo-manager-asset-delete' %}"
|
||||
id="asset-delete">{% trans 'Delete' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
{% if is_paginated %}
|
||||
<p class="paginator">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page={{ page_obj.previous_page_number }}&q={{ query|iriencode }}"><<</a>
|
||||
{% else %}
|
||||
<span><<</span>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<span class="current">
|
||||
{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
|
||||
</span>
|
||||
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}&q={{ query|iriencode }}">>></a>
|
||||
{% else %}
|
||||
<span>>></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -381,40 +381,61 @@ def page_get_additional_label(request, page_pk, cell_reference):
|
|||
return response
|
||||
|
||||
|
||||
class Assets(TemplateView):
|
||||
template_name = 'combo/manager_assets.html'
|
||||
class Asset(object):
|
||||
def __init__(self, filepath):
|
||||
self.filepath = filepath
|
||||
self.filename = os.path.basename(filepath)
|
||||
self.src = ckeditor.utils.get_media_url(filepath)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(Assets, self).get_context_data(**kwargs)
|
||||
context['files'] = []
|
||||
for filename in ckeditor.views.get_image_files(self.request.user):
|
||||
src = ckeditor.utils.get_media_url(filename)
|
||||
if getattr(settings, 'CKEDITOR_IMAGE_BACKEND', None):
|
||||
thumb = ckeditor.utils.get_media_url(
|
||||
ckeditor.utils.get_thumb_filename(filename))
|
||||
else:
|
||||
thumb = src
|
||||
context['files'].append({
|
||||
'thumb': thumb,
|
||||
'src': src,
|
||||
'is_image': ckeditor.views.is_image(src),
|
||||
'orig': filename,
|
||||
})
|
||||
return context
|
||||
def css_classes(self):
|
||||
extension = os.path.splitext(self.filepath)[-1].strip('.')
|
||||
if extension:
|
||||
return 'asset-ext-%s' % extension
|
||||
return ''
|
||||
|
||||
def size(self):
|
||||
return os.stat(default_storage.path(self.filepath)).st_size
|
||||
|
||||
def thumb(self):
|
||||
if getattr(settings, 'CKEDITOR_IMAGE_BACKEND', None):
|
||||
thumb = ckeditor.utils.get_media_url(
|
||||
ckeditor.utils.get_thumb_filename(self.filepath))
|
||||
else:
|
||||
thumb = self.src
|
||||
return thumb
|
||||
|
||||
def is_image(self):
|
||||
return ckeditor.views.is_image(self.src)
|
||||
|
||||
|
||||
class Assets(ListView):
|
||||
template_name = 'combo/manager_assets.html'
|
||||
paginate_by = 10
|
||||
|
||||
def get_queryset(self):
|
||||
files = [Asset(x) for x in ckeditor.views.get_image_files(self.request.user)]
|
||||
files.sort(key=lambda x: getattr(x, 'filename'))
|
||||
return files
|
||||
|
||||
assets = Assets.as_view()
|
||||
|
||||
def asset_delete(request):
|
||||
img_orig = request.GET['img_orig']
|
||||
if '..' in img_orig:
|
||||
raise PermissionDenied() # better safe than sorry
|
||||
base_path = settings.CKEDITOR_UPLOAD_PATH
|
||||
if getattr(settings, 'CKEDITOR_RESTRICT_BY_USER', False):
|
||||
base_path = os.path.join(base_path, request.user.username)
|
||||
if not img_orig.startswith(base_path):
|
||||
raise PermissionDenied()
|
||||
default_storage.delete(img_orig)
|
||||
return HttpResponse(status=204)
|
||||
|
||||
class AssetDelete(TemplateView):
|
||||
template_name = 'combo/manager_asset_confirm_delete.html'
|
||||
|
||||
def post(self, request):
|
||||
img_orig = request.GET['img']
|
||||
if '..' in img_orig:
|
||||
raise PermissionDenied() # better safe than sorry
|
||||
base_path = settings.CKEDITOR_UPLOAD_PATH
|
||||
if getattr(settings, 'CKEDITOR_RESTRICT_BY_USER', False):
|
||||
base_path = os.path.join(base_path, request.user.username)
|
||||
if not img_orig.startswith(base_path):
|
||||
raise PermissionDenied()
|
||||
default_storage.delete(img_orig)
|
||||
return redirect(reverse('combo-manager-assets'))
|
||||
|
||||
asset_delete = AssetDelete.as_view()
|
||||
|
||||
|
||||
def menu_json(request):
|
||||
|
|
|
@ -580,10 +580,10 @@ def test_asset_management(app, admin_user):
|
|||
resp = app.get('/manage/assets/')
|
||||
assert 'have any asset yet.' not in resp.body
|
||||
|
||||
app.get('/manage/assets/delete?img_orig=%s' % filepath, status=204)
|
||||
assert not os.path.exists(default_storage.path(filepath))
|
||||
|
||||
app.get('/manage/assets/delete?img_orig=/foo.png', status=403)
|
||||
resp = resp.click('Delete')
|
||||
assert 'Are you sure you want to delete' in resp.body
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'have any asset yet.' in resp.body
|
||||
|
||||
def test_menu_json(app, admin_user):
|
||||
app.get('/manage/menu.json', status=302)
|
||||
|
|
Loading…
Reference in New Issue