Ticket #4165: 5343_javascript_and_admin.diff

File 5343_javascript_and_admin.diff, 15.9 KB (added by Michael Axiak <axiak@…>, 17 years ago)

New batch of JavaScript and Admin interaction

  • django/contrib/admin/media/js/UploadProgress.js

     
     1
     2var upload_progress_failures = 0;
     3var TOTAL_UPLOAD_PROGRESS_FAILURES = 10;
     4var upload_progress_num__IE = 0;
     5var show_progress = false;
     6/* below is the url from admin to the upload progress.
     7   e.g. upload_progress/
     8*/
     9var progress_url  = "upload_progress/";
     10
     11var split_path = location.pathname.split('/');
     12
     13var new_array = new Array();
     14
     15var j=0;
     16for (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
     23admin_root = '/';
     24if (new_array.length > 3) {
     25    for (var i=0; i<new_array.length-3; i++) {
     26        admin_root += new_array[i]+'/';
     27    }
     28}
     29
     30progress_url = admin_root + progress_url;
     31
     32function 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
     54function 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
     67var humanvalue = ['B','KB','MB','GB']
     68function 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
     81interval = null;
     82function 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
     147function 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
     156function 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
     166function 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
     197addEvent(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/urls.py

     
    1010    ('^$', 'django.contrib.admin.views.main.index'),
    1111    ('^r/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
    1212    ('^jsi18n/$', i18n_view, {'packages': 'django.conf'}),
     13    ('^upload_progress/$', 'django.contrib.admin.views.main.upload_progress'),
    1314    ('^logout/$', 'django.contrib.auth.views.logout'),
    1415    ('^password_change/$', 'django.contrib.auth.views.password_change'),
    1516    ('^password_change/done/$', 'django.contrib.auth.views.password_change_done'),
  • django/contrib/admin/views/main.py

     
    99from django.shortcuts import get_object_or_404, render_to_response
    1010from django.db import models
    1111from django.db.models.query import handle_legacy_orderlist, QuerySet
    12 from django.http import Http404, HttpResponse, HttpResponseRedirect
     12from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError
    1313from django.utils.html import escape
    1414from django.utils.text import capfirst, get_text_list
    1515import operator
     
    8181def get_javascript_imports(opts, auto_populated_fields, field_sets):
    8282# Put in any necessary JavaScript imports.
    8383    js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
     84    if opts.has_field_type(models.FileField) and settings.FILE_UPLOAD_DIR:
     85        js.append('js/UploadProgress.js')
    8486    if auto_populated_fields:
    8587        js.append('js/urlify.js')
    8688    if opts.has_field_type(models.DateTimeField) or opts.has_field_type(models.TimeField) or opts.has_field_type(models.DateField):
     
    777779                               'admin/%s/change_list.html' % app_label,
    778780                               'admin/change_list.html'], context_instance=c)
    779781change_list = staff_member_required(never_cache(change_list))
     782
     783def upload_progress(request):
     784    """
     785    Given this request, returns a JSON
     786    object that has information on a file upload progress.
     787    If there is no file upload in progress, returns an
     788    empty dictionary, '{}'.
     789    """
     790    from django.utils import simplejson
     791
     792    content = simplejson.dumps(request.file_progress)
     793
     794    if content.strip() == '{}':
     795        return HttpResponseServerError('')
     796    else:
     797        return HttpResponse(content=content, mimetype='text/plain')
  • django/contrib/admin/templates/admin/change_form.html

     
    6565   {% auto_populated_field_script auto_populated_fields change %}
    6666   </script>
    6767{% endif %}
     68
     69{% if has_file_field %}
     70<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;">
     71   <a href="#" onclick="close_progress();return false" title="Close Progress Bar"
     72      style="color: #c00; font-size: 1.5em; font-weight: bold; float: right; padding: 0; position: relative; top: -2px; left: -2px;">X</a>
     73   <h1>Upload progress</h1>
     74
     75   <div id="progress_bar" style="top: 0; left: 0; width: 0; z-index: 9049; height: 4px;" class="submit-row"></div>
     76   <div id="progress_text" style="color: black;">0%</div>
    6877</div>
     78{% endif %}
     79
     80</div>
    6981</form></div>
    7082{% endblock %}
  • django/contrib/uploadprogress/models.py

     
     1"""
     2Models file for a simple file upload progress application.
     3This cause the file progress to be stored in the database.
     4To activate:
     51) Add 'django.contrib.uploadprogress.middleware.FileProgressDB'
     6   to your MIDDLEWARE_CLASSES setting.
     72) Add 'django.contrib.uploadprogress' to your INSTALLED_APPS.
     8
     9"""
     10
     11from django.db import models
     12import datetime
     13
     14try:
     15    import cPickle as pickle
     16except ImportError:
     17    import pickle
     18
     19class 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)
  • django/contrib/uploadprogress/middleware/uploadcache.py

     
     1"""
     2
     3Middleware to track file progress using the cache framework.
     4To use, just add
     5    'django.contrib.uploadprogress.middleware.FileProgressCached'
     6to your ``MIDDLEWARE_SETTINGS``.
     7
     8If your cache framework does not work, this will not work either.
     9
     10"""
     11from django.core.cache import cache
     12from django.conf import settings
     13from django.http.multipartparser import MultiPartParserError
     14
     15UPLOAD_CACHE_PREFIX = getattr(settings, 'UPLOAD_CACHE_PREFIX', 'UPLOAD_PROGRESS_')
     16
     17class 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
     55class FileProgressCached(object):
     56
     57    def process_request(self, request):
     58        # set the request.file_progress descriptor
     59        request.__class__.file_progress = FileProgressStore()
  • django/contrib/uploadprogress/middleware/uploaddb.py

     
     1"""
     2
     3Middleware to hold fileupload progress state in a database.
     4To install, simply add
     5    'django.contrib.uploadprogress.middleware.FileProgressDB'
     6   
     7to your ``MIDDLEWARE_SETTINGS`` and
     8    'django.contrib.uploadprogress'
     9to your ``INSTALLED_APPS``.
     10
     11Then run ``./manage.py syncdb`` as you normally would.
     12
     13"""
     14from django.contrib.uploadprogress.models import FileProgress
     15from django.http.multipartparser import MultiPartParserError
     16from django.conf import settings
     17
     18try:
     19    import cPickle as pickle
     20except ImportError:
     21    import pickle
     22
     23class 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
     44class FileProgressDB(object):
     45
     46    def process_request(self, request):
     47        request.__class__.file_progress = FileProgressDBStore()
  • django/contrib/uploadprogress/middleware/__init__.py

     
     1from django.contrib.uploadprogress.middleware.uploaddb import FileProgressDB
     2from django.contrib.uploadprogress.middleware.uploadcache import FileProgressCached
     3
Back to Top