Merge branch '1.0.x' into profile-fixups

* 1.0.x:
  For good measure; trip short error mode in earlier on ajax shownotice
  Realtime plugin: fix i18n, thumbnails, location display, OStatus server display, micro-apps display.
  'ajax' param on shownotice action so we can pull items in full html version for realtime
  Whoops, need to reset the background color on the aside.
  Realtime work in progress: switch makeNoticeData to async -- next we'll load fresh copies from server, maintaining proper language and plugin enhancements.
  Check the site minifications etting for realtime plugin; debugging aid.
This commit is contained in:
Zach Copley 2011-03-15 09:11:31 -07:00
commit 4f217a3133
6 changed files with 105 additions and 149 deletions

View File

@ -78,6 +78,9 @@ class ShownoticeAction extends OwnerDesignAction
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if ($this->boolean('ajax')) {
StatusNet::setApi(true);
}
$id = $this->arg('notice'); $id = $this->arg('notice');
@ -188,22 +191,26 @@ class ShownoticeAction extends OwnerDesignAction
{ {
parent::handle($args); parent::handle($args);
if ($this->notice->is_local == Notice::REMOTE_OMB) { if ($this->boolean('ajax')) {
if (!empty($this->notice->url)) { $this->showAjax();
$target = $this->notice->url; } else {
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) { if ($this->notice->is_local == Notice::REMOTE_OMB) {
// Old OMB posts saved the remote URL only into the URI field. if (!empty($this->notice->url)) {
$target = $this->notice->uri; $target = $this->notice->url;
} else { } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
// Shouldn't happen. // Old OMB posts saved the remote URL only into the URI field.
$target = false; $target = $this->notice->uri;
} } else {
if ($target && $target != $this->selfUrl()) { // Shouldn't happen.
common_redirect($target, 301); $target = false;
return false; }
if ($target && $target != $this->selfUrl()) {
common_redirect($target, 301);
return false;
}
} }
$this->showPage();
} }
$this->showPage();
} }
/** /**
@ -232,6 +239,21 @@ class ShownoticeAction extends OwnerDesignAction
$this->elementEnd('ol'); $this->elementEnd('ol');
} }
function showAjax()
{
header('Content-Type: text/xml;charset=utf-8');
$this->xw->startDocument('1.0', 'UTF-8');
$this->elementStart('html');
$this->elementStart('head');
$this->element('title', null, _('Notice'));
$this->elementEnd('head');
$this->elementStart('body');
$nli = new NoticeListItem($this->notice, $this);
$nli->show();
$this->elementEnd('body');
$this->elementEnd('html');
}
/** /**
* Don't show page notice * Don't show page notice
* *

View File

@ -1,9 +1,12 @@
As of StatusNet 1.0.x, actual formatting of the notices is done server-side,
loaded by AJAX after the real-time notification comes in. This has the drawback
that we may make extra HTTP requests and delay incoming notices a little, but
means that formatting and internationalization is consistent.
== TODO == == TODO ==
* i18n
* Update mark behaviour (on notice send) * Update mark behaviour (on notice send)
* Pause, Send a notice ~ should not update counter * Pause, Send a notice ~ should not update counter
* Pause ~ retain up to 50-100 most recent notices * Pause ~ retain up to 50-100 most recent notices
* Add geo data
* Make it work for Conversation page (perhaps a little tricky) * Make it work for Conversation page (perhaps a little tricky)
* IE is updating the counter in document title all the time (Not sure if this * IE is updating the counter in document title all the time (Not sure if this
is still an issue) is still an issue)

View File

@ -45,9 +45,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/ */
class RealtimePlugin extends Plugin class RealtimePlugin extends Plugin
{ {
protected $replyurl = null; protected $showurl = null;
protected $favorurl = null;
protected $deleteurl = null;
/** /**
* When it's time to initialize the plugin, calculate and * When it's time to initialize the plugin, calculate and
@ -56,11 +54,8 @@ class RealtimePlugin extends Plugin
function onInitializePlugin() function onInitializePlugin()
{ {
$this->replyurl = common_local_url('newnotice');
$this->favorurl = common_local_url('favor');
$this->repeaturl = common_local_url('repeat');
// FIXME: need to find a better way to pass this pattern in // FIXME: need to find a better way to pass this pattern in
$this->deleteurl = common_local_url('deletenotice', $this->showurl = common_local_url('shownotice',
array('notice' => '0000000000')); array('notice' => '0000000000'));
return true; return true;
} }
@ -323,7 +318,12 @@ class RealtimePlugin extends Plugin
function _getScripts() function _getScripts()
{ {
return array(Plugin::staticPath('Realtime', 'realtimeupdate.min.js')); if (common_config('site', 'minify')) {
$js = 'realtimeupdate.min.js';
} else {
$js = 'realtimeupdate.js';
}
return array(Plugin::staticPath('Realtime', $js));
} }
/** /**
@ -354,7 +354,7 @@ class RealtimePlugin extends Plugin
function _updateInitialize($timeline, $user_id) function _updateInitialize($timeline, $user_id)
{ {
return "RealtimeUpdate.init($user_id, \"$this->replyurl\", \"$this->favorurl\", \"$this->repeaturl\", \"$this->deleteurl\"); "; return "RealtimeUpdate.init($user_id, \"$this->showurl\"); ";
} }
function _connect() function _connect()

View File

@ -44,10 +44,7 @@
*/ */
RealtimeUpdate = { RealtimeUpdate = {
_userid: 0, _userid: 0,
_replyurl: '', _showurl: '',
_favorurl: '',
_repeaturl: '',
_deleteurl: '',
_updatecounter: 0, _updatecounter: 0,
_maxnotices: 50, _maxnotices: 50,
_windowhasfocus: true, _windowhasfocus: true,
@ -66,21 +63,15 @@ RealtimeUpdate = {
* feed data into the RealtimeUpdate object! * feed data into the RealtimeUpdate object!
* *
* @param {int} userid: local profile ID of the currently logged-in user * @param {int} userid: local profile ID of the currently logged-in user
* @param {String} replyurl: URL for newnotice action, used when generating reply buttons * @param {String} showurl: URL for shownotice action, used when fetching formatting notices.
* @param {String} favorurl: URL for favor action, used when generating fave buttons
* @param {String} repeaturl: URL for repeat action, used when generating repeat buttons
* @param {String} deleteurl: URL template for deletenotice action, used when generating delete buttons.
* This URL contains a stub value of 0000000000 which will be replaced with the notice ID. * This URL contains a stub value of 0000000000 which will be replaced with the notice ID.
* *
* @access public * @access public
*/ */
init: function(userid, replyurl, favorurl, repeaturl, deleteurl) init: function(userid, showurl)
{ {
RealtimeUpdate._userid = userid; RealtimeUpdate._userid = userid;
RealtimeUpdate._replyurl = replyurl; RealtimeUpdate._showurl = showurl;
RealtimeUpdate._favorurl = favorurl;
RealtimeUpdate._repeaturl = repeaturl;
RealtimeUpdate._deleteurl = deleteurl;
RealtimeUpdate._documenttitle = document.title; RealtimeUpdate._documenttitle = document.title;
@ -163,50 +154,51 @@ RealtimeUpdate = {
return; return;
} }
var noticeItem = RealtimeUpdate.makeNoticeItem(data); RealtimeUpdate.makeNoticeItem(data, function(noticeItem) {
var noticeItemID = $(noticeItem).attr('id'); var noticeItemID = $(noticeItem).attr('id');
var list = $("#notices_primary .notices:first") var list = $("#notices_primary .notices:first")
var prepend = true; var prepend = true;
var threaded = list.hasClass('threaded-notices'); var threaded = list.hasClass('threaded-notices');
if (threaded && data.in_reply_to_status_id) { if (threaded && data.in_reply_to_status_id) {
// aho! // aho!
var parent = $('#notice-' + data.in_reply_to_status_id); var parent = $('#notice-' + data.in_reply_to_status_id);
if (parent.length == 0) { if (parent.length == 0) {
// @todo fetch the original, insert it, and finish the rest // @todo fetch the original, insert it, and finish the rest
} else { } else {
// Check the parent notice to make sure it's not a reply itself. // Check the parent notice to make sure it's not a reply itself.
// If so, use it's parent as the parent. // If so, use it's parent as the parent.
var parentList = parent.closest('.notices'); var parentList = parent.closest('.notices');
if (parentList.hasClass('threaded-replies')) { if (parentList.hasClass('threaded-replies')) {
parent = parentList.closest('.notice'); parent = parentList.closest('.notice');
}
list = parent.find('.threaded-replies');
if (list.length == 0) {
list = $('<ul class="notices threaded-replies xoxo"></ul>');
parent.append(list);
}
prepend = false;
} }
list = parent.find('.threaded-replies');
if (list.length == 0) {
list = $('<ul class="notices threaded-replies xoxo"></ul>');
parent.append(list);
}
prepend = false;
} }
}
var newNotice = $(noticeItem); var newNotice = $(noticeItem);
if (prepend) { if (prepend) {
list.prepend(newNotice); list.prepend(newNotice);
} else {
var placeholder = list.find('li.notice-reply-placeholder')
if (placeholder.length > 0) {
newNotice.insertBefore(placeholder)
} else { } else {
newNotice.appendTo(list); var placeholder = list.find('li.notice-reply-placeholder')
SN.U.NoticeInlineReplyPlaceholder(parent); if (placeholder.length > 0) {
newNotice.insertBefore(placeholder)
} else {
newNotice.appendTo(list);
SN.U.NoticeInlineReplyPlaceholder(parent);
}
} }
} newNotice.css({display:"none"}).fadeIn(1000);
newNotice.css({display:"none"}).fadeIn(1000);
SN.U.NoticeReplyTo($('#'+noticeItemID)); SN.U.NoticeReplyTo($('#'+noticeItemID));
SN.U.NoticeWithAttachment($('#'+noticeItemID)); SN.U.NoticeWithAttachment($('#'+noticeItemID));
});
}, },
/** /**
@ -263,86 +255,24 @@ RealtimeUpdate = {
}, },
/** /**
* Builds a notice HTML block from JSON API-style data. * Builds a notice HTML block from JSON API-style data;
* loads data from server, so runs async.
* *
* @param {Object} data: extended JSON API-formatted notice * @param {Object} data: extended JSON API-formatted notice
* @return {String} HTML fragment * @param {function} callback: function(DOMNode) to receive new code
*
* @fixme this replicates core StatusNet code, making maintenance harder
* @fixme sloppy HTML building (raw concat without escaping)
* @fixme no i18n support
* @fixme local variables pollute global namespace
* *
* @access private * @access private
*/ */
makeNoticeItem: function(data) makeNoticeItem: function(data, callback)
{ {
if (data.hasOwnProperty('retweeted_status')) { var url = RealtimeUpdate._showurl.replace('0000000000', data.id);
original = data['retweeted_status']; $.get(url, {ajax: 1}, function(data, textStatus, xhr) {
repeat = data; var notice = $('li.notice:first', data);
data = original; if (notice.length) {
unique = repeat['id']; var node = document._importNode(notice[0], true);
responsible = repeat['user']; callback(node);
} else { }
original = null; });
repeat = null;
unique = data['id'];
responsible = data['user'];
}
user = data['user'];
html = data['html'].replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&amp;/g,'&');
source = data['source'].replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&amp;/g,'&');
ni = "<li class=\"hentry notice\" id=\"notice-"+unique+"\">"+
"<div class=\"entry-title\">"+
"<span class=\"vcard author\">"+
"<a href=\""+user['profile_url']+"\" class=\"url\" title=\""+user['name']+"\">"+
"<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['conversation_url']) {
ni = ni+" <a class=\"response\" href=\""+data['conversation_url']+"\">in context</a>";
}
if (repeat) {
ru = repeat['user'];
ni = ni + "<span class=\"repeat vcard\">Repeated by " +
"<a href=\"" + ru['profile_url'] + "\" class=\"url\">" +
"<span class=\"nickname\">"+ ru['screen_name'] + "</span></a></span>";
}
ni = ni+"</div>";
ni = ni + "<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 == responsible['id']) {
ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
} else if (RealtimeUpdate._userid != user['id']) {
ni = ni+RealtimeUpdate.makeRepeatForm(data['id'], session_key);
}
}
ni = ni+"</div>";
ni = ni+"</li>";
return ni;
}, },
/** /**

File diff suppressed because one or more lines are too long

View File

@ -392,6 +392,7 @@ address {
left: 802px; left: 802px;
padding: 22px 10px 40px 10px; padding: 22px 10px 40px 10px;
margin-top: 0px; margin-top: 0px;
background: none;
} }
#aside_primary .section { #aside_primary .section {