Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prettify the FileUploadWidget #280

Merged
merged 9 commits into from
Jun 2, 2016
11 changes: 11 additions & 0 deletions deform/static/css/form.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,14 @@ form .required:after {
form .deform-readonly-text {
font-style: italic;
}

/* styles for file_upload.js, file_upload.pt */
.btn-file {
background-color: #f2f2f2;
}
.btn-file:hover {
background-color: #ededed;
}
.upload-filename[readonly] {
background-color: #fdfdfd;
}
109 changes: 109 additions & 0 deletions deform/static/scripts/file_upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Nicer looking file inputs for bootstrap 3
* By Jeff Dairiki <dairiki@dairiki.org> based on ideas from
* http://www.abeautifulsite.net/blog/2013/08/whipping-file-inputs-into-shape-with-bootstrap-3/
*/
(function ($) {

var Upload = function (element, options) {
this.$element = $(element);
this.options = $.extend({}, Upload.DEFAULTS,
this.$element.data(),
options);

this.orig_style = this.$element.attr('style');
this.$input_group = $(this.options.template)
.replaceAll(this.$element)
.attr('style', this.orig_style)
.css({position: 'relative', overflow: 'hidden'});
this.$input_group.find(':text').before(this.$element);
this.$element
.on('change.deform.upload', $.proxy(this, 'update'))
.css(this.options.element_style);
this.update();
};

Upload.DEFAULTS = {
filename: null,
selectfile: 'Select file…',
changefile: 'Change file…',

template: '<div>'
+ '<div class="input-group">'
+ '<span class="input-group-btn">'
+ '<span class="btn btn-default btn-file"></span>'
+ '</span>'
+ '<input type="text" readonly=""'
+ ' class="form-control upload-filename"/>'
+ '</div>'
+ '</div>',

element_style: {
position: 'absolute',
/* Older FF (3.5) seems to put a margin on the bottom of
* the file input (the margin is proportional to
* font-size, so in this case it's significant.) Shift
* bottom a bit to allow for some slop.
*/
//bottom: '0',
bottom: '-40px',
right: '0',
minWidth: '100%',
minHeight: '100%',
fontSize: '999px',
textAlign: 'right',
filter: 'alpha(opacity=0)',
opacity: '0',
background: 'red',
cursor: 'inherit',
display: 'block'
}
};

Upload.prototype.update = function () {
var selected_filename = this.$element.val().replace(/.*[\\\/]/, ''),
options = this.options,
filename = selected_filename || options.filename;
this.$input_group.find(':text')
.val(filename);
this.$input_group.find('.btn-file')
.text(filename ? options.changefile : options.selectfile);
};

Upload.prototype.destroy = function () {
this.$element
.off('.deform.upload')
.attr('style', this.orig_style || null)
.replaceAll(this.$input_group)
.removeData('deform.upload');
};


////////////////////////////////////////////////////////////////
// plugin definition

var old = $.fn.upload;

$.fn.upload = function (option) {
return this.each(function () {
var $this = $(this),
data = $this.data('deform.upload');
if (!data) {
var options = typeof option == 'object' && option;
data = new Upload(this, options);
$this.data('deform.upload', data);
}
if (typeof option == 'string') {
data[option]();
}
});
};

$.fn.upload.Constructor = Upload;

$.fn.upload.noConflict = function () {
$.fn.upload = old;
return this;
};

})(window.jQuery);
38 changes: 16 additions & 22 deletions deform/templates/file_upload.pt
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
<div class="deform-file-upload"
tal:define="oid oid|field.oid;
css_class css_class|field.widget.css_class;
style style|field.widget.style">

<tal:block tal:define="oid oid|field.oid;
css_class css_class|field.widget.css_class;
style style|field.widget.style;">
${field.start_mapping()}

<div class="deform-replaces" tal:condition="cstruct.get('uid')">

<input type="hidden" name="uid" value="${cstruct['uid']}"
id="${oid}-uid"/>
<span tal:content="cstruct.get('filename')"
id="${oid}-filename"/>

</div>

<input type="file" name="upload"
tal:attributes="class css_class;
style style;"
id="${oid}"/>

<input type="file" name="upload" id="${oid}"
tal:attributes="style style;
accept accept|field.widget.accept;
data-filename cstruct.get('filename');"/>
<input tal:define="uid cstruct.get('uid')"
tal:condition="uid"
type="hidden" name="uid" value="${uid}"/>
${field.end_mapping()}

</div>
<script type="text/javascript">
deform.addCallback('${oid}', function (oid) {
$('#' + oid).upload();
});
</script>
</tal:block>
10 changes: 10 additions & 0 deletions deform/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -1613,9 +1613,14 @@ class FileUploadWidget(Widget):
The template name used to render the widget in read-only mode.
Default: ``readonly/file_upload``.

accept
The ``accept`` attribute of the input field (default ``None``).
"""
template = 'file_upload'
readonly_template = 'readonly/file_upload'
accept = None

requirements = (('fileupload', None),)

_pstruct_schema = SchemaNode(
Mapping(),
Expand Down Expand Up @@ -2045,6 +2050,11 @@ def __call__(self, requirements):
'css':'deform:static/select2/select2.css',
},
},
'fileupload': {
None: {
'js': 'deform:static/scripts/file_upload.js',
},
},
}

default_resource_registry = ResourceRegistry()