1/* 2 * django-sticky-uploads widget 3 * Source: https://github.com/caktus/django-sticky-uploads 4 * Docs: http://django-sticky-uploads.readthedocs.org/ 5 * 6 * Depends: 7 * - jQuery 1.7+ 8 * 9 * Copyright 2013, Caktus Consulting Group, LLC 10 * BSD License 11 * 12*/ 13var djUp = djUp || jQuery; 14(function ($, window, document, undefined) { 15 "use strict"; 16 var pluginName = "djangoUploader", 17 defaults = { 18 url: "", 19 before: null, 20 success: null, 21 failure: null, 22 submit: null, 23 csrfCookieName: "csrftoken" 24 }; 25 26 function csrfSafeMethod(method) { 27 // these HTTP methods do not require CSRF protection 28 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 29 } 30 31 function getCookie(name) { 32 var cookieValue = null, 33 i = 0, cookies, cookie; 34 if (document.cookie && document.cookie !== "") { 35 cookies = document.cookie.split(";"); 36 for (i = 0; i < cookies.length; i++) { 37 cookie = $.trim(cookies[i]); 38 // Does this cookie string begin with the name we want? 39 if (cookie.substring(0, name.length + 1) === (name + "=")) { 40 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 41 break; 42 } 43 } 44 } 45 return cookieValue; 46 } 47 48 function DjangoUploader(element, options) { 49 this.element = element; 50 this.$element = $(element); 51 this.options = $.extend({}, defaults, options); 52 this._defaults = defaults; 53 this._name = pluginName; 54 this.init(); 55 } 56 57 DjangoUploader.prototype = { 58 59 init: function () { 60 this.processing = false; 61 this.options.url = this.$element.data("uploadUrl"); 62 this.$form = this.$element.closest("form"); 63 this.$hidden = this.$form.find("input[type=hidden][name=_" + this.$element.attr("name") + "]"); 64 if (this.enabled()) { 65 this.$element.on("change", $.proxy(this.change, this)); 66 this.$form.on("submit", $.proxy(this.submit, this)); 67 this.$progress = $("<span>").addClass("progress-label"); 68 this.$element.after(this.$progress); 69 } 70 }, 71 72 change: function (event) { 73 var formData = new FormData(), 74 file; 75 if (this.element.files.length === 0) { 76 return; 77 } 78 file = this.element.files[0]; 79 if (this.before(file) !== false) { 80 formData.append("upload", file); 81 this.abort(); 82 this.processing = $.ajax({ 83 url: this.options.url, 84 type: "POST", 85 data: formData, 86 crossDomain: false, 87 context: this, 88 beforeSend: this._add_csrf_header, 89 processData: false, 90 contentType: false, 91 xhr: this.xhr 92 }).done( 93 this.done 94 ).fail( 95 this.fail 96 ).always( 97 this.always 98 ); 99 } 100 }, 101 102 before: function (file) { 103 // Runs before the AJAX call. 104 // Returning false will abort the call. 105 var result = true; 106 if (this.options.before) { 107 result = this.options.before.apply(this, [file]); 108 } 109 return result; 110 }, 111 112 always: function (response) { 113 // Runs after the AJAX call regardless of success or failure. 114 this.processing = false; 115 }, 116 117 done: function (response) { 118 // Runs on a successful (200) response 119 if (response.is_valid && response.stored) { 120 this.$hidden.val(response.stored); 121 } else { 122 this.$hidden.val(""); 123 } 124 if (this.options.success) { 125 this.options.success.apply(this, [response]); 126 } 127 }, 128 129 fail: function (response) { 130 // Runs on a error (40X-50X) response 131 this.$hidden.val(""); 132 if (this.options.failure) { 133 this.options.failure.apply(this, [response]); 134 } 135 }, 136 137 submit: function (event) { 138 // Hijacked form submission 139 if (this.options.submit) { 140 this.options.submit.apply(this, [event]); 141 } else { 142 // Cancel current request and file will be submitted normally 143 this.abort(); 144 } 145 146 if (this.$hidden.val()) { 147 // Don't submit the file since its already on the server 148 this.$element.prop("disabled", true); 149 } 150 }, 151 152 abort: function () { 153 // Abort the current upload if any 154 if (this.processing) { 155 this.processing.abort(); 156 } 157 }, 158 159 enabled: function () { 160 // Checks for necessary browser support 161 var xhr2 = false, 162 fileApi = false, 163 xhr = new XMLHttpRequest(); 164 if (typeof xhr.upload !== "undefined") { 165 xhr2 = true; 166 } 167 if (window.FormData) { 168 fileApi = true; 169 } 170 return xhr2 && fileApi; 171 }, 172 173 174 _add_csrf_header: function (xhr, settings) { 175 var csrftoken = ""; 176 if (!csrfSafeMethod(settings.type)) { 177 csrftoken = getCookie(this.options.csrfCookieName); 178 xhr.setRequestHeader("X-CSRFToken", csrftoken); 179 } 180 }, 181 182 xhr: function(){ 183 //progress indicator for the uploading file 184 var xhr = new XMLHttpRequest(), 185 progressLabel = this.$progress; 186 xhr.upload.addEventListener("progress", function (file) { 187 if (file.lengthComputable) { 188 var percentLoaded = Math.round((file.loaded / file.total) * 100); 189 // Increase the progress progress label until 100% 190 progressLabel.text(percentLoaded + '%'); 191 } 192 }); 193 return xhr; 194 } 195 }; 196 197 $.fn[pluginName] = function (options) { 198 return this.each(function () { 199 if (!$.data(this, pluginName)) { 200 $.data(this, pluginName, new DjangoUploader(this, options)); 201 } 202 }); 203 }; 204 205 $(document).ready(function () { 206 // Auto-bind file inputs with data-upload-url attributes 207 $(":input[type=file][data-upload-url]").djangoUploader(); 208 }); 209 210})(djUp, window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.