[zeam.form.silva][Sylvain Viollon] Beta new upload widget.
[email protected] Thu, 25 Jul 2013 15:23:57 +0200
Newsgroups
gmane.comp.web.zope.silva.cvs
Message-ID
<[email protected] >
author: Sylvain Viollon
date: Thu Jul 25 15:23:54 2013 +0200
revision: 408:404f9e87e1ff in zeam.form.silva
branch: 2.4
details: https://hg.infrae.com/zeam.form.silva?cmd=changeset;node=404f9e87e1ff
modified: src/zeam/form/silva/form/static/public.min.css src/zeam/form/silva/widgets/file.py src/zeam/form/silva/widgets/file_templates/filewidgetinput.cpt src/zeam/form/silva/widgets/static/upload.js src/zeam/form/silva/widgets/static/upload.min.js
added:
removed:
log: Beta new upload widget.
diffstat:
src/zeam/form/silva/form/static/public.min.css | 2 +-
src/zeam/form/silva/widgets/file.py | 88 +-
src/zeam/form/silva/widgets/file_templates/filewidgetinput.cpt | 45 +-
src/zeam/form/silva/widgets/static/upload.js | 451 +++++----
src/zeam/form/silva/widgets/static/upload.min.js | 2 +-
5 files changed, 324 insertions(+), 264 deletions(-)
diffs (735 lines):
diff -r c495987a48d9 -r 404f9e87e1ff src/zeam/form/silva/form/static/public.min.css
--- a/src/zeam/form/silva/form/static/public.min.css Mon Jul 15 15:56:35 2013 +0200
+++ b/src/zeam/form/silva/form/static/public.min.css Thu Jul 25 15:23:54 2013 +0200
@@ -1,1 +1,1 @@
-.public-form,.login-form{width:35em}.form{margin:1em 0;padding:.2em .5em .3em;border:1px solid #808080}.form-title{height:1.6em;font-size:15px;font-weight:700}.form-label{float:left;width:7em;height:2em}.form-label label{display:block;margin:.2em 0 0;font-weight:400}.form-field{height:2.2em}.form-field input[type="text"],.form-field input[type="password"],.form-field input[type="email"]{float:right;width:22em}.form-actions .submit{float:right;padding:.1em 1.5em;font-weight:700;margin-left:.4em}.form-actions .cancel{padding:.1em 1.5em}.form-error,.field-error{color:red;font-weight:700}.field-captcha-wrapper{width:22em;float:right}
\ No newline at end of file
+.public-form,.login-form{width:35em}.form{margin:1em 0;padding:.5em .5em 0;border:1px solid #808080}.form-element{clear:both}.form-title{height:1.6em;font-size:15px;font-weight:700}.form-label{float:left;width:7em;height:2em}.form-label label{display:block;margin:.2em 0 0;font-weight:400}.form-field{height:2.2em}.form-field input[type="text"],.form-field input[type="password"],.form-field input[type="email"],.form-field textarea{float:right;width:22em;padding:2px}.form-field textarea{height:3.5em}.form-actions .submit{float:right;padding:.1em 1.5em;font-weight:700;margin-left:.4em}.form-actions .cancel{padding:.1em 1.5em}.form-error,.field-error{color:red;font-weight:700}.field-captcha-wrapper{width:22em;float:right}
\ No newline at end of file
diff -r c495987a48d9 -r 404f9e87e1ff src/zeam/form/silva/widgets/file.py
--- a/src/zeam/form/silva/widgets/file.py Mon Jul 15 15:56:35 2013 +0200
+++ b/src/zeam/form/silva/widgets/file.py Thu Jul 25 15:23:54 2013 +0200
@@ -5,18 +5,18 @@
import os.path
import logging
import json
+import uuid
from five import grok
from zope.interface import Interface
from zope.traversing.browser import absoluteURL
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-from App.config import getConfiguration
-
from js.jqueryui import jqueryui
from infrae import rest
from silva.core import conf as silvaconf
+from silva.core import interfaces
from silva.core.conf import schema as silvaschema
from silva.core.interfaces.adapters import IIconResolver
from silva.fanstatic import need
@@ -25,6 +25,7 @@
from zeam.form.base.errors import Error
from zeam.form.base.markers import NO_VALUE, NO_CHANGE
from zeam.form.base.widgets import WidgetExtractor
+from zeam.form.composed.interfaces import ISubForm
from zeam.form.ztk.fields import SchemaField, SchemaFieldWidget
from zeam.form.ztk.fields import registerSchemaField
from zeam.form.silva.interfaces import ISMIForm
@@ -105,9 +106,16 @@
need(IUploadResources)
super(FileWidgetInput, self).update()
+ def uploadIdentifier(self):
+ return str(uuid.uuid1())
+
def uploadURL(self):
- return absoluteURL(self.form.context, self.request) + \
- '/++rest++zeam.form.silva.upload'
+ if ISubForm.providedBy(self.form):
+ form = self.form.getComposedForm()
+ else:
+ form = self.form
+ return absoluteURL(form, self.request) + \
+ '/upload'
def prepareContentValue(self, value):
formatted_value = u''
@@ -117,17 +125,25 @@
def displayValue(self):
value = self.inputValue()
+ status = None
label = None
+ icon = IIconResolver(self.request).get_tag(None)
if value:
label = self.component.fileSetLabel
if value != u'__NO_CHANGE__':
- return {'icon': None,
- 'message': None,
- 'filename': unicode(os.path.basename(value))}
+ manager = self.request.environ.get('infrae.fileupload.manager')
+ if manager is None:
+ raise interfaces.Error(
+ 'The upload component is not available.')
+ bucket = manager.access_upload_bucket(value)
+ if bucket is not None:
+ status = json.dumps(bucket.get_status())
else:
label = self.component.fileNotSetLabel
- icon = IIconResolver(self.request).get_tag(None)
- return {'icon': icon, 'message': label, 'filename': None}
+ return {'icon': icon,
+ 'message': label,
+ 'status': status,
+ 'empty': status is None}
def valueToUnicode(self, value):
if value is NO_CHANGE:
@@ -135,52 +151,58 @@
return unicode(value)
+class UploadedFile(object):
+
+ def __init__(self, bucket):
+ metadata = bucket.get_status()
+ self.name = metadata.get('filename') # Python filename
+ self.filename = metadata.get('filename') # Zope filename
+ self.__descriptor = open(bucket.get_filename(), 'r')
+
+ def __getattr__(self, name):
+ return getattr(self.__descriptor, name)
+
+
class FileWidgetExtractor(WidgetExtractor):
grok.adapts(FileSchemaField, ISMIForm, Interface)
- @classmethod
- def upload_dir(cls):
- if hasattr(cls, '_upload_dir_cache'):
- return cls._upload_dir_cache
- zconf = getattr(getConfiguration(), 'product_config', {})
- config = zconf.get('zeam.form.silva', {})
- upload_dir = config.get('upload-directory', None)
- if upload_dir is None:
- raise RuntimeError(
- '(zeam.form.silva) upload directory no configured')
- cls._upload_dir_cache = upload_dir
- return upload_dir
-
def extract(self):
value = self.request.form.get(self.identifier, u'')
if value == "__NO_CHANGE__":
return NO_CHANGE, None
- if value:
- return open(os.path.join(self.upload_dir(), value), 'r'), None
- return NO_VALUE, None
+ if not value:
+ return NO_VALUE, None
+ manager = self.request.environ.get('infrae.fileupload.manager')
+ if manager is None:
+ raise interfaces.Error('The upload component is not available')
+ bucket = manager.access_upload_bucket(value)
+ if bucket is not None:
+ if not bucket.is_complete():
+ return NO_VALUE, _(u"Upload is incomplete.")
+ return UploadedFile(bucket), None
+ return NO_VALUE, _(u"Upload failed.")
class Upload(rest.REST):
""" Check security and return information about gp.fileupload upload
"""
- grok.context(Interface)
+ grok.adapts(ISMIForm, Interface)
grok.require('silva.ChangeSilvaContent')
- grok.name('zeam.form.silva.upload')
+ grok.name('upload')
def POST(self):
""" get information about file upload
"""
- upload_id = long(self.request.get('gp.fileupload.id'))
- paths = self.request.environ.get('HTTP_STORED_PATHS', '').split(':')
- path = paths[0]
- logger.info("upload paths: %r" % paths)
+ info = self.request.environ['infrae.fileupload.current'].get_status()
+ info['message'] = 'File uploaded'
return """
<html>
<body>
<script>
var $ = window.parent.jQuery;
- $(window.parent.document).trigger('done-%d-upload', %s);
+ $(window.parent.document).trigger(
+ 'done-%s-upload', %s);
</script>
</body>
</html>
- """ % (upload_id, json.dumps({'path': path, 'upload-id': upload_id}))
+ """ % (info['identifier'], json.dumps(info))
diff -r c495987a48d9 -r 404f9e87e1ff src/zeam/form/silva/widgets/file_templates/filewidgetinput.cpt
--- a/src/zeam/form/silva/widgets/file_templates/filewidgetinput.cpt Mon Jul 15 15:56:35 2013 +0200
+++ b/src/zeam/form/silva/widgets/file_templates/filewidgetinput.cpt Thu Jul 25 15:23:54 2013 +0200
@@ -1,39 +1,50 @@
-<div class="upload-file" i18n:domain="silva">
- <div class="upload-popup" style="width: 100px; height:10px;">
- <p></p>
- </div>
+<div class="upload-file"
+ data-upload-url="${widget.uploadURL()}"
+ data-upload-identifier="${widget.uploadIdentifier()}"
+ i18n:domain="silva">
<div class="upload-display"
- tal:define="display widget.displayValue()">
- <p tal:condition="display.message">
+ data-upload-status="${display.status}"
+ tal:define="display widget.displayValue()">
+ <p class="upload-display-empty">
<img tal:condition="display.icon"
tal:replace="structure display.icon" />
<i tal:content="display.message" />
</p>
- <span tal:content="display.filename"
- tal:condition="display.filename" />
+ <p class="upload-display-uploading"
+ style="display: none;">
+ <ins class="icon form_warning" />
+ <i i18n:translate="">Uploading {filename}...</i>
+ </p>
+ <p class="upload-display-complete"
+ style="display: none;">
+ <ins class="icon form_check" />
+ <i i18n:translate="">File {filename} uploaded.</i>
+ </p>
</div>
<div style="display:none"
class="upload-progress">
</div>
- <iframe width="0"
- height="0"
- style="display:none"
- src="about:blank"
- class="upload-iframe"
- name="${widget.htmlId()}-upload-iframe">
- </iframe>
- <a href="${widget.uploadURL()}" onclick="return false"
+ <a onclick="return false"
title="Upload a new file in Silva"
class="form-button upload-trigger ui-state-default"
i18n:attributes="title">
<ins class="ui-icon ui-icon-document"></ins>
<tal:msg i18n:translate="">Upload</tal:msg>
</a>
- <a tal:condition="not widget.required" href="#" onclick="return false"
+ <a tal:condition="not widget.required"
+ onclick="return false"
class="upload-clear form-button ui-state-default">
<ins class="ui-icon ui-icon-circle-close"></ins>
<tal:msg i18n:translate="">Clear</tal:msg>
</a>
+ <a onclick="return false"
+ style="display: none;"
+ class="upload-cancel form-button ui-state-default">
+ <ins class="ui-icon ui-icon-circle-close"></ins>
+ <tal:msg i18n:translate="">Cancel</tal:msg>
+ </a>
+ <input type="file" name="${widget.htmlId()}.upload"
+ class="upload-file-input" />
<input type="hidden"
id="${widget.htmlId()}"
name="${widget.identifier}"
diff -r c495987a48d9 -r 404f9e87e1ff src/zeam/form/silva/widgets/static/upload.js
--- a/src/zeam/form/silva/widgets/static/upload.js Mon Jul 15 15:56:35 2013 +0200
+++ b/src/zeam/form/silva/widgets/static/upload.js Thu Jul 25 15:23:54 2013 +0200
@@ -1,240 +1,267 @@
+(function($, jsontemplate) {
+ var POLL_RETRIES = 5,
+ POLL_DELAY = 500,
+ NEED_POPUP = (function () {
+ // Test if we need a Javascript POPUP to display the file input or not.
+ var $test = $('<div style="display:none;"><form id="testform1">' +
+ '<input type="file" form="testform2" /></form><form id="testform2">' +
+ '</form></div>'),
+ supported = false;
+ $('body').append($test);
+ supported = ($test.find('#testform1')[0].length === 0 &&
+ $test.find('#testform2')[0].length === 1);
+ $test.remove();
+ return supported;
+ })();
-(function($) {
+ var UploadForm = function($field, identifier, url) {
+ // Upload a file input using the given identifier at the given URL.
+ // It will trigger callbacks uring various steps of the progress.
+ var $upload = $('<div style="display:none">' +
+ '<iframe width="0" height="0" style="display:none"' +
+ 'src="about:blank" class="upload-iframe" name="upload-' +
+ identifier + '-iframe"></iframe>' +
+ '<form class="upload-form" enctype="multipart/form-data"' +
+ 'method="POST" action="' + url + '?identifier=' + identifier +
+ '" target="upload-' + identifier +
+ '-iframe" id="upload-' + identifier + '-form">' +
+ '<input type="reset" class="upload-reset" /></form></div>'),
+ poll_retries = POLL_RETRIES,
+ poll_timeout = null,
+ result = $.Deferred().fail(function() {
+ $upload.find('.upload-reset').click();
+ $upload.find('.upload-iframe').attr('src', 'javascript:false;');
+ }).always(function() {
+ if (poll_timeout !== null) {
+ clearTimeout(poll_timeout);
+ poll_timeout = null;
+ };
+ $upload.remove();
+ $field.removeAttr('form');
+ }),
+ start = $.Deferred().done(function() {
+ poll_timeout = setTimeout(poll, POLL_DELAY);
+ });
- function basename(path) {
- return path.replace(/^.*[\/\\](.*)/, '$1');
- };
-
- var default_options = {
- stat_url: '/gp.fileupload.stat/',
- stat_timeout: 5000,
- stat_delay: 500,
- max_retries: 3,
- errors: {
- too_many_retries: 'unknown error while uploading file.',
- file_too_big: 'upload failed file is too big.'
- }
- };
-
- var FileUploader = function($progress, options){
- var deferred = $.Deferred();
- var progress = 0;
- var retries = 0;
-
- var upload_id = Math.random() * 10000000000000000000;
- var timeout = null;
-
- var form = null;
-
- options = $.extend({}, default_options, options);
-
- var clear_status = function() {
- if (timeout !== null) {
- clearTimeout(timeout);
- timeout = null;
- };
- };
-
- var set_progress = function(value) {
- if (progress != value) {
- progress = value;
- $progress.progressbar('option', 'value', value);
- }
- };
-
- var abort_upload = function(message) {
- clear_status();
- deferred.reject({filename: null, message: message});
- };
-
- var poll_success = function(data) {
- switch (data.state) {
- case -1:
- abort_upload(options.errors.file_too_big);
- break;
- case 0:
- // not started
- retries += 1;
- if (retries > options.max_retries) {
- abort_upload(options.errors.too_many_retries);
- return;
- };
- $progress.show();
- poll_status();
- break;
- case 1:
- // dl in progress
- retries = 0;
- $progress.show();
- if (data.percent > 0) {
- set_progress(data.percent);
- };
- if (data.percent < 100) {
- poll_status();
- };
- break;
- case 2:
- // not using the progressbar
- $progress.hide();
- clear_status();
- break;
- };
- };
-
- var poll_error = function(jqXHR, textStatus, errorThrown) {
- retries += 1;
- if (retries > options.max_retries) {
- abort_upload(options.errors.too_many_retries);
- return;
- }
- poll_status();
- };
-
- var _poll_status = function() {
- var url = options.stat_url + upload_id;
+ var poll = function() {
+ // Poll status from the server.
$.ajax({
type: 'GET',
dataType: 'json',
- timeout: options.stat_timeout,
- url: url,
- success: poll_success,
- error: poll_error
+ url: url + '?status&identifier=' + identifier
+ }).then(function(info){
+ result.notify(info);
+ if (!info['upload-finished'] && result.state() == "pending") {
+ // Unless the file is completely uploaded or
+ // cancel request status again.
+ poll_retries = POLL_RETRIES;
+ poll_timeout = setTimeout(poll, POLL_DELAY);
+ };
+ }, function() {
+ if (result.state() == "pending") {
+ if (poll_retries) {
+ poll_retries -= 1;
+ poll_timeout = setTimeout(poll, POLL_DELAY);
+ } else {
+ result.reject({message: 'Status check failed: cannot upload file.'});
+ }
+ }
});
};
-
- var poll_status = function() {
- clear_status();
- timeout = setTimeout(_poll_status, options.stat_delay);
- };
-
return {
- get_form: function(target, action) {
- var sep = '?';
-
- form = $('<form class="upload-form"' +
- 'enctype="multipart/form-data"' +
- 'method="POST"' +
- 'action=""' +
- 'target="' + target + '">' +
- '<input type="file" name="file" />' +
- '</form>');
- if (action.match(/\?/))
- sep = "&";
- form.attr('action', action + sep + 'gp.fileupload.id=' + upload_id);
- return form;
+ start: function() {
+ $(document).one('done-' + identifier + '-upload', function(event, data) {
+ result.resolve(data);
+ });
+ $('body').append($upload);
+ $field.attr('form', 'upload-' + identifier + '-form');
+ $upload.find('form').submit();
+ start.resolve({
+ 'uploaded-length': 0, 'content-type': 'n/a', 'request-length': 0, 'filename': ''});
},
- send: function() {
- if (form === null) {
- return null;
+ cancel: function() {
+ result.reject({});
+ },
+ register: function(plugin) {
+ if (plugin.start !== undefined) {
+ start.done(plugin.start);
};
- // listen to event triggered by the iframe, that will
- // mark the end of a successful upload
- $(document).one('done-' + String(upload_id) + '-upload', function(event, data) {
- deferred.resolve({filename: data.path});
- });
- form.submit();
- poll_status();
- return deferred.promise();
+ for (var event in {progress: 1, done: 1, fail: 1, always: 1}) {
+ if (plugin[event] !== undefined) {
+ result[event](plugin[event]);
+ };
+ };
}
};
};
- var create_upload_field = function() {
- var $field = $(this);
+ var UploadStatusMessage = function($display) {
+ // Manage the status message of the upload widget.
+ var $empty = $display.children('.upload-display-empty'),
+ $uploading = $display.children('.upload-display-uploading'),
+ $done = $display.children('.upload-display-complete');
+ var empty = $empty.children('i').text(),
+ uploading = jsontemplate.Template($uploading.children('i').text(), {}),
+ done = jsontemplate.Template($done.children('i').text(), {}),
+ state = 'empty',
+ original = $display.data('upload-status');
- var $upload_button = $field.find('a.upload-trigger');
- var $clear_button = $field.find('a.upload-clear');
+ var api = {
+ start: function(data) {
+ if (state != 'starting') {
+ $uploading.children('i').text(uploading.expand(data));
+ $empty.hide();
+ $done.hide();
+ $uploading.show();
+ state = 'starting';
+ }
+ },
+ progress: function(data) {
+ if (state != 'uploading') {
+ // Refresh information on the first notification of progress.
+ $uploading.children('i').text(uploading.expand(data));
+ state = 'uploading';
+ };
+ },
+ done: function(data) {
+ if (state != 'done') {
+ $done.children('i').text(done.expand(data));
+ $empty.hide();
+ $uploading.hide();
+ $done.show();
+ state = 'done';
+ };
+ },
+ fail: function(data) {
+ if (state != 'empty' || data.message) {
+ $empty.children('i').text(data.message || empty);
+ if (state != 'empty') {
+ $uploading.hide();
+ $done.hide();
+ $empty.show();
+ state = 'empty';
+ };
+ };
+ }
+ };
+ if (original) {
+ api.done(original);
+ };
+ return api;
+ };
- var $progress = $field.find('.upload-progress');
- var $input = $field.find('.upload-input');
- var $status = $field.find('.upload-display');
+ var UploadProgress = function($progress) {
+ // Manage the progress bar of the upload widget.
+ var progress = 0;
- var previous_value = $input.val();
+ return {
+ start: function() {
+ $progress.progressbar({value: 0}).show();
+ },
+ progress: function(data) {
+ var updated = 0;
- var set_input_value = function(data) {
- if (data.filename) {
- $status.text(basename(data.filename));
- } else if (data.message) {
- $status.text(data.message);
- } else {
- $status.text('not set.');
+ if (!data['missing']) {
+ updated = data['uploaded-length'] * 100 / data['request-length'];
+ };
+ if (updated != progress) {
+ $progress.progressbar({value: updated});
+ progress = updated;
+ };
+ },
+ always: function(data) {
+ $progress.hide();
+ progress = 0;
+ }
+ };
+ };
+
+ var UploadField = function ($field, set_objection) {
+ var $input = $field.children('.upload-input'),
+ $trigger = $field.children('.upload-trigger'),
+ $cancel = $field.children('.upload-cancel'),
+ $clear = $field.children('.upload-clear'),
+ $file = $field.children('.upload-file-input');
+ var upload = null,
+ objection = null,
+ progress = UploadProgress($field.children('.upload-progress')),
+ status = UploadStatusMessage($field.children('.upload-display')),
+ ui = {
+ start: function() {
+ if (set_objection !== undefined) {
+ objection = $.Deferred();
+ set_objection(function () {
+ if (objection.state() == 'pending') {
+ var $dialog = $('<div title="Uploading file">Please wait until the upload is finished ...</div>');
+
+ $dialog.dialog({
+ modal: true,
+ closeOnEscape: false,
+ resizable: false,
+ draggable: false,
+ beforeClose: function() {
+ return false;
+ }});
+ return objection.always(function() {
+ $dialog.dialog('close').remove();
+ objection = null;
+ });
+ };
+ return null;
+ });
+ };
+ $file.hide();
+ $cancel.show();
+ },
+ done: function(data) {
+ $input.attr('value', $field.data('upload-identifier'));
+ },
+ always: function(data) {
+ if (objection !== null) {
+ objection.resolve();
+ };
+ $file.show();
+ $cancel.hide();
+ upload = null;
+ }
};
- $input.val(data.filename);
- $input.change();
+
+ var get_upload = function(create) {
+ if (upload == null && create) {
+ upload = UploadForm($file, $field.data('upload-identifier'), $field.data('upload-url'));
+ upload.register(status);
+ upload.register(progress);
+ upload.register(ui);
+ }
+ return upload;
};
- var disable_upload_button = function() {
- $progress.progressbar({value: 0});
- //$progress.show();
- $upload_button.button('disable');
- $upload_button.hide();
- };
-
- var enable_upload_button = function() {
- $progress.hide();
- $upload_button.button('enable');
- $upload_button.show();
- };
-
- // Support for clear button
- $clear_button.bind('click', function(){
- set_input_value('');
+ $trigger.remove();
+ $cancel.on('click', function() {
+ var upload = get_upload();
+ if (upload !== null) {
+ upload.cancel();
+ };
});
-
- // Support for upload button
- $upload_button.bind('click', function(){
- var $iframe = $field.find('iframe');
- var $popup = $field.find('.upload-popup').clone();
- var uploader = FileUploader($progress);
- var promise = null;
-
- $popup.dialog({
- title: $upload_button.text(),
- modal: true,
- create: function() {
- $popup.find('p').append(
- uploader.get_form(
- $iframe.attr('name'), $upload_button.attr('href')));
- },
- autoOpen: false,
- zIndex: 12500,
- buttons: {
- Send: function(event){
- disable_upload_button();
- promise = uploader.send().fail(
- function (data) {
- // failure
- $field.trigger(
- 'notify-feedback-smi',
- {message: data.message, category: 'error'});
- }).always(function (data) {
- // in any case
- set_input_value(data);
- enable_upload_button();
- $popup.remove();
- });
- $popup.dialog('close');
- }
- }
- });
- $popup.bind('dialogclose', function() {
- // the user click on close.
- if (promise === null) {
- $popup.remove();
- }
- });
- $popup.dialog('open');
+ $clear.on('click', function() {
+ var upload = get_upload(true);
+ upload.cancel();
+ $input.attr('value', '');
});
-
+ $file.on('change', function() {
+ upload = UploadForm($file, $field.data('upload-identifier'), $field.data('upload-url'));
+ upload.register(status);
+ upload.register(progress);
+ upload.register(ui);
+ upload.start();
+ });
};
- $(document).on('loadwidget-smiform', '.form-fields-container', function(event) {
- $(this).find('.upload-file').each(create_upload_field);
+ $(document).on('loadwidget-smiform', '.form-fields-container', function(event, data) {
+ $(this).find('.upload-file').each(function(){
+ UploadField($(this), data.set_objection);
+ });
event.stopPropagation();
});
- $(document).ready(function() {
- $('.upload-file').each(create_upload_field);
- });
-
-})(jQuery);
+})(jQuery, jsontemplate);
diff -r c495987a48d9 -r 404f9e87e1ff src/zeam/form/silva/widgets/static/upload.min.js
--- a/src/zeam/form/silva/widgets/static/upload.min.js Mon Jul 15 15:56:35 2013 +0200
+++ b/src/zeam/form/silva/widgets/static/upload.min.js Thu Jul 25 15:23:54 2013 +0200
@@ -1,1 +1,1 @@
-(function($){function basename(path){return path.replace(/^.*[\/\\](.*)/,"$1")}var default_options={stat_url:"/gp.fileupload.stat/",stat_timeout:5e3,stat_delay:500,max_retries:3,errors:{too_many_retries:"unknown error while uploading file.",file_too_big:"upload failed file is too big."}},FileUploader=function($progress,options){var deferred=$.Deferred(),progress=0,retries=0,upload_id=1e19*Math.random(),timeout=null,form=null;options=$.extend({},default_options,options);var clear_status=function(){null!==timeout&&(clearTimeout(timeout),timeout=null)},set_progress=function(value){progress!=value&&(progress=value,$progress.progressbar("option","value",value))},abort_upload=function(message){clear_status(),deferred.reject({filename:null,message:message})},poll_success=function(data){switch(da
ta.state){case-1:abort_upload(options.errors.file_too_big);break;case 0:if(retries+=1,retries>options.max_retries)return abort_upload(options.errors.too_many_retries),void 0;$progress.show()
,poll_status();break;case 1:retries=0,$progress.show(),data.percent>0&&set_progress(data.percent),100>data.percent&&poll_status();break;case 2:$progress.hide(),clear_status()}},poll_error=function(){return retries+=1,retries>options.max_retries?(abort_upload(options.errors.too_many_retries),void 0):(poll_status(),void 0)},_poll_status=function(){var url=options.stat_url+upload_id;$.ajax({type:"GET",dataType:"json",timeout:options.stat_timeout,url:url,success:poll_success,error:poll_error})},poll_status=function(){clear_status(),timeout=setTimeout(_poll_status,options.stat_delay)};return{get_form:function(target,action){var sep="?";return form=$('<form class="upload-form"enctype="multipart/form-data"method="POST"action=""target="'+target+'">'+'<input type="file" name="file" />'+"</form>"),
action.match(/\?/)&&(sep="&"),form.attr("action",action+sep+"gp.fileupload.id="+upload_id),form},send:function(){return null===form?null:($(document).one("done-"+(upload_id+"")+"-upload",fun
ction(event,data){deferred.resolve({filename:data.path})}),form.submit(),poll_status(),deferred.promise())}}},create_upload_field=function(){var $field=$(this),$upload_button=$field.find("a.upload-trigger"),$clear_button=$field.find("a.upload-clear"),$progress=$field.find(".upload-progress"),$input=$field.find(".upload-input"),$status=$field.find(".upload-display");$input.val();var set_input_value=function(data){data.filename?$status.text(basename(data.filename)):data.message?$status.text(data.message):$status.text("not set."),$input.val(data.filename),$input.change()},disable_upload_button=function(){$progress.progressbar({value:0}),$upload_button.button("disable"),$upload_button.hide()},enable_upload_button=function(){$progress.hide(),$upload_button.button("enable"),$upload_button.show(
)};$clear_button.bind("click",function(){set_input_value("")}),$upload_button.bind("click",function(){var $iframe=$field.find("iframe"),$popup=$field.find(".upload-popup").clone(),uploader=F
ileUploader($progress),promise=null;$popup.dialog({title:$upload_button.text(),modal:!0,create:function(){$popup.find("p").append(uploader.get_form($iframe.attr("name"),$upload_button.attr("href")))},autoOpen:!1,zIndex:12500,buttons:{Send:function(){disable_upload_button(),promise=uploader.send().fail(function(data){$field.trigger("notify-feedback-smi",{message:data.message,category:"error"})}).always(function(data){set_input_value(data),enable_upload_button(),$popup.remove()}),$popup.dialog("close")}}}),$popup.bind("dialogclose",function(){null===promise&&$popup.remove()}),$popup.dialog("open")})};$(document).on("loadwidget-smiform",".form-fields-container",function(event){$(this).find(".upload-file").each(create_upload_field),event.stopPropagation()}),$(document).ready(function(){$(".up
load-file").each(create_upload_field)})})(jQuery);
\ No newline at end of file
+(function($,jsontemplate){var POLL_RETRIES=5,POLL_DELAY=500;(function(){var $test=$('<div style="display:none;"><form id="testform1"><input type="file" form="testform2" /></form><form id="testform2"></form></div>'),supported=!1;return $("body").append($test),supported=0===$test.find("#testform1")[0].length&&1===$test.find("#testform2")[0].length,$test.remove(),supported})();var UploadForm=function($field,identifier,url){var $upload=$('<div style="display:none"><iframe width="0" height="0" style="display:none"src="about:blank" class="upload-iframe" name="upload-'+identifier+'-iframe"></iframe>'+'<form class="upload-form" enctype="multipart/form-data"'+'method="POST" action="'+url+"?identifier="+identifier+'" target="upload-'+identifier+'-iframe" id="upload-'+identifier+'-form">'+'<input ty
pe="reset" class="upload-reset" /></form></div>'),poll_retries=POLL_RETRIES,poll_timeout=null,result=$.Deferred().fail(function(){$upload.find(".upload-reset").click(),$upload.find(".upload-
iframe").attr("src","javascript:false;")}).always(function(){null!==poll_timeout&&(clearTimeout(poll_timeout),poll_timeout=null),$upload.remove(),$field.removeAttr("form")}),start=$.Deferred().done(function(){poll_timeout=setTimeout(poll,POLL_DELAY)}),poll=function(){$.ajax({type:"GET",dataType:"json",url:url+"?status&identifier="+identifier}).then(function(info){result.notify(info),info["upload-finished"]||"pending"!=result.state()||(poll_retries=POLL_RETRIES,poll_timeout=setTimeout(poll,POLL_DELAY))},function(){"pending"==result.state()&&(poll_retries?(poll_retries-=1,poll_timeout=setTimeout(poll,POLL_DELAY)):result.reject({message:"Status check failed: cannot upload file."}))})};return{start:function(){$(document).one("done-"+identifier+"-upload",function(event,data){result.resolve(dat
a)}),$("body").append($upload),$field.attr("form","upload-"+identifier+"-form"),$upload.find("form").submit(),start.resolve({"uploaded-length":0,"content-type":"n/a","request-length":0,filen
ame:""})},cancel:function(){result.reject({})},register:function(plugin){void 0!==plugin.start&&start.done(plugin.start);for(var event in{progress:1,done:1,fail:1,always:1})void 0!==plugin[event]&&result[event](plugin[event])}}},UploadStatusMessage=function($display){var $empty=$display.children(".upload-display-empty"),$uploading=$display.children(".upload-display-uploading"),$done=$display.children(".upload-display-complete"),empty=$empty.children("i").text(),uploading=jsontemplate.Template($uploading.children("i").text(),{}),done=jsontemplate.Template($done.children("i").text(),{}),state="empty",original=$display.data("upload-status"),api={start:function(data){"starting"!=state&&($uploading.children("i").text(uploading.expand(data)),$empty.hide(),$done.hide(),$uploading.show(),state="s
tarting")},progress:function(data){"uploading"!=state&&($uploading.children("i").text(uploading.expand(data)),state="uploading")},done:function(data){"done"!=state&&($done.children("i").text
(done.expand(data)),$empty.hide(),$uploading.hide(),$done.show(),state="done")},fail:function(data){("empty"!=state||data.message)&&($empty.children("i").text(data.message||empty),"empty"!=state&&($uploading.hide(),$done.hide(),$empty.show(),state="empty"))}};return original&&api.done(original),api},UploadProgress=function($progress){var progress=0;return{start:function(){$progress.progressbar({value:0}).show()},progress:function(data){var updated=0;data.missing||(updated=100*data["uploaded-length"]/data["request-length"]),updated!=progress&&($progress.progressbar({value:updated}),progress=updated)},always:function(){$progress.hide(),progress=0}}},UploadField=function($field,set_objection){var $input=$field.children(".upload-input"),$trigger=$field.children(".upload-trigger"),$cancel=$fie
ld.children(".upload-cancel"),$clear=$field.children(".upload-clear"),$file=$field.children(".upload-file-input"),upload=null,objection=null,progress=UploadProgress($field.children(".upload-
progress")),status=UploadStatusMessage($field.children(".upload-display")),ui={start:function(){void 0!==set_objection&&(objection=$.Deferred(),set_objection(function(){if("pending"==objection.state()){var $dialog=$('<div title="Uploading file">Please wait until the upload is finished ...</div>');return $dialog.dialog({modal:!0,closeOnEscape:!1,resizable:!1,draggable:!1,beforeClose:function(){return!1}}),objection.always(function(){$dialog.dialog("close").remove(),objection=null})}return null})),$file.hide(),$cancel.show()},done:function(){$input.attr("value",$field.data("upload-identifier"))},always:function(){null!==objection&&objection.resolve(),$file.show(),$cancel.hide(),upload=null}},get_upload=function(create){return null==upload&&create&&(upload=UploadForm($file,$field.data("uploa
d-identifier"),$field.data("upload-url")),upload.register(status),upload.register(progress),upload.register(ui)),upload};$trigger.remove(),$cancel.on("click",function(){var upload=get_upload
();null!==upload&&upload.cancel()}),$clear.on("click",function(){var upload=get_upload(!0);upload.cancel(),$input.attr("value","")}),$file.on("change",function(){upload=UploadForm($file,$field.data("upload-identifier"),$field.data("upload-url")),upload.register(status),upload.register(progress),upload.register(ui),upload.start()})};$(document).on("loadwidget-smiform",".form-fields-container",function(event,data){$(this).find(".upload-file").each(function(){UploadField($(this),data.set_objection)}),event.stopPropagation()})})(jQuery,jsontemplate);
\ No newline at end of file