Merge branch '0.7.x' of git@gitorious.org:laconica/dev into 0.7.x

This commit is contained in:
Zach Copley 2009-04-03 13:24:01 -07:00
commit 590cc0c9a4
62 changed files with 984 additions and 543 deletions

24
README
View File

@ -925,6 +925,16 @@ dupelimit: Time in which it's not OK for the same person to post the
same notice; default = 60 seconds.
logo: URL of an image file to use as the logo for the site. Overrides
the logo in the theme, if any.
ssl: Whether to use SSL and https:// URLs for some or all pages.
Possible values are 'always' (use it for all pages), 'never'
(don't use it for any pages), or 'sometimes' (use it for
sensitive pages that include passwords like login and registration,
but not for regular pages). Default to 'never'.
sslserver: use an alternate server name for SSL URLs, like
'secure.example.org'. You should be careful to set cookie
parameters correctly so that both the SSL server and the
"normal" server can access the session cookie and
preferably other cookies as well.
db
--
@ -1169,6 +1179,20 @@ banned: an array of usernames and/or profile IDs of 'banned' profiles.
not be accepted at all. (Compare with blacklisted users above,
whose posts just won't show up in the public stream.)
newuser
-------
Options with new users.
default: nickname of a user account to automatically subscribe new
users to. Typically this would be system account for e.g.
service updates or announcements. Users are able to unsub
if they want. Default is null; no auto subscribe.
welcome: nickname of a user account that sends welcome messages to new
users. Can be the same as 'subscribe' account, although on
busy servers it may be a good idea to keep that one just for
'urgent' messages. Default is null; no message.
Troubleshooting
===============

View File

@ -93,7 +93,8 @@ class BlockAction extends Action
if ($this->arg('no')) {
$cur = common_current_user();
$other = Profile::staticGet('id', $this->arg('blockto'));
common_redirect(common_local_url('showstream', array('nickname' => $other->nickname)));
common_redirect(common_local_url('showstream', array('nickname' => $other->nickname)),
303);
} elseif ($this->arg('yes')) {
$this->blockProfile();
} elseif ($this->arg('blockto')) {
@ -102,7 +103,6 @@ class BlockAction extends Action
}
}
function showContent() {
$this->areYouSureForm();
}
@ -110,7 +110,7 @@ class BlockAction extends Action
function title() {
return _('Block user');
}
function showNoticeForm() {
// nop
}
@ -178,10 +178,11 @@ class BlockAction extends Action
}
if ($action) {
common_redirect(common_local_url($action, $args));
common_redirect(common_local_url($action, $args), 303);
} else {
common_redirect(common_local_url('subscriptions',
array('nickname' => $cur->nickname)));
array('nickname' => $cur->nickname)),
303);
}
}
}

View File

@ -141,6 +141,6 @@ class DeletenoticeAction extends DeleteAction
$url = common_local_url('public');
}
common_redirect($url);
common_redirect($url, 303);
}
}

View File

