changeset 45:683a99c35a12

Refactor objects listing and implement objects table sorting.
author Daniele Nicolodi <daniele@grinta.net>
date Tue, 26 Jul 2011 00:29:55 +0200
parents b9c38c1704bd
children b3570e2e25a5
files src/ltpdarepo/__init__.py src/ltpdarepo/static/style.css src/ltpdarepo/templates/browse.html src/ltpdarepo/templates/objs.html src/ltpdarepo/templates/query.html src/ltpdarepo/views/browse.py
diffstat 6 files changed, 100 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/src/ltpdarepo/__init__.py	Tue Jul 26 00:26:49 2011 +0200
+++ b/src/ltpdarepo/__init__.py	Tue Jul 26 00:29:55 2011 +0200
@@ -74,6 +74,18 @@
 app.jinja_env.globals['url_for_other_page'] = url_for_other_page
 
 
+def url_for_other_order(field):
+    current = request.args.get('o', 'id')
+    reverse = int(request.args.get('r', 0))
+    if current == field:
+        reverse = int(not reverse)
+    args = request.view_args.copy()
+    args.update(request.args)
+    args.update(o=field, r=int(reverse))
+    return url_for(request.endpoint, **args)
+app.jinja_env.globals['url_for_other_order'] = url_for_other_order
+
+
 @app.route('/login', methods=['GET', 'POST'])
 def login():
     if request.method == 'POST':
--- a/src/ltpdarepo/static/style.css	Tue Jul 26 00:26:49 2011 +0200
+++ b/src/ltpdarepo/static/style.css	Tue Jul 26 00:29:55 2011 +0200
@@ -10,6 +10,10 @@
     display: none;
 }
 
+.small {
+    font-size: 90%;
+}
+
 div.left {
     float: left;
 }
