diff options
author | Evan Prodromou <evan@status.net> | 2009-09-24 17:22:51 -0400 |
---|---|---|
committer | Evan Prodromou <evan@status.net> | 2009-09-24 17:22:51 -0400 |
commit | 78cec7ab87c005e988dbd8176585ffad9182d25c (patch) | |
tree | 735c4755433140939e6b841f971a273c6a2f76f8 /plugins | |
parent | 8284b3cb82f4dec6e0f2bf74dea6e1a3bc7f4eac (diff) | |
parent | 49bce941a9aae495ee7221bd367791227487b458 (diff) |
Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 0.9.x
Conflicts:
install.php
lib/noticeform.php
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Autocomplete/autocomplete.php | 54 | ||||
-rw-r--r-- | plugins/Meteor/meteorupdater.js | 43 | ||||
-rw-r--r-- | plugins/PiwikAnalyticsPlugin.php | 2 | ||||
-rw-r--r-- | plugins/Realtime/RealtimePlugin.php | 184 | ||||
-rw-r--r-- | plugins/Realtime/realtimeupdate.js | 273 |
5 files changed, 353 insertions, 203 deletions
diff --git a/plugins/Autocomplete/autocomplete.php b/plugins/Autocomplete/autocomplete.php index 4379a86f2..aa57b3915 100644 --- a/plugins/Autocomplete/autocomplete.php +++ b/plugins/Autocomplete/autocomplete.php @@ -47,10 +47,48 @@ class AutocompleteAction extends Action { private $result; + /** + * Last-modified date for page + * + * When was the content of this page last modified? Based on notice, + * profile, avatar. + * + * @return int last-modified date as unix timestamp + */ + function lastModified() + { + $max=0; + foreach($this->users as $user){ + $max = max($max,strtotime($user->modified),strtotime($user->profile->modified)); + } + foreach($this->groups as $group){ + $max = max($max,strtotime($group->modified)); + } + return $max; + } + + /** + * An entity tag for this page + * + * Shows the ETag for the page, based on the notice ID and timestamps + * for the notice, profile, and avatar. It's weak, since we change + * the date text "one hour ago", etc. + * + * @return string etag + */ + function etag() + { + return '"' . implode(':', array($this->arg('action'), + crc32($this->arg('q')), //the actual string can have funny characters in we don't want showing up in the etag + $this->arg('limit'), + $this->lastModified())) . '"'; + } + function prepare($args) { parent::prepare($args); - $this->results = array(); + $this->groups=array(); + $this->users=array(); $q = $this->arg('q'); $limit = $this->arg('limit'); if($limit > 200) $limit=200; //prevent DOS attacks @@ -63,7 +101,8 @@ class AutocompleteAction extends Action $user->find(); while($user->fetch()) { $profile = Profile::staticGet($user->id); - $this->results[]=array('nickname' => $user->nickname, 'fullname'=> $profile->fullname, 'type'=>'user'); + $user->profile=$profile; + $this->users[]=$user; } } if(substr($q,0,1)=='!'){ @@ -74,7 +113,7 @@ class AutocompleteAction extends Action $group->whereAdd('nickname like \'' . trim($group->escape($q), '\'') . '%\''); $group->find(); while($group->fetch()) { - $this->results[]=array('nickname' => $group->nickname, 'fullname'=> $group->fullname, 'type'=>'group'); + $this->groups[]=$group; } } return true; @@ -83,7 +122,14 @@ class AutocompleteAction extends Action function handle($args) { parent::handle($args); - foreach($this->results as $result) { + $results = array(); + foreach($this->users as $user){ + $results[]=array('nickname' => $user->nickname, 'fullname'=> $user->profile->fullname, 'type'=>'user'); + } + foreach($this->groups as $group){ + $results[]=array('nickname' => $group->nickname, 'fullname'=> $group->fullname, 'type'=>'group'); + } + foreach($results as $result) { print json_encode($result) . "\n"; } } diff --git a/plugins/Meteor/meteorupdater.js b/plugins/Meteor/meteorupdater.js index 91d12cde9..9ce68775b 100644 --- a/plugins/Meteor/meteorupdater.js +++ b/plugins/Meteor/meteorupdater.js @@ -4,34 +4,19 @@ var MeteorUpdater = function() { - return { - - init: function(server, port, timeline) - { - Meteor.callbacks["process"] = function(data) { - var d = JSON.parse(data); - - var user_url = $('address .url')[0].href+d['user']['screen_name']; - - var wlh = window.location.href; - - if (wlh.indexOf('?') > 0) { - wlh = wlh.slice(0, wlh.indexOf('?')) - } - - if (timeline == 'public' || - user_url+'/all' == wlh || - user_url == wlh) { - - RealtimeUpdate.receive(d); - } - }; - - Meteor.host = server; - Meteor.port = port; - Meteor.joinChannel(timeline, 0); - Meteor.connect(); - } - } + return { + + init: function(server, port, timeline) + { + Meteor.callbacks["process"] = function(data) { + RealtimeUpdate.receive(JSON.parse(data)); + }; + + Meteor.host = server; + Meteor.port = port; + Meteor.joinChannel(timeline, 0); + Meteor.connect(); + } + } }(); diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php index e36bd1c5c..8191f5181 100644 --- a/plugins/PiwikAnalyticsPlugin.php +++ b/plugins/PiwikAnalyticsPlugin.php @@ -73,7 +73,7 @@ class PiwikAnalyticsPlugin extends Plugin function __construct($root=null, $id=null) { $this->piwikroot = $root; - $this->piwikid = $id; + $this->piwikId = $id; parent::__construct(); } diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index 611b1d86c..e30c41156 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -50,6 +50,11 @@ class RealtimePlugin extends Plugin protected $favorurl = null; protected $deleteurl = null; + /** + * When it's time to initialize the plugin, calculate and + * pass the URLs we need. + */ + function onInitializePlugin() { $this->replyurl = common_local_url('newnotice'); @@ -57,31 +62,26 @@ class RealtimePlugin extends Plugin // FIXME: need to find a better way to pass this pattern in $this->deleteurl = common_local_url('deletenotice', array('notice' => '0000000000')); + return true; } function onEndShowScripts($action) { - $path = null; + $timeline = $this->_getTimeline($action); - $a = $action->trimmed('action'); - - switch ($a) { - case 'public': case 'all': case 'replies': case 'showstream': - $path = array($a); - break; - case 'tag': - $tag = $action->trimmed('tag'); - if (!empty($tag)) { - $path = array('tag', $tag); - } else { - return true; - } - break; - default: - return true; + // If there's not a timeline on this page, + // just return true + + if (empty($timeline)) { + return true; } - $timeline = $this->_pathToChannel($path); + $base = $action->selfUrl(); + if (mb_strstr($base, '?')) { + $url = $base . '&realtime=1'; + } else { + $url = $base . '?realtime=1'; + } $scripts = $this->_getScripts(); @@ -97,16 +97,22 @@ class RealtimePlugin extends Plugin $user_id = 0; } - $action->script('plugins/Realtime/jquery.getUrlParam.js'); + if ($action->boolean('realtime')) { + $realtimeUI = ' RealtimeUpdate.initPopupWindow();'; + } + else { + $iconurl = common_path('plugins/Realtime/icon_external.gif'); + $realtimeUI = ' RealtimeUpdate.addPopup("'.$url.'", "'.$timeline.'", "'. $iconurl .'");'; + } $action->elementStart('script', array('type' => 'text/javascript')); - $action->raw(' - <!-- - $(document).ready(function() { - ' . $this->_updateInitialize($timeline, $user_id) . ' - }); - --> - '); + + $script = ' $(document).ready(function() { '. + $realtimeUI. + $this->_updateInitialize($timeline, $user_id). + '}); '; + $action->raw($script); + $action->elementEnd('script'); return true; @@ -116,15 +122,23 @@ class RealtimePlugin extends Plugin { $paths = array(); - // TODO: Replies timeline + // Add to the author's timeline + + $user = User::staticGet('id', $notice->profile_id); + + if (!empty($user)) { + $paths[] = array('showstream', $user->nickname); + } + + // Add to the public timeline if ($notice->is_local || ($notice->is_local == 0 && !common_config('public', 'localonly'))) { - foreach (array('public', 'all', 'replies', 'showstream') as $a) { - $paths[] = array($a); - } + $paths[] = array('public'); } + // Add to the tags timeline + $tags = $this->getNoticeTags($notice); if (!empty($tags)) { @@ -133,6 +147,46 @@ class RealtimePlugin extends Plugin } } + // Add to inbox timelines + // XXX: do a join + + $inbox = new Notice_inbox(); + $inbox->notice_id = $notice->id; + + if ($inbox->find()) { + while ($inbox->fetch()) { + $user = User::staticGet('id', $inbox->user_id); + $paths[] = array('all', $user->nickname); + } + } + + // Add to the replies timeline + + $reply = new Reply(); + $reply->notice_id = $notice->id; + + if ($reply->find()) { + while ($reply->fetch()) { + $user = User::staticGet('id', $reply->profile_id); + if (!empty($user)) { + $paths[] = array('replies', $user->nickname); + } + } + } + + // Add to the group timeline + // XXX: join + + $gi = new Group_inbox(); + $gi->notice_id = $notice->id; + + if ($gi->find()) { + while ($gi->fetch()) { + $ug = User_group::staticGet('id', $gi->group_id); + $paths[] = array('showgroup', $ug->nickname); + } + } + if (count($paths) > 0) { $json = $this->noticeAsJson($notice); @@ -150,6 +204,39 @@ class RealtimePlugin extends Plugin return true; } + function onStartShowBody($action) + { + $realtime = $action->boolean('realtime'); + if (!$realtime) { + return true; + } + + $action->elementStart('body', + (common_current_user()) ? array('id' => $action->trimmed('action'), + 'class' => 'user_in') + : array('id' => $action->trimmed('action'))); + + $action->elementStart('div', array('id' => 'header')); + + // XXX hack to deal with JS that tries to get the + // root url from page output + + $action->elementStart('address'); + $action->element('a', array('class' => 'url', + 'href' => common_local_url('public')), + ''); + $action->elementEnd('address'); + + if (common_logged_in()) { + $action->showNoticeForm(); + } + $action->elementEnd('div'); + + $action->showContentBlock(); + $action->elementEnd('body'); + return false; // No default processing + } + function noticeAsJson($notice) { // FIXME: this code should be abstracted to a neutral third @@ -234,4 +321,41 @@ class RealtimePlugin extends Plugin { return ''; } + + function _getTimeline($action) + { + $path = null; + $timeline = null; + + $action_name = $action->trimmed('action'); + + switch ($action_name) { + case 'public': + $path = array('public'); + break; + case 'tag': + $tag = $action->trimmed('tag'); + if (!empty($tag)) { + $path = array('tag', $tag); + } + break; + case 'showstream': + case 'all': + case 'replies': + case 'showgroup': + $nickname = common_canonical_nickname($action->trimmed('nickname')); + if (!empty($nickname)) { + $path = array($action_name, $nickname); + } + break; + default: + break; + } + + if (!empty($path)) { + $timeline = $this->_pathToChannel($path); + } + + return $timeline; + } } diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js index da2f9ed3a..57fe0a843 100644 --- a/plugins/Realtime/realtimeupdate.js +++ b/plugins/Realtime/realtimeupdate.js @@ -1,152 +1,147 @@ -$(document).ready(function() { - if (!$(document).getUrlParam('realtime')) { - $('#site_nav_local_views .current a').append('<button id="realtime_timeline" title="Pop this tab">↗</button>'); - - $('#realtime_timeline').css({ - 'margin':'2px 0 0 11px', - 'background':'transparent url('+$('address .url')[0].href+'/plugins/Realtime/icon_external.gif) no-repeat 45% 45%', - 'text-indent':'-9999px', - 'width':'16px', - 'height':'16px', - 'padding':'0', - 'display':'block', - 'float':'right', - 'border':'none', - 'cursor':'pointer' - }); - - $('#realtime_timeline').click(function() { - window.open($(this).parent('a').attr('href')+'?realtime=1', - $(this).parent('a').attr('title'), - 'toolbar=no,resizable=yes,scrollbars=yes,status=yes'); - - return false; - }); - } - else { - window.resizeTo(575, 640); - address = $('address'); - content = $('#content'); - $('body').html(address); - $('address').hide(); - $('body').append(content); - $('#content').css({'width':'92%'}); - } - - - // add a notice encoded as JSON into the current timeline - // - // TODO: i18n - - RealtimeUpdate = { - _userid: 0, - _replyurl: '', - _favorurl: '', - _deleteurl: '', - - init: function(userid, replyurl, favorurl, deleteurl) - { - RealtimeUpdate._userid = userid; - RealtimeUpdate._replyurl = replyurl; - RealtimeUpdate._favorurl = favorurl; - RealtimeUpdate._deleteurl = deleteurl; - }, - - receive: function(data) - { - id = data.id; - - // Don't add it if it already exists - - if ($("#notice-"+id).length > 0) { - return; - } - - var noticeItem = RealtimeUpdate.makeNoticeItem(data); - $("#notices_primary .notices").prepend(noticeItem, true); - $("#notices_primary .notice:first").css({display:"none"}); - $("#notices_primary .notice:first").fadeIn(1000); - NoticeReply(); - }, - - makeNoticeItem: function(data) - { - user = data['user']; - html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); - source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); - - ni = "<li class=\"hentry notice\" id=\"notice-"+data['id']+"\">"+ - "<div class=\"entry-title\">"+ - "<span class=\"vcard author\">"+ - "<a href=\""+user['profile_url']+"\" class=\"url\">"+ - "<img src=\""+user['profile_image_url']+"\" class=\"avatar photo\" width=\"48\" height=\"48\" alt=\""+user['screen_name']+"\"/>"+ - "<span class=\"nickname fn\">"+user['screen_name']+"</span>"+ - "</a>"+ - "</span>"+ - "<p class=\"entry-content\">"+html+"</p>"+ - "</div>"+ - "<div class=\"entry-content\">"+ - "<a class=\"timestamp\" rel=\"bookmark\" href=\""+data['url']+"\" >"+ - "<abbr class=\"published\" title=\""+data['created_at']+"\">a few seconds ago</abbr>"+ - "</a> "+ - "<span class=\"source\">"+ - "from "+ +// add a notice encoded as JSON into the current timeline +// +// TODO: i18n + +RealtimeUpdate = { + _userid: 0, + _replyurl: '', + _favorurl: '', + _deleteurl: '', + + init: function(userid, replyurl, favorurl, deleteurl) + { + RealtimeUpdate._userid = userid; + RealtimeUpdate._replyurl = replyurl; + RealtimeUpdate._favorurl = favorurl; + RealtimeUpdate._deleteurl = deleteurl; + }, + + receive: function(data) + { + id = data.id; + + // Don't add it if it already exists + // + if ($("#notice-"+id).length > 0) { + return; + } + + var noticeItem = RealtimeUpdate.makeNoticeItem(data); + $("#notices_primary .notices").prepend(noticeItem, true); + $("#notices_primary .notice:first").css({display:"none"}); + $("#notices_primary .notice:first").fadeIn(1000); + NoticeReply(); + }, + + makeNoticeItem: function(data) + { + user = data['user']; + html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); + source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); + + ni = "<li class=\"hentry notice\" id=\"notice-"+data['id']+"\">"+ + "<div class=\"entry-title\">"+ + "<span class=\"vcard author\">"+ + "<a href=\""+user['profile_url']+"\" class=\"url\">"+ + "<img src=\""+user['profile_image_url']+"\" class=\"avatar photo\" width=\"48\" height=\"48\" alt=\""+user['screen_name']+"\"/>"+ + "<span class=\"nickname fn\">"+user['screen_name']+"</span>"+ + "</a>"+ + "</span>"+ + "<p class=\"entry-content\">"+html+"</p>"+ + "</div>"+ + "<div class=\"entry-content\">"+ + "<a class=\"timestamp\" rel=\"bookmark\" href=\""+data['url']+"\" >"+ + "<abbr class=\"published\" title=\""+data['created_at']+"\">a few seconds ago</abbr>"+ + "</a> "+ + "<span class=\"source\">"+ + "from "+ "<span class=\"device\">"+source+"</span>"+ // may have a link - "</span>"; - if (data['in_reply_to_status_id']) { - ni = ni+" <a class=\"response\" href=\""+data['in_reply_to_status_url']+"\">in context</a>"; - } + "</span>"; + if (data['in_reply_to_status_id']) { + ni = ni+" <a class=\"response\" href=\""+data['in_reply_to_status_url']+"\">in context</a>"; + } - ni = ni+"</div>"+ + ni = ni+"</div>"+ "<div class=\"notice-options\">"; - if (RealtimeUpdate._userid != 0) { - var input = $("form#form_notice fieldset input#token"); - var session_key = input.val(); - ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key); - ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']); - if (RealtimeUpdate._userid == data['user']['id']) { + if (RealtimeUpdate._userid != 0) { + var input = $("form#form_notice fieldset input#token"); + var session_key = input.val(); + ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key); + ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']); + if (RealtimeUpdate._userid == data['user']['id']) { ni = ni+RealtimeUpdate.makeDeleteLink(data['id']); - } - } + } + } - ni = ni+"</div>"+ - "</li>"; - return ni; - }, + ni = ni+"</div>"+ + "</li>"; + return ni; + }, - makeFavoriteForm: function(id, session_key) - { - var ff; + makeFavoriteForm: function(id, session_key) + { + var ff; - ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+ + ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+ "<fieldset>"+ - "<legend>Favor this notice</legend>"+ - "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+ - "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+ - "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+ + "<legend>Favor this notice</legend>"+ + "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+ + "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+ + "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+ "</fieldset>"+ - "</form>"; - return ff; - }, - - makeReplyLink: function(id, nickname) - { - var rl; - rl = "<a class=\"notice_reply\" href=\""+RealtimeUpdate._replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span></a>"; - return rl; + "</form>"; + return ff; + }, + + makeReplyLink: function(id, nickname) + { + var rl; + rl = "<a class=\"notice_reply\" href=\""+RealtimeUpdate._replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span></a>"; + return rl; }, - makeDeleteLink: function(id) - { - var dl, delurl; - delurl = RealtimeUpdate._deleteurl.replace("0000000000", id); - - dl = "<a class=\"notice_delete\" href=\""+delurl+"\" title=\"Delete this notice\">Delete</a>"; - - return dl; - } - } - -}); + makeDeleteLink: function(id) + { + var dl, delurl; + delurl = RealtimeUpdate._deleteurl.replace("0000000000", id); + + dl = "<a class=\"notice_delete\" href=\""+delurl+"\" title=\"Delete this notice\">Delete</a>"; + + return dl; + }, + + addPopup: function(url, timeline, iconurl) + { + $('#site_nav_local_views .current a').append('<button id="realtime_timeline" title="Real-time pop window">↗</button>'); + + $('#realtime_timeline').css({ + 'margin':'2px 0 0 11px', + 'background':'transparent url('+ iconurl + ') no-repeat 45% 45%', + 'text-indent':'-9999px', + 'width':'16px', + 'height':'16px', + 'padding':'0', + 'display':'block', + 'float':'right', + 'border':'none', + 'cursor':'pointer' + }); + + $('#realtime_timeline').click(function() { + window.open(url, + timeline, + 'toolbar=no,resizable=yes,scrollbars=yes,status=yes'); + + return false; + }); + }, + + initPopupWindow: function() + { + window.resizeTo(575, 640); + $('address').hide(); + $('#content').css({'width':'92%'}); + } +} |