first attempt at a single/multi-column toggle for folder contents #5

Merged
merged 4 commits into from Apr 30, 2012
View
63 substanced/folder/templates/contents.pt
@@ -40,24 +40,56 @@
-- all --
</label>
- <div id="choices">
-
- <tal:loop tal:repeat="choice batch.items">
- <tal:block condition="choice['viewable']">
- <label class="checkbox" for="delete-${repeat.choice.index}">
- <i class="${choice['icon']}"> </i>
- <input tal:attributes="disabled not choice['deletable']"
- type="checkbox"
- name="delete"
- value="${choice['name']}"
- id="delete-${repeat.choice.index}"/>
- <a href="${choice['url']}">${choice['name']}</a>
- </label>
- </tal:block>
- </tal:loop>
+ <div id="choices" class="row" tal:condition="not batch.multicolumn">
+
+ <div class="span3">
+ <tal:loop tal:repeat="choice batch.items">
+ <tal:block condition="choice['viewable']">
+ <label class="checkbox" for="delete-${repeat.choice.index}">
+ <i class="${choice['icon']}"> </i>
+ <input tal:attributes="disabled not choice['deletable']"
+ type="checkbox"
+ name="delete"
+ value="${choice['name']}"
+ id="delete-${repeat.choice.index}"/>
+ <a href="${choice['url']}">${choice['name']}</a>
+ </label>
+ </tal:block>
+ </tal:loop>
+ </div>
</div>
+ <div id="choices" tal:condition="batch.multicolumn">
+
+ <div class="row-fluid" tal:define="position 0">
+ <tal:loop tal:repeat="column batch.make_columns()">
+ <div class="span3">
+ <tal:loop tal:repeat="choice column">
+ <tal:block condition="choice['viewable']">
+ <label class="checkbox" for="delete-${position}">
+ <i class="${choice['icon']}"> </i>
+ <input tal:attributes="disabled not choice['deletable']"
+ type="checkbox"
+ name="delete"
+ value="${choice['name']}"
+ id="delete-${position}"/>
+ <a href="${choice['url']}">${choice['name']}</a>
+ </label>
+ </tal:block>
+ <?python position += 1 ?>
+ </tal:loop>
+ </div>
+ </tal:loop>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="row-fluid" tal:condition="batch.required">
+ <div class="span2">
+ <a class="btn" href="${batch.toggle_url}">${batch.toggle_text}</a>
+ </div>
</div>
<input type="hidden" name="csrf_token"
@@ -85,7 +117,6 @@
</ul>
</div>
</div>
-
</fieldset>
</form>
View
56 substanced/util/__init__.py
@@ -142,10 +142,31 @@ class Batch(object):
``True`` if either ``next_url`` or ``prev_url`` are ``True`` (meaning
batching is required).
+ ``multicolumn``
+
+ ``True`` if the current view should be rendered in multiple columns.
+
+ ``toggle_url``
+
+ The URL to be used for the multicolumn/single column toggle button. The
+ ``batch_size``, ``batch_num``, and ``multicolumn`` parameters are
+ converted to their multicolumn or single column equivalents. If a user
+ is viewing items 40-80 in multiple columns, the toggle will switch to
+ items 40-50 in a single column. If a user is viewing items 50-60 in a
+ single column, the toggle will switch to items 40-80 in multiple columns.
+
+ ``toggle_text``
+
+ The text to display on the multi-column/single column toggle.
+
The ``seq`` passed must define ``__len__`` and ``__slice__`` methods.
+
+ ``make_columns``
+
+ A method to split ``items`` into a nested list representing columns.
"""
- def __init__(self, seq, request, url=None, default_size=15):
+ def __init__(self, seq, request, url=None, default_size=10, toggle_size=40):
if url is None:
url = request.url
@@ -163,6 +184,17 @@ def __init__(self, seq, request, url=None, default_size=15):
if size < 1:
size = default_size
+ multicolumn = request.params.get('multicolumn', '') == 'True'
+
+ # create multicolumn/single column toggle attributes
+ if multicolumn:
+ toggle_num = size * num / default_size
+ toggle_size = default_size
+ toggle_text = 'Single column'
+ else:
+ toggle_num = size * num / toggle_size
+ toggle_text = 'Multi-column'
+
start = num * size
end = start + size
items = seq[start:end]
@@ -173,6 +205,7 @@ def __init__(self, seq, request, url=None, default_size=15):
prev_url = None
next_url = None
last_url = None
+ toggle_url = None
if num:
first_url = merge_url_qs(url, batch_size=size, batch_num=0)
@@ -183,17 +216,38 @@ def __init__(self, seq, request, url=None, default_size=15):
if size and (num < last):
last_url = merge_url_qs(url, batch_size=size, batch_num=last)
+ if prev_url or next_url:
+ toggle_url = merge_url_qs(
+ url,
+ batch_size=toggle_size,
+ batch_num=toggle_num,
+ multicolumn=not multicolumn,
+ )
+
self.items = items
self.num = num
self.size = size
self.length = length
self.required = bool(prev_url or next_url)
+ self.multicolumn = multicolumn
+ self.toggle_url = toggle_url
+ self.toggle_text = toggle_text
self.first_url = first_url
self.prev_url = prev_url
self.next_url = next_url
self.last_url = last_url
self.last = last
+ def make_columns(self, column_size=10, num_columns=4):
+ """ Break ``self.items`` into a nested list representing columns."""
+ columns = []
+ for i in range(num_columns):
+ start = i * column_size
+ end = start + column_size
+ part = self.items[start:end]
+ columns.append(part)
+ return columns
+
def chunks(stream, chunk_size=10000):
""" Return a generator that will iterate over a stream (a filelike
object) ``chunk_size`` bytes at a time."""
View
22 substanced/util/tests.py
@@ -183,6 +183,28 @@ def test_it_size_zero(self):
self.assertEqual(inst.items, seq)
self.assertEqual(inst.size, 15)
+ def test_it_multicolumn_toggle_text(self):
+ seq = [1,2,3,4,5,6]
+ request = testing.DummyRequest()
+ request.params['multicolumn'] = 'True'
+ inst = self._makeOne(seq, request)
+ self.assertEqual(inst.toggle_text, 'Single column')
+
+ def test_it_not_multicolumn_toggle_text(self):
+ seq = [1,2,3,4,5,6]
+ request = testing.DummyRequest()
+ request.params['multicolumn'] = 'False'
+ inst = self._makeOne(seq, request)
+ self.assertEqual(inst.toggle_text, 'Multi-column')
+
+ def test_it_make_columns(self):
+ seq = [1,2,3,4,5,6]
+ request = testing.DummyRequest()
+ inst = self._makeOne(seq, request)
+ cols = inst.make_columns(column_size=2, num_columns=3)
+ expected = [ [1,2], [3,4], [5,6] ]
+ self.assertEqual(cols, expected)
+
class Test_merge_url_qs(unittest.TestCase):
def _callFUT(self, url, **kw):
from . import merge_url_qs