245 lines
8.1 KiB
Python
245 lines
8.1 KiB
Python
import re
|
|
import uuid
|
|
|
|
from django.conf import settings
|
|
from django.forms import (
|
|
CheckboxSelectMultiple,
|
|
FileInput,
|
|
HiddenInput,
|
|
MultiWidget,
|
|
Select,
|
|
SelectMultiple,
|
|
Textarea,
|
|
)
|
|
from django.template.loader import render_to_string
|
|
from django.utils.safestring import mark_safe
|
|
|
|
from docbow_project.docbow import app_settings
|
|
|
|
from .upload_views import get_files_for_id
|
|
|
|
|
|
class TextInpuWithPredefinedValues(MultiWidget):
|
|
CLIENT_CODE = '''
|
|
<script type="text/javascript">
|
|
$(document).ready(function () {
|
|
$('#id_%(name)s_0').change(function () {
|
|
$('#id_%(name)s_1').val($(this).val());
|
|
});
|
|
$('#id_%(name)s_1').keypress(function () {
|
|
$('#id_%(name)s_0').val('---');
|
|
});
|
|
});
|
|
</script>'''
|
|
|
|
def __init__(self, attrs=None, choices=[]):
|
|
widget_list = (Select(attrs=attrs, choices=choices), Textarea(attrs=attrs))
|
|
super().__init__(widget_list, attrs)
|
|
|
|
def decompress(self, value):
|
|
return ['---', value]
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
select, text_input = super().value_from_datadict(data, files, name)
|
|
if text_input or select == '---':
|
|
return text_input
|
|
else:
|
|
return select
|
|
|
|
def render(self, name, value, attrs=None, renderer=None):
|
|
output = super().render(name, value, attrs)
|
|
return output + mark_safe(self.CLIENT_CODE % {'name': name})
|
|
|
|
|
|
class MultiFileInput(FileInput):
|
|
"""
|
|
FileInput field supporting the multiple attribute
|
|
"""
|
|
|
|
def __init__(self, attrs=None):
|
|
super().__init__(attrs)
|
|
self.attrs['multiple'] = 'true'
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
if name in files:
|
|
return files.getlist(name)
|
|
else:
|
|
return []
|
|
|
|
|
|
class JqueryFileUploadFileInput(MultiFileInput):
|
|
template_name = 'docbow/upload-multiwidget.html'
|
|
|
|
class Media:
|
|
js = (
|
|
'jquery-ui/js/jquery-ui-1.8.4.min.js',
|
|
'jquery-plugin/js/jquery.tmpl.min-beta1.js',
|
|
'jquery-plugin/js/jquery.iframe-transport.js',
|
|
'jquery-plugin/js/jquery.fileupload.js',
|
|
'jquery-plugin/js/jquery.fileupload-ui.js',
|
|
)
|
|
css = {
|
|
'all': (
|
|
'jquery-ui/css/jquery-ui-1.8.4.css',
|
|
'jquery-plugin/css/jquery.fileupload-ui.css',
|
|
)
|
|
}
|
|
|
|
def __init__(self, extensions=[], attached_file_kind=None, *args, **kwargs):
|
|
self.extensions = extensions
|
|
self.attached_file_kind = attached_file_kind
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def _get_context(self, name):
|
|
return {
|
|
'open_tv': '{{',
|
|
'close_tv': '}}',
|
|
'upload_url': self.url,
|
|
'max_file_size': app_settings.MAX_FILE_SIZE,
|
|
'extensions': self.extensions,
|
|
'attached_file_kind': self.attached_file_kind,
|
|
'files': self.files,
|
|
'name': name,
|
|
'STATIC_URL': settings.STATIC_URL,
|
|
}
|
|
|
|
def get_context(self, name, value, attrs):
|
|
context = super().get_context(name, value, attrs)
|
|
context['widget'].update(self._get_context(name))
|
|
return context
|
|
|
|
def render(self, name, value, attrs=None):
|
|
# Dead code in django 1.11
|
|
output = render_to_string('docbow/upload.html', self._get_context(name))
|
|
return mark_safe(output)
|
|
|
|
|
|
class JqueryFileUploadInput(MultiWidget):
|
|
needs_multipart_form = True
|
|
CLIENT_CODE = '''
|
|
<script type="text/javascript">
|
|
</script>'''
|
|
upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
|
|
upload_id = None
|
|
template_name = 'docbow/multiwidget.html'
|
|
|
|
def __init__(
|
|
self, attrs=None, choices=[], max_filename_length=None, extensions=[], attached_file_kind=None
|
|
):
|
|
self.extensions = extensions
|
|
self.max_filename_length = max_filename_length
|
|
self.attached_file_kind = attached_file_kind
|
|
widget_list = (
|
|
HiddenInput(attrs=attrs),
|
|
JqueryFileUploadFileInput(
|
|
attrs=attrs, extensions=extensions, attached_file_kind=attached_file_kind
|
|
),
|
|
)
|
|
super().__init__(widget_list, attrs)
|
|
|
|
def decompress(self, value):
|
|
# map python value to widget contents
|
|
if self.upload_id:
|
|
pass
|
|
elif isinstance(value, (list, tuple)) and value and value[0] is not None:
|
|
self.upload_id = str(value[0])
|
|
else:
|
|
self.upload_id = str(uuid.uuid4())
|
|
return [self.upload_id, None]
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
"""
|
|
If some file was submitted, that's the value,
|
|
If a regular hidden_id is present, use it to find uploaded files,
|
|
otherwise return an empty list
|
|
"""
|
|
upload_id, file_input = super().value_from_datadict(data, files, name)
|
|
if file_input:
|
|
pass
|
|
elif JqueryFileUploadInput.upload_id_re.match(upload_id):
|
|
file_input = list(get_files_for_id(upload_id))
|
|
else:
|
|
file_input = []
|
|
return [upload_id, file_input]
|
|
|
|
def render(self, name, value, attrs=None, renderer=None):
|
|
self.decompress(value)
|
|
url = '/upload/%s/' % self.upload_id
|
|
if self.attached_file_kind and self.attached_file_kind.id:
|
|
url += '%s/' % self.attached_file_kind.id
|
|
if self.attached_file_kind.cardinality:
|
|
url += '?cardinality=%s' % self.attached_file_kind.cardinality
|
|
if self.max_filename_length:
|
|
url += '&' if '?' in url else '?'
|
|
url += 'max_filename_length=%d' % self.max_filename_length
|
|
self.widgets[1].url = url
|
|
self.widgets[1].files = '/upload/%s/' % get_files_for_id(self.upload_id)
|
|
output = super().render(name, value, attrs)
|
|
fileinput_id = '%s_%s' % (attrs['id'], '1')
|
|
return output + mark_safe(
|
|
self.CLIENT_CODE % {'upload_id': self.upload_id, 'fileinput_id': fileinput_id}
|
|
)
|
|
|
|
|
|
class ForcedValueWidget(SelectMultiple):
|
|
def __init__(self, attrs=None, format=None, value=None, display_value=''):
|
|
super().__init__(attrs)
|
|
self.display_value = display_value
|
|
self.value = value
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
return self.value
|
|
|
|
def render(self, name, value, attrs=None, renderer=None):
|
|
return mark_safe(
|
|
'<div class="selector"><span class="display-value">%s</span></div>' % self.display_value
|
|
)
|
|
|
|
|
|
class FilteredSelectMultiple(SelectMultiple):
|
|
"""
|
|
Imported from django.contrib.admin.widget, to improve on javascript files.
|
|
A SelectMultiple with a JavaScript filter interface.
|
|
|
|
Note that the resulting JavaScript assumes that the jsi18n
|
|
catalog has been loaded in the page
|
|
"""
|
|
|
|
class Media:
|
|
js = (
|
|
'docbow/filter-widget/js/core.js',
|
|
'docbow/filter-widget/js/SelectBox.js',
|
|
'docbow/filter-widget/js/SelectFilter2.js',
|
|
'js/i18n.js',
|
|
)
|
|
css = {'all': ('docbow/filter-widget/css/filter-widget.css',)}
|
|
|
|
def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
|
|
self.verbose_name = verbose_name
|
|
self.is_stacked = is_stacked
|
|
super().__init__(attrs, choices)
|
|
|
|
def render(self, name, value, attrs=None, *args, **kwargs):
|
|
if attrs is None:
|
|
attrs = {}
|
|
attrs['class'] = 'selectfilter'
|
|
if self.is_stacked:
|
|
attrs['class'] += 'stacked'
|
|
|
|
# disable html5 validation
|
|
if 'required' in attrs:
|
|
del attrs['required']
|
|
|
|
output = [super().render(name, value, attrs, *args, **kwargs)]
|
|
output.append('<script type="text/javascript">addEvent(window, "load", function(e) {')
|
|
# TODO: "id_" is hard-coded here. This should instead use the correct
|
|
# API to determine the ID dynamically.
|
|
output.append(
|
|
'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n'
|
|
% (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.STATIC_URL)
|
|
)
|
|
return mark_safe(''.join(output))
|
|
|
|
|
|
CheckboxMultipleSelect = CheckboxSelectMultiple
|