another day

This commit is contained in:
j 2007-04-05 18:37:32 +00:00
parent 04b0a2bae9
commit f7f3753cbf
76 changed files with 683 additions and 297 deletions

View file

@ -21,10 +21,14 @@ from sortname import sortname
def httpExpires(sec): def httpExpires(sec):
return cherrypy.lib.httptools.HTTPDate(time.gmtime(time.mktime(time.gmtime()) + sec)) return cherrypy.lib.httptools.HTTPDate(time.gmtime(time.mktime(time.gmtime()) + sec))
def _default_search_values():
return dict(q = '', f = 'all', s = 'title', o = 0, n = 60, l = 'all', v = 'icon', length = 0)
class View: class View:
@expose(template=".templates.view") @expose(template=".templates.view")
def view(self, item): def view(self, item):
return dict(item = item) search = cherrypy.session.get('search', _default_search_values())
return dict(item = item, search = search)
def icon(self, item): def icon(self, item):
response.headerMap['Content-Type'] = "image/png" response.headerMap['Content-Type'] = "image/png"
@ -48,6 +52,9 @@ class View:
return self.icon(item) return self.icon(item)
elif args[0].startswith('icon_reflection.'): elif args[0].startswith('icon_reflection.'):
return self.icon_reflection(item) return self.icon_reflection(item)
elif args[0] == 'update':
item.archive.updateItem(item.archiveItemId)
raise redirect("/view/%s" % item.hashId)
elif args[0] == 'json': elif args[0] == 'json':
return item.json return item.json
@ -69,11 +76,33 @@ class Admin:
@validate(form = forms.add_archive) @validate(form = forms.add_archive)
@error_handler(archives) @error_handler(archives)
def archives_add(self, **data): def archives_add(self, **data):
print data
try:
url = "%s?metadata=1" % data['archiveUrl']
result = simplejson.loads(read_url(url))
print result
except:
result = None
if result and result.has_key('name') \
and result.has_key('id') \
and result.has_key('ttl'):
archiveId = result['id']
archiveName = result['name']
ttl = int(result['ttl'])
if result.has_key('icon'):
icon = result['icon']
else:
icon = ''
else:
tg_errors ="Not a valid JSON Backend"
return "FIXME"
new = Archive( new = Archive(
archiveName = data['archiveName'], archiveName = archiveName,
archiveType = data['archiveType'], archiveId = archiveId,
archiveUrl = data['archiveUrl'], archiveUrl = data['archiveUrl'],
ttl = int(data['ttl']), icon = icon,
ttl = ttl,
hashId = "%s" % time.mktime(time.localtime()),
) )
new.setHashId() new.setHashId()
raise redirect('archives') raise redirect('archives')
@ -125,13 +154,27 @@ class ArchiveStyleSheet:
cherrypy.response.headerMap["Expires"] = httpExpires(60) #(60*60*24*30) cherrypy.response.headerMap["Expires"] = httpExpires(60) #(60*60*24*30)
return archive.css return archive.css
class Root(controllers.RootController): class ArchiveIcon:
@expose()
def default(self, name):
name = name.split('.')[0]
archive = Archive.byHashId(name)
response.headerMap['Content-Type'] = "image/png"
cherrypy.response.headerMap["Expires"] = httpExpires(60*60*24*30)
return oilcache.loadArchiveIcon(archive)
class Root(controllers.RootController):
view = View() view = View()
admin = Admin() admin = Admin()
api = Api() api = Api()
js = ArchiveJavascript() js = ArchiveJavascript()
css = ArchiveStyleSheet() css = ArchiveStyleSheet()
icon = ArchiveIcon()
@expose()
def redirect(self, *kw, **args):
url = "?".join(cherrypy.request.browserUrl.split('?')[1:])
raise redirect(url)
@expose(template=".templates.login") @expose(template=".templates.login")
def login(self, forward_url=None, previous_url=None, *args, **kw): def login(self, forward_url=None, previous_url=None, *args, **kw):
@ -163,8 +206,6 @@ class Root(controllers.RootController):
identity.current.logout() identity.current.logout()
raise redirect("/") raise redirect("/")
def default_search_values(self):
return dict(q = '', f = 'all', s = 'title', o = 0, n = 60, l = 'all', v = 'icon', length = 0)
_sort_map = { _sort_map = {
'id': 'hashId', 'id': 'hashId',
@ -184,6 +225,7 @@ class Root(controllers.RootController):
'title': ArchiveItem.q.title, 'title': ArchiveItem.q.title,
'author': ArchiveItem.q.author, 'author': ArchiveItem.q.author,
'genre': ArchiveItem.q.genre, 'genre': ArchiveItem.q.genre,
'date': ArchiveItem.q.relDate,
} }
_search_map = { _search_map = {
@ -192,7 +234,7 @@ class Root(controllers.RootController):
@expose(template=".templates.iconview") @expose(template=".templates.iconview")
def search(self, q = '', f = None, s = None, o = -1, n = None, l = None, v = None): def search(self, q = '', f = None, s = None, o = -1, n = None, l = None, v = None):
search = cherrypy.session.get('search', self.default_search_values()) search = cherrypy.session.get('search', _default_search_values())
if not v: if not v:
v = search['v'] v = search['v']
if not l: if not l:
@ -219,10 +261,10 @@ class Root(controllers.RootController):
orderBy = [self.get_sort(s), 'title_sort', 'rel_date'] orderBy = [self.get_sort(s), 'title_sort', 'rel_date']
if q: if q:
q = q.encode('utf-8')
if f=='all': if f=='all':
items = queryArchive(q, s) items = queryArchive(q, s)
elif f in ('title', 'author', 'genre'): elif f in ('title', 'author', 'genre', 'date'):
q = q.encode('utf-8')
items = ArchiveItem.select(LIKE(self._field_map[f], '%'+q+'%') , orderBy=orderBy) items = ArchiveItem.select(LIKE(self._field_map[f], '%'+q+'%') , orderBy=orderBy)
else: else:
items = ArchiveItem.select(orderBy = orderBy) items = ArchiveItem.select(orderBy = orderBy)

View file

@ -20,12 +20,12 @@ def updateSortAuthorNames():
''' '''
def spiderArchives(): def spiderArchives():
for archive in Archive.select(Archive.q.initialized == True): for archive in Archive.select(Archive.q.initialized == True):
if archive.modDate - datetime.now() < timedelta(minutes = archive.ttl): if archive.modDate - datetime.now() < timedelta(seconds = archive.ttl):
print "updating", archive.archiveName print "updating", archive.archiveName
archive.update() archive.update()
else: else:
print "skipping", archive.archiveName print "skipping", archive.archiveName
def runCron(): def runCron():
spiderArchives() #spiderArchives()
updateSortAuthorNames() updateSortAuthorNames()

View file

@ -14,11 +14,7 @@ class forms:
add_archive = widgets.TableForm( add_archive = widgets.TableForm(
fields=[ fields=[
widgets.TextField(name="archiveName",label="Name"),
widgets.TextField(name="archiveType",label="Type"),
widgets.TextField(name="archiveUrl",label="JSON url"), widgets.TextField(name="archiveUrl",label="JSON url"),
widgets.TextField(name="ttl",label="Update Interval(Minutes)"),
], ],
submit_text="Save" submit_text="Save"
) )

View file

@ -29,14 +29,17 @@ def queryArchive(query, orderBy="score", offset = 0, count = 100):
orderBy = orderBy.encode('utf-8') orderBy = orderBy.encode('utf-8')
print orderBy print orderBy
if orderBy not in ('score', 'size', 'title', 'description'): if orderBy not in ('score', 'size', 'title', 'description'):
orderBy = 'score' orderBy = 'score DESC, title'
if orderBy == 'size': if orderBy == 'size':
orderBy = "size DESC" orderBy = "size DESC"
match = "MATCH (title, description, text) AGAINST ('%s')" % query match = '''MATCH (title, description, text) AGAINST ('%s')''' % query
sql = """SELECT id, %s AS score, title, size, description FROM archive_item match_b = '''MATCH (title, description, text) AGAINST ('%s' IN BOOLEAN MODE)''' % query
sql = """SELECT id, ((100000/LENGTH(text)) * %s) AS score, title, size, description FROM archive_item
WHERE %s ORDER BY %s""" % \ WHERE %s ORDER BY %s""" % \
(match, match, orderBy) #, offset, count) (match_b, match_b, orderBy) #, offset, count)
result = [] result = []
max_score= None
print sql print sql
matches = ArchiveItem._connection.queryAll(sql) matches = ArchiveItem._connection.queryAll(sql)
if len(matches) > offset: if len(matches) > offset:
@ -45,7 +48,9 @@ WHERE %s ORDER BY %s""" % \
matches = matches[:count] matches = matches[:count]
for m in matches: for m in matches:
item = ArchiveItem.get(m[0]) item = ArchiveItem.get(m[0])
item.score = m[1] if not max_score:
max_score = m[1] / 100
item.score = m[1] / max_score
result.append(item) result.append(item)
return result return result
@ -67,8 +72,10 @@ class ArchiveItem(SQLObject):
downloadUrl = UnicodeCol() # -> url (link to item) downloadUrl = UnicodeCol() # -> url (link to item)
storeUrl = UnicodeCol() # -> url (link to store) storeUrl = UnicodeCol() # -> url (link to store)
size = IntCol() #bytes size = IntCol() #bytes
rights = IntCol(default = 5) #-> int: 0 (free) - 5 (unfree) rightsLevel = IntCol(default = 5) #-> int: 0 (free) - 5 (unfree)
itemType = UnicodeCol() #string (Text, Pictures, Music, Movies, Software) rightsText = UnicodeCol(default = '')
kind = UnicodeCol() #string (Text, Pictures, Music, Movies, Software)
fileType = UnicodeCol() #fileType (pdf, txt etc)
genre = UnicodeCol(default = '') genre = UnicodeCol(default = '')
archive = ForeignKey('Archive') archive = ForeignKey('Archive')
@ -80,9 +87,17 @@ class ArchiveItem(SQLObject):
#Fulltext search #Fulltext search
#ALTER TABLE archive_item ADD FULLTEXT (title, description, text); #ALTER TABLE archive_item ADD FULLTEXT (title, description, text);
def _get_filetype(self):
return self.downloadUrl.split('.')[-1].upper()
def _get_sizeFormated(self):
return utils.formatFileSize(self.size)
def getPreview(self, sort): def getPreview(self, sort):
if sort == 'size': if sort == 'size':
return utils.formatFileSize(self.size) return self.sizeFormated
if sort == 'relevance':
return "%d" % self.score
return self.relDateFormated return self.relDateFormated
def _set_author(self, value): def _set_author(self, value):
@ -90,15 +105,30 @@ class ArchiveItem(SQLObject):
if not self.authorSort: if not self.authorSort:
self.authorSort = value self.authorSort = value
def _set_title(self, value):
self._SO_set_title(value)
if not self.titleSort:
self.titleSort = value
def _get_year(self): def _get_year(self):
return self.relDate.strftime('%Y') return self.relDate.strftime('%Y')
def rightsLevelClass(self, level):
if level == self.rightsLevel:
return "rightsLevelActive"
return "rightsLevelInactive"
def _get_relDateFormated(self): def _get_relDateFormated(self):
if self.itemType in ('Movie', 'Book'): if self.kind in ('Movie', 'Book'):
return self.year return self.year
else: else:
return self.relDate.strftime('%Y-%m-%d') return self.relDate.strftime('%Y-%m-%d')
def domain(self, url):
d = url.split('/')
if len(d) > 2:
return d[2].split('?')[0]
return url
#expand urls in case they are relative to the archive #expand urls in case they are relative to the archive
def _get_archiveUrl(self): def _get_archiveUrl(self):
return self.archive.full_url(self._SO_get_archiveUrl()) return self.archive.full_url(self._SO_get_archiveUrl())
@ -113,6 +143,7 @@ class ArchiveItem(SQLObject):
result = jsonify_sqlobject(self) result = jsonify_sqlobject(self)
result['relDate'] = self.relDate.strftime('%s') result['relDate'] = self.relDate.strftime('%s')
result['pubDate'] = self.pubDate.strftime('%s') result['pubDate'] = self.pubDate.strftime('%s')
result['modDate'] = self.relDate.strftime('%s')
return result return result
''' '''
return dict( return dict(
@ -134,24 +165,25 @@ class ArchiveItem(SQLObject):
def update(self, data): def update(self, data):
for key in data: for key in data:
setattr(self, key, data[key]) setattr(self, key, data[key])
self.updateHashID() self.setHashId()
def updateHashID(self): def setHashId(self):
salt = u'%s/%s' % (self.archive.archiveName, self.archiveItemId) salt = u'%s/%s' % (self.archive.archiveName, self.archiveItemId)
self.hashID = md5.new(salt.encode('utf-8')).hexdigest() self.hashID = md5.new(salt.encode('utf-8')).hexdigest()
class Archive(SQLObject): class Archive(SQLObject):
archiveName = UnicodeCol(alternateID = True, length = 1000) archiveId = UnicodeCol(alternateID = True, length = 1000)
archiveName = UnicodeCol()
archiveUrl = UnicodeCol() archiveUrl = UnicodeCol()
archiveType = UnicodeCol(default=u'') ttl = IntCol(default = "900") #seconds
ttl = IntCol(default = "15")
pubDate = DateTimeCol(default=datetime.now) pubDate = DateTimeCol(default=datetime.now)
modDate = DateTimeCol(default=datetime.now) modDate = DateTimeCol(default=datetime.now)
created = DateTimeCol(default=datetime.now) created = DateTimeCol(default=datetime.now)
initialized = BoolCol(default = False) initialized = BoolCol(default = False)
css = UnicodeCol(default='') css = UnicodeCol(default='')
js = UnicodeCol(default='') js = UnicodeCol(default='')
icon = UnicodeCol() # -> url (128x128)
hashId = UnicodeCol(alternateID = True, length=128) hashId = UnicodeCol(alternateID = True, length=128)
@ -171,13 +203,15 @@ class Archive(SQLObject):
def _get_update_url(self): def _get_update_url(self):
return self._query_url({'modDate': self.modDateTimestamp}) return self._query_url({'modDate': self.modDateTimestamp})
def _get_files_url(self): def _get_metadata_url(self):
return self._query_url({'files': '1'}) return self._query_url({'metadata': '1'})
def data_url(self, id): def data_url(self, id):
return self._query_url({'id': id}) return self._query_url({'id': id})
def full_url(self, url): def full_url(self, url):
if not url:
return ''
if url.find('://') > 0: if url.find('://') > 0:
return url return url
if url.startswith('/'): if url.startswith('/'):
@ -187,37 +221,63 @@ class Archive(SQLObject):
url = "%s/%s" % (self.archiveUrl, url) url = "%s/%s" % (self.archiveUrl, url)
return url return url
def _get_iconUrl(self):
if self.icon:
return "/icon/%s.png" % self.hashId
else:
return "/static/images/iconCollection.png"
def update(self): def update(self):
result = simplejson.loads(read_url(self.files_url)) result = simplejson.loads(read_url(self.metadata_url))
if result and result.has_key('css'): if result:
self.css = read_url(self.full_url(result['css'])) if result.has_key('name'):
else: self.archiveName = result['name']
self.css = '' if result.has_key('id'):
if result and result.has_key('js'): self.archiveId = result['id']
self.js = read_url(self.full_url(result['js'])) if result.has_key('ttl'):
self.ttl = int(result['ttl'])
if result.has_key('icon'):
self.icon = result['icon']
if result.has_key('css'):
try:
data = read_url(self.full_url(result['css']))
self.css = data
except:
self.css = ''
if result.has_key('js'):
try:
data = read_url(self.full_url(result['js']))
self.js = data
except:
self.js = ''
else: else:
self.icon = ''
self.js = '' self.js = ''
self.css = ''
result = simplejson.loads(read_url(self.update_url)) result = simplejson.loads(read_url(self.update_url))
items = result.get('items', []) items = result.get('items', [])
print "importing", len(items), "items" print "importing", len(items), "items"
for id in items: for id in items:
try: try:
data = read_url(self.data_url(id)) self.updateItem(id)
data = jsonLoadArchiveItem(data)
print data['title'].encode('utf-8')
except: except:
print "failed to load ", id, "from ", self.data_url(id) print "failed to load ", id, "from ", self.data_url(id)
continue continue
q = ArchiveItem.select(AND(
ArchiveItem.q.archiveItemId == id,
ArchiveItem.q.archiveID == self.id))
if q.count() == 0:
jsonImportArchiveItem(self, id, data)
else:
q[0].update(data)
self.initialized = True self.initialized = True
self.modDate = datetime.now() self.modDate = datetime.now()
def updateItem(self, id):
data = read_url(self.data_url(id))
data = jsonLoadArchiveItem(data)
print data['title'].encode('utf-8')
q = ArchiveItem.select(AND(
ArchiveItem.q.archiveItemId == id,
ArchiveItem.q.archiveID == self.id))
if q.count() == 0:
jsonImportArchiveItem(self, id, data)
else:
q[0].update(data)
''' '''
get list of all items from archive and remove those from ArchiveItem that get list of all items from archive and remove those from ArchiveItem that
are no longer in the list are no longer in the list

View file

@ -85,3 +85,16 @@ def loadIconReflection(item):
else: else:
return '' return ''
return loadFile(iconReflection) return loadFile(iconReflection)
'''
return icon data, reads from remote url if not cached
'''
def loadArchiveIcon(archive):
icon = iconPath('archiveIcon', archive)
if exists(icon):
data = loadFile(icon)
else:
data = read_url(archive.icon)
saveFile(icon, data)
return data

View file

@ -5,10 +5,12 @@
from datetime import datetime from datetime import datetime
import time import time
import md5
import simplejson import simplejson
from scrapeit.utils import stripTags
import model import model
import md5 import utils
def jsonLoadArchiveItem(data): def jsonLoadArchiveItem(data):
json_array = simplejson.loads(data) json_array = simplejson.loads(data)
@ -21,9 +23,15 @@ def jsonLoadArchiveItem(data):
json_array['storeUrl'] = json_array.pop('storeURL') json_array['storeUrl'] = json_array.pop('storeURL')
for key in ('relDate', 'pubDate', 'modDate'): for key in ('relDate', 'pubDate', 'modDate'):
json_array[key] = datetime.utcfromtimestamp(float(json_array[key])) json_array[key] = datetime.utcfromtimestamp(float(json_array[key]))
for key in ('rights', 'size'): for key in ('rightsLevel', 'size'):
json_array[key] = int(json_array[key]) json_array[key] = int(json_array[key])
json_array['itemType'] = json_array.pop('type', 'Text')
json_array['fileType'] = json_array.pop('type', 'unknown')
for key in ('title', 'description'):
json_array[key] = stripTags(json_array[key])
for key in ('storeUrl', 'archiveUrl', 'title', 'description'):
json_array[key] = json_array.get(key, u'')
json_array['html'] = utils.fix_ampersands(json_array['html'])
return json_array return json_array
@ -37,7 +45,8 @@ def jsonImportArchiveItem(archive, archiveItemId, json_array):
hashId = hashID, hashId = hashID,
archiveItemId = "%s" % archiveItemId, archiveItemId = "%s" % archiveItemId,
description=json_array['description'], description=json_array['description'],
rights=json_array['rights'], rightsLevel=json_array['rightsLevel'],
rightsText=json_array['rightsText'],
text=json_array['text'], text=json_array['text'],
author=json_array['author'], author=json_array['author'],
pubDate=json_array['pubDate'], pubDate=json_array['pubDate'],
@ -50,6 +59,8 @@ def jsonImportArchiveItem(archive, archiveItemId, json_array):
genre=json_array['genre'], genre=json_array['genre'],
title=json_array['title'], title=json_array['title'],
size=json_array['size'], size=json_array['size'],
itemType=json_array['itemType'], fileType=json_array['fileType'],
kind=json_array['kind'],
icon= json_array['icon'] icon= json_array['icon']
) )
i.setHashId()

View file

@ -69,7 +69,7 @@ input {
font-size: 8px; font-size: 8px;
} }
.item { .oil21_item {
position: relative; position: relative;
left: 0px; left: 0px;
top: 0px; top: 0px;
@ -120,78 +120,8 @@ input {
} }
.listItemLink { .listItemLink {
width: 128px;
height: 128px;
} }
.item .textIconLarge { .oil21_item .textIconLarge {
color: rgb(0, 0, 0); color: rgb(0, 0, 0);
} }
table {
border-collapse: collapse;
border-spacing: 0px;
}
td {
padding: 0px;
}
#itemPageIcon {
width: 128px;
padding-left: 8px;
padding-right: 8px;
}
#itemPageText {
padding-left: 8px;
padding-right: 8px;
}
#itemPageTextLeftTop {
width: 8px;
height: 8px;
background: url(/static/images/itemPageTextLeftTop.png)
}
#itemPageTextCenterTop {
height: 8px;
background: url(/static/images/itemPageTextCenterTop.png);
}
#itemPageTextRightTop {
width: 8px;
height: 8px;
background: url(/static/images/itemPageTextRightTop.png)
}
#itemPageTextLeftMiddle {
width: 8px;
background: url(/static/images/itemPageTextLeftMiddle.png)
}
#itemPageTextCenterMiddle {
background: url(/static/images/itemPageTextCenterMiddle.png);
}
#itemPageTextRightMiddle {
width: 8px;
background: url(/static/images/itemPageTextRightMiddle.png)
}
#itemPageTextLeftBottom {
width: 8px;
height: 8px;
background: url(/static/images/itemPageTextLeftBottom.png)
}
#itemPageTextCenterBottom {
height: 8px;
background: url(/static/images/itemPageTextCenterBottom.png);
}
#itemPageTextRightBottom {
width: 8px;
height: 8px;
background: url(/static/images/itemPageTextRightBottom.png)
}

View file

@ -0,0 +1,149 @@
table {
border-collapse: collapse;
border-spacing: 0px;
}
td {
padding: 0px;
}
div {
font-family: Lucida Grande;
}
#itemPageText {
width: 864px;
margin-left: auto;
margin-right: auto;
margin-top: 8px;
margin-bottom: 16px;
}
.boxWhiteLeftTop {
width: 8px;
height: 8px;
background: url(/static/images/boxWhiteLeftTop.png);
}
.boxWhiteCenterTop {
height: 8px;
background: url(/static/images/boxWhiteCenterTop.png);
}
.boxWhiteRightTop {
width: 8px;
height: 8px;
background: url(/static/images/boxWhiteRightTop.png);
}
.boxWhiteLeftMiddle {
width: 8px;
background: url(/static/images/boxWhiteLeftMiddle.png);
}
.boxWhiteCenterMiddle {
background: url(/static/images/boxWhiteCenterMiddle.png);
text-align: center;
}
.boxWhiteRightMiddle {
width: 8px;
background: url(/static/images/boxWhiteRightMiddle.png);
}
.boxWhiteLeftBottom {
width: 8px;
height: 8px;
background: url(/static/images/boxWhiteLeftBottom.png);
}
.boxWhiteCenterBottom {
height: 8px;
background: url(/static/images/boxWhiteCenterBottom.png);
}
.boxWhiteRightBottom {
width: 8px;
height: 8px;
background: url(/static/images/boxWhiteRightBottom.png);
}
.boxData {
width: 144px;
height: 192px;
margin: 8px;
padding: 8px;
background: url(/static/images/boxData.png) center no-repeat;
text-align: center;
float: left;
}
.boxData img {
margin-top: 8px;
}
.iconText {
padding-top: 8px;
}
.rightsLevel {
width: 128px;
height: 32px;
margin-left: 8px;
text-align: center;
}
.textBold {
font-weight: bold;
}
.textLarge {
font-size: 12px;
}
.textMedium {
font-size: 11px;
}
.textSmall {
font-size: 10px;
}
.textXSmall {
font-size: 9px;
}
.textXXSmall {
font-size: 8px;
}
.textSpacing {
letter-spacing: 1px;
}
.textCenter {
text-align: center;
}
.textWhite {
color: rgb(255, 255, 255);
}
.rightsLevelActive {
opacity: 1.0;
}
.rightsLevelInactive {
opacity: 0.25;
}
.textSmall a {
color: #fff;
text-decoration: underline;
}
.rightsLevelTable {
width: 128px;
height: 32px;
vertical-align: middle;
display: table-cell;
}

View file

@ -1,13 +1,10 @@
#head { #head {
position: fixed; width: 100%; height: 56px; top: 0px; background: url(/static/images/boxBlack75CenterMiddle.png); position: fixed; z-index: 1
top: 0px;
width: 100%;
height: 64px;
background: rgb(64, 64, 64);
text-align: center;
z-index: 1;
} }
#shadowTop {
width: 100%; height: 8px; top: 56px; background: url(/static/images/boxBlack75CenterBottom.png); position: fixed; z-index: 1;
}
#headList { #headList {
position: relative; position: relative;
margin-left: auto; margin-left: auto;
@ -24,8 +21,5 @@
} }
.headBottom { .headBottom {
position: absolute; width: 100%; height: 32px; top: 32px; background: url(/static/images/boxBlack75CenterMiddle.png); position: fixed; z-index: 1
left: 0px;
bottom: 0px;
width: 128px;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1,6 +1,5 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#">
py:extends="'master.kid'">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>Oil Archive</title> <title>Oil Archive</title>
@ -8,7 +7,7 @@
<body> <body>
known archives known archives
<ul> <ul>
<li py:for="archive in archives">${archive.archiveName}</li> <li py:for="archive in archives">${archive.id} - <a href="${archive.archiveUrl}?modDate=-1">${archive.archiveName}</a></li>
</ul> </ul>
add new archive: add new archive:
${add_archive(action="archives_add")} ${add_archive(action="archives_add")}

View file

@ -1,136 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<?python
selectView = [
('icon', 'View: Icon'),
('list', 'View: List'),
('quote', 'View: Quotes'),
]
selectSort = [
('title', 'Sort: Title'),
('date', 'Sort: Date'),
('size', 'Sort: Size'),
('relevance', 'Sort: Relevance'),
]
selectFind = [
('all', 'Find: All'),
('title', 'Find: Title'),
('author', 'Find: Author'),
('date', 'Find: Date'),
('genre', 'Find: Genre'),
]
selectList = [
('all', 'List: All'),
('Screenings', 'List: Screenings'),
]
def search_link(search, n = None, o = None):
link = "/search?"
if n:
o = search['o'] - (search['o'] % n) + 1
for key in search:
value = search[key]
if key == 'o' and o:
value = o -1
if key == 'n' and n:
value = n
if key not in ['length']:
link += "%s=%s&" %(key, value)
return link
?>
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>Oil of the 21st Century Archive</title> <title>Oil of the 21st Century Archive</title>
</head> </head>
<body> <body>
<div id="head">
<div id="headList">
<div class="headTop">
</div>
<div class="headTop" style="left: 136px">
<select id="selectList" onChange="changeList()">
<option py:for="value, content in selectList"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['l'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 272px">
<select id="selectView" onChange="changeView()">
<option py:for="value, content in selectView"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['v'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 408px">
<select id="selectSort" onChange="changeSort()">
<option py:for="value, content in selectSort"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['s'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 544px">
<select id="selectFind" onChange="changeFind()">
<option py:for="value, content in selectFind"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['f'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 680px">
<input id="inputFind" type="search" placeholder="Find" autosave="find" results="10" onBlur="submitFind()" value="${search['q']}"/>
</div>
<div py:if="search['length'] > 30" id="numberDiv" class="headBottom textSmall">
Items per Page<br/> <span py:for="n in [30, 60, 90, 120]">
<a py:if="n != search['n']" href="${search_link(search, n=n)}">${n}</a>
<span py:if="n == search['n']" py:replace="n" />
</span>
</div>
<?python
number_pages = search['length'] / search['n']
if search['length'] % search['n']:
number_pages += 1
current_page = search['o'] / search['n'] + 1
current_page_start = search['o'] + 1
current_page_end = min(search['o']+search['n'], search['length'])
previous_page = current_page - 1
previous_page_start = None
if current_page > 1:
previous_page_end = current_page_start - 1
previous_page_start = current_page_start - search['n']
next_page = current_page + 1
next_page_start = None
if current_page < number_pages:
next_page_start = current_page_end + 1
next_page_end = min(next_page_start + search['n'] -1, search['length'])
last_page = number_pages
last_page_start = None
if search['length'] > search['o'] + search['n']:
last_page_start = search['n'] * (number_pages -1) + 1
last_page_end = search['length']
?>
<div py:if="search['length'] > search['n'] and current_page > 1" id="firstDiv" class="headBottom textSmall" style="left: 136px">
<a href="${search_link(search, o=1)}">First Page<br/>1 (1-${search['n']})</a>
</div>
<div py:if="previous_page_start" id="previousDiv" class="headBottom textSmall" style="left: 272px">
<a href="${search_link(search, o= previous_page_start)}">Previous Page<br/>${previous_page} (${previous_page_start}-${previous_page_end})</a>
</div>
<div id="currentDiv" class="headBottom textSmall" style="left: 408px">
Current Page<br/>${current_page} (${current_page_start}-${current_page_end})
</div>
<div py:if="next_page_start" id="nextDiv" class="headBottom textSmall" style="left: 544px">
<a href="${search_link(search, o= next_page_start)}">Next Page<br/>${next_page} (${next_page_start}-${next_page_end})</a>
</div>
<div py:if="last_page_start" id="lastDiv" class="headBottom textSmall" style="left: 680px">
<a href="${search_link(search, o= last_page_start)}">Last Page<br/>${last_page} (${last_page_start}-${last_page_end})</a>
</div>
</div>
</div>
<div id="shadowTop"></div>
<div id="listBody"> <div id="listBody">
<div py:for="item in items" id="${item.hashId}" class="inline listItem"> <div py:for="item in items" id="${item.hashId}" class="inline listItem">
<div class="table"> <div class="table">
@ -138,7 +12,7 @@ if search['length'] > search['o'] + search['n']:
<img src="/view/${item.hashId}/icon.png" class="listItemLink link" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')" /> <img src="/view/${item.hashId}/icon.png" class="listItemLink link" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')" />
</a> </a>
</div> </div>
<div class="item"> <div class="oil21_item">
<img src="/static/images/transparent.png" class="link" style="width: 128px; height: 8px" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')" /> <img src="/static/images/transparent.png" class="link" style="width: 128px; height: 8px" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')" />
<div class="link textIconLarge" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')"> <div class="link textIconLarge" onMouseOver="mouseOver('${item.hashId}','IconLarge')" onMouseOut="mouseOut('${item.hashId}','IconLarge')">
${item.title} ${item.title}

View file

@ -1,5 +1,48 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<?python import sitetemplate ?> <?python import sitetemplate ?>
<?python
selectView = [
('icon', 'View: Icon'),
('list', 'View: List'),
('quote', 'View: Quotes'),
]
selectSort = [
('title', 'Sort: Title'),
('date', 'Sort: Date'),
('size', 'Sort: Size'),
('relevance', 'Sort: Relevance'),
]
selectFind = [
('all', 'Find: All'),
('title', 'Find: Title'),
('author', 'Find: Author'),
('date', 'Find: Date'),
('genre', 'Find: Genre'),
]
selectList = [
('all', 'List: All'),
('Screenings', 'List: Screenings'),
]
def search_link(search, n = None, o = None):
link = "/search?"
if n:
o = search['o'] - (search['o'] % n) + 1
for key in search:
value = search[key]
if key == 'o' and o:
value = o -1
if key == 'n' and n:
value = n
if key not in ['length']:
link += "%s=%s&" %(key, value)
return link
?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="sitetemplate"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="sitetemplate">
<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()"> <head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
@ -32,7 +75,88 @@
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
</span> </span>
</div> </div>
<div id="header">&nbsp;</div> <div id="head">
<div id="headList">
<div class="headTop">
</div>
<div class="headTop" style="left: 136px">
<select id="selectList" onChange="changeList()">
<option py:for="value, content in selectList"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['l'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 272px">
<select id="selectView" onChange="changeView()">
<option py:for="value, content in selectView"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['v'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 408px">
<select id="selectSort" onChange="changeSort()">
<option py:for="value, content in selectSort"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['s'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 544px">
<select id="selectFind" onChange="changeFind()">
<option py:for="value, content in selectFind"
py:content="content"
py:attrs="dict(value=value, selected=(value==search['f'] and 'selected' or None))" />
</select>
</div>
<div class="headTop" style="left: 680px">
<input id="inputFind" type="search" placeholder="Find" autosave="find" results="10" onBlur="submitFind()" value="${search['q']}"/>
</div>
<div py:if="search['length'] > 30" id="numberDiv" class="headBottom textSmall">
Items per Page<br/> <span py:for="n in [30, 60, 90, 120]">
<a py:if="n != search['n']" href="${search_link(search, n=n)}">${n}</a>
<span py:if="n == search['n']" py:replace="n" />
</span>
</div>
<?python
number_pages = search['length'] / search['n']
if search['length'] % search['n']:
number_pages += 1
current_page = search['o'] / search['n'] + 1
current_page_start = search['o'] + 1
current_page_end = min(search['o']+search['n'], search['length'])
previous_page = current_page - 1
previous_page_start = None
if current_page > 1:
previous_page_end = current_page_start - 1
previous_page_start = current_page_start - search['n']
next_page = current_page + 1
next_page_start = None
if current_page < number_pages:
next_page_start = current_page_end + 1
next_page_end = min(next_page_start + search['n'] -1, search['length'])
last_page = number_pages
last_page_start = None
if search['length'] > search['o'] + search['n']:
last_page_start = search['n'] * (number_pages -1) + 1
last_page_end = search['length']
?>
<div py:if="search['length'] > search['n'] and current_page > 1" id="firstDiv" class="headBottom textSmall" style="left: 136px">
<a href="${search_link(search, o=1)}">First Page<br/>1 (1-${search['n']})</a>
</div>
<div py:if="previous_page_start" id="previousDiv" class="headBottom textSmall" style="left: 272px">
<a href="${search_link(search, o= previous_page_start)}">Previous Page<br/>${previous_page} (${previous_page_start}-${previous_page_end})</a>
</div>
<div id="currentDiv" class="headBottom textSmall" style="left: 408px">
Current Page<br/>${current_page} (${current_page_start}-${current_page_end})
</div>
<div py:if="next_page_start" id="nextDiv" class="headBottom textSmall" style="left: 544px">
<a href="${search_link(search, o= next_page_start)}">Next Page<br/>${next_page} (${next_page_start}-${next_page_end})</a>
</div>
<div py:if="last_page_start" id="lastDiv" class="headBottom textSmall" style="left: 680px">
<a href="${search_link(search, o= last_page_start)}">Last Page<br/>${last_page} (${last_page_start}-${last_page_end})</a>
</div>
</div>
</div>
<div id="shadowTop"></div>
<div id="main_content"> <div id="main_content">
<div py:if="tg_flash" class="flash" py:content="tg_flash"></div> <div py:if="tg_flash" class="flash" py:content="tg_flash"></div>

View file

@ -4,37 +4,222 @@
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
<title>Oil21 - ${item.title}</title> <title>Oil21 - ${item.title}</title>
<!--
<style type="text/css" media="screen" py:if="item.archive.css"> <style type="text/css" media="screen">
@import "/css/${item.archive.hashId}.css"; @import "/static/css/archiveItem.css";
</style> </style>
<style type="text/css" media="screen" py:if="item.archive.css">
@import "/css/${item.archive.hashId}.css";
</style>
<script py:if="item.archive.js" src="/js/${item.archive.hashId}.js" /> <script py:if="item.archive.js" src="/js/${item.archive.hashId}.js" />
<!--
--> -->
</head> </head>
<body> <body>
<div class="itemPageIcon"> <div style="width: 880px; height: 232px; margin-left: auto; margin-right: auto; margin-top: 48px">
<img class="itemIcon" src="/view/${item.hashId}/icon.png" /> <div class="boxData">
</div> <div>
<div class="itemPageText"> <img src="/view/${item.hashId}/icon.png" />
<table> </div>
<tr> <div class="iconText textBold textMedium textCenter" style="width: 144px; height: 64px; background: url(/view/${item.hashId}/icon_reflection.png);background-position: center top; background-repeat: no-repeat;">
<td id="itemPageTextLeftTop"></td> ${item.author} - ${item.title}
<td id="itemPageTextCenterTop"></td> </div>
<td id="itemPageTextRightTop"></td> </div>
</tr> <div class="boxData">
<tr> <div style="height: 64px">
<td id="itemPageTextLeftMiddle"></td> <div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
<td id="itemPageTextCenterMiddle"> <img src="${item.archive.iconUrl}" style="width: 48px; height: 48px" />
x${XML(item.html)} </div>
</td> <div style="height: 64px; padding-left: 4px; display: table-cell; text-align: left; vertical-align: middle">
<td id="itemPageTextRightMiddle"></td> <div class="textLarge textBold">
</tr> ${item.archive.archiveName}
<tr> </div>
<td id="itemPageTextLeftBottom"></td> </div>
<td id="itemPageTextCenterBottom"></td> </div>
<td id="itemPageTextRightBottom"></td> <div style="height: 64px">
</tr> <div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
</table> <img src="/static/images/iconType${item.kind}.png" style="width: 48px; height: 48px" />
</div> </div>
<div style="height: 64px; padding-left: 4px; display: table-cell; text-align: left; vertical-align: middle">
<div class="textLarge textBold">
${item.kind}
</div>
<div class="textSmall">
${item.genre}
</div>
</div>
</div>
<div style="height: 64px">
<div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
<img src="/static/images/iconFile${item.kind}.png" style="width: 48px; height: 48px" />
</div>
<div style="height: 64px; padding-left: 4px; display: table-cell; text-align: left; vertical-align: middle">
<div class="textBold textLarge">
${item.fileType}
</div>
<div class="textSmall">
${item.sizeFormated}
</div>
</div>
</div>
</div>
<div class="boxData">
<div style="height: 64px">
<div style="width: 144px; height: 64px; text-align: center; display: table-cell; vertical-align: middle">
<div class="textLarge textBold">
Released
</div>
<div class="textSmall" style="vertical-align: bottom">
${item.relDateFormated}
</div>
</div>
</div>
<div style="height: 64px">
<div style="width: 144px; height: 64px; text-align: center; display: table-cell; vertical-align: middle">
<div class="textLarge textBold">
Archived
</div>
<div class="textSmall" style="vertical-align: bottom">
${item.pubDate}
</div>
</div>
</div>
<div style="height: 64px">
<div style="width: 144px; height: 64px; text-align: center; display: table-cell; vertical-align: middle">
<div class="textLarge textBold">
Modified
</div>
<div class="textSmall" style="vertical-align: bottom">
${item.modDate}
</div>
</div>
</div>
</div>
<div class="boxData">
<div style="height: 64px">
<div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
<img src="/static/images/iconLinkDownload.png" style="width: 48px; height: 48px" />
</div>
<div style="height: 64px; display: table-cell; text-align: left; vertical-align: middle">
<div class="textLarge textBold">
Download
</div>
<div class="textSmall" py:if="item.downloadUrl">
<a href="${item.downloadUrl}">${item.domain(item.downloadUrl)}</a>
</div>
</div>
</div>
<div style="height: 64px">
<div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
<img src="/static/images/iconLinkArchive.png" style="width: 48px; height: 48px" />
</div>
<div style="height: 64px; display: table-cell; text-align: left; vertical-align: middle">
<div class="textLarge textBold">
Archive
</div>
<div class="textSmall" py:if="item.archiveUrl">
<a href="${item.archiveUrl}">${item.domain(item.archiveUrl)}</a>
</div>
</div>
</div>
<div style="height: 64px">
<div style="width: 64px; height: 64px; display: table-cell; text-align: center; vertical-align: middle">
<img src="/static/images/iconLinkStore.png" style="width: 48px; height: 48px" />
</div>
<div style="height: 64px; display: table-cell; text-align: left; vertical-align: middle">
<div class="textLarge textBold">
Store
</div>
<div class="textSmall" py:if="item.storeUrl">
<a href="${item.storeUrl}">${item.domain(item.storeUrl)}</a>
</div>
</div>
</div>
</div>
<div class="boxData">
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(5)}" style="background: rgb(255, 0, 0);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
SEVERE
</div>
<div class="textXXSmall">
Severe Risk of Legal Action
</div>
</div>
</div>
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(4)}" style="background: rgb(255, 192, 0);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
HIGH
</div>
<div class="textXXSmall">
High Risk of Legal Action
</div>
</div>
</div>
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(3)}" style="background: rgb(255, 255, 0);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
ELEVATED
</div>
<div class="textXXSmall">
Elevated Risk of Legal Action
</div>
</div>
</div>
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(2)}" style="background: rgb(128, 255, 0);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
GUARDED
</div>
<div class="textXXSmall">
General Risk of Legal Action
</div>
</div>
</div>
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(1)}" style="background: rgb(0, 255, 0);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
LOW
</div>
<div class="textXXSmall">
Low Risk of Legal Action
</div>
</div>
</div>
<div py:attrs="{'class':'rightsLevel ' + item.rightsLevelClass(0)}" style="background: rgb(0, 255, 128);">
<div class="rightsLevelTable">
<div class="textBold textLarge textSpacing">
FREE
</div>
<div class="textXXSmall">
No Risk of Legal Action
</div>
</div>
</div>
</div>
</div>
<div class="itemPageText" style="width: 864px; margin-left: auto; margin-right: auto">
<table>
<tr>
<td class="boxWhiteLeftTop"></td>
<td class="boxWhiteCenterTop"></td>
<td class="boxWhiteRightTop"></td>
</tr>
<tr>
<td class="boxWhiteLeftMiddle"></td>
<td class="boxWhiteCenterMiddle" style="width: 848px">
${XML(item.html)}
</td>
<td class="boxWhiteRightMiddle"></td>
</tr>
<tr>
<td class="boxWhiteLeftBottom"></td>
<td class="boxWhiteCenterBottom"></td>
<td class="boxWhiteRightBottom"></td>
</tr>
</table>
</div>
</body> </body>
</html> </html>

View file

@ -2,6 +2,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=2:sts=2:ts=2 # vi:si:et:sw=2:sts=2:ts=2
import re
'''
Returns the given HTML with all unencoded ampersands encoded correctly
'''
unencoded_ampersands_re = re.compile(r'&(?!(\w+|#\d+);)')
def fix_ampersands(value):
return unencoded_ampersands_re.sub('&amp;', value)
''' '''
highlight search term in text, scipping html tags and script elements highlight search term in text, scipping html tags and script elements