forked from GNUsocial/gnu-social
Merge remote branch 'origin/1.0.x' into 1.0.x
This commit is contained in:
commit
a63e1418a8
16
EVENTS.txt
16
EVENTS.txt
@ -1115,3 +1115,19 @@ StartGroupProfileElements: Start showing stuff about the group on its profile pa
|
||||
EndGroupProfileElements: Start showing stuff about the group on its profile page
|
||||
- $action: action being executed (for output and params)
|
||||
- $group: group for the page
|
||||
|
||||
StartActivityObjectOutputAtom: Called at start of Atom XML output generation for ActivityObject chunks, just inside the <activity:object>. Cancel the event to take over its output completely (you're responsible for calling the matching End event if so)
|
||||
- $obj: ActivityObject
|
||||
- $out: XMLOutputter to append custom output
|
||||
|
||||
EndActivityObjectOutputAtom: Called at end of Atom XML output generation for ActivityObject chunks, just inside the </activity:object>
|
||||
- $obj: ActivityObject
|
||||
- $out: XMLOutputter to append custom output
|
||||
|
||||
StartActivityObjectOutputJson: Called at start of JSON output generation for ActivityObject chunks: the array has not yet been filled out. Cancel the event to take over its output completely (you're responsible for calling the matching End event if so)
|
||||
- $obj ActivityObject
|
||||
- &$out: array to be serialized; you're free to modify it
|
||||
|
||||
EndActivityObjectOutputJson: Called at end of JSON output generation for ActivityObject chunks: the array has not yet been filled out.
|
||||
- $obj ActivityObject
|
||||
- &$out: array to be serialized; you're free to modify it
|
||||
|
50
js/util.js
50
js/util.js
@ -423,7 +423,6 @@ var SN = { // StatusNet
|
||||
.css({display:'none'})
|
||||
.fadeIn(2500);
|
||||
SN.U.NoticeWithAttachment($('#'+notice.id));
|
||||
SN.U.NoticeReplyTo($('#'+notice.id));
|
||||
SN.U.switchInputFormTab("placeholder");
|
||||
}
|
||||
} else {
|
||||
@ -516,34 +515,22 @@ var SN = { // StatusNet
|
||||
* @access private
|
||||
*/
|
||||
NoticeReply: function() {
|
||||
if ($('#content .notice_reply').length > 0) {
|
||||
$('#content .notice').each(function() { SN.U.NoticeReplyTo($(this)); });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup function -- DOES NOT trigger actions immediately.
|
||||
*
|
||||
* Sets up event handlers on the given notice's reply button to
|
||||
* tweak the new-notice form with needed variables and focus it
|
||||
* when pushed.
|
||||
*
|
||||
* (This replaces the default reply button behavior to submit
|
||||
* directly to a form which comes back with a specialized page
|
||||
* with the form data prefilled.)
|
||||
*
|
||||
* @param {jQuery} notice: jQuery object containing one or more notices
|
||||
* @access private
|
||||
*/
|
||||
NoticeReplyTo: function(notice) {
|
||||
notice.find('.notice_reply').live('click', function(e) {
|
||||
$('#content .notice_reply').live('click', function(e) {
|
||||
e.preventDefault();
|
||||
var notice = $(this).closest('li.notice');
|
||||
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
|
||||
SN.U.NoticeInlineReplyTrigger(notice, '@' + nickname.text());
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Stub -- kept for compat with plugins for now.
|
||||
* @access private
|
||||
*/
|
||||
NoticeReplyTo: function(notice) {
|
||||
},
|
||||
|
||||
/**
|
||||
* Open up a notice's inline reply box.
|
||||
*
|
||||
@ -640,26 +627,23 @@ var SN = { // StatusNet
|
||||
'<input class="placeholder">' +
|
||||
'</li>');
|
||||
placeholder.find('input')
|
||||
.val(SN.msg('reply_placeholder'))
|
||||
.focus(function() {
|
||||
SN.U.NoticeInlineReplyTrigger(notice);
|
||||
return false;
|
||||
});
|
||||
.val(SN.msg('reply_placeholder'));
|
||||
list.append(placeholder);
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup function -- DOES NOT apply immediately.
|
||||
*
|
||||
* Sets up event handlers for favor/disfavor forms to submit via XHR.
|
||||
* Sets up event handlers for inline reply mini-form placeholders.
|
||||
* Uses 'live' rather than 'bind', so applies to future as well as present items.
|
||||
*/
|
||||
NoticeInlineReplySetup: function() {
|
||||
$('.threaded-replies').each(function() {
|
||||
var list = $(this);
|
||||
var notice = list.closest('.notice');
|
||||
SN.U.NoticeInlineReplyPlaceholder(notice);
|
||||
});
|
||||
$('li.notice-reply-placeholder input')
|
||||
.live('focus', function() {
|
||||
var notice = $(this).closest('li.notice');
|
||||
SN.U.NoticeInlineReplyTrigger(notice);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
2
js/util.min.js
vendored
2
js/util.min.js
vendored
File diff suppressed because one or more lines are too long
@ -293,11 +293,19 @@ class Action extends HTMLOutputter // lawsuit
|
||||
{
|
||||
if (Event::handle('StartShowScripts', array($this))) {
|
||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||
$this->script('jquery.min.js');
|
||||
$this->script('jquery.form.min.js');
|
||||
$this->script('jquery.cookie.min.js');
|
||||
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.min.js').'"); }');
|
||||
$this->script('jquery.joverlay.min.js');
|
||||
if (common_config('site', 'minify')) {
|
||||
$this->script('jquery.min.js');
|
||||
$this->script('jquery.form.min.js');
|
||||
$this->script('jquery.cookie.min.js');
|
||||
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.min.js').'"); }');
|
||||
$this->script('jquery.joverlay.min.js');
|
||||
} else {
|
||||
$this->script('jquery.js');
|
||||
$this->script('jquery.form.js');
|
||||
$this->script('jquery.cookie.js');
|
||||
$this->inlineScript('if (typeof window.JSON !== "object") { $.getScript("'.common_path('js/json2.js').'"); }');
|
||||
$this->script('jquery.joverlay.js');
|
||||
}
|
||||
Event::handle('EndShowJQueryScripts', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||
|
@ -533,91 +533,95 @@ class ActivityObject
|
||||
$xo->elementStart($tag);
|
||||
}
|
||||
|
||||
$xo->element('activity:object-type', null, $this->type);
|
||||
if (Event::handle('StartActivityObjectOutputAtom', array($this, $xo))) {
|
||||
$xo->element('activity:object-type', null, $this->type);
|
||||
|
||||
// <author> uses URI
|
||||
// <author> uses URI
|
||||
|
||||
if ($tag == 'author') {
|
||||
$xo->element(self::URI, null, $this->id);
|
||||
} else {
|
||||
$xo->element(self::ID, null, $this->id);
|
||||
}
|
||||
|
||||
if (!empty($this->title)) {
|
||||
$name = common_xml_safe_str($this->title);
|
||||
if ($tag == 'author') {
|
||||
// XXX: Backward compatibility hack -- atom:name should contain
|
||||
// full name here, instead of nickname, i.e.: $name. Change
|
||||
// this in the next version.
|
||||
$xo->element(self::NAME, null, $this->poco->preferredUsername);
|
||||
$xo->element(self::URI, null, $this->id);
|
||||
} else {
|
||||
$xo->element(self::TITLE, null, $name);
|
||||
$xo->element(self::ID, null, $this->id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->summary)) {
|
||||
$xo->element(
|
||||
self::SUMMARY,
|
||||
null,
|
||||
common_xml_safe_str($this->summary)
|
||||
);
|
||||
}
|
||||
if (!empty($this->title)) {
|
||||
$name = common_xml_safe_str($this->title);
|
||||
if ($tag == 'author') {
|
||||
// XXX: Backward compatibility hack -- atom:name should contain
|
||||
// full name here, instead of nickname, i.e.: $name. Change
|
||||
// this in the next version.
|
||||
$xo->element(self::NAME, null, $this->poco->preferredUsername);
|
||||
} else {
|
||||
$xo->element(self::TITLE, null, $name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->content)) {
|
||||
// XXX: assuming HTML content here
|
||||
$xo->element(
|
||||
ActivityUtils::CONTENT,
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($this->content)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->link)) {
|
||||
$xo->element(
|
||||
'link',
|
||||
array(
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
'href' => $this->link
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->type == ActivityObject::PERSON
|
||||
|| $this->type == ActivityObject::GROUP) {
|
||||
|
||||
foreach ($this->avatarLinks as $avatar) {
|
||||
if (!empty($this->summary)) {
|
||||
$xo->element(
|
||||
'link', array(
|
||||
'rel' => 'avatar',
|
||||
'type' => $avatar->type,
|
||||
'media:width' => $avatar->width,
|
||||
'media:height' => $avatar->height,
|
||||
'href' => $avatar->url
|
||||
self::SUMMARY,
|
||||
null,
|
||||
common_xml_safe_str($this->summary)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->content)) {
|
||||
// XXX: assuming HTML content here
|
||||
$xo->element(
|
||||
ActivityUtils::CONTENT,
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($this->content)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->link)) {
|
||||
$xo->element(
|
||||
'link',
|
||||
array(
|
||||
'rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
'href' => $this->link
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->geopoint)) {
|
||||
$xo->element(
|
||||
'georss:point',
|
||||
null,
|
||||
$this->geopoint
|
||||
);
|
||||
}
|
||||
if ($this->type == ActivityObject::PERSON
|
||||
|| $this->type == ActivityObject::GROUP) {
|
||||
|
||||
if (!empty($this->poco)) {
|
||||
$this->poco->outputTo($xo);
|
||||
}
|
||||
foreach ($this->avatarLinks as $avatar) {
|
||||
$xo->element(
|
||||
'link', array(
|
||||
'rel' => 'avatar',
|
||||
'type' => $avatar->type,
|
||||
'media:width' => $avatar->width,
|
||||
'media:height' => $avatar->height,
|
||||
'href' => $avatar->url
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// @fixme there's no way here to make a tree; elements can only contain plaintext
|
||||
// @fixme these may collide with JSON extensions
|
||||
foreach ($this->extra as $el) {
|
||||
list($extraTag, $attrs, $content) = $el;
|
||||
$xo->element($extraTag, $attrs, $content);
|
||||
if (!empty($this->geopoint)) {
|
||||
$xo->element(
|
||||
'georss:point',
|
||||
null,
|
||||
$this->geopoint
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->poco)) {
|
||||
$this->poco->outputTo($xo);
|
||||
}
|
||||
|
||||
// @fixme there's no way here to make a tree; elements can only contain plaintext
|
||||
// @fixme these may collide with JSON extensions
|
||||
foreach ($this->extra as $el) {
|
||||
list($extraTag, $attrs, $content) = $el;
|
||||
$xo->element($extraTag, $attrs, $content);
|
||||
}
|
||||
|
||||
Event::handle('EndActivityObjectOutputAtom', array($this, $xo));
|
||||
}
|
||||
|
||||
if (!empty($tag)) {
|
||||
@ -647,94 +651,96 @@ class ActivityObject
|
||||
{
|
||||
$object = array();
|
||||
|
||||
// XXX: attachedObjects are added by Activity
|
||||
if (Event::handle('StartActivityObjectOutputJson', array($this, &$object))) {
|
||||
// XXX: attachedObjects are added by Activity
|
||||
|
||||
// displayName
|
||||
$object['displayName'] = $this->title;
|
||||
// displayName
|
||||
$object['displayName'] = $this->title;
|
||||
|
||||
// TODO: downstreamDuplicates
|
||||
// TODO: downstreamDuplicates
|
||||
|
||||
// embedCode (used for video)
|
||||
// embedCode (used for video)
|
||||
|
||||
// id
|
||||
//
|
||||
// XXX: Should we use URL here? or a crazy tag URI?
|
||||
$object['id'] = $this->id;
|
||||
// id
|
||||
//
|
||||
// XXX: Should we use URL here? or a crazy tag URI?
|
||||
$object['id'] = $this->id;
|
||||
|
||||
if ($this->type == ActivityObject::PERSON
|
||||
|| $this->type == ActivityObject::GROUP) {
|
||||
if ($this->type == ActivityObject::PERSON
|
||||
|| $this->type == ActivityObject::GROUP) {
|
||||
|
||||
// XXX: Not sure what the best avatar is to use for the
|
||||
// author's "image". For now, I'm using the large size.
|
||||
// XXX: Not sure what the best avatar is to use for the
|
||||
// author's "image". For now, I'm using the large size.
|
||||
|
||||
$avatarLarge = null;
|
||||
$avatarMediaLinks = array();
|
||||
$avatarLarge = null;
|
||||
$avatarMediaLinks = array();
|
||||
|
||||
foreach ($this->avatarLinks as $a) {
|
||||
foreach ($this->avatarLinks as $a) {
|
||||
|
||||
// Make a MediaLink for every other Avatar
|
||||
$avatar = new ActivityStreamsMediaLink(
|
||||
$a->url,
|
||||
$a->width,
|
||||
$a->height,
|
||||
$a->type,
|
||||
'avatar'
|
||||
);
|
||||
// Make a MediaLink for every other Avatar
|
||||
$avatar = new ActivityStreamsMediaLink(
|
||||
$a->url,
|
||||
$a->width,
|
||||
$a->height,
|
||||
$a->type,
|
||||
'avatar'
|
||||
);
|
||||
|
||||
// Find the big avatar to use as the "image"
|
||||
if ($a->height == AVATAR_PROFILE_SIZE) {
|
||||
$imgLink = $avatar;
|
||||
// Find the big avatar to use as the "image"
|
||||
if ($a->height == AVATAR_PROFILE_SIZE) {
|
||||
$imgLink = $avatar;
|
||||
}
|
||||
|
||||
$avatarMediaLinks[] = $avatar->asArray();
|
||||
}
|
||||
|
||||
$avatarMediaLinks[] = $avatar->asArray();
|
||||
$object['avatarLinks'] = $avatarMediaLinks; // extension
|
||||
|
||||
// image
|
||||
$object['image'] = $imgLink->asArray();
|
||||
}
|
||||
|
||||
$object['avatarLinks'] = $avatarMediaLinks; // extension
|
||||
// objectType
|
||||
//
|
||||
// We can probably use the whole schema URL here but probably the
|
||||
// relative simple name is easier to parse
|
||||
// @fixme this breaks extension URIs
|
||||
$object['type'] = substr($this->type, strrpos($this->type, '/') + 1);
|
||||
|
||||
// image
|
||||
$object['image'] = $imgLink->asArray();
|
||||
// summary
|
||||
$object['summary'] = $this->summary;
|
||||
|
||||
// TODO: upstreamDuplicates
|
||||
|
||||
// url (XXX: need to put the right thing here...)
|
||||
$object['url'] = $this->id;
|
||||
|
||||
/* Extensions */
|
||||
// @fixme these may collide with XML extensions
|
||||
// @fixme multiple tags of same name will overwrite each other
|
||||
// @fixme text content from XML extensions will be lost
|
||||
foreach ($this->extra as $e) {
|
||||
list($objectName, $props, $txt) = $e;
|
||||
$object[$objectName] = $props;
|
||||
}
|
||||
|
||||
// GeoJSON
|
||||
|
||||
if (!empty($this->geopoint)) {
|
||||
|
||||
list($lat, $long) = explode(' ', $this->geopoint);
|
||||
|
||||
$object['geopoint'] = array(
|
||||
'type' => 'Point',
|
||||
'coordinates' => array($lat, $long)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->poco)) {
|
||||
$object['contact'] = $this->poco->asArray();
|
||||
}
|
||||
Event::handle('EndActivityObjectOutputJson', array($this, &$object));
|
||||
}
|
||||
|
||||
// objectType
|
||||
//
|
||||
// We can probably use the whole schema URL here but probably the
|
||||
// relative simple name is easier to parse
|
||||
// @fixme this breaks extension URIs
|
||||
$object['type'] = substr($this->type, strrpos($this->type, '/') + 1);
|
||||
|
||||
// summary
|
||||
$object['summary'] = $this->summary;
|
||||
|
||||
// TODO: upstreamDuplicates
|
||||
|
||||
// url (XXX: need to put the right thing here...)
|
||||
$object['url'] = $this->id;
|
||||
|
||||
/* Extensions */
|
||||
// @fixme these may collide with XML extensions
|
||||
// @fixme multiple tags of same name will overwrite each other
|
||||
// @fixme text content from XML extensions will be lost
|
||||
foreach ($this->extra as $e) {
|
||||
list($objectName, $props, $txt) = $e;
|
||||
$object[$objectName] = $props;
|
||||
}
|
||||
|
||||
// GeoJSON
|
||||
|
||||
if (!empty($this->geopoint)) {
|
||||
|
||||
list($lat, $long) = explode(' ', $this->geopoint);
|
||||
|
||||
$object['geopoint'] = array(
|
||||
'type' => 'Point',
|
||||
'coordinates' => array($lat, $long)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->poco)) {
|
||||
$object['contact'] = $this->poco->asArray();
|
||||
}
|
||||
|
||||
return array_filter($object);
|
||||
}
|
||||
}
|
||||
|
@ -212,6 +212,44 @@ abstract class MicroAppPlugin extends Plugin
|
||||
in_array($activity->objects[0]->type, $types));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when generating Atom XML ActivityStreams output from an
|
||||
* ActivityObject belonging to this plugin. Gives the plugin
|
||||
* a chance to add custom output.
|
||||
*
|
||||
* Note that you can only add output of additional XML elements,
|
||||
* not change existing stuff here.
|
||||
*
|
||||
* If output is already handled by the base Activity classes,
|
||||
* you can leave this base implementation as a no-op.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param XMLOutputter $out to add elements at end of object
|
||||
*/
|
||||
function activityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
|
||||
{
|
||||
// default is a no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when generating JSON ActivityStreams output from an
|
||||
* ActivityObject belonging to this plugin. Gives the plugin
|
||||
* a chance to add custom output.
|
||||
*
|
||||
* Modify the array contents to your heart's content, and it'll
|
||||
* all get serialized out as JSON.
|
||||
*
|
||||
* If output is already handled by the base Activity classes,
|
||||
* you can leave this base implementation as a no-op.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param array &$out JSON-targeted array which can be modified
|
||||
*/
|
||||
public function activityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||
{
|
||||
// default is a no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* When a notice is deleted, delete the related objects
|
||||
* by calling the overridable $this->deleteRelated().
|
||||
@ -439,6 +477,46 @@ abstract class MicroAppPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler gives the plugin a chance to add custom
|
||||
* Atom XML ActivityStreams output from a previously filled-out
|
||||
* ActivityObject.
|
||||
*
|
||||
* The atomOutput method is called if it's one of
|
||||
* our matching types.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param XMLOutputter $out to add elements at end of object
|
||||
* @return boolean hook return value
|
||||
*/
|
||||
function onEndActivityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
|
||||
{
|
||||
if (in_array($obj->type, $this->types())) {
|
||||
$this->activityObjectOutputAtom($obj, $out);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler gives the plugin a chance to add custom
|
||||
* JSON ActivityStreams output from a previously filled-out
|
||||
* ActivityObject.
|
||||
*
|
||||
* The activityObjectOutputJson method is called if it's one of
|
||||
* our matching types.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param array &$out JSON-targeted array which can be modified
|
||||
* @return boolean hook return value
|
||||
*/
|
||||
function onEndActivityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||
{
|
||||
if (in_array($obj->type, $this->types())) {
|
||||
$this->activityObjectOutputJson($obj, &$out);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartShowEntryForms(&$tabs)
|
||||
{
|
||||
$tabs[$this->tag()] = $this->appTitle();
|
||||
|
@ -63,6 +63,9 @@ class PersonalGroupNav extends Menu
|
||||
$nickname = $user->nickname;
|
||||
$name = $user_profile->getBestName();
|
||||
|
||||
$action = $this->actionName;
|
||||
$mine = ($this->action->arg('nickname') == $nickname); // @fixme kinda vague
|
||||
|
||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
if (Event::handle('StartPersonalGroupNav', array($this))) {
|
||||
@ -70,23 +73,23 @@ class PersonalGroupNav extends Menu
|
||||
$nickname)),
|
||||
_('Home'),
|
||||
sprintf(_('%s and friends'), $name),
|
||||
$this->action == 'all', 'nav_timeline_personal');
|
||||
$mine && $action =='all', 'nav_timeline_personal');
|
||||
$this->out->menuItem(common_local_url('showstream', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Profile'),
|
||||
_('Your profile'),
|
||||
$this->action == 'showstream',
|
||||
$mine && $action =='showstream',
|
||||
'nav_profile');
|
||||
$this->out->menuItem(common_local_url('replies', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Replies'),
|
||||
sprintf(_('Replies to %s'), $name),
|
||||
$this->action == 'replies', 'nav_timeline_replies');
|
||||
$mine && $action =='replies', 'nav_timeline_replies');
|
||||
$this->out->menuItem(common_local_url('showfavorites', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Favorites'),
|
||||
sprintf(_('%s\'s favorite notices'), ($user_profile) ? $name : _('User')),
|
||||
$this->action == 'showfavorites', 'nav_timeline_favorites');
|
||||
$mine && $action =='showfavorites', 'nav_timeline_favorites');
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
@ -97,7 +100,7 @@ class PersonalGroupNav extends Menu
|
||||
$nickname)),
|
||||
_('Messages'),
|
||||
_('Your incoming messages'),
|
||||
$this->action == 'inbox');
|
||||
$mine && $action =='inbox');
|
||||
}
|
||||
|
||||
Event::handle('EndPersonalGroupNav', array($this));
|
||||
|
@ -168,7 +168,5 @@ E_O_T
|
||||
$this->elementStart('div', 'help instructions');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,12 @@ class ThreadedNoticeListItem extends NoticeListItem
|
||||
$item = new ThreadedNoticeListSubItem($notice, $this->out);
|
||||
$item->show();
|
||||
}
|
||||
// @fixme do a proper can-post check that's consistent
|
||||
// with the JS side
|
||||
if (common_current_user()) {
|
||||
$item = new ThreadedNoticeListReplyItem($notice, $this->out);
|
||||
$item->show();
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
}
|
||||
@ -253,10 +259,7 @@ class ThreadedNoticeListMoreItem extends NoticeListItem
|
||||
|
||||
function showStart()
|
||||
{
|
||||
if (Event::handle('StartOpenNoticeListItemElement', array($this))) {
|
||||
$id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id;
|
||||
$this->out->elementStart('li', array('class' => 'notice-reply-comments'));
|
||||
}
|
||||
$this->out->elementStart('li', array('class' => 'notice-reply-comments'));
|
||||
}
|
||||
|
||||
function showMiniForm()
|
||||
@ -270,21 +273,47 @@ class ThreadedNoticeListMoreItem extends NoticeListItem
|
||||
$msg = sprintf(_m('Show %d reply', 'Show all %d replies', $n), $n);
|
||||
|
||||
$this->out->element('a', array('href' => $url), $msg);
|
||||
|
||||
// @fixme replace this with an ajax-friendly form pair?
|
||||
/*
|
||||
$this->out->elementStart('form',
|
||||
array('id' => $id,
|
||||
'class' => 'replyform',
|
||||
'method' => 'post',
|
||||
'action' => $url));
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->hidden("$id-inreplyto", $replyToId, "inreplyto");
|
||||
$this->out->element('textarea', array('name' => 'status_textarea'));
|
||||
$this->out->elementStart('div', array('class' => 'controls'));
|
||||
$this->out->submit("$id-submit", _m('Send reply'));
|
||||
$this->out->elementEnd('div');
|
||||
$this->out->elementEnd('form');
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Placeholder for reply form...
|
||||
* Same as get added at runtime via SN.U.NoticeInlineReplyPlaceholder
|
||||
*/
|
||||
class ThreadedNoticeListReplyItem extends NoticeListItem
|
||||
{
|
||||
|
||||
/**
|
||||
* recipe function for displaying a single notice.
|
||||
*
|
||||
* This uses all the other methods to correctly display a notice. Override
|
||||
* it or one of the others to fine-tune the output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->showStart();
|
||||
$this->showMiniForm();
|
||||
$this->showEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* start a single notice.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showStart()
|
||||
{
|
||||
$this->out->elementStart('li', array('class' => 'notice-reply-placeholder'));
|
||||
}
|
||||
|
||||
function showMiniForm()
|
||||
{
|
||||
$this->out->element('input', array('class' => 'placeholder',
|
||||
'value' => _('Write a reply...')));
|
||||
}
|
||||
}
|
@ -48,8 +48,8 @@ class PollPlugin extends MicroAppPlugin
|
||||
const VERSION = '0.1';
|
||||
|
||||
// @fixme which domain should we use for these namespaces?
|
||||
const POLL_OBJECT = 'http://apinamespace.org/activitystreams/object/poll';
|
||||
const POLL_RESPONSE_OBJECT = 'http://apinamespace.org/activitystreams/object/poll-response';
|
||||
const POLL_OBJECT = 'http://activityschema.org/object/poll';
|
||||
const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response';
|
||||
|
||||
/**
|
||||
* Database schema setup
|
||||
@ -203,26 +203,22 @@ class PollPlugin extends MicroAppPlugin
|
||||
$pollElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'poll');
|
||||
$responseElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'response');
|
||||
if ($pollElements->length) {
|
||||
$data = $pollElements->item(0);
|
||||
$question = $data->getAttribute('question');
|
||||
$question = '';
|
||||
$opts = array();
|
||||
foreach ($data->attributes as $node) {
|
||||
$name = $node->nodeName;
|
||||
if (substr($name, 0, 6) == 'option') {
|
||||
$n = intval(substr($name, 6));
|
||||
if ($n > 0) {
|
||||
$opts[$n - 1] = $node->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
$data = $pollElements->item(0);
|
||||
foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'question') as $node) {
|
||||
$question = $node->textContent;
|
||||
}
|
||||
foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'option') as $node) {
|
||||
$opts[] = $node->textContent;
|
||||
}
|
||||
common_log(LOG_DEBUG, "YYY question: $question");
|
||||
common_log(LOG_DEBUG, "YYY opts: " . var_export($opts, true));
|
||||
try {
|
||||
$notice = Poll::saveNew($profile, $question, $opts, $options);
|
||||
common_log(LOG_DEBUG, "YYY ok: " . $notice->id);
|
||||
common_log(LOG_DEBUG, "Saved Poll from ActivityStream data ok: notice id " . $notice->id);
|
||||
return $notice;
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_DEBUG, "YYY fail: " . $e->getMessage());
|
||||
common_log(LOG_DEBUG, "Poll save from ActivityStream data failed: " . $e->getMessage());
|
||||
}
|
||||
} else if ($responseElements->length) {
|
||||
$data = $responseElements->item(0);
|
||||
@ -240,10 +236,10 @@ class PollPlugin extends MicroAppPlugin
|
||||
}
|
||||
try {
|
||||
$notice = Poll_response::saveNew($profile, $poll, $selection, $options);
|
||||
common_log(LOG_DEBUG, "YYY response ok: " . $notice->id);
|
||||
common_log(LOG_DEBUG, "Saved Poll_response ok, notice id: " . $notice->id);
|
||||
return $notice;
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_DEBUG, "YYY response fail: " . $e->getMessage());
|
||||
common_log(LOG_DEBUG, "Poll response save fail: " . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
common_log(LOG_DEBUG, "YYY no poll data");
|
||||
@ -277,33 +273,15 @@ class PollPlugin extends MicroAppPlugin
|
||||
$object->link = $notice->bestUrl();
|
||||
|
||||
$response = Poll_response::getByNotice($notice);
|
||||
if (!$response) {
|
||||
common_log(LOG_DEBUG, "QQQ notice uri: $notice->uri");
|
||||
} else {
|
||||
if ($response) {
|
||||
$poll = $response->getPoll();
|
||||
/**
|
||||
* For the moment, using a kind of icky-looking schema that happens to
|
||||
* work with out code for generating both Atom and JSON forms, though
|
||||
* I don't like it:
|
||||
*
|
||||
* <poll:response xmlns:poll="http://apinamespace.org/activitystreams/object/poll"
|
||||
* poll="http://..../poll/...."
|
||||
* selection="3" />
|
||||
*
|
||||
* "poll:response": {
|
||||
* "xmlns:poll": http://apinamespace.org/activitystreams/object/poll
|
||||
* "uri": "http://..../poll/...."
|
||||
* "selection": 3
|
||||
* }
|
||||
*
|
||||
*/
|
||||
// @fixme there's no way to specify an XML node tree here, like <poll><option/><option/></poll>
|
||||
// @fixme there's no way to specify a JSON array or multi-level tree unless you break the XML attribs
|
||||
// @fixme XML node contents don't get shown in JSON
|
||||
$data = array('xmlns:poll' => self::POLL_OBJECT,
|
||||
'poll' => $poll->uri,
|
||||
'selection' => intval($response->selection));
|
||||
$object->extra[] = array('poll:response', $data, '');
|
||||
if ($poll) {
|
||||
// Stash data to be formatted later by
|
||||
// $this->activityObjectOutputAtom() or
|
||||
// $this->activityObjectOutputJson()...
|
||||
$object->pollSelection = intval($response->selection);
|
||||
$object->pollUri = $poll->uri;
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
@ -318,41 +296,112 @@ class PollPlugin extends MicroAppPlugin
|
||||
$object->link = $notice->bestUrl();
|
||||
|
||||
$poll = Poll::getByNotice($notice);
|
||||
/**
|
||||
* Adding the poll-specific data. There's no standard in AS for polls,
|
||||
* so we're making stuff up.
|
||||
*
|
||||
* For the moment, using a kind of icky-looking schema that happens to
|
||||
* work with out code for generating both Atom and JSON forms, though
|
||||
* I don't like it:
|
||||
*
|
||||
* <poll:data xmlns:poll="http://apinamespace.org/activitystreams/object/poll"
|
||||
* question="Who wants a poll question?"
|
||||
* option1="Option one"
|
||||
* option2="Option two"
|
||||
* option3="Option three"></poll:data>
|
||||
*
|
||||
* "poll:response": {
|
||||
* "xmlns:poll": http://apinamespace.org/activitystreams/object/poll
|
||||
* "question": "Who wants a poll question?"
|
||||
* "option1": "Option one"
|
||||
* "option2": "Option two"
|
||||
* "option3": "Option three"
|
||||
* }
|
||||
*
|
||||
*/
|
||||
// @fixme there's no way to specify an XML node tree here, like <poll><option/><option/></poll>
|
||||
// @fixme there's no way to specify a JSON array or multi-level tree unless you break the XML attribs
|
||||
// @fixme XML node contents don't get shown in JSON
|
||||
$data = array('xmlns:poll' => self::POLL_OBJECT,
|
||||
'question' => $poll->question);
|
||||
foreach ($poll->getOptions() as $i => $opt) {
|
||||
$data['option' . ($i + 1)] = $opt;
|
||||
if ($poll) {
|
||||
// Stash data to be formatted later by
|
||||
// $this->activityObjectOutputAtom() or
|
||||
// $this->activityObjectOutputJson()...
|
||||
$object->pollQuestion = $poll->question;
|
||||
$object->pollOptions = $poll->getOptions();
|
||||
}
|
||||
$object->extra[] = array('poll:poll', $data, '');
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when generating Atom XML ActivityStreams output from an
|
||||
* ActivityObject belonging to this plugin. Gives the plugin
|
||||
* a chance to add custom output.
|
||||
*
|
||||
* Note that you can only add output of additional XML elements,
|
||||
* not change existing stuff here.
|
||||
*
|
||||
* If output is already handled by the base Activity classes,
|
||||
* you can leave this base implementation as a no-op.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param XMLOutputter $out to add elements at end of object
|
||||
*/
|
||||
function activityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
|
||||
{
|
||||
if (isset($obj->pollQuestion)) {
|
||||
/**
|
||||
* <poll:poll xmlns:poll="http://apinamespace.org/activitystreams/object/poll">
|
||||
* <poll:question>Who wants a poll question?</poll:question>
|
||||
* <poll:option>Option one</poll:option>
|
||||
* <poll:option>Option two</poll:option>
|
||||
* <poll:option>Option three</poll:option>
|
||||
* </poll:poll>
|
||||
*/
|
||||
$data = array('xmlns:poll' => self::POLL_OBJECT);
|
||||
$out->elementStart('poll:poll', $data);
|
||||
$out->element('poll:question', array(), $obj->pollQuestion);
|
||||
foreach ($obj->pollOptions as $opt) {
|
||||
$out->element('poll:option', array(), $opt);
|
||||
}
|
||||
$out->elementEnd('poll:poll');
|
||||
}
|
||||
if (isset($obj->pollSelection)) {
|
||||
/**
|
||||
* <poll:response xmlns:poll="http://apinamespace.org/activitystreams/object/poll">
|
||||
* poll="http://..../poll/...."
|
||||
* selection="3" />
|
||||
*/
|
||||
$data = array('xmlns:poll' => self::POLL_OBJECT,
|
||||
'poll' => $obj->pollUri,
|
||||
'selection' => $obj->pollSelection);
|
||||
$out->element('poll:response', $data, '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when generating JSON ActivityStreams output from an
|
||||
* ActivityObject belonging to this plugin. Gives the plugin
|
||||
* a chance to add custom output.
|
||||
*
|
||||
* Modify the array contents to your heart's content, and it'll
|
||||
* all get serialized out as JSON.
|
||||
*
|
||||
* If output is already handled by the base Activity classes,
|
||||
* you can leave this base implementation as a no-op.
|
||||
*
|
||||
* @param ActivityObject $obj
|
||||
* @param array &$out JSON-targeted array which can be modified
|
||||
*/
|
||||
public function activityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||
{
|
||||
common_log(LOG_DEBUG, 'QQQ: ' . var_export($obj, true));
|
||||
if (isset($obj->pollQuestion)) {
|
||||
/**
|
||||
* "poll": {
|
||||
* "question": "Who wants a poll question?",
|
||||
* "options": [
|
||||
* "Option 1",
|
||||
* "Option 2",
|
||||
* "Option 3"
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
$data = array('question' => $obj->pollQuestion,
|
||||
'options' => array());
|
||||
foreach ($obj->pollOptions as $opt) {
|
||||
$data['options'][] = $opt;
|
||||
}
|
||||
$out['poll'] = $data;
|
||||
}
|
||||
if (isset($obj->pollSelection)) {
|
||||
/**
|
||||
* "pollResponse": {
|
||||
* "poll": "http://..../poll/....",
|
||||
* "selection": 3
|
||||
* }
|
||||
*/
|
||||
$data = array('poll' => $obj->pollUri,
|
||||
'selection' => $obj->pollSelection);
|
||||
$out['pollResponse'] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @fixme WARNING WARNING WARNING parent class closes the final div that we
|
||||
* open here, but we probably shouldn't open it here. Check parent class
|
||||
|
Loading…
Reference in New Issue
Block a user