From 3146c9fae843a3f3ba0e840610b4a7607d29153e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 11:54:23 -0800 Subject: [PATCH 01/10] Add event hooks for customizing ActivityObject output to Atom and JSON, and helpers for MicroAppPlugin. New hooks: * StartActivityObjectOutputAtom * EndActivityObjectOutputAtom $obj ActivityObject $out XMLOutputter * StartActivityObjectOutputJson * EndActivityObjectOutputJson $obj ActivityObject &$out array --- EVENTS.txt | 16 +++ lib/activityobject.php | 290 +++++++++++++++++++++-------------------- lib/microappplugin.php | 78 +++++++++++ 3 files changed, 242 insertions(+), 142 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 6cc1a7fe1c..1443a94fbe 100644 --- a/EVENTS.txt +++ b/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 . 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 +- $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 diff --git a/lib/activityobject.php b/lib/activityobject.php index d620bf27bb..241f99564f 100644 --- a/lib/activityobject.php +++ b/lib/activityobject.php @@ -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); - // uses URI + // 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); } } diff --git a/lib/microappplugin.php b/lib/microappplugin.php index fbead58cc5..86803b8ae3 100644 --- a/lib/microappplugin.php +++ b/lib/microappplugin.php @@ -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(); From a9d589dbdcd19169a6e1900bf578fba6c5c5ec4e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 12:28:15 -0800 Subject: [PATCH 02/10] Poll plugin: switching Atom & JSON output to use new hooks & methods, much nicer output. Also switched types, which may break old entries. Beware! Input not yet updated. --- plugins/Poll/PollPlugin.php | 171 +++++++++++++++++++++++------------- 1 file changed, 112 insertions(+), 59 deletions(-) diff --git a/plugins/Poll/PollPlugin.php b/plugins/Poll/PollPlugin.php index 34c37eb526..78357457a6 100644 --- a/plugins/Poll/PollPlugin.php +++ b/plugins/Poll/PollPlugin.php @@ -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 @@ -277,33 +277,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 - * "uri": "http://..../poll/...." - * "selection": 3 - * } - * - */ - // @fixme there's no way to specify an XML node tree here, like - // @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 +300,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: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 - // @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)) { + /** + * + * Who wants a poll question? + * Option one + * Option two + * Option three + * + */ + $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="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 From e1136bacaec721c08b830f52e80069f89b7a45e2 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 12:41:11 -0800 Subject: [PATCH 03/10] Update PollPlugin Atom input --- plugins/Poll/PollPlugin.php | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/plugins/Poll/PollPlugin.php b/plugins/Poll/PollPlugin.php index 78357457a6..490f39005f 100644 --- a/plugins/Poll/PollPlugin.php +++ b/plugins/Poll/PollPlugin.php @@ -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->textValue; // ? + } + foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'option') as $node) { + $opts[] = $node->textValue; } - 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"); From d5f5f769479e6e97d23875eb0705bd5cda1a0c1b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 12:45:55 -0800 Subject: [PATCH 04/10] durrrr s/textValue/textContent/ --- plugins/Poll/PollPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Poll/PollPlugin.php b/plugins/Poll/PollPlugin.php index 490f39005f..ea6ab9ecd9 100644 --- a/plugins/Poll/PollPlugin.php +++ b/plugins/Poll/PollPlugin.php @@ -208,10 +208,10 @@ class PollPlugin extends MicroAppPlugin $data = $pollElements->item(0); foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'question') as $node) { - $question = $node->textValue; // ? + $question = $node->textContent; } foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'option') as $node) { - $opts[] = $node->textValue; + $opts[] = $node->textContent; } try { $notice = Poll::saveNew($profile, $question, $opts, $options); From d393ac4bbbee1c4021cb928ea16781a294978242 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 14:08:48 -0800 Subject: [PATCH 05/10] remove stray close div from empty search results doc bits --- lib/searchaction.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/searchaction.php b/lib/searchaction.php index 73c287eef3..7038424fab 100644 --- a/lib/searchaction.php +++ b/lib/searchaction.php @@ -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'); } } From 717fed785efca5f589a293a045907264cb1bc67e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 14:25:57 -0800 Subject: [PATCH 06/10] Update PersonalGroupNav with fixed highlighting checks. Couldn't use Menu::item() as its checks are only for the action name, so would have highlighted stuff for other users though it always links to self. --- lib/personalgroupnav.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/personalgroupnav.php b/lib/personalgroupnav.php index 3d6bb98fc0..2e15ca5f6a 100644 --- a/lib/personalgroupnav.php +++ b/lib/personalgroupnav.php @@ -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)); From 4e2a0e2fd0e3717541ed76e59631a0f4814eb311 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 14:48:47 -0800 Subject: [PATCH 07/10] Use non-minified jQuery when $config['site']['minify'] is off; aids in debugging when something fails deep in jQuery-land. --- lib/action.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/action.php b/lib/action.php index b1f16f5f16..233ac78567 100644 --- a/lib/action.php +++ b/lib/action.php @@ -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)) && From 10e5cb482e8eefdc3dcbe5aa1983df336524c02d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 15:03:15 -0800 Subject: [PATCH 08/10] JS performance: speeding up initialization by consolidating event handlers for reply buttons Saved about 60ms on my test system during page setup by using a single global 'live' click handler for reply links. No longer need to seek out and attach event handlers on every notice, yay! --- js/util.js | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/js/util.js b/js/util.js index a244f1ecfb..d0d23d464d 100644 --- a/js/util.js +++ b/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. * From 2bccd18d9a4f1ed2b74b854a7c1cffc707f961af Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 15:20:20 -0800 Subject: [PATCH 09/10] JS optimization: move creation of inline reply placeholders to server-side so we don't have to create them client-side (which causes reflows and takes about 25-30ms on my test system) Using live instead of bind for the event handling, we don't have to play any games on the ones that we do add at runtime. Yay! --- js/util.js | 19 +++++------ lib/threadednoticelist.php | 67 +++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/js/util.js b/js/util.js index d0d23d464d..966df4d93f 100644 --- a/js/util.js +++ b/js/util.js @@ -627,26 +627,23 @@ var SN = { // StatusNet '' + ''); 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; + }); }, /** diff --git a/lib/threadednoticelist.php b/lib/threadednoticelist.php index 867ce28ed6..919c912831 100644 --- a/lib/threadednoticelist.php +++ b/lib/threadednoticelist.php @@ -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...'))); } } \ No newline at end of file From 096f99be1615ff3a6ac4a8ae3b9f283f4aad36ad Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Mar 2011 15:31:58 -0800 Subject: [PATCH 10/10] (update util.min.js for recent changes) --- js/util.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/util.min.js b/js/util.min.js index efe3736e3e..26ae7494cb 100644 --- a/js/util.min.js +++ b/js/util.min.js @@ -1 +1 @@ -var SN={C:{I:{CounterBlackout:false,MaxLength:140,PatternUsername:/^[0-9a-zA-Z\-_.]*$/,HTTP20x30x:[200,201,202,203,204,205,206,300,301,302,303,304,305,306,307],NoticeFormMaster:null},S:{Disabled:"disabled",Warning:"warning",Error:"error",Success:"success",Processing:"processing",CommandResult:"command_result",FormNotice:"form_notice",NoticeDataGeo:"notice_data-geo",NoticeDataGeoCookie:"NoticeDataGeo",NoticeDataGeoSelected:"notice_data-geo_selected",StatusNetInstance:"StatusNetInstance"}},messages:{},msg:function(a){if(typeof SN.messages[a]=="undefined"){return"["+a+"]"}else{return SN.messages[a]}},U:{FormNoticeEnhancements:function(b){if(jQuery.data(b[0],"ElementData")===undefined){MaxLength=b.find(".count").text();if(typeof(MaxLength)=="undefined"){MaxLength=SN.C.I.MaxLength}jQuery.data(b[0],"ElementData",{MaxLength:MaxLength});SN.U.Counter(b);NDT=b.find(".notice_data-text:first");NDT.bind("keyup",function(c){SN.U.Counter(b)});var a=function(c){window.setTimeout(function(){SN.U.Counter(b)},50)};NDT.bind("cut",a).bind("paste",a)}else{b.find(".count").text(jQuery.data(b[0],"ElementData").MaxLength)}},Counter:function(d){SN.C.I.FormNoticeCurrent=d;var b=jQuery.data(d[0],"ElementData").MaxLength;if(b<=0){return}var c=b-SN.U.CharacterCount(d);var a=d.find(".count");if(c.toString()!=a.text()){if(!SN.C.I.CounterBlackout||c===0){if(a.text()!=String(c)){a.text(c)}if(c<0){d.addClass(SN.C.S.Warning)}else{d.removeClass(SN.C.S.Warning)}if(!SN.C.I.CounterBlackout){SN.C.I.CounterBlackout=true;SN.C.I.FormNoticeCurrent=d;window.setTimeout("SN.U.ClearCounterBlackout(SN.C.I.FormNoticeCurrent);",500)}}}},CharacterCount:function(a){return a.find(".notice_data-text:first").val().length},ClearCounterBlackout:function(a){SN.C.I.CounterBlackout=false;SN.U.Counter(a)},RewriteAjaxAction:function(a){if(document.location.protocol=="https:"&&a.substr(0,5)=="http:"){return a.replace(/^http:\/\/[^:\/]+/,"https://"+document.location.host)}else{return a}},FormXHR:function(a){$.ajax({type:"POST",dataType:"xml",url:SN.U.RewriteAjaxAction(a.attr("action")),data:a.serialize()+"&ajax=1",beforeSend:function(b){a.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled)},error:function(c,d,b){alert(b||d)},success:function(b,c){if(typeof($("form",b)[0])!="undefined"){form_new=document._importNode($("form",b)[0],true);a.replaceWith(form_new)}else{a.replaceWith(document._importNode($("p",b)[0],true))}}})},FormNoticeXHR:function(b){SN.C.I.NoticeDataGeo={};b.append('');b.attr("action",SN.U.RewriteAjaxAction(b.attr("action")));var c=function(d,e){b.append($('

