Merge pull request #1 from hannesmannerheim/master

Merge commits from qvitter 6.10.14
This commit is contained in:
Knut Erik Hollund 2014-10-06 23:32:57 +02:00
commit 615f0d66b8
24 changed files with 3897 additions and 2101 deletions

View File

@ -74,6 +74,16 @@ class QvitterPlugin extends Plugin {
return $settings[$setting];
}
// make sure we have a notifications table
function onCheckSchema()
{
$schema = Schema::get();
$schema->ensureTable('qvitternotification', QvitterNotification::schemaDef());
return true;
}
// route/reroute urls
public function onRouterInitialized($m)
{
@ -91,19 +101,19 @@ class QvitterPlugin extends Plugin {
array('action' => 'apiqvitterallfollowing',
'id' => Nickname::INPUT_FMT));
$m->connect('api/qvitter/update_cover_photo.json',
array('action' => 'ApiUpdateCoverPhoto'));
$m->connect('api/qvitter/statuses/friends_timeline.json',
array('action' => 'apiqvitterfriends'));
$m->connect('api/qvitter/statuses/friends_timeline/:id.json',
array('action' => 'apiqvitterfriends',
'id' => Nickname::INPUT_FMT));
$m->connect('api/qvitter/statuses/mentions/:id.json',
array('action' => 'apiqvittermentions',
'id' => Nickname::INPUT_FMT));
$m->connect('api/qvitter/statuses/mentions.:format',
array('action' => 'apiqvittermentions'));
array('action' => 'ApiUpdateCoverPhoto'));
$m->connect('api/qvitter/statuses/notifications.json',
array('action' => 'apiqvitternotifications'));
$m->connect(':nickname/notifications',
array('action' => 'qvitter',
'nickname' => Nickname::INPUT_FMT));
$m->connect('api/qvitter/newnotifications.json',
array('action' => 'ApiNewNotifications'));
$m->connect('settings/qvitter',
array('action' => 'qvittersettings'));
$m->connect('panel/qvitter',
array('action' => 'qvitteradminsettings'));
common_config_append('admin', 'panels', 'qvitteradm');
$m->connect('main/qlogin',
array('action' => 'qvitterlogin'));
@ -181,7 +191,11 @@ class QvitterPlugin extends Plugin {
URLMapperOverwrite::overwrite_variable($m, 'tag/:tag',
array('action' => 'showstream'),
array('tag' => Router::REGEX_TAG),
'qvitter');
'qvitter');
URLMapperOverwrite::overwrite_variable($m, 'notice/:notice',
array('action' => 'shownotice'),
array('notice' => '[0-9]+'),
'qvitter');
}
}
@ -207,10 +221,35 @@ class QvitterPlugin extends Plugin {
return true;
}
/**
* Menu item for admin panel
*
* @param Action $action action being executed
*
* @return boolean hook return
*/
function onEndAdminPanelNav($action)
{
$action_name = $action->trimmed('action');
$action->out->menuItem(common_local_url('qvitteradminsettings'),
// TRANS: Poll plugin menu item on user settings page.
_m('MENU', 'Qvitter'),
// TRANS: Poll plugin tooltip for user settings menu item.
_m('Qvitter Sidebar Notice'),
$action_name === 'qvitteradminsettings');
return true;
}
/**
* Group addresses in API response
* Add stuff to notices in API responses
*
* @param Action $action action being executed
*
@ -220,6 +259,7 @@ class QvitterPlugin extends Plugin {
function onNoticeSimpleStatusArray($notice, &$twitter_status)
{
// groups
$notice_groups = $notice->getGroups();
$group_addressees = false;
foreach($notice_groups as $g) {
@ -229,26 +269,217 @@ class QvitterPlugin extends Plugin {
if($group_addressees == '') $group_addressees = false;
$twitter_status['statusnet_in_groups'] = $group_addressees;
// thumb urls
// find all thumbs
$attachments = $notice->attachments();
$attachment_url_to_thumb = array();
if (!empty($attachments)) {
foreach ($attachments as $attachment) {
try {
$enclosure_o = $attachment->getEnclosure();
$thumb = File_thumbnail::getKV('file_id', $attachment->id);
if(isset($thumb->url)) {
$attachment_url_to_thumb[$enclosure_o->url] = $thumb->url;
}
} catch (ServerException $e) {
// There was not enough metadata available
}
}
}
// add thumbs to $twitter_status
if (!empty($twitter_status['attachments'])) {
foreach ($twitter_status['attachments'] as &$attachment) {
if (!empty($attachment_url_to_thumb[$attachment['url']])) {
$attachment['thumb_url'] = $attachment_url_to_thumb[$attachment['url']];
}
}
}
return true;
}
/**
* Cover photo in API response
*
* @param Action $action action being executed
* Cover photo in API response, also follows_you
*
* @return boolean hook return
*/
function onTwitterUserArray($profile, &$twitter_user)
function onTwitterUserArray($profile, &$twitter_user, $scoped)
{
$twitter_user['cover_photo'] = Profile_prefs::getConfigData($profile, 'qvitter', 'cover_photo');
// follows me?
if ($scoped) {
$twitter_user['follows_you'] = $profile->isSubscribed($scoped);
}
return true;
}
/**
* Insert into notification table
*/
function insertNotification($to_profile_id, $from_profile_id, $ntype, $notice_id=false)
{
// never notify myself
if($to_profile_id != $from_profile_id) {
// insert
$notif = new QvitterNotification();
$notif->to_profile_id = $to_profile_id;
$notif->from_profile_id = $from_profile_id;
$notif->ntype = $ntype;
$notif->notice_id = $notice_id;
$notif->created = common_sql_now();
if (!$notif->insert()) {
common_log_db_error($notif, 'INSERT', __FILE__);
return false;
}
}
return true;
}
/**
* Insert likes in notification table
*/
public function onEndFavorNotice($profile, $notice)
{
// don't notify people favoriting their own notices
if($notice->profile_id != $profile->id) {
$this->insertNotification($notice->profile_id, $profile->id, 'like', $notice->id, $notice->id);
}
}
/**
* Remove likes in notification table on dislike
*/
public function onEndDisfavorNotice($profile, $notice)
{
$notif = new QvitterNotification();
$notif->from_profile_id = $profile->id;
$notif->notice_id = $notice->id;
$notif->ntype = 'like';
$notif->delete();
return true;
}
/**
* Insert notifications for replies, mentions and repeats
*
* @return boolean hook flag
*/
function onStartNoticeDistribute($notice) {
// repeats
if ($notice->isRepeat()) {
$repeated_notice = Notice::getKV('id', $notice->repeat_of);
if ($repeated_notice instanceof Notice) {
$this->insertNotification($repeated_notice->profile_id, $notice->profile_id, 'repeat', $repeated_notice->id);
}
}
// replies and mentions (no notifications for these if this is a repeat)
else {
$reply_notification_to = false;
// check for reply to insert in notifications
if($notice->reply_to) {
$replyparent = $notice->getParent();
$replyauthor = $replyparent->getProfile();
if ($replyauthor instanceof Profile) {
$reply_notification_to = $replyauthor->id;
$this->insertNotification($replyauthor->id, $notice->profile_id, 'reply', $notice->id);
}
}
// check for mentions to insert in notifications
$mentions = common_find_mentions($notice->content, $notice);
$sender = Profile::getKV($notice->profile_id);
foreach ($mentions as $mention) {
foreach ($mention['mentioned'] as $mentioned) {
// Not from blocked profile
$mentioned_user = User::getKV('id', $mentioned->id);
if ($mentioned_user instanceof User && $mentioned_user->hasBlocked($sender)) {
continue;
}
// only notify if mentioned user is not already notified for reply
if($reply_notification_to != $mentioned->id) {
$this->insertNotification($mentioned->id, $notice->profile_id, 'mention', $notice->id);
}
}
}
}
return true;
}
/**
* Delete any notifications tied to deleted notices and un-repeats
*
* @return boolean hook flag
*/
public function onNoticeDeleteRelated($notice)
{
$notif = new QvitterNotification();
// unrepeats
if ($notice->isRepeat()) {
$repeated_notice = Notice::getKV('id', $notice->repeat_of);
$notif->notice_id = $repeated_notice->id;
$notif->from_profile_id = $notice->profile_id;
}
// notices
else {
$notif->notice_id = $notice->id;
}
$notif->delete();
return true;
}
/**
* Add notification on subscription, remove on unsubscribe
*
* @return boolean hook flag
*/
public function onEndSubscribe($subscriber, $other)
{
if(Subscription::exists($subscriber, $other)) {
$this->insertNotification($other->id, $subscriber->id, 'follow');
}
return true;
}
public function onEndUnsubscribe($subscriber, $other)
{
if(!Subscription::exists($subscriber, $other)) {
$notif = new QvitterNotification();
$notif->to_profile_id = $other->id;
$notif->from_profile_id = $subscriber->id;
$notif->ntype = 'follow';
$notif->delete();
}
return true;
}
}

View File

