forked from GNUsocial/gnu-social
		
	Merge remote branch 'origin/1.0.x' into 1.0.x
This commit is contained in:
		
							
								
								
									
										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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user