Ticket #4165: 6602_javascript_and_admin.diff
File 6602_javascript_and_admin.diff, 16.0 KB (added by , 17 years ago) |
---|
-
new file django/contrib/admin/media/js/UploadProgress.js
diff -r 8c85b71cb6b6 django/contrib/admin/media/js/UploadProgress.js
- + 1 2 var upload_progress_failures = 0; 3 var TOTAL_UPLOAD_PROGRESS_FAILURES = 10; 4 var upload_progress_num__IE = 0; 5 var show_progress = false; 6 /* below is the url from admin to the upload progress. 7 e.g. upload_progress/ 8 */ 9 var progress_url = "upload_progress/"; 10 11 var split_path = location.pathname.split('/'); 12 13 var new_array = new Array(); 14 15 var j=0; 16 for (var i=0; i<split_path.length; i++) { 17 if (split_path[i] != '') { 18 new_array[j] = split_path[i]; 19 j++; 20 } 21 } 22 23 admin_root = '/'; 24 if (new_array.length > 3) { 25 for (var i=0; i<new_array.length-3; i++) { 26 admin_root += new_array[i]+'/'; 27 } 28 } 29 30 progress_url = admin_root + progress_url; 31 32 function getxy(){ 33 var x,y; 34 if (self.innerHeight) // all except Explorer 35 { 36 x = self.innerWidth; 37 y = self.innerHeight; 38 } 39 else if (document.documentElement && document.documentElement.clientHeight) 40 // Explorer 6 Strict Mode 41 { 42 x = document.documentElement.clientWidth; 43 y = document.documentElement.clientHeight; 44 } 45 else if (document.body) // other Explorers 46 { 47 x = document.body.clientWidth; 48 y = document.body.clientHeight; 49 } 50 return {'x':x,'y':y} 51 } 52 53 54 function upload_ajax_problem() { 55 /* If there's a problem, will cancel after 56 TOTAL_UPLOAD_PROGRESS_FAILURES tries. */ 57 58 var progress_wrap2 = document.getElementById('progress_wrap'); 59 upload_progress_failures++; 60 if (upload_progress_failures >= TOTAL_UPLOAD_PROGRESS_FAILURES){ 61 window.clearTimeout(interval); 62 } 63 progress_wrap2.style.display = 'none'; 64 progress_wrap2.style.visibility = 'hidden'; 65 } 66 67 var humanvalue = ['B','KB','MB','GB'] 68 function humanize(bytes) { 69 curbytes = bytes; 70 iterations = 0; 71 if (!curbytes) { 72 return ''; 73 } 74 while (curbytes>1024) { 75 iterations++; 76 curbytes=curbytes/1024; 77 } 78 return curbytes.toFixed(1) + ' ' + humanvalue[iterations]; 79 } 80 81 interval = null; 82 function fetch(uuid) { 83 /* no ajax here */ 84 if (!xmlhttp) { 85 upload_ajax_problem(); 86 return; 87 } 88 89 req = xmlhttp; 90 req.open("GET", progress_url+"?" + upload_progress_num__IE, true); 91 upload_progress_num__IE++; // IE Hack 92 req.onreadystatechange = function () { 93 var progress_wrap2 = document.getElementById('progress_wrap'); 94 var progress_bar2 = document.getElementById('progress_bar'); 95 var bar_txt = document.getElementById('progress_text'); 96 97 if (req.readyState == 4) { 98 try { 99 request_status = req.status; 100 } catch (e) { 101 /* Really bad. */ 102 request_status = -1; 103 } 104 if (request_status == 200) { 105 var upload = new Function(" return "+req.responseText)(); 106 if (upload) { 107 108 if (!upload.state) { 109 progress_wrap2.style.visibility = 'hidden'; 110 progress_wrap2.style.display = 'none'; 111 return; 112 } else if (upload.state == 'done') { 113 window.clearTimeout(interval); 114 progress_wrap2.style.visibility = 'hidden'; 115 progress_wrap2.style.display = 'none'; 116 return; 117 } else { 118 if (show_progress) { 119 progress_wrap2.style.visibility = 'visible'; 120 progress_wrap2.style.display = 'block'; 121 } 122 move_to_center(progress_wrap2); 123 bar_txt.innerHTML = ((upload.received / upload.size) * 100).toFixed(1) 124 + '% - ' + humanize(upload.received) + ' of ' 125 + humanize(upload.size); 126 var bar_width__px = 400 * upload.received / upload.size; 127 progress_bar2.style.width = bar_width__px + 'px'; 128 } 129 } else { 130 upload_ajax_problem(); 131 } 132 } else { 133 upload_ajax_problem(); 134 } 135 } 136 }; 137 try { 138 req.setRequestHeader("X-Upload-Id", uuid); 139 } catch (e) { 140 /* couldn't set the header, the request is broken. */ 141 req.abort(); 142 } 143 req.send(null); 144 145 } 146 147 function move_to_center(progress_wrap) { 148 pos = getxy(); 149 posx = parseInt((pos.x/2)-(420/2), 10); 150 posy = parseInt((pos.y/2)-(50/2), 10); 151 152 progress_wrap.style.top = posy + 'px'; 153 progress_wrap.style.left = posx + 'px'; 154 } 155 156 function close_progress() { 157 var progress_wrap2 = document.getElementById('progress_wrap'); 158 progress_wrap2.style.display = 'none'; 159 progress_wrap2.style.visibility = 'hidden'; 160 show_progress = false; 161 // don't want to follow a link. 162 return false; 163 } 164 165 166 function openprogress(e) { 167 168 show_progress = true; 169 upload_progress_failures = 0; 170 uuid = ""; 171 for (i = 0; i < 32; i++) { 172 uuid += Math.floor(Math.random() * 16).toString(16); 173 } 174 frm = e.target||e.srcElement; 175 176 /* 177 var progress_wrap2 = document.getElementById('progress_wrap'); 178 move_to_center(progress_wrap2); 179 progress_wrap2.style.display = 'block'; 180 progress_wrap2.style.visibility = 'visible'; 181 */ 182 183 if (frm.action.indexOf('?') == -1) { 184 frm.action=frm.action+"?progress_id=" + uuid 185 } else { 186 frm.action=frm.action+"&progress_id=" + uuid; 187 } 188 189 interval = window.setInterval( 190 function () { 191 fetch(uuid); 192 }, 193 1000 194 ); 195 } 196 197 addEvent(window, 'load', function() { 198 frms = document.getElementsByTagName('form'); 199 for (var i=0; i<frms.length; i++) { 200 if (frms[i].encoding.toLowerCase() == 'multipart/form-data') { 201 addEvent(frms[i], 'submit', openprogress); 202 return; 203 } 204 } 205 }); -
django/contrib/admin/templates/admin/change_form.html
diff -r 8c85b71cb6b6 django/contrib/admin/templates/admin/change_form.html
a b 64 64 {% auto_populated_field_script auto_populated_fields change %} 65 65 </script> 66 66 {% endif %} 67 68 {% if has_file_field %} 69 <div id="progress_wrap" style="position: absolute; background: white; z-index: 9040; display: none; visibility: hidden; width: 420px; height: 50px padding: 10px; border: solid 1px #ddd;"> 70 <a href="#" onclick="close_progress();return false" title="Close Progress Bar" 71 style="color: #c00; font-size: 1.5em; font-weight: bold; float: right; padding: 0; position: relative; top: -2px; left: -2px;">X</a> 72 <h1>Upload progress</h1> 73 74 <div id="progress_bar" style="top: 0; left: 0; width: 0; z-index: 9049; height: 4px;" class="submit-row"></div> 75 <div id="progress_text" style="color: black;">0%</div> 76 </div> 77 {% endif %} 78 67 79 </div> 68 80 </form></div> 69 81 {% endblock %} -
django/contrib/admin/urls.py
diff -r 8c85b71cb6b6 django/contrib/admin/urls.py
a b urlpatterns = patterns('', 10 10 ('^$', 'django.contrib.admin.views.main.index'), 11 11 ('^r/(\d+)/(.*)/$', 'django.views.defaults.shortcut'), 12 12 ('^jsi18n/$', i18n_view, {'packages': 'django.conf'}), 13 ('^upload_progress/$', 'django.contrib.admin.views.main.upload_progress'), 13 14 ('^logout/$', 'django.contrib.auth.views.logout'), 14 15 ('^password_change/$', 'django.contrib.auth.views.password_change'), 15 16 ('^password_change/done/$', 'django.contrib.auth.views.password_change_done'), -
django/contrib/admin/views/main.py
diff -r 8c85b71cb6b6 django/contrib/admin/views/main.py
a b from django.shortcuts import get_object_ 9 9 from django.shortcuts import get_object_or_404, render_to_response 10 10 from django.db import models 11 11 from django.db.models.query import handle_legacy_orderlist, QuerySet 12 from django.http import Http404, HttpResponse, HttpResponseRedirect 12 from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError 13 13 from django.utils.html import escape 14 14 from django.utils.text import capfirst, get_text_list 15 15 from django.utils.encoding import force_unicode, smart_str … … def get_javascript_imports(opts, auto_po 88 88 def get_javascript_imports(opts, auto_populated_fields, field_sets): 89 89 # Put in any necessary JavaScript imports. 90 90 js = ['js/core.js', 'js/admin/RelatedObjectLookups.js'] 91 if opts.has_field_type(models.FileField) and settings.FILE_UPLOAD_DIR: 92 js.append('js/UploadProgress.js') 91 93 if auto_populated_fields: 92 94 js.append('js/urlify.js') 93 95 if opts.has_field_type(models.DateTimeField) or opts.has_field_type(models.TimeField) or opts.has_field_type(models.DateField): … … def change_list(request, app_label, mode 789 791 'admin/%s/change_list.html' % app_label, 790 792 'admin/change_list.html'], context_instance=c) 791 793 change_list = staff_member_required(never_cache(change_list)) 794 795 def upload_progress(request): 796 """ 797 Given this request, returns a JSON 798 object that has information on a file upload progress. 799 If there is no file upload in progress, returns an 800 empty dictionary, '{}'. 801 """ 802 from django.utils import simplejson 803 804 content = simplejson.dumps(request.file_progress) 805 806 if content.strip() == '{}': 807 return HttpResponseServerError('') 808 else: 809 return HttpResponse(content=content, mimetype='text/plain') -
new file django/contrib/uploadprogress/__init__.py
diff -r 8c85b71cb6b6 django/contrib/uploadprogress/__init__.py
- + 1 -
new file django/contrib/uploadprogress/middleware/__init__.py
diff -r 8c85b71cb6b6 django/contrib/uploadprogress/middleware/__init__.py
- + 1 from django.contrib.uploadprogress.middleware.uploaddb import FileProgressDB 2 from django.contrib.uploadprogress.middleware.uploadcache import FileProgressCached 3 -
new file django/contrib/uploadprogress/middleware/uploadcache.py
diff -r 8c85b71cb6b6 django/contrib/uploadprogress/middleware/uploadcache.py
- + 1 """ 2 3 Middleware to track file progress using the cache framework. 4 To use, just add 5 'django.contrib.uploadprogress.middleware.FileProgressCached' 6 to your ``MIDDLEWARE_SETTINGS``. 7 8 If your cache framework does not work, this will not work either. 9 10 """ 11 from django.core.cache import cache 12 from django.conf import settings 13 from django.http.multipartparser import MultiPartParserError 14 15 UPLOAD_CACHE_PREFIX = getattr(settings, 'UPLOAD_CACHE_PREFIX', 'UPLOAD_PROGRESS_') 16 17 class FileProgressStore(object): 18 19 def _get_key(self, request): 20 """ 21 Returns the cache prefix for any cache key. 22 Uses the IP Address as well as the randomly generated uuid. 23 """ 24 25 if hasattr(self, '_cache_key'): 26 return self._cache_key 27 28 self._cache_key = '%s__%s__%s' % \ 29 (UPLOAD_CACHE_PREFIX, 30 request.META['REMOTE_ADDR'], 31 request.META['UPLOAD_PROGRESS_ID'],) 32 33 return self._cache_key 34 35 def __get__(self, request, HttpRequest): 36 return cache.get(self._get_key(request), {}) 37 38 def __set__(self, request, new_val): 39 received_size = total_size = -1 40 try: 41 total_size = int(new_val['size']) 42 except: 43 pass 44 45 try: 46 received_size = int(new_val['received']) 47 except: 48 pass 49 50 cache.set(self._get_key(request), new_val) 51 52 def __delete__(self, request): 53 cache.delete(self._get_key(request)) 54 55 class FileProgressCached(object): 56 57 def process_request(self, request): 58 # set the request.file_progress descriptor 59 request.__class__.file_progress = FileProgressStore() -
new file django/contrib/uploadprogress/middleware/uploaddb.py
diff -r 8c85b71cb6b6 django/contrib/uploadprogress/middleware/uploaddb.py
- + 1 """ 2 3 Middleware to hold fileupload progress state in a database. 4 To install, simply add 5 'django.contrib.uploadprogress.middleware.FileProgressDB' 6 7 to your ``MIDDLEWARE_SETTINGS`` and 8 'django.contrib.uploadprogress' 9 to your ``INSTALLED_APPS``. 10 11 Then run ``./manage.py syncdb`` as you normally would. 12 13 """ 14 from django.contrib.uploadprogress.models import FileProgress 15 from django.http.multipartparser import MultiPartParserError 16 from django.conf import settings 17 18 try: 19 import cPickle as pickle 20 except ImportError: 21 import pickle 22 23 class FileProgressDBStore(object): 24 25 def _get_db_row(self, request): 26 if not hasattr(self, '_db_row'): 27 self._db_row, created = FileProgress.objects.get_or_create( 28 remote_addr = request.META['REMOTE_ADDR'], 29 progress_id = request.META['UPLOAD_PROGRESS_ID']) 30 31 return self._db_row 32 33 def __get__(self, request, HttpRequest): 34 return self._get_db_row(request).progress 35 36 def __set__(self, request, new_val): 37 row = self._get_db_row(request) 38 row.progress = new_val 39 row.save() 40 41 def __delete__(self, request): 42 self._get_db_row(request).delete() 43 44 class FileProgressDB(object): 45 46 def process_request(self, request): 47 request.__class__.file_progress = FileProgressDBStore() -
new file django/contrib/uploadprogress/models.py
diff -r 8c85b71cb6b6 django/contrib/uploadprogress/models.py
- + 1 """ 2 Models file for a simple file upload progress application. 3 This cause the file progress to be stored in the database. 4 To activate: 5 1) Add 'django.contrib.uploadprogress.middleware.FileProgressDB' 6 to your MIDDLEWARE_CLASSES setting. 7 2) Add 'django.contrib.uploadprogress' to your INSTALLED_APPS. 8 9 """ 10 11 from django.db import models 12 import datetime 13 14 try: 15 import cPickle as pickle 16 except ImportError: 17 import pickle 18 19 class FileProgress(models.Model): 20 21 remote_addr = models.CharField(maxlength=64) 22 progress_id = models.CharField(maxlength=32) 23 progress_text = models.TextField(editable = False) 24 last_ts = models.DateTimeField() 25 26 class Meta: 27 verbose_name_plural = 'File Progresses' 28 unique_together = (('remote_addr', 29 'progress_id', 30 ), 31 ) 32 33 class Admin: 34 pass 35 36 def __str__(self): 37 return 'File Progress for "%s" and IP "%s".' % (self.progress_id, self.remote_addr) 38 39 def _get_dict(self): 40 """ 41 Returns a dictionary object. 42 """ 43 if hasattr(self, '_progress_dict'): 44 return self._progress_dict 45 46 if not self.progress_text: 47 self._progress_dict = {} 48 return {} 49 50 try: 51 self._progress_dict = pickle.loads(self.progress_text) 52 except: 53 self._progress_dict = {} 54 55 return self._progress_dict 56 57 def _set_dict(self, dict): 58 """ 59 Sets a dictionary object. 60 """ 61 self._progress_dict = dict 62 63 progress = property(_get_dict, _set_dict) 64 65 def save(self, *args, **kwargs): 66 """ 67 Pickles the dictionary representation 68 of the progress. 69 """ 70 try: 71 self.progress_text = pickle.dumps(self.progress) 72 except: 73 pass 74 75 self.last_ts = datetime.datetime.now() 76 77 return super(FileProgress, self).save(*args, **kwargs)