@ -49,7 +49,7 @@ class DisfavorAction extends Action
{
/**
* Class handler.
*
*
* @param array $args query arguments
*
* @return void
@ -100,7 +100,8 @@ class DisfavorAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('showfavorites',
array('nickname' => $user->nickname)));
array('nickname' => $user->nickname)),
303);
}
}
}

View File

@ -166,7 +166,6 @@ class EditgroupAction extends Action
return;
}
$nickname = common_canonical_nickname($this->trimmed('nickname'));
$fullname = $this->trimmed('fullname');
$homepage = $this->trimmed('homepage');
@ -221,7 +220,7 @@ class EditgroupAction extends Action
if ($this->group->nickname != $orig->nickname) {
common_redirect(common_local_url('editgroup',
array('nickname' => $nickname)),
307);
303);
} else {
$this->showForm(_('Options saved.'));
}

View File

@ -52,7 +52,7 @@ class FavorAction extends Action
{
/**
* Class handler.
*
*
* @param array $args query arguments
*
* @return void
@ -100,13 +100,14 @@ class FavorAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('showfavorites',
array('nickname' => $user->nickname)));
array('nickname' => $user->nickname)),
303);
}
}
/**
* Notifies a user when his notice is favorited.
*
*
* @param class $notice favorited notice
* @param class $user user declaring a favorite
*

View File

@ -139,7 +139,7 @@ class FinishaddopenidAction extends Action
oid_set_last($display);
common_redirect(common_local_url('openidsettings'));
common_redirect(common_local_url('openidsettings'), 303);
}
}

View File

@ -271,7 +271,8 @@ class FinishopenidloginAction extends Action
common_rememberme($user);
}
unset($_SESSION['openid_rememberme']);
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)));
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
303);
}
function connectUser()
@ -324,7 +325,7 @@ class FinishopenidloginAction extends Action
array('nickname' =>
$nickname));
}
common_redirect($url);
common_redirect($url, 303);
}
function bestNewNickname($display, $sreg)

View File

@ -230,7 +230,8 @@ class FinishremotesubscribeAction extends Action
# show up close to the top of the page
common_redirect(common_local_url('subscribers', array('nickname' =>
$user->nickname)));
$user->nickname)),
303);
}
function add_avatar($profile, $url)

View File

@ -33,7 +33,24 @@ class FoafAction extends Action
function prepare($args)
{
parent::prepare($args);
$this->nickname = $this->trimmed('nickname');
$nickname_arg = $this->arg('nickname');
if (empty($nickname_arg)) {
$this->clientError(_('No such user.'), 404);
return false;
}
$this->nickname = common_canonical_nickname($nickname_arg);
// Permanent redirect on non-canonical nickname
if ($nickname_arg != $this->nickname) {
common_redirect(common_local_url('foaf',
array('nickname' => $this->nickname)),
301);
return false;
}
$this->user = User::staticGet('nickname', $this->nickname);
@ -122,20 +139,30 @@ class FoafAction extends Action
if ($sub->find()) {
while ($sub->fetch()) {
if ($sub->token) {
if (!empty($sub->token)) {
$other = Remote_profile::staticGet('id', $sub->subscribed);
} else {
$other = User::staticGet('id', $sub->subscribed);
}
if (!$other) {
if (empty($other)) {
common_debug('Got a bad subscription: '.print_r($sub,true));
continue;
}
$this->element('knows', array('rdf:resource' => $other->uri));
$person[$other->uri] = array(LISTENEE, $other);
$person[$other->uri] = array(LISTENEE,
$other->id,
$other->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile');
$other->free();
$other = null;
unset($other);
}
}
$sub->free();
$sub = null;
unset($sub);
// Get people who subscribe to user
$sub = new Subscription();
@ -156,25 +183,36 @@ class FoafAction extends Action
if (array_key_exists($other->uri, $person)) {
$person[$other->uri][0] = BOTH;
} else {
$person[$other->uri] = array(LISTENER, $other);
$person[$other->uri] = array(LISTENER,
$other->id,
$other->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile');
}
$other->free();
$other = null;
unset($other);
}
}
$sub->free();
$sub = null;
unset($sub);
$this->elementEnd('Person');
foreach ($person as $uri => $p) {
$foaf_url = null;
if ($p[1] instanceof User) {
$foaf_url = common_local_url('foaf', array('nickname' => $p[1]->nickname));
list($type, $id, $nickname, $cls) = $p;
if ($cls == 'User') {
$foaf_url = common_local_url('foaf', array('nickname' => $nickname));
}
$this->profile = Profile::staticGet($p[1]->id);
$profile = Profile::staticGet($id);
$this->elementStart('Person', array('rdf:about' => $uri));
if ($p[0] == LISTENER || $p[0] == BOTH) {
if ($type == LISTENER || $type == BOTH) {
$this->element('knows', array('rdf:resource' => $this->user->uri));
}
$this->showMicrobloggingAccount($this->profile, ($p[1] instanceof User) ?
common_root_url() : null);
$this->showMicrobloggingAccount($profile, ($cls == 'User') ?
common_root_url() : null);
if ($foaf_url) {
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
}
@ -182,6 +220,9 @@ class FoafAction extends Action
if ($foaf_url) {
$this->showPpd($foaf_url, $uri);
}
$profile->free();
$profile = null;
unset($profile);
}
$this->elementEnd('rdf:RDF');

View File

@ -143,7 +143,8 @@ class JoingroupAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('groupmembers', array('nickname' =>
$this->group->nickname)));
$this->group->nickname)),
303);
}
}
}

View File

@ -147,7 +147,8 @@ class LeavegroupAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('groupmembers', array('nickname' =>
$this->group->nickname)));
$this->group->nickname)),
303);
}
}
}

View File

@ -138,7 +138,7 @@ class LoginAction extends Action
$nickname));
}
common_redirect($url);
common_redirect($url, 303);
}
/**

View File

@ -46,10 +46,10 @@ require_once INSTALLDIR.'/lib/openid.php';
*/
class LogoutAction extends Action
{
/**
* This is read only.
*
*
* @return boolean true
*/
function isReadOnly()
@ -59,7 +59,7 @@ class LogoutAction extends Action
/**
* Class handler.
*
*
* @param array $args array of arguments
*
* @return nothing
@ -73,7 +73,7 @@ class LogoutAction extends Action
common_set_user(null);
common_real_login(false); // not logged in
common_forgetme(); // don't log back in!
common_redirect(common_local_url('public'));
common_redirect(common_local_url('public'), 303);
}
}
}

View File

@ -193,7 +193,7 @@ class NewgroupAction extends Action
$group->query('COMMIT');
common_redirect($group->homeUrl(), 307);
common_redirect($group->homeUrl(), 303);
}
function nicknameExists($nickname)

View File

@ -122,9 +122,10 @@ class NoticesearchAction extends SearchAction
$cnt = $nl->show();
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'noticesearch', array('q' => $q));
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
$page, 'noticesearch', array('q' => $q));
}
function isReadOnly()
{
return true;

View File

@ -50,7 +50,7 @@ class NudgeAction extends Action
{
/**
* Class handler.
*
*
* @param array $args array of arguments
*
* @return nothing
@ -75,7 +75,7 @@ class NudgeAction extends Action
// CSRF protection
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token. Try again, please.'));
return;
@ -100,7 +100,8 @@ class NudgeAction extends Action
} else {
// display a confirmation to the user
common_redirect(common_local_url('showstream',
array('nickname' => $other->nickname)));
array('nickname' => $other->nickname)),
303);
}
}

View File

@ -166,6 +166,34 @@ class PublicAction extends Action
$nav->show();
}
function showPageNotice()
{
$notice = Notice::publicStream(0, 1);
if (!$notice) {
$this->serverError(_('Could not retrieve public stream.'));
return;
}
// no notices in the public stream, let's get out of here
if ($notice->count()) {
return;
}
$message = _('This is the public timeline for %%site.name%% but noone has posted anything yet.') . ' ';
if (common_logged_in()) {
$message .= _('Be the first to post!');
}
else {
$message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
}
$this->elementStart('div', 'blankfiller');
$this->raw(common_markup_to_html($message));
$this->elementEnd('div');
}
/**
* Fill the content area
*

View File

@ -62,6 +62,24 @@ class PublictagcloudAction extends Action
$this->element('p', 'instructions',
sprintf(_('These are most popular recent tags on %s '),
common_config('site', 'name')));
$tags = new Notice_tag();
if ($tags->count()) {
return;
}
$message = _('Noone has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' ';
if (common_logged_in()) {
$message .= _('Be the first to post one!');
}
else {
$message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
}
$this->elementStart('div', 'blankfiller');
$this->raw(common_markup_to_html($message));
$this->elementEnd('div');
}
function showLocalNav()

View File

@ -181,13 +181,21 @@ class RecoverpasswordAction extends Action
function showRecoverForm()
{
$this->elementStart('form', array('method' => 'post',
'id' => 'recoverpassword',
'id' => 'form_password_recover',
'class' => 'form_settings',
'action' => common_local_url('recoverpassword')));
$this->elementStart('fieldset');
$this->element('legend', null, _('Password recover'));
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->input('nicknameoremail', _('Nickname or email'),
$this->trimmed('nicknameoremail'),
_('Your nickname on this server, ' .
'or your registered email address.'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->submit('recover', _('Recover'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
@ -213,14 +221,24 @@ class RecoverpasswordAction extends Action
function showResetForm()
{
$this->elementStart('form', array('method' => 'post',
'id' => 'recoverpassword',
'id' => 'form_password_change',
'class' => 'form_settings',
'action' => common_local_url('recoverpassword')));
$this->elementStart('fieldset');
$this->element('legend', null, _('Password change'));
$this->hidden('token', common_session_token());
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->password('newpassword', _('New password'),
_('6 or more characters, and don\'t forget it!'));
$this->elementEnd('li');
$this->elementStart('li');
$this->password('confirm', _('Confirm'),
_('Same as password above'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->submit('reset', _('Reset'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}

View File

@ -97,9 +97,9 @@ class RemotesubscribeAction extends Action
'class' => 'form_settings',
'action' => common_local_url('remotesubscribe')));
$this->elementStart('fieldset');
$this->element('legend', 'Subscribe to a remote user');
$this->element('legend', _('Subscribe to a remote user'));
$this->hidden('token', common_session_token());
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->input('nickname', _('User nickname'), $this->nickname,
@ -407,7 +407,7 @@ class RemotesubscribeAction extends Action
# Redirect to authorization service
common_redirect($req->to_url());
common_redirect($req->to_url(), 303);
return;
}
}

View File

@ -73,11 +73,17 @@ class ShowgroupAction extends Action
function title()
{
if (!empty($this->group->fullname)) {
$base = $this->group->fullname . ' (' . $this->group->nickname . ')';
} else {
$base = $this->group->nickname;
}
if ($this->page == 1) {
return sprintf(_("%s group"), $this->group->nickname);
return sprintf(_("%s group"), $base);
} else {
return sprintf(_("%s group, page %d"),
$this->group->nickname,
$base,
$this->page);
}
}

View File

@ -67,11 +67,17 @@ class ShowstreamAction extends Action
function title()
{
if (!empty($this->profile->fullname)) {
$base = $this->profile->fullname . ' (' . $this->user->nickname . ') ';
} else {
$base = $this->user->nickname;
}
if ($this->page == 1) {
return $this->user->nickname;
return $base;
} else {
return sprintf(_("%s, page %d"),
$this->user->nickname,
$base,
$this->page);
}
}
@ -140,16 +146,6 @@ class ShowstreamAction extends Action
$nav->show();
}
function showPageTitle()
{
$user =& common_current_user();
if ($user && ($user->id == $this->profile->id)) {
$this->element('h1', NULL, _("Your profile"));
} else {
$this->element('h1', NULL, sprintf(_('%s\'s profile'), $this->profile->nickname));
}
}
function showPageNoticeBlock()
{
return;

View File

@ -488,7 +488,8 @@ class SmssettingsAction extends ConnectSettingsAction
}
common_redirect(common_local_url('confirmaddress',
array('code' => $code)));
array('code' => $code)),
303);
}
/**

View File

@ -85,7 +85,8 @@ class SubeditAction extends Action
}
common_redirect(common_local_url('subscriptions',
array('nickname' => $cur->nickname)));
array('nickname' => $cur->nickname)),
303);
}
}
}

View File

@ -75,7 +75,8 @@ class SubscribeAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('subscriptions', array('nickname' =>
$user->nickname)));
$user->nickname)),
303);
}
}
}

View File

@ -45,7 +45,7 @@ class SupAction extends Action
function availablePeriods()
{
static $periods = array(86400, 43200, 21600, 7200,
3600, 1800, 600, 300, 120,
3600, 1800, 600, 300, 120,
60, 30, 15);
$available = array();
foreach ($periods as $period) {

View File

@ -33,7 +33,9 @@ class TagAction extends Action
}
if ($this->tag != $taginput) {
common_redirect(common_local_url('tag', array('tag' => $this->tag)));
common_redirect(common_local_url('tag', array('tag' => $this->tag)),
301);
return false;
}
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

View File

@ -221,7 +221,8 @@ class TagotherAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url($action, array('nickname' =>
$user->nickname)));
$user->nickname)),
303);
}
}

View File

@ -116,10 +116,11 @@ class UnblockAction extends Action
}
}
if ($action) {
common_redirect(common_local_url($action, $args));
common_redirect(common_local_url($action, $args), 303);
} else {
common_redirect(common_local_url('subscriptions',
array('nickname' => $cur->nickname)));
array('nickname' => $cur->nickname)),
303);
}
}
}

View File

@ -77,7 +77,8 @@ class UnsubscribeAction extends Action
$this->elementEnd('html');
} else {
common_redirect(common_local_url('subscriptions', array('nickname' =>
$user->nickname)));
$user->nickname)),
303);
}
}
}

View File

@ -799,4 +799,98 @@ class Notice extends Memcached_DataObject
}
}
}
function asAtomEntry($namespace=false, $source=false)
{
$profile = $this->getProfile();
$xs = new XMLStringer(true);
if ($namespace) {
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0');
} else {
$attrs = array();
}
$xs->elementStart('entry', $attrs);
if ($source) {
$xs->elementStart('source');
$xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
$xs->element('link', array('href' => $profile->profileurl));
$user = User::staticGet('id', $profile->id);
if (!empty($user)) {
$atom_feed = common_local_url('api',
array('apiaction' => 'statuses',
'method' => 'user_timeline',
'argument' => $profile->nickname.'.atom'));
$xs->element('link', array('rel' => 'self',
'type' => 'application/atom+xml',
'href' => $profile->profileurl));
$xs->element('link', array('rel' => 'license',
'href' => common_config('license', 'url')));
}
$xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
}
$xs->elementStart('author');
$xs->element('name', null, $profile->nickname);
$xs->element('uri', null, $profile->profileurl);
$xs->elementEnd('author');
if ($source) {
$xs->elementEnd('source');
}
$xs->element('title', null, $this->content);
$xs->element('summary', null, $this->content);
$xs->element('link', array('rel' => 'alternate',
'href' => $this->bestUrl()));
$xs->element('id', null, $this->uri);
$xs->element('published', null, common_date_w3dtf($this->created));
$xs->element('updated', null, common_date_w3dtf($this->modified));
if ($this->reply_to) {
$reply_notice = Notice::staticGet('id', $this->reply_to);
if (!empty($reply_notice)) {
$xs->element('link', array('rel' => 'related',
'href' => $reply_notice->bestUrl()));
$xs->element('thr:in-reply-to',
array('ref' => $reply_notice->uri,
'href' => $reply_notice->bestUrl()));
}
}
$xs->element('content', array('type' => 'html'), $this->rendered);
$tag = new Notice_tag();
$tag->notice_id = $this->id;
if ($tag->find()) {
while ($tag->fetch()) {
$xs->element('category', array('term' => $tag->tag));
}
}
$tag->free();
$xs->elementEnd('entry');
return $xs->getString();
}
function bestUrl()
{
if (!empty($this->url)) {
return $this->url;
} else if (!empty($this->uri) && preg_match('/^https?:/', $this->uri)) {
return $this->uri;
} else {
return common_local_url('shownotice',
array('notice' => $this->id));
}
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, Controlez-Vous, Inc.
* Copyright (C) 2008, 2009, Control Yourself, Inc.
*
* 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
@ -17,11 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) { exit(1); }
if (!defined('LACONICA')) {
exit(1);
}
/**
* Table Definition for user
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
require_once 'Validate.php';
@ -79,13 +82,13 @@ class User extends Memcached_DataObject
function isSubscribed($other)
{
assert(!is_null($other));
# XXX: cache results of this query
// XXX: cache results of this query
$sub = Subscription::pkeyGet(array('subscriber' => $this->id,
'subscribed' => $other->id));
return (is_null($sub)) ? false : true;
}
# 'update' won't write key columns, so we have to do it ourselves.
// 'update' won't write key columns, so we have to do it ourselves.
function updateKeys(&$orig)
{
@ -96,7 +99,7 @@ class User extends Memcached_DataObject
}
}
if (count($parts) == 0) {
# No changes
// No changes
return true;
}
$toupdate = implode(', ', $parts);
@ -117,7 +120,7 @@ class User extends Memcached_DataObject
function allowed_nickname($nickname)
{
# XXX: should already be validated for size, content, etc.
// XXX: should already be validated for size, content, etc.
static $blacklist = array('rss', 'xrds', 'doc', 'main',
'settings', 'notice', 'user',
'search', 'avatar', 'tag', 'tags',
@ -147,7 +150,7 @@ class User extends Memcached_DataObject
$sub->subscriber = $this->id;
$sub->subscribed = $other->id;
$sub->created = common_sql_now(); # current time
$sub->created = common_sql_now(); // current time
if (!$sub->insert()) {
return false;
@ -173,7 +176,7 @@ class User extends Memcached_DataObject
static function register($fields) {
# MAGICALLY put fields into current scope
// MAGICALLY put fields into current scope
extract($fields);
@ -211,11 +214,11 @@ class User extends Memcached_DataObject
$user->id = $id;
$user->nickname = $nickname;
if (!empty($password)) { # may not have a password for OpenID users
if (!empty($password)) { // may not have a password for OpenID users
$user->password = common_munge_password($password, $id);
}
# Users who respond to invite email have proven their ownership of that address
// Users who respond to invite email have proven their ownership of that address
if (!empty($code)) {
$invite = Invitation::staticGet($code);
@ -240,7 +243,7 @@ class User extends Memcached_DataObject
return false;
}
# Everyone is subscribed to themself
// Everyone is subscribed to themself
$subscription = new Subscription();
$subscription->subscriber = $user->id;
@ -273,16 +276,58 @@ class User extends Memcached_DataObject
$user->emailChanged();
}
// Default system subscription
$defnick = common_config('newuser', 'default');
if (!empty($defnick)) {
$defuser = User::staticGet('nickname', $defnick);
if (empty($defuser)) {
common_log(LOG_WARNING, sprintf("Default user %s does not exist.", $defnick),
__FILE__);
} else {
$defsub = new Subscription();
$defsub->subscriber = $user->id;
$defsub->subscribed = $defuser->id;
$defsub->created = $user->created;
$result = $defsub->insert();
if (!$result) {
common_log_db_error($defsub, 'INSERT', __FILE__);
return false;
}
}
}
$profile->query('COMMIT');
if ($email && !$user->email) {
mail_confirm_address($user, $confirm->code, $profile->nickname, $email);
}
// Welcome message
$welcome = common_config('newuser', 'welcome');
if (!empty($welcome)) {
$welcomeuser = User::staticGet('nickname', $welcome);
if (empty($welcomeuser)) {
common_log(LOG_WARNING, sprintf("Welcome user %s does not exist.", $defnick),
__FILE__);
} else {
$notice = Notice::saveNew($welcomeuser->id,
sprintf(_('Welcome to %1$s, @%2$s!'),
common_config('site', 'name'),
$user->nickname),
'system');
}
}
return $user;
}
# Things we do when the email changes
// Things we do when the email changes
function emailChanged()
{
@ -303,46 +348,46 @@ class User extends Memcached_DataObject
{
$cache = common_memcache();
# XXX: Kind of a hack.
// XXX: Kind of a hack.
if ($cache) {
# This is the stream of favorite notices, in rev chron
# order. This forces it into cache.
// This is the stream of favorite notices, in rev chron
// order. This forces it into cache.
$faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
$cnt = 0;
while ($faves->fetch()) {
if ($faves->id < $notice->id) {
# If we passed it, it's not a fave
// If we passed it, it's not a fave
return false;
} else if ($faves->id == $notice->id) {
# If it matches a cached notice, then it's a fave
// If it matches a cached notice, then it's a fave
return true;
}
$cnt++;
}
# If we're not past the end of the cache window,
# then the cache has all available faves, so this one
# is not a fave.
// If we're not past the end of the cache window,
// then the cache has all available faves, so this one
// is not a fave.
if ($cnt < NOTICE_CACHE_WINDOW) {
return false;
}
# Otherwise, cache doesn't have all faves;
# fall through to the default
// Otherwise, cache doesn't have all faves;
// fall through to the default
}
$fave = Fave::pkeyGet(array('user_id' => $this->id,
'notice_id' => $notice->id));
return ((is_null($fave)) ? false : true);
}
function mutuallySubscribed($other)
{
return $this->isSubscribed($other) &&
$other->isSubscribed($this);
}
function mutuallySubscribedUsers()
{
# 3-way join; probably should get cached
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
function mutuallySubscribedUsers()
{
// 3-way join; probably should get cached
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = "SELECT $UT.* " .
"FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
"JOIN subscription sub2 ON $UT.id = sub2.subscriber " .
@ -365,8 +410,8 @@ class User extends Memcached_DataObject
$offset, $limit, $since_id, $before_id, null, $since);
}
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
$profile = $this->getProfile();
if (!$profile) {
return null;
@ -375,8 +420,8 @@ class User extends Memcached_DataObject
}
}
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE)
{
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE)
{
$qry =
'SELECT notice.* ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
@ -386,12 +431,12 @@ class User extends Memcached_DataObject
$offset, $limit);
}
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
$enabled = common_config('inboxes', 'enabled');
# Complicated code, depending on whether we support inboxes yet
# XXX: make this go away when inboxes become mandatory
// Complicated code, depending on whether we support inboxes yet
// XXX: make this go away when inboxes become mandatory
if ($enabled === false ||
($enabled == 'transitional' && $this->inboxed == 0)) {
@ -401,13 +446,13 @@ class User extends Memcached_DataObject
'WHERE subscription.subscriber = %d ';
$order = null;
} else if ($enabled === true ||
($enabled == 'transitional' && $this->inboxed == 1)) {
($enabled == 'transitional' && $this->inboxed == 1)) {
$qry =
'SELECT notice.* ' .
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
'WHERE notice_inbox.user_id = %d ';
# NOTE: we override ORDER
// NOTE: we override ORDER
$order = null;
}
return Notice::getStream(sprintf($qry, $this->id),
@ -416,35 +461,34 @@ class User extends Memcached_DataObject
$order, $since);
}
function blowFavesCache()
{
function blowFavesCache()
{
$cache = common_memcache();
if ($cache) {
# Faves don't happen chronologically, so we need to blow
# ;last cache, too
// Faves don't happen chronologically, so we need to blow
// ;last cache, too
$cache->delete(common_cache_key('user:faves:'.$this->id));
$cache->delete(common_cache_key('user:faves:'.$this->id).';last');
}
}
function getSelfTags()
{
function getSelfTags()
{
return Profile_tag::getTags($this->id, $this->id);
}
function setSelfTags($newtags)
{
function setSelfTags($newtags)
{
return Profile_tag::setTags($this->id, $this->id, $newtags);
}
function block($other)
{
# Add a new block record
// Add a new block record
$block = new Profile_block();
# Begin a transaction
// Begin a transaction
$block->query('BEGIN');
@ -458,7 +502,7 @@ class User extends Memcached_DataObject
return false;
}
# Cancel their subscription, if it exists
// Cancel their subscription, if it exists
$sub = Subscription::pkeyGet(array('subscriber' => $other->id,
'subscribed' => $this->id));
@ -478,8 +522,7 @@ class User extends Memcached_DataObject
function unblock($other)
{
# Get the block record
// Get the block record
$block = Profile_block::get($this->id, $other->id);

View File

@ -174,3 +174,13 @@ $config['sphinx']['port'] = 3312;
#http://taguri.org/ Examples:
#$config['integration']['taguri'] = 'example.net,2008';
#$config['integration']['taguri'] = 'admin@example.net,2009-03-09'
#Don't use SSL
#$config['site']['ssl'] = 'never';
#Use SSL only for sensitive pages (like login, password change)
#$config['site']['ssl'] = 'sometimes';
#Use SSL for all pages
#$config['site']['ssl'] = 'always';
#Use a different hostname for SSL-encrypted pages
#$config['site']['sslserver'] = 'secure.example.org';

View File

@ -13,7 +13,7 @@ create table profile (
index profile_nickname_idx (nickname),
FULLTEXT(nickname, fullname, location, bio, homepage)
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_bin;
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
create table avatar (
profile_id integer not null comment 'foreign key to profile table' references profile (id),
@ -73,7 +73,7 @@ create table user (
modified timestamp comment 'date this record was modified',
index user_smsemail_idx (smsemail)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
/* remote people */
@ -103,7 +103,6 @@ create table subscription (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table notice (
id integer auto_increment primary key comment 'unique identifier',
profile_id integer not null comment 'who made the update' references profile (id),
uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
@ -119,7 +118,7 @@ create table notice (
index notice_profile_id_idx (profile_id),
index notice_created_idx (created),
FULLTEXT(content)
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_bin;
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
create table notice_source (
code varchar(32) primary key not null comment 'source code',
@ -130,7 +129,6 @@ create table notice_source (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table reply (
notice_id integer not null comment 'notice that is the reply' references notice (id),
profile_id integer not null comment 'profile replied to' references profile (id),
modified timestamp not null comment 'date this record was modified',
@ -144,7 +142,6 @@ create table reply (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table fave (
notice_id integer not null comment 'notice that is the favorite' references notice (id),
user_id integer not null comment 'user who likes this notice' references user (id),
modified timestamp not null comment 'date this record was modified',
@ -321,7 +318,6 @@ create table invitation (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table message (
id integer auto_increment primary key comment 'unique identifier',
uri varchar(255) unique key comment 'universally unique identifier',
from_profile integer not null comment 'who the message is from' references profile (id),
@ -336,10 +332,9 @@ create table message (
index message_from_idx (from_profile),
index message_to_idx (to_profile),
index message_created_idx (created)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table notice_inbox (
user_id integer not null comment 'user receiving the message' references user (id),
notice_id integer not null comment 'notice received' references notice (id),
created datetime not null comment 'date the notice was created',
@ -362,7 +357,6 @@ create table profile_tag (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table profile_block (
blocker integer not null comment 'user making the block' references user (id),
blocked integer not null comment 'profile that is blocked' references profile (id),
modified timestamp comment 'date of blocking',
@ -372,7 +366,6 @@ create table profile_block (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table user_group (
id integer auto_increment primary key comment 'unique identifier',
nickname varchar(64) unique key comment 'nickname for addressing',
@ -391,10 +384,9 @@ create table user_group (
index user_group_nickname_idx (nickname)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table group_member (
group_id integer not null comment 'foreign key to user_group' references user_group (id),
profile_id integer not null comment 'foreign key to profile table' references profile (id),
is_admin boolean default false comment 'is this user an admin?',
@ -409,7 +401,6 @@ create table group_member (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table related_group (
group_id integer not null comment 'foreign key to user_group' references user_group (id),
related_group_id integer not null comment 'foreign key to user_group' references user_group (id),

View File

@ -19,6 +19,7 @@ VALUES
('identichat','identichat','http://identichat.prosody.im/', now()),
('identitwitch','IdentiTwitch','http://richfish.org/identitwitch/', now()),
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
('moconica','Moconica','http://moconica.com/', now()),
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
@ -44,4 +45,4 @@ VALUES
('twitux','Twitux','http://live.gnome.org/DanielMorales/Twitux', now()),
('twitvim','TwitVim','http://vim.sourceforge.net/scripts/script.php?script_id=2204', now()),
('urfastr','urfastr','http://urfastr.net/', now()),
('adium', 'Adium', 'http://www.adiumx.com/', now()));
('adium', 'Adium', 'http://www.adiumx.com/', now());

499
js/jquery.js vendored
View File

@ -1,13 +1,13 @@
/*!
* jQuery JavaScript Library v1.3.1
* jQuery JavaScript Library v1.3.2
* http://jquery.com/
*
* Copyright (c) 2009 John Resig
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
* Date: 2009-01-21 20:42:16 -0500 (Wed, 21 Jan 2009)
* Revision: 6158
* Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
* Revision: 6246
*/
(function(){
@ -88,14 +88,16 @@ jQuery.fn = jQuery.prototype = {
this.context = selector.context;
}
return this.setArray(jQuery.makeArray(selector));
return this.setArray(jQuery.isArray( selector ) ?
selector :
jQuery.makeArray(selector));
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "1.3.1",
jquery: "1.3.2",
// The number of elements contained in the matched element set
size: function() {
@ -108,7 +110,7 @@ jQuery.fn = jQuery.prototype = {
return num === undefined ?
// Return a 'clean' array
jQuery.makeArray( this ) :
Array.prototype.slice.call( this ) :
// Return just the object
this[ num ];
@ -278,23 +280,21 @@ jQuery.fn = jQuery.prototype = {
},
// For internal use only.
// Behaves like an Array's .push method, not like a jQuery method.
// Behaves like an Array's method, not like a jQuery method.
push: [].push,
sort: [].sort,
splice: [].splice,
find: function( selector ) {
if ( this.length === 1 && !/,/.test(selector) ) {
if ( this.length === 1 ) {
var ret = this.pushStack( [], "find", selector );
ret.length = 0;
jQuery.find( selector, this[0], ret );
return ret;
} else {
var elems = jQuery.map(this, function(elem){
return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
return jQuery.find( selector, elem );
});
return this.pushStack( /[^+>] [^+>]/.test( selector ) ?
jQuery.unique( elems ) :
elems, "find", selector );
})), "find", selector );
}
},
@ -310,33 +310,37 @@ jQuery.fn = jQuery.prototype = {
// attributes in IE that are actually only stored
// as properties will not be copied (such as the
// the name attribute on an input).
var clone = this.cloneNode(true),
container = document.createElement("div");
container.appendChild(clone);
return jQuery.clean([container.innerHTML])[0];
var html = this.outerHTML;
if ( !html ) {
var div = this.ownerDocument.createElement("div");
div.appendChild( this.cloneNode(true) );
html = div.innerHTML;
}
return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
} else
return this.cloneNode(true);
});
// Need to set the expando to null on the cloned set if it exists
// removeData doesn't work here, IE removes it from the original as well
// this is primarily for IE but the data expando shouldn't be copied over in any browser
var clone = ret.find("*").andSelf().each(function(){
if ( this[ expando ] !== undefined )
this[ expando ] = null;
});
// Copy the events from the original to the clone
if ( events === true )
this.find("*").andSelf().each(function(i){
if (this.nodeType == 3)
return;
var events = jQuery.data( this, "events" );
if ( events === true ) {
var orig = this.find("*").andSelf(), i = 0;
for ( var type in events )
for ( var handler in events[ type ] )
jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
ret.find("*").andSelf().each(function(){
if ( this.nodeName !== orig[i].nodeName )
return;
var events = jQuery.data( orig[i], "events" );
for ( var type in events ) {
for ( var handler in events[ type ] ) {
jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
}
}
i++;
});
}
// Return the cloned set
return ret;
@ -355,14 +359,18 @@ jQuery.fn = jQuery.prototype = {
},
closest: function( selector ) {
var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null;
var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
closer = 0;
return this.map(function(){
var cur = this;
while ( cur && cur.ownerDocument ) {
if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) )
if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
jQuery.data(cur, "closest", closer);
return cur;
}
cur = cur.parentNode;
closer++;
}
});
},
@ -475,7 +483,7 @@ jQuery.fn = jQuery.prototype = {
html: function( value ) {
return value === undefined ?
(this[0] ?
this[0].innerHTML :
this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
null) :
this.empty().append( value );
},
@ -507,13 +515,13 @@ jQuery.fn = jQuery.prototype = {
if ( this[0] ) {
var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
first = fragment.firstChild,
extra = this.length > 1 ? fragment.cloneNode(true) : fragment;
first = fragment.firstChild;
if ( first )
for ( var i = 0, l = this.length; i < l; i++ )
callback.call( root(this[i], first), i > 0 ? extra.cloneNode(true) : fragment );
callback.call( root(this[i], first), this.length > 1 || i > 0 ?
fragment.cloneNode(true) : fragment );
if ( scripts )
jQuery.each( scripts, evalScript );
}
@ -636,9 +644,7 @@ jQuery.extend({
// Evalulates a script in a global context
globalEval: function( data ) {
data = jQuery.trim( data );
if ( data ) {
if ( data && /\S/.test(data) ) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
var head = document.getElementsByTagName("head")[0] || document.documentElement,
@ -741,26 +747,32 @@ jQuery.extend({
elem.style[ name ] = old[ name ];
},
css: function( elem, name, force ) {
css: function( elem, name, force, extra ) {
if ( name == "width" || name == "height" ) {
var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
function getWH() {
val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
var padding = 0, border = 0;
if ( extra === "border" )
return;
jQuery.each( which, function() {
padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
if ( !extra )
val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
if ( extra === "margin" )
val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
else
val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
});
val -= Math.round(padding + border);
}
if ( jQuery(elem).is(":visible") )
if ( elem.offsetWidth !== 0 )
getWH();
else
jQuery.swap( elem, props, getWH );
return Math.max(0, val);
return Math.max(0, Math.round(val));
}
return jQuery.curCSS( elem, name, force );
@ -866,7 +878,7 @@ jQuery.extend({
});
// Trim whitespace, otherwise indexOf won't work as expected
var tags = jQuery.trim( elem ).toLowerCase();
var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
var wrap =
// option or optgroup
@ -906,11 +918,12 @@ jQuery.extend({
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious <tbody>
var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
div.firstChild && div.firstChild.childNodes :
var hasBody = /<tbody/i.test(elem),
tbody = !tags.indexOf("<table") && !hasBody ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
wrap[1] == "<table>" && !hasBody ?
div.childNodes :
[];
@ -1189,13 +1202,16 @@ jQuery.each({
insertAfter: "after",
replaceAll: "replaceWith"
}, function(name, original){
jQuery.fn[ name ] = function() {
var args = arguments;
jQuery.fn[ name ] = function( selector ) {
var ret = [], insert = jQuery( selector );
return this.each(function(){
for ( var i = 0, length = args.length; i < length; i++ )
jQuery( args[ i ] )[ original ]( this );
});
for ( var i = 0, l = insert.length; i < l; i++ ) {
var elems = (i > 0 ? this.clone(true) : this).get();
jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
ret = ret.concat( elems );
}
return this.pushStack( ret, name, selector );
};
});
@ -1234,7 +1250,7 @@ jQuery.each({
empty: function() {
// Remove element nodes and prevent memory leaks
jQuery( ">*", this ).remove();
jQuery(this).children().remove();
// Remove any remaining nodes
while ( this.firstChild )
@ -1402,7 +1418,7 @@ jQuery.fn.extend({
*/
(function(){
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]+['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
done = 0,
toString = Object.prototype.toString;
@ -1507,6 +1523,19 @@ var Sizzle = function(selector, context, results, seed) {
if ( extra ) {
Sizzle( extra, context, results, seed );
if ( sortOrder ) {
hasDuplicate = false;
results.sort(sortOrder);
if ( hasDuplicate ) {
for ( var i = 1; i < results.length; i++ ) {
if ( results[i] === results[i-1] ) {
results.splice(i--, 1);
}
}
}
}
}
return results;
@ -1548,7 +1577,8 @@ Sizzle.find = function(expr, context, isXML){
};
Sizzle.filter = function(expr, set, inplace, not){
var old = expr, result = [], curLoop = set, match, anyFound;
var old = expr, result = [], curLoop = set, match, anyFound,
isXMLFilter = set && set[0] && isXML(set[0]);
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
@ -1561,7 +1591,7 @@ Sizzle.filter = function(expr, set, inplace, not){
}
if ( Expr.preFilter[ type ] ) {
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not );
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
if ( !match ) {
anyFound = found = true;
@ -1606,8 +1636,6 @@ Sizzle.filter = function(expr, set, inplace, not){
}
}
expr = expr.replace(/\s*,\s*/, "");
// Improper expression
if ( expr == old ) {
if ( anyFound == null ) {
@ -1645,26 +1673,33 @@ var Expr = Sizzle.selectors = {
}
},
relative: {
"+": function(checkSet, part){
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
var cur = elem.previousSibling;
while ( cur && cur.nodeType !== 1 ) {
cur = cur.previousSibling;
}
checkSet[i] = typeof part === "string" ?
cur || false :
cur === part;
"+": function(checkSet, part, isXML){
var isPartStr = typeof part === "string",
isTag = isPartStr && !/\W/.test(part),
isPartStrNotTag = isPartStr && !isTag;
if ( isTag && !isXML ) {
part = part.toUpperCase();
}
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
if ( (elem = checkSet[i]) ) {
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
elem || false :
elem === part;
}
}
if ( typeof part === "string" ) {
if ( isPartStrNotTag ) {
Sizzle.filter( part, checkSet, true );
}
},
">": function(checkSet, part, isXML){
if ( typeof part === "string" && !/\W/.test(part) ) {
var isPartStr = typeof part === "string";
if ( isPartStr && !/\W/.test(part) ) {
part = isXML ? part : part.toUpperCase();
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
@ -1678,19 +1713,19 @@ var Expr = Sizzle.selectors = {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
checkSet[i] = typeof part === "string" ?
checkSet[i] = isPartStr ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( typeof part === "string" ) {
if ( isPartStr ) {
Sizzle.filter( part, checkSet, true );
}
}
},
"": function(checkSet, part, isXML){
var doneName = "done" + (done++), checkFn = dirCheck;
var doneName = done++, checkFn = dirCheck;
if ( !part.match(/\W/) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
@ -1700,7 +1735,7 @@ var Expr = Sizzle.selectors = {
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
},
"~": function(checkSet, part, isXML){
var doneName = "done" + (done++), checkFn = dirCheck;
var doneName = done++, checkFn = dirCheck;
if ( typeof part === "string" && !part.match(/\W/) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
@ -1718,8 +1753,16 @@ var Expr = Sizzle.selectors = {
}
},
NAME: function(match, context, isXML){
if ( typeof context.getElementsByName !== "undefined" && !isXML ) {
return context.getElementsByName(match[1]);
if ( typeof context.getElementsByName !== "undefined" ) {
var ret = [], results = context.getElementsByName(match[1]);
for ( var i = 0, l = results.length; i < l; i++ ) {
if ( results[i].getAttribute("name") === match[1] ) {
ret.push( results[i] );
}
}
return ret.length === 0 ? null : ret;
}
},
TAG: function(match, context){
@ -1727,13 +1770,16 @@ var Expr = Sizzle.selectors = {
}
},
preFilter: {
CLASS: function(match, curLoop, inplace, result, not){
CLASS: function(match, curLoop, inplace, result, not, isXML){
match = " " + match[1].replace(/\\/g, "") + " ";
var elem;
for ( var i = 0; (elem = curLoop[i]) != null; i++ ) {
if ( isXML ) {
return match;
}
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
if ( elem ) {
if ( not ^ (" " + elem.className + " ").indexOf(match) >= 0 ) {
if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
if ( !inplace )
result.push( elem );
} else if ( inplace ) {
@ -1764,14 +1810,14 @@ var Expr = Sizzle.selectors = {
}
// TODO: Move to normal caching system
match[0] = "done" + (done++);
match[0] = done++;
return match;
},
ATTR: function(match){
ATTR: function(match, curLoop, inplace, result, not, isXML){
var name = match[1].replace(/\\/g, "");
if ( Expr.attrMap[name] ) {
if ( !isXML && Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
}
@ -1784,7 +1830,7 @@ var Expr = Sizzle.selectors = {
PSEUDO: function(match, curLoop, inplace, result, not){
if ( match[1] === "not" ) {
// If we're dealing with a complex expression, or a simple one
if ( match[3].match(chunker).length > 1 ) {
if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
match[3] = Sizzle(match[3], null, null, curLoop);
} else {
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
@ -1793,7 +1839,7 @@ var Expr = Sizzle.selectors = {
}
return false;
}
} else if ( Expr.match.POS.test( match[0] ) ) {
} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
return true;
}
@ -1890,47 +1936,6 @@ var Expr = Sizzle.selectors = {
}
},
filter: {
CHILD: function(elem, match){
var type = match[1], parent = elem.parentNode;
var doneName = match[0];
if ( parent && (!parent[ doneName ] || !elem.nodeIndex) ) {
var count = 1;
for ( var node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType == 1 ) {
node.nodeIndex = count++;
}
}
parent[ doneName ] = count - 1;
}
if ( type == "first" ) {
return elem.nodeIndex == 1;
} else if ( type == "last" ) {
return elem.nodeIndex == parent[ doneName ];
} else if ( type == "only" ) {
return parent[ doneName ] == 1;
} else if ( type == "nth" ) {
var add = false, first = match[2], last = match[3];
if ( first == 1 && last == 0 ) {
return true;
}
if ( first == 0 ) {
if ( elem.nodeIndex == last ) {
add = true;
}
} else if ( (elem.nodeIndex - last) % first == 0 && (elem.nodeIndex - last) / first >= 0 ) {
add = true;
}
return add;
}
},
PSEUDO: function(elem, match, i, array){
var name = match[1], filter = Expr.filters[ name ];
@ -1950,6 +1955,49 @@ var Expr = Sizzle.selectors = {
return true;
}
},
CHILD: function(elem, match){
var type = match[1], node = elem;
switch (type) {
case 'only':
case 'first':
while (node = node.previousSibling) {
if ( node.nodeType === 1 ) return false;
}
if ( type == 'first') return true;
node = elem;
case 'last':
while (node = node.nextSibling) {
if ( node.nodeType === 1 ) return false;
}
return true;
case 'nth':
var first = match[2], last = match[3];
if ( first == 1 && last == 0 ) {
return true;
}
var doneName = match[0],
parent = elem.parentNode;
if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
var count = 0;
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.nodeIndex = ++count;
}
}
parent.sizcache = doneName;
}
var diff = elem.nodeIndex - last;
if ( first == 0 ) {
return diff == 0;
} else {
return ( diff % first == 0 && diff / first >= 0 );
}
}
},
ID: function(elem, match){
return elem.nodeType === 1 && elem.getAttribute("id") === match;
},
@ -1957,10 +2005,20 @@ var Expr = Sizzle.selectors = {
return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
},
CLASS: function(elem, match){
return match.test( elem.className );
return (" " + (elem.className || elem.getAttribute("class")) + " ")
.indexOf( match ) > -1;
},
ATTR: function(elem, match){
var result = Expr.attrHandle[ match[1] ] ? Expr.attrHandle[ match[1] ]( elem ) : elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
var name = match[1],
result = Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
elem.getAttribute( name ),
value = result + "",
type = match[2],
check = match[4];
return result == null ?
type === "!=" :
type === "=" ?
@ -1969,8 +2027,8 @@ var Expr = Sizzle.selectors = {
value.indexOf(check) >= 0 :
type === "~=" ?
(" " + value + " ").indexOf(check) >= 0 :
!match[4] ?
result :
!check ?
value && result !== false :
type === "!=" ?
value != check :
type === "^=" ?
@ -2036,6 +2094,39 @@ try {
};
}
var sortOrder;
if ( document.documentElement.compareDocumentPosition ) {
sortOrder = function( a, b ) {
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
} else if ( "sourceIndex" in document.documentElement ) {
sortOrder = function( a, b ) {
var ret = a.sourceIndex - b.sourceIndex;
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
} else if ( document.createRange ) {
sortOrder = function( a, b ) {
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
aRange.selectNode(a);
aRange.collapse(true);
bRange.selectNode(b);
bRange.collapse(true);
var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
if ( ret === 0 ) {
hasDuplicate = true;
}
return ret;
};
}
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
@ -2099,7 +2190,8 @@ try {
// Check to see if an attribute returns normalized href attributes
div.innerHTML = "<a href='#'></a>";
if ( div.firstChild && div.firstChild.getAttribute("href") !== "#" ) {
if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
div.firstChild.getAttribute("href") !== "#" ) {
Expr.attrHandle.href = function(elem){
return elem.getAttribute("href", 2);
};
@ -2136,29 +2228,50 @@ if ( document.querySelectorAll ) (function(){
Sizzle.matches = oldSizzle.matches;
})();
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) {
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
var div = document.createElement("div");
div.innerHTML = "<div class='test e'></div><div class='test'></div>";
// Opera can't find a second classname (in 9.6)
if ( div.getElementsByClassName("e").length === 0 )
return;
// Safari caches class attributes, doesn't catch changes (in 3.2)
div.lastChild.className = "e";
if ( div.getElementsByClassName("e").length === 1 )
return;
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function(match, context) {
return context.getElementsByClassName(match[1]);
Expr.find.CLASS = function(match, context, isXML) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
return context.getElementsByClassName(match[1]);
}
};
}
})();
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ){
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem && elem.nodeType ) {
var done = elem[doneName];
if ( done ) {
match = checkSet[ done ];
while ( elem ) {
if ( elem.sizcache === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 && !isXML )
elem[doneName] = i;
if ( elem.nodeType === 1 && !isXML ){
elem.sizcache = doneName;
elem.sizset = i;
}
if ( elem.nodeName === cur ) {
match = elem;
@ -2174,22 +2287,28 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
}
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ) {
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem && elem.nodeType ) {
if ( elem[doneName] ) {
match = checkSet[ elem[doneName] ];
while ( elem ) {
if ( elem.sizcache === doneName ) {
match = checkSet[elem.sizset];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML )
elem[doneName] = i;
if ( !isXML ) {
elem.sizcache = doneName;
elem.sizset = i;
}
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
@ -2248,15 +2367,11 @@ jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
Sizzle.selectors.filters.hidden = function(elem){
return "hidden" === elem.type ||
jQuery.css(elem, "display") === "none" ||
jQuery.css(elem, "visibility") === "hidden";
return elem.offsetWidth === 0 || elem.offsetHeight === 0;
};
Sizzle.selectors.filters.visible = function(elem){
return "hidden" !== elem.type &&
jQuery.css(elem, "display") !== "none" &&
jQuery.css(elem, "visibility") !== "hidden";
return elem.offsetWidth > 0 || elem.offsetHeight > 0;
};
Sizzle.selectors.filters.animated = function(elem){
@ -2552,7 +2667,8 @@ jQuery.event = {
var all, handlers;
event = arguments[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
var namespaces = event.type.split(".");
event.type = namespaces.shift();
@ -2883,9 +2999,13 @@ function liveHandler( event ){
}
});
elems.sort(function(a,b) {
return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
});
jQuery.each(elems, function(){
if ( this.fn.call(this.elem, event, this.fn.data) === false )
stop = false;
return (stop = false);
});
return stop;
@ -2949,7 +3069,7 @@ function bindReady(){
// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( jQuery.isReady ) return;
try {
@ -3079,12 +3199,11 @@ jQuery( window ).bind( 'unload', function(){
// document.body must exist before we can do this
jQuery(function(){
var div = document.createElement("div");
div.style.width = "1px";
div.style.paddingLeft = "1px";
div.style.width = div.style.paddingLeft = "1px";
document.body.appendChild( div );
jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
document.body.removeChild( div );
document.body.removeChild( div ).style.display = 'none';
});
})();
@ -3175,7 +3294,7 @@ jQuery.fn.extend({
.filter(function(){
return this.name && !this.disabled &&
(this.checked || /select|textarea/i.test(this.nodeName) ||
/text|hidden|password/i.test(this.type));
/text|hidden|password|search/i.test(this.type));
})
.map(function(i, elem){
var val = jQuery(this).val();
@ -3371,6 +3490,9 @@ jQuery.extend({
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
@ -3686,9 +3808,15 @@ jQuery.fn.extend({
elemdisplay[ tagName ] = display;
}
this[i].style.display = jQuery.data(this[i], "olddisplay", display);
jQuery.data(this[i], "olddisplay", display);
}
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
for ( var i = 0, l = this.length; i < l; i++ ){
this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
}
return this;
}
@ -3702,8 +3830,14 @@ jQuery.fn.extend({
var old = jQuery.data(this[i], "olddisplay");
if ( !old && old !== "none" )
jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
for ( var i = 0, l = this.length; i < l; i++ ){
this[i].style.display = "none";
}
return this;
}
},
@ -3915,7 +4049,7 @@ jQuery.fx.prototype = {
t.elem = this.elem;
if ( t() && jQuery.timers.push(t) == 1 ) {
if ( t() && jQuery.timers.push(t) && !timerId ) {
timerId = setInterval(function(){
var timers = jQuery.timers;
@ -3925,6 +4059,7 @@ jQuery.fx.prototype = {
if ( !timers.length ) {
clearInterval( timerId );
timerId = undefined;
}
}, 13);
}
@ -4193,22 +4328,21 @@ jQuery.each( ['Left', 'Top'], function(i, name) {
jQuery.each([ "Height", "Width" ], function(i, name){
var tl = i ? "Left" : "Top", // top or left
br = i ? "Right" : "Bottom"; // bottom or right
br = i ? "Right" : "Bottom", // bottom or right
lower = name.toLowerCase();
// innerHeight and innerWidth
jQuery.fn["inner" + name] = function(){
return this[ name.toLowerCase() ]() +
num(this, "padding" + tl) +
num(this, "padding" + br);
return this[0] ?
jQuery.css( this[0], lower, false, "padding" ) :
null;
};
// outerHeight and outerWidth
jQuery.fn["outer" + name] = function(margin) {
return this["inner" + name]() +
num(this, "border" + tl + "Width") +
num(this, "border" + br + "Width") +
(margin ?
num(this, "margin" + tl) + num(this, "margin" + br) : 0);
return this[0] ?
jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
null;
};
var type = name.toLowerCase();
@ -4238,4 +4372,5 @@ jQuery.each([ "Height", "Width" ], function(i, name){
this.css( type, typeof size === "string" ? size : size + "px" );
};
});})();
});
})();

10
js/jquery.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -161,6 +161,7 @@ $(document).ready(function(){
$("#form_notice").addClass("warning");
return false;
}
$("#form_notice").addClass("processing");
$("#notice_action-submit").attr("disabled", "disabled");
$("#notice_action-submit").addClass("disabled");
return true;
@ -179,6 +180,7 @@ $(document).ready(function(){
NoticeHover();
NoticeReply();
}
$("#form_notice").removeClass("processing");
$("#notice_action-submit").removeAttr("disabled");
$("#notice_action-submit").removeClass("disabled");
}

View File

@ -326,7 +326,9 @@ class Action extends HTMLOutputter // lawsuit
*/
function showBody()
{
$this->elementStart('body', array('id' => $this->trimmed('action')));
$this->elementStart('body', (common_current_user()) ? array('id' => $this->trimmed('action'),
'class' => 'user_in')
: array('id' => $this->trimmed('action')));
$this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader();

View File

@ -87,6 +87,8 @@ $config =
'closed' => false,
'inviteonly' => false,
'private' => false,
'ssl' => 'never',
'sslserver' => null,
'dupelimit' => 60), # default for same person saying the same thing
'syslog' =>
array('appname' => 'laconica', # for syslog
@ -151,6 +153,9 @@ $config =
array('notify' => array()),
'inboxes' =>
array('enabled' => true), # on by default for new sites
'newuser' =>
array('subscribe' => null,
'welcome' => null),
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');

View File

@ -163,50 +163,25 @@ function jabber_send_notice($to, $notice)
function jabber_format_entry($profile, $notice)
{
// FIXME: notice url might be remote
$entry = $notice->asAtomEntry(true, true);
$noticeurl = common_local_url('shownotice',
array('notice' => $notice->id));
$msg = jabber_format_notice($profile, $notice);
$self_url = common_local_url('userrss', array('nickname' => $profile->nickname));
$entry = "\n<entry xmlns='http://www.w3.org/2005/Atom'>\n";
$entry .= "<source>\n";
$entry .= "<title>" . $profile->nickname . " - " . common_config('site', 'name') . "</title>\n";
$entry .= "<link href='" . htmlspecialchars($profile->profileurl) . "'/>\n";
$entry .= "<link rel='self' type='application/rss+xml' href='" . $self_url . "'/>\n";
$entry .= "<author><name>" . $profile->nickname . "</name></author>\n";
$entry .= "<icon>" . $profile->avatarUrl(AVATAR_PROFILE_SIZE) . "</icon>\n";
$entry .= "</source>\n";
$entry .= "<title>" . htmlspecialchars($msg) . "</title>\n";
$entry .= "<summary>" . htmlspecialchars($msg) . "</summary>\n";
$entry .= "<link rel='alternate' href='" . $noticeurl . "' />\n";
$entry .= "<id>". $notice->uri . "</id>\n";
$entry .= "<published>".common_date_w3dtf($notice->created)."</published>\n";
$entry .= "<updated>".common_date_w3dtf($notice->modified)."</updated>\n";
if ($notice->reply_to) {
$replyurl = common_local_url('shownotice',
array('notice' => $notice->reply_to));
$entry .= "<link rel='related' href='" . $replyurl . "'/>\n";
$xs = new XMLStringer();
$xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
$xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
$xs->element('a', array('href' => $profile->profileurl),
$profile->nickname);
$xs->text(": ");
if (!empty($notice->rendered)) {
$xs->raw($notice->rendered);
} else {
$xs->raw(common_render_content($notice->content, $notice));
}
$entry .= "</entry>\n";
$xs->elementEnd('body');
$xs->elementEnd('html');
$html = "\n<html xmlns='http://jabber.org/protocol/xhtml-im'>\n";
$html .= "<body xmlns='http://www.w3.org/1999/xhtml'>\n";
$html .= "<a href='".htmlspecialchars($profile->profileurl)."'>".$profile->nickname."</a>: ";
$html .= ($notice->rendered) ? $notice->rendered : common_render_content($notice->content, $notice);
$html .= "\n</body>\n";
$html .= "\n</html>\n";
$html = $xs->getString();
$address = "<addresses xmlns='http://jabber.org/protocol/address'>\n";
$address .= "<address type='replyto' jid='" . jabber_daemon_address() . "' />\n";
$address .= "</addresses>\n";
// FIXME: include a pubsub event, too.
return $html . $entry . $address;
return $html . ' ' . $entry;
}
/**

View File

@ -115,7 +115,7 @@ function get_all_languages() {
'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'),
'it' => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'),
'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'),
'ko' => array('q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'),
'ko' => array('q' => 0.9, 'lang' => 'ko_KR', 'name' => 'Korean', 'direction' => 'ltr'),
'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'),
'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),

View File

@ -554,17 +554,19 @@ function mail_notify_fave($other, $user, $notice)
$body = sprintf(_("%1\$s just added your notice from %2\$s".
" as one of their favorites.\n\n" .
"In case you forgot, you can see the text".
" of your notice here:\n\n" .
"The URL of your notice is:\n\n" .
"%3\$s\n\n" .
"You can see the list of %1\$s's favorites here:\n\n" .
"The text of your notice is:\n\n" .
"%4\$s\n\n" .
"You can see the list of %1\$s's favorites here:\n\n" .
"%5\$s\n\n" .
"Faithfully yours,\n" .
"%5\$s\n"),
"%6\$s\n"),
$bestname,
common_exact_date($notice->created),
common_local_url('shownotice',
array('notice' => $notice->id)),
$notice->content,
common_local_url('showfavorites',
array('nickname' => $user->nickname)),
common_config('site', 'name'));

View File

@ -132,20 +132,14 @@ class MessageForm extends Form
$mutual_users->free();
unset($mutual_users);
$this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li', array('id' => 'notice_to'));
$this->out->dropdown('to', _('To'), $mutual, null, false,
($this->to) ? $this->to->id : null);
$this->out->elementEnd('li');
$this->out->elementStart('li', array('id' => 'notice_text'));
$this->out->element('textarea', array('id' => 'notice_data-text',
'cols' => 35,
'rows' => 4,
'name' => 'content'),
($this->content) ? $this->content : '');
$this->out->elementEnd('li');
$this->out->elementEnd('ul');
}
/**
@ -156,14 +150,10 @@ class MessageForm extends Form
function formActions()
{
$this->out->elementStart('ul', 'form_actions');
$this->out->elementStart('li', array('id' => 'notice_submit'));
$this->out->element('input', array('id' => 'notice_action-submit',
'class' => 'submit',
'name' => 'message_send',
'type' => 'submit',
'value' => _('Send')));
$this->out->elementEnd('li');
$this->out->elementEnd('ul');
}
}

View File

@ -134,9 +134,6 @@ class NoticeForm extends Form
function formData()
{
$this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li', array('id' => 'notice_text'));
$this->out->element('label', array('for' => 'notice_data-text'),
sprintf(_('What\'s up, %s?'), $this->user->nickname));
// XXX: vary by defined max size
@ -145,8 +142,6 @@ class NoticeForm extends Form
'rows' => 4,
'name' => 'status_textarea'),
($this->content) ? $this->content : '');
$this->out->elementEnd('li');
$this->out->elementEnd('ul');
$this->out->elementStart('dl', 'form_note');
$this->out->element('dt', null, _('Available characters'));
@ -168,14 +163,10 @@ class NoticeForm extends Form
function formActions()
{
$this->out->elementStart('ul', 'form_actions');
$this->out->elementStart('li', array('id' => 'notice_submit'));
$this->out->element('input', array('id' => 'notice_action-submit',
'class' => 'submit',
'name' => 'status_submit',
'type' => 'submit',
'value' => _('Send')));
$this->out->elementEnd('li');
$this->out->elementEnd('ul');
}
}

View File

@ -258,8 +258,12 @@ class NoticeListItem extends Widget
function showAuthor()
{
$this->out->elementStart('span', 'vcard author');
$this->out->elementStart('a', array('href' => $this->profile->profileurl,
'class' => 'url'));
$attrs = array('href' => $this->profile->profileurl,
'class' => 'url');
if (!empty($this->profile->fullname)) {
$attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
}
$this->out->elementStart('a', $attrs);
$this->showAvatar();
$this->showNickname();
$this->out->elementEnd('a');
@ -387,6 +391,7 @@ class NoticeListItem extends Widget
case 'xmpp':
case 'mail':
case 'omb':
case 'system':
case 'api':
$this->out->element('dd', null, $source_name);
break;

View File

@ -160,7 +160,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
$auth_request->addExtension($sreg_request);
}
$trust_root = common_path('');
$trust_root = common_root_url(true);
$process_url = common_local_url($returnto);
if ($auth_request->shouldSendRedirect()) {
@ -171,7 +171,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
} else if (Auth_OpenID::isFailure($redirect_url)) {
return sprintf(_('Could not redirect to server: %s'), $redirect_url->message);
} else {
common_redirect($redirect_url);
common_redirect($redirect_url, 303);
}
} else {
// Generate form markup and render it.

View File

@ -48,9 +48,17 @@ function ping_broadcast_notice($notice) {
'header' =>
"Content-Type: text/xml\r\n".
"User-Agent: Laconica/".LACONICA_VERSION."\r\n",
'content' => $request)));
'content' => $req)));
$file = file_get_contents($notify_url, false, $context);
if ($file === false || mb_strlen($file) == 0) {
common_log(LOG_WARNING,
"XML-RPC empty results for ping ($notify_url, $notice->id) ");
continue;
}
$response = xmlrpc_decode($file);
if (xmlrpc_is_fault($response)) {
common_log(LOG_WARNING,
"XML-RPC error for ping ($notify_url, $notice->id) ".

View File

@ -109,7 +109,7 @@ class ProfileList extends Widget
$this->out->elementEnd('span');
$this->out->elementEnd('a');
if ($this->profile->fullname !== '') {
if (!empty($this->profile->fullname)) {
$this->out->elementStart('dl', 'entity_fn');
$this->out->element('dt', null, 'Full name');
$this->out->elementStart('dd');
@ -119,7 +119,7 @@ class ProfileList extends Widget
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');
}
if ($this->profile->location !== '') {
if (!empty($this->profile->location)) {
$this->out->elementStart('dl', 'entity_location');
$this->out->element('dt', null, _('Location'));
$this->out->elementStart('dd', 'label');
@ -127,7 +127,7 @@ class ProfileList extends Widget
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');
}
if ($this->profile->homepage !== '') {
if (!empty($this->profile->homepage)) {
$this->out->elementStart('dl', 'entity_url');
$this->out->element('dt', null, _('URL'));
$this->out->elementStart('dd');
@ -138,7 +138,7 @@ class ProfileList extends Widget
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');
}
if ($this->profile->bio !== '') {
if (!empty($this->profile->bio)) {
$this->out->elementStart('dl', 'entity_note');
$this->out->element('dt', null, _('Note'));
$this->out->elementStart('dd', 'note');
@ -194,11 +194,12 @@ class ProfileList extends Widget
$this->out->elementStart('ul');
if (!$is_own) {
# XXX: special-case for user looking at own
# subscriptions page
// Is this a logged-in user, looking at someone else's
// profile?
if (!empty($user) && $this->profile->id != $user->id) {
$this->out->elementStart('li', 'entity_subscribe');
if (!is_null($user) && $user->isSubscribed($this->profile)) {
if ($user->isSubscribed($this->profile)) {
$usf = new UnsubscribeForm($this->out, $this->profile);
$usf->show();
} else {
@ -207,6 +208,9 @@ class ProfileList extends Widget
}
$this->out->elementEnd('li');
$this->out->elementStart('li', 'entity_block');
if ($user->id == $this->owner->id) {
$this->showBlockForm();
}
$this->out->elementEnd('li');
}

View File

@ -68,8 +68,8 @@ class Router
}
}
function initialize() {
function initialize()
{
$m = Net_URL_Mapper::getInstance();
// In the "root"
@ -107,6 +107,9 @@ class Router
$m->connect('main/'.$a, array('action' => $a));
}
$m->connect('main/sup/:seconds', array('action' => 'sup'),
array('seconds' => '[0-9]+'));
$m->connect('main/tagother/:id', array('action' => 'tagother'));
// these take a code
@ -136,10 +139,17 @@ class Router
foreach (array('group', 'people', 'notice') as $s) {
$m->connect('search/'.$s, array('action' => $s.'search'));
$m->connect('search/'.$s.'?q=:q', array('action' => $s.'search'), array('q' => '.+'));
$m->connect('search/'.$s.'?q=:q',
array('action' => $s.'search'),
array('q' => '.+'));
}
// The second of these is needed to make the link work correctly
// when inserted into the page. The first is needed to match the
// route on the way in. Seems to be another Net_URL_Mapper bug to me.
$m->connect('search/notice/rss', array('action' => 'noticesearchrss'));
$m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
array('q' => '.+'));
// notice
@ -259,8 +269,8 @@ class Router
foreach (array('xml', 'json', 'rss', 'atom') as $e) {
$m->connect('api/direct_messages/sent.'.$e,
array('action' => 'api',
'apiaction' => 'direct_messages',
'method' => 'sent.'.$e));
'apiaction' => 'direct_messages',
'method' => 'sent.'.$e));
}
$m->connect('api/direct_messages/destroy/:argument',
@ -324,9 +334,9 @@ class Router
foreach (array('xml', 'json', 'rss', 'atom') as $e) {
$m->connect('api/favorites.'.$e,
array('action' => 'api',
'apiaction' => 'favorites',
'method' => 'favorites.'.$e));
array('action' => 'api',
'apiaction' => 'favorites',
'method' => 'favorites.'.$e));
}
// notifications
@ -411,7 +421,7 @@ class Router
$match = $this->m->match($path);
} catch (Net_URL_Mapper_InvalidException $e) {
common_log(LOG_ERR, "Problem getting route for $path - " .
$e->getMessage());
$e->getMessage());
$cac = new ClientErrorAction("Page not found.", 404);
$cac->showPage();
}
@ -429,6 +439,17 @@ class Router
$args = $action_arg;
}
return $this->m->generate($args, $params, $fragment);
$url = $this->m->generate($args, $params, $fragment);
// Due to a bug in the Net_URL_Mapper code, the returned URL may
// contain a malformed query of the form ?p1=v1?p2=v2?p3=v3. We
// repair that here rather than modifying the upstream code...
$qpos = strpos($url, '?');
if ($qpos !== false) {
$url = substr($url, 0, $qpos+1) .
str_replace('?', '&', substr($url, $qpos+1));
}
return $url;
}
}

View File

@ -94,11 +94,11 @@ class Rss10Action extends Action
function handle($args)
{
// Get the list of notices
$this->notices = $this->getNotices();
// Parent handling, including cache check
parent::handle($args);
$this->showRss($this->limit);
// Get the list of notices
$this->notices = $this->getNotices($this->limit);
$this->showRss();
}
/**
@ -132,15 +132,13 @@ class Rss10Action extends Action
return null;
}
function showRss($limit=0)
function showRss()
{
$notices = $this->getNotices($limit);
$this->initRss();
$this->showChannel($notices);
$this->showChannel();
$this->showImage();
foreach ($notices as $n) {
foreach ($this->notices as $n) {
$this->showItem($n);
}
@ -148,7 +146,7 @@ class Rss10Action extends Action
$this->endRss();
}
function showChannel($notices)
function showChannel()
{
$channel = $this->getChannel();
@ -167,7 +165,7 @@ class Rss10Action extends Action
$this->elementStart('items');
$this->elementStart('rdf:Seq');
foreach ($notices as $notice) {
foreach ($this->notices as $notice) {
$this->element('sioct:MicroblogPost', array('rdf:resource' => $notice->uri));
}

View File

@ -78,9 +78,9 @@ class SettingsAction extends Action
common_set_returnto($this->selfUrl());
$user = common_current_user();
if ($user->hasOpenID()) {
common_redirect(common_local_url('openidlogin'));
common_redirect(common_local_url('openidlogin'), 303);
} else {
common_redirect(common_local_url('login'));
common_redirect(common_local_url('login'), 303);
}
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->handlePost();

View File

@ -238,21 +238,6 @@ class TwitterapiAction extends Action
$this->elementEnd('item');
}
function show_twitter_atom_entry($entry)
{
$this->elementStart('entry');
$this->element('title', null, $entry['title']);
$this->element('content', array('type' => 'html'), $entry['content']);
$this->element('id', null, $entry['id']);
$this->element('published', null, $entry['published']);
$this->element('updated', null, $entry['updated']);
$this->element('link', array('href' => $entry['link'], 'rel' => 'alternate', 'type' => 'text/html'), null);
$this->elementStart('author');
$this->element('name', null, $entry['author']);
$this->elementEnd('author');
$this->elementEnd('entry');
}
function show_json_objects($objects)
{
print(json_encode($objects));
@ -383,7 +368,7 @@ class TwitterapiAction extends Action
}
if (!is_null($selfuri)) {
$this->element('link', array('href' => $selfuri,
$this->element('link', array('href' => $selfuri,
'rel' => 'self', 'type' => 'application/atom+xml'), null);
}
@ -392,13 +377,11 @@ class TwitterapiAction extends Action
if (is_array($notice)) {
foreach ($notice as $n) {
$entry = $this->twitter_rss_entry_array($n);
$this->show_twitter_atom_entry($entry);
$this->raw($n->asAtomEntry());
}
} else {
while ($notice->fetch()) {
$entry = $this->twitter_rss_entry_array($notice);
$this->show_twitter_atom_entry($entry);
$this->raw($notice->asAtomEntry());
}
}
@ -578,13 +561,16 @@ class TwitterapiAction extends Action
function init_twitter_atom()
{
$this->startXML();
$this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en-US'));
// FIXME: don't hardcode the language here!
$this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom',
'xml:lang' => 'en-US',
'xmlns:thr' => 'http://purl.org/syndication/thread/1.0'));
}
function end_twitter_atom()
{
$this->endXML();
$this->elementEnd('feed');
$this->endXML();
}
function show_profile($profile, $content_type='xml', $notice=null)

View File

@ -620,9 +620,13 @@ function common_at_link($sender_id, $nickname)
$url = $recipient->profileurl;
}
$xs = new XMLStringer(false);
$attrs = array('href' => $url,
'class' => 'url');
if (!empty($recipient->fullname)) {
$attrs['title'] = $recipient->fullname . ' (' . $recipient->nickname . ')';
}
$xs->elementStart('span', 'vcard');
$xs->elementStart('a', array('href' => $url,
'class' => 'url'));
$xs->elementStart('a', $attrs);
$xs->element('span', 'fn nickname', $nickname);
$xs->elementEnd('a');
$xs->elementEnd('span');
@ -637,10 +641,14 @@ function common_group_link($sender_id, $nickname)
$sender = Profile::staticGet($sender_id);
$group = User_group::staticGet('nickname', common_canonical_nickname($nickname));
if ($group && $sender->isMember($group)) {
$attrs = array('href' => $group->permalink(),
'class' => 'url');
if (!empty($group->fullname)) {
$attrs['title'] = $group->fullname . ' (' . $group->nickname . ')';
}
$xs = new XMLStringer();
$xs->elementStart('span', 'vcard');
$xs->elementStart('a', array('href' => $group->permalink(),
'class' => 'url'));
$xs->elementStart('a', $attrs);
$xs->element('span', 'fn nickname', $nickname);
$xs->elementEnd('a');
$xs->elementEnd('span');
@ -711,25 +719,46 @@ function common_relative_profile($sender, $nickname, $dt=null)
function common_local_url($action, $args=null, $params=null, $fragment=null)
{
static $sensitive = array('login', 'register', 'passwordsettings',
'twittersettings', 'finishopenidlogin',
'finishaddopenid', 'api');
$r = Router::get();
$path = $r->build($action, $args, $params, $fragment);
$ssl = in_array($action, $sensitive);
if (common_config('site','fancy')) {
$url = common_path(mb_substr($path, 1));
$url = common_path(mb_substr($path, 1), $ssl);
} else {
if (mb_strpos($path, '/index.php') === 0) {
$url = common_path(mb_substr($path, 1));
$url = common_path(mb_substr($path, 1), $ssl);
} else {
$url = common_path('index.php'.$path);
$url = common_path('index.php'.$path, $ssl);
}
}
return $url;
}
function common_path($relative)
function common_path($relative, $ssl=false)
{
$pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
return "http://".common_config('site', 'server').'/'.$pathpart.$relative;
if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
|| common_config('site', 'ssl') === 'always') {
$proto = 'https';
if (is_string(common_config('site', 'sslserver')) &&
mb_strlen(common_config('site', 'sslserver')) > 0) {
$serverpart = common_config('site', 'sslserver');
} else {
$serverpart = common_config('site', 'server');
}
} else {
$proto = 'http';
$serverpart = common_config('site', 'server');
}
return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
}
function common_date_string($dt)
@ -819,7 +848,7 @@ function common_redirect($url, $code=307)
303 => "See Other",
307 => "Temporary Redirect");
header("Status: ${code} $status[$code]");
header('HTTP/1.1 '.$code.' '.$status[$code]);
header("Location: $url");
$xo = new XMLOutputter();
@ -921,9 +950,9 @@ function common_profile_url($nickname)
// Should make up a reasonable root URL
function common_root_url()
function common_root_url($ssl=false)
{
return common_path('');
return common_path('', $ssl);
}
// returns $bytes bytes of random data as a hexadecimal string

View File

@ -105,12 +105,13 @@ class LinkbackPlugin extends Plugin
$pb = $match[1];
}
$tb = $this->getTrackback($result->body, $result->final_url);
if (!empty($tb)) {
$this->trackback($result->final_url, $tb);
} else if (!empty($pb)) {
if (!empty($pb)) {
$this->pingback($result->final_url, $pb);
} else {
$tb = $this->getTrackback($result->body, $result->final_url);
if (!empty($tb)) {
$this->trackback($result->final_url, $tb);
}
}
return $orig;

View File

@ -150,7 +150,9 @@ font-weight:bold;
#form_openid_login legend,
#form_search legend,
#form_invite legend,
#form_notice_delete legend {
#form_notice_delete legend,
#form_password_recover legend,
#form_password_change legend {
display:none;
}
@ -214,6 +216,9 @@ margin-right:0;
address .fn {
font-weight:bold;
}
address img + .fn {
display:none;
}
#header {
width:100%;
@ -245,6 +250,7 @@ position:absolute;
top:65px;
right:18px;
width:250px;
width:24%;
}
#page_notice {
clear:both;
@ -254,9 +260,8 @@ margin-bottom:18px;
#anon_notice {
float:left;
width:432px;
width:28.052em;
padding:11px;
width:43.2%;
padding:1.1%;
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
@ -364,7 +369,9 @@ margin-right:4px;
#wrap {
margin:0 auto;
width:1003px;
width:100%;
min-width:760px;
max-width:1003px;
overflow:hidden;
}
@ -376,14 +383,16 @@ margin-bottom:1em;
}
#content {
width:644px;
padding:18px;
width:64.009%;
padding:1.795%;
float:left;
border-radius:7px;
-moz-border-radius:7px;
-moz-border-radius-topleft:0;
-webkit-border-radius:7px;
-webkit-border-top-left-radius:0;
border-style:solid;
border-width:1px;
}
#content_inner {
@ -393,10 +402,10 @@ float:left;
}
#aside_primary {
width:280px;
width:27.917%;
float:left;
margin-left:4px;
padding:18px;
margin-left:0.395%;
padding:1.795%;
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
@ -404,9 +413,8 @@ border-width:1px;
border-style:solid;
}
/*Start: FORM NOTICE*/
#form_notice {
width:458px;
width:45.664%;
float:left;
position:relative;
line-height:1;
@ -419,40 +427,30 @@ padding:0;
display:none;
}
#form_notice textarea {
float:left;
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
width:370px;
width:80.789%;
height:67px;
line-height:1.5;
padding:7px 7px 16px 7px;
}
#form_notice label {
display:block;
float:left;
font-size:1.3em;
margin-bottom:7px;
}
#form_notice .form_data li {
float:left;
}
#form_notice #notice_attach_file label,
#form_notice #notice_submit label {
display:none;
}
#form_notice #notice_attachment {
margin-top:25px;
margin-left:4px;
}
#form_notice .form_note {
position:absolute;
top:99px;
right:98px;
z-index:9;
}
#form_notice .form_note dt {
font-weight:bold;
display:none;
@ -462,51 +460,28 @@ font-weight:bold;
line-height:1.15;
padding:1px 2px;
}
#form_notice #notice_data-attach_view {
position:absolute;
top:25px;
right:30px;
margin-left:4px;
#form_notice #notice_action-submit {
width:14%;
height:47px;
padding:0;
width:16px;
height:16px;
border:0;
text-indent:-9999px;
}
#form_notice .form_actions {
position:absolute;
bottom:0;
right:0;
}
#form_notice .form_actions input.submit {
width:60px;
padding:8px;
}
#form_notice li {
margin-bottom:0;
}
#form_notice #notice_to {
margin-bottom:7px;
}
#notice_to label {
float:left;
margin-right:18px;
#form_notice label[for=to] {
margin-top:11px;
}
#notice_to select {
#form_notice select[id=to] {
margin-bottom:7px;
margin-left:18px;
float:left;
}
/*end FORM NOTICE*/
/* entity_profile */
.entity_profile {
position:relative;
width:475px;
width:67.702%;
min-height:123px;
float:left;
margin-bottom:18px;
@ -536,7 +511,6 @@ margin-bottom:18px;
.entity_profile .entity_tags {
margin-left:113px;
margin-bottom:4px;
width:322px;
}
.entity_profile .entity_fn,
@ -564,14 +538,14 @@ display:none;
.entity_profile h2 {
display:none;
}
/* entity_profile */
/*entity_actions*/
.entity_actions {
float:right;
margin-left:28px;
margin-left:4.35%;
max-width:25%;
}
.entity_actions h2 {
display:none;
@ -939,8 +913,6 @@ display:none;
border:0;
padding:0;
}
/*END: NOTICES */
#new_group, #group_search {

View File

@ -1,8 +1,21 @@
/* IE specific styles */
#aside_primary {
padding-left:11px;
legend {
margin-left:-7px;
}
input.checkbox {
top:0;
}
#form_notice textarea {
width:78%;
}
#form_notice #notice_action-submit {
width:17%;
max-width:17%;
}
#anon_notice {
max-width:39%;
}
.notice-options input.submit {
font-size:0;
margin-top:3px;
@ -11,15 +24,9 @@ text-align:right;
text-indent:0;
width:24px;
}
input.checkbox {
top:0;
}
legend {
margin-left:-7px;
}
.notice div.entry-content .timestamp a {
margin-right:4px;
}
.entity_profile {
width:64%;
}

View File

@ -1,4 +1,17 @@
/* IE6 specific styles */
address {
margin-left:7px;
}
address .fn {
display:none;
}
#content {
width:70%;
}
#aside_primary {
padding:5%;
width:29.5%;
}
.entity_profile .entity_nickname,
.entity_profile .entity_location,
.entity_profile .entity_url,
@ -9,3 +22,9 @@ margin-left:0;
.entity_profile .entity_depiction {
margin-bottom:123px;
}
.entity_actions {
width:20%;
}
.notice div.entry-content {
width:63%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

View File

@ -17,10 +17,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
font-size:1em;
}
address {
margin-right:71px;
}
address .fn {
display:none;
margin-right:7.18%;
}
input, textarea, select, option {
@ -94,6 +91,11 @@ color:#333;
#form_notice.warning #notice_text-count {
color:#000;
}
#form_notice.processing #notice_action-submit {
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait;
text-indent:-9999px;
}
#nav_register a {

View File

@ -17,10 +17,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
font-size:1em;
}
address {
margin-right:71px;
}
address .fn {
display:none;
margin-right:7.18%;
}
input, textarea, select, option {
@ -94,7 +91,11 @@ color:#333;
#form_notice.warning #notice_text-count {
color:#000;
}
#form_notice.processing #notice_action-submit {
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait;
text-indent:-9999px;
}
#nav_register a {
text-decoration:none;