Browse Source

User fullname and avatar are now in an iframe

Great performance boost.

Also:
* Input field to copy @username
  Once we can post, this may be handy
* Search is also an iframe (containing an iframe per user)
  So you can keep composing a twist while searching for usernames
* Should be responsive for cellulars (I can only resize browser
  to check. Got no phone. Anyway, the floating "Fork me" footer
  now has a link to navigation (local users), and that's about all
  the essential navigation. You can scroll a bit down from there
  for search results, or all the way up for the content.
* Make sure Dillo etc. that don't see bootstrap font icon
  can still have text links to everything

Enjoy
master
The Dod 11 years ago
parent
commit
3ffb1e6524
  1. 3
      static/assets/css/swizzler.css
  2. 77
      swizzler.py
  3. 3
      templates/footer.html
  4. 66
      templates/message.html
  5. 40
      templates/messages.html
  6. 37
      templates/sidebar.html
  7. 40
      templates/standard.html
  8. 16
      templates/twist.html
  9. 15
      twister.py

3
static/assets/css/swizzler.css

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
body {padding-top:8px; background:#eef url(/assets/img/swizzler-128.png) no-repeat fixed right bottom}
.avatar {max-width:64px; max-height:64px}
.avatars32 .avatar {max-width:32px; max-height:32px}
.avatars42 .avatar {max-width:44px; max-height:44px}
.panel, .list-group-item { background-color: rgba(255,255,255,0.33) } /* I should be doing this by customizing bootstrap. Later :) */
#footer {z-index:115;position:fixed;right:123px;bottom:0}
#footer {z-index:115;position:fixed;right:96px;bottom:8px}

77
swizzler.py

@ -12,19 +12,19 @@ from ttp import ttp @@ -12,19 +12,19 @@ from ttp import ttp
class TwistParser(ttp.Parser):
def format_tag(self, tag, text):
'''Return formatted HTML for a hashtag.'''
return '<a href="{0}/tag/{1}">{2}{3}</a>'.format(
return '<a target="_top" href="{0}/tag/{1}">{2}{3}</a>'.format(
cherrypy.request.base+cherrypy.request.script_name,
ttp.urllib.quote(text.lower().encode('utf-8'),'xmlcharrefreplace'), tag, text)
def format_username(self, at_char, user):
'''Return formatted HTML for a username.'''
return '<a href="{0}/user/{1}">{2}{3}</a>'.format(
return '<a target="_top" href="{0}/user/{1}">{2}{3}</a>'.format(
cherrypy.request.base+cherrypy.request.script_name,
user, at_char, user.lower())
def format_list(self, at_char, user, list_name):
'''We don't have lists, so we see it as "@user" followed by "/something"'''
return '<a href="{0}/user/{1}">{2}{3}</a>/{4}'.format(
return '<a target="_top" href="{0}/user/{1}">{2}{3}</a>/{4}'.format(
cherrypy.request.base+cherrypy.request.script_name,
cherrypy.request.base+cherrypy.request.script_name, user, at_char, user.lower(), list_name)
@ -45,47 +45,47 @@ def format_trending(twister,num_messages=8): @@ -45,47 +45,47 @@ def format_trending(twister,num_messages=8):
### The Swizzler app
class SwizzlerApp(object):
def _standard_params(self,twister,q,num_items=8):
@cherrypy.expose
def search(self,q=''):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
result = {'site_root':cherrypy.request.base+cherrypy.request.script_name}
result['here'] = result['site_root']+cherrypy.request.path_info
q=(q or '').strip().split(' ')[0] # ignore anything after the first space if any
q = q.strip().split(' ')[0] # ignore anything after the first space if any
if q.startswith('#'): # user said "#sometag", change to "sometag"
q=q[1:]
if q and not q.startswith('@'): # Tag. redirect.
raise cherrypy.HTTPRedirect(result['site_root']+'/tag/{0}'.format(q))
if q:
result['user_prefix'] = q
result['users'] = twister.get_users_by_partial_name(q[1:],num_items)
return result
result['trending'] = format_trending(twister,num_items)
return result
result['users'] = twister.get_users_by_partial_name(q[1:],conf['num_messages'])
else:
result['trending'] = format_trending(twister,conf['num_messages'])
return stache.render(stache.load_template('search'),result)
@cherrypy.expose
def twist(self,username,k,q=None):
def twist(self,username,k):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
twist = twister.get_twist(username,k)
twist['style_large'] = True
rts = twister.get_twist_rts(username,k)
print rts
result = {
'is_twist':True,
'title':u"@{0}: {1} - Swizzler".format(twist['user']['username'],twist['time']),
'title':u"@{0}: {1} - Swizzler".format(username,twist['time']),
'twist':twist,
'in_reply_to':twist.get('reply') and twister.get_twist(twist['reply']['user']['username'],twist['reply']['k']) or None,
'in_reply_to':twist.get('reply') and twister.get_twist(twist['reply']['username'],twist['reply']['k']) or None,
'replies':twister.get_twist_replies(username,k),
'rts':rts,
'any_rts':not not rts,
'local_users':twister.local_user_menu()['users'],
'info':twister.get_info(),
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('twist'),result)
@cherrypy.expose
def user(self,username,q=None):
def user(self,username):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
user = twister.get_user_info(username)
messages = twister.get_user_posts(username,conf['num_messages'])
result = {
@ -96,14 +96,26 @@ class SwizzlerApp(object): @@ -96,14 +96,26 @@ class SwizzlerApp(object):
'any_messages':not not messages,
'local_users':twister.local_user_menu()['users'],
'info':twister.get_info(),
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('standard'),result)
@cherrypy.expose
def tag(self,tag,q=None):
def user_embed(self,username='nobody',style='normal'):
if username=='nobody': username='' # to enable /nobody/large
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
user = twister.get_user_info(username)
result = {
'title':'@{0} - Swizzler'.format(username),
'site_root':cherrypy.request.base+cherrypy.request.script_name,
'user':twister.get_user_info(username)
}
result['style_{0}'.format(style)] = True
return stache.render(stache.load_template('user-iframe'),result)
@cherrypy.expose
def tag(self,tag):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
messages = twister.get_tag_posts(tag)
result = {
'is_tag':True,
@ -113,15 +125,13 @@ class SwizzlerApp(object): @@ -113,15 +125,13 @@ class SwizzlerApp(object):
'any_messages':not not messages,
'local_users':twister.local_user_menu()['users'],
'info':twister.get_info(),
#the filter avoids some utf etc. that ttf can't handle (TODO: fix or replace format_twist)
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('standard'),result)
@cherrypy.expose
def home(self,localusername,mode='feed',q=None):
def home(self,localusername,mode='feed'):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
menu = twister.local_user_menu(localusername)
if mode=='mentions':
messages = twister.get_user_mentions(localusername)
@ -131,20 +141,19 @@ class SwizzlerApp(object): @@ -131,20 +141,19 @@ class SwizzlerApp(object):
'is_home':True,
'is_mentions':mode=='mentions',
'is_feed':mode!='mentions',
'title':u"{fullname} (@{username}): Home - Swizzler".format(**menu['active']),
'title':u"{fullname} (@{username}): {mode} - Swizzler".format(mode=mode=='mentions' and 'Mentions' or 'Home',**menu['active']),
'local_users':menu['users'],
'info':twister.get_info(),
'subject':menu['active'],
'messages':messages,
'any_messages':not not messages,
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('standard'),result)
@cherrypy.expose
def messages(self,localusername,remoteusername=None,q=None):
def messages(self,localusername,remoteusername=None):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
localuser = twister.get_user_info(localusername)
remoteuser = remoteusername and twister.get_user_info(remoteusername) or None
threads = remoteusername and twister.get_user_messages(localusername,remoteusername,conf['num_messages']) or twister.get_user_messages(localusername)
@ -158,18 +167,17 @@ class SwizzlerApp(object): @@ -158,18 +167,17 @@ class SwizzlerApp(object):
'any_threads':not not threads,
'local_users':twister.local_user_menu()['users'],
'info':twister.get_info(),
#the filter avoids some utf etc. that ttf can't handle (TODO: fix or replace format_twist)
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('messages'),result)
@cherrypy.expose
def index(self,q=None):
def index(self):
conf = cherrypy.request.app.config['swizzler']
twister = Twister(conf['rpc_url'],format_twist)
params = self._standard_params(twister,q,conf['num_messages']) # called as soon as possible, because it might raise a redirect
messages = twister.get_sponsored_posts(conf['num_messages'])
result = {
'is_user':True, # i.e. we want to display "bio" and not mentions/DMs/profile buttons
'is_sponsored':True, # message template needs to know not to show "permalink"
'title':"Welcome to Swizzler",
'local_users':twister.local_user_menu('')['users'], # '' means: "Nobody" is active
'info':twister.get_info(),
@ -184,9 +192,8 @@ Start mining today, and all this (AND moral satisfaction) can be yours.""") @@ -184,9 +192,8 @@ Start mining today, and all this (AND moral satisfaction) can be yours.""")
},
'messages':messages,
'any_messages':not not messages,
#the filter avoids some utf etc. that ttf can't handle (TODO: fix or replace format_twist)
'site_root':cherrypy.request.base+cherrypy.request.script_name,
}
result.update(params)
return stache.render(stache.load_template('standard'),result)
if __name__ == '__main__':

3
templates/footer.html

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
<footer id="footer">
<div class="alert alert-info"><a target="_blank" href="https://github.com/swizzler/swizzler#readme"><strong>Fork</strong></a> this. Swizzler is <a target="_blank" href="http://www.gnu.org/licenses/agpl-3.0.html"><strong>AGPLV3</strong></a>.</span>
<a class="btn btn-primary btn-sm" title="Scroll to navigation" href="#localusers"><span class="glyphicon glyphicon-th-list"></span></a>
<a class="badge" target="_blank" title="Fork it like you mean it" href="https://github.com/swizzler/swizzler#readme"><span class="glyphicon glyphicon-wrench"></a>
</footer>

66
templates/message.html

@ -1,45 +1,37 @@ @@ -1,45 +1,37 @@
<li class="list-group-item media">
{{#user}}
<iframe class="thumbnail media-object {{#fromMe}}pull-right{{/fromMe}}{{^fromMe}}pull-left{{/fromMe}}"
style="border:none; padding:0; background:none; overflow:hidden"
width=33% height={{#style_large}}96{{/style_large}}{{^style_large}}72{{/style_large}} seamless=seamless
src="{{site_root}}/user_embed/{{username}}{{^username}}nobody{{/username}}{{#style_large}}/large{{/style_large}}{{#fromMe}}/from_me{{/fromMe}}"></iframe>
<div class="media-body">
{{#username}}
<a class="{{#fromMe}}pull-right{{/fromMe}}{{^fromMe}}pull-left{{/fromMe}} thumbnail" href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile">
<img class="media-object avatar" src="{{#avatar}}{{.}}{{/avatar}}{{^avatar}}/assets/img/genericPerson.png{{/avatar}}" alt="{{fullname}}">
</a>
<h5 class="media-heading">
{{^threads}}
<span class="pull-right small">
{{^is_sponsored}}<a title="View twist details" href="{{site_root}}/twist/{{.}}/{{k}}">{{/is_sponsored}}{{time}}{{^is_sponsored}}</a>{{/is_sponsored}}
</span>
{{/threads}}
{{#rt_username}}
<small>
<a href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile">@{{.}}</a>
<span class="glyphicon glyphicon-retweet"></span>
</small>
{{/rt_username}}
<a href="{{site_root}}/user/{{username}}" title="@{{username}}'s profile"><strong>@{{username}}</strong></a>
{{^is_twist}}{{#reply}}
<small>
<span class="glyphicon glyphicon-share-alt"></span>
<a title="Re: @{{username}}'s twist" href="{{site_root}}/twist/{{username}}/{{k}}">@{{username}}</a>
</small>
{{/reply}}{{/is_twist}}
</h5>
{{/username}}
{{^username}}
<a class="pull-left thumbnail" href="#">
<img class="media-object avatar" src="{{site_root}}/assets/img/twister-64.jpg" alt="{{fullname}}">
</a>
<h5 class="media-heading">
<span class="pull-right small">{{time}}</span>
<a href="{{site_root}}/">@{{username}}</a>
</h5>
{{/username}}
{{/user}}
<div class="media-body">
{{#user}}
{{#username}}
<h5 class="media-heading">
<span class="pull-right small">
<a title="View twist details" href="{{site_root}}/twist/{{.}}/{{k}}">{{time}}</a>
</span>
{{#rt_user}}
<small>
<a href="{{site_root}}/user/{{username}}" title="@{{username}}'s profile">{{fullname}}</a>
<span class="glyphicon glyphicon-retweet"></span>
</small>
{{/rt_user}}
<a href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile"><strong>{{fullname}}</strong></a>
{{^is_twist}}{{#reply}}
<small>
<span class="glyphicon glyphicon-share-alt"></span>
{{#user}}<a title="Re: @{{username}}'s twist" href="{{site_root}}/twist/{{username}}/{{k}}">{{fullname}}</a>{{/user}}
</small>
{{/reply}}{{/is_twist}}
</h5>
{{/username}}
{{^username}}
<h5 class="media-heading">
<span class="pull-right small">{{time}}</span>
<a href="{{site_root}}/">{{fullname}}</a>
</h5>
{{/username}}
{{/user}}
{{{message}}}
</div>
</li>

40
templates/messages.html

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<!DOCTYPE html>
<html language="{{lang}}">
<html language="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -22,22 +22,18 @@ @@ -22,22 +22,18 @@
<img class="media-object avatar" src="{{#avatar}}{{.}}{{/avatar}}{{^avatar}}/assets/img/twister-64.jpg{{/avatar}}" alt="{{fullname}}">
</a>
<div class="media-body">
<h4 class="media-heading">
<a href="{{site_root}}/messages/{{username}}{{#remoteuser}}/{{username}}{{/remoteuser}}"
<h3 class="media-heading">
<a class="label label-primary" href="{{site_root}}/messages/{{username}}{{#remoteuser}}/{{username}}{{/remoteuser}}"
title="@{{username}}'s messages{{#remoteuser}} with {{username}}{{/remoteuser}}"
><span class="glyphicon glyphicon-envelope"></span></a>
><span class="glyphicon glyphicon-envelope"></span>
{{fullname}}'s direct messages
{{#remoteuser}}with {{fullname}}{{/remoteuser}}
{{#remoteuser}}with {{fullname}}{{/remoteuser}}</a>
</h3>
<h4>
<a class="label label-primary" href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span> Home</a>
<a class="label label-primary" href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span> Mentions</a>
<a class="label label-info" href="{{site_root}}/user/{{username}}" title="@{{username}}'s profile"><span class="glyphicon glyphicon-user"></span> Profile</a>
</h4>
{{#remoteuser}}
{{#subject}}
<a href="{{site_root}}/messages/{{username}}" title="Back to @{{username}}'s direct message summary"><span
class="glyphicon glyphicon-arrow-left"></span></a>
{{/subject}}
{{/remoteuser}}
<a href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span></a>
<a href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span></a>
<a href="{{site_root}}/user/{{username}}" title="@{{username}}'s profile"><span class="glyphicon glyphicon-user"></span></a>
</div>
</div>
{{/subject}}
@ -49,21 +45,13 @@ @@ -49,21 +45,13 @@
<ul class="list-group media-list">
{{#threads}}
{{^remoteuser}}
{{#user}}
<div class="label label-info">
<a href="{{site_root}}/messages/{{subject.username}}/{{username}}" title="See more messages to/from @{{username}}">{{fullname}}</a>
<a href="{{site_root}}/messages/{{subject.username}}/{{username}}" title="See more messages to/from @{{username}}"><span
class="glyphicon glyphicon-arrow-right"></span></a>
</div>
{{/user}}
<a class="label label-primary" href="{{site_root}}/messages/{{subject.username}}/{{username}}"
title="See more messages to/from @{{username}}">@{{username}} <span class="glyphicon glyphicon-arrow-right"></span></a>
{{/remoteuser}}
{{#remoteuser}}
{{#subject}}
<div class="label label-info">
<a href="{{site_root}}/messages/{{subject.username}}" title="Back to @{{username}}'s direct message summary"><span
class="glyphicon glyphicon-arrow-left"></span></a>
<a href="{{site_root}}/messages/{{subject.username}}" title="Back to @{{username}}'s direct message summary">Back</a>
</div>
<a class="label label-primary" href="{{site_root}}/messages/{{subject.username}}"
title="Back to @{{username}}'s direct message summary"><span class="glyphicon glyphicon-arrow-left"></span> Back</a>
{{/subject}}
{{/remoteuser}}
<ul class="list-group media-list">

37
templates/sidebar.html

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
<div class="panel panel-primary">
<div id="localusers" class="panel panel-primary">
<div class="panel-heading">
{{#info}}
<div class="pull-right badge">Peers: {{dht_nodes}}/{{dht_global_nodes}}</div>
{{/info}}
<h3 class="panel-title"><span class="glyphicon glyphicon-home"></span> Local users</h3>
<h3 class="panel-title"><span class="glyphicon glyphicon-th-list"></span> Local users</h3>
</div>
<ul class="panel-body list-group media-list">
{{#local_users}}
@ -18,17 +18,15 @@ @@ -18,17 +18,15 @@
href="{{site_root}}/{{#username}}home/{{.}}{{/username}}">{{/active}}{{fullname}}{{^active}}</a>
{{/active}}
</h5>
{{^active}}
{{#username}}
<a href="{{site_root}}/home/{{.}}" title="@{{.}}'s home"><span class="glyphicon glyphicon-home"></span></a>
<a href="{{site_root}}/home/{{.}}/mentions" title="mentions of @{{.}}"><span class="glyphicon glyphicon-bell"></span></a>
<a href="{{site_root}}/messages/{{.}}" title="direct messages from/to @{{.}}"><span class="glyphicon glyphicon-envelope"></span></a>
<a href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile"><span class="glyphicon glyphicon-user"></span></a>
<a class="label label-primary" href="{{site_root}}/home/{{.}}" title="@{{.}}'s home"><span class="glyphicon glyphicon-home"></span></a>
<a class="label label-primary" href="{{site_root}}/home/{{.}}/mentions" title="mentions of @{{.}}"><span class="glyphicon glyphicon-bell"></span></a>
<a class="label label-primary" href="{{site_root}}/messages/{{.}}" title="direct messages from/to @{{.}}"><span class="glyphicon glyphicon-envelope"></span></a>
<a class="label label-info" href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile"><span class="glyphicon glyphicon-user"></span></a>
{{/username}}
{{^username}}
(view sponsored posts)
{{/username}}
{{/active}}
</div>
</li>
{{/local_users}}
@ -37,27 +35,16 @@ @@ -37,27 +35,16 @@
<div class="panel panel-primary">
<div class="panel-heading">
<form method=get action="{{here}}" class="inline-form" role="search">
<form target="searchresult" tag="searchresult" method=get action="{{site_root}}/search" class="inline-form" role="search">
<div class="form-group">
<label for="#search"><span class="glyphicon glyphicon-search"></span> Search for tag or partial username</label>
<input id="q" name="q" type="text" class="form-control" placeholder="#twister or @twi"{{#user_prefix}} value="{{.}}"{{/user_prefix}}>
</div>
</form>
</div>
<div class="panel-body">
{{#user_prefix}}
<div class="label label-primary"><span class="glyphicon glyphicon-tags"></span> User prefix search: <strong><em>{{user_prefix}}</em></strong></div>
<ul class="list-group">
{{#users}}<li class="list-group-item"><a href="{{site_root}}/user/{{.}}" title="@{{.}}'s profile">@{{.}}</a></li>{{/users}}
{{^users}}<li class="list-group-item"><h3><small>Nothing. Nada. Rien de rien. &#128557;</small></h3>{{/users}}
</ul>
{{/user_prefix}}
{{^user_prefix}}
<div class="label label-primary"><span class="glyphicon glyphicon-tags"></span> Trending tags</div>
<ul class="list-group">
{{#trending}}<li class="list-group-item">{{{.}}}</li>{{/trending}}
{{^trending}}<li class="list-group-item"><h3>Can't find trending tags. <small>Nothing. Nada. Rien de rien. &#128557;</small></h3>{{/trending}}
</ul>
{{/user_prefix}}
</div>
</div>
<iframe name="searchresult" class="thumbnail media-object {{#fromMe}}pull-right{{/fromMe}}{{^fromMe}}pull-left{{/fromMe}}"
style="width:100%; border:none; padding:0; background:none; overflow:hidden"
width=100 height=2645 seamless=seamless
src="{{site_root}}/search"></iframe>
</div>

40
templates/standard.html

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<!DOCTYPE html>
<html language="{{lang}}">
<html language="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -24,34 +24,40 @@ @@ -24,34 +24,40 @@
<div class="media-body">
{{#is_home}}
{{#username}}
<h4 class="media-heading">
<h3 class="media-heading">
{{#is_feed}}
<a href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span></a> {{fullname}}
<a class="label label-primary" href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span>
{{fullname}}'s home</a>
{{/is_feed}}
{{#is_mentions}}
<a href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span></a> {{fullname}}
<a class="label label-primary" href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span>
Mentions of {{fullname}}</a>
{{/is_mentions}}
{{#is_messages}}
<a href="{{site_root}}/messages/{{username}}" title="direct messages to/from @{{username}}"><span class="glyphicon glyphicon-envelope"></span></a> {{fullname}}
<a class="label label-primary" href="{{site_root}}/messages/{{username}}" title="direct messages to/from @{{username}}"><span class="glyphicon glyphicon-envelope"></span>
{{fullname}}</a>
{{/is_messages}}
</h3>
<h4>
{{^is_feed}}
<a class="label label-primary" href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span>Home</a>
{{/is_feed}}
{{^is_mentions}}
<a class="label label-primary" href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span>Mentions</a>
{{/is_mentions}}
{{^is_messages}}
<a class="label label-primary" href="{{site_root}}/messages/{{username}}" title="direct messages from/to @{{username}}"><span class="glyphicon glyphicon-envelope"></span>Messages</a>
{{/is_messages}}
<a class="label label-info" href="{{site_root}}{{#username}}/user/{{.}}{{/username}}" title="@{{username}}'s profile"><span class="glyphicon glyphicon-user"></span>Profile</a>
</h4>
{{^is_feed}}
<a href="{{site_root}}/home/{{username}}" title="@{{username}}'s home"><span class="glyphicon glyphicon-home"></span></a>
{{/is_feed}}
{{^is_mentions}}
<a href="{{site_root}}/home/{{username}}/mentions" title="mentions of @{{username}}"><span class="glyphicon glyphicon-bell"></span></a>
{{/is_mentions}}
{{^is_messages}}
<a href="{{site_root}}/messages/{{username}}" title="direct messages from/to @{{username}}"><span class="glyphicon glyphicon-envelope"></span></a>
{{/is_messages}}
<a href="{{site_root}}/user/{{username}}" title="@{{username}}'s profile"><span class="glyphicon glyphicon-user"></span></a>
{{/username}}
{{/is_home}}
{{#is_user}}
<h4 class="media-heading">
{{#location}}<span class="pull-right small">{{.}}</span>{{/location}}
{{fullname}}
{{#url}}<small><a href="{{.}}">{{.}}</a></small>{{/url}}</h4>
<a class="label label-primary" href="{{site_root}}/user/{{username}}"><span class="glyphicon glyphicon-user"></span>
{{fullname}}</a>
{{#url}}<small><a target="_blank" href="{{.}}">{{.}}</a></small>{{/url}}</h4>
{{{bio}}}
{{/is_user}}
{{#is_tag}}

16
templates/twist.html

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<!DOCTYPE html>
<html language="{{lang}}">
<html language="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -28,14 +28,12 @@ @@ -28,14 +28,12 @@
{{#any_rts}}
<div class="avatars32">
<h5 class="pull-left"><span class="glyphicon glyphicon-retweet"></span> Retwists:&nbsp;</h5>{{! I know it's ugly. I suck at CSS !}}
{{#rts}}{{#rt_user}}
<div class="thumbnail pull-left">
<a href="{{site_root}}/user/{{username}}" title="Retwisted by {{fullname}} (@{{username}})">
<img class="media-object avatar" src="{{#avatar}}{{.}}{{/avatar}}{{^avatar}}/assets/img/genericPerson.png{{/avatar}}"
alt="Retwisted by {{fullname}} (@{{username}})">
</a>
</div>
{{/rt_user}}{{/rts}}
{{#rts}}
<iframe class="thumbnail pull-left"
style="border:none; padding:0; background:none; overflow:hidden"
width=84 height=72 seamless=seamless
src="{{site_root}}/user_embed/{{rt_username}}/rt"></iframe>
{{/rts}}
</div>
{{/any_rts}}
{{/twist}}

15
twister.py

@ -18,7 +18,7 @@ class Twister: @@ -18,7 +18,7 @@ class Twister:
db.shelve.sync()
def _format_reply(self,r):
"gracefully fails if reply is empty"
return r and {"user":self.get_user_info(r['n']),'k':r['k']} or {}
return r and {"user":self.get_user_info(r['n']),'username':r['n'],'k':r['k']} or {}
def _format_post_info(self,p):
result = {
"height":p['userpost']['height'],
@ -28,15 +28,18 @@ class Twister: @@ -28,15 +28,18 @@ class Twister:
if p['userpost'].has_key('rt'):
result.update({
"message":self._format_message(p['userpost']['rt']['msg']),
"user":self.get_user_info(p['userpost']['rt']['n']),
"username":p['userpost']['rt']['n'],
#"user":self.get_user_info(p['userpost']['rt']['n']), ### too heavy. we do it in an iframe
"k":p['userpost']['rt']['k'],
"rt_user":self.get_user_info(p['userpost']['n']),
"rt_username":p['userpost']['n'],
#"rt_user":self.get_user_info(p['userpost']['n']), ### too heavy. we do it in an iframe
"reply":self._format_reply(p['userpost']['rt'].get('reply',{})),
})
else:
result.update({
"message":self._format_message(p['userpost']['msg']),
"user":self.get_user_info(p['userpost']['n']),
"username":p['userpost']['n'],
#"user":self.get_user_info(p['userpost']['n']), ### too heavy. we do it in an iframe
"k":p['userpost']['k'],
"reply":self._format_reply(p['userpost'].get('reply',{})),
})
@ -47,6 +50,7 @@ class Twister: @@ -47,6 +50,7 @@ class Twister:
if p:
return self._format_post_info(p[0]['p']['v'])
raise SkipCache("Twist not found @{0}/{1}".format(username,k),{
"username":"",
"user":self.get_user_info('nobody'),
"k":0, # maybe something needs this
"lastk":0, # or this
@ -125,10 +129,11 @@ class Twister: @@ -125,10 +129,11 @@ class Twister:
if message['time'] > latest_ts:
latest_ts = message['time']
message['time'] = timestamp2iso(message['time'])
message['username'] = message['fromMe'] and localusername or username
message['user'] = message['fromMe'] and localuser or user
message['message'] = self._format_message(message['text'])
messages.insert(0,message) # reverse order (newer first)
result.append({'user':user,'messages':messages,'latest_ts':latest_ts})
result.append({'username':username,'user':user,'messages':messages,'latest_ts':latest_ts})
return sorted(result,key=lambda thread:thread['latest_ts'],reverse=True)
@functioncache(60,ignore_instance=True)

Loading…
Cancel
Save