@@ -272,7 +276,7 @@
 }
 
 td.id, td.name {
-    font-family: monospace;
+    font-family: andale mono, monospace;
 }
 
 td.name, td.title, td.description {
--- a/src/ltpdarepo/templates/browse.html	Tue Jul 26 00:26:49 2011 +0200
+++ b/src/ltpdarepo/templates/browse.html	Tue Jul 26 00:29:55 2011 +0200
@@ -1,52 +1,1 @@
-{% extends "layout.html" %}
-{% block title %}{{ database.id }}{% endblock %}
-{# block head %}
-    <script type="text/javascript" src="/static/jquery-1.6.1.min.js"></script>
-    <script type="text/javascript">
-      $("document").ready(function() {
-        $("tr.data").click(function() {
-          var id = $(this).attr("id");
-          $("tr.details:visible").hide()
-          $("tr.details:hidden").filter(function() { return $(this).attr("id") == id; }).show();
-        });
-      });
-    </script>
-{% endblock #}
-{% block body %}
-<h2>Database &#x00AB;{{ database.id }}&#x00BB;</h2>
-<p class="discrete">{{ database.description }}</p>
-{% if not objs %}
-<p class="important">&mdash;</p>
-{% else %}
-<p class="discrete">{{ batch.count }} objects</p>
-<table class="listing">
-  <thead>
-    <tr>
-      {% for field in fields %}
-      <th>{{ field }}</th>
-      {% endfor %}
-    </tr>
-  </thead>
-  <tbody>
-    {% for obj in objs %}
-    <tr class="data {{ loop.cycle('odd', 'even') }}" id="{{ loop.index }}">
-      {% for field in fields %}
-      {% if field == 'name' %}
-      <td class="{{ field }}"><a href="{{ url_for('browse.obj', database=database.id, objid=obj.id) }}">{{ obj[field] }}</a></td>
-      {% else %}
-      <td class="{{ field }}">{{ obj[field]|string|truncate(60, False, '…') }}</td>
-      {% endif %}
-      {% endfor %}
-    </tr>
-    <tr class="details" id="{{ loop.index }}">
-      <td colspan="{{ fields|length }}" style="text-align: left;">details</td>
-    </tr>
-    {% endfor %}
-  </tbody>
-</table>
-{% import "pagination.html" as pagination %}
-{% if pagination is defined %}
-{{ pagination.render(batch) }}
-{% endif %}
-{% endif %}
-{% endblock %}
+{% extends "objs.html" %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ltpdarepo/templates/objs.html	Tue Jul 26 00:29:55 2011 +0200
@@ -0,0 +1,53 @@
+{% import "pagination.html" as pagination %}
+{% extends "layout.html" %}
+{% block title %}{{ database.id }}{% endblock %}
+{% block body %}
+<h2>Database &#x00AB;{{ database.id }}&#x00BB;</h2>
+<p class="discrete small">{{ database.description|default('&nbsp;'|safe, true) }}</p>
+
+{% block above %}{% endblock %}
+
+<p class="discrete small">{{ batch.count }} objects</p>
+{% if pagination is defined %}
+  {{ pagination.render(batch) }}
+{% endif %}
+<table class="listing">
+  <thead>
+    <tr>
+      {% for field in fields %}
+      <th>
+        <a href="{{ url_for_other_order(field) }}">
+          {% if field == request.args.get('o', 'id') %}
+            <b>{{ field }}</b>
+          {% else %}
+            {{ field }}
+          {% endif %}
+        </a>
+      </th>
+      {% endfor %}
+    </tr>
+  </thead>
+  <tbody>
+    {% for obj in objs %}
+    <tr class="data {{ loop.cycle('odd', 'even') }}" id="{{ loop.index }}">
+      {% for field in fields %}
+      {% if field == 'name' %}
+      <td class="{{ field }}"><a href="{{ url_for('browse.obj', database=database.id, objid=obj.id) }}">{{ obj[field] }}</a></td>
+      {% else %}
+      <td class="{{ field }}">{{ obj[field]|string|truncate(60, False, '…') }}</td>
+      {% endif %}
+      {% endfor %}
+    </tr>
+    <tr class="details" id="{{ loop.index }}">
+      <td colspan="{{ fields|length }}" style="text-align: left;">details</td>
+    </tr>
+    {% endfor %}
+  </tbody>
+</table>
+{% if pagination is defined %}
+  {{ pagination.render(batch) }}
+{% endif %}
+
+{% block below %}{% endblock %}
+
+{% endblock %}
--- a/src/ltpdarepo/templates/query.html	Tue Jul 26 00:26:49 2011 +0200
+++ b/src/ltpdarepo/templates/query.html	Tue Jul 26 00:29:55 2011 +0200
@@ -1,5 +1,5 @@
-{% extends "layout.html" %}
-{% block title %}{{ database.id }}{% endblock %}
+{% extends "objs.html" %}
+
 {% block head %}
     <script type="text/javascript" src="{{ url_for('.static', filename='jquery.js') }}"></script>
     <script type="text/javascript" src="{{ url_for('.static', filename='querywidget.js') }}"></script>
@@ -7,10 +7,9 @@
       var criteria = {{ criteria|tojson|safe }};
     </script>
 {% endblock %}
-{% block body %}
-<h2>Database &#x00AB;{{ database.id }}&#x00BB;</h2>
-<p class="discrete">{{ database.description|default('&mdash;'|safe, true) }}</p>
-<div class="query">
+
+{% block above %}
+<div class="query wrapper">
   <form method="GET" action="{{ url_for('browse.query', database=database.id) }}">
     <div id="criteria" class="wrapper">
       {% for field, op, value in query %}
@@ -54,43 +53,14 @@
     </div>
 
     <div>
-      <input type="submit" value="&raquo;" class="search"></input>
+      <input type="submit" value="search" class="search"></input>
     </div>
     {% if 'admin' in g.identity.roles %}
     <div id="save-search-criteria">
-      <input id="save" type="submit" name="save" value="save"></input>
+      <input id="save" type="submit" name="save" value="save query"></input>
     </div>
     {% endif %}
 
   </form>
 </div>
-
-{% if objs %}
-<p class="discrete">{{ batch.count }} objects</p>
-<table class="listing">
-  <thead>
-    <tr>
-      {% for field in fields %}
-      <th>{{ field }}</th>
-      {% endfor %}
-    </tr>
-  </thead>
-  <tbody>
-    {% for obj in objs %}
-    <tr class="data {{ loop.cycle('odd', 'even') }}" id="{{ loop.index }}">
-      {% for field in fields %}
-      {% if field == 'name' %}
-      <td class="{{ field }}"><a href="{{ url_for('browse.obj', database=database.id, objid=obj.id) }}">{{ obj[field] }}</a></td>
-      {% else %}
-      <td class="{{ field }}">{{ obj[field]|string|truncate(60, False, '…') }}</td>
-      {% endif %}
-      {% endfor %}
-    </tr>
-    <tr class="details" id="{{ loop.index }}">
-      <td colspan="{{ fields|length }}" style="text-align: left;">details</td>
-    </tr>
-    {% endfor %}
-  </tbody>
-</table>
-{% endif %}
 {% endblock %}
--- a/src/ltpdarepo/views/browse.py	Tue Jul 26 00:26:49 2011 +0200
+++ b/src/ltpdarepo/views/browse.py	Tue Jul 26 00:29:55 2011 +0200
@@ -36,7 +36,7 @@
 
 ALLFIELDS = FIELDS + EXTRA
 
-MAPPING = { 'id':                 'obj_id',
+RMAPPING = { 'id':                 'obj_id',
             'name':               'name',
             'type':               'obj_type',
             'quantity':           'quantity',
@@ -58,7 +58,7 @@
             # 'vdate':              '',
            }
 
-MAPPING = dict(((v, k) for k, v in MAPPING.iteritems()))
+MAPPING = dict(((v, k) for k, v in RMAPPING.iteritems()))
 
 
 def _current_page():
@@ -66,10 +66,19 @@
     return int(request.args.get('p', 1))
 
 
+def _current_ordering():
+    """return the current page in a paginated view"""
+    order = request.args.get('o', 'id')
+    order = RMAPPING[order]
+    reverse = int(request.args.get('r', 0))
+    return (order, reverse)
+
+
 class Objs(object):
     def __init__(self, database):
         self._database = database
         self._orderby = None
+        self._reverse = None
         self._limit = None
         self._where = None
         self._values = None
@@ -82,6 +91,8 @@
             query += " WHERE %s" % self._where
         if self._orderby:
             query += " ORDER BY `%s`" % self._orderby
+        if self._reverse:
+            query += " DESC"            
         if self._limit:
             query += " LIMIT %d,%d" % self._limit
         return query
@@ -103,7 +114,10 @@
         return self
 
     def orderby(self, order):
-        self._orderby = order
+        if isinstance(order, tuple):
+            self._orderby, self._reverse = order
+        else:
+            self._orderby = order
         return self
 
     def __getitem__(self, item):
@@ -157,8 +171,8 @@
             abort(404)
 
         count = Objs(database=database).count()
-        batch = Pagination(_current_page(), size=PAGESIZE, count=count)
-        objs  = Objs(database=database).orderby('obj_id')[batch.slice]
+        batch = Pagination(_current_page(), size=PAGESIZE, count=count)        
+        objs  = Objs(database=database).orderby(_current_ordering())[batch.slice]
 
         return render_template('browse.html', objs=objs,
                                fields=FIELDS, database=db, batch=batch)
@@ -263,7 +277,7 @@
         # query
         count = Objs(database=database).filter('name LIKE %s', q).count()
         batch = Pagination(_current_page(), size=PAGESIZE, count=count)
-        objs  = Objs(database=database).filter('name LIKE %s', q).orderby('obj_id')[batch.slice]
+        objs  = Objs(database=database).filter('name LIKE %s', q).orderby(_current_ordering())[batch.slice]
 
         return render_template('browse.html', objs=objs,
                                fields=FIELDS, database=db, batch=batch)
@@ -316,7 +330,7 @@
 
         if name is not None:
             curs = g.db.cursor()
-            curs.execute("""SELECT querystring FROM queries WHERE db=%s AND name=%s""",
+            curs.execute("SELECT querystring FROM queries WHERE db=%s AND name=%s",
                          (database, name))
             query = json.loads(curs.fetchone()[0])
             fields, ops, values = [], [], []
@@ -342,7 +356,7 @@
         # get objects
         count = Objs(database=database).filter(where, values).count()
         batch = Pagination(_current_page(), size=PAGESIZE, count=count)
-        objs  = Objs(database=database).filter(where, values).orderby('obj_id')[batch.slice]
+        objs  = Objs(database=database).filter(where, values).orderby(_current_ordering())[batch.slice]
 
         # collect search critaeria
         criteria = _indexes(database, 'objmeta')