another day
|
@ -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)
|
||||||
|
|
|
@ -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()
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
149
oilarchive/static/css/archiveItem.css
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
BIN
oilarchive/static/images/backgroundBruegelChildren.png
Normal file
After Width: | Height: | Size: 1.6 MiB |
BIN
oilarchive/static/images/boxBlack75CenterBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxBlack75CenterMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxBlackCenterBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxBlackCenterMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxData.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
oilarchive/static/images/boxWhite75CenterBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhite75CenterMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteCenterBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteCenterMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteCenterTop.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteLeftBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteLeftMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteLeftTop.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteRightBottom.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteRightMiddle.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/boxWhiteRightTop.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/iconCollection.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
oilarchive/static/images/iconFileAll.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
oilarchive/static/images/iconFileMovies.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
oilarchive/static/images/iconFileMusic.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
oilarchive/static/images/iconFileNews.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
oilarchive/static/images/iconFilePictures.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
oilarchive/static/images/iconFileSoftware.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
oilarchive/static/images/iconFileTexts.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
oilarchive/static/images/iconFolderAll.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
oilarchive/static/images/iconFolderMovies.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
oilarchive/static/images/iconFolderMusic.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
oilarchive/static/images/iconFolderNews.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
oilarchive/static/images/iconFolderPictures.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
oilarchive/static/images/iconFolderSmart.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
oilarchive/static/images/iconFolderSoftware.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
oilarchive/static/images/iconFolderTexts.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
oilarchive/static/images/iconLinkArchive.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
oilarchive/static/images/iconLinkDownload.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
oilarchive/static/images/iconLinkStore.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
oilarchive/static/images/iconTypeMovies.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
oilarchive/static/images/iconTypeMusic.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
oilarchive/static/images/iconTypeNews.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
oilarchive/static/images/iconTypePictures.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
oilarchive/static/images/iconTypeSoftware.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
oilarchive/static/images/iconTypeTexts.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
oilarchive/static/images/iconTypeTexts2.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
oilarchive/static/images/itemListLargeCenterActive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListLargeCenterMouseOver.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListLargeCenterSelected.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListLargeLeftActive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListLargeLeftMouseOver.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemListLargeLeftSelected.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemListLargeRightActive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListLargeRightMouseOver.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
oilarchive/static/images/itemListLargeRightSelected.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemListSmallCenterMouseOver.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
oilarchive/static/images/itemListSmallLeftMouseOver.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemListSmallRightMouseOver.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemPageBottomMouseOver.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/itemPageMiddleMouseOver.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
oilarchive/static/images/itemPageTopMouseOver.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
oilarchive/static/images/transparent25Black.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
oilarchive/static/images/transparent25White.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
oilarchive/static/images/transparent50Black.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
oilarchive/static/images/transparent50White.png
Normal file
After Width: | Height: | Size: 3 KiB |
|
@ -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")}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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"> </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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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('&', value)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
highlight search term in text, scipping html tags and script elements
|
highlight search term in text, scipping html tags and script elements
|
||||||
|
|