From 7dbb0b4dede38d256153373042ccb42bb3399ac8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 6 Jul 2020 19:54:24 +0200 Subject: [PATCH] wiki: add document upload support --- panikdb/static/css/style.scss | 14 +++++++++- panikdb/static/js/combo.wiki.js | 46 ++++++++++++++++++++++++++++++--- panikdb/urls.py | 2 +- panikdb/wiki/views.py | 26 ++++++++++++------- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/panikdb/static/css/style.scss b/panikdb/static/css/style.scss index 5e8837d..5ade304 100644 --- a/panikdb/static/css/style.scss +++ b/panikdb/static/css/style.scss @@ -761,8 +761,8 @@ div.wiki-section { [contenteditable=true] div.figure { cursor: pointer; } + div.document, div.figure { - min-height: 50px; text-align: center; line-height: initial; img { @@ -770,6 +770,7 @@ div.wiki-section { max-height: 70vh; } span.empty::before { + min-height: 50px; margin: 0 auto; display: block; width: 90%; @@ -781,6 +782,16 @@ div.wiki-section { font-family: FontAwesome; } } + div.document a { + &::before { + content: "\f019"; + font-family: FontAwesome; + padding-right: 0.7em; + } + } + div.document span.empty::before { + content: "\f0f6"; // fa-file-text-o + } div[contenteditable] { a[href^="/wiki/"] { box-shadow: inset 0 -8px 0 0 rgba(34, 27, 242,0.1); @@ -828,6 +839,7 @@ div#content div.wiki-section h4.intertitle { top: 0px; } +#document-upload, #image-upload { visibility: hidden; } diff --git a/panikdb/static/js/combo.wiki.js b/panikdb/static/js/combo.wiki.js index a94d8cb..d1464e3 100644 --- a/panikdb/static/js/combo.wiki.js +++ b/panikdb/static/js/combo.wiki.js @@ -39,6 +39,7 @@ function auto_anchors() { {name: 'intertitre', tag: 'H4', klass: 'intertitle'}, {name: 'liste', special: 'list', tag: 'UL', klass: 'list'}, {name: 'illustration', special: 'img', tag: 'DIV', subtag: true, klass: 'figure'}, + {name: 'document', special: 'doc', tag: 'DIV', subtag: true, klass: 'document'}, {name: 'code', tag: 'PRE', klass: 'code'}, {name: 'note', tag: 'DIV', subtag: true, klass: 'note'}, ], @@ -133,20 +134,30 @@ function auto_anchors() { $(inline_style_toolbar).hide(); } }); - var $image_upload = $(''); + var $image_upload = $(''); $image_upload.on('change', upload_image); $image_upload.appendTo(document.body); + var $document_upload = $(''); + $document_upload.on('change', upload_document); + $document_upload.appendTo(document.body); + document.execCommand('defaultParagraphSeparator', false, 'p'); $(document).on('click', 'div.figure span.empty', function() { window.active_figure = this.parentNode; $('#image-upload').trigger('click'); return true; }); + $(document).on('click', 'div.document span.empty', function() { + window.active_document = this.parentNode; + $('#document-upload').trigger('click'); + return true; + }); }, off: function() { $('#image-upload').remove(); + $('#document-upload').remove(); if (block_style_toolbar) { block_style_toolbar.hide(); } if (inline_style_toolbar) { inline_style_toolbar.hide(); } $(document).off('selectionchange'); @@ -184,8 +195,8 @@ function auto_anchors() { if ($(this).prop('files').length > 0) { var file = $(this).prop('files')[0]; var params = new FormData(); - params.append('image', file); - $.post({url: '/wiki/ajax/image/', processData: false, data: params, contentType: false}).success(function(data) { + params.append('upload', file); + $.post({url: '/wiki/ajax/upload/', processData: false, data: params, contentType: false}).success(function(data) { var img = document.createElement('IMG'); img.src = data.url; if (data.orig_url) { @@ -196,6 +207,21 @@ function auto_anchors() { } } + function upload_document() { + if ($(this).prop('files').length > 0) { + var file = $(this).prop('files')[0]; + var params = new FormData(); + params.append('upload', file); + $.post({url: '/wiki/ajax/upload/', processData: false, data: params, contentType: false}).success(function(data) { + var doc_link = document.createElement('A'); + doc_link.className = 'button'; + doc_link.textContent = 'Télécharger ' + data.filename; + doc_link.href = data.url; + $(window.active_document).empty().append(doc_link); + }); + } + } + function get_contenteditable_subnode(node) { if (node === null) return null; if (node.contentEditable === 'true') return node; // but we shouldn't arrive at root @@ -232,7 +258,19 @@ function auto_anchors() { sel.removeAllRanges(); sel.addRange(range); update_block_style_toolbar(); - + return; + } + if (this.action_block.special == 'doc') { + action = 'insertHTML'; + param = '

'; + document.execCommand(action, false, param); + current_anchor = $('#new-p')[0]; + $(current_anchor).attr('id', null); + var range = document.createRange(); + range.setStart(current_anchor, 0); + sel.removeAllRanges(); + sel.addRange(range); + update_block_style_toolbar(); return; } if (this.action_block.special == 'list') { diff --git a/panikdb/urls.py b/panikdb/urls.py index eff62c0..6208ed3 100644 --- a/panikdb/urls.py +++ b/panikdb/urls.py @@ -85,7 +85,7 @@ urlpatterns = [ url(r'^wiki/newpage/$', wiki_views.new_page), url(r'^wiki/ajax/newpage/$', wiki_views.ajax_new_page), - url(r'^wiki/ajax/image/$', wiki_views.ajax_image), + url(r'^wiki/ajax/upload/$', wiki_views.ajax_upload), url(r'^wiki/', combo.public.views.page), url(r'^ajax/cell/(?P\d+)/(?P[\w_]+-\d+)/$', combo.public.views.ajax_page_cell, name='combo-public-ajax-page-cell'), diff --git a/panikdb/wiki/views.py b/panikdb/wiki/views.py index 9457d81..15df481 100644 --- a/panikdb/wiki/views.py +++ b/panikdb/wiki/views.py @@ -1,3 +1,5 @@ +import os + from django.contrib.auth.decorators import login_required from django.core.files.storage import default_storage from django.db.models import Q @@ -55,15 +57,19 @@ def ajax_new_page(request, *args, **kwargs): @csrf_exempt -def ajax_image(request, *args, **kwargs): - img = request.FILES['image'] - saved_path = default_storage.save('wiki/images/%s' % img.name, img) +def ajax_upload(request, *args, **kwargs): + upload = request.FILES['upload'] + upload_path = 'uploads' + if os.path.splitext(upload.name.lower())[-1] in ('.jpg', '.jpeg', '.png', '.gif', '.svg'): + upload_path = 'images' + saved_path = default_storage.save('wiki/%s/%s' % (upload_path, upload.name), upload) url = '/media/' + saved_path - response = {'url': url} - if default_storage.size(saved_path) > 500_000 and not img.name.endswith('.svg'): - response['orig_url'] = url - try: - response['url'] = get_thumbnail(saved_path, '1000', upscale=False).url - except OSError: - pass + response = {'url': url, 'filename': upload.name} + if upload_path == 'images': + if default_storage.size(saved_path) > 500_000 and not upload.name.endswith('.svg'): + response['orig_url'] = url + try: + response['url'] = get_thumbnail(saved_path, '1000', upscale=False).url + except OSError: + pass return JsonResponse(response) -- 2.39.2