Changeset 204:d4db4a0781e0
- Timestamp:
- 09/26/09 19:05:55 (11 months ago)
- Author:
- rgrp
- Branch:
- default
- convert_revision:
- svn:0ead1229-0713-0410-96cd-f668dbfad531/trunk@293
- Message:
-
[all][m]: work on ticket:56 and ticket:59 to integrate new Resource object into WUI and move focus away from Material to Work.
- our_resource.py: new resource controller which handles all display of resources (i.e. texts ...)
- (need to call our_resource to avoid conflict with builtin resource)
- move material view action here (and simplify it to remove all multi stuff now in multi controller/templates)
- material view now redirects to relevant resource
- work/info.html: integrate resource links directly here
- format.py: deal with unicode input as well as utf8 lineno formatter (already done for plain text)
- shksprdata/templates/layout.html: fixes for navbar links (change already made in main layout.html!!)
- TODO: deal with multiview and resources
- Location:
- shakespeare
- Files:
-
Legend:
- Unmodified
- Added
- Removed
-
|
r187
|
r204
|
|
| 23 | 23 | maps.admin_map(map, controller='admin', url='/admin') |
| 24 | 24 | # now main shakespeare routes |
| | 25 | map.connect('pdf', 'pdf/*url') |
| 25 | 26 | map.connect('', controller='site', action='index') |
| 26 | 27 | map.connect('marginalia/*url', controller='site', action='marginalia') |
| | 28 | map.connect('resource/:action/:id', controller='our_resource') |
| 27 | 29 | map.connect('material/:action/:id', controller='text') |
| 28 | 30 | map.connect(':controller/:action/:id') |
-
|
r193
|
r204
|
|
| 1 | 1 | import logging |
| 2 | | |
| 3 | | import genshi |
| 4 | 2 | |
| 5 | 3 | from shakespeare.lib.base import * |
| … |
… |
|
| 31 | 29 | |
| 32 | 30 | def view(self, id=''): |
| 33 | | # first check ?name param then do name in url |
| 34 | | name = request.params.get('name', '') |
| 35 | | if not name: |
| 36 | | name = id |
| 37 | | if not name: |
| | 31 | name = id |
| | 32 | m = model.Material.by_name(name) |
| | 33 | if not m: |
| 38 | 34 | abort(404) |
| 39 | | format = request.params.get('format', 'plain') |
| 40 | | namelist = name.split() |
| 41 | | numtexts = len(namelist) |
| 42 | | textlist = [model.Material.by_name(tname) for tname in namelist] |
| 43 | | # special case (only return the first text) |
| 44 | | if format == 'raw': |
| 45 | | result = textlist[0].get_text().read() |
| 46 | | status = '200 OK' |
| 47 | | response.headers['Content-Type'] = 'text/plain' |
| 48 | | return result |
| 49 | | texthtml = {} |
| 50 | | for item in textlist: |
| 51 | | tfileobj = item.get_text() |
| 52 | | # hack for time being ... |
| 53 | | if item.resources and item.resources[0].format == 'mkd': |
| 54 | | ttext = h.markdown(tfileobj.read()) |
| 55 | | else: |
| 56 | | ttext = shakespeare.format.format_text(tfileobj, format) |
| 57 | | texthtml[item.name] = genshi.HTML(ttext) |
| 58 | | # would have assumed this would be 100.0/numtexts but for some reason |
| 59 | | # you need to allow more room (maybe because of the scrollbars?) |
| 60 | | # result is not consistent across browsers ... |
| 61 | | c.frame_width = 100.0/numtexts - 4.0 |
| 62 | | c.textlist = textlist |
| 63 | | c.texthtml = texthtml |
| 64 | | # set to not strip whitespace as o/w whitespace in pre tag gets removed |
| 65 | | return render('text/view.html', strip_whitespace=False) |
| | 35 | if m.resources: |
| | 36 | h.redirect_to(controller='resource', action='view', |
| | 37 | id=m.resources[0].id) |
| | 38 | else: |
| | 39 | return 'No resource to view for this material' |
| 66 | 40 | |
-
|
r167
|
r204
|
|
| 19 | 19 | name = id |
| 20 | 20 | c.work = model.Work.by_name(name) |
| 21 | | if c.work: |
| 22 | | return render('work/info.html') |
| 23 | | else: |
| | 21 | if not c.work: |
| 24 | 22 | abort(404) |
| | 23 | |
| | 24 | # TODO: stats link |
| | 25 | return render('work/info.html') |
| 25 | 26 | |
-
|
r197
|
r204
|
|
| 36 | 36 | def escape_chars(self, text): |
| 37 | 37 | return text.replace('&', '&').replace('<', '<') |
| | 38 | |
| 38 | 39 | |
| 39 | 40 | class TextFormatterPlain(TextFormatter): |
| … |
… |
|
| 54 | 55 | return out |
| 55 | 56 | |
| | 57 | |
| 56 | 58 | class TextFormatterLineno(TextFormatter): |
| 57 | 59 | """Format the text to have line numbers. |
| … |
… |
|
| 64 | 66 | for line in self.file.readlines(): |
| 65 | 67 | tlineno = unicode(count).ljust(4) # assume line no < 10000 |
| 66 | | tline = unicode(line, 'utf-8').rstrip() |
| | 68 | tline = line |
| | 69 | if not isinstance(tline, unicode): |
| | 70 | tline = unicode(tline, 'utf-8') |
| | 71 | tline = tline.rstrip() |
| 67 | 72 | tline = self.escape_chars(tline) |
| 68 | 73 | result += u'<pre id="%s">%s %s</pre>\n' % (count, tlineno, tline) |
-
|
r193
|
r204
|
|
| 11 | 11 | <ul> |
| 12 | 12 | <li><a href="${h.url_for(controller='text', action='view', |
| 13 | | id=c.material.name)}">View</a> |
| | 13 | id=c.material.name)}">Read Text</a> |
| 14 | 14 | </li> |
| 15 | 15 | <li> |
| 16 | 16 | <a href="${h.url_for(controller='stats', action='text', |
| 17 | 17 | id=c.material.name)}"> |
| 18 | | Statistics</a> |
| | 18 | View Statistics</a> |
| 19 | 19 | </li> |
| 20 | 20 | </ul> |
| … |
… |
|
| 22 | 22 | <h3>Metadata</h3> |
| 23 | 23 | <ul> |
| 24 | | <li py:for="attr in ['creator', 'name', 'notes']"> |
| 25 | | <strong>${attr.capitalize()}:</strong> |
| 26 | | ${getattr(c.material, attr)} |
| | 24 | <li py:for="attrn in ['creator', 'name', 'notes']"> |
| | 25 | <strong>${attrn.capitalize()}:</strong> |
| | 26 | ${getattr(c.material, attrn)} |
| 27 | 27 | </li> |
| 28 | 28 | </ul> |
-
|
r156
|
r204
|
|
| 5 | 5 | |
| 6 | 6 | <py:def function="page_title">View Texts</py:def> |
| 7 | | <head> |
| 8 | | <style type="text/css" py:def="page_specific_css"> |
| 9 | | body |
| 10 | | { |
| 11 | | margin: 0; |
| 12 | | padding: 0; |
| 13 | | } |
| 14 | | |
| 15 | | .sidebar |
| 16 | | { |
| 17 | | display: none; |
| 18 | | } |
| 19 | | |
| 20 | | #main |
| 21 | | { |
| 22 | | width: 98%; |
| 23 | | height: 100%; |
| 24 | | } |
| 25 | | |
| 26 | | div.frame |
| 27 | | { |
| 28 | | /* height: 90%; */ |
| 29 | | height: 500px; |
| 30 | | overflow: auto; |
| 31 | | float: left; |
| 32 | | padding: 1em; |
| 33 | | background-color: white; |
| 34 | | } |
| 35 | | |
| 36 | | div.singleview |
| 37 | | { |
| 38 | | padding: 2em; |
| 39 | | padding-left: 10%; |
| 40 | | padding-right: 10%; |
| 41 | | } |
| 42 | | |
| 43 | | /* ensure we take up the whole width */ |
| 44 | | div.multiview |
| 45 | | { |
| 46 | | width: 100%; |
| 47 | | height: 90%; |
| 48 | | } |
| 49 | | |
| 50 | | </style> |
| 51 | | </head> |
| 52 | 7 | |
| 53 | 8 | <div py:match="content"> |
| 54 | | <div py:if="len(c.textlist) == 1" class="singleview" xmlns:dc="http://purl.org/dc/elements/1.1/"> |
| 55 | | <h2 property="dc:title">${c.textlist[0].name}</h2> |
| 56 | | ${c.texthtml[c.textlist[0].name]} |
| 57 | | </div> |
| 58 | | <div class="multiview" py:if="len(c.textlist) > 1" > |
| 59 | | <div py:for="text in c.textlist" class="frame" |
| 60 | | style="width: ${c.frame_width}%;" xmlns:dc="http://purl.org/dc/elements/1.1/"> |
| 61 | | <h2 property="dc:title">${text.name}</h2> |
| 62 | | ${c.texthtml[text.name]} |
| 63 | | </div> |
| | 9 | <div xmlns:dc="http://purl.org/dc/elements/1.1/"> |
| | 10 | <h2 property="dc:title">${c.title}</h2> |
| | 11 | ${c.texthtml} |
| 64 | 12 | </div> |
| 65 | 13 | </div> |
-
|
r160
|
r204
|
|
| 17 | 17 | <ul> |
| 18 | 18 | <li py:for="material in c.work.materials"> |
| 19 | | <a href="${h.url_for(controller='text', action='info', |
| 20 | | id=material.name)}">${material.title}</a> |
| | 19 | <a href="${h.url_for(controller='text', action='info', |
| | 20 | id=material.name)}">${material.title}</a> |
| | 21 | <ul> |
| | 22 | <li py:for="res in material.resources"> |
| | 23 | <a href="${h.url_for(controller='our_resource', action='view', id=res.id)}">Text (${res.format})</a> |
| | 24 | </li> |
| | 25 | </ul> |
| 21 | 26 | </li> |
| 22 | 27 | </ul> |
-
|
r197
|
r204
|
|
| 78 | 78 | if not sonnet18.resources: |
| 79 | 79 | res = model.Resource(locator_type=u'inline', |
| 80 | | locator=sonnet18_text) |
| | 80 | locator=sonnet18_text, |
| | 81 | format=u'txt') |
| 81 | 82 | sonnet18.resources.append(res) |
| 82 | 83 | assert len(sonnet18_work.materials)==1 |
-
|
r192
|
r204
|
|
| 40 | 40 | format='plain') |
| 41 | 41 | res = self.app.get(url) |
| | 42 | res = res.follow() |
| 42 | 43 | assert 'CALIBAN, a savage and deformed Slave' in res |
| 43 | 44 | |
| … |
… |
|
| 52 | 53 | res = self.app.get(url) |
| 53 | 54 | res = res.click('view', index=0) |
| | 55 | res = res.follow() |
| 54 | 56 | assert "All's Well, that Ends Well" in res, res[:1000] |
| 55 | | |
| 56 | | def test_view_2(self): |
| 57 | | url = url_for(controller='text', action='view', |
| 58 | | name=['tempest_gut','tempest_gut_f'], format='plain') |
| 59 | | # check url as url_for sometimes does not process [...] stuff right |
| 60 | | # assert 'tempest_gut+tempest_gut_f' in url, 'KNOWN ISSUE: url_for not working with multi args: %s' % url |
| 61 | | res = self.app.get(url) |
| 62 | | assert 'CALIBAN, a savage and deformed Slave' in res |
| 63 | | |
| 64 | | def test_view_3(self): |
| 65 | | url = url_for(controller='text', action='view', |
| 66 | | name=['tempest_gut', 'tempest_gut_f'], format='raw') |
| 67 | | # assert 'tempest_gut+tempest_gut_f' in url, 'KNOWN ISSUE: url_for not working with multi args: %s' % url |
| 68 | | res = self.app.get(url) |
| 69 | | assert 'CALIBAN, a savage and deformed Slave' in res |
| 70 | 57 | |
| 71 | 58 | def test_view_with_unicode_source(self): |
| 72 | 59 | url = url_for(controller='text', action='view', |
| 73 | | name='all_is_well_that_ends_well_gut_f', format='plain') |
| | 60 | id='all_is_well_that_ends_well_gut_f') |
| 74 | 61 | res = self.app.get(url) |
| | 62 | res = res.follow() |
| 75 | 63 | assert "All's Well, that Ends Well" in res |
| 76 | 64 | |