@ -43,16 +43,26 @@ Note: Qvitter is tested with GNU Social version 1.1.1-alpha2 (7e47026085fa4f2071
TODO
----
1. "following you" badge on other peoples profiles
1. avatar upload from profile card
1. better user popup, with e.g. latest queets
1. Faq
1. DM's
1. lists
1. user actions-cog wheel in users lists, with block, list etc
1. proxy to non-https for getting conversations the instance doesn't have via jsonp
1. preview different types of attachments, not just images. e.g. mp3's, torrents etc etc
1. Join _new_ external groups and follow _new_ external users ("New" meaning users/groups that the server don't know yet)
2. Creating groups, make admin, block user
3. Background image uploading/editing
6. Auto url-shortening setting under queet box
7. Settings (e.g. don't show replies to people I don't follow)
9. Image/file upload
@ -65,14 +75,8 @@ TODO
14. More languages, maybe make proper po/mo-files
15. Notice-page
16. Admin-interface
16. New api for serving _number_ of new items in several streams (to show number of new items in menu/history)
17. Notifications-page with likes and repeats
17. New "expand queet" api for getting conversation, retweets, favs and attachment in the same request
19. Node.js long polling server and an new api that serve aggregate of all polling users requests in one go

View File

@ -0,0 +1,100 @@
<?php
/**
*
* Qvitter: Unread notifications
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package GNUsocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiNewNotificationsAction extends ApiAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
protected function prepare(array $args=array())
{
parent::prepare($args);
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
protected function handle()
{
parent::handle();
$new_notifications = array();
if(Profile::current()) {
$user_id = Profile::current()->id;
$notification = new QvitterNotification();
$notification->selectAdd();
$notification->selectAdd('ntype');
$notification->selectAdd('count(id) as count');
$notification->whereAdd("(to_profile_id = '".$user_id."')");
$notification->groupBy('ntype');
$notification->whereAdd("(is_seen = '0')");
$notification->find();
while ($notification->fetch()) {
$new_notifications[$notification->ntype] = $notification->count;
}
}
else {
$new_notifications = 'You must be logged in.';
}
$this->initDocument('json');
$this->showJsonObjects($new_notifications);
$this->endDocument('json');
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -1,46 +0,0 @@
<?php
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiQvitterFriendsAction extends ApiTimelineFriendsAction
{
function showTimeline()
{
ApiQvitterAction::showQvitterJsonTimeline($this->notices);
}
}

View File

@ -1,44 +0,0 @@
<?php
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiQvitterMentionsAction extends ApiTimelineMentionsAction
{
function showTimeline()
{
ApiQvitterAction::showQvitterJsonTimeline($this->notices);
}
}

View File

@ -0,0 +1,206 @@
<?php
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('STATUSNET')) {
exit(1);
}
class ApiQvitterNotificationsAction extends ApiPrivateAuthAction
{
var $notifications = null;
var $notices = null;
var $profiles = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->notifications = $this->getNotifications();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$notice = null;
$notifications_populated = array();
if(!empty($this->notifications)) {
foreach($this->notifications as $notification) {
// all but follow has an notice
if($notification->ntype != 'follow') {
$notice = self::twitterSimpleStatusArray(Notice::getKV($notification->notice_id));
}
$notifications_populated[] = array(
'id'=> $notification->id,
'from_profile'=> self::twitterUserArray(Profile::getKV($notification->from_profile_id)),
'ntype'=> $notification->ntype,
'notice'=> $notice,
'created_at'=>self::dateTwitter($notification->created),
'is_seen'=>$notification->is_seen
);
}
// mark as seen
foreach($this->notifications as $notification) {
if($notification->is_seen == 0) {
$notification->is_seen = 1;
$notification->update();
}
}
}
$this->initDocument('json');
$this->showJsonObjects($notifications_populated);
$this->endDocument('json');
}
/**
* Get notices
*
* @return array notices
*/
function getNotifications()
{
$notices = array();
$profile = ($this->auth_user) ? $this->auth_user->getProfile() : null;
if(!$profile instanceof Profile) {
return false;
}
$stream = new NotificationStream($profile);
$notifications = $stream->getNotifications(($this->page - 1) * $this->count,
$this->count,
$this->since_id,
$this->max_id);
$notifications = $notifications->fetchAll();
return $notifications;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notifications) && (count($this->notifications) > 0)) {
return strtotime($this->notifications[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notifications) && (count($this->notifications) > 0)) {
$last = count($this->notifications) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(),
strtotime($this->notifications[0]->created),
strtotime($this->notifications[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -1,38 +1,37 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show the public timeline
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('STATUSNET')) {
exit(1);
@ -54,94 +53,6 @@ if (!defined('STATUSNET')) {
* @link http://status.net/
*/
/* External API usage documentation. Please update when you change how this method works. */
/*! @page publictimeline statuses/public_timeline
@section Description
Returns the 20 most recent notices from users throughout the system who have
uploaded their own avatars. Depending on configuration, it may or may not
not include notices from automatic posting services.
@par URL patterns
@li /api/statuses/public_timeline.:format
@par Formats (:format)
xml, json, rss, atom
@par HTTP Method(s)
GET
@par Requires Authentication
No
@param since_id (Optional) Returns only statuses with an ID greater
than (that is, more recent than) the specified ID.
@param max_id (Optional) Returns only statuses with an ID less than
(that is, older than) or equal to the specified ID.
@param count (Optional) Specifies the number of statuses to retrieve.
@param page (Optional) Specifies the page of results to retrieve.
@sa @ref apiroot
@subsection usagenotes Usage notes
@li The URL pattern is relative to the @ref apiroot.
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
to encode the latitude and longitude (see example response below <georss:point>).
@subsection exampleusage Example usage
@verbatim
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
@endverbatim
@subsection exampleresponse Example response
@verbatim
<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
<text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
<truncated>false</truncated>
<created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
<in_reply_to_status_id>28838393</in_reply_to_status_id>
<source>xmpp</source>
<id>28838456</id>
<in_reply_to_user_id>39303</in_reply_to_user_id>
<in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
<geo></geo>
<favorited>false</favorited>
<user>
<id>44517</id>
<name>joshua may</name>
<screen_name>notjosh</screen_name>
<location></location>
<description></description>
<profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
<url></url>
<protected>false</protected>
<followers_count>17</followers_count>
<profile_background_color></profile_background_color>
<profile_text_color></profile_text_color>
<profile_link_color></profile_link_color>
<profile_sidebar_fill_color></profile_sidebar_fill_color>
<profile_sidebar_border_color></profile_sidebar_border_color>
<friends_count>20</friends_count>
<created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
<favourites_count>0</favourites_count>
<utc_offset>0</utc_offset>
<time_zone>UTC</time_zone>
<profile_background_image_url></profile_background_image_url>
<profile_background_tile>false</profile_background_tile>
<statuses_count>100</statuses_count>
<following>false</following>
<notifications>false</notifications>
</user>
</status>
[....]
</statuses>
@endverbatim
*/
class ApiTimelinePublicAndExternalAction extends ApiPrivateAuthAction
{
var $notices = null;
@ -230,7 +141,7 @@ class ApiTimelinePublicAndExternalAction extends ApiPrivateAuthAction
break;
case 'json':
ApiQvitterAction::showQvitterJsonTimeline($this->notices);
$this->showJsonTimeline($this->notices);
break;
case 'as':
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);

View File

@ -102,9 +102,9 @@ class QvitterAction extends ApiAction
<title><?php print $sitetitle; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
<link rel="stylesheet" type="text/css" href="<?php print $qvitterpath; ?>css/qvitter.css?v=18" />
<link rel="stylesheet" type="text/css" href="<?php print $qvitterpath; ?>css/qvitter.css?v=20" />
<link rel="stylesheet" type="text/css" href="<?php print $qvitterpath; ?>css/jquery.minicolors.css" />
<link rel="shortcut icon" type="image/x-icon" href="<?php print $qvitterpath; ?>favicon.ico?v=2">
<link rel="shortcut icon" type="image/x-icon" href="<?php print $qvitterpath; ?>favicon.ico?v=3">
<?php
// if qvitter is a webapp and this is a users url we add feeds
@ -155,7 +155,13 @@ class QvitterAction extends ApiAction
window.textLimit = <?php print json_encode((int)common_config('site','textlimit')) ?>;
window.registrationsClosed = <?php print json_encode($registrationsclosed) ?>;
window.siteTitle = <?php print json_encode($sitetitle) ?>;
window.loggedIn = <?php print json_encode($logged_in_user_obj) ?>;
window.loggedIn = <?php
$logged_in_user_json = json_encode($logged_in_user_obj);
$logged_in_user_json = str_replace('http:\/\/quitter.se\/','https:\/\/quitter.se\/',$logged_in_user_json);
print $logged_in_user_json;
?>;
window.timeBetweenPolling = <?php print QvitterPlugin::settings("timebetweenpolling"); ?>;
window.apiRoot = '<?php print common_path("api/", true); ?>';
window.avatarRoot = '<?php print common_path("avatar/", true); ?>';
@ -189,7 +195,9 @@ class QvitterAction extends ApiAction
color:#0084B4;/*COLOREND*/
}
.topbar .global-nav,
.menu-container {
.menu-container,
#unseen-notifications,
.stream-item.notification .not-seen {
background-color:#0084B4;/*BACKGROUNDCOLOREND*/
}
</style>
@ -210,9 +218,7 @@ class QvitterAction extends ApiAction
<span class="caret-inner"></span>
</li>
<li><a id="settings"></a></li>
<?php
if($siterootdomain == 'quitter.se') { print '<li><a id="classic" href="https://old.quitter.se/">Classic Quitter</a></li>'; } // sry for this junk
?><li class="dropdown-divider"></li>
<li class="dropdown-divider"></li>
<li><a id="logout"></a></li>
<li class="language dropdown-divider"></li>
<li class="language"><a class="language-link" title="Arabic" data-lang-code="ar">العربيّة</a></li>
@ -230,7 +236,8 @@ class QvitterAction extends ApiAction
<li class="language"><a class="language-link" title="Norwegian" data-lang-code="no">Norsk</a></li>
<li class="language"><a class="language-link" title="Português-Brasil" data-lang-code="pt_br">Português-Brasil</a></li>
<li class="language"><a class="language-link" title="Swedish" data-lang-code="sv">svenska</a></li>
</ul>
</ul>
<div id="birds-top"></div>
<div class="global-nav">
<div class="global-nav-inner">
<div class="container">
@ -278,7 +285,14 @@ class QvitterAction extends ApiAction
</div>
</div>
<div id="page-container">
<div class="front-welcome-text">
<?php
$site_notice = common_config('site', 'notice');
if(!empty($site_notice)) {
print '<div id="site-notice">'.common_config('site', 'notice').'</div>';
}
?><div class="front-welcome-text">
<h1></h1>
<p></p>
</div>
@ -342,14 +356,16 @@ class QvitterAction extends ApiAction
</div>
</div>
<div class="menu-container">
<a class="stream-selection friends-timeline" data-stream-header="" data-stream-name="qvitter/statuses/friends_timeline.json"><i class="chev-right"></i></a>
<a class="stream-selection mentions" data-stream-header="" data-stream-name="qvitter/statuses/mentions.json"><i class="chev-right"></i></a>
<a class="stream-selection friends-timeline" data-stream-header="" data-stream-name="statuses/friends_timeline.json"><i class="chev-right"></i></a>
<a class="stream-selection notifications" data-stream-header="" data-stream-name="qvitter/statuses/notifications.json"><span id="unseen-notifications"></span><i class="chev-right"></i></a>
<a class="stream-selection mentions" data-stream-header="" data-stream-name="statuses/mentions.json"><i class="chev-right"></i></a>
<a class="stream-selection my-timeline" data-stream-header="@statuses/user_timeline.json" data-stream-name="statuses/user_timeline.json"><i class="chev-right"></i></a>
<a class="stream-selection favorites" data-stream-header="" data-stream-name="favorites.json"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>" class="stream-selection public-timeline" data-stream-header="" data-stream-name="statuses/public_timeline.json"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>main/all" class="stream-selection public-and-external-timeline" data-stream-header="" data-stream-name="statuses/public_and_external_timeline.json"><i class="chev-right"></i></a>
</div>
<div class="menu-container" id="history-container"></div>
<div id="qvitter-notice"><?php print common_config('site', 'qvitternotice'); ?></div>
</div>
<div id="feed">
<div id="feed-header">
@ -364,17 +380,17 @@ class QvitterAction extends ApiAction
<div id="footer"></div>
</div>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery-2.0.2.min.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery-ui-1.10.3.min.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery.easing.1.3.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery.minicolors.min.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery.jWindowCrop.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/load-image.min.js"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/dom-functions.js?v=22"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/misc-functions.js?v=17"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/ajax-functions.js?v=9"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lan.js?v=23"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/qvitter.js?v=18"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/dom-functions.js?v=24"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/misc-functions.js?v=19"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/ajax-functions.js?v=11"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lan.js?v=25"></script>
<script type="text/javascript" src="<?php print $qvitterpath; ?>js/qvitter.js?v=20"></script>
</body>
</html>

View File

@ -0,0 +1,203 @@
<?php
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
class QvitterAdminSettingsAction extends AdminPanelAction
{
/**
* Returns the page title
*
* @return string page title
*/
function title()
{
// TRANS: Page title for site-wide notice tab in admin panel.
return _('Qvitter Sidebar Notice');
}
/**
* Instructions for using this form.
*
* @return string instructions
*/
function getInstructions()
{
// TRANS: Instructions for site-wide notice tab in admin panel.
return _('Edit notice in Qvitter\'s sidebar');
}
/**
* Show the site notice admin panel form
*
* @return void
*/
function showForm()
{
$form = new QvitterNoticeAdminPanelForm($this);
$form->show();
return;
}
/**
* Save settings from the form
*
* @return void
*/
function saveSettings()
{
$qvitterNotice = $this->trimmed('qvitter-notice');
// assert(all values are valid);
// This throws an exception on validation errors
$this->validate($qvitterNotice);
$config = new Config();
$result = Config::save('site', 'qvitternotice', $qvitterNotice);
if (!$result) {
// TRANS: Server error displayed when saving a sidebar notice was impossible.
$this->ServerError(_('Unable to save qvitter sidebar notice.'));
}
}
function validate(&$qvitterNotice)
{
// Validate notice text
if (mb_strlen($qvitterNotice) > 255) {
$this->clientError(
// TRANS: Client error displayed when a sidebar notice was longer than allowed.
_('Maximum length for the sidebar notice is 255 characters.')
);
}
// scrub HTML input
$config = array(
'safe' => 1,
'deny_attribute' => 'on*'
);
$qvitterNotice = htmLawed($qvitterNotice, $config);
}
}
class QvitterNoticeAdminPanelForm extends AdminForm
{
/**
* ID of the form
*
* @return int ID of the form
*/
function id()
{
return 'form_qvitter_notice_admin_panel';
}
/**
* class of the form
*
* @return string class of the form
*/
function formClass()
{
return 'form_settings';
}
/**
* Action of the form
*
* @return string URL of the action
*/
function action()
{
return common_local_url('qvitteradminsettings');
}
/**
* Data elements of the form
*
* @return void
*/
function formData()
{
$this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li');
$this->out->textarea(
'qvitter-notice',
// TRANS: Label for sidebar notice text field in admin panel.
_('Qvitter sidebar notice text'),
common_config('site', 'qvitternotice'),
// TRANS: Tooltip for sidebar notice text field in admin panel.
_('Qvitter\'s sidebar notice text (255 characters maximum; HTML allowed)')
);
$this->out->elementEnd('li');
$this->out->elementEnd('ul');
}
/**
* Action elements
*
* @return void
*/
function formActions()
{
$this->out->submit(
'submit',
// TRANS: Button text for saving sidebar notice in admin panel.
_m('BUTTON','Save'),
'submit',
null,
// TRANS: Button title to save sidebar notice in admin panel.
_('Save sidebar notice.')
);
}
}

View File

@ -1,160 +0,0 @@
<?php
/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· http://github.com/hannesmannerheim/qvitter ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· ·
· Qvitter is free software: you can redistribute it and / or modify it ·
· under the terms of the GNU Affero General Public License as published by ·
· the Free Software Foundation, either version three of the License or (at ·
· your option) any later version. ·
· ·
· Qvitter is distributed in hope that it will be useful but WITHOUT ANY ·
· WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS ·
· FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for ·
· more details. ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· Contact h@nnesmannerhe.im if you have any questions. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiQvitterAction extends ApiAction
{
function showQvitterJsonTimeline($notice)
{
$this->initDocument('json');
$statuses = array();
if (is_array($notice)) {
$notice = new ArrayWrapper($notice);
}
while ($notice->fetch()) {
try {
$twitter_status = $this->twitterStatusArray($notice);
array_push($statuses, $twitter_status);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
}
}
$simplified_statuses = new stdClass();
$i=0;
foreach($statuses as &$s) {
foreach($s as &$ss) {
if($ss === false || $ss === null) {
$ss=0;
}
elseif($ss === true) {
$ss=1;
}
}
foreach($s['user'] as &$su) {
if($su === false || $su === null) {
$su=0;
}
elseif($su === true) {
$su=1;
}
}
$simplified_statuses->s[$i][0] = $s['id'];
$simplified_statuses->s[$i][1] = strtotime($s['created_at']);
$simplified_statuses->s[$i][2] = $s['text'];
$simplified_statuses->s[$i][3] = $s['statusnet_html'];
$simplified_statuses->s[$i][4] = $s['in_reply_to_status_id'];
$simplified_statuses->s[$i][5] = $s['in_reply_to_user_id'];
$simplified_statuses->s[$i][6] = $s['in_reply_to_screen_name'];
$simplified_statuses->s[$i][7] = $s['favorited'];
$simplified_statuses->s[$i][8] = $s['repeated'];
$simplified_statuses->s[$i][9] = $s['statusnet_in_groups'];
$simplified_statuses->s[$i][10] = $s['user']['id'];
$simplified_statuses->s[$i][11] = $s['statusnet_conversation_id'];
$simplified_statuses->s[$i][12] = $s['source'];
$simplified_statuses->u[$s['user']['id']][0] = $s['user']['screen_name'];
$simplified_statuses->u[$s['user']['id']][1] = $s['user']['name'];
$simplified_statuses->u[$s['user']['id']][2] = $s['user']['location'];
$simplified_statuses->u[$s['user']['id']][3] = $s['user']['description'];
$simplified_statuses->u[$s['user']['id']][4] = $s['user']['profile_image_url_profile_size'];
$simplified_statuses->u[$s['user']['id']][5] = $s['user']['profile_image_url_original'];
$simplified_statuses->u[$s['user']['id']][6] = $s['user']['groups_count'];
$simplified_statuses->u[$s['user']['id']][7] = $s['user']['linkcolor'];
$simplified_statuses->u[$s['user']['id']][8] = $s['user']['backgroundcolor'];
$simplified_statuses->u[$s['user']['id']][9] = $s['user']['url'];
$simplified_statuses->u[$s['user']['id']][10] = $s['user']['followers_count'];
$simplified_statuses->u[$s['user']['id']][11] = $s['user']['friends_count'];
$simplified_statuses->u[$s['user']['id']][12] = $s['user']['favourites_count'];
$simplified_statuses->u[$s['user']['id']][13] = $s['user']['statuses_count'];
$simplified_statuses->u[$s['user']['id']][14] = $s['user']['following'];
$simplified_statuses->u[$s['user']['id']][15] = $s['user']['statusnet_blocking'];
$simplified_statuses->u[$s['user']['id']][16] = $s['user']['statusnet_profile_url'];
$simplified_statuses->u[$s['user']['id']][17] = $s['user']['cover_photo'];
if(isset($s['retweeted_status'])) {
$simplified_statuses->s[$i][13][0] = $s['retweeted_status']['id'];
$simplified_statuses->s[$i][13][1] = strtotime($s['retweeted_status']['created_at']);
$simplified_statuses->s[$i][13][2] = $s['retweeted_status']['text'];
$simplified_statuses->s[$i][13][3] = $s['retweeted_status']['statusnet_html'];
$simplified_statuses->s[$i][13][4] = $s['retweeted_status']['in_reply_to_status_id'];
$simplified_statuses->s[$i][13][5] = $s['retweeted_status']['in_reply_to_user_id'];
$simplified_statuses->s[$i][13][6] = $s['retweeted_status']['in_reply_to_screen_name'];
$simplified_statuses->s[$i][13][7] = $s['retweeted_status']['favorited'];
$simplified_statuses->s[$i][13][8] = $s['retweeted_status']['repeated'];
$simplified_statuses->s[$i][13][9] = $s['retweeted_status']['statusnet_in_groups'];
$simplified_statuses->s[$i][13][10] = $s['retweeted_status']['user']['id'];
$simplified_statuses->s[$i][13][11] = $s['retweeted_status']['statusnet_conversation_id'];
$simplified_statuses->s[$i][13][12] = $s['retweeted_status']['source'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][0] = $s['retweeted_status']['user']['screen_name'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][1] = $s['retweeted_status']['user']['name'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][2] = $s['retweeted_status']['user']['location'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][3] = $s['retweeted_status']['user']['description'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][4] = $s['retweeted_status']['user']['profile_image_url_profile_size'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][5] = $s['retweeted_status']['user']['profile_image_url_original'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][6] = $s['retweeted_status']['user']['groups_count'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][7] = $s['retweeted_status']['user']['linkcolor'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][8] = $s['retweeted_status']['user']['backgroundcolor'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][9] = $s['retweeted_status']['user']['url'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][10] = $s['retweeted_status']['user']['followers_count'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][11] = $s['retweeted_status']['user']['friends_count'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][12] = $s['retweeted_status']['user']['favourites_count'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][13] = $s['retweeted_status']['user']['statuses_count'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][14] = $s['retweeted_status']['user']['following'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][15] = $s['retweeted_status']['user']['statusnet_blocking'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][16] = $s['retweeted_status']['user']['statusnet_profile_url'];
$simplified_statuses->u[$s['retweeted_status']['user']['id']][17] = $s['retweeted_status']['user']['cover_photo'];
}
$i++;
}
$this->showJsonObjects($simplified_statuses);
$this->endDocument('json');
}
}

View File

@ -0,0 +1,85 @@
<?php
/**
*
* Notification stream
*
*/
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
class NotificationStream
{
protected $target = null;
/**
* Constructor
*
* @param Profile $target Profile to get a stream for
*/
function __construct(Profile $target)
{
$this->target = $target;
}
/**
* Get IDs in a range
*
* @param int $offset Offset from start
* @param int $limit Limit of number to get
* @param int $since_id Since this notice
* @param int $max_id Before this notice
*
* @return Array IDs found
*/
function getNotificationIds($offset, $limit, $since_id, $max_id)
{
$notification = new QvitterNotification();
$notification->selectAdd();
$notification->selectAdd('id');
$notification->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $notification->escape($this->target->id)));
$notification->whereAdd(sprintf('qvitternotification.created > "%s"', $notification->escape($this->target->created)));
$notification->limit($offset, $limit);
$notification->orderBy('qvitternotification.created DESC');
QvitterNotification::addWhereSinceId($notification, $since_id);
QvitterNotification::addWhereMaxId($notification, $max_id);
if (!$notification->find()) {
return array();
}
$ids = $notification->fetchAll('id');
return $ids;
}
function getNotifications($offset, $limit, $sinceId, $maxId)
{
$all = array();
do {
$ids = $this->getNotificationIds($offset, $limit, $sinceId, $maxId);
$notifications = QvitterNotification::pivotGet('id', $ids);
// By default, takes out false values
$notifications = array_filter($notifications);
$all = array_merge($all, $notifications);
if (count($notifications < count($ids))) {
$offset += $limit;
$limit -= count($notifications);
}
} while (count($notifications) < count($ids) && count($ids) > 0);
return new ArrayWrapper($all);
}
}

View File

@ -0,0 +1,152 @@
<?php
/**
* Table Definition for reply
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class QvitterNotification extends Managed_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'qvitternotification'; // table name
public $id; // int(4) primary_key not_null
public $to_profile_id; // int(4) primary_key not_null
public $from_profile_id; // int(4) primary_key not_null
public $type; // varchar(7)
public $notice_id; // int(4) primary_key not_null
public $date; // datetime multiple_key not_null default_0000-00-00%2000%3A00%3A00
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
public static function schemaDef()
{
return array(
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true),
'to_profile_id' => array('type' => 'int', 'description' => 'the profile being notified'),
'from_profile_id' => array('type' => 'int', 'description' => 'the profile that is notifying'),
'ntype' => array('type' => 'varchar', 'length' => 7, 'description' => 'reply, like, mention or follow'),
'notice_id' => array('type' => 'int', 'description' => 'id for the reply or mention or notice being faved'),
'is_seen' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'if the notification has been seen'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created')
),
'primary key' => array('id')
);
}
/**
* Wrapper for record insertion to update related caches
*/
function insert()
{
$result = parent::insert();
if ($result) {
self::blow('qvitternotification:stream:%d', $this->to_profile_id);
}
return $result;
}
/**
* Look up the creation timestamp for a given notice ID, even
* if it's been deleted.
*
* @param int $id
* @return mixed string recorded creation timestamp, or false if can't be found
*/
public static function getAsTimestamp($id)
{
if (!$id) {
return false;
}
$notice = QvitterNotification::getKV('id', $id);
if ($notice) {
return $notice->created;
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a since_id
* parameter, matching notices posted after the given one (exclusive).
*
* If the referenced notice can't be found, will return false.
*
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function whereSinceId($id, $idField='id', $createdField='created')
{
$since = QvitterNotification::getAsTimestamp($id);
if ($since) {
return sprintf("($createdField = '%s' and $idField > %d) or ($createdField > '%s')", $since, $id, $since);
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a since_id
* parameter, matching notices posted after the given one (exclusive), and
* if necessary add it to the data object's query.
*
* @param DB_DataObject $obj
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function addWhereSinceId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
{
$since = self::whereSinceId($id, $idField, $createdField);
if ($since) {
$obj->whereAdd($since);
}
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a max_id
* parameter, matching notices posted before the given one (inclusive).
*
* If the referenced notice can't be found, will return false.
*
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function whereMaxId($id, $idField='id', $createdField='created')
{
$max = QvitterNotification::getAsTimestamp($id);
if ($max) {
return sprintf("($createdField < '%s') or ($createdField = '%s' and $idField <= %d)", $max, $max, $id);
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a max_id
* parameter, matching notices posted before the given one (inclusive), and
* if necessary add it to the data object's query.
*
* @param DB_DataObject $obj
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function addWhereMaxId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
{
$max = self::whereMaxId($id, $idField, $createdField);
if ($max) {
$obj->whereAdd($max);
}
}
}

View File

@ -89,7 +89,7 @@ button.icon.nav-search,
.upload-cover-photo,
button.shorten i,
.reload-stream {
background-image: url("../img/sprite.png?v=4");
background-image: url("../img/sprite.png?v=6");
background-size: 500px 1329px;
}
@ -409,11 +409,11 @@ body.rtl .dropdown-menu li:not(.dropdown-caret) {
.dropdown-menu.quitter-settings li.language {
display:none;
}
#birds-top {
background-position: -193px -3px;
background-position: -385px -5px;
display: block;
height: 64px;
height: 75px;
position: fixed;
right: 0;
width: 103px;
@ -436,7 +436,8 @@ body.rtl .dropdown-menu li:not(.dropdown-caret) {
unicode-bidi: bidi-override;
}
.front-welcome-text {
.front-welcome-text,
#site-notice {
color: #EEEEEE;
font-size: 30px;
font-weight: 300;
@ -453,6 +454,26 @@ body.rtl .front-welcome-text {
text-align:right;
font-family:Tahoma,Arial,sans-serif;
}
#site-notice{
display:block;
}
#qvitter-notice {
text-shadow:none;
color:#fff;
font-size:11px;
padding:10px;
display:none;
}
#qvitter-notice a {
color:#fff;
opacity:0.5;
line-height:17px;
display:inline-block;
}
#qvitter-notice a:hover {
opacity:0.8;
}
.front-welcome-text h1 {
color: #FFFFFF;
font-size: 30px;
@ -992,7 +1013,32 @@ button#submit-login:hover {
}
#history-container a:hover .chev-right:hover {
background-position:-40px -508px;
}
}
.menu-container a.notifications {
line-height:32px;
padding:0 12px;
position:relative;
}
#unseen-notifications {
display:block;
position:absolute;
right:0px;
top:0;
width:24px;
height:24px;
line-height:24px;
border-radius:12px;
color:#fff;
text-shadow:none;
margin:4px 5px;
z-index:10;
display:none;
text-align:center;
font-weight:normal;
}
#history-container {
display:none;
}
@ -1204,6 +1250,7 @@ button#submit-login:hover {
-o-transition: opacity 0.1s ease, height 0s linear, margin 0.1s ease;
transition: opacity 0.1s ease, height 0s linear, margin 0.1s ease;
height:auto;
/* position:relative; */
}
.stream-item.hidden {
display:none;
@ -1230,6 +1277,70 @@ button#submit-login:hover {
.stream-item.conversation .queet:hover {
background-color:#F6F6F6;
}
.stream-item.notification .not-seen {
position:absolute;
left:-5px;
top:50%;
margin-top:-5px;
width:10px;
height:10px;
border-radius:5px;
z-index:10;
}
.stream-item.notification.repeat .dogear,
.stream-item.notification.like .dogear {
display:block;
left: 36px;
top: 7px;
z-index: 10;
width:24px;
height:24px;
}
.stream-item.notification.repeat .dogear {
background-position:-70px -1072px;
}
.stream-item.notification.like .dogear {
background-position:-115px -1075px;
}
.stream-item.notification.follow .queet,
.stream-item.notification.repeat .queet,
.stream-item.notification.like .queet {
min-height:37px;
cursor:default;
}
.stream-item.notification.follow .queet .queet-content,
.stream-item.notification.repeat .queet .queet-content,
.stream-item.notification.like .queet .queet-content {
cursor:default;
}
.stream-item.notification.follow .queet:hover,
.stream-item.notification.repeat .queet:hover,
.stream-item.notification.like .queet:hover {
background-color:transparent;
}
.stream-item.notification.follow a.account-group img.avatar,
.stream-item.notification.repeat a.account-group img.avatar,
.stream-item.notification.like a.account-group img.avatar {
width:24px;
height:24px;
left:36px;
top:4px;
}
.stream-item.notification .small-grey-notice,
.stream-item.notification .small-grey-notice a {
color:#999;
}
.stream-item.notification .small-grey-notice a:hover {
color:#333;
text-decoration:underline;
}
.stream-item.notification .stream-item-header {
color:#333;
}
.show-full-conversation {
float:right;
font-style:italic;
@ -1281,6 +1392,14 @@ button#submit-login:hover {
border-radius:0 0 6px 6px;
}
.expanded-content {
-webkit-transition: height 0s linear;
-moz-transition: height 0s linear;
-o-transition: height 0s linear;
transition: height 0s linear;
overflow:hidden;
}
body.rtl .queet.rtl .expanded-content {
direction:rtl;
}
@ -1884,6 +2003,7 @@ ul.queet-actions li .icon.sm-fav {
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 6px 6px 6px 6px;
margin:8px 0;
overflow: hidden;
}
.stream-item.expanded > .queet{
}
@ -2741,13 +2861,27 @@ button.signup-btn.disabled,
}
.profile-header-inner .profile-card-inner h2.username {
margin-top:0;
color: #FFFFFF;
color: #FFFFFF;
font-size: 18px;
font-weight: normal;
line-height: 24px;
margin-bottom: 1px;
text-rendering: optimizelegibility;
}
.profile-header-inner .profile-card-inner h2.username .follows-you {
display:inline-block;
font-size:11px;
color:#eee;
background-color:rgba(0,0,0,0.5);
padding:3px 5px;
height:15px;
line-height:15px;
border-radius:3px;
margin-left:7px;
text-transform:uppercase;
}
.profile-header-inner .profile-card-inner h2.username a {
color:#fff;
}
@ -3486,7 +3620,7 @@ body.rtl .profile-banner-footer ul.stats {
content: "@";
}
.queet-text .vcard .group:before,
.queet-text .h-card .group:before {
.queet-text .h-card.group:before {
content:"!";
}
.queet.rtl .queet-text .vcard .group:before,
@ -3596,9 +3730,10 @@ body.rtl #feed {
float: left;
}
body.rtl #birds-top {
background-position: -205px -74px;
background-position: -400px -100px;
right:auto;
left:-3px;
width:100px;
}
body.rtl .language-dropdown {
float:left;
@ -3718,6 +3853,12 @@ body.rtl #feed-header-inner h2 {
@media (max-width: 866px) {
#site-notice,
#qvitter-notice {
display:none !important;
}
#new-queets-bar-container {
height:77px;
}
@ -3771,7 +3912,7 @@ body.rtl #feed-header-inner h2 {
}
#search-query {
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
background-position: -100px -804px;
border: 0 none;
@ -3830,7 +3971,7 @@ body.rtl #feed-header-inner h2 {
#top-compose {
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
background-position: -55px -800px;
cursor: pointer;
@ -4011,7 +4152,7 @@ body.rtl #feed-header-inner h2 {
display:none;
}
.nav-session {
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
background-position: 0 -800px;
height: 49px;
@ -4060,6 +4201,7 @@ body.rtl #feed-header-inner h2 {
display:block;
}
.menu-container a.favorites,
.menu-container a.mentions,
.menu-container a.public-and-external-timeline {
display:none;
}
@ -4071,10 +4213,10 @@ body.rtl #feed-header-inner h2 {
font-size:0;
color:transparent;
height:55px;
padding:0;
padding:0 !important;
margin:0;
border-radius:0 0 0 0 !important;
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
background-position: center -1003px;
}
@ -4098,7 +4240,7 @@ body.rtl #feed-header-inner h2 {
}
.stream-selection.friends-timeline:after,
.stream-selection.mentions:after,
.stream-selection.notifications:after,
.stream-selection.my-timeline:after,
.stream-selection.public-timeline:after {
content: "";
@ -4108,14 +4250,14 @@ body.rtl #feed-header-inner h2 {
margin-left: -35px;
width: 70px;
height: 55px;
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
background-color:#ccc;
}
.stream-selection.friends-timeline:after {
background-position:0px -861px ;
}
.stream-selection.mentions:after {
.stream-selection.notifications:after {
background-position:-78px -861px ;
}
.stream-selection.my-timeline:after {
@ -4249,8 +4391,12 @@ body.rtl #feed-header-inner h2 {
border-top: 1px solid #E8E8E8;
border-bottom: 1px solid #E8E8E8;
height:45px;
margin-top:20px;
margin-top:9px;
}
.queet-content {
margin-bottom: -1px;
padding-bottom:0;
}
/* .stream-item.collapsing > .queet ul.queet-actions {
display:none !important;
} */
@ -4258,7 +4404,7 @@ body.rtl #feed-header-inner h2 {
ul.queet-actions li .icon.sm-rt,
ul.queet-actions li .icon.sm-trash,
ul.queet-actions li .icon.sm-reply {
background-image: url("../img/sprite.png?v=2");
background-image: url("../img/sprite.png?v=5");
background-size: 500px 1329px;
width:35px;
height:35px;
@ -4289,9 +4435,6 @@ body.rtl #feed-header-inner h2 {
}
.queet ul.stats {
border-top: 0 none;
margin-left:-63px;
margin-top:0;
}
.queet ul.stats li.rq-count a,
@ -4302,7 +4445,11 @@ body.rtl #feed-header-inner h2 {
.queet ul.stats li:first-child a {
padding-left:0 !important;
}
.client-and-actions {
.expanded-content {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
transition: none !important;
margin-left:-63px;
}
.client-and-actions .permalink-link {

View File

@ -88,7 +88,7 @@ class ApiAuthAction extends ApiAction
// qvitterfix, accepts regular login session
if ($this->scoped) {
$this->auth_user = $this->scoped;
$this->auth_user = $this->scoped->getUser();
$this->access = self::READ_WRITE;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 60 KiB

File diff suppressed because one or more lines are too long

View File

@ -94,8 +94,7 @@ function getFromAPI(stream, actionOnSuccess) {
dataType: 'json',
success: function(data) {
// decode if we have a qvitter compact stream
data = decodeQvitterCompactFormat(data);
data = convertEmptyObjectToEmptyArray(data);
actionOnSuccess(data);
},
@ -256,8 +255,7 @@ function postActionToAPI(action, actionOnSuccess) {
error: function(data){ actionOnSuccess(false); console.log(data); },
success: function(data) {
// decode if we have a qvitter compact stream
data = decodeQvitterCompactFormat(data);
data = convertEmptyObjectToEmptyArray(data);
actionOnSuccess(data);
}
@ -326,4 +324,53 @@ function getFavsOrRequeetsForQueet(apiaction,qid,actionOnSuccess) {
}
});
}
/* ·
·
· Check for unseen notifications
·
· @param actionOnSuccess: callback function
·
· · · · · · · · · */
function checkForNewNotifications() {
$.ajax({ url: window.apiRoot + "qvitter/newnotifications.json",
type: "GET",
dataType: 'json',
success: function(data) {
if(data.length == 0) {
$('#unseen-notifications').hide();
document.title = window.siteTitle;
}
else {
var totNotif = 0;
$.each(data,function(k,v){
totNotif = totNotif + parseInt(v,10);
});
if(totNotif>0) {
$('#unseen-notifications').html(totNotif);
document.title = window.siteTitle + ' (' + totNotif + ')'; // update html page title
$('#unseen-notifications').show();
}
else {
$('#unseen-notifications').hide();
document.title = window.siteTitle;
}
}
},
error: function(data) {
$('#unseen-notifications').hide();
document.title = window.siteTitle;
remove_spinner();
console.log(data);
}
});
}

View File

@ -161,6 +161,12 @@ function profileCardFromFirstObject(data,screen_name) {
first.user.cover_photo = first.user.profile_image_url_original;
}
// follows me?
var follows_you = '';
if(first.user.follows_you === true && window.myUserID != first.user.id) {
var follows_you = '<span class="follows-you">' + window.sL.followsYou + '</span>';
}
// show user actions if logged in
var followingClass = '';
if(first.user.following) {
@ -189,7 +195,7 @@ function profileCardFromFirstObject(data,screen_name) {
$('#feed').siblings('.profile-card').remove();
// insert profile card into dom
$('#feed').before('<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + first.user.cover_photo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture" href="' + first.user.profile_image_url_original + '"><img src="' + first.user.profile_image_url_profile_size + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + first.user.name + '<span></span></h1><h2 class="username"><span class="screen-name">@' + first.user.screen_name + '</span><span class="follow-status"></span></h2><div class="bio-container"><p>' + first.user.description + '</p></div><p class="location-and-url"><span class="location">' + first.user.location + '</span><span class="divider"> · </span><span class="url"><a href="' + first.user.url + '">' + first.user.url.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a class="tweet-stats"><strong>' + first.user.statuses_count + '</strong>' + window.sL.notices + '</a></li><li><a class="following-stats"><strong>' + first.user.friends_count + '</strong>' + window.sL.following + '</a></li><li><a class="follower-stats"><strong>' + first.user.followers_count + '</strong>' + window.sL.followers + '</a></li><li><a class="groups-stats"><strong>' + first.user.groups_count + '</strong>' + window.sL.groups + '</a></li></ul>' + followButton + '<div class="clearfix"></div></div></div>');
$('#feed').before('<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + first.user.cover_photo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture" href="' + first.user.profile_image_url_original + '"><img src="' + first.user.profile_image_url_profile_size + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + first.user.name + '<span></span></h1><h2 class="username"><span class="screen-name">@' + first.user.screen_name + '</span>' + follows_you + '</h2><div class="bio-container"><p>' + first.user.description + '</p></div><p class="location-and-url"><span class="location">' + first.user.location + '</span><span class="divider"> · </span><span class="url"><a href="' + first.user.url + '">' + first.user.url.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a class="tweet-stats"><strong>' + first.user.statuses_count + '</strong>' + window.sL.notices + '</a></li><li><a class="following-stats"><strong>' + first.user.friends_count + '</strong>' + window.sL.following + '</a></li><li><a class="follower-stats"><strong>' + first.user.followers_count + '</strong>' + window.sL.followers + '</a></li><li><a class="groups-stats"><strong>' + first.user.groups_count + '</strong>' + window.sL.groups + '</a></li></ul>' + followButton + '<div class="clearfix"></div></div></div>');
}
// if user hasn't queeted or if we're not allowed to read their queets
@ -202,6 +208,12 @@ function profileCardFromFirstObject(data,screen_name) {
data.cover_photo = data.profile_image_url_original;
}
// follows me?
var follows_you = '';
if(data.follows_you === true && window.myUserID != data.id) {
var follows_you = '<span class="follows-you">' + window.sL.followsYou + '</span>';
}
// show user actions if logged in
var followingClass = '';
if(data.following) {
@ -228,7 +240,7 @@ function profileCardFromFirstObject(data,screen_name) {
// remove any old profile card and show profile card
$('#feed').siblings('.profile-card').remove();
$('#feed').before('<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + data.cover_photo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture" href="' + data.profile_image_url_original + '"><img src="' + data.profile_image_url_profile_size + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + data.name + '<span></span></h1><h2 class="username"><span class="screen-name">@' + data.screen_name + '</span><span class="follow-status"></span></h2><div class="bio-container"><p>' + data.description + '</p></div><p class="location-and-url"><span class="location">' + data.location + '</span><span class="divider"> · </span><span class="url"><a href="' + data.url + '">' + data.url.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a class="tweet-stats"><strong>' + data.statuses_count + '</strong>' + window.sL.notices + '</a></li><li><a class="following-stats"><strong>' + data.friends_count + '</strong>' + window.sL.following + '</a></li><li><a class="follower-stats"><strong>' + data.followers_count + '</strong>' + window.sL.followers + '</a></li><li><a class="groups-stats"><strong>' + data.groups_count + '</strong>' + window.sL.groups + '</a></li></ul>' + followButton + '<div class="clearfix"></div></div></div>');
$('#feed').before('<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + data.cover_photo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture" href="' + data.profile_image_url_original + '"><img src="' + data.profile_image_url_profile_size + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + data.name + '<span></span></h1><h2 class="username"><span class="screen-name">@' + data.screen_name + '</span>' + follows_you + '</span></h2><div class="bio-container"><p>' + data.description + '</p></div><p class="location-and-url"><span class="location">' + data.location + '</span><span class="divider"> · </span><span class="url"><a href="' + data.url + '">' + data.url.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a class="tweet-stats"><strong>' + data.statuses_count + '</strong>' + window.sL.notices + '</a></li><li><a class="following-stats"><strong>' + data.friends_count + '</strong>' + window.sL.following + '</a></li><li><a class="follower-stats"><strong>' + data.followers_count + '</strong>' + window.sL.followers + '</a></li><li><a class="groups-stats"><strong>' + data.groups_count + '</strong>' + window.sL.groups + '</a></li></ul>' + followButton + '<div class="clearfix"></div></div></div>');
}});
}
}
@ -302,6 +314,7 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
// halt interval that checks for new queets
window.clearInterval(checkForNewQueetsInterval);
window.clearInterval(checkForNewNotificationsInterval);
display_spinner();
@ -318,9 +331,9 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
if(stream.substring(0,45) == 'statuses/followers.json?count=20&screen_name='
|| stream.substring(0,43) == 'statuses/friends.json?count=20&screen_name='
|| stream.substring(0,48) == 'statusnet/groups/list.json?count=10&screen_name='
|| stream.substring(0,51) == 'qvitter/statuses/friends_timeline.json?screen_name='
|| stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name='
|| stream.substring(0,27) == 'favorites.json?screen_name='
|| stream.substring(0,43) == 'qvitter/statuses/mentions.json?screen_name='
|| stream.substring(0,35) == 'statuses/mentions.json?screen_name='
|| stream.substring(0,27) == 'statuses/user_timeline.json') {
var defaultStreamName = 'statuses/user_timeline.json?' + stream.substring(stream.indexOf('screen_name='));
var streamHeader = '@' + stream.substring(stream.lastIndexOf('=')+1);
@ -333,8 +346,9 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
var streamHeader = '@' + window.loggedIn.screen_name;
}
// if this is one of the default streams, get header from DOM
else if(stream == 'qvitter/statuses/friends_timeline.json'
|| stream == 'qvitter/statuses/mentions.json'
else if(stream == 'statuses/friends_timeline.json'
|| stream == 'statuses/mentions.json'
|| stream == 'qvitter/statuses/notifications.json'
|| stream == 'favorites.json'
|| stream == 'statuses/public_timeline.json'
|| stream == 'statuses/public_and_external_timeline.json') {
@ -354,6 +368,11 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
var defaultStreamName = stream;
var streamHeader = '#' + stream.substring(stream.indexOf('/timeline/')+10,stream.indexOf('.json'));
}
// if this is a notice stream
else if(stream.substring(0,14) == 'statuses/show/') {
var defaultStreamName = stream;
var streamHeader = 'notice/' + stream.substring(stream.indexOf('/show/')+6,stream.indexOf('.json'));
}
// if this is a search stream
else if(stream.substring(0,11) == 'search.json') {
var defaultStreamName = stream;
@ -362,15 +381,15 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
// set the h2 header in the feed
if(stream.substring(0,23) == 'statuses/followers.json') {
var h2FeedHeader = window.sL.followers;
var h2FeedHeader = '<div class="queet-streams"><a class="queet-stream following">' + window.sL.following + '</a> / </div>' + window.sL.followers;
}
else if(stream.substring(0,21) == 'statuses/friends.json') {
var h2FeedHeader = window.sL.following;
var h2FeedHeader = window.sL.following + '<div class="queet-streams">/ <a class="queet-stream followers">' + window.sL.followers + '</a></div>';
}
else if(stream.substring(0,40) == 'statuses/user_timeline.json?screen_name=') {
var h2FeedHeader = window.sL.notices + '<div class="queet-streams">/ <a class="queet-stream mentions">' + window.sL.mentions + '</a> / <a class="queet-stream favorites">' + window.sL.favoritesNoun +'</a></div>';
}
else if(stream.substring(0,43) == 'qvitter/statuses/mentions.json?screen_name=') {
else if(stream.substring(0,35) == 'statuses/mentions.json?screen_name=') {
var h2FeedHeader = '<div class="queet-streams"><a class="queet-stream queets">' + window.sL.notices + '</a> /</div>' + window.sL.mentions + '<div class="queet-streams">/ <a class="queet-stream favorites">' + window.sL.favoritesNoun + '</a></div>';
}
else if(stream.substring(0,27) == 'favorites.json?screen_name=') {
@ -385,7 +404,7 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
else if(stream.substring(0,24) == 'statusnet/groups/admins/') {
var h2FeedHeader = window.sL.adminCount;
}
else if(stream.substring(0,51) == 'qvitter/statuses/friends_timeline.json?screen_name=') {
else if(stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name=') {
var h2FeedHeader = '<span style="unicode-bidi:bidi-override;direction:ltr;">' + streamHeader + '/all</span>'; // ugly rtl fix, sry, we should have translations for this stream header
}
else {
@ -428,13 +447,14 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
$('.stream-selection').removeClass('current');
$('.stream-selection[data-stream-header="' + streamHeader + '"]').addClass('current');
// if this is user's user feed, i.e. followers etc, we want a profile card, which we need to get from user_timeline since the users/show api action is broken (auth doesn't work)
if(stream.substring(0,23) == 'statuses/followers.json'
|| stream.substring(0,21) == 'statuses/friends.json'
|| stream.substring(0,26) == 'statusnet/groups/list.json'
|| stream.substring(0,43) == 'qvitter/statuses/mentions.json?screen_name='
|| stream.substring(0,35) == 'statuses/mentions.json?screen_name='
|| stream.substring(0,27) == 'favorites.json?screen_name='
|| stream.substring(0,51) == 'qvitter/statuses/friends_timeline.json?screen_name=') {
|| stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name=') {
getFromAPI(defaultStreamName + '&count=1', function(profile_data){
if(profile_data) {
getFromAPI(stream, function(user_data){
@ -454,7 +474,14 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
}
profileCardFromFirstObject(profile_data,thisUsersScreenName); // show profile card
checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling); // start interval again
// start checking for new queets again
window.clearInterval(checkForNewQueetsInterval);
window.clearInterval(checkForNewNotificationsInterval);
checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling);
checkForNewNotificationsInterval=window.setInterval(function(){checkForNewNotifications()},window.timeBetweenPolling);
checkForNewNotifications();
remove_spinner();
$('#feed-body').html(''); // empty feed only now so the scrollers don't flicker on and off
$('#new-queets-bar').parent().addClass('hidden'); document.title = window.siteTitle; // hide new queets bar if it's visible there
@ -493,7 +520,19 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
groupProfileCard(thisGroupAlias);
}
checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling); // start interval again
// start checking for new queets again
window.clearInterval(checkForNewQueetsInterval);
window.clearInterval(checkForNewNotificationsInterval);
checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling);
if(window.currentStream != 'qvitter/statuses/notifications.json') { // don't check for notifications if this is the notifications page
checkForNewNotifications();
checkForNewNotificationsInterval=window.setInterval(function(){checkForNewNotifications()},window.timeBetweenPolling);
}
else {
$('#unseen-notifications').hide();
document.title = window.siteTitle;
}
remove_spinner();
$('#feed-body').html(''); // empty feed only now so the scrollers don't flicker on and off
$('#new-queets-bar').parent().addClass('hidden'); document.title = window.siteTitle; // hide new queets bar if it's visible there
@ -526,7 +565,7 @@ function convertStreamToPath(stream) {
var screenName = stream.substring(stream.lastIndexOf('=')+1);
return screenName + '/subscriptions';
}
else if(stream.substring(0,43) == 'qvitter/statuses/mentions.json?screen_name=') {
else if(stream.substring(0,35) == 'statuses/mentions.json?screen_name=') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName + '/replies';
}
@ -544,9 +583,12 @@ function convertStreamToPath(stream) {
else if(stream == 'statuses/friends.json?count=20') {
return window.loggedIn.screen_name + '/subscriptions';
}
else if(stream == 'qvitter/statuses/mentions.json') {
else if(stream == 'statuses/mentions.json') {
return window.loggedIn.screen_name + '/replies';
}
else if(stream == 'qvitter/statuses/notifications.json') {
return window.loggedIn.screen_name + '/notifications';
}
else if(stream == 'favorites.json') {
return window.loggedIn.screen_name + '/favorites';
}
@ -557,16 +599,13 @@ function convertStreamToPath(stream) {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName;
}
else if(stream == 'qvitter/statuses/friends_timeline.json') {
else if(stream == 'statuses/friends_timeline.json') {
return window.loggedIn.screen_name + '/all';
}
else if(stream.substring(0,51) == 'qvitter/statuses/friends_timeline.json?screen_name=') {
else if(stream.substring(0,51) == 'statuses/friends_timeline.json?screen_name=') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName + '/all';
}
else if (stream == 'qvitter/statuses/mentions.json') {
return window.loggedIn.screen_name + '/replies';
}
else if(stream == 'statuses/public_timeline.json') {
return '';
}
@ -589,6 +628,10 @@ function convertStreamToPath(stream) {
var tagName = stream.substring(stream.indexOf('/timeline/')+10,stream.indexOf('.json'));
return 'tag/' + tagName;
}
else if(stream.substring(0,14) == 'statuses/show/') {
var noticeId = stream.substring(stream.indexOf('/show/')+6,stream.indexOf('.json'));
return 'notice/' + noticeId;
}
else if(stream.substring(0,11) == 'search.json') {
var searchTerms = stream.substring(stream.indexOf('?q=')+3);
return 'search/notice?q=' + searchTerms;
@ -642,10 +685,10 @@ function getStreamFromUrl() {
var userToStream = loc.replace('/','').replace('/all','');
if(userToStream.length>0) {
if(window.loggedIn.screen_name == userToStream) {
streamToSet = 'qvitter/statuses/friends_timeline.json';
streamToSet = 'statuses/friends_timeline.json';
}
else {
streamToSet = 'qvitter/statuses/friends_timeline.json?screen_name=' + userToStream;
streamToSet = 'statuses/friends_timeline.json?screen_name=' + userToStream;
}
}
}
@ -655,13 +698,28 @@ function getStreamFromUrl() {
var userToStream = loc.replace('/','').replace('/replies','');
if(userToStream.length>0) {
if(window.loggedIn.screen_name == userToStream) {
streamToSet = 'qvitter/statuses/mentions.json';
streamToSet = 'statuses/mentions.json';
}
else {
streamToSet = 'qvitter/statuses/mentions.json?screen_name=' + userToStream;
streamToSet = 'statuses/mentions.json?screen_name=' + userToStream;
}
}
}
// {domain}/{screen_name}/notifications
else if ((/^[a-zA-Z0-9]+$/.test(loc.replace('/','').replace('/notifications','')))) {
var userToStream = loc.replace('/','').replace('/notifications','');
if(userToStream.length>0) {
if(window.loggedIn.screen_name == userToStream) {
streamToSet = 'qvitter/statuses/notifications.json';
}
else {
// not allowed for others than logged in user
window.location.replace(window.siteInstanceURL);
}
}
}
// {domain}/{screen_name}/favorites
else if ((/^[a-zA-Z0-9]+$/.test(loc.replace('/','').replace('/favorites','')))) {
@ -723,6 +781,15 @@ function getStreamFromUrl() {
}
}
// {domain}/notice/{notide_id}
else if (loc.indexOf('/notice/')>-1) {
var noticeToStream = loc.replace('/notice/','');
if(noticeToStream.length>0) {
streamToSet = 'statuses/show/' + noticeToStream + '.json';
}
}
// {domain}/group/{group}/members, {domain}/group/{group}/admins or {domain}/group/{group}
else if (loc.indexOf('/group/')>-1) {
@ -776,6 +843,10 @@ function expand_queet(q,doScrolling) {
var sel = getSelection().toString();
if(!sel && !q.find('.queet-button').children('button').hasClass('enabled')) { // don't collapse if text is selected, or if queet has an active queet button
// remove some things right away
q.find('.inline-reply-caret').remove();
q.addClass('collapsing');
q.css('overflow','hidden');
q.find('.stream-item-expand').html(window.sL.expand);
@ -786,18 +857,19 @@ function expand_queet(q,doScrolling) {
q.find('.view-more-container-bottom').remove();
q.find('.stream-item.conversation').remove();
q.find('.inline-reply-queetbox').remove();
q.find('.expanded-content').remove();
q.find('.expanded-content').remove();
}
else {
rememberMyScrollPos(q.children('.queet'),qid,0);
// give stream item a height
q.css('height',q.height() + 'px');
q.children('.queet').find('.expanded-content').css('height',q.find('.expanded-content').height() + 'px');
q.children('div').not('.queet').children('a').css('opacity','0.5');
q.children('div').not('.queet').children().children().css('opacity','0.5');
var collapseTime = 150 + q.find('.stream-item.conversation:not(.hidden-conversation)').length*50;
var collapseTime = 350 + q.find('.stream-item.conversation:not(.hidden-conversation)').length*50;
// set transition time (needs to be delayed, otherwise webkit animates the height-setting above)
setTimeout(function() {
@ -809,10 +881,15 @@ function expand_queet(q,doScrolling) {
q.css('-o-transition-duration',Math.round( collapseTime / 1000 * 10) / 10 + 's');
q.css('-webkit-transition-duration',Math.round( collapseTime * 1000 * 10) / 10 + 's');
q.css('transition-duration',Math.round( collapseTime / 1000 * 10) / 10 + 's');
q.find('.expanded-content').css('-moz-transition-duration',Math.round( collapseTime / 1000 * 10) / 10 + 's');
q.find('.expanded-content').css('-o-transition-duration',Math.round( collapseTime / 1000 * 10) / 10 + 's');
q.find('.expanded-content').css('-webkit-transition-duration',Math.round( collapseTime * 1000 * 10) / 10 + 's');
q.find('.expanded-content').css('transition-duration',Math.round( collapseTime / 1000 * 10) / 10 + 's');
// set new heights and margins to animate to
q.css('height',(q.children('.queet').find('.queet-content').outerHeight() - q.children('.queet').find('.expanded-content').outerHeight() - 10) + 'px');
q.css('height',(q.children('.queet').find('.queet-content').outerHeight() - q.children('.queet').find('.expanded-content').outerHeight()) + 'px');
q.children('.queet').css('margin-top', '-' + (q.children('.queet').offset().top - q.offset().top) + 'px');
q.children('.queet').find('.expanded-content').css('height','0');
}, 50);
@ -839,12 +916,12 @@ function expand_queet(q,doScrolling) {
}
}
}
else {
else if(!q.hasClass('collapsing')) {
rememberMyScrollPos(q,qid,-8);
// not for acitivity
if(!q.hasClass('activity')) {
// not for acitivity or notifications
if(!q.hasClass('activity') && !q.hasClass('repeat') && !q.hasClass('like') && !q.hasClass('follow')) {
q.addClass('expanded');
q.find('.stream-item-expand').html(window.sL.collapse);
@ -856,7 +933,7 @@ function expand_queet(q,doScrolling) {
getFromAPI("attachment/" + attachmentId + ".json",function(data){
if(data) {
console.log(data);
q.children('.queet').find('.queet-text').html($.trim(data.replace(/&#64;<span class="vcard">/gi,'<span class="vcard">').replace(/@<span class="vcard">/gi,'<span class="vcard">').replace(/!<span class="vcard">/gi,'<span class="vcard">').replace(/#<span class="tag">/gi,'<span class="tag">')));
q.children('.queet').find('.queet-text').html($.trim(data.replace(/@<a href="/gi,'<a href="').replace(/!<a href="/gi,'<a href="').replace(/@<span class="vcard">/gi,'<span class="vcard">').replace(/!<span class="vcard">/gi,'<span class="vcard">').replace(/#<span class="tag">/gi,'<span class="tag">').replace(/&#64;<span class="vcard">/gi,'<span class="vcard">').replace(/@<span class="vcard">/gi,'<span class="vcard">').replace(/!<span class="vcard">/gi,'<span class="vcard">').replace(/#<span class="tag">/gi,'<span class="tag">')));
}
});
}
@ -869,7 +946,7 @@ function expand_queet(q,doScrolling) {
var metadata = '<span class="longdate" title="' + longdate + '">' + longdate + ' · ' + unescape(q.attr('data-source')) + '</span> · <a href="' + qurl + '" class="permalink-link">' + window.sL.details + '</a>';
// show expanded content
q.find('.stream-item-footer').after('<div class="expanded-content"><div class="queet-stats-container"></div><div class="client-and-actions"><span class="metadata">' + metadata + '</span></div></div>');
q.find('.stream-item-footer').before('<div class="expanded-content"><div class="queet-stats-container"></div><div class="client-and-actions"><span class="metadata">' + metadata + '</span></div></div>');
// maybe show images or videos
@ -1327,13 +1404,68 @@ function checkForHiddenConversationQueets(qid) {
· · · · · · · · · · · · · */
function addToFeed(feed, after, extraClasses) {
// some streams, e.g. /statuses/show/1234.json is not enclosed in an array, make sure it is
if(!$.isArray(feed)) {
feed = [feed];
}
$.each(feed.reverse(), function (key,obj) {
var extraClassesThisRun = extraClasses;
// if this is the notifications feed
if(window.currentStream.substring(0,35) == 'qvitter/statuses/notifications.json') {
// only if this notification isn't already in stream
if($('#stream-item-' + obj.id).length == 0) {
obj.from_profile.description = obj.from_profile.description || '';
var notificationTime = parseTwitterDate(obj.created_at);
if(obj.is_seen == '0') {
extraClassesThisRun = extraClassesThisRun + ' not-seen'
}
if(obj.ntype == 'like') {
var noticeTime = parseTwitterDate(obj.notice.created_at);
obj.notice = convertNewGNUSocialURItoURL(obj.notice);
var notificationHtml = '<div data-quitter-id-in-stream="' + obj.id + '" id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' notification like"><div class="queet"><div class="queet-content"><div class="stream-item-header"><small class="created-at" data-created-at="' + obj.created_at + '" title="' + obj.created_at + '">' + notificationTime + '</small><a class="account-group" href="' + obj.from_profile.statusnet_profile_url + '"><span class="dogear"></span><img class="avatar" src="' + obj.from_profile.profile_image_url + '" /><strong class="name" data-user-id="' + obj.from_profile.id + '" title="@' + obj.from_profile.screen_name + '">' + obj.from_profile.name + '</strong></a> ' + window.sL.xFavedYourQueet + '</div><div class="small-grey-notice"><a href="' + obj.notice.uri + '">' + noticeTime + '</a>: ' + $.trim(obj.notice.statusnet_html) + '</div></div></div></div>';
}
else if(obj.ntype == 'repeat') {
obj.notice = convertNewGNUSocialURItoURL(obj.notice);
var noticeTime = parseTwitterDate(obj.notice.created_at);
var notificationHtml = '<div data-quitter-id-in-stream="' + obj.id + '" id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' notification repeat"><div class="queet"><div class="queet-content"><div class="stream-item-header"><small class="created-at" data-created-at="' + obj.created_at + '" title="' + obj.created_at + '">' + notificationTime + '</small><a class="account-group" href="' + obj.from_profile.statusnet_profile_url + '"><span class="dogear"></span><img class="avatar" src="' + obj.from_profile.profile_image_url + '" /><strong class="name" data-user-id="' + obj.from_profile.id + '" title="@' + obj.from_profile.screen_name + '">' + obj.from_profile.name + '</strong></a> ' + window.sL.xRepeatedYourQueet + '</div><div class="small-grey-notice"><a href="' + obj.notice.uri + '">' + noticeTime + '</a>: ' + $.trim(obj.notice.statusnet_html) + '</div></div></div></div>';
}
else if(obj.ntype == 'mention') {
var notificationHtml = buildQueetHtml(obj.notice, obj.id, extraClassesThisRun + ' notification mention');
}
else if(obj.ntype == 'reply') {
var notificationHtml = buildQueetHtml(obj.notice, obj.id, extraClassesThisRun + ' notification reply');
}
else if(obj.ntype == 'follow') {
var notificationHtml = '<div data-quitter-id-in-stream="' + obj.id + '" id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' notification follow"><div class="queet"><div class="queet-content"><div class="stream-item-header"><small class="created-at" data-created-at="' + obj.created_at + '" title="' + obj.created_at + '">' + notificationTime + '</small><a class="account-group" href="' + obj.from_profile.statusnet_profile_url + '"><img class="avatar" src="' + obj.from_profile.profile_image_url + '" /><strong class="name" data-user-id="' + obj.from_profile.id + '" title="@' + obj.from_profile.screen_name + '">' + obj.from_profile.name + '</strong></a> ' + window.sL.xStartedFollowingYou + '</div></div></div></div>';
}
if(after) {
$('#' + after).after(notificationHtml);
}
else {
$('#feed-body').prepend(notificationHtml);
}
// add not seen notification circle
$.each($('.notification.not-seen .queet'),function(){
if($(this).children('.not-seen').length<1) {
$(this).prepend('<div class="not-seen"></div>');
}
});
}
}
// if this is a user feed
if(window.currentStream.substring(0,21) == 'statuses/friends.json'
else if(window.currentStream.substring(0,21) == 'statuses/friends.json'
|| window.currentStream.substring(0,18) == 'statuses/followers'
|| window.currentStream.substring(0,28) == 'statusnet/groups/membership/'
|| window.currentStream.substring(0,24) == 'statusnet/groups/admins/') {
@ -1426,73 +1558,7 @@ function addToFeed(feed, after, extraClasses) {
// retweeted object don't exist in feed
else {
// we don't want to print 'null', someone might have that username!
var in_reply_to_screen_name = '';
if(obj.retweeted_status.in_reply_to_screen_name != null) {
in_reply_to_screen_name = obj.retweeted_status.in_reply_to_screen_name;
}
// requeet html
var requeetedClass = '';
if(obj.retweeted_status.user.id == window.myUserID) {
var requeetHtml = '<li class="action-del-container"><a class="with-icn"><span class="icon sm-trash"></span> <b>' + window.sL.deleteVerb + '</b></a></li></i>';
}
else if(obj.retweeted_status.repeated) {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn done"><span class="icon sm-rt"></span> <b>' + window.sL.requeetedVerb + '</b></a></i>';
requeetedClass = 'requeeted';
}
else {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn"><span class="icon sm-rt"></span> <b>' + window.sL.requeetVerb + '</b></a></i>';
}
// favorite html
var favoritedClass = '';
if(obj.retweeted_status.favorited) {
var favoriteHtml = '<a class="with-icn done"><span class="icon sm-fav"></span> <b>' + window.sL.favoritedVerb + '</b></a>';
favoritedClass = 'favorited';
}
else {
var favoriteHtml = '<a class="with-icn"><span class="icon sm-fav"></span> <b>' + window.sL.favoriteVerb + '</b></a>';
}
// actions only for logged in users
var queetActions = '';
if(typeof window.loggedIn.screen_name != 'undefined') {
queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>';
}
// reply-to html
var reply_to_html = '';
if(obj.retweeted_status.in_reply_to_screen_name != null && obj.retweeted_status.in_reply_to_screen_name != obj.retweeted_status.user.screen_name) {
reply_to_html = '<span class="reply-to">@' + obj.retweeted_status.in_reply_to_screen_name + '</span> ';
}
// in-groups html
var in_groups_html = '';
if(obj.retweeted_status.statusnet_in_groups !== false && typeof obj.retweeted_status.statusnet_in_groups != 'undefined') {
in_groups_html = '<span class="in-groups">' + obj.retweeted_status.statusnet_in_groups + '</span>';
}
// image attachment thumbnails
var attachment_html = '';
if(typeof obj.retweeted_status.attachments != "undefined") {
$.each(obj.retweeted_status.attachments, function(){
if(this.thumb_url != null) {
attachment_html = attachment_html + '<a href="' + this.url + '"><img src="' + this.thumb_url + '"/></a>';
}
});
}
if(attachment_html.length>0) {
attachment_html = '<div class="attachments">' + attachment_html + '</div>';
}
obj.retweeted_status = convertNewGNUSocialURItoURL(obj.retweeted_status);
var queetTime = parseTwitterDate(obj.retweeted_status.created_at);
var queetHtml = '<div id="stream-item-' + obj.retweeted_status.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-source="' + escape(obj.retweeted_status.source) + '" data-quitter-id="' + obj.retweeted_status.id + '" data-conversation-id="' + obj.retweeted_status.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.retweeted_status.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.retweeted_status.id + '">' + attachment_html + '<span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.retweeted_status.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.retweeted_status.user.profile_image_url_profile_size + '" /><strong class="name" data-user-id="' + obj.retweeted_status.user.id + '">' + obj.retweeted_status.user.name + '</strong> <span class="screen-name">@' + obj.retweeted_status.user.screen_name + '</span></a><i class="addressees">' + reply_to_html + in_groups_html + '</i><small class="created-at" data-created-at="' + obj.retweeted_status.created_at + '"><a href="' + obj.retweeted_status.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.retweeted_status.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + '<div class="context" id="requeet-' + obj.id + '"><span class="with-icn"><i class="badge-requeeted"></i><span class="requeet-text"> ' + window.sL.requeetedBy + '<a href="' + obj.user.statusnet_profile_url + '"> <b>' + obj.user.name + '</b></a></span></span></div><span class="stream-item-expand">' + window.sL.expand + '</span></div></div></div></div>';
// detect rtl
queetHtml = detectRTL(queetHtml);
var queetHtml = buildQueetHtml(obj.retweeted_status, obj.id, extraClassesThisRun, obj);
if(after) {
$('#' + after).after(queetHtml);
@ -1549,74 +1615,7 @@ function addToFeed(feed, after, extraClasses) {
}
}
// we don't want to print 'null' in in_reply_to_screen_name-attribute, someone might have that username!
var in_reply_to_screen_name = '';
if(obj.in_reply_to_screen_name != null) {
in_reply_to_screen_name = obj.in_reply_to_screen_name;
}
// requeet html
var requeetedClass = '';
if(obj.user.id == window.myUserID) {
var requeetHtml = '<li class="action-del-container"><a class="with-icn"><span class="icon sm-trash"></span> <b>' + window.sL.deleteVerb + '</b></a></li></i></li>';
}
else if(obj.repeated) {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn done"><span class="icon sm-rt"></span> <b>' + window.sL.requeetedVerb + '</b></a></li>';
var requeetedClass = 'requeeted';
}
else {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn"><span class="icon sm-rt"></span> <b>' + window.sL.requeetVerb + '</b></a></li>';
}
// favorite html
var favoritedClass = '';
if(obj.favorited) {
var favoriteHtml = '<a class="with-icn done"><span class="icon sm-fav"></span> <b>' + window.sL.favoritedVerb + '</b></a>';
favoritedClass = 'favorited';
}
else {
var favoriteHtml = '<a class="with-icn"><span class="icon sm-fav"></span> <b>' + window.sL.favoriteVerb + '</b></a>';
}
// actions only for logged in users
var queetActions = '';
if(typeof window.loggedIn.screen_name != 'undefined') {
queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>';
}
// reply-to html
var reply_to_html = '';
if(obj.in_reply_to_screen_name != null && obj.in_reply_to_screen_name != obj.user.screen_name) {
reply_to_html = '<span class="reply-to">@' + obj.in_reply_to_screen_name + '</span> ';
}
// in-groups html
var in_groups_html = '';
if(obj.statusnet_in_groups !== false && typeof obj.statusnet_in_groups != 'undefined') {
in_groups_html = '<span class="in-groups">' + obj.statusnet_in_groups + '</span>';
}
// image attachment thumbnails
var attachment_html = '';
if(typeof obj.attachments != "undefined") {
$.each(obj.attachments, function(){
if(this.thumb_url != null) {
attachment_html = attachment_html + '<a href="' + this.url + '"><img src="' + this.thumb_url + '"/></a>';
}
});
}
if(attachment_html.length>0) {
attachment_html = '<div class="attachments">' + attachment_html + '</div>';
}
obj = convertNewGNUSocialURItoURL(obj);
var queetTime = parseTwitterDate(obj.created_at);
var queetHtml = '<div id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-source="' + escape(obj.source) + '" data-quitter-id="' + obj.id + '" data-conversation-id="' + obj.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.id + '">' + attachment_html + '<span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.user.profile_image_url_profile_size + '" /><strong class="name" data-user-id="' + obj.user.id + '">' + obj.user.name + '</strong> <span class="screen-name">@' + obj.user.screen_name + '</span></a><i class="addressees">' + reply_to_html + in_groups_html + '</i><small class="created-at" data-created-at="' + obj.created_at + '"><a href="' + obj.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + '<span class="stream-item-expand">' + window.sL.expand + '</span></div></div></div></div>';
// detect rtl
queetHtml = detectRTL(queetHtml);
var queetHtml = buildQueetHtml(obj, obj.id, extraClassesThisRun);
if(after) {
if($('#' + after).hasClass('conversation')) { // if this is a reply, give stream item some conversation formatting
@ -1630,7 +1629,13 @@ function addToFeed(feed, after, extraClasses) {
}
}
else {
$('#feed-body').prepend(queetHtml);
$('#feed-body').prepend(queetHtml);
// if this is a single notice, we expand it
if(window.currentStream.substring(0,14) == 'statuses/show/') {
expand_queet($('#stream-item-' + obj.id));
}
}
}
@ -1642,61 +1647,125 @@ function addToFeed(feed, after, extraClasses) {
$('.stream-selection').removeAttr('data-current-user-stream-name'); // don't remeber user feeds
}
/* ·
·
· View threaded converation
· Build HTML for a queet from an object
·
· @param id: the stream item id
·
· (experimental, not finished, commented out...)
· @param obj: a queet object
· @param requeeted_by: if this is a requeet
·
· · · · · · · · · · · · · */
// $('body').on('click','.longdate',function(){
// threadedConversation($(this).closest('.stream-item:not(.conversation)').attr('data-quitter-id'));
// })
// function threadedConversation(id){
// $('body').prepend('<div id="threaded-' + id + '" class="modal-container"><div class="thread-container" style="margin-left:0;"><div></div></div></div>');
// var scrollTop = $(window).scrollTop();
// var containerStreamItem = $('#stream-item-' + id);
// if(containerStreamItem.children('div:first-child').hasClass('.queet')) {
// var firstStreamItemId = id;
// }
// else {
// var firstStreamItemId = containerStreamItem.children('div:first-child').attr('data-quitter-id');
// }
// getThreadedReply(id,firstStreamItemId,$('#threaded-' + id + ' .thread-container div'));
// }
//
// function getThreadedReply(containerStreamId,this_id,appendToObj) {
//
// var $this_item = $('<div/>').append($('.stream-item[data-quitter-id="' + this_id + '"]').outerHTML());
// $this_item.children().children().remove('.stream-item.conversation');
// $this_item.children('.stream-item').css('margin-left',parseInt(appendToObj.css('margin-left'),10)+20 + 'px');
// $this_item.children('.stream-item').removeClass('hidden-conversation');
// $this_item.children('.stream-item').removeClass('expanded');
// $this_item.children('.stream-item').removeClass('activity');
// $this_item.children('.stream-item').removeClass('conversation');
// $this_item.children('.stream-item').removeClass('visible');
// $this_item.children('.stream-item').children('div:not(.queet)').remove();
// $this_item.children('.stream-item').find('.inline-reply-queetbox').remove();
// $this_item.children('.stream-item').find('.expanded-content').remove();
// $this_item.children('.stream-item').find('.stream-item-expand').remove();
// $this_item.children('.stream-item').css('opacity','1');
// appendToObj.after($this_item.html());
//
// $.each($('.stream-item[data-quitter-id="' + containerStreamId + '"]').children().get().reverse(),function(){
// if($(this).hasClass('queet')) {
// var this_reply_to = $(this).parent().attr('data-in-reply-to-status-id');
// var childs_id = $(this).parent().attr('data-quitter-id');
// }
// else {
// var this_reply_to = $(this).attr('data-in-reply-to-status-id');
// var childs_id = $(this).attr('data-quitter-id');
// }
// if(this_id == this_reply_to) {
// getThreadedReply(containerStreamId,childs_id,$('#threaded-' + containerStreamId + ' .stream-item[data-quitter-id="' + this_id + '"]'));
// }
// });
// }
function buildQueetHtml(obj, idInStream, extraClassesThisRun, requeeted_by) {
// we don't want to print 'null' in in_reply_to_screen_name-attribute, someone might have that username!
var in_reply_to_screen_name = '';
if(obj.in_reply_to_screen_name != null) {
in_reply_to_screen_name = obj.in_reply_to_screen_name;
}
// requeet html
var requeetedClass = '';
if(obj.user.id == window.myUserID) {
var requeetHtml = '<li class="action-del-container"><a class="with-icn"><span class="icon sm-trash"></span> <b>' + window.sL.deleteVerb + '</b></a></li></i></li>';
}
else if(obj.repeated) {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn done"><span class="icon sm-rt"></span> <b>' + window.sL.requeetedVerb + '</b></a></li>';
var requeetedClass = 'requeeted';
}
else {
var requeetHtml = '<li class="action-rt-container"><a class="with-icn"><span class="icon sm-rt"></span> <b>' + window.sL.requeetVerb + '</b></a></li>';
}
// favorite html
var favoritedClass = '';
if(obj.favorited) {
var favoriteHtml = '<a class="with-icn done"><span class="icon sm-fav"></span> <b>' + window.sL.favoritedVerb + '</b></a>';
favoritedClass = 'favorited';
}
else {
var favoriteHtml = '<a class="with-icn"><span class="icon sm-fav"></span> <b>' + window.sL.favoriteVerb + '</b></a>';
}
// actions only for logged in users
var queetActions = '';
if(typeof window.loggedIn.screen_name != 'undefined') {
queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>';
}
// reply-to html
var reply_to_html = '';
if(obj.in_reply_to_screen_name != null && obj.in_reply_to_screen_name != obj.user.screen_name) {
reply_to_html = '<span class="reply-to">@' + obj.in_reply_to_screen_name + '</span> ';
}
// in-groups html
var in_groups_html = '';
if(obj.statusnet_in_groups !== false && typeof obj.statusnet_in_groups != 'undefined') {
in_groups_html = '<span class="in-groups">' + obj.statusnet_in_groups + '</span>';
}
// image attachment thumbnails
var attachment_html = '';
if(typeof obj.attachments != "undefined") {
$.each(obj.attachments, function(){
if(this.thumb_url != null) {
attachment_html = attachment_html + '<a href="' + this.url + '"><img src="' + this.thumb_url + '"/></a>';
}
});
}
if(attachment_html.length>0) {
attachment_html = '<div class="attachments">' + attachment_html + '</div>';
}
// requeets
var requeetHtml = '';
if(typeof requeeted_by != 'undefined') {
requeetHtml = '<div class="context" id="requeet-' + requeeted_by.id + '"><span class="with-icn"><i class="badge-requeeted"></i><span class="requeet-text"> ' + window.sL.requeetedBy + '<a href="' + requeeted_by.user.statusnet_profile_url + '"> <b>' + requeeted_by.user.name + '</b></a></span></span></div>';
}
obj = convertNewGNUSocialURItoURL(obj);
var queetTime = parseTwitterDate(obj.created_at);
var queetHtml = '<div \
id="stream-item-' + obj.id + '" \
class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" \
data-source="' + escape(obj.source) + '" \
data-quitter-id="' + obj.id + '" \
data-conversation-id="' + obj.statusnet_conversation_id + '" \
data-quitter-id-in-stream="' + idInStream + '" \
data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" \
data-in-reply-to-status-id="' + obj.in_reply_to_status_id + '">\
<div class="queet" id="q-' + obj.id + '">\
' + attachment_html + '\
<span class="dogear"></span>\
<div class="queet-content">\
<div class="stream-item-header">\
<a class="account-group" href="' + obj.user.statusnet_profile_url + '">\
<img class="avatar" src="' + obj.user.profile_image_url_profile_size + '" />\
<strong class="name" data-user-id="' + obj.user.id + '">' + obj.user.name + '</strong> \
<span class="screen-name">@' + obj.user.screen_name + '</span>\
</a>\
<i class="addressees">' + reply_to_html + in_groups_html + '</i>\
<small class="created-at" data-created-at="' + obj.created_at + '">\
<a href="' + obj.uri + '">' + queetTime + '</a>\
</small>\
</div>\
<div class="queet-text">' + $.trim(obj.statusnet_html) + '</div>\
<div class="stream-item-footer">\
' + queetActions + '\
' + requeetHtml + '\
<span class="stream-item-expand">' + window.sL.expand + '</span>\
</div>\
</div>\
</div>\
</div>';
// detect rtl
queetHtml = detectRTL(queetHtml);
return queetHtml;
}

View File

@ -146,6 +146,12 @@ window.l.es.registerRepeatPassword = 'Verificar contraseña';
window.l.es.moreSettings = 'Más configuraciones';
window.l.es.otherServers = 'De manera alternativa, puedes crear una cuenta en otro servidor de la red GNUsocial. <a href="http://federation.skilledtests.com/select_your_server.html">Comparativa</a>';
window.l.es.editMyProfile = 'Editar perfil';
window.l.es.notifications = 'Notificaciones';
window.l.es.xFavedYourQueet = 'marcó tu Queet como favorito';
window.l.es.xRepeatedYourQueet = 'te ha requitteado ';
window.l.es.xStartedFollowingYou = 'te ha seguido';
window.l.es.followsYou = 'te sigue';
// Português-Brasil
@ -257,6 +263,13 @@ window.l.pt_br.registerRepeatPassword = 'Repetir senha';
window.l.pt_br.moreSettings = 'Mais configurações';
window.l.pt_br.otherServers = 'De manera alternativa, você pode criar uma conta em outro servidor da rede GNUsocial. <a href="http://federation.skilledtests.com/select_your_server.html">Comparativo</a>';
window.l.pt_br.editMyProfile = 'Editar perfil';
window.l.pt_br.notifications = 'Notificações';
window.l.pt_br.xFavedYourQueet = 'curtiu seu Queet';
window.l.pt_br.xRepeatedYourQueet = 'requeetou você';
window.l.pt_br.xStartedFollowingYou = 'seguiu você';
window.l.pt_br.followsYou = 'segue você';
// galician
window.l.gl = new Object();
@ -367,7 +380,11 @@ window.l.gl.registerRepeatPassword = 'Verificar contrasinal';
window.l.gl.moreSettings = 'máis opcións';
window.l.gl.otherServers = 'De maneira alternativa, podes crear unha conta noutro servidor da rede GNUsocial. <a href="http://federation.skilledtests.com/select_your_server.html">Comparativa</a>';
window.l.gl.editMyProfile = 'Editar o perfil';
window.l.gl.notifications = 'Notificacións';
window.l.gl.xFavedYourQueet = 'marcou como favorito o teu chío';
window.l.gl.xRepeatedYourQueet = 'rechouchioute';
window.l.gl.xStartedFollowingYou = 'está a seguirte';
window.l.gl.followsYou = 'séguete';
// basque
window.l.eu = new Object();
@ -478,6 +495,11 @@ window.l.eu.registerRepeatPassword = 'Errepikatu pasahitza';
window.l.eu.moreSettings = 'Aukera gehiago';
window.l.eu.otherServers = 'GNU social sareko beste nodo batean sor dezakezu kontu bat nahi izanez gero. <a href="http://federation.skilledtests.com/select_your_server.html">Alderatu</a>';
window.l.eu.editMyProfile = 'Editatu profila';
window.l.eu.notifications = 'Jakinarazpenak';
window.l.eu.xFavedYourQueet = 'erabiltzaileak gustuko du zure Txioa';
window.l.eu.xRepeatedYourQueet = 'erabiltzaileak bertxiotu zaitu';
window.l.eu.xStartedFollowingYou = 'jarraitzen hasi zaizu';
window.l.eu.followsYou = 'jarraitzen dizu';
// french
window.l.fr = new Object();
@ -588,7 +610,11 @@ window.l.fr.registerRepeatPassword = 'Vérifiez votre mot de passe';
window.l.fr.moreSettings = 'Plus de paramètres';
window.l.fr.otherServers = '';
window.l.fr.editMyProfile = 'Éditer le profil';
window.l.fr.notifications = 'Notifications';
window.l.fr.xFavedYourQueet = 'a ajouté votre Queet à ses favoris ';
window.l.fr.xRepeatedYourQueet = 'vous a requeeté ';
window.l.fr.xStartedFollowingYou = 'vous a suivi';
window.l.fr.followsYou = 'vous suit';
// deutsch
window.l.de = new Object();
@ -711,7 +737,11 @@ window.l.de.registerRepeatPassword = 'Passwort bestätigen';
window.l.de.moreSettings = 'Weitere Einstellungen';
window.l.de.otherServers = 'Du kannst Dir auch gerne ein Konto auf einem anderen Server des GNUsocial-Netzwerks einrichten. <a href="http://federation.skilledtests.com/select_your_server.html">Übersicht</a>';
window.l.de.editMyProfile = 'Profil bearbeiten';
window.l.de.notifications = 'Mitteilungen';
window.l.de.xFavedYourQueet = 'favorisierte Deinen Queet';
window.l.de.xRepeatedYourQueet = 'hat Dich requeetet';
window.l.de.xStartedFollowingYou = 'folgt Dir jetzt';
window.l.de.followsYou = 'folgt Dir';
// english
window.l.en = new Object();
@ -830,6 +860,12 @@ window.l.en.registerRepeatPassword = 'Repeat password';
window.l.en.moreSettings = 'More settings';
window.l.en.otherServers = 'Alternatively you can create an account on another server of the GNU social network. <a href="http://federation.skilledtests.com/select_your_server.html">Comparison</a>';
window.l.en.editMyProfile = 'Edit profile';
window.l.en.notifications = 'Notifications';
window.l.en.xFavedYourQueet = 'favorited your Queet';
window.l.en.xRepeatedYourQueet = 'requeeted you';
window.l.en.xStartedFollowingYou = 'followed you';
window.l.en.followsYou = 'follows you';
// simplified chinese
window.l.zh_cn = new Object();
@ -940,6 +976,12 @@ window.l.zh_cn.registerRepeatPassword = '重复密码';
window.l.zh_cn.moreSettings = '更多的设置';
window.l.zh_cn.otherServers = '其他服务器: <a href="http://federation.skilledtests.com/select_your_server.html">对照</a>';
window.l.zh_cn.editMyProfile = '编辑个人资料';
window.l.zh_cn.notifications = '通知';
window.l.zh_cn.xFavedYourQueet = '收藏了你的推文';
window.l.zh_cn.xRepeatedYourQueet = '转推了你的推文';
window.l.zh_cn.xStartedFollowingYou = '关注了你';
window.l.zh_cn.followsYou = '关注了你';
// traditional chinese
window.l.zh_tw = new Object();
@ -1050,6 +1092,12 @@ window.l.zh_tw.registerRepeatPassword = '重複密碼';
window.l.zh_tw.moreSettings = '更多的設置';
window.l.zh_tw.otherServers = '其他服務器: <a href="http://federation.skilledtests.com/select_your_server.html">對照</a>';
window.l.zh_tw.editMyProfile = '編輯個人檔案';
window.l.zh_tw.notifications = '通知';
window.l.zh_tw.xFavedYourQueet = '已收藏你的推文';
window.l.zh_tw.xRepeatedYourQueet = '已轉推你';
window.l.zh_tw.xStartedFollowingYou = '已跟隨你';
window.l.zh_tw.followsYou = '跟隨你';
// svenska
window.l.sv = new Object();
@ -1160,7 +1208,11 @@ window.l.sv.registerRepeatPassword = 'Upprepa lösenord';
window.l.sv.moreSettings = 'Fler inställningar';
window.l.sv.otherServers = 'Men du kan lika gärna skapa ett konto på en annan server som är del av GNU social-nätverket. <a href="http://federation.skilledtests.com/select_your_server.html">Här är en jämförelse.</a>';
window.l.sv.editMyProfile = 'Redigera profil';
window.l.sv.notifications = 'Notiser';
window.l.sv.xFavedYourQueet = 'favoritmarkerade ditt qvitter';
window.l.sv.xRepeatedYourQueet = 'requeetade dig';
window.l.sv.xStartedFollowingYou = 'följde dig';
window.l.sv.followsYou = 'följer dig';
// farsi/persian
window.l.fa = new Object();
@ -1271,6 +1323,11 @@ window.l.fa.registerRepeatPassword = 'تایید گذرواژه';
window.l.fa.moreSettings = 'تنظیمات بیشتر';
window.l.fa.otherServers = '';
window.l.fa.editMyProfile = 'ویرایش نمایه';
window.l.fa.notifications = 'آگاه‌سازی‌ها';
window.l.fa.xFavedYourQueet = 'موارد دلخواه خود را صدای جیر جیر';
window.l.fa.xRepeatedYourQueet = 'توییت شما را باز توییت کرد.';
window.l.fa.xStartedFollowingYou = 'شما را دنبال کرد';
window.l.fa.followsYou = 'شما را دنبال می‌کند';
// arabic
window.l.ar = new Object();
@ -1381,6 +1438,11 @@ window.l.ar.registerRepeatPassword = 'تأكيد كلمة المرور';
window.l.ar.moreSettings = 'مزيد من الإعدادات';
window.l.ar.otherServers = '';
window.l.ar.editMyProfile = 'تعديل الملف الشخصي';
window.l.ar.notifications = 'التنبيهات';
window.l.ar.xFavedYourQueet = 'بتفضيل تغريدتك';
window.l.ar.xRepeatedYourQueet = 'بإعادة تغريد';
window.l.ar.xStartedFollowingYou = 'بمتابعتك';
window.l.ar.followsYou = 'يُتابعك';
// esperanto
window.l.eo = new Object();
@ -1500,7 +1562,11 @@ window.l.eo.registerRepeatPassword = 'Ripeti pasvorton';
window.l.eo.moreSettings = 'Pli agordoj';
window.l.eo.otherServers = '';
window.l.eo.editMyProfile = 'Redaktu profilon';
window.l.eo.notifications = 'Sciigoj';
window.l.eo.xFavedYourQueet = 'ŝatataj via avizo';
window.l.eo.xRepeatedYourQueet = 'ripetis vin';
window.l.eo.xStartedFollowingYou = 'sekvas vin';
window.l.eo.followsYou = 'sekvas vin';
// italian
window.l.it = new Object();
@ -1620,6 +1686,11 @@ window.l.it.registerRepeatPassword = 'Ripetere la password';
window.l.it.moreSettings = 'Altre opzioni';
window.l.it.otherServers = 'In alternativa puoi creare un account su un altro server della rete GNU Social. <a href="http://federation.skilledtests.com/select_your_server.html">Confronto</a>';
window.l.it.editMyProfile = 'Modifica profilo';
window.l.it.notifications = 'Notifiche';
window.l.it.xFavedYourQueet = 'ha aggiunto ai preferiti il tuo Queet';
window.l.it.xRepeatedYourQueet = 'ti ha requittato';
window.l.it.xStartedFollowingYou = 'ha iniziato a seguirti';
window.l.it.followsYou = 'ti segue';
// Norwegian
window.l.no = new Object();
@ -1730,6 +1801,11 @@ window.l.no.registerRepeatPassword = 'Gjenta passord';
window.l.no.moreSettings = 'Flere instillinger';
window.l.no.otherServers = 'Det finnes flere instanser i GNUsocial nettverket som alternativt kan benyttes. <a href="http://gnu.io/social/try/">Følger du denne lenken finner du noen anbefalinger.</a>';
window.l.no.editMyProfile = 'Rediger profil';
window.l.no.notifications = 'Varsler';
window.l.no.xFavedYourQueet = 'favorittmarkerte queeten din';
window.l.no.xRepeatedYourQueet = 'requeetet deg';
window.l.no.xStartedFollowingYou = 'følger deg';
window.l.no.followsYou = 'følger deg';
// set language, from local storage, else browser language, else english (english also if no localstorage availible)
@ -1793,10 +1869,12 @@ $('#settings').html(window.sL.settings);
$('#other-servers-link').html(window.sL.otherServers);
$('.language-dropdown .dropdown-toggle small').html(window.sL.languageSelected);
$('.language-dropdown .current-language').html(window.sL.languageName);
$('.stream-selection[data-stream-name="qvitter/statuses/friends_timeline.json"]').prepend(window.sL.timeline);
$('.stream-selection[data-stream-name="qvitter/statuses/friends_timeline.json"]').attr('data-stream-header',window.sL.timeline);
$('.stream-selection[data-stream-name="qvitter/statuses/mentions.json"]').prepend(window.sL.mentions);
$('.stream-selection[data-stream-name="qvitter/statuses/mentions.json"]').attr('data-stream-header',window.sL.mentions);
$('.stream-selection[data-stream-name="statuses/friends_timeline.json"]').prepend(window.sL.timeline);
$('.stream-selection[data-stream-name="statuses/friends_timeline.json"]').attr('data-stream-header',window.sL.timeline);
$('.stream-selection[data-stream-name="statuses/mentions.json"]').prepend(window.sL.mentions);
$('.stream-selection[data-stream-name="statuses/mentions.json"]').attr('data-stream-header',window.sL.mentions);
$('.stream-selection[data-stream-name="qvitter/statuses/notifications.json"]').prepend(window.sL.notifications);
$('.stream-selection[data-stream-name="qvitter/statuses/notifications.json"]').attr('data-stream-header',window.sL.notifications);
$('.stream-selection[data-stream-name="favorites.json"]').prepend(window.sL.favoritesNoun);
$('.stream-selection[data-stream-name="favorites.json"]').attr('data-stream-header',window.sL.favoritesNoun);
$('.stream-selection[data-stream-name="statuses/public_timeline.json"]').prepend(window.sL.publicTimeline);

File diff suppressed because one or more lines are too long

4
js/lib/jquery-2.1.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -335,92 +335,21 @@ function timestampToTwitterDate(timestamp) {
/* ·
·
· Decode Qvitter's compact API reponse
·
· @param data: the data returned from qvitter's compact api response
·
· @return data formatted as the non-compact "[old] twitter style" api response
· If we want to make sure we have empty arrays, not empty objects
·
· · · · · · · · · · */
function decodeQvitterCompactFormat(data) {
function convertEmptyObjectToEmptyArray(data) {
// empty object? return empty array instead...
if($.isEmptyObject(data)) {
return [];
}
// leave data unchanged if we don't recognize it
else if(typeof data.s == 'undefined') {
else {
return data;
}
// decode
else {
var users = new Object();
var i = 0;
$.each(data.u, function(k,v){
users[k] = new Object;
users[k].id = k;
users[k].screen_name = v[0];
users[k].name = (v[1]==0?null:v[1]);
users[k].location = (v[2]==0?null:v[2]);
users[k].description = (v[3]==0?null:v[3]);
users[k].profile_image_url_profile_size = v[4];
users[k].profile_image_url_original = v[5];
users[k].groups_count = v[6];
users[k].linkcolor = (v[7]==0?false:v[7]);
users[k].backgroundcolor = (v[8]==0?false:v[8]);
users[k].url = (v[9]==0?null:v[9]);
users[k].followers_count = v[10];
users[k].friends_count = v[11];
users[k].favourites_count = v[12];
users[k].statuses_count = v[13];
users[k].following = (v[14]==0?false:v[14]);
users[k].statusnet_blocking = (v[15]==0?false:v[15]);
users[k].statusnet_profile_url = v[16];
users[k].cover_photo = (v[17]==0?false:v[17]);
i++;
});
var unqvitter = Array();
var i = 0;
$.each(data.s, function(k,v){
unqvitter[i] = new Object;
unqvitter[i].id = v[0];
unqvitter[i].created_at = timestampToTwitterDate(v[1]);
unqvitter[i].text = v[2];
unqvitter[i].statusnet_html = v[3];
unqvitter[i].in_reply_to_status_id = (v[4]==0?null:v[4]);
unqvitter[i].in_reply_to_user_id = (v[5]==0?null:v[5]);
unqvitter[i].in_reply_to_screen_name = (v[6]==0?null:v[6]);
unqvitter[i].favorited = (v[7]==0?false:v[7]);
unqvitter[i].repeated = (v[8]==0?false:v[8]);
unqvitter[i].statusnet_in_groups = (v[9]==0?false:v[9]);
unqvitter[i].user = users[v[10]];
unqvitter[i].statusnet_conversation_id = v[11];
unqvitter[i].uri = window.siteInstanceURL + 'notice/' + v[0];
unqvitter[i].source = (v[12]==0?null:v[12]);
if(typeof v[13] != 'undefined') {
unqvitter[i].retweeted_status = new Object;
unqvitter[i].retweeted_status.id = v[13][0];
unqvitter[i].retweeted_status.created_at = timestampToTwitterDate(v[13][1]);
unqvitter[i].retweeted_status.text = v[13][2];
unqvitter[i].retweeted_status.statusnet_html = v[13][3];
unqvitter[i].retweeted_status.in_reply_to_status_id = (v[13][4]==0?null:v[13][4]);
unqvitter[i].retweeted_status.in_reply_to_user_id = (v[13][5]==0?null:v[13][5]);
unqvitter[i].retweeted_status.in_reply_to_screen_name = (v[13][6]==0?null:v[13][6]);
unqvitter[i].retweeted_status.favorited = (v[13][7]==0?false:v[13][7]);
unqvitter[i].retweeted_status.repeated = (v[13][8]==0?false:v[13][8]);
unqvitter[i].retweeted_status.statusnet_in_groups = (v[13][9]==0?false:v[13][9]);
unqvitter[i].retweeted_status.user = users[v[13][10]];
unqvitter[i].retweeted_status.statusnet_conversation_id = v[13][11];
unqvitter[i].retweeted_status.uri = window.siteInstanceURL + 'notice/' + v[13][0];
unqvitter[i].retweeted_status.source = (v[13][12]==0?null:v[13][12]);
}
i++;
});
return unqvitter;
}
}
@ -458,25 +387,27 @@ function findUrls(text) {
· · · · · · · · · · · · */
function display_spinner() {
$('body').prepend('\
<div class="loader">\
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\
width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">\
<path opacity="0.2" enable-background="new " d="M20.201,8.503c-6.413,0-11.612,5.199-11.612,11.612s5.199,11.611,11.612,11.611\
c6.412,0,11.611-5.198,11.611-11.611S26.613,8.503,20.201,8.503z M20.201,29.153c-4.992,0-9.039-4.046-9.039-9.038\
s4.047-9.039,9.039-9.039c4.991,0,9.038,4.047,9.038,9.039S25.192,29.153,20.201,29.153z"/>\
<path d="M24.717,12.293l1.285-2.227c-1.708-0.988-3.686-1.563-5.801-1.563l0,0v2.573l0,0C21.848,11.076,23.386,11.524,24.717,12.293 z">\
<animateTransform attributeType="xml"\
attributeName="transform"\
type="rotate"\
from="0 20 20"\
to="360 20 20"\
dur="1s"\
repeatCount="indefinite"/>\
</path>\
</svg>\
</div>\
');
if($('.loader').length<1) {
$('body').prepend('\
<div class="loader">\
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\
width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">\
<path opacity="0.2" enable-background="new " d="M20.201,8.503c-6.413,0-11.612,5.199-11.612,11.612s5.199,11.611,11.612,11.611\
c6.412,0,11.611-5.198,11.611-11.611S26.613,8.503,20.201,8.503z M20.201,29.153c-4.992,0-9.039-4.046-9.039-9.038\
s4.047-9.039,9.039-9.039c4.991,0,9.038,4.047,9.038,9.039S25.192,29.153,20.201,29.153z"/>\
<path d="M24.717,12.293l1.285-2.227c-1.708-0.988-3.686-1.563-5.801-1.563l0,0v2.573l0,0C21.848,11.076,23.386,11.524,24.717,12.293 z">\
<animateTransform attributeType="xml"\
attributeName="transform"\
type="rotate"\
from="0 20 20"\
to="360 20 20"\
dur="1s"\
repeatCount="indefinite"/>\
</path>\
</svg>\
</div>\
');
}
}
function remove_spinner() {
$('.loader').remove();
@ -861,14 +792,17 @@ function shortenUrlsInBox(shortenButton) {
$.each(shortenButton.parent().parent().siblings('.syntax-middle').find('span.url'),function(key,obj){
var url = $.trim($(obj).html().replace(/&amp;/gi,'&').replace(/&nbsp;/gi,'').replace(/<br>/gi,''));
var url = $.trim($(obj).text());
display_spinner();
$.ajax({ url: window.urlShortenerAPIURL + '?format=jsonp&action=shorturl&signature=' + window.urlShortenerSignature + '&url=' + encodeURIComponent(url), type: "GET", dataType: "jsonp", success: function(data) {
if(typeof data.shorturl != 'undefined') {
shortenButton.parent().parent().siblings('.queet-box-syntax').html(shortenButton.parent().parent().siblings('.queet-box-syntax').html().replace(data.url.url, data.shorturl));
console.log(data.url);
shortenButton.parent().parent().siblings('.queet-box-syntax').html(shortenButton.parent().parent().siblings('.queet-box-syntax').html().replace($('<div/>').text(data.url.url).html(), data.shorturl));
shortenButton.parent().parent().siblings('.queet-box-syntax').trigger('keyup');
shortenButton.addClass('disabled'); // make sure the button is disabled right after
}

View File

@ -59,12 +59,12 @@ window.onpopstate = function(event) {
·
· · · · · · · · · · · · · */
window.loginContentStartPos = $('.front-welcome-text').height()+45;
$(window).scroll(function(e){
if ($(this).scrollTop() > window.loginContentStartPos && $('#login-content').css('position') != 'fixed'){
// console.log($('#feed').offset().top);
if ($(this).scrollTop() > ($('#feed').offset().top-50) && $('#login-content').css('position') != 'fixed'){
$('#login-content, .front-signup').not('#popup-signup').css({'position': 'fixed', 'top': '50px'});
}
else if ($(this).scrollTop() < window.loginContentStartPos && $('#login-content').css('position') != 'absolute'){
else if ($(this).scrollTop() < ($('#feed').offset().top-50) && $('#login-content').css('position') != 'absolute'){
$('#login-content, .front-signup').not('#popup-signup').css({'position': 'absolute', 'top': 'auto'});
}
});
@ -123,9 +123,9 @@ if(!window.registrationsClosed) {
$('#signup-user-nickname-step2').after('<div class="spinner-wrap"><div class="spinner"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div>');
}
window.checkNicknameTimeout = setTimeout(function(){
getFromAPI('check_nickname.json?nickname=' + encodeURIComponent($('#signup-user-nickname-step2').val()),function(data){
$.get(window.apiRoot + 'check_nickname.json?nickname=' + encodeURIComponent($('#signup-user-nickname-step2').val()),function(data){
$('.spinner-wrap').remove();
if(data=='taken') {
if(data==0) {
$('#signup-user-password2-step2').trigger('keyup'); // revalidates
}
else {
@ -288,6 +288,7 @@ function doLogin(streamToSet) {
// add user data to DOM, show search form, remeber user id, show the feed
$('#user-container').css('z-index','1000');
$('#top-compose').removeClass('hidden');
$('#qvitter-notice').show();
$('#user-avatar').attr('src', window.loggedIn.profile_image_url_profile_size);
$('#user-name').append(window.loggedIn.name);
$('#user-screen-name').append(window.loggedIn.screen_name);
@ -298,6 +299,7 @@ function doLogin(streamToSet) {
$('#user-groups strong').html(window.loggedIn.groups_count);
$('.stream-selection.friends-timeline').attr('href', window.loggedIn.statusnet_profile_url + '/all');
$('.stream-selection.mentions').attr('href', window.loggedIn.statusnet_profile_url + '/replies');
$('.stream-selection.notifications').attr('href', window.loggedIn.statusnet_profile_url + '/notifications');
$('.stream-selection.my-timeline').attr('href', window.loggedIn.statusnet_profile_url);
$('.stream-selection.favorites').attr('href', window.loggedIn.statusnet_profile_url + '/favorites');
window.myUserID = window.loggedIn.id;
@ -425,16 +427,6 @@ function keyupSetBGColor(hex) {
}
// go to standard settingspage
$('body').on('click','#moresettings',function(){
$(document.body).append('<iframe id="logout-iframe" src="https://quitter.se/main/logout" style="display:none;">'); // we need to logout before login, otherwise redirection to settingspage doesn't work
$('iframe#logout-iframe').load(function() {
$('#moresettings').children('form').submit(); // submit hidden form and open settingspage in new tab
});
});
/* ·
@ -663,11 +655,17 @@ $('body').on('click','.profile-banner-footer .stats li a, .queet-stream',functio
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + screenName,function(){},true);
}
else if($(this).hasClass('mentions')) {
setNewCurrentStream('qvitter/statuses/mentions.json?screen_name=' + screenName,function(){},true);
setNewCurrentStream('statuses/mentions.json?screen_name=' + screenName,function(){},true);
}
else if($(this).hasClass('favorites')) {
setNewCurrentStream('favorites.json?screen_name=' + screenName,function(){},true);
}
else if($(this).hasClass('following')) {
setNewCurrentStream('statuses/friends.json?count=20',function(){},true);
}
else if($(this).hasClass('followers')) {
setNewCurrentStream('statuses/followers.json?count=20',function(){},true);
}
else if($(this).hasClass('member-stats')) {
setNewCurrentStream('statusnet/groups/membership/' + screenName + '.json?count=20',function(){},true);
}
@ -731,12 +729,16 @@ $(document).on('click','a', function(e) {
// logged in users streams
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/all') {
e.preventDefault();
setNewCurrentStream('qvitter/statuses/friends_timeline.json',function(){},true);
setNewCurrentStream('statuses/friends_timeline.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/replies') {
e.preventDefault();
setNewCurrentStream('qvitter/statuses/mentions.json',function(){},true);
setNewCurrentStream('statuses/mentions.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/notifications') {
e.preventDefault();
setNewCurrentStream('qvitter/statuses/notifications.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/favorites') {
e.preventDefault();
setNewCurrentStream('favorites.json',function(){},true);
@ -747,9 +749,6 @@ $(document).on('click','a', function(e) {
if($(this).parent().attr('id') == 'user-profile-link') { // logged in user
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name,function(){},true);
}
else if($(this).hasClass('account-group')) { // any user
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + $(this).find('.screen-name').text().substring(1).toLowerCase(),function(){},true);
}
else { // any user
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/',''),function(){},true);
}
@ -763,6 +762,11 @@ $(document).on('click','a', function(e) {
e.preventDefault();
setNewCurrentStream('statusnet/tags/timeline/' + $(this).text().toLowerCase().replace('#','') + '.json',function(){},true);
}
// notices
else if ($(this).attr('href').indexOf(window.siteRootDomain + '/notice/')>-1) {
e.preventDefault();
setNewCurrentStream('statuses/show/' + $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/notice/','') + '.json',function(){},true);
}
// groups
else if (/^[0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/group/','').replace('/id',''))) {
e.preventDefault();
@ -793,6 +797,7 @@ $(document).on('click','a', function(e) {
// external profiles
else if (($(this).children('span.mention').length>0 // if it's a mention
|| $(this).hasClass('h-card mention') // if it's a newer gnusocial group mention
|| ($(this).hasClass('account-group') && $(this).attr('href').indexOf('/group/')==-1) // or if this is queet stream item header but not a group
|| ($(this).closest('.stream-item').hasClass('activity') && $(this).attr('href').indexOf('/group/')==-1)) // or if it's a activity notice but not a group link
&& typeof window.loggedIn.screen_name != 'undefined') { // if logged in
@ -849,6 +854,7 @@ $(document).on('click','a', function(e) {
// external groups
else if (($(this).children('span.group').length>0 // if it's a group mention
|| $(this).hasClass('h-card group') // if it's a newer gnusocial group mention
|| ($(this).hasClass('account-group') && $(this).attr('href').indexOf('/group/')>-1) // or if this is group stream item header
|| ($(this).closest('.stream-item').hasClass('activity') && $(this).attr('href').indexOf('/group/')>-1)) // or if it's a activity notice
&& typeof window.loggedIn.screen_name != 'undefined') { // if logged in
@ -1005,10 +1011,12 @@ var updateTimesInterval=self.setInterval(function(){
/* ·
·
· Check for new queets
· Check for new queets and notifications
·
· · · · · · · · · · · · · */
var checkForNewNotificationsInterval=window.setInterval(function(){checkForNewNotifications()},window.timeBetweenPolling);
checkForNewNotifications();
var checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling);
function checkForNewQueets() {
@ -1033,7 +1041,12 @@ function checkForNewQueets() {
// if we have hidden items, show new-queets-bar
if($('#feed-body').find('.stream-item.hidden').length > 0) {
var new_queets_num = $('#feed-body').find('.stream-item.hidden').length;
document.title = window.siteTitle + ' (' + new_queets_num + ')';
// if this is notifications page, update site title with hidden notification count
if(window.currentStream == 'qvitter/statuses/notifications.json') {
document.title = window.siteTitle + ' (' + new_queets_num + ')';
}
$('#new-queets-bar').parent().removeClass('hidden');
// text plural
@ -1050,8 +1063,6 @@ function checkForNewQueets() {
}
/* ·
·
· Show hidden queets when user clicks on new-queets-bar
@ -1059,7 +1070,9 @@ function checkForNewQueets() {
· · · · · · · · · · · · · */
$('body').on('click','#new-queets-bar',function(){
document.title = window.siteTitle;
if(window.currentStream == 'qvitter/statuses/notifications.json') {
document.title = window.siteTitle;
}
$('.stream-item.hidden').css('opacity','0')
$('.stream-item.hidden').animate({opacity:'1'}, 200);
$('.stream-item.hidden').removeClass('hidden');
@ -1296,7 +1309,13 @@ $('body').on('click','.action-reply-container',function(){
$queetHtmlExpandedContent.remove();
var queetHtmlWithoutFooter = $queetHtml.html();
popUpAction('popup-reply-' + this_stream_item_id, window.sL.replyTo + ' ' + this_stream_item.find('.screen-name').html(),replyFormHtml(this_stream_item,this_stream_item_id),queetHtmlWithoutFooter);
$('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.queet-box').width($('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.inline-reply-queetbox').width()-20);
// fix the width of the queet box, otherwise the syntax highlighting break
var queetBoxWidth = $('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.inline-reply-queetbox').width()-20;
$('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.queet-box-syntax').width(queetBoxWidth);
$('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.syntax-middle').width(queetBoxWidth);
$('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.syntax-two').width(queetBoxWidth);
$('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.queet-box').trigger('click'); // expand
});
@ -1819,6 +1838,7 @@ $('body').on('click','.edit-profile-button',function(){
</div>\
</div>\
</div>');
$('#edit-profile-popup .profile-card').css('top',$('#page-container .profile-card').offset().top-53 + 'px'); // position exactly over
}
else {
abortEditProfile();

View File

@ -19,8 +19,10 @@ GitHub: => https://github.com/knuthollund
$query = $_SERVER['QUERY_STRING'];
$shortenerUrl = 'http://qttr.at/yourls-api.php?' . $query;
print file_get_contents($shortenerUrl);
if(strlen($query)>0) {
$shortenerUrl = 'http://qttr.at/yourls-api.php?' . $query;
print file_get_contents($shortenerUrl);
}
?>