--- a/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/create_content.html Sun Feb 10 23:04:28 2013 +0100
+++ b/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/create_content.html Tue Feb 12 17:30:41 2013 +0100
@@ -10,12 +10,12 @@
{{ block.super }}
<script type="text/javascript" src="{{ADMIN_MEDIA_PREFIX}}js/core.js" ></script>
<script type="text/javascript" src="{{ADMIN_MEDIA_PREFIX}}js/jquery.init.js"></script>
- <script type="text/javascript" src="{{ADMIN_MEDIA_PREFIX}}js/jquery.min.js"></script>
+ <script type="text/javascript" src='{% absstatic "ldt/js/jquery.min.js" %}'></script>
+ <script type="text/javascript" src="{% url ldt.jsi18n packages='ldt' %}" ></script>
<script type="text/javascript" src="{% absurl ldt.jsi18n packages='ldt' %}" ></script>
<script type="text/javascript" src='{% absstatic "ldt/js/projectscontents.js" %}'></script>
<script type="text/javascript" src='{% absstatic "ldt/js/jquery.textchange.min.js" %}'></script>
<script type="text/javascript" src='{% absstatic "ldt/js/jquery-ui.min.js" %}'></script>
- <script type="text/javascript" src='{% absstatic "ldt/js/swfupload/swfupload.js" %}'></script>
{{ content_form.media.js }}
{% endblock %}
@@ -29,26 +29,52 @@
post_added_params = {"csrfmiddlewaretoken" : "{{csrf_token}}",
"{{cookie_name}}" : "{{session_key}}"};
- onCreateContentReady("{% url ldt.ldt_utils.views.content.upload %}",
- '{% absstatic "ldt" %}',
- post_added_params,
- '{% trans "Browse" %}',
- '{% trans "File uploaded" %}',
- '{% trans "Please wait, the upload is not finished yet" %}',
- '{% trans "Cancel upload" %}',
- "{% url ldt.ldt_utils.views.content.remove_temp_file %}",
- "{% url ldt.ldt_utils.views.content.get_duration %}");
-
+ onCreateContentReady('{% absstatic "ldt" %}', post_added_params);
});
// the function stopRKey prevents from the validation of the form if the user tape enter button while entering a field
function stopRKey(evt) {
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
- }
+ }
document.onkeypress = stopRKey;
+ chunked_uploads_endpoints = {
+ upload_url: '{{WEB_URL}}{% url upload %}',
+ done_url: '{{WEB_URL}}{% url upload_done uuid='00000000-0000-0000-0000-000000000000' %}',
+ username: 'example',
+ api_key: 'secret_example',
+ };
+
+ $(function() {
+ //gets video_url and returns it to the "scr" field
+ chunked_uploads_video_url = function(video_url) {
+ $('#id_content-media_input_type').val("create");
+ $('#id_media-src').val(video_url);
+ $('#id_media-src').attr('readOnly', true);
+ $(".media_fields").hide();
+ $("#media_field_create").show();
+ $('#upload_url').append(video_url);
+ };
+
+ //callback of chunked upload start
+ chunked_uploads_start = function(){
+ };
+
+ //callback of chunked upload stop
+ chunked_uploads_stop = function(){
+ };
+
+ //callback of chunked upload error
+ chunked_uploads_error = function(){
+ alert("The upload failed. Please reload the page, and try again.");
+ };
+
+ //callback of chunked upload complete
+ chunked_uploads_complete = function(){
+ };
+ });
</script>
{% endblock %}
@@ -60,7 +86,7 @@
<link rel="stylesheet" href='{% absstatic "ldt/css/style.css" %}'/>
<link rel="stylesheet" href='{% absstatic "ldt/css/blueprint/screen.css" %}' type="text/css" media="screen, projection" />
<link rel="stylesheet" href='{% absstatic "ldt/css/blueprint/print.css" %}' type="text/css" media="print" />
- <link rel="stylesheet" href='{% absstatic "ldt//css/workspace.css" %}'type="text/css"/>
+ <link rel="stylesheet" href='{% absstatic "ldt/css/workspace.css" %}'type="text/css"/>
{% endblock %}
@@ -114,15 +140,14 @@
<div>{{ content_form.media_input_type.errors }}{{ content_form.media_input_type.label_tag }}{{content_form.media_input_type}}</div>
<div id="media_fields_div">
<div id="media_field_link" class="media_fields">{{ content_form.media_obj.errors }}{{ content_form.media_obj.label_tag }}{{content_form.media_obj}}</div>
+
<div id="media_field_upload" class="media_fields">
- {{ media_form.media_file.errors }}
- {% comment %}{{ media_form.media_file.label_tag }}{{media_form.media_file}}{% endcomment %}
- <div id="upload_btn"></div>
- <input type="text" name="media-local_file_name" id="id_media-local_file_name" readonly/>
- <div id="upload_progress_bar"></div>
- <div id="upload_progress_info"></div>
+ <!-- refers to chunked_upload template -->
+ {% include "ldt/ldt_utils/partial/chunked_uploads.html"%}
</div>
+
<div id="media_field_url" class="media_fields">{{ media_form.external_src_url.errors }}{{ media_form.external_src_url.label_tag }}{{ media_form.external_src_url }}</div>
+
<div id="media_field_create" class="media_fields">{{ media_form.src.errors }}{{ media_form.src.label_tag }}{{ media_form.src }}</div>
</div>
</div>
@@ -138,7 +163,6 @@
{% endif %}
{% include "ldt/ldt_utils/partial/picture.html"%}
{% include "ldt/ldt_utils/partial/permissions.html" %}
-
<div id="submitcontent" class="span-18 last">
<div id="submitcontent-loader" class="span-10">
@@ -155,4 +179,8 @@
</form>
</div>
+ <script type="text/javascript" src='{% absstatic "ldt/js/jquery.ui.widget.js" %}'></script>
+ <script type="text/javascript" src='{% absstatic "ldt/js/jquery.iframe-transport.js" %}'></script>
+ <script type="text/javascript" src='{% absstatic "ldt/js/jquery.fileupload.js" %}'></script>
+ <script type="text/javascript" src='{% absstatic "ldt/js/jquery.chunked_uploads.js" %}'></script>
{% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/partial/chunked_uploads.html Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,33 @@
+<!-- {% load absstatic %} -->
+
+<link rel="stylesheet" href='{% absstatic "ldt/css/chunked_uploads.css" %}'/>
+
+<script type="text/javascript" charset="utf-8">
+ function file_name(element) {
+ $(element).hide();
+ $("#file_part").append(element.value);
+ };
+</script>
+
+<span id="file_part" class="fileinput-button">
+ <input type="file" id="fileupload" name="files[]" onchange="file_name(this)"/>
+</span>
+<br/>
+<button id="start_upload" class="action_upload" type="button">
+ <span>Start</span>
+</button>
+<button id="resume_upload" class="action_upload" type="button">
+ <span>Resume</span>
+</button>
+<button id="pause_upload" class="action_upload" type="button">
+ <span>Pause</span>
+</button>
+<button id="cancel_upload" class="action_upload" type="button">
+ <span>Cancel</span>
+</button>
+<div class="bar grey stripes">
+ <span class="progress" style="width: 0%"></span>
+</div>
+
+<div id="upload_url">
+</div>
\ No newline at end of file
--- a/src/ldt/ldt/ldt_utils/urls.py Sun Feb 10 23:04:28 2013 +0100
+++ b/src/ldt/ldt/ldt_utils/urls.py Tue Feb 12 17:30:41 2013 +0100
@@ -75,5 +75,4 @@
url(r'^space/upload/$', 'views.content.upload'),
url(r'^space/removetempfile/$', 'views.content.remove_temp_file'),
url(r'^space/getduration/$', 'views.content.get_duration'),
-
)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/css/chunked_uploads.css Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,46 @@
+
+.fileinput-button {
+}
+
+.fileinput-button input {
+ opacity: 1;
+ filter: alpha(opacity=0);
+}
+
+.bar {
+background-color: #FFFFFF;
+ height: 12px;
+ padding: 3px;
+ width: 250px;
+ border-radius: 45px;
+ box-shadow: 0 1px 5px #000 inset, 0 1px 0 #444;
+ }
+
+.bar span {
+ display: inline-block;
+ height: 100%;
+ border-radius: 45px;
+ -webkit-transition: width .4s ease-in-out;
+}
+
+.grey span {
+ background-color: #838383;
+}
+
+.stripes span {
+ -webkit-background-size: 30px 30px;
+ background-size: 30px 30px;
+ background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
+ transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
+ transparent 75%, transparent);
+
+ -webkit-animation: animate-stripes 3s linear infinite;
+}
+
+@-webkit-keyframes animate-stripes {
+ 0% {background-position: 0 0;} 100% {background-position: 60px 0;}
+}
+
+@-moz-keyframes animate-stripes {
+ 0% {background-position: 0 0;} 100% {background-position: 60px 0;}
+}
\ No newline at end of file
--- a/src/ldt/ldt/static/ldt/css/ldtform.css Sun Feb 10 23:04:28 2013 +0100
+++ b/src/ldt/ldt/static/ldt/css/ldtform.css Tue Feb 12 17:30:41 2013 +0100
@@ -163,7 +163,7 @@
}
#media_fields_div {
- width : 338px;
+ width : 300px;
height : 50px;
margin-top: 10px 0px;
padding-left: 10px;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.chunked_uploads.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,229 @@
+$(function () {
+ 'use strict';
+ var is_canceled=false;
+ var is_paused=false;
+ var data_resume = null;
+ var chunked_uploads_jqXHR = null;
+ $('#start_upload').attr('disabled', true);
+ $('#pause_upload').attr('disabled', true);
+ $('#resume_upload').attr('disabled', true);
+ $('#cancel_upload').attr('disabled', true);
+
+ //authentication send in the header, to log with ApiKey
+ var authentication = {
+ username: chunked_uploads_endpoints.username,
+ api_key: chunked_uploads_endpoints.api_key
+ }
+
+ $('#fileupload').fileupload({
+ url: chunked_uploads_endpoints.upload_url,
+ dataType: 'json',
+ maxChunkSize: 1048576,
+ singleFileUploads: false,
+ maxNumberOfFiles: 1,
+ multipart: false,
+ xhrFields: {
+ withCredentials: true
+ },
+ headers: authentication,
+ add: function (e, data) {
+ //Get json from server to know if and upload has already been started
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ data: authentication,
+ url: chunked_uploads_endpoints.upload_url,
+ xhrFields: {withCredentials: true},
+ success: function(current_upload){
+ //If not null then an upload has already been started
+ if (current_upload != ""){
+ //checks if the file selected match with the file currently uploaded on the server
+ if (data.files[0].size == current_upload[0].total_size){
+ //the file match, so we'll resume the upload from uploadedBytes
+ data.uploadedBytes = current_upload[0].size;
+ }
+ else{
+ //The file doesn't match, so delete the current upload on the server
+ $.ajax({
+ type: current_upload[0].delete_type,
+ url: current_upload[0].delete_url,
+ data: authentication,
+ });
+ }
+ }
+ },
+ });
+
+ $('#start_upload').attr('disabled', false);
+ $('#start_upload').one('click', function (e) {
+ e.preventDefault();
+ chunked_uploads_jqXHR = data.submit();
+ });
+ },
+ start: function (e, data){
+ if (typeof chunked_uploads_start === "function") {
+ chunked_uploads_start();
+ }
+ },
+ done: function (e, data) {
+ $('#start_upload').hide();
+ $('#pause_upload').hide();
+ $('#resume_upload').hide();
+ $('#cancel_upload').hide();
+
+ chunked_uploads_endpoints.done_url = chunked_uploads_endpoints.done_url.replace('00000000-0000-0000-0000-000000000000', data.result[0].upload_uuid);
+ //send COMPLETE request
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ headers: authentication,
+ url: chunked_uploads_endpoints.done_url,
+ xhrFields: {withCredentials: true},
+ success: function(current_upload){
+ //error callback if upload state is FAIL
+ if (current_upload[0].state=="FAIL"){
+ if (typeof chunked_uploads_error === "function") {
+ chunked_uploads_error();
+ }
+ }
+ //complete and video_url callback if success
+ else{
+ if (typeof chunked_uploads_complete === "function") {
+ chunked_uploads_complete();
+ }
+ if (typeof chunked_uploads_video_url === "function") {
+ chunked_uploads_video_url(current_upload[0].video_url);
+ }
+ }
+ },
+ error: function(){
+ if (typeof chunked_uploads_error === "function") {
+ chunked_uploads_error();
+ }
+ }
+ });
+ },
+ progressall: function (e, data) {
+ var progress = parseInt(data.loaded / data.total * 100, 10);
+ $('.progress').css(
+ 'width',
+ progress + '%'
+ );
+ },
+ send: function(e, data) {
+ $("#fileupload").hide();
+ $('#start_upload').hide();
+ $('#pause_upload').attr('disabled', false);
+ $('#cancel_upload').attr('disabled', false);
+ },
+ fail: function(e, data) {
+ data_resume = data;
+ },
+ });
+
+ $('#cancel_upload').click(function (e) {
+ if (!is_paused){
+ //if cancel is clicked during the upload
+ is_canceled = true;
+ //stop the download
+ chunked_uploads_jqXHR.abort();
+ $('#pause_upload').attr('disabled', true);
+ $('#resume_upload').attr('disabled', true);
+ //wait 1s before sending a DELETE request to the server
+ setTimeout(function() {
+ $.ajax({
+ dataType: "json",
+ url: chunked_uploads_endpoints.upload_url,
+ data: authentication,
+ xhrFields: {withCredentials: true},
+ success: function(current_upload){
+ $.ajax({
+ type: current_upload[0].delete_type,
+ url: current_upload[0].delete_url,
+ data: authentication,
+ });
+ }
+ });
+ },1000);
+ }
+ else{
+ //if cancel is clicked while pause we send the DELETE request
+ $.ajax({
+ dataType: "json",
+ url: chunked_uploads_endpoints.upload_url,
+ xhrFields: {withCredentials: true},
+ data: authentication,
+ success: function(current_upload){
+ $.ajax({
+ type: current_upload[0].delete_type,
+ url: current_upload[0].delete_url,
+ headers: authentication,
+ });
+ }
+ });
+ }
+ });
+
+ $('#pause_upload').click(function (e) {
+ is_paused = true;
+ chunked_uploads_jqXHR.abort();
+ if (typeof chunked_uploads_stop === "function") {
+ chunked_uploads_stop();
+ }
+ $('#pause_upload').attr('disabled', true);
+ $('#resume_upload').attr('disabled', false);
+ });
+
+ $('#resume_upload').click(function (e) {
+ is_paused = false;
+ $.ajax({
+ dataType: "json",
+ url: chunked_uploads_endpoints.upload_url,
+ data: authentication,
+ xhrFields: {withCredentials: true},
+ success: function(current_upload){
+ data_resume.uploadedBytes = current_upload[0].size;
+ chunked_uploads_jqXHR = data_resume.submit();
+ }
+ });
+ if (typeof chunked_uploads_start === "function") {
+ chunked_uploads_start();
+ }
+ $('#resume_upload').attr('disabled', true);
+ $('#pause_upload').attr('disabled', false);
+ });
+
+ //connection listener
+ if ('onLine' in navigator) {
+ //event listener on connection found
+ window.addEventListener('online', function(){
+ is_paused = false;
+ $.ajax({
+ dataType: "json",
+ url: chunked_uploads_endpoints.upload_url,
+ data: authentication,
+ xhrFields: {withCredentials: true},
+ success: function(current_upload){
+ data_resume.uploadedBytes = current_upload[0].size;
+ chunked_uploads_jqXHR = data_resume.submit();
+ }
+ });
+ if (typeof chunked_uploads_start === "function") {
+ chunked_uploads_start();
+ }
+ $('#resume_upload').attr('disabled', true);
+ $('#pause_upload').attr('disabled', false);
+ });
+
+ //event listener on connection lost
+ window.addEventListener('offline', function(){
+ if (chunked_uploads_jqXHR != null){
+ is_paused = true;
+ $('#pause_upload').attr('disabled', true);
+ $('#resume_upload').attr('disabled', true);
+ chunked_uploads_jqXHR.abort();
+ }
+ });
+ };
+
+});
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.fileupload.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,1113 @@
+/*
+ * jQuery File Upload Plugin 5.19.7
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/*jslint nomen: true, unparam: true, regexp: true */
+/*global define, window, document, File, Blob, FormData, location */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define([
+ 'jquery',
+ 'jquery.ui.widget'
+ ], factory);
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+
+ // The FileReader API is not actually used, but works as feature detection,
+ // as e.g. Safari supports XHR file uploads via the FormData API,
+ // but not non-multipart XHR file uploads:
+ $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
+ $.support.xhrFormDataFileUpload = !!window.FormData;
+
+ // The fileupload widget listens for change events on file input fields defined
+ // via fileInput setting and paste or drop events of the given dropZone.
+ // In addition to the default jQuery Widget methods, the fileupload widget
+ // exposes the "add" and "send" methods, to add or directly send files using
+ // the fileupload API.
+ // By default, files added via file input selection, paste, drag & drop or
+ // "add" method are uploaded immediately, but it is possible to override
+ // the "add" callback option to queue file uploads.
+ $.widget('blueimp.fileupload', {
+
+ options: {
+ // The drop target element(s), by the default the complete document.
+ // Set to null to disable drag & drop support:
+ dropZone: $(document),
+ // The paste target element(s), by the default the complete document.
+ // Set to null to disable paste support:
+ pasteZone: $(document),
+ // The file input field(s), that are listened to for change events.
+ // If undefined, it is set to the file input fields inside
+ // of the widget element on plugin initialization.
+ // Set to null to disable the change listener.
+ fileInput: undefined,
+ // By default, the file input field is replaced with a clone after
+ // each input field change event. This is required for iframe transport
+ // queues and allows change events to be fired for the same file
+ // selection, but can be disabled by setting the following option to false:
+ replaceFileInput: true,
+ // The parameter name for the file form data (the request argument name).
+ // If undefined or empty, the name property of the file input field is
+ // used, or "files[]" if the file input name property is also empty,
+ // can be a string or an array of strings:
+ paramName: undefined,
+ // By default, each file of a selection is uploaded using an individual
+ // request for XHR type uploads. Set to false to upload file
+ // selections in one request each:
+ singleFileUploads: true,
+ // To limit the number of files uploaded with one XHR request,
+ // set the following option to an integer greater than 0:
+ limitMultiFileUploads: undefined,
+ // Set the following option to true to issue all file upload requests
+ // in a sequential order:
+ sequentialUploads: false,
+ // To limit the number of concurrent uploads,
+ // set the following option to an integer greater than 0:
+ limitConcurrentUploads: undefined,
+ // Set the following option to true to force iframe transport uploads:
+ forceIframeTransport: false,
+ // Set the following option to the location of a redirect url on the
+ // origin server, for cross-domain iframe transport uploads:
+ redirect: undefined,
+ // The parameter name for the redirect url, sent as part of the form
+ // data and set to 'redirect' if this option is empty:
+ redirectParamName: undefined,
+ // Set the following option to the location of a postMessage window,
+ // to enable postMessage transport uploads:
+ postMessage: undefined,
+ // By default, XHR file uploads are sent as multipart/form-data.
+ // The iframe transport is always using multipart/form-data.
+ // Set to false to enable non-multipart XHR uploads:
+ multipart: true,
+ // To upload large files in smaller chunks, set the following option
+ // to a preferred maximum chunk size. If set to 0, null or undefined,
+ // or the browser does not support the required Blob API, files will
+ // be uploaded as a whole.
+ maxChunkSize: undefined,
+ // When a non-multipart upload or a chunked multipart upload has been
+ // aborted, this option can be used to resume the upload by setting
+ // it to the size of the already uploaded bytes. This option is most
+ // useful when modifying the options object inside of the "add" or
+ // "send" callbacks, as the options are cloned for each file upload.
+ uploadedBytes: undefined,
+ // By default, failed (abort or error) file uploads are removed from the
+ // global progress calculation. Set the following option to false to
+ // prevent recalculating the global progress data:
+ recalculateProgress: true,
+ // Interval in milliseconds to calculate and trigger progress events:
+ progressInterval: 100,
+ // Interval in milliseconds to calculate progress bitrate:
+ bitrateInterval: 500,
+
+ // Additional form data to be sent along with the file uploads can be set
+ // using this option, which accepts an array of objects with name and
+ // value properties, a function returning such an array, a FormData
+ // object (for XHR file uploads), or a simple object.
+ // The form of the first fileInput is given as parameter to the function:
+ formData: function (form) {
+ return form.serializeArray();
+ },
+
+ // The add callback is invoked as soon as files are added to the fileupload
+ // widget (via file input selection, drag & drop, paste or add API call).
+ // If the singleFileUploads option is enabled, this callback will be
+ // called once for each file in the selection for XHR file uplaods, else
+ // once for each file selection.
+ // The upload starts when the submit method is invoked on the data parameter.
+ // The data object contains a files property holding the added files
+ // and allows to override plugin options as well as define ajax settings.
+ // Listeners for this callback can also be bound the following way:
+ // .bind('fileuploadadd', func);
+ // data.submit() returns a Promise object and allows to attach additional
+ // handlers using jQuery's Deferred callbacks:
+ // data.submit().done(func).fail(func).always(func);
+ add: function (e, data) {
+ data.submit();
+ },
+
+ // Other callbacks:
+ // Callback for the submit event of each file upload:
+ // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
+ // Callback for the start of each file upload request:
+ // send: function (e, data) {}, // .bind('fileuploadsend', func);
+ // Callback for successful uploads:
+ // done: function (e, data) {}, // .bind('fileuploaddone', func);
+ // Callback for failed (abort or error) uploads:
+ // fail: function (e, data) {}, // .bind('fileuploadfail', func);
+ // Callback for completed (success, abort or error) requests:
+ // always: function (e, data) {}, // .bind('fileuploadalways', func);
+ // Callback for upload progress events:
+ // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
+ // Callback for global upload progress events:
+ // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
+ // Callback for uploads start, equivalent to the global ajaxStart event:
+ // start: function (e) {}, // .bind('fileuploadstart', func);
+ // Callback for uploads stop, equivalent to the global ajaxStop event:
+ // stop: function (e) {}, // .bind('fileuploadstop', func);
+ // Callback for change events of the fileInput(s):
+ // change: function (e, data) {}, // .bind('fileuploadchange', func);
+ // Callback for paste events to the pasteZone(s):
+ // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
+ // Callback for drop events of the dropZone(s):
+ // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
+ // Callback for dragover events of the dropZone(s):
+ // dragover: function (e) {}, // .bind('fileuploaddragover', func);
+
+ // The plugin options are used as settings object for the ajax calls.
+ // The following are jQuery ajax settings required for the file uploads:
+ processData: false,
+ contentType: false,
+ cache: false
+ },
+
+ // A list of options that require a refresh after assigning a new value:
+ _refreshOptionsList: [
+ 'fileInput',
+ 'dropZone',
+ 'pasteZone',
+ 'multipart',
+ 'forceIframeTransport'
+ ],
+
+ _BitrateTimer: function () {
+ this.timestamp = +(new Date());
+ this.loaded = 0;
+ this.bitrate = 0;
+ this.getBitrate = function (now, loaded, interval) {
+ var timeDiff = now - this.timestamp;
+ if (!this.bitrate || !interval || timeDiff > interval) {
+ this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
+ this.loaded = loaded;
+ this.timestamp = now;
+ }
+ return this.bitrate;
+ };
+ },
+
+ _isXHRUpload: function (options) {
+ return !options.forceIframeTransport &&
+ ((!options.multipart && $.support.xhrFileUpload) ||
+ $.support.xhrFormDataFileUpload);
+ },
+
+ _getFormData: function (options) {
+ var formData;
+ if (typeof options.formData === 'function') {
+ return options.formData(options.form);
+ }
+ if ($.isArray(options.formData)) {
+ return options.formData;
+ }
+ if (options.formData) {
+ formData = [];
+ $.each(options.formData, function (name, value) {
+ formData.push({name: name, value: value});
+ });
+ return formData;
+ }
+ return [];
+ },
+
+ _getTotal: function (files) {
+ var total = 0;
+ $.each(files, function (index, file) {
+ total += file.size || 1;
+ });
+ return total;
+ },
+
+ _onProgress: function (e, data) {
+ if (e.lengthComputable) {
+ var now = +(new Date()),
+ total,
+ loaded;
+ if (data._time && data.progressInterval &&
+ (now - data._time < data.progressInterval) &&
+ e.loaded !== e.total) {
+ return;
+ }
+ data._time = now;
+ total = data.total || this._getTotal(data.files);
+ loaded = parseInt(
+ e.loaded / e.total * (data.chunkSize || total),
+ 10
+ ) + (data.uploadedBytes || 0);
+ this._loaded += loaded - (data.loaded || data.uploadedBytes || 0);
+ data.lengthComputable = true;
+ data.loaded = loaded;
+ data.total = total;
+ data.bitrate = data._bitrateTimer.getBitrate(
+ now,
+ loaded,
+ data.bitrateInterval
+ );
+ // Trigger a custom progress event with a total data property set
+ // to the file size(s) of the current upload and a loaded data
+ // property calculated accordingly:
+ this._trigger('progress', e, data);
+ // Trigger a global progress event for all current file uploads,
+ // including ajax calls queued for sequential file uploads:
+ this._trigger('progressall', e, {
+ lengthComputable: true,
+ loaded: this._loaded,
+ total: this._total,
+ bitrate: this._bitrateTimer.getBitrate(
+ now,
+ this._loaded,
+ data.bitrateInterval
+ )
+ });
+ }
+ },
+
+ _initProgressListener: function (options) {
+ var that = this,
+ xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
+ // Accesss to the native XHR object is required to add event listeners
+ // for the upload progress event:
+ if (xhr.upload) {
+ $(xhr.upload).bind('progress', function (e) {
+ var oe = e.originalEvent;
+ // Make sure the progress event properties get copied over:
+ e.lengthComputable = oe.lengthComputable;
+ e.loaded = oe.loaded;
+ e.total = oe.total;
+ that._onProgress(e, options);
+ });
+ options.xhr = function () {
+ return xhr;
+ };
+ }
+ },
+
+ _initXHRData: function (options) {
+ var formData,
+ file = options.files[0],
+ // Ignore non-multipart setting if not supported:
+ multipart = options.multipart || !$.support.xhrFileUpload,
+ paramName = options.paramName[0];
+ options.headers = options.headers || {};
+ if (options.contentRange) {
+ options.headers['Content-Range'] = options.contentRange;
+ }
+ if (!multipart) {
+ options.headers['Content-Disposition'] = 'attachment; filename="' +
+ encodeURI(file.name) + '"';
+ options.contentType = file.type;
+ options.data = options.blob || file;
+ } else if ($.support.xhrFormDataFileUpload) {
+ if (options.postMessage) {
+ // window.postMessage does not allow sending FormData
+ // objects, so we just add the File/Blob objects to
+ // the formData array and let the postMessage window
+ // create the FormData object out of this array:
+ formData = this._getFormData(options);
+ if (options.blob) {
+ formData.push({
+ name: paramName,
+ value: options.blob
+ });
+ } else {
+ $.each(options.files, function (index, file) {
+ formData.push({
+ name: options.paramName[index] || paramName,
+ value: file
+ });
+ });
+ }
+ } else {
+ if (options.formData instanceof FormData) {
+ formData = options.formData;
+ } else {
+ formData = new FormData();
+ $.each(this._getFormData(options), function (index, field) {
+ formData.append(field.name, field.value);
+ });
+ }
+ if (options.blob) {
+ options.headers['Content-Disposition'] = 'attachment; filename="' +
+ encodeURI(file.name) + '"';
+ formData.append(paramName, options.blob, file.name);
+ } else {
+ $.each(options.files, function (index, file) {
+ // Files are also Blob instances, but some browsers
+ // (Firefox 3.6) support the File API but not Blobs.
+ // This check allows the tests to run with
+ // dummy objects:
+ if ((window.Blob && file instanceof Blob) ||
+ (window.File && file instanceof File)) {
+ formData.append(
+ options.paramName[index] || paramName,
+ file,
+ file.name
+ );
+ }
+ });
+ }
+ }
+ options.data = formData;
+ }
+ // Blob reference is not needed anymore, free memory:
+ options.blob = null;
+ },
+
+ _initIframeSettings: function (options) {
+ // Setting the dataType to iframe enables the iframe transport:
+ options.dataType = 'iframe ' + (options.dataType || '');
+ // The iframe transport accepts a serialized array as form data:
+ options.formData = this._getFormData(options);
+ // Add redirect url to form data on cross-domain uploads:
+ if (options.redirect && $('<a></a>').prop('href', options.url)
+ .prop('host') !== location.host) {
+ options.formData.push({
+ name: options.redirectParamName || 'redirect',
+ value: options.redirect
+ });
+ }
+ },
+
+ _initDataSettings: function (options) {
+ if (this._isXHRUpload(options)) {
+ if (!this._chunkedUpload(options, true)) {
+ if (!options.data) {
+ this._initXHRData(options);
+ }
+ this._initProgressListener(options);
+ }
+ if (options.postMessage) {
+ // Setting the dataType to postmessage enables the
+ // postMessage transport:
+ options.dataType = 'postmessage ' + (options.dataType || '');
+ }
+ } else {
+ this._initIframeSettings(options, 'iframe');
+ }
+ },
+
+ _getParamName: function (options) {
+ var fileInput = $(options.fileInput),
+ paramName = options.paramName;
+ if (!paramName) {
+ paramName = [];
+ fileInput.each(function () {
+ var input = $(this),
+ name = input.prop('name') || 'files[]',
+ i = (input.prop('files') || [1]).length;
+ while (i) {
+ paramName.push(name);
+ i -= 1;
+ }
+ });
+ if (!paramName.length) {
+ paramName = [fileInput.prop('name') || 'files[]'];
+ }
+ } else if (!$.isArray(paramName)) {
+ paramName = [paramName];
+ }
+ return paramName;
+ },
+
+ _initFormSettings: function (options) {
+ // Retrieve missing options from the input field and the
+ // associated form, if available:
+ if (!options.form || !options.form.length) {
+ options.form = $(options.fileInput.prop('form'));
+ // If the given file input doesn't have an associated form,
+ // use the default widget file input's form:
+ if (!options.form.length) {
+ options.form = $(this.options.fileInput.prop('form'));
+ }
+ }
+ options.paramName = this._getParamName(options);
+ if (!options.url) {
+ options.url = options.form.prop('action') || location.href;
+ }
+ // The HTTP request method must be "POST" or "PUT":
+ options.type = (options.type || options.form.prop('method') || '')
+ .toUpperCase();
+ if (options.type !== 'POST' && options.type !== 'PUT') {
+ options.type = 'POST';
+ }
+ if (!options.formAcceptCharset) {
+ options.formAcceptCharset = options.form.attr('accept-charset');
+ }
+ },
+
+ _getAJAXSettings: function (data) {
+ var options = $.extend({}, this.options, data);
+ this._initFormSettings(options);
+ this._initDataSettings(options);
+ return options;
+ },
+
+ // Maps jqXHR callbacks to the equivalent
+ // methods of the given Promise object:
+ _enhancePromise: function (promise) {
+ promise.success = promise.done;
+ promise.error = promise.fail;
+ promise.complete = promise.always;
+ return promise;
+ },
+
+ // Creates and returns a Promise object enhanced with
+ // the jqXHR methods abort, success, error and complete:
+ _getXHRPromise: function (resolveOrReject, context, args) {
+ var dfd = $.Deferred(),
+ promise = dfd.promise();
+ context = context || this.options.context || promise;
+ if (resolveOrReject === true) {
+ dfd.resolveWith(context, args);
+ } else if (resolveOrReject === false) {
+ dfd.rejectWith(context, args);
+ }
+ promise.abort = dfd.promise;
+ return this._enhancePromise(promise);
+ },
+
+ // Parses the Range header from the server response
+ // and returns the uploaded bytes:
+ _getUploadedBytes: function (jqXHR) {
+ var range = jqXHR.getResponseHeader('Range'),
+ parts = range && range.split('-'),
+ upperBytesPos = parts && parts.length > 1 &&
+ parseInt(parts[1], 10);
+ return upperBytesPos && upperBytesPos + 1;
+ },
+
+ // Uploads a file in multiple, sequential requests
+ // by splitting the file up in multiple blob chunks.
+ // If the second parameter is true, only tests if the file
+ // should be uploaded in chunks, but does not invoke any
+ // upload requests:
+ _chunkedUpload: function (options, testOnly) {
+ var that = this,
+ file = options.files[0],
+ fs = file.size,
+ ub = options.uploadedBytes = options.uploadedBytes || 0,
+ mcs = options.maxChunkSize || fs,
+ slice = file.slice || file.webkitSlice || file.mozSlice,
+ dfd = $.Deferred(),
+ promise = dfd.promise(),
+ jqXHR,
+ upload;
+ if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
+ options.data) {
+ return false;
+ }
+ if (testOnly) {
+ return true;
+ }
+ if (ub >= fs) {
+ file.error = 'Uploaded bytes exceed file size';
+ return this._getXHRPromise(
+ false,
+ options.context,
+ [null, 'error', file.error]
+ );
+ }
+ // The chunk upload method:
+ upload = function (i) {
+ // Clone the options object for each chunk upload:
+ var o = $.extend({}, options);
+ o.blob = slice.call(
+ file,
+ ub,
+ ub + mcs,
+ file.type
+ );
+ // Store the current chunk size, as the blob itself
+ // will be dereferenced after data processing:
+ o.chunkSize = o.blob.size;
+ // Expose the chunk bytes position range:
+ o.contentRange = 'bytes ' + ub + '-' +
+ (ub + o.chunkSize - 1) + '/' + fs;
+ // Process the upload data (the blob and potential form data):
+ that._initXHRData(o);
+ // Add progress listeners for this chunk upload:
+ that._initProgressListener(o);
+ jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context))
+ .done(function (result, textStatus, jqXHR) {
+ ub = that._getUploadedBytes(jqXHR) ||
+ (ub + o.chunkSize);
+ // Create a progress event if upload is done and
+ // no progress event has been invoked for this chunk:
+ if (!o.loaded) {
+ that._onProgress($.Event('progress', {
+ lengthComputable: true,
+ loaded: ub - o.uploadedBytes,
+ total: ub - o.uploadedBytes
+ }), o);
+ }
+ options.uploadedBytes = o.uploadedBytes = ub;
+ if (ub < fs) {
+ // File upload not yet complete,
+ // continue with the next chunk:
+ upload();
+ } else {
+ dfd.resolveWith(
+ o.context,
+ [result, textStatus, jqXHR]
+ );
+ }
+ })
+ .fail(function (jqXHR, textStatus, errorThrown) {
+ dfd.rejectWith(
+ o.context,
+ [jqXHR, textStatus, errorThrown]
+ );
+ });
+ };
+ this._enhancePromise(promise);
+ promise.abort = function () {
+ return jqXHR.abort();
+ };
+ upload();
+ return promise;
+ },
+
+ _beforeSend: function (e, data) {
+ if (this._active === 0) {
+ // the start callback is triggered when an upload starts
+ // and no other uploads are currently running,
+ // equivalent to the global ajaxStart event:
+ this._trigger('start');
+ // Set timer for global bitrate progress calculation:
+ this._bitrateTimer = new this._BitrateTimer();
+ }
+ this._active += 1;
+ // Initialize the global progress values:
+ this._loaded += data.uploadedBytes || 0;
+ this._total += this._getTotal(data.files);
+ },
+
+ _onDone: function (result, textStatus, jqXHR, options) {
+ if (!this._isXHRUpload(options)) {
+ // Create a progress event for each iframe load:
+ this._onProgress($.Event('progress', {
+ lengthComputable: true,
+ loaded: 1,
+ total: 1
+ }), options);
+ }
+ options.result = result;
+ options.textStatus = textStatus;
+ options.jqXHR = jqXHR;
+ this._trigger('done', null, options);
+ },
+
+ _onFail: function (jqXHR, textStatus, errorThrown, options) {
+ options.jqXHR = jqXHR;
+ options.textStatus = textStatus;
+ options.errorThrown = errorThrown;
+ this._trigger('fail', null, options);
+ if (options.recalculateProgress) {
+ // Remove the failed (error or abort) file upload from
+ // the global progress calculation:
+ this._loaded -= options.loaded || options.uploadedBytes || 0;
+ this._total -= options.total || this._getTotal(options.files);
+ }
+ },
+
+ _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
+ this._active -= 1;
+ options.textStatus = textStatus;
+ if (jqXHRorError && jqXHRorError.always) {
+ options.jqXHR = jqXHRorError;
+ options.result = jqXHRorResult;
+ } else {
+ options.jqXHR = jqXHRorResult;
+ options.errorThrown = jqXHRorError;
+ }
+ this._trigger('always', null, options);
+ if (this._active === 0) {
+ // The stop callback is triggered when all uploads have
+ // been completed, equivalent to the global ajaxStop event:
+ this._trigger('stop');
+ // Reset the global progress values:
+ this._loaded = this._total = 0;
+ this._bitrateTimer = null;
+ }
+ },
+
+ _onSend: function (e, data) {
+ var that = this,
+ jqXHR,
+ aborted,
+ slot,
+ pipe,
+ options = that._getAJAXSettings(data),
+ send = function () {
+ that._sending += 1;
+ // Set timer for bitrate progress calculation:
+ options._bitrateTimer = new that._BitrateTimer();
+ jqXHR = jqXHR || (
+ ((aborted || that._trigger('send', e, options) === false) &&
+ that._getXHRPromise(false, options.context, aborted)) ||
+ that._chunkedUpload(options) || $.ajax(options)
+ ).done(function (result, textStatus, jqXHR) {
+ that._onDone(result, textStatus, jqXHR, options);
+ }).fail(function (jqXHR, textStatus, errorThrown) {
+ that._onFail(jqXHR, textStatus, errorThrown, options);
+ }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
+ that._sending -= 1;
+ that._onAlways(
+ jqXHRorResult,
+ textStatus,
+ jqXHRorError,
+ options
+ );
+ if (options.limitConcurrentUploads &&
+ options.limitConcurrentUploads > that._sending) {
+ // Start the next queued upload,
+ // that has not been aborted:
+ var nextSlot = that._slots.shift(),
+ isPending;
+ while (nextSlot) {
+ // jQuery 1.6 doesn't provide .state(),
+ // while jQuery 1.8+ removed .isRejected():
+ isPending = nextSlot.state ?
+ nextSlot.state() === 'pending' :
+ !nextSlot.isRejected();
+ if (isPending) {
+ nextSlot.resolve();
+ break;
+ }
+ nextSlot = that._slots.shift();
+ }
+ }
+ });
+ return jqXHR;
+ };
+ this._beforeSend(e, options);
+ if (this.options.sequentialUploads ||
+ (this.options.limitConcurrentUploads &&
+ this.options.limitConcurrentUploads <= this._sending)) {
+ if (this.options.limitConcurrentUploads > 1) {
+ slot = $.Deferred();
+ this._slots.push(slot);
+ pipe = slot.pipe(send);
+ } else {
+ pipe = (this._sequence = this._sequence.pipe(send, send));
+ }
+ // Return the piped Promise object, enhanced with an abort method,
+ // which is delegated to the jqXHR object of the current upload,
+ // and jqXHR callbacks mapped to the equivalent Promise methods:
+ pipe.abort = function () {
+ aborted = [undefined, 'abort', 'abort'];
+ if (!jqXHR) {
+ if (slot) {
+ slot.rejectWith(options.context, aborted);
+ }
+ return send();
+ }
+ return jqXHR.abort();
+ };
+ return this._enhancePromise(pipe);
+ }
+ return send();
+ },
+
+ _onAdd: function (e, data) {
+ var that = this,
+ result = true,
+ options = $.extend({}, this.options, data),
+ limit = options.limitMultiFileUploads,
+ paramName = this._getParamName(options),
+ paramNameSet,
+ paramNameSlice,
+ fileSet,
+ i;
+ if (!(options.singleFileUploads || limit) ||
+ !this._isXHRUpload(options)) {
+ fileSet = [data.files];
+ paramNameSet = [paramName];
+ } else if (!options.singleFileUploads && limit) {
+ fileSet = [];
+ paramNameSet = [];
+ for (i = 0; i < data.files.length; i += limit) {
+ fileSet.push(data.files.slice(i, i + limit));
+ paramNameSlice = paramName.slice(i, i + limit);
+ if (!paramNameSlice.length) {
+ paramNameSlice = paramName;
+ }
+ paramNameSet.push(paramNameSlice);
+ }
+ } else {
+ paramNameSet = paramName;
+ }
+ data.originalFiles = data.files;
+ $.each(fileSet || data.files, function (index, element) {
+ var newData = $.extend({}, data);
+ newData.files = fileSet ? element : [element];
+ newData.paramName = paramNameSet[index];
+ newData.submit = function () {
+ newData.jqXHR = this.jqXHR =
+ (that._trigger('submit', e, this) !== false) &&
+ that._onSend(e, this);
+ return this.jqXHR;
+ };
+ result = that._trigger('add', e, newData);
+ return result;
+ });
+ return result;
+ },
+
+ _replaceFileInput: function (input) {
+ var inputClone = input.clone(true);
+ $('<form></form>').append(inputClone)[0].reset();
+ // Detaching allows to insert the fileInput on another form
+ // without loosing the file input value:
+ input.after(inputClone).detach();
+ // Avoid memory leaks with the detached file input:
+ $.cleanData(input.unbind('remove'));
+ // Replace the original file input element in the fileInput
+ // elements set with the clone, which has been copied including
+ // event handlers:
+ this.options.fileInput = this.options.fileInput.map(function (i, el) {
+ if (el === input[0]) {
+ return inputClone[0];
+ }
+ return el;
+ });
+ // If the widget has been initialized on the file input itself,
+ // override this.element with the file input clone:
+ if (input[0] === this.element[0]) {
+ this.element = inputClone;
+ }
+ },
+
+ _handleFileTreeEntry: function (entry, path) {
+ var that = this,
+ dfd = $.Deferred(),
+ errorHandler = function (e) {
+ if (e && !e.entry) {
+ e.entry = entry;
+ }
+ // Since $.when returns immediately if one
+ // Deferred is rejected, we use resolve instead.
+ // This allows valid files and invalid items
+ // to be returned together in one set:
+ dfd.resolve([e]);
+ },
+ dirReader;
+ path = path || '';
+ if (entry.isFile) {
+ if (entry._file) {
+ // Workaround for Chrome bug #149735
+ entry._file.relativePath = path;
+ dfd.resolve(entry._file);
+ } else {
+ entry.file(function (file) {
+ file.relativePath = path;
+ dfd.resolve(file);
+ }, errorHandler);
+ }
+ } else if (entry.isDirectory) {
+ dirReader = entry.createReader();
+ dirReader.readEntries(function (entries) {
+ that._handleFileTreeEntries(
+ entries,
+ path + entry.name + '/'
+ ).done(function (files) {
+ dfd.resolve(files);
+ }).fail(errorHandler);
+ }, errorHandler);
+ } else {
+ // Return an empy list for file system items
+ // other than files or directories:
+ dfd.resolve([]);
+ }
+ return dfd.promise();
+ },
+
+ _handleFileTreeEntries: function (entries, path) {
+ var that = this;
+ return $.when.apply(
+ $,
+ $.map(entries, function (entry) {
+ return that._handleFileTreeEntry(entry, path);
+ })
+ ).pipe(function () {
+ return Array.prototype.concat.apply(
+ [],
+ arguments
+ );
+ });
+ },
+
+ _getDroppedFiles: function (dataTransfer) {
+ dataTransfer = dataTransfer || {};
+ var items = dataTransfer.items;
+ if (items && items.length && (items[0].webkitGetAsEntry ||
+ items[0].getAsEntry)) {
+ return this._handleFileTreeEntries(
+ $.map(items, function (item) {
+ var entry;
+ if (item.webkitGetAsEntry) {
+ entry = item.webkitGetAsEntry();
+ if (entry) {
+ // Workaround for Chrome bug #149735:
+ entry._file = item.getAsFile();
+ }
+ return entry;
+ }
+ return item.getAsEntry();
+ })
+ );
+ }
+ return $.Deferred().resolve(
+ $.makeArray(dataTransfer.files)
+ ).promise();
+ },
+
+ _getSingleFileInputFiles: function (fileInput) {
+ fileInput = $(fileInput);
+ var entries = fileInput.prop('webkitEntries') ||
+ fileInput.prop('entries'),
+ files,
+ value;
+ if (entries && entries.length) {
+ return this._handleFileTreeEntries(entries);
+ }
+ files = $.makeArray(fileInput.prop('files'));
+ if (!files.length) {
+ value = fileInput.prop('value');
+ if (!value) {
+ return $.Deferred().resolve([]).promise();
+ }
+ // If the files property is not available, the browser does not
+ // support the File API and we add a pseudo File object with
+ // the input value as name with path information removed:
+ files = [{name: value.replace(/^.*\\/, '')}];
+ } else if (files[0].name === undefined && files[0].fileName) {
+ // File normalization for Safari 4 and Firefox 3:
+ $.each(files, function (index, file) {
+ file.name = file.fileName;
+ file.size = file.fileSize;
+ });
+ }
+ return $.Deferred().resolve(files).promise();
+ },
+
+ _getFileInputFiles: function (fileInput) {
+ if (!(fileInput instanceof $) || fileInput.length === 1) {
+ return this._getSingleFileInputFiles(fileInput);
+ }
+ return $.when.apply(
+ $,
+ $.map(fileInput, this._getSingleFileInputFiles)
+ ).pipe(function () {
+ return Array.prototype.concat.apply(
+ [],
+ arguments
+ );
+ });
+ },
+
+ _onChange: function (e) {
+ var that = this,
+ data = {
+ fileInput: $(e.target),
+ form: $(e.target.form)
+ };
+ this._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ if (that.options.replaceFileInput) {
+ that._replaceFileInput(data.fileInput);
+ }
+ if (that._trigger('change', e, data) !== false) {
+ that._onAdd(e, data);
+ }
+ });
+ },
+
+ _onPaste: function (e) {
+ var cbd = e.originalEvent.clipboardData,
+ items = (cbd && cbd.items) || [],
+ data = {files: []};
+ $.each(items, function (index, item) {
+ var file = item.getAsFile && item.getAsFile();
+ if (file) {
+ data.files.push(file);
+ }
+ });
+ if (this._trigger('paste', e, data) === false ||
+ this._onAdd(e, data) === false) {
+ return false;
+ }
+ },
+
+ _onDrop: function (e) {
+ var that = this,
+ dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer,
+ data = {};
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
+ e.preventDefault();
+ }
+ this._getDroppedFiles(dataTransfer).always(function (files) {
+ data.files = files;
+ if (that._trigger('drop', e, data) !== false) {
+ that._onAdd(e, data);
+ }
+ });
+ },
+
+ _onDragOver: function (e) {
+ var dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer;
+ if (this._trigger('dragover', e) === false) {
+ return false;
+ }
+ if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1) {
+ dataTransfer.dropEffect = 'copy';
+ e.preventDefault();
+ }
+ },
+
+ _initEventHandlers: function () {
+ if (this._isXHRUpload(this.options)) {
+ this._on(this.options.dropZone, {
+ dragover: this._onDragOver,
+ drop: this._onDrop
+ });
+ this._on(this.options.pasteZone, {
+ paste: this._onPaste
+ });
+ }
+ this._on(this.options.fileInput, {
+ change: this._onChange
+ });
+ },
+
+ _destroyEventHandlers: function () {
+ this._off(this.options.dropZone, 'dragover drop');
+ this._off(this.options.pasteZone, 'paste');
+ this._off(this.options.fileInput, 'change');
+ },
+
+ _setOption: function (key, value) {
+ var refresh = $.inArray(key, this._refreshOptionsList) !== -1;
+ if (refresh) {
+ this._destroyEventHandlers();
+ }
+ this._super(key, value);
+ if (refresh) {
+ this._initSpecialOptions();
+ this._initEventHandlers();
+ }
+ },
+
+ _initSpecialOptions: function () {
+ var options = this.options;
+ if (options.fileInput === undefined) {
+ options.fileInput = this.element.is('input[type="file"]') ?
+ this.element : this.element.find('input[type="file"]');
+ } else if (!(options.fileInput instanceof $)) {
+ options.fileInput = $(options.fileInput);
+ }
+ if (!(options.dropZone instanceof $)) {
+ options.dropZone = $(options.dropZone);
+ }
+ if (!(options.pasteZone instanceof $)) {
+ options.pasteZone = $(options.pasteZone);
+ }
+ },
+
+ _create: function () {
+ var options = this.options;
+ // Initialize options set via HTML5 data-attributes:
+ $.extend(options, $(this.element[0].cloneNode(false)).data());
+ this._initSpecialOptions();
+ this._slots = [];
+ this._sequence = this._getXHRPromise(true);
+ this._sending = this._active = this._loaded = this._total = 0;
+ this._initEventHandlers();
+ },
+
+ _destroy: function () {
+ this._destroyEventHandlers();
+ },
+
+ // This method is exposed to the widget API and allows adding files
+ // using the fileupload API. The data parameter accepts an object which
+ // must have a files property and can contain additional options:
+ // .fileupload('add', {files: filesList});
+ add: function (data) {
+ var that = this;
+ if (!data || this.options.disabled) {
+ return;
+ }
+ if (data.fileInput && !data.files) {
+ this._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ that._onAdd(null, data);
+ });
+ } else {
+ data.files = $.makeArray(data.files);
+ this._onAdd(null, data);
+ }
+ },
+
+ // This method is exposed to the widget API and allows sending files
+ // using the fileupload API. The data parameter accepts an object which
+ // must have a files or fileInput property and can contain additional options:
+ // .fileupload('send', {files: filesList});
+ // The method returns a Promise object for the file upload call.
+ send: function (data) {
+ if (data && !this.options.disabled) {
+ if (data.fileInput && !data.files) {
+ var that = this,
+ dfd = $.Deferred(),
+ promise = dfd.promise(),
+ jqXHR,
+ aborted;
+ promise.abort = function () {
+ aborted = true;
+ if (jqXHR) {
+ return jqXHR.abort();
+ }
+ dfd.reject(null, 'abort', 'abort');
+ return promise;
+ };
+ this._getFileInputFiles(data.fileInput).always(
+ function (files) {
+ if (aborted) {
+ return;
+ }
+ data.files = files;
+ jqXHR = that._onSend(null, data).then(
+ function (result, textStatus, jqXHR) {
+ dfd.resolve(result, textStatus, jqXHR);
+ },
+ function (jqXHR, textStatus, errorThrown) {
+ dfd.reject(jqXHR, textStatus, errorThrown);
+ }
+ );
+ }
+ );
+ return this._enhancePromise(promise);
+ }
+ data.files = $.makeArray(data.files);
+ if (data.files.length) {
+ return this._onSend(null, data);
+ }
+ }
+ return this._getXHRPromise(false, data && data.context);
+ }
+
+ });
+
+}));
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.iframe-transport.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,172 @@
+/*
+ * jQuery Iframe Transport Plugin 1.5
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/*jslint unparam: true, nomen: true */
+/*global define, window, document */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define(['jquery'], factory);
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+
+ // Helper variable to create unique names for the transport iframes:
+ var counter = 0;
+
+ // The iframe transport accepts three additional options:
+ // options.fileInput: a jQuery collection of file input fields
+ // options.paramName: the parameter name for the file form data,
+ // overrides the name property of the file input field(s),
+ // can be a string or an array of strings.
+ // options.formData: an array of objects with name and value properties,
+ // equivalent to the return data of .serializeArray(), e.g.:
+ // [{name: 'a', value: 1}, {name: 'b', value: 2}]
+ $.ajaxTransport('iframe', function (options) {
+ if (options.async && (options.type === 'POST' || options.type === 'GET')) {
+ var form,
+ iframe;
+ return {
+ send: function (_, completeCallback) {
+ form = $('<form style="display:none;"></form>');
+ form.attr('accept-charset', options.formAcceptCharset);
+ // javascript:false as initial iframe src
+ // prevents warning popups on HTTPS in IE6.
+ // IE versions below IE8 cannot set the name property of
+ // elements that have already been added to the DOM,
+ // so we set the name along with the iframe HTML markup:
+ iframe = $(
+ '<iframe src="javascript:false;" name="iframe-transport-' +
+ (counter += 1) + '"></iframe>'
+ ).bind('load', function () {
+ var fileInputClones,
+ paramNames = $.isArray(options.paramName) ?
+ options.paramName : [options.paramName];
+ iframe
+ .unbind('load')
+ .bind('load', function () {
+ var response;
+ // Wrap in a try/catch block to catch exceptions thrown
+ // when trying to access cross-domain iframe contents:
+ try {
+ response = iframe.contents();
+ // Google Chrome and Firefox do not throw an
+ // exception when calling iframe.contents() on
+ // cross-domain requests, so we unify the response:
+ if (!response.length || !response[0].firstChild) {
+ throw new Error();
+ }
+ } catch (e) {
+ response = undefined;
+ }
+ // The complete callback returns the
+ // iframe content document as response object:
+ completeCallback(
+ 200,
+ 'success',
+ {'iframe': response}
+ );
+ // Fix for IE endless progress bar activity bug
+ // (happens on form submits to iframe targets):
+ $('<iframe src="javascript:false;"></iframe>')
+ .appendTo(form);
+ form.remove();
+ });
+ form
+ .prop('target', iframe.prop('name'))
+ .prop('action', options.url)
+ .prop('method', options.type);
+ if (options.formData) {
+ $.each(options.formData, function (index, field) {
+ $('<input type="hidden"/>')
+ .prop('name', field.name)
+ .val(field.value)
+ .appendTo(form);
+ });
+ }
+ if (options.fileInput && options.fileInput.length &&
+ options.type === 'POST') {
+ fileInputClones = options.fileInput.clone();
+ // Insert a clone for each file input field:
+ options.fileInput.after(function (index) {
+ return fileInputClones[index];
+ });
+ if (options.paramName) {
+ options.fileInput.each(function (index) {
+ $(this).prop(
+ 'name',
+ paramNames[index] || options.paramName
+ );
+ });
+ }
+ // Appending the file input fields to the hidden form
+ // removes them from their original location:
+ form
+ .append(options.fileInput)
+ .prop('enctype', 'multipart/form-data')
+ // enctype must be set as encoding for IE:
+ .prop('encoding', 'multipart/form-data');
+ }
+ form.submit();
+ // Insert the file input fields at their original location
+ // by replacing the clones with the originals:
+ if (fileInputClones && fileInputClones.length) {
+ options.fileInput.each(function (index, input) {
+ var clone = $(fileInputClones[index]);
+ $(input).prop('name', clone.prop('name'));
+ clone.replaceWith(input);
+ });
+ }
+ });
+ form.append(iframe).appendTo(document.body);
+ },
+ abort: function () {
+ if (iframe) {
+ // javascript:false as iframe src aborts the request
+ // and prevents warning popups on HTTPS in IE6.
+ // concat is used to avoid the "Script URL" JSLint error:
+ iframe
+ .unbind('load')
+ .prop('src', 'javascript'.concat(':false;'));
+ }
+ if (form) {
+ form.remove();
+ }
+ }
+ };
+ }
+ });
+
+ // The iframe transport returns the iframe content document as response.
+ // The following adds converters from iframe to text, json, html, and script:
+ $.ajaxSetup({
+ converters: {
+ 'iframe text': function (iframe) {
+ return $(iframe[0].body).text();
+ },
+ 'iframe json': function (iframe) {
+ return $.parseJSON($(iframe[0].body).text());
+ },
+ 'iframe html': function (iframe) {
+ return $(iframe[0].body).html();
+ },
+ 'iframe script': function (iframe) {
+ return $.globalEval($(iframe[0].body).text());
+ }
+ }
+ });
+
+}));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.postmessage-transport.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,117 @@
+/*
+ * jQuery postMessage Transport Plugin 1.1
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/*jslint unparam: true, nomen: true */
+/*global define, window, document */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define(['jquery'], factory);
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+
+ var counter = 0,
+ names = [
+ 'accepts',
+ 'cache',
+ 'contents',
+ 'contentType',
+ 'crossDomain',
+ 'data',
+ 'dataType',
+ 'headers',
+ 'ifModified',
+ 'mimeType',
+ 'password',
+ 'processData',
+ 'timeout',
+ 'traditional',
+ 'type',
+ 'url',
+ 'username'
+ ],
+ convert = function (p) {
+ return p;
+ };
+
+ $.ajaxSetup({
+ converters: {
+ 'postmessage text': convert,
+ 'postmessage json': convert,
+ 'postmessage html': convert
+ }
+ });
+
+ $.ajaxTransport('postmessage', function (options) {
+ if (options.postMessage && window.postMessage) {
+ var iframe,
+ loc = $('<a>').prop('href', options.postMessage)[0],
+ target = loc.protocol + '//' + loc.host,
+ xhrUpload = options.xhr().upload;
+ return {
+ send: function (_, completeCallback) {
+ var message = {
+ id: 'postmessage-transport-' + (counter += 1)
+ },
+ eventName = 'message.' + message.id;
+ iframe = $(
+ '<iframe style="display:none;" src="' +
+ options.postMessage + '" name="' +
+ message.id + '"></iframe>'
+ ).bind('load', function () {
+ $.each(names, function (i, name) {
+ message[name] = options[name];
+ });
+ message.dataType = message.dataType.replace('postmessage ', '');
+ $(window).bind(eventName, function (e) {
+ e = e.originalEvent;
+ var data = e.data,
+ ev;
+ if (e.origin === target && data.id === message.id) {
+ if (data.type === 'progress') {
+ ev = document.createEvent('Event');
+ ev.initEvent(data.type, false, true);
+ $.extend(ev, data);
+ xhrUpload.dispatchEvent(ev);
+ } else {
+ completeCallback(
+ data.status,
+ data.statusText,
+ {postmessage: data.result},
+ data.headers
+ );
+ iframe.remove();
+ $(window).unbind(eventName);
+ }
+ }
+ });
+ iframe[0].contentWindow.postMessage(
+ message,
+ target
+ );
+ }).appendTo(document.body);
+ },
+ abort: function () {
+ if (iframe) {
+ iframe.remove();
+ }
+ }
+ };
+ }
+ });
+
+}));
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.ui.widget.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,528 @@
+/*
+ * jQuery UI Widget 1.9.1+amd
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+
+(function (factory) {
+ if (typeof define === "function" && define.amd) {
+ // Register as an anonymous AMD module:
+ define(["jquery"], factory);
+ } else {
+ // Browser globals:
+ factory(jQuery);
+ }
+}(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( $.isFunction( value ) ) {
+ prototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ }
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: basePrototype.widgetEventPrefix || name
+ }, prototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ // TODO remove widgetBaseClass, see #8155
+ widgetBaseClass: fullName,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+ var input = slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ new object( options, this );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ $.data( element, this.widgetName, this );
+ $.data( element, this.widgetFullName, this );
+ this._on( this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( value === undefined ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( value === undefined ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( element, handlers ) {
+ var delegateElement,
+ instance = this;
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ $.Widget.prototype._getCreateOptions = function() {
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
+ };
+}
+
+}));
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/static/ldt/js/jquery.xdr-transport.js Tue Feb 12 17:30:41 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * jQuery XDomainRequest Transport Plugin 1.1.2
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ *
+ * Based on Julian Aubourg's ajaxHooks xdr.js:
+ * https://github.com/jaubourg/ajaxHooks/
+ */
+
+/*jslint unparam: true */
+/*global define, window, XDomainRequest */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define(['jquery'], factory);
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+ if (window.XDomainRequest && !$.support.cors) {
+ $.ajaxTransport(function (s) {
+ if (s.crossDomain && s.async) {
+ if (s.timeout) {
+ s.xdrTimeout = s.timeout;
+ delete s.timeout;
+ }
+ var xdr;
+ return {
+ send: function (headers, completeCallback) {
+ function callback(status, statusText, responses, responseHeaders) {
+ xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
+ xdr = null;
+ completeCallback(status, statusText, responses, responseHeaders);
+ }
+ xdr = new XDomainRequest();
+ // XDomainRequest only supports GET and POST:
+ if (s.type === 'DELETE') {
+ s.url = s.url + (/\?/.test(s.url) ? '&' : '?') +
+ '_method=DELETE';
+ s.type = 'POST';
+ } else if (s.type === 'PUT') {
+ s.url = s.url + (/\?/.test(s.url) ? '&' : '?') +
+ '_method=PUT';
+ s.type = 'POST';
+ }
+ xdr.open(s.type, s.url);
+ xdr.onload = function () {
+ callback(
+ 200,
+ 'OK',
+ {text: xdr.responseText},
+ 'Content-Type: ' + xdr.contentType
+ );
+ };
+ xdr.onerror = function () {
+ callback(404, 'Not Found');
+ };
+ if (s.xdrTimeout) {
+ xdr.ontimeout = function () {
+ callback(0, 'timeout');
+ };
+ xdr.timeout = s.xdrTimeout;
+ }
+ xdr.send((s.hasContent && s.data) || null);
+ },
+ abort: function () {
+ if (xdr) {
+ xdr.onerror = $.noop();
+ xdr.abort();
+ }
+ }
+ };
+ }
+ });
+ }
+}));
\ No newline at end of file
--- a/src/ldt/ldt/static/ldt/js/projectscontents.js Sun Feb 10 23:04:28 2013 +0100
+++ b/src/ldt/ldt/static/ldt/js/projectscontents.js Tue Feb 12 17:30:41 2013 +0100
@@ -1,4 +1,4 @@
-
+
function init_events_base(base_node, embed_url) {
$('.imageline',base_node).each(function(i) {
@@ -386,7 +386,6 @@
function resize_modal_window (element, createcontent) {
- var nm = parent.$.nmTop();
var iframe = $("iframe", window.parent.document);
if ( $('#init_ldt_view', element).size() > 0) { // if contains ldt lpayer
var h = 660;
@@ -395,17 +394,9 @@
var h = $(element).innerHeight() + 10;
var w = $(element).innerWidth() + 10;
}
-
- nm.sizes.minH = h + 10;
- nm.sizes.minW = w;
+
iframe.height(h);
iframe.width(w);
-
- if ($.browser.mozilla && createcontent) {
- $(".nyroModalCont", parent.window.document).height(h+10);
- } else {
- nm.resize(true);
- }
}
//
@@ -417,11 +408,7 @@
window.submit_asked = false;
window.remove_temp_file_url = remove_url;
window.ask_duration_url = ask_dur_url;
-
- $("#close_button").click(function (e) {
- e.preventDefault();
- parent.$.nmTop().close();
- });
+
$("#submit_button_write").click(function(e) {
$(".submitcontent-loader-content").show();
resize_modal_window($("#add_content"), true);
@@ -439,103 +426,22 @@
$('#my_form').bind('submit', function() {
window.submit_asked = true;
if($('#id_content-media_input_type').val()=="upload"){
- if(window.upload_from_local_done==false){
- // The form has sent but the uploading has not ended.
- if($('#upload_progress_info').children().size()>0){
- $('#progress_info').remove();
- }
- $('#upload_progress_info').append('<p id="progress_info"><font color="red"><strong>' + wait_label + '.</strong></font><br/><a href="javascript:cancelSwfUpload()">' + cancel_label + '.</a></p>');
- return false;
+ /*if(chunked_upload_complete == true){
+ return true;
}
else{
- return true;
- }
+ return false;
+ }*/
+ return false;
}
else{
- //alert("2. " + $('#id_content-media_input_type').val());
return true;
}
});
- $("#upload_progress_bar").css({ width:"90%", height:"10" });
-
$('#media_fields_div').height(80);
-
- // We init the swfupload object
- swfupload = new SWFUpload({
- debug: false,
-
- upload_url: url_upload,
- flash_url: media_prefix+"swf/swfupload.swf",
-
- post_params: post_added_params,
-
- button_placeholder_id: "upload_btn",
- button_width: "60",
- button_height: "16",
- button_cursor: SWFUpload.CURSOR.HAND,
- button_text : '<span class="btnText">' + btn_label + '</span>',
- button_text_style : ".btnText { font-size: 12; font-family: Arial; }",
-
- file_types : "*.flv;*.f4v;*.mp4;*.mov;*.mp3",
- file_types_description : "Media Files (flv, f4v, mov H264, mp4, mp3)",
- file_upload_limit : "1",
- file_queue_limit : "1",
-
- upload_error_handler : uploadError,
- upload_start_handler : function(file) {
- try {
- if($('#upload_progress_info').children().size()>0){
- $('#progress_info').remove();
- }
- $('#upload_progress_info').append('<p id="progress_info"><a href="javascript:cancelSwfUpload()">' + cancel_label + '.</a></p>');
- }
- catch (ex) {
- //this.debug(ex);
- }
- },
- upload_progress_handler : uploadProgress,
- upload_success_handler : function() {
- try {
- if($('#upload_progress_info').children().size()>0){
- $('#progress_info').remove();
- }
- $('#upload_progress_info').append('<p id="progress_info">' + success_label + '.</p>');
- $("#upload_progress_bar > div").css({ 'background': '#90ffa8' });
- window.upload_from_local_done = true;
- // Now that the file is uploaded, we submit the form if asked
- if(window.submit_asked==true){
- $('#my_form').submit();
- }
- else{
- // We ask the uploaded media's duration
- if(window.ask_duration_url){
- $.ajax({
- type: "GET",
- url: window.ask_duration_url,
- data: "filename="+ $('#id_media-local_file_name').val(),
- cache: false,
- success: function(data, status, request){
- if(data && data!=""){
- $('#id_content-duration').val(data);
- }
- }
- });
- }
- }
- }
- catch (ex) {
- //this.debug(ex);
- }
- },
- file_queued_handler : displayUploadPath,
- file_dialog_complete_handler: function() {
- window.submit_asked = false;
- this.startUpload();
- }
- //upload_complete_handler: function() { this.startUpload(); },
- });
}
+
function displayUploadPath(file) {
try {
$('#id_media-local_file_name').val(file.name);
@@ -544,62 +450,6 @@
//this.debug(ex);
}
}
-function startLocalUpload(){
- swfupload.startUpload();
-}
-function uploadProgress(file, bytesLoaded, bytesTotal) {
- try {
- var percent = Math.ceil((bytesLoaded / bytesTotal) * 100);
- $("#upload_progress_bar").progressbar({ value: percent });
- }
- catch (ex) {
- //this.debug(ex);
- }
-}
-function cancelSwfUpload(){
- swfupload.cancelUpload();
- if($('#media_field_upload').has($('#cancelupload')).length==0){
- $('#cancelupload').remove();
- }
-}
-function uploadError(file, errorCode, message) {
- try {
- if($('#upload_progress_info').children().size()>0){
- $('#progress_info').remove();
- }
- switch (errorCode) {
- case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: HTTP Error, File name: " + file.name + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: Upload Failed, File name: " + file.name + ", File size: " + file.size + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.IO_ERROR:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: IO Error, File name: " + file.name + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: Security Error, File name: " + file.name + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: Upload Limit Exceeded, File name: " + file.name + ", File size: " + file.size + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: File Validation Failed, File name: " + file.name + ", File size: " + file.size + ", Message: " + message + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
- $('#upload_progress_info').append('<p id="progress_info">' + "Error Code: FILE_CANCELLED" + '</p>');
- break;
- case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
- $('#upload_progress_info').append('<p id="progress_info">' + "STOPPED" + '</p>');
- break;
- default:
- $('#upload_progress_info').append('<p id="progress_info">' + "unhandled error: File name: " + file.name + ", File size: " + file.size + ", Message: " + message + '</p>');
- break;
- }
- } catch (ex) {
- //this.debug(ex);
- }
-}
// Test the value of the URL from the form to load a picture in case it is a youtube video
function testUrlValue(e){
@@ -704,3 +554,4 @@
$(checkbox_names).trigger("change");
});
}
+