').addClass(d).text(e))};var a=function(){b.find(".form_response").remove()};b.ajaxForm({dataType:"xml",timeout:"60000",beforeSend:function(d){if(b.find(".notice_data-text:first").val()==""){b.addClass(SN.C.S.Warning);return false}b.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled);SN.U.normalizeGeoData(b);return true},error:function(f,g,e){b.removeClass(SN.C.S.Processing).find(".submit").removeClass(SN.C.S.Disabled).removeAttr(SN.C.S.Disabled,SN.C.S.Disabled);a();if(g=="timeout"){c("error","Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.")}else{var d=SN.U.GetResponseXML(f);if($("."+SN.C.S.Error,d).length>0){b.append(document._importNode($("."+SN.C.S.Error,d)[0],true))}else{if(parseInt(f.status)===0||jQuery.inArray(parseInt(f.status),SN.C.I.HTTP20x30x)>=0){b.resetForm().find(".attach-status").remove();SN.U.FormNoticeEnhancements(b)}else{c("error","(Sorry! We had trouble sending your notice ("+f.status+" "+f.statusText+"). Please report the problem to the site administrator if this happens again.")}}}},success:function(i,f){a();var n=$("#"+SN.C.S.Error,i);if(n.length>0){c("error",n.text())}else{if($("body")[0].id=="bookmarklet"){self.close()}var d=$("#"+SN.C.S.CommandResult,i);if(d.length>0){c("success",d.text())}else{var m=document._importNode($("li",i)[0],true);var k=$("#notices_primary .notices:first");var l=b.closest("li.notice-reply");if(l.length>0){var e=$(m).attr("id");if($("#"+e).length==0){var j=l.closest("li.notice");l.replaceWith(m);SN.U.NoticeInlineReplyPlaceholder(j)}else{l.remove()}}else{if(k.length>0&&SN.U.belongsOnTimeline(m)){if($("#"+m.id).length===0){var h=b.find("[name=inreplyto]").val();var g="#notices_primary #notice-"+h;if($("body")[0].id=="conversation"){if(h.length>0&&$(g+" .notices").length<1){$(g).append('
    ')}$($(g+" .notices")[0]).append(m)}else{k.prepend(m)}$("#"+m.id).css({display:"none"}).fadeIn(2500);SN.U.NoticeWithAttachment($("#"+m.id));SN.U.NoticeReplyTo($("#"+m.id));SN.U.switchInputFormTab("placeholder")}}else{c("success",$("title",i).text())}}}b.resetForm();b.find("[name=inreplyto]").val("");b.find(".attach-status").remove();SN.U.FormNoticeEnhancements(b)}},complete:function(d,e){b.removeClass(SN.C.S.Processing).find(".submit").removeAttr(SN.C.S.Disabled).removeClass(SN.C.S.Disabled);b.find("[name=lat]").val(SN.C.I.NoticeDataGeo.NLat);b.find("[name=lon]").val(SN.C.I.NoticeDataGeo.NLon);b.find("[name=location_ns]").val(SN.C.I.NoticeDataGeo.NLNS);b.find("[name=location_id]").val(SN.C.I.NoticeDataGeo.NLID);b.find("[name=notice_data-geo]").attr("checked",SN.C.I.NoticeDataGeo.NDG)}})},normalizeGeoData:function(a){SN.C.I.NoticeDataGeo.NLat=a.find("[name=lat]").val();SN.C.I.NoticeDataGeo.NLon=a.find("[name=lon]").val();SN.C.I.NoticeDataGeo.NLNS=a.find("[name=location_ns]").val();SN.C.I.NoticeDataGeo.NLID=a.find("[name=location_id]").val();SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked");var b=$.cookie(SN.C.S.NoticeDataGeoCookie);if(b!==null&&b!="disabled"){b=JSON.parse(b);SN.C.I.NoticeDataGeo.NLat=a.find("[name=lat]").val(b.NLat).val();SN.C.I.NoticeDataGeo.NLon=a.find("[name=lon]").val(b.NLon).val();if(b.NLNS){SN.C.I.NoticeDataGeo.NLNS=a.find("[name=location_ns]").val(b.NLNS).val();SN.C.I.NoticeDataGeo.NLID=a.find("[name=location_id]").val(b.NLID).val()}else{a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("")}}if(b=="disabled"){SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked",false).attr("checked")}else{SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked",true).attr("checked")}},GetResponseXML:function(b){try{return b.responseXML}catch(a){return(new DOMParser()).parseFromString(b.responseText,"text/xml")}},NoticeReply:function(){if($("#content .notice_reply").length>0){$("#content .notice").each(function(){SN.U.NoticeReplyTo($(this))})}},NoticeReplyTo:function(a){a.find(".notice_reply").live("click",function(c){c.preventDefault();var b=($(".author .nickname",a).length>0)?$($(".author .nickname",a)[0]):$(".author .nickname.uid");SN.U.NoticeInlineReplyTrigger(a,"@"+b.text());return false})},NoticeInlineReplyTrigger:function(h,i){var b=$($(".notice_id",h)[0]).text();var e=h;var f=h.closest(".notices");if(f.hasClass("threaded-replies")){e=f.closest(".notice")}else{f=$("ul.threaded-replies",h);if(f.length==0){f=$('
      ');h.append(f)}}var j=$(".notice-reply-form",f);var d=function(){j.find("input[name=inreplyto]").val(b);var m=j.find("textarea");if(m.length==0){throw"No textarea"}var l="";if(i){l=i+" "}m.val(l+m.val().replace(RegExp(l,"i"),""));m.data("initialText",$.trim(i+""));m.focus();if(m[0].setSelectionRange){var k=m.val().length;m[0].setSelectionRange(k,k)}};if(j.length>0){d()}else{f.find("li.notice-reply-placeholder").remove();var g=$("li.notice-reply",f);if(g.length==0){g=$('
    • ');var c=function(k){var l=document._importNode(k,true);g.append(l);f.append(g);var m=j=$(l);SN.Init.NoticeFormSetup(m);d()};if(SN.C.I.NoticeFormMaster){c(SN.C.I.NoticeFormMaster)}else{var a=$("#form_notice").attr("action");$.get(a,{ajax:1},function(k,m,l){c($("form",k)[0])})}}}},NoticeInlineReplyPlaceholder:function(b){var a=b.find("ul.threaded-replies");var c=$('
    • ');c.find("input").val(SN.msg("reply_placeholder")).focus(function(){SN.U.NoticeInlineReplyTrigger(b);return false});a.append(c)},NoticeInlineReplySetup:function(){$(".threaded-replies").each(function(){var b=$(this);var a=b.closest(".notice");SN.U.NoticeInlineReplyPlaceholder(a)})},NoticeRepeat:function(){$(".form_repeat").live("click",function(a){a.preventDefault();SN.U.NoticeRepeatConfirmation($(this));return false})},NoticeRepeatConfirmation:function(a){var c=a.find(".submit");var b=c.clone();b.addClass("submit_dialogbox").removeClass("submit");a.append(b);b.bind("click",function(){SN.U.FormXHR(a);return false});c.hide();a.addClass("dialogbox").append('').closest(".notice-options").addClass("opaque");a.find("button.close").click(function(){$(this).remove();a.removeClass("dialogbox").closest(".notice-options").removeClass("opaque");a.find(".submit_dialogbox").remove();a.find(".submit").show();return false})},NoticeAttachments:function(){$(".notice a.attachment").each(function(){SN.U.NoticeWithAttachment($(this).closest(".notice"))})},NoticeWithAttachment:function(b){if(b.find(".attachment").length===0){return}var a=b.find(".attachment.more");if(a.length>0){$(a[0]).click(function(){var c=$(this);c.addClass(SN.C.S.Processing);$.get(c.attr("href")+"/ajax",null,function(d){c.parent(".entry-content").html($(d).find("#attachment_view .entry-content").html())});return false}).attr("title",SN.msg("showmore_tooltip"))}},NoticeDataAttach:function(b){var a=b.find("input[type=file]");a.change(function(f){b.find(".attach-status").remove();var d=$(this).val();if(!d){return false}var c=$('
      ');c.find("code").text(d);c.find("button").click(function(){c.remove();a.val("");return false});b.append(c);if(typeof this.files=="object"){for(var e=0;eg){f=false}if(f){h(c,function(j){var i=$("").attr("title",e).attr("alt",e).attr("src",j).attr("style","height: 120px");d.find(".attach-status").append(i)})}else{var b=$("
      ").text(e);d.find(".attach-status").append(b)}},NoticeLocationAttach:function(a){var e=a.find("[name=lat]");var k=a.find("[name=lon]");var g=a.find("[name=location_ns]").val();var l=a.find("[name=location_id]").val();var b="";var d=a.find("[name=notice_data-geo]");var c=a.find("[name=notice_data-geo]");var j=a.find("label.notice_data-geo");function f(n){j.attr("title",jQuery.trim(j.text())).removeClass("checked");a.find("[name=lat]").val("");a.find("[name=lon]").val("");a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("");a.find("[name=notice_data-geo]").attr("checked",false);$.cookie(SN.C.S.NoticeDataGeoCookie,"disabled",{path:"/"});if(n){a.find(".geo_status_wrapper").removeClass("success").addClass("error");a.find(".geo_status_wrapper .geo_status").text(n)}else{a.find(".geo_status_wrapper").remove()}}function m(n,o){SN.U.NoticeGeoStatus(a,"Looking up place name...");$.getJSON(n,o,function(p){var q,r;if(typeof(p.location_ns)!="undefined"){a.find("[name=location_ns]").val(p.location_ns);q=p.location_ns}if(typeof(p.location_id)!="undefined"){a.find("[name=location_id]").val(p.location_id);r=p.location_id}if(typeof(p.name)=="undefined"){NLN_text=o.lat+";"+o.lon}else{NLN_text=p.name}SN.U.NoticeGeoStatus(a,NLN_text,o.lat,o.lon,p.url);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+NLN_text+")");a.find("[name=lat]").val(o.lat);a.find("[name=lon]").val(o.lon);a.find("[name=location_ns]").val(q);a.find("[name=location_id]").val(r);a.find("[name=notice_data-geo]").attr("checked",true);var s={NLat:o.lat,NLon:o.lon,NLNS:q,NLID:r,NLN:NLN_text,NLNU:p.url,NDG:true};$.cookie(SN.C.S.NoticeDataGeoCookie,JSON.stringify(s),{path:"/"})})}if(c.length>0){if($.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){c.attr("checked",false)}else{c.attr("checked",true)}var h=a.find(".notice_data-geo_wrap");var i=h.attr("data-api");j.attr("title",j.text());c.change(function(){if(c.attr("checked")===true||$.cookie(SN.C.S.NoticeDataGeoCookie)===null){j.attr("title",NoticeDataGeo_text.ShareDisable).addClass("checked");if($.cookie(SN.C.S.NoticeDataGeoCookie)===null||$.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){if(navigator.geolocation){SN.U.NoticeGeoStatus(a,"Requesting location from browser...");navigator.geolocation.getCurrentPosition(function(p){a.find("[name=lat]").val(p.coords.latitude);a.find("[name=lon]").val(p.coords.longitude);var q={lat:p.coords.latitude,lon:p.coords.longitude,token:$("#token").val()};m(i,q)},function(p){switch(p.code){case p.PERMISSION_DENIED:f("Location permission denied.");break;case p.TIMEOUT:f("Location lookup timeout.");break}},{timeout:10000})}else{if(e.length>0&&k.length>0){var n={lat:e,lon:k,token:$("#token").val()};m(i,n)}else{f();c.remove();j.remove()}}}else{var o=JSON.parse($.cookie(SN.C.S.NoticeDataGeoCookie));a.find("[name=lat]").val(o.NLat);a.find("[name=lon]").val(o.NLon);a.find("[name=location_ns]").val(o.NLNS);a.find("[name=location_id]").val(o.NLID);a.find("[name=notice_data-geo]").attr("checked",o.NDG);SN.U.NoticeGeoStatus(a,o.NLN,o.NLat,o.NLon,o.NLNU);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+o.NLN+")").addClass("checked")}}else{f()}}).change()}},NoticeGeoStatus:function(e,a,f,g,c){var h=e.find(".geo_status_wrapper");if(h.length==0){h=$('
      ');h.find("button.close").click(function(){e.find("[name=notice_data-geo]").removeAttr("checked").change();return false});e.append(h)}var b;if(c){b=$("").attr("href",c)}else{b=$("")}b.text(a);if(f||g){var d=f+";"+g;b.attr("title",d);if(!a){b.text(d)}}h.find(".geo_status").empty().append(b)},NewDirectMessage:function(){NDM=$(".entity_send-a-message a");NDM.attr({href:NDM.attr("href")+"&ajax=1"});NDM.bind("click",function(){var a=$(".entity_send-a-message form");if(a.length===0){$(this).addClass(SN.C.S.Processing);$.get(NDM.attr("href"),null,function(b){$(".entity_send-a-message").append(document._importNode($("form",b)[0],true));a=$(".entity_send-a-message .form_notice");SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);a.append('');$(".entity_send-a-message button").click(function(){a.hide();return false});NDM.removeClass(SN.C.S.Processing)})}else{a.show();$(".entity_send-a-message textarea").focus()}return false})},GetFullYear:function(c,d,a){var b=new Date();b.setFullYear(c,d,a);return b},StatusNetInstance:{Set:function(b){var a=SN.U.StatusNetInstance.Get();if(a!==null){b=$.extend(a,b)}$.cookie(SN.C.S.StatusNetInstance,JSON.stringify(b),{path:"/",expires:SN.U.GetFullYear(2029,0,1)})},Get:function(){var a=$.cookie(SN.C.S.StatusNetInstance);if(a!==null){return JSON.parse(a)}return null},Delete:function(){$.cookie(SN.C.S.StatusNetInstance,null)}},belongsOnTimeline:function(b){var a=$("body").attr("id");if(a=="public"){return true}var c=$("#nav_profile a").attr("href");if(c){var d=$(b).find(".vcard.author a.url").attr("href");if(d==c){if(a=="all"||a=="showstream"){return true}}}return false},switchInputFormTab:function(a){$(".input_form_nav_tab.current").removeClass("current");if(a=="placeholder"){$("#input_form_nav_status").addClass("current")}else{$("#input_form_nav_"+a).addClass("current")}$(".input_form.current").removeClass("current");$("#input_form_"+a).addClass("current").find(".ajax-notice").each(function(){var b=$(this);SN.Init.NoticeFormSetup(b)}).find("textarea:first").focus()}},Init:{NoticeForm:function(){if($("body.user_in").length>0){$("#input_form_placeholder input.placeholder").focus(function(){SN.U.switchInputFormTab("status")});$("body").bind("click",function(g){var d=$("#content .input_forms div.current");if(d.length>0){if($("#content .input_forms").has(g.target).length==0){var a=d.find('textarea, input[type=text], input[type=""]');var c=false;a.each(function(){c=c||$(this).val()});if(!c){SN.U.switchInputFormTab("placeholder")}}}var b=$("li.notice-reply");if(b.length>0){var f=$(g.target);b.each(function(){var j=$(this);if(j.has(g.target).length==0){var h=j.find(".notice_data-text:first");var i=$.trim(h.val());if(i==""||i==h.data("initialText")){var e=j.closest("li.notice");j.remove();SN.U.NoticeInlineReplyPlaceholder(e)}}})}})}},NoticeFormSetup:function(a){if(!a.data("NoticeFormSetup")){SN.U.NoticeLocationAttach(a);SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);SN.U.NoticeDataAttach(a);a.data("NoticeFormSetup",true)}},Notices:function(){if($("body.user_in").length>0){var a=$(".form_notice:first");if(a.length>0){SN.C.I.NoticeFormMaster=document._importNode(a[0],true)}SN.U.NoticeRepeat();SN.U.NoticeReply();SN.U.NoticeInlineReplySetup()}SN.U.NoticeAttachments()},EntityActions:function(){if($("body.user_in").length>0){SN.U.NewDirectMessage()}},Login:function(){if(SN.U.StatusNetInstance.Get()!==null){var a=SN.U.StatusNetInstance.Get().Nickname;if(a!==null){$("#form_login #nickname").val(a)}}$("#form_login").bind("submit",function(){SN.U.StatusNetInstance.Set({Nickname:$("#form_login #nickname").val()});return true})},AjaxForms:function(){$("form.ajax").live("submit",function(){SN.U.FormXHR($(this));return false})},UploadForms:function(){$("input[type=file]").change(function(d){if(typeof this.files=="object"&&this.files.length>0){var c=0;for(var b=0;b0&&c>a){var e="File too large: maximum upload size is %d bytes.";alert(e.replace("%d",a));$(this).val("");d.preventDefault();return false}}})}}};$(document).ready(function(){SN.Init.AjaxForms();SN.Init.UploadForms();if($("."+SN.C.S.FormNotice).length>0){SN.Init.NoticeForm()}if($("#content .notices").length>0){SN.Init.Notices()}if($("#content .entity_actions").length>0){SN.Init.EntityActions()}if($("#form_login").length>0){SN.Init.Login()}});if(!document.ELEMENT_NODE){document.ELEMENT_NODE=1;document.ATTRIBUTE_NODE=2;document.TEXT_NODE=3;document.CDATA_SECTION_NODE=4;document.ENTITY_REFERENCE_NODE=5;document.ENTITY_NODE=6;document.PROCESSING_INSTRUCTION_NODE=7;document.COMMENT_NODE=8;document.DOCUMENT_NODE=9;document.DOCUMENT_TYPE_NODE=10;document.DOCUMENT_FRAGMENT_NODE=11;document.NOTATION_NODE=12}document._importNode=function(e,a){switch(e.nodeType){case document.ELEMENT_NODE:var d=document.createElement(e.nodeName);if(e.attributes&&e.attributes.length>0){for(var c=0,b=e.attributes.length;c0){for(var c=0,b=e.childNodes.length;c0){var j=c.pop();j()}}};window._google_loader_apiLoaded=function(){f()};var d=function(){return(window.google&&google.loader)};var g=function(j){if(d()){return true}h(j);e();return false};e();return{shim:true,type:"ClientLocation",lastPosition:null,getCurrentPosition:function(k,n,o){var m=this;if(!g(function(){m.getCurrentPosition(k,n,o)})){return}if(google.loader.ClientLocation){var l=google.loader.ClientLocation;var j={coords:{latitude:l.latitude,longitude:l.longitude,altitude:null,accuracy:43000,altitudeAccuracy:null,heading:null,speed:null},address:{city:l.address.city,country:l.address.country,country_code:l.address.country_code,region:l.address.region},timestamp:new Date()};k(j);this.lastPosition=j}else{if(n==="function"){n({code:3,message:"Using the Google ClientLocation API and it is not able to calculate a location."})}}},watchPosition:function(j,l,m){this.getCurrentPosition(j,l,m);var k=this;var n=setInterval(function(){k.getCurrentPosition(j,l,m)},10000);return n},clearWatch:function(j){clearInterval(j)},getPermission:function(l,j,k){return true}}});navigator.geolocation=(window.google&&google.gears)?a():b()})()}; \ No newline at end of file +var SN={C:{I:{CounterBlackout:false,MaxLength:140,PatternUsername:/^[0-9a-zA-Z\-_.]*$/,HTTP20x30x:[200,201,202,203,204,205,206,300,301,302,303,304,305,306,307],NoticeFormMaster:null},S:{Disabled:"disabled",Warning:"warning",Error:"error",Success:"success",Processing:"processing",CommandResult:"command_result",FormNotice:"form_notice",NoticeDataGeo:"notice_data-geo",NoticeDataGeoCookie:"NoticeDataGeo",NoticeDataGeoSelected:"notice_data-geo_selected",StatusNetInstance:"StatusNetInstance"}},messages:{},msg:function(a){if(typeof SN.messages[a]=="undefined"){return"["+a+"]"}else{return SN.messages[a]}},U:{FormNoticeEnhancements:function(b){if(jQuery.data(b[0],"ElementData")===undefined){MaxLength=b.find(".count").text();if(typeof(MaxLength)=="undefined"){MaxLength=SN.C.I.MaxLength}jQuery.data(b[0],"ElementData",{MaxLength:MaxLength});SN.U.Counter(b);NDT=b.find(".notice_data-text:first");NDT.bind("keyup",function(c){SN.U.Counter(b)});var a=function(c){window.setTimeout(function(){SN.U.Counter(b)},50)};NDT.bind("cut",a).bind("paste",a)}else{b.find(".count").text(jQuery.data(b[0],"ElementData").MaxLength)}},Counter:function(d){SN.C.I.FormNoticeCurrent=d;var b=jQuery.data(d[0],"ElementData").MaxLength;if(b<=0){return}var c=b-SN.U.CharacterCount(d);var a=d.find(".count");if(c.toString()!=a.text()){if(!SN.C.I.CounterBlackout||c===0){if(a.text()!=String(c)){a.text(c)}if(c<0){d.addClass(SN.C.S.Warning)}else{d.removeClass(SN.C.S.Warning)}if(!SN.C.I.CounterBlackout){SN.C.I.CounterBlackout=true;SN.C.I.FormNoticeCurrent=d;window.setTimeout("SN.U.ClearCounterBlackout(SN.C.I.FormNoticeCurrent);",500)}}}},CharacterCount:function(a){return a.find(".notice_data-text:first").val().length},ClearCounterBlackout:function(a){SN.C.I.CounterBlackout=false;SN.U.Counter(a)},RewriteAjaxAction:function(a){if(document.location.protocol=="https:"&&a.substr(0,5)=="http:"){return a.replace(/^http:\/\/[^:\/]+/,"https://"+document.location.host)}else{return a}},FormXHR:function(a){$.ajax({type:"POST",dataType:"xml",url:SN.U.RewriteAjaxAction(a.attr("action")),data:a.serialize()+"&ajax=1",beforeSend:function(b){a.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled)},error:function(c,d,b){alert(b||d)},success:function(b,c){if(typeof($("form",b)[0])!="undefined"){form_new=document._importNode($("form",b)[0],true);a.replaceWith(form_new)}else{a.replaceWith(document._importNode($("p",b)[0],true))}}})},FormNoticeXHR:function(b){SN.C.I.NoticeDataGeo={};b.append('');b.attr("action",SN.U.RewriteAjaxAction(b.attr("action")));var c=function(d,e){b.append($('

      ').addClass(d).text(e))};var a=function(){b.find(".form_response").remove()};b.ajaxForm({dataType:"xml",timeout:"60000",beforeSend:function(d){if(b.find(".notice_data-text:first").val()==""){b.addClass(SN.C.S.Warning);return false}b.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled);SN.U.normalizeGeoData(b);return true},error:function(f,g,e){b.removeClass(SN.C.S.Processing).find(".submit").removeClass(SN.C.S.Disabled).removeAttr(SN.C.S.Disabled,SN.C.S.Disabled);a();if(g=="timeout"){c("error","Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.")}else{var d=SN.U.GetResponseXML(f);if($("."+SN.C.S.Error,d).length>0){b.append(document._importNode($("."+SN.C.S.Error,d)[0],true))}else{if(parseInt(f.status)===0||jQuery.inArray(parseInt(f.status),SN.C.I.HTTP20x30x)>=0){b.resetForm().find(".attach-status").remove();SN.U.FormNoticeEnhancements(b)}else{c("error","(Sorry! We had trouble sending your notice ("+f.status+" "+f.statusText+"). Please report the problem to the site administrator if this happens again.")}}}},success:function(i,f){a();var n=$("#"+SN.C.S.Error,i);if(n.length>0){c("error",n.text())}else{if($("body")[0].id=="bookmarklet"){self.close()}var d=$("#"+SN.C.S.CommandResult,i);if(d.length>0){c("success",d.text())}else{var m=document._importNode($("li",i)[0],true);var k=$("#notices_primary .notices:first");var l=b.closest("li.notice-reply");if(l.length>0){var e=$(m).attr("id");if($("#"+e).length==0){var j=l.closest("li.notice");l.replaceWith(m);SN.U.NoticeInlineReplyPlaceholder(j)}else{l.remove()}}else{if(k.length>0&&SN.U.belongsOnTimeline(m)){if($("#"+m.id).length===0){var h=b.find("[name=inreplyto]").val();var g="#notices_primary #notice-"+h;if($("body")[0].id=="conversation"){if(h.length>0&&$(g+" .notices").length<1){$(g).append('
        ')}$($(g+" .notices")[0]).append(m)}else{k.prepend(m)}$("#"+m.id).css({display:"none"}).fadeIn(2500);SN.U.NoticeWithAttachment($("#"+m.id));SN.U.switchInputFormTab("placeholder")}}else{c("success",$("title",i).text())}}}b.resetForm();b.find("[name=inreplyto]").val("");b.find(".attach-status").remove();SN.U.FormNoticeEnhancements(b)}},complete:function(d,e){b.removeClass(SN.C.S.Processing).find(".submit").removeAttr(SN.C.S.Disabled).removeClass(SN.C.S.Disabled);b.find("[name=lat]").val(SN.C.I.NoticeDataGeo.NLat);b.find("[name=lon]").val(SN.C.I.NoticeDataGeo.NLon);b.find("[name=location_ns]").val(SN.C.I.NoticeDataGeo.NLNS);b.find("[name=location_id]").val(SN.C.I.NoticeDataGeo.NLID);b.find("[name=notice_data-geo]").attr("checked",SN.C.I.NoticeDataGeo.NDG)}})},normalizeGeoData:function(a){SN.C.I.NoticeDataGeo.NLat=a.find("[name=lat]").val();SN.C.I.NoticeDataGeo.NLon=a.find("[name=lon]").val();SN.C.I.NoticeDataGeo.NLNS=a.find("[name=location_ns]").val();SN.C.I.NoticeDataGeo.NLID=a.find("[name=location_id]").val();SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked");var b=$.cookie(SN.C.S.NoticeDataGeoCookie);if(b!==null&&b!="disabled"){b=JSON.parse(b);SN.C.I.NoticeDataGeo.NLat=a.find("[name=lat]").val(b.NLat).val();SN.C.I.NoticeDataGeo.NLon=a.find("[name=lon]").val(b.NLon).val();if(b.NLNS){SN.C.I.NoticeDataGeo.NLNS=a.find("[name=location_ns]").val(b.NLNS).val();SN.C.I.NoticeDataGeo.NLID=a.find("[name=location_id]").val(b.NLID).val()}else{a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("")}}if(b=="disabled"){SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked",false).attr("checked")}else{SN.C.I.NoticeDataGeo.NDG=a.find("[name=notice_data-geo]").attr("checked",true).attr("checked")}},GetResponseXML:function(b){try{return b.responseXML}catch(a){return(new DOMParser()).parseFromString(b.responseText,"text/xml")}},NoticeReply:function(){$("#content .notice_reply").live("click",function(c){c.preventDefault();var b=$(this).closest("li.notice");var a=($(".author .nickname",b).length>0)?$($(".author .nickname",b)[0]):$(".author .nickname.uid");SN.U.NoticeInlineReplyTrigger(b,"@"+a.text());return false})},NoticeReplyTo:function(a){},NoticeInlineReplyTrigger:function(h,i){var b=$($(".notice_id",h)[0]).text();var e=h;var f=h.closest(".notices");if(f.hasClass("threaded-replies")){e=f.closest(".notice")}else{f=$("ul.threaded-replies",h);if(f.length==0){f=$('
          ');h.append(f)}}var j=$(".notice-reply-form",f);var d=function(){j.find("input[name=inreplyto]").val(b);var m=j.find("textarea");if(m.length==0){throw"No textarea"}var l="";if(i){l=i+" "}m.val(l+m.val().replace(RegExp(l,"i"),""));m.data("initialText",$.trim(i+""));m.focus();if(m[0].setSelectionRange){var k=m.val().length;m[0].setSelectionRange(k,k)}};if(j.length>0){d()}else{f.find("li.notice-reply-placeholder").remove();var g=$("li.notice-reply",f);if(g.length==0){g=$('
        • ');var c=function(k){var l=document._importNode(k,true);g.append(l);f.append(g);var m=j=$(l);SN.Init.NoticeFormSetup(m);d()};if(SN.C.I.NoticeFormMaster){c(SN.C.I.NoticeFormMaster)}else{var a=$("#form_notice").attr("action");$.get(a,{ajax:1},function(k,m,l){c($("form",k)[0])})}}}},NoticeInlineReplyPlaceholder:function(b){var a=b.find("ul.threaded-replies");var c=$('
        • ');c.find("input").val(SN.msg("reply_placeholder"));a.append(c)},NoticeInlineReplySetup:function(){$("li.notice-reply-placeholder input").live("focus",function(){var a=$(this).closest("li.notice");SN.U.NoticeInlineReplyTrigger(a);return false})},NoticeRepeat:function(){$(".form_repeat").live("click",function(a){a.preventDefault();SN.U.NoticeRepeatConfirmation($(this));return false})},NoticeRepeatConfirmation:function(a){var c=a.find(".submit");var b=c.clone();b.addClass("submit_dialogbox").removeClass("submit");a.append(b);b.bind("click",function(){SN.U.FormXHR(a);return false});c.hide();a.addClass("dialogbox").append('').closest(".notice-options").addClass("opaque");a.find("button.close").click(function(){$(this).remove();a.removeClass("dialogbox").closest(".notice-options").removeClass("opaque");a.find(".submit_dialogbox").remove();a.find(".submit").show();return false})},NoticeAttachments:function(){$(".notice a.attachment").each(function(){SN.U.NoticeWithAttachment($(this).closest(".notice"))})},NoticeWithAttachment:function(b){if(b.find(".attachment").length===0){return}var a=b.find(".attachment.more");if(a.length>0){$(a[0]).click(function(){var c=$(this);c.addClass(SN.C.S.Processing);$.get(c.attr("href")+"/ajax",null,function(d){c.parent(".entry-content").html($(d).find("#attachment_view .entry-content").html())});return false}).attr("title",SN.msg("showmore_tooltip"))}},NoticeDataAttach:function(b){var a=b.find("input[type=file]");a.change(function(f){b.find(".attach-status").remove();var d=$(this).val();if(!d){return false}var c=$('
          ');c.find("code").text(d);c.find("button").click(function(){c.remove();a.val("");return false});b.append(c);if(typeof this.files=="object"){for(var e=0;eg){f=false}if(f){h(c,function(j){var i=$("").attr("title",e).attr("alt",e).attr("src",j).attr("style","height: 120px");d.find(".attach-status").append(i)})}else{var b=$("
          ").text(e);d.find(".attach-status").append(b)}},NoticeLocationAttach:function(a){var e=a.find("[name=lat]");var k=a.find("[name=lon]");var g=a.find("[name=location_ns]").val();var l=a.find("[name=location_id]").val();var b="";var d=a.find("[name=notice_data-geo]");var c=a.find("[name=notice_data-geo]");var j=a.find("label.notice_data-geo");function f(n){j.attr("title",jQuery.trim(j.text())).removeClass("checked");a.find("[name=lat]").val("");a.find("[name=lon]").val("");a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("");a.find("[name=notice_data-geo]").attr("checked",false);$.cookie(SN.C.S.NoticeDataGeoCookie,"disabled",{path:"/"});if(n){a.find(".geo_status_wrapper").removeClass("success").addClass("error");a.find(".geo_status_wrapper .geo_status").text(n)}else{a.find(".geo_status_wrapper").remove()}}function m(n,o){SN.U.NoticeGeoStatus(a,"Looking up place name...");$.getJSON(n,o,function(p){var q,r;if(typeof(p.location_ns)!="undefined"){a.find("[name=location_ns]").val(p.location_ns);q=p.location_ns}if(typeof(p.location_id)!="undefined"){a.find("[name=location_id]").val(p.location_id);r=p.location_id}if(typeof(p.name)=="undefined"){NLN_text=o.lat+";"+o.lon}else{NLN_text=p.name}SN.U.NoticeGeoStatus(a,NLN_text,o.lat,o.lon,p.url);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+NLN_text+")");a.find("[name=lat]").val(o.lat);a.find("[name=lon]").val(o.lon);a.find("[name=location_ns]").val(q);a.find("[name=location_id]").val(r);a.find("[name=notice_data-geo]").attr("checked",true);var s={NLat:o.lat,NLon:o.lon,NLNS:q,NLID:r,NLN:NLN_text,NLNU:p.url,NDG:true};$.cookie(SN.C.S.NoticeDataGeoCookie,JSON.stringify(s),{path:"/"})})}if(c.length>0){if($.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){c.attr("checked",false)}else{c.attr("checked",true)}var h=a.find(".notice_data-geo_wrap");var i=h.attr("data-api");j.attr("title",j.text());c.change(function(){if(c.attr("checked")===true||$.cookie(SN.C.S.NoticeDataGeoCookie)===null){j.attr("title",NoticeDataGeo_text.ShareDisable).addClass("checked");if($.cookie(SN.C.S.NoticeDataGeoCookie)===null||$.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){if(navigator.geolocation){SN.U.NoticeGeoStatus(a,"Requesting location from browser...");navigator.geolocation.getCurrentPosition(function(p){a.find("[name=lat]").val(p.coords.latitude);a.find("[name=lon]").val(p.coords.longitude);var q={lat:p.coords.latitude,lon:p.coords.longitude,token:$("#token").val()};m(i,q)},function(p){switch(p.code){case p.PERMISSION_DENIED:f("Location permission denied.");break;case p.TIMEOUT:f("Location lookup timeout.");break}},{timeout:10000})}else{if(e.length>0&&k.length>0){var n={lat:e,lon:k,token:$("#token").val()};m(i,n)}else{f();c.remove();j.remove()}}}else{var o=JSON.parse($.cookie(SN.C.S.NoticeDataGeoCookie));a.find("[name=lat]").val(o.NLat);a.find("[name=lon]").val(o.NLon);a.find("[name=location_ns]").val(o.NLNS);a.find("[name=location_id]").val(o.NLID);a.find("[name=notice_data-geo]").attr("checked",o.NDG);SN.U.NoticeGeoStatus(a,o.NLN,o.NLat,o.NLon,o.NLNU);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+o.NLN+")").addClass("checked")}}else{f()}}).change()}},NoticeGeoStatus:function(e,a,f,g,c){var h=e.find(".geo_status_wrapper");if(h.length==0){h=$('
          ');h.find("button.close").click(function(){e.find("[name=notice_data-geo]").removeAttr("checked").change();return false});e.append(h)}var b;if(c){b=$("").attr("href",c)}else{b=$("")}b.text(a);if(f||g){var d=f+";"+g;b.attr("title",d);if(!a){b.text(d)}}h.find(".geo_status").empty().append(b)},NewDirectMessage:function(){NDM=$(".entity_send-a-message a");NDM.attr({href:NDM.attr("href")+"&ajax=1"});NDM.bind("click",function(){var a=$(".entity_send-a-message form");if(a.length===0){$(this).addClass(SN.C.S.Processing);$.get(NDM.attr("href"),null,function(b){$(".entity_send-a-message").append(document._importNode($("form",b)[0],true));a=$(".entity_send-a-message .form_notice");SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);a.append('');$(".entity_send-a-message button").click(function(){a.hide();return false});NDM.removeClass(SN.C.S.Processing)})}else{a.show();$(".entity_send-a-message textarea").focus()}return false})},GetFullYear:function(c,d,a){var b=new Date();b.setFullYear(c,d,a);return b},StatusNetInstance:{Set:function(b){var a=SN.U.StatusNetInstance.Get();if(a!==null){b=$.extend(a,b)}$.cookie(SN.C.S.StatusNetInstance,JSON.stringify(b),{path:"/",expires:SN.U.GetFullYear(2029,0,1)})},Get:function(){var a=$.cookie(SN.C.S.StatusNetInstance);if(a!==null){return JSON.parse(a)}return null},Delete:function(){$.cookie(SN.C.S.StatusNetInstance,null)}},belongsOnTimeline:function(b){var a=$("body").attr("id");if(a=="public"){return true}var c=$("#nav_profile a").attr("href");if(c){var d=$(b).find(".vcard.author a.url").attr("href");if(d==c){if(a=="all"||a=="showstream"){return true}}}return false},switchInputFormTab:function(a){$(".input_form_nav_tab.current").removeClass("current");if(a=="placeholder"){$("#input_form_nav_status").addClass("current")}else{$("#input_form_nav_"+a).addClass("current")}$(".input_form.current").removeClass("current");$("#input_form_"+a).addClass("current").find(".ajax-notice").each(function(){var b=$(this);SN.Init.NoticeFormSetup(b)}).find("textarea:first").focus()}},Init:{NoticeForm:function(){if($("body.user_in").length>0){$("#input_form_placeholder input.placeholder").focus(function(){SN.U.switchInputFormTab("status")});$("body").bind("click",function(g){var d=$("#content .input_forms div.current");if(d.length>0){if($("#content .input_forms").has(g.target).length==0){var a=d.find('textarea, input[type=text], input[type=""]');var c=false;a.each(function(){c=c||$(this).val()});if(!c){SN.U.switchInputFormTab("placeholder")}}}var b=$("li.notice-reply");if(b.length>0){var f=$(g.target);b.each(function(){var j=$(this);if(j.has(g.target).length==0){var h=j.find(".notice_data-text:first");var i=$.trim(h.val());if(i==""||i==h.data("initialText")){var e=j.closest("li.notice");j.remove();SN.U.NoticeInlineReplyPlaceholder(e)}}})}})}},NoticeFormSetup:function(a){if(!a.data("NoticeFormSetup")){SN.U.NoticeLocationAttach(a);SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);SN.U.NoticeDataAttach(a);a.data("NoticeFormSetup",true)}},Notices:function(){if($("body.user_in").length>0){var a=$(".form_notice:first");if(a.length>0){SN.C.I.NoticeFormMaster=document._importNode(a[0],true)}SN.U.NoticeRepeat();SN.U.NoticeReply();SN.U.NoticeInlineReplySetup()}SN.U.NoticeAttachments()},EntityActions:function(){if($("body.user_in").length>0){SN.U.NewDirectMessage()}},Login:function(){if(SN.U.StatusNetInstance.Get()!==null){var a=SN.U.StatusNetInstance.Get().Nickname;if(a!==null){$("#form_login #nickname").val(a)}}$("#form_login").bind("submit",function(){SN.U.StatusNetInstance.Set({Nickname:$("#form_login #nickname").val()});return true})},AjaxForms:function(){$("form.ajax").live("submit",function(){SN.U.FormXHR($(this));return false})},UploadForms:function(){$("input[type=file]").change(function(d){if(typeof this.files=="object"&&this.files.length>0){var c=0;for(var b=0;b0&&c>a){var e="File too large: maximum upload size is %d bytes.";alert(e.replace("%d",a));$(this).val("");d.preventDefault();return false}}})}}};$(document).ready(function(){SN.Init.AjaxForms();SN.Init.UploadForms();if($("."+SN.C.S.FormNotice).length>0){SN.Init.NoticeForm()}if($("#content .notices").length>0){SN.Init.Notices()}if($("#content .entity_actions").length>0){SN.Init.EntityActions()}if($("#form_login").length>0){SN.Init.Login()}});if(!document.ELEMENT_NODE){document.ELEMENT_NODE=1;document.ATTRIBUTE_NODE=2;document.TEXT_NODE=3;document.CDATA_SECTION_NODE=4;document.ENTITY_REFERENCE_NODE=5;document.ENTITY_NODE=6;document.PROCESSING_INSTRUCTION_NODE=7;document.COMMENT_NODE=8;document.DOCUMENT_NODE=9;document.DOCUMENT_TYPE_NODE=10;document.DOCUMENT_FRAGMENT_NODE=11;document.NOTATION_NODE=12}document._importNode=function(e,a){switch(e.nodeType){case document.ELEMENT_NODE:var d=document.createElement(e.nodeName);if(e.attributes&&e.attributes.length>0){for(var c=0,b=e.attributes.length;c0){for(var c=0,b=e.childNodes.length;c0){var j=c.pop();j()}}};window._google_loader_apiLoaded=function(){f()};var d=function(){return(window.google&&google.loader)};var g=function(j){if(d()){return true}h(j);e();return false};e();return{shim:true,type:"ClientLocation",lastPosition:null,getCurrentPosition:function(k,n,o){var m=this;if(!g(function(){m.getCurrentPosition(k,n,o)})){return}if(google.loader.ClientLocation){var l=google.loader.ClientLocation;var j={coords:{latitude:l.latitude,longitude:l.longitude,altitude:null,accuracy:43000,altitudeAccuracy:null,heading:null,speed:null},address:{city:l.address.city,country:l.address.country,country_code:l.address.country_code,region:l.address.region},timestamp:new Date()};k(j);this.lastPosition=j}else{if(n==="function"){n({code:3,message:"Using the Google ClientLocation API and it is not able to calculate a location."})}}},watchPosition:function(j,l,m){this.getCurrentPosition(j,l,m);var k=this;var n=setInterval(function(){k.getCurrentPosition(j,l,m)},10000);return n},clearWatch:function(j){clearInterval(j)},getPermission:function(l,j,k){return true}}});navigator.geolocation=(window.google&&google.gears)?a():b()})()}; \ No newline at end of file