suggest group mentions, and always post to correct group even user is member of multiple groups with same nickname
This commit is contained in:
parent
4584a03ffe
commit
976be81ce9
|
@ -179,6 +179,10 @@ class QvitterPlugin extends Plugin {
|
|||
array('action' => 'qvitteradminsettings'));
|
||||
$m->connect('main/qlogin',
|
||||
array('action' => 'qvitterlogin'));
|
||||
URLMapperOverwrite::overwrite_variable($m, 'api/statuses/update.:format',
|
||||
array('action' => 'ApiStatusesUpdate'),
|
||||
array('format' => '(xml|json)'),
|
||||
'ApiQvitterStatusesUpdate');
|
||||
|
||||
|
||||
// check if we should reroute UI to qvitter, and which home-stream the user wants (hide-replies or normal)
|
||||
|
@ -916,6 +920,42 @@ class QvitterPlugin extends Plugin {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct group mentions
|
||||
*
|
||||
* We get the correct group ids in a $_POST var called "post_to_groups", formatted as a string with ids separated by colon, e.g. 4:5
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
public function onEndFindMentions($sender, $text, &$mentions) {
|
||||
|
||||
// get the correct group profiles
|
||||
if(isset($_POST['post_to_groups'])) {
|
||||
$correct_group_mentions = explode(':',$_POST['post_to_groups']);
|
||||
foreach($correct_group_mentions as $group_id) {
|
||||
$correct_group_mentions_profiles[] = Profile::getKV('id',$group_id);
|
||||
}
|
||||
|
||||
// loop through the groups guessed by gnu social's common_find_mentions() and correct them
|
||||
foreach($mentions as $mention_array_id=>$mention) {
|
||||
foreach($correct_group_mentions_profiles as $correct_group_array_id=>$correct_group_profile) {
|
||||
if($mention['mentioned'][0]->nickname == $correct_group_profile->nickname
|
||||
&& !isset($mentions[$mention_array_id]['corrected'])) {
|
||||
$mentions[$mention_array_id]['mentioned'][0] = $correct_group_profile;
|
||||
$user_group = User_group::getKV('profile_id',$correct_group_profile->id);
|
||||
$mentions[$mention_array_id]['url'] = $user_group->permalink();
|
||||
$mentions[$mention_array_id]['title'] = $user_group->getFancyName();
|
||||
$mentions[$mention_array_id]['corrected'] = true;
|
||||
// now we've used this
|
||||
unset($correct_group_mentions_profiles[$correct_group_array_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Everybody I'm following and all groups I'm member of ·
|
||||
· (to use for auto-suggestions) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· (to use for auto-suggestions) ·
|
||||
· ·
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
· ·
|
||||
· ·
|
||||
· Q V I T T E R ·
|
||||
|
@ -19,9 +19,9 @@
|
|||
· (____/ ·
|
||||
· (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 ·
|
||||
|
@ -36,7 +36,7 @@
|
|||
· along with Qvitter. If not, see <http://www.gnu.org/licenses/>. ·
|
||||
· ·
|
||||
· Contact h@nnesmannerhe.im if you have any questions. ·
|
||||
· ·
|
||||
· ·
|
||||
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
|
||||
|
||||
|
||||
|
@ -48,6 +48,7 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
|
||||
var $profiles = null;
|
||||
var $users_stripped = null;
|
||||
var $groups_stripped = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
|
@ -71,16 +72,16 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
$this->groups = $this->getGroups();
|
||||
|
||||
|
||||
// only keep id, name, nickname and avatar URL
|
||||
|
||||
// profiles: only keep id, name, nickname and avatar URL
|
||||
foreach($this->profiles as $p) {
|
||||
try {
|
||||
$avatar = Avatar::byProfile($p, AVATAR_STREAM_SIZE);
|
||||
$avatar = $avatar->url;
|
||||
$avatar = Avatar::urlByProfile($p, AVATAR_STREAM_SIZE);
|
||||
} catch (Exception $e) {
|
||||
$avatar = false;
|
||||
}
|
||||
}
|
||||
$this_user = array($p->fullname,$p->nickname,$avatar);
|
||||
if(!$p->isLocal()) {
|
||||
$this_user[3] = $p->getUrl();
|
||||
|
@ -91,6 +92,20 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
$this->users_stripped[$p->id] = $this_user;
|
||||
}
|
||||
|
||||
// groups: only keep id, name, nickname, avatar and local aliases
|
||||
foreach($this->groups as $user_group) {
|
||||
$p = $user_group->getProfile();
|
||||
$avatar = $user_group->stream_logo;
|
||||
$this_group = array($p->fullname,$p->nickname,$avatar);
|
||||
if(!$user_group->isLocal()) {
|
||||
$this_group[3] = $p->getUrl();
|
||||
}
|
||||
else {
|
||||
$this_group[3] = false;
|
||||
}
|
||||
$this->groups_stripped[$p->id] = $this_group;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -104,13 +119,13 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->users_stripped);
|
||||
$this->showJsonObjects(array('users'=>$this->users_stripped,'groups'=>$this->groups_stripped));
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get profiles
|
||||
*
|
||||
|
@ -123,16 +138,10 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscriptions(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
|
||||
$profiles = array();
|
||||
|
||||
|
@ -143,4 +152,28 @@ class ApiQvitterAllFollowingAction extends ApiBareAuthAction
|
|||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
$group = $this->target->getGroups(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
356
actions/apiqvitterstatusesupdate.php
Normal file
356
actions/apiqvitterstatusesupdate.php
Normal file
|
@ -0,0 +1,356 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Post a notice (update your status) through the API
|
||||
*
|
||||
* 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 Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 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/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page statusesupdate statuses/update
|
||||
|
||||
@section Description
|
||||
Updates the authenticating user's status. Requires the status parameter specified below.
|
||||
Request must be a POST.
|
||||
|
||||
@par URL pattern
|
||||
/api/statuses/update.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json
|
||||
|
||||
@par HTTP Method(s)
|
||||
POST
|
||||
|
||||
@par Requires Authentication
|
||||
Yes
|
||||
|
||||
@param status (Required) The URL-encoded text of the status update.
|
||||
@param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
|
||||
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
|
||||
@param lat (Optional) The latitude the status refers to.
|
||||
@param long (Optional) The longitude the status refers to.
|
||||
@param media (Optional) a media upload, such as an image or movie file.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
|
||||
@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>).
|
||||
@li Data uploaded via the @e media parameter should be multipart/form-data encoded.
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<status>
|
||||
<text>Howdy!</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source>api</source>
|
||||
<id>26668724</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo xmlns:georss="http://www.georss.org/georss">
|
||||
<georss:point>30.468 -94.743</georss:point>
|
||||
</geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>25803</id>
|
||||
<name>Jed Sanders</name>
|
||||
<screen_name>jedsanders</screen_name>
|
||||
<location>Hoop and Holler, Texas</location>
|
||||
<description>I like to think of myself as America's Favorite.</description>
|
||||
<profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
|
||||
<url>http://jedsanders.net</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>5</followers_count>
|
||||
<profile_background_color/>
|
||||
<profile_text_color/>
|
||||
<profile_link_color/>
|
||||
<profile_sidebar_fill_color/>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>2</friends_count>
|
||||
<created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>70</statuses_count>
|
||||
<following>true</following>
|
||||
<notifications>true</notifications>
|
||||
</user>
|
||||
</status>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's status (posts a notice).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiQvitterStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $status = null;
|
||||
var $in_reply_to_status_id = null;
|
||||
var $lat = null;
|
||||
var $lon = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->post_to_groups = $this->trimmed('post_to_groups');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
|
||||
$this->in_reply_to_status_id
|
||||
= intval($this->trimmed('in_reply_to_status_id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
if (empty($this->status)) {
|
||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||
$this->clientError(_('Client must provide a \'status\' parameter with a value.'));
|
||||
}
|
||||
|
||||
if (is_null($this->scoped)) {
|
||||
// TRANS: Client error displayed when updating a status for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
|
||||
// Check for commands
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
$cmd = $inter->handle_command($this->auth_user, $this->status);
|
||||
|
||||
if ($cmd) {
|
||||
if ($this->supported($cmd)) {
|
||||
$cmd->execute(new Channel());
|
||||
}
|
||||
|
||||
// Cmd not supported? Twitter just returns your latest status.
|
||||
// And, it returns your last status whether the cmd was successful
|
||||
// or not!
|
||||
|
||||
$this->notice = $this->auth_user->getCurrentNotice();
|
||||
} else {
|
||||
$reply_to = null;
|
||||
|
||||
if (!empty($this->in_reply_to_status_id)) {
|
||||
// Check whether notice actually exists
|
||||
|
||||
$reply = Notice::getKV($this->in_reply_to_status_id);
|
||||
|
||||
if ($reply) {
|
||||
$reply_to = $this->in_reply_to_status_id;
|
||||
} else {
|
||||
// TRANS: Client error displayed when replying to a non-existing notice.
|
||||
$this->clientError(_('Parent notice not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
$upload = null;
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
$this->status .= ' ' . $upload->shortUrl();
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// There was no uploaded media for us today.
|
||||
}
|
||||
|
||||
// in Qvitter we shorten _before_ posting, so disble shortening here
|
||||
$status_shortened = $this->status;
|
||||
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
if ($upload instanceof MediaFile) {
|
||||
$upload->delete();
|
||||
}
|
||||
// TRANS: Client error displayed exceeding the maximum notice length.
|
||||
// TRANS: %d is the maximum lenth for a notice.
|
||||
$msg = _m('Maximum notice size is %d character, including attachment URL.',
|
||||
'Maximum notice size is %d characters, including attachment URL.',
|
||||
Notice::maxContent());
|
||||
/* Use HTTP 413 error code (Request Entity Too Large)
|
||||
* instead of basic 400 for better understanding
|
||||
*/
|
||||
$this->clientError(sprintf($msg, Notice::maxContent()), 413);
|
||||
}
|
||||
|
||||
|
||||
$content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
// groups
|
||||
$group_ids = Array();
|
||||
if(strlen($this->post_to_groups)>0) {
|
||||
$groups_profile_ids = explode(':',$this->post_to_groups);
|
||||
foreach($groups_profile_ids as $group_profile_id) {
|
||||
$user_group = User_group::getKV('profile_id',$group_profile_id);
|
||||
$group_ids[] = $user_group->id;
|
||||
}
|
||||
}
|
||||
|
||||
$options = array('reply_to' => $reply_to, 'groups' => $group_ids);
|
||||
|
||||
if ($this->scoped->shareLocation()) {
|
||||
|
||||
$locOptions = Notice::locationOptions($this->lat,
|
||||
$this->lon,
|
||||
null,
|
||||
null,
|
||||
$this->scoped);
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notice = Notice::saveNew(
|
||||
$this->scoped->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this command supported when doing an update from the API?
|
||||
*
|
||||
* @param string $cmd the command to check for
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function supported($cmd)
|
||||
{
|
||||
static $cmdlist = array('SubCommand', 'UnsubCommand',
|
||||
'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
|
||||
|
||||
$supported = null;
|
||||
|
||||
if (Event::handle('CommandSupportedAPI', array($cmd, &$supported))) {
|
||||
$supported = $supported || in_array(get_class($cmd), $cmdlist);
|
||||
}
|
||||
|
||||
return $supported;
|
||||
}
|
||||
}
|
|
@ -195,6 +195,7 @@ class QvitterAction extends ApiAction
|
|||
*/
|
||||
|
||||
window.defaultAvatarStreamSize = <?php print json_encode(Avatar::defaultImage(AVATAR_STREAM_SIZE)) ?>;
|
||||
window.defaultAvatarProfileSize = <?php print json_encode(Avatar::defaultImage(AVATAR_PROFILE_SIZE)) ?>;
|
||||
window.textLimit = <?php print json_encode((int)common_config('site','textlimit')) ?>;
|
||||
window.registrationsClosed = <?php print json_encode($registrationsclosed) ?>;
|
||||
window.thisSiteThinksItIsHttpButIsActuallyHttps = <?php
|
||||
|
|
|
@ -1563,7 +1563,7 @@ background-repeat: no-repeat;
|
|||
}
|
||||
.stream-item.expanded:not(.conversation) + .stream-item:not(.conversation)::before {
|
||||
border-top-left-radius: 9px;
|
||||
border-top-right-radius: 9px;
|
||||
border-top-right-radius: 9px;
|
||||
}
|
||||
.stream-item.expanded.selected-by-keyboard::before {
|
||||
height:100%;
|
||||
|
@ -1577,6 +1577,7 @@ background-repeat: no-repeat;
|
|||
line-height: 12px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.show-full-conversation:hover {
|
||||
text-decoration:underline;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB |
|
@ -293,17 +293,19 @@ function APIJoinOrLeaveGroup(joinOrLeave,group_id,this_element,actionOnSuccess)
|
|||
·
|
||||
· @param queetText_txt: the text to post
|
||||
· @param in_reply_to_status_id: the local id for the queet to reply to
|
||||
· @param postToGroups: post the queet in these groups, string of ids separated by colon expected, e.g. 5:2:4
|
||||
· @param actionOnSuccess: callback function, false on error, data on success
|
||||
·
|
||||
· · · · · · · · · · · · · */
|
||||
|
||||
function postQueetToAPI(queetText_txt, in_reply_to_status_id, actionOnSuccess) {
|
||||
function postQueetToAPI(queetText_txt, in_reply_to_status_id, postToGroups, actionOnSuccess) {
|
||||
$.ajax({ url: window.apiRoot + 'statuses/update.json?t=' + timeNow(),
|
||||
type: "POST",
|
||||
data: {
|
||||
status: queetText_txt,
|
||||
source: 'Qvitter',
|
||||
in_reply_to_status_id: in_reply_to_status_id
|
||||
in_reply_to_status_id: in_reply_to_status_id,
|
||||
post_to_groups: postToGroups
|
||||
},
|
||||
dataType:"json",
|
||||
error: function(data){ actionOnSuccess(false); console.log(data); },
|
||||
|
|
|
@ -446,9 +446,9 @@ function groupProfileCard(groupAlias) {
|
|||
|
||||
data.nickname = data.nickname || '';
|
||||
data.fullname = data.fullname || '';
|
||||
data.stream_logo = data.stream_logo || window.fullUrlToThisQvitterApp + 'img/default-avatar-stream.png';
|
||||
data.homepage_logo = data.homepage_logo || window.fullUrlToThisQvitterApp + 'img/default-avatar-profile.png';
|
||||
data.original_logo = data.original_logo || window.fullUrlToThisQvitterApp + 'img/default-avatar-profile.png';
|
||||
data.stream_logo = data.stream_logo || window.defaultAvatarStreamSize;
|
||||
data.homepage_logo = data.homepage_logo || window.defaultAvatarProfileSize;
|
||||
data.original_logo = data.original_logo || window.defaultAvatarProfileSize;
|
||||
data.description = data.description || '';
|
||||
data.homepage = data.homepage || '';
|
||||
data.url = data.url || '';
|
||||
|
@ -1718,7 +1718,7 @@ function addToFeed(feed, after, extraClasses, isReply) {
|
|||
if($('#stream-item-' + obj.id).length == 0) {
|
||||
|
||||
obj.description = obj.description || '';
|
||||
obj.stream_logo = obj.stream_logo || window.fullUrlToThisQvitterApp + 'img/default-avatar-profile.png';
|
||||
obj.stream_logo = obj.stream_logo || window.defaultAvatarStreamSize;
|
||||
|
||||
// rtl or not
|
||||
var rtlOrNot = '';
|
||||
|
@ -1733,7 +1733,6 @@ function addToFeed(feed, after, extraClasses, isReply) {
|
|||
}
|
||||
var memberButton = '';
|
||||
if(typeof window.loggedIn.screen_name != 'undefined') {
|
||||
console.log(obj);
|
||||
var memberButton = '<div class="user-actions"><button data-group-id="' + obj.id + '" type="button" class="member-button ' + memberClass + '"><span class="button-text join-text"><i class="join"></i>' + window.sL.joinGroup + '</span><span class="button-text ismember-text">' + window.sL.isMemberOfGroup + '</span><span class="button-text leave-text">' + window.sL.leaveGroup + '</span></button></div>';
|
||||
}
|
||||
var groupAvatar = obj.stream_logo;
|
||||
|
|
File diff suppressed because one or more lines are too long
193
js/qvitter.js
193
js/qvitter.js
|
@ -533,10 +533,14 @@ function doLogin(streamToSet) {
|
|||
|
||||
// get all users i'm following for autosuggestion
|
||||
window.following = new Array();
|
||||
window.groupMemberships = new Array();
|
||||
window.groupNicknamesAndLocalAliases = new Array();
|
||||
|
||||
getFromAPI('qvitter/allfollowing/' + window.loggedIn.screen_name + '.json',function(data){
|
||||
if(data) {
|
||||
|
||||
if(data.users) {
|
||||
var i=0;
|
||||
$.each(data,function(k,v){
|
||||
$.each(data.users,function(k,v){
|
||||
if(v[2] === false) { var avatar = window.defaultAvatarStreamSize; }
|
||||
else { var avatar = v[2]; }
|
||||
if(v[3]) {
|
||||
|
@ -547,20 +551,39 @@ function doLogin(streamToSet) {
|
|||
window.following[i] = { 'id': k,'name': v[0], 'username': v[1],'avatar': avatar, 'url':v[3] };
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
cacheSyntaxHighlighting(); // do this now not to stall slow computers
|
||||
if(data.groups) {
|
||||
var i=0;
|
||||
$.each(data.groups,function(k,v){
|
||||
if(v[2] === false || v[2] === null) { var avatar = window.defaultAvatarStreamSize; }
|
||||
else { var avatar = v[2]; }
|
||||
if(v[3]) {
|
||||
// extract server base url
|
||||
v[3] = v[3].substring(v[3].indexOf('://')+3);
|
||||
v[3] = v[3].substring(0, v[3].indexOf('/'));
|
||||
}
|
||||
v[0] = v[0] || v[1]; // if name is null we go with username there too
|
||||
window.groupMemberships[i] = { 'id': k,'name': v[0], 'username': v[1],'avatar': avatar, 'url':v[3] };
|
||||
window.groupNicknamesAndLocalAliases[i] = v[1];
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
// we might have cached text for the queet box
|
||||
// (we need to get the mentions suggestions and cache the syntax highlighting before doing this)
|
||||
var cachedQueetBoxData = localStorageObjectCache_GET('queetBoxInput','queet-box');
|
||||
var cachedQueetBoxDataText = $('<div/>').html(cachedQueetBoxData).text();
|
||||
if(cachedQueetBoxData) {
|
||||
queetBox = $('#queet-box');
|
||||
queetBox.click();
|
||||
queetBox.html(cachedQueetBoxData);
|
||||
setSelectionRange(queetBox[0], cachedQueetBoxDataText.length, cachedQueetBoxDataText.length);
|
||||
queetBox.trigger('input');
|
||||
}
|
||||
// do this now not to stall slow computers, also we know of group memberships to highlight now
|
||||
cacheSyntaxHighlighting();
|
||||
cacheSyntaxHighlightingGroups();
|
||||
|
||||
// we might have cached text for the queet box
|
||||
// (we need to get the mentions suggestions and cache the syntax highlighting before doing this)
|
||||
var cachedQueetBoxData = localStorageObjectCache_GET('queetBoxInput','queet-box');
|
||||
var cachedQueetBoxDataText = $('<div/>').html(cachedQueetBoxData).text();
|
||||
if(cachedQueetBoxData) {
|
||||
queetBox = $('#queet-box');
|
||||
queetBox.click();
|
||||
queetBox.html(cachedQueetBoxData);
|
||||
setSelectionRange(queetBox[0], cachedQueetBoxDataText.length, cachedQueetBoxDataText.length);
|
||||
queetBox.trigger('input');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1195,9 +1218,9 @@ $('body').on('click','a', function(e) {
|
|||
|
||||
data.nickname = data.nickname || '';
|
||||
data.fullname = data.fullname || '';
|
||||
data.stream_logo = data.stream_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-stream.png';
|
||||
data.homepage_logo = data.homepage_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-profile.png';
|
||||
data.original_logo = data.original_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-profile.png';
|
||||
data.stream_logo = data.stream_logo || window.defaultAvatarStreamSize;
|
||||
data.homepage_logo = data.homepage_logo || window.defaultAvatarProfileSize;
|
||||
data.original_logo = data.original_logo || window.defaultAvatarProfileSize;
|
||||
data.description = data.description || '';
|
||||
data.homepage = data.homepage || '';
|
||||
data.url = data.url || '';
|
||||
|
@ -2104,6 +2127,19 @@ $('body').on('click', '.queet-toolbar button',function () {
|
|||
popUpAction('popup-sending', '',queetHtml.replace('class="stream-item conversation','class="stream-item'),false);
|
||||
}
|
||||
|
||||
// maybe post queet in groups
|
||||
var postToGroups = '';
|
||||
var postToGropsArray = new Array();
|
||||
$.each(queetBox.siblings('.post-to-group'),function(){
|
||||
postToGropsArray.push($(this).data('group-id'));
|
||||
});
|
||||
if(postToGropsArray.length > 0) {
|
||||
postToGroups = postToGropsArray.join(':');
|
||||
}
|
||||
|
||||
// remove any post-to-group-divs
|
||||
queetBox.siblings('.post-to-group').remove();
|
||||
|
||||
// remove any replying-to classes
|
||||
$('.stream-item').removeClass('replying-to');
|
||||
|
||||
|
@ -2114,7 +2150,7 @@ $('body').on('click', '.queet-toolbar button',function () {
|
|||
setTimeout('checkForNewQueets()', 1000);
|
||||
|
||||
// post queet
|
||||
postQueetToAPI(queetText, in_reply_to_status_id, function(data){ if(data) {
|
||||
postQueetToAPI(queetText, in_reply_to_status_id, postToGroups, function(data){ if(data) {
|
||||
|
||||
// show real queet
|
||||
var new_queet = Array();
|
||||
|
@ -2229,6 +2265,11 @@ $('body').on('mousedown','.syntax-two',function () {
|
|||
});
|
||||
$('body').on('blur','.queet-box-syntax',function (e) {
|
||||
|
||||
// empty the mention suggestions on blur, timeout because we want to capture clicks in .mentions-suggestions
|
||||
setTimeout(function(){
|
||||
$(this).siblings('.mentions-suggestions').empty();
|
||||
},10);
|
||||
|
||||
// don't collapse if a toolbar button has been clicked
|
||||
var clickedToolbarButtons = $(this).siblings('.queet-toolbar').find('button.clicked');
|
||||
if(clickedToolbarButtons.length>0) {
|
||||
|
@ -2408,13 +2449,31 @@ $('body').on('keydown', '.queet-box-syntax', function(e) {
|
|||
});
|
||||
|
||||
function useSelectedMention(queetBox){
|
||||
|
||||
// use selected
|
||||
if(queetBox.siblings('.mentions-suggestions').children('div.selected').length > 0) {
|
||||
var username = queetBox.siblings('.mentions-suggestions').children('div.selected').children('span').html();
|
||||
var selectedSuggestion = queetBox.siblings('.mentions-suggestions').children('div.selected');
|
||||
}
|
||||
// if none selected, take top suggestion
|
||||
else {
|
||||
var username = queetBox.siblings('.mentions-suggestions').children('div').first().children('span').html();
|
||||
var selectedSuggestion = queetBox.siblings('.mentions-suggestions').children('div').first();
|
||||
}
|
||||
|
||||
var username = selectedSuggestion.children('span').html();
|
||||
var name = selectedSuggestion.children('strong').html();
|
||||
|
||||
// if this is a group, we remember its id, the user might be member of multiple groups with the same username
|
||||
if(selectedSuggestion.hasClass('group-suggestion')) {
|
||||
var groupId = selectedSuggestion.data('group-id');
|
||||
if(queetBox.siblings('.post-to-group[data-group-id="' + groupId + '"]').length < 1) {
|
||||
if(queetBox.siblings('.post-to-group').length>0) {
|
||||
var addAfter = queetBox.siblings('.post-to-group').last();
|
||||
}
|
||||
else {
|
||||
var addAfter = queetBox;
|
||||
}
|
||||
addAfter.after('<div class="post-to-group" data-group-username="' + username + '" data-group-id="' + groupId + '">' + name + '</div>');
|
||||
}
|
||||
}
|
||||
|
||||
// replace the halfwritten username with the one we want
|
||||
|
@ -2428,7 +2487,18 @@ function useSelectedMention(queetBox){
|
|||
queetBox.trigger('input'); // avoid some flickering
|
||||
}
|
||||
|
||||
// check for mentions
|
||||
// check for removed group mentions
|
||||
$('body').on('keyup', 'div.queet-box-syntax', function(e) {
|
||||
var groupMentions = $(this).siblings('.post-to-group');
|
||||
var queetBoxContent = $(this).text();
|
||||
$.each(groupMentions,function(){
|
||||
if(queetBoxContent.indexOf('!' + $(this).data('group-username')) == -1) {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// check for user mentions
|
||||
window.lastMention = new Object();
|
||||
$('body').on('keyup', 'div.queet-box-syntax', function(e) {
|
||||
|
||||
|
@ -2455,7 +2525,7 @@ $('body').on('keyup', 'div.queet-box-syntax', function(e) {
|
|||
}
|
||||
if((contents.lastIndexOf('@')+match[0].length) == cursorPos) {
|
||||
|
||||
queetBox.siblings('.mentions-suggestions').empty();
|
||||
queetBox.siblings('.mentions-suggestions').children('.user-suggestion').remove();
|
||||
queetBox.siblings('.mentions-suggestions').css('top',(queetBox.height()+20) + 'px');
|
||||
var term = match[0].substring(match[0].lastIndexOf('@')+1, match[0].length).toLowerCase();
|
||||
window.lastMention.mentionPos = mentionPos;
|
||||
|
@ -2487,17 +2557,90 @@ $('body').on('keyup', 'div.queet-box-syntax', function(e) {
|
|||
if(suggestionsUsernameCount[this.username]>1 && this.url !== false) {
|
||||
serverHtml = '@' + this.url;
|
||||
}
|
||||
queetBox.siblings('.mentions-suggestions').append('<div title="@' + this.username + serverHtml + '"><img height="24" width="24" src="' + this.avatar + '" /><strong>' + this.name + '</strong> @<span>' + this.username + serverHtml + '</span></div>')
|
||||
queetBox.siblings('.mentions-suggestions').append('<div class="user-suggestion" title="@' + this.username + serverHtml + '"><img height="24" width="24" src="' + this.avatar + '" /><strong>' + this.name + '</strong> @<span>' + this.username + serverHtml + '</span></div>')
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
queetBox.siblings('.mentions-suggestions').empty();
|
||||
queetBox.siblings('.mentions-suggestions').children('.user-suggestion').remove();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
queetBox.siblings('.mentions-suggestions').empty();
|
||||
queetBox.siblings('.mentions-suggestions').children('.user-suggestion').remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// check for group mentions
|
||||
$('body').on('keyup', 'div.queet-box-syntax', function(e) {
|
||||
|
||||
var queetBox = $(this);
|
||||
var cursorPosArray = getSelectionInElement(queetBox[0]);
|
||||
var cursorPos = cursorPosArray[0];
|
||||
|
||||
// add space before linebreaks (to separate mentions in beginning of new lines when .text():ing later)
|
||||
if(e.keyCode == '13') {
|
||||
e.preventDefault();
|
||||
var range = createRangeFromCharacterIndices(queetBox[0], cursorPos, cursorPos);
|
||||
range.insertNode(document.createTextNode(" \n"));
|
||||
}
|
||||
else if(e.keyCode != '40' && e.keyCode != '38' && e.keyCode != '13' && e.keyCode != '9') {
|
||||
var contents = queetBox.text().substring(0,cursorPos);
|
||||
var mentionPos = contents.lastIndexOf('!');
|
||||
var check_contents = contents.substring(mentionPos - 1, cursorPos);
|
||||
var regex = /(^|\s|\.|\n)(!)[a-zA-Z0-9]+/;
|
||||
var match = check_contents.match(regex);
|
||||
if (contents.indexOf('!') >= 0 && match) {
|
||||
|
||||
if(contents.lastIndexOf('!') > 1) {
|
||||
match[0] = match[0].substring(1,match[0].length);
|
||||
}
|
||||
if((contents.lastIndexOf('!')+match[0].length) == cursorPos) {
|
||||
|
||||
queetBox.siblings('.mentions-suggestions').children('.group-suggestion').remove();
|
||||
queetBox.siblings('.mentions-suggestions').css('top',(queetBox.height()+20) + 'px');
|
||||
var term = match[0].substring(match[0].lastIndexOf('!')+1, match[0].length).toLowerCase();
|
||||
window.lastMention.mentionPos = mentionPos;
|
||||
window.lastMention.cursorPos = cursorPos;
|
||||
|
||||
|
||||
// see if any group we're member of matches
|
||||
var suggestionsToShow = [];
|
||||
var suggestionsUsernameCount = {};
|
||||
$.each(window.groupMemberships,function(){
|
||||
var userregex = new RegExp(term);
|
||||
if(this.username.toLowerCase().match(userregex) || this.name.toLowerCase().match(userregex)) {
|
||||
suggestionsToShow.push({id:this.id, avatar:this.avatar, name:this.name, username:this.username,url:this.url});
|
||||
|
||||
// count the usernames to see if we need to show the server for any of them
|
||||
if(typeof suggestionsUsernameCount[this.username] != 'undefined') {
|
||||
suggestionsUsernameCount[this.username] = suggestionsUsernameCount[this.username] + 1;
|
||||
}
|
||||
else {
|
||||
suggestionsUsernameCount[this.username] = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// show matches
|
||||
$.each(suggestionsToShow,function(){
|
||||
var serverHtml = '';
|
||||
if(suggestionsUsernameCount[this.username]>1 && this.url !== false) {
|
||||
serverHtml = this.url + '/group/';
|
||||
}
|
||||
queetBox.siblings('.mentions-suggestions').append('<div class="group-suggestion" title="' + serverHtml + this.username + '" data-group-id="' + this.id + '"><img height="24" width="24" src="' + this.avatar + '" /><strong>' + this.name + '</strong> !<span>' + this.username + '</span></div>')
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
queetBox.siblings('.mentions-suggestions').children('.group-suggestion').remove();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
queetBox.siblings('.mentions-suggestions').children('.group-suggestion').remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user