Merge branch '0.7.x' of git://gitorious.org/laconica/dev into 0.7.x
This commit is contained in:
commit
4277a6818c
148
README
148
README
|
@ -2,8 +2,8 @@
|
||||||
README
|
README
|
||||||
------
|
------
|
||||||
|
|
||||||
Laconica 0.7.2.1 ("Talk about the Passion")
|
Laconica 0.7.3 ("You Are The Everything")
|
||||||
11 March 2009
|
7 April 2009
|
||||||
|
|
||||||
This is the README file for Laconica, the Open Source microblogging
|
This is the README file for Laconica, the Open Source microblogging
|
||||||
platform. It includes installation instructions, descriptions of
|
platform. It includes installation instructions, descriptions of
|
||||||
|
@ -71,93 +71,29 @@ for additional terms.
|
||||||
New this version
|
New this version
|
||||||
================
|
================
|
||||||
|
|
||||||
This is a minor bug-fix and feature release since version 0.7.1,
|
This is a minor bug-fix and feature release since version 0.7.2.1,
|
||||||
released Feb 9 2009. Notable changes this version:
|
released Mar 11 2009. Notable changes this version:
|
||||||
|
|
||||||
- First version of a web-based installer
|
- A plugin to allow a templating language for customization
|
||||||
- Use Net_URL_Mapper instead of mod_rewrite to map "fancy URLs",
|
- A plugin for Piwik Analytics engine
|
||||||
for a much simpler installation and use of PATH_INFO on sites
|
- A bookmarklet for posting a notice about a Web page you're reading
|
||||||
that don't have mod_rewrite.
|
- A welcome notice ('welcomebot') and default subscription for new users
|
||||||
- A plugin framework for system events, to make it easier to build
|
- Support for SSL for some or all pages on the site
|
||||||
server-side plugins.
|
- Better handling of empty notice lists on many pages
|
||||||
- A plugin for Google Analytics
|
- Major improvements to the Twitter friend-sync offline processing
|
||||||
- A plugin to use blogspam.net to check notices for spam
|
- subscribers, subscriptions, groups are listed on the Personal page.
|
||||||
- A plugin to send linkbacks for notices about blog posts
|
- "Invite" link restored to main menu
|
||||||
- Configurable check for duplicate notices in a specific time
|
- Better memory handling in FOAF output
|
||||||
period
|
- Fix for SUP support (FriendFeed)
|
||||||
- Better Atom feeds
|
- Correct and intelligent redirect HTTP status codes
|
||||||
- First implementation of Twitter Search API
|
- Fix DB collations for search and sort
|
||||||
- Add streamlined mobile device-friendly styles when enabled in config.
|
- Better H1s and Titles using user full names
|
||||||
- A queue server for sending notices to Twitter
|
- Fixes to make the linkback plugin operational
|
||||||
- A queue server for sending notices to Facebook
|
- Better indication that a notice is being published by Ajax (spinner)
|
||||||
- A queue server for sending notices to a ping server
|
- Better and unified Atom output
|
||||||
- Fixed a bug in nonces for OAuth in OpenMicroBlogging
|
- Hiding "register" and "join now" messages when site is closed
|
||||||
- Fixed bugs in transfer of avatars in OpenMicroBlogging
|
- ping, twitter and facebook queuehandlers working better
|
||||||
- @-links go to permalinks for local users
|
- Updated RPM spec
|
||||||
- Better handling of DB errors (instead of dreaded DB_DataObject blank
|
|
||||||
screen)
|
|
||||||
- Initial version of an RPM spec file
|
|
||||||
- More consistent display of notices in notice search
|
|
||||||
- A stylesheet for printed output
|
|
||||||
- "Social graph" methods for Twitter API
|
|
||||||
- Documentation for the JavaScript badge
|
|
||||||
- Debugged a ton of problems that happened with E_NOTICE on
|
|
||||||
- Better caching in RSS feeds
|
|
||||||
- Optionally send email when an @-message is received
|
|
||||||
- Automatically add tags for every group message
|
|
||||||
- Add framebusting JavaScript to help avoid clickjacking attacks.
|
|
||||||
- Optionally ignore some notice sources for public page.
|
|
||||||
- Add default SMS carriers and notice sources to distribution file.
|
|
||||||
- Change titles to use mixed case instead of all uppercase.
|
|
||||||
- Use exceptions for error handling.
|
|
||||||
|
|
||||||
Changes in version 0.7.1:
|
|
||||||
|
|
||||||
- Vast improvement in auto-linking to URLs.
|
|
||||||
- Link to group search from user's group page
|
|
||||||
- Improved interface in Facebook application
|
|
||||||
- Fix bad redirects in delete notice
|
|
||||||
- Updated PostgreSQL database creation script
|
|
||||||
- Show filesize in avatar/logo upload
|
|
||||||
- Vastly improved avatar/logo upload
|
|
||||||
- Allow re-authentication with OpenID
|
|
||||||
- Correctly link hashtabs inside parens and brackets
|
|
||||||
- Group and avatar image transparency works
|
|
||||||
- Better handling of commands through the Web and Ajax channels
|
|
||||||
- Fix links for profile page feeds
|
|
||||||
- Fixed destroy method in API
|
|
||||||
- Fix endpoint of Connect menu when XMPP disabled
|
|
||||||
- Show number of group members
|
|
||||||
- Enable configuration files in /etc/laconica/
|
|
||||||
|
|
||||||
Changes in version 0.7.0:
|
|
||||||
|
|
||||||
- Support for groups. Users can join groups and send themed notices
|
|
||||||
to those groups. All other members of the group receive the notices.
|
|
||||||
- Laconica-specific extensions to the Twitter API.
|
|
||||||
- A Facebook application.
|
|
||||||
- A massive UI redesign. The HTML generated by Laconica has changed
|
|
||||||
significantly, to make theming easier and to give a more open look
|
|
||||||
by default. Also, sidebar.
|
|
||||||
- Massive code hygiene changes to move towards compliance with the PEAR
|
|
||||||
coding standards and to support the new UI redesign.
|
|
||||||
- Began the breakup of util.php -- moved about 30% of code to a views
|
|
||||||
hierarchy.
|
|
||||||
- UI elements for statistical information (like top posters or most
|
|
||||||
popular groups) added in a sidebar.
|
|
||||||
- include Javascript badge by Kent Brewster.
|
|
||||||
- Updated online documentation.
|
|
||||||
- Cropping of user avatars using Jcrop.
|
|
||||||
- fix for Twitter bridge to not send "Expect:" headers.
|
|
||||||
- add 'dm' as a synonym for 'd' in commands.
|
|
||||||
- Upgrade upstream version of jQuery to 1.3.
|
|
||||||
- Upgrade upstream version of PHP-OpenID to 2.1.2.
|
|
||||||
- Move OpenMicroBlogging specification to its own repository.
|
|
||||||
- Make tag-based RSS streams work.
|
|
||||||
- Additional locales: Bulgarian, Catalan, Greek, Hebrew, simplified
|
|
||||||
Chinese, Telugu, Taiwanese Chinese, Vietnamese,
|
|
||||||
- PostgreSQL updates.
|
|
||||||
- Nasty bug in Twitter bridge that wouldn't verify with Twitter
|
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
|
@ -257,9 +193,9 @@ especially if you've previously installed PHP/MySQL packages.
|
||||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||||
command like this will work:
|
command like this will work:
|
||||||
|
|
||||||
tar zxf laconica-0.7.2.1.tar.gz
|
tar zxf laconica-0.7.3.tar.gz
|
||||||
|
|
||||||
...which will make a laconica-0.7.2.1 subdirectory in your current
|
...which will make a laconica-0.7.3 subdirectory in your current
|
||||||
directory. (If you don't have shell access on your Web server, you
|
directory. (If you don't have shell access on your Web server, you
|
||||||
may have to unpack the tarball on your local computer and FTP the
|
may have to unpack the tarball on your local computer and FTP the
|
||||||
files to the server.)
|
files to the server.)
|
||||||
|
@ -267,7 +203,7 @@ especially if you've previously installed PHP/MySQL packages.
|
||||||
2. Move the tarball to a directory of your choosing in your Web root
|
2. Move the tarball to a directory of your choosing in your Web root
|
||||||
directory. Usually something like this will work:
|
directory. Usually something like this will work:
|
||||||
|
|
||||||
mv laconica-0.7.2.1 /var/www/mublog
|
mv laconica-0.7.3 /var/www/mublog
|
||||||
|
|
||||||
This will make your Laconica instance available in the mublog path of
|
This will make your Laconica instance available in the mublog path of
|
||||||
your server, like "http://example.net/mublog". "microblog" or
|
your server, like "http://example.net/mublog". "microblog" or
|
||||||
|
@ -757,7 +693,7 @@ Upgrading
|
||||||
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
||||||
tracking the "git" version of the software, you will probably want
|
tracking the "git" version of the software, you will probably want
|
||||||
to upgrade and keep your existing data. There is no automated upgrade
|
to upgrade and keep your existing data. There is no automated upgrade
|
||||||
procedure in Laconica 0.7.2.1. Try these step-by-step instructions; read
|
procedure in Laconica 0.7.3. Try these step-by-step instructions; read
|
||||||
to the end first before trying them.
|
to the end first before trying them.
|
||||||
|
|
||||||
0. Download Laconica and set up all the prerequisites as if you were
|
0. Download Laconica and set up all the prerequisites as if you were
|
||||||
|
@ -925,6 +861,16 @@ dupelimit: Time in which it's not OK for the same person to post the
|
||||||
same notice; default = 60 seconds.
|
same notice; default = 60 seconds.
|
||||||
logo: URL of an image file to use as the logo for the site. Overrides
|
logo: URL of an image file to use as the logo for the site. Overrides
|
||||||
the logo in the theme, if any.
|
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
|
db
|
||||||
--
|
--
|
||||||
|
@ -1169,6 +1115,20 @@ banned: an array of usernames and/or profile IDs of 'banned' profiles.
|
||||||
not be accepted at all. (Compare with blacklisted users above,
|
not be accepted at all. (Compare with blacklisted users above,
|
||||||
whose posts just won't show up in the public stream.)
|
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 'default' 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
|
Troubleshooting
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
@ -1181,7 +1141,7 @@ repository (see below), and you get a compilation error ("unexpected
|
||||||
T_STRING") in the browser, check to see that you don't have any
|
T_STRING") in the browser, check to see that you don't have any
|
||||||
conflicts in your code.
|
conflicts in your code.
|
||||||
|
|
||||||
If you upgraded to Laconica 0.7.2.1 without reading the "Notice inboxes"
|
If you upgraded to Laconica 0.7.3 without reading the "Notice inboxes"
|
||||||
section above, and all your users' 'Personal' tabs are empty, read the
|
section above, and all your users' 'Personal' tabs are empty, read the
|
||||||
"Notice inboxes" section above.
|
"Notice inboxes" section above.
|
||||||
|
|
||||||
|
@ -1270,6 +1230,8 @@ if anyone's been overlooked in error.
|
||||||
* Leslie Michael Orchard
|
* Leslie Michael Orchard
|
||||||
* Eric Helgeson
|
* Eric Helgeson
|
||||||
* Ken Sedgwick
|
* Ken Sedgwick
|
||||||
|
* Brian Hendrickson
|
||||||
|
* Tobias Diekershoff
|
||||||
|
|
||||||
Thanks also to the developers of our upstream library code and to the
|
Thanks also to the developers of our upstream library code and to the
|
||||||
thousands of people who have tried out Identi.ca, installed Laconi.ca,
|
thousands of people who have tried out Identi.ca, installed Laconi.ca,
|
||||||
|
|
|
@ -23,31 +23,13 @@ require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
|
|
||||||
class AllAction extends Action
|
class AllAction extends ProfileAction
|
||||||
{
|
{
|
||||||
var $user = null;
|
|
||||||
var $page = null;
|
|
||||||
|
|
||||||
function isReadOnly()
|
function isReadOnly()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
$nickname = common_canonical_nickname($this->arg('nickname'));
|
|
||||||
$this->user = User::staticGet('nickname', $nickname);
|
|
||||||
$this->page = $this->trimmed('page');
|
|
||||||
if (!$this->page) {
|
|
||||||
$this->page = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_set_returnto($this->selfUrl());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
@ -93,6 +75,27 @@ class AllAction extends Action
|
||||||
$nav->show();
|
$nav->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' ';
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message .= _('Try subscribing to more people, [join a group](%%action.groups) or post something yourself.');
|
||||||
|
} else {
|
||||||
|
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
$notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||||
|
@ -101,6 +104,10 @@ class AllAction extends Action
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'all', array('nickname' => $this->user->nickname));
|
$this->page, 'all', array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,8 @@ class BlockAction extends Action
|
||||||
if ($this->arg('no')) {
|
if ($this->arg('no')) {
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
$other = Profile::staticGet('id', $this->arg('blockto'));
|
$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')) {
|
} elseif ($this->arg('yes')) {
|
||||||
$this->blockProfile();
|
$this->blockProfile();
|
||||||
} elseif ($this->arg('blockto')) {
|
} elseif ($this->arg('blockto')) {
|
||||||
|
@ -102,7 +103,6 @@ class BlockAction extends Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function showContent() {
|
function showContent() {
|
||||||
$this->areYouSureForm();
|
$this->areYouSureForm();
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ class BlockAction extends Action
|
||||||
function title() {
|
function title() {
|
||||||
return _('Block user');
|
return _('Block user');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeForm() {
|
function showNoticeForm() {
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
|
@ -178,10 +178,11 @@ class BlockAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action) {
|
if ($action) {
|
||||||
common_redirect(common_local_url($action, $args));
|
common_redirect(common_local_url($action, $args), 303);
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('subscriptions',
|
common_redirect(common_local_url('subscriptions',
|
||||||
array('nickname' => $cur->nickname)));
|
array('nickname' => $cur->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,6 @@ class DeletenoticeAction extends DeleteAction
|
||||||
$url = common_local_url('public');
|
$url = common_local_url('public');
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect($url);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ class DisfavorAction extends Action
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Class handler.
|
* Class handler.
|
||||||
*
|
*
|
||||||
* @param array $args query arguments
|
* @param array $args query arguments
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
@ -100,7 +100,8 @@ class DisfavorAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('showfavorites',
|
common_redirect(common_local_url('showfavorites',
|
||||||
array('nickname' => $user->nickname)));
|
array('nickname' => $user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,6 @@ class EditgroupAction extends Action
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
|
@ -221,7 +220,7 @@ class EditgroupAction extends Action
|
||||||
if ($this->group->nickname != $orig->nickname) {
|
if ($this->group->nickname != $orig->nickname) {
|
||||||
common_redirect(common_local_url('editgroup',
|
common_redirect(common_local_url('editgroup',
|
||||||
array('nickname' => $nickname)),
|
array('nickname' => $nickname)),
|
||||||
307);
|
303);
|
||||||
} else {
|
} else {
|
||||||
$this->showForm(_('Options saved.'));
|
$this->showForm(_('Options saved.'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class FavorAction extends Action
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Class handler.
|
* Class handler.
|
||||||
*
|
*
|
||||||
* @param array $args query arguments
|
* @param array $args query arguments
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
|
@ -100,13 +100,14 @@ class FavorAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('showfavorites',
|
common_redirect(common_local_url('showfavorites',
|
||||||
array('nickname' => $user->nickname)));
|
array('nickname' => $user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies a user when his notice is favorited.
|
* Notifies a user when his notice is favorited.
|
||||||
*
|
*
|
||||||
* @param class $notice favorited notice
|
* @param class $notice favorited notice
|
||||||
* @param class $user user declaring a favorite
|
* @param class $user user declaring a favorite
|
||||||
*
|
*
|
||||||
|
|
|
@ -104,9 +104,9 @@ class FavoritedAction extends Action
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
|
|
||||||
common_set_returnto($this->selfUrl());
|
common_set_returnto($this->selfUrl());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +145,22 @@ class FavoritedAction extends Action
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyList()
|
||||||
|
{
|
||||||
|
$message = _('Favorite notices appear on this page but no one has favorited one yet.') . ' ';
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local navigation
|
* Local navigation
|
||||||
*
|
*
|
||||||
|
@ -198,6 +214,10 @@ class FavoritedAction extends Action
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->showEmptyList();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'favorited');
|
$this->page, 'favorited');
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ class FeaturedAction extends Action
|
||||||
|
|
||||||
$featured_nicks = common_config('nickname', 'featured');
|
$featured_nicks = common_config('nickname', 'featured');
|
||||||
|
|
||||||
|
|
||||||
if (count($featured_nicks) > 0) {
|
if (count($featured_nicks) > 0) {
|
||||||
|
|
||||||
$quoted = array();
|
$quoted = array();
|
||||||
|
@ -118,7 +119,7 @@ class FeaturedAction extends Action
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
|
$user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
|
||||||
$user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
|
$user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
|
||||||
$user->orderBy('user.nickname ASC');
|
$user->orderBy(common_database_tablename('user') .'.nickname ASC');
|
||||||
|
|
||||||
$user->find();
|
$user->find();
|
||||||
|
|
||||||
|
@ -145,4 +146,4 @@ class FeaturedAction extends Action
|
||||||
$this->page, 'featured');
|
$this->page, 'featured');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ class FinishaddopenidAction extends Action
|
||||||
|
|
||||||
oid_set_last($display);
|
oid_set_last($display);
|
||||||
|
|
||||||
common_redirect(common_local_url('openidsettings'));
|
common_redirect(common_local_url('openidsettings'), 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,8 @@ class FinishopenidloginAction extends Action
|
||||||
common_rememberme($user);
|
common_rememberme($user);
|
||||||
}
|
}
|
||||||
unset($_SESSION['openid_rememberme']);
|
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()
|
function connectUser()
|
||||||
|
@ -324,7 +325,7 @@ class FinishopenidloginAction extends Action
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$nickname));
|
$nickname));
|
||||||
}
|
}
|
||||||
common_redirect($url);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bestNewNickname($display, $sreg)
|
function bestNewNickname($display, $sreg)
|
||||||
|
|
|
@ -230,7 +230,8 @@ class FinishremotesubscribeAction extends Action
|
||||||
# show up close to the top of the page
|
# show up close to the top of the page
|
||||||
|
|
||||||
common_redirect(common_local_url('subscribers', array('nickname' =>
|
common_redirect(common_local_url('subscribers', array('nickname' =>
|
||||||
$user->nickname)));
|
$user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_avatar($profile, $url)
|
function add_avatar($profile, $url)
|
||||||
|
|
|
@ -33,7 +33,24 @@ class FoafAction extends Action
|
||||||
function prepare($args)
|
function prepare($args)
|
||||||
{
|
{
|
||||||
parent::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);
|
$this->user = User::staticGet('nickname', $this->nickname);
|
||||||
|
|
||||||
|
@ -122,20 +139,30 @@ class FoafAction extends Action
|
||||||
|
|
||||||
if ($sub->find()) {
|
if ($sub->find()) {
|
||||||
while ($sub->fetch()) {
|
while ($sub->fetch()) {
|
||||||
if ($sub->token) {
|
if (!empty($sub->token)) {
|
||||||
$other = Remote_profile::staticGet('id', $sub->subscribed);
|
$other = Remote_profile::staticGet('id', $sub->subscribed);
|
||||||
} else {
|
} else {
|
||||||
$other = User::staticGet('id', $sub->subscribed);
|
$other = User::staticGet('id', $sub->subscribed);
|
||||||
}
|
}
|
||||||
if (!$other) {
|
if (empty($other)) {
|
||||||
common_debug('Got a bad subscription: '.print_r($sub,true));
|
common_debug('Got a bad subscription: '.print_r($sub,true));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$this->element('knows', array('rdf:resource' => $other->uri));
|
$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
|
// Get people who subscribe to user
|
||||||
|
|
||||||
$sub = new Subscription();
|
$sub = new Subscription();
|
||||||
|
@ -156,25 +183,36 @@ class FoafAction extends Action
|
||||||
if (array_key_exists($other->uri, $person)) {
|
if (array_key_exists($other->uri, $person)) {
|
||||||
$person[$other->uri][0] = BOTH;
|
$person[$other->uri][0] = BOTH;
|
||||||
} else {
|
} 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');
|
$this->elementEnd('Person');
|
||||||
|
|
||||||
foreach ($person as $uri => $p) {
|
foreach ($person as $uri => $p) {
|
||||||
$foaf_url = null;
|
$foaf_url = null;
|
||||||
if ($p[1] instanceof User) {
|
list($type, $id, $nickname, $cls) = $p;
|
||||||
$foaf_url = common_local_url('foaf', array('nickname' => $p[1]->nickname));
|
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));
|
$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->element('knows', array('rdf:resource' => $this->user->uri));
|
||||||
}
|
}
|
||||||
$this->showMicrobloggingAccount($this->profile, ($p[1] instanceof User) ?
|
$this->showMicrobloggingAccount($profile, ($cls == 'User') ?
|
||||||
common_root_url() : null);
|
common_root_url() : null);
|
||||||
if ($foaf_url) {
|
if ($foaf_url) {
|
||||||
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
|
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
|
||||||
}
|
}
|
||||||
|
@ -182,6 +220,9 @@ class FoafAction extends Action
|
||||||
if ($foaf_url) {
|
if ($foaf_url) {
|
||||||
$this->showPpd($foaf_url, $uri);
|
$this->showPpd($foaf_url, $uri);
|
||||||
}
|
}
|
||||||
|
$profile->free();
|
||||||
|
$profile = null;
|
||||||
|
unset($profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementEnd('rdf:RDF');
|
$this->elementEnd('rdf:RDF');
|
||||||
|
|
|
@ -72,12 +72,23 @@ class GroupsearchAction extends SearchAction
|
||||||
$terms = preg_split('/[\s,]+/', $q);
|
$terms = preg_split('/[\s,]+/', $q);
|
||||||
$results = new GroupSearchResults($user_group, $terms, $this);
|
$results = new GroupSearchResults($user_group, $terms, $this);
|
||||||
$results->show();
|
$results->show();
|
||||||
} else {
|
$user_group->free();
|
||||||
$this->element('p', 'error', _('No results'));
|
$this->pagination($page > 1, $cnt > GROUPS_PER_PAGE,
|
||||||
}
|
|
||||||
$user_group->free();
|
|
||||||
$this->pagination($page > 1, $cnt > GROUPS_PER_PAGE,
|
|
||||||
$page, 'groupsearch', array('q' => $q));
|
$page, 'groupsearch', array('q' => $q));
|
||||||
|
} else {
|
||||||
|
$this->element('p', 'error', _('No results.'));
|
||||||
|
$this->searchSuggestions($q);
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!');
|
||||||
|
}
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
$user_group->free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,10 +109,5 @@ class GroupSearchResults extends GroupList
|
||||||
{
|
{
|
||||||
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isReadOnly()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,8 @@ class JoingroupAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
||||||
$this->group->nickname)));
|
$this->group->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -147,7 +147,8 @@ class LeavegroupAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
||||||
$this->group->nickname)));
|
$this->group->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ class LoginAction extends Action
|
||||||
$nickname));
|
$nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect($url);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,10 +46,10 @@ require_once INSTALLDIR.'/lib/openid.php';
|
||||||
*/
|
*/
|
||||||
class LogoutAction extends Action
|
class LogoutAction extends Action
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is read only.
|
* This is read only.
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return boolean true
|
||||||
*/
|
*/
|
||||||
function isReadOnly()
|
function isReadOnly()
|
||||||
|
@ -59,7 +59,7 @@ class LogoutAction extends Action
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class handler.
|
* Class handler.
|
||||||
*
|
*
|
||||||
* @param array $args array of arguments
|
* @param array $args array of arguments
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
|
@ -73,7 +73,7 @@ class LogoutAction extends Action
|
||||||
common_set_user(null);
|
common_set_user(null);
|
||||||
common_real_login(false); // not logged in
|
common_real_login(false); // not logged in
|
||||||
common_forgetme(); // don't log back in!
|
common_forgetme(); // don't log back in!
|
||||||
common_redirect(common_local_url('public'));
|
common_redirect(common_local_url('public'), 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ class NewgroupAction extends Action
|
||||||
|
|
||||||
$group->query('COMMIT');
|
$group->query('COMMIT');
|
||||||
|
|
||||||
common_redirect($group->homeUrl(), 307);
|
common_redirect($group->homeUrl(), 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
function nicknameExists($nickname)
|
function nicknameExists($nickname)
|
||||||
|
|
|
@ -114,22 +114,27 @@ class NoticesearchAction extends SearchAction
|
||||||
$cnt = $notice->find();
|
$cnt = $notice->find();
|
||||||
}
|
}
|
||||||
if ($cnt === 0) {
|
if ($cnt === 0) {
|
||||||
$this->element('p', 'error', _('No results'));
|
$this->element('p', 'error', _('No results.'));
|
||||||
|
|
||||||
|
$this->searchSuggestions($q);
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$terms = preg_split('/[\s,]+/', $q);
|
$terms = preg_split('/[\s,]+/', $q);
|
||||||
$nl = new SearchNoticeList($notice, $this, $terms);
|
$nl = new SearchNoticeList($notice, $this, $terms);
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
|
||||||
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$page, 'noticesearch', array('q' => $q));
|
$page, 'noticesearch', array('q' => $q));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isReadOnly()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchNoticeList extends NoticeList {
|
class SearchNoticeList extends NoticeList {
|
||||||
|
|
|
@ -50,7 +50,7 @@ class NudgeAction extends Action
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Class handler.
|
* Class handler.
|
||||||
*
|
*
|
||||||
* @param array $args array of arguments
|
* @param array $args array of arguments
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
|
@ -75,7 +75,7 @@ class NudgeAction extends Action
|
||||||
|
|
||||||
// CSRF protection
|
// CSRF protection
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
|
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$this->clientError(_('There was a problem with your session token. Try again, please.'));
|
$this->clientError(_('There was a problem with your session token. Try again, please.'));
|
||||||
return;
|
return;
|
||||||
|
@ -100,7 +100,8 @@ class NudgeAction extends Action
|
||||||
} else {
|
} else {
|
||||||
// display a confirmation to the user
|
// display a confirmation to the user
|
||||||
common_redirect(common_local_url('showstream',
|
common_redirect(common_local_url('showstream',
|
||||||
array('nickname' => $other->nickname)));
|
array('nickname' => $other->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,14 +60,8 @@ class PeoplesearchAction extends SearchAction
|
||||||
|
|
||||||
function showResults($q, $page)
|
function showResults($q, $page)
|
||||||
{
|
{
|
||||||
|
|
||||||
$profile = new Profile();
|
$profile = new Profile();
|
||||||
|
|
||||||
// lcase it for comparison
|
|
||||||
// $q = strtolower($q);
|
|
||||||
|
|
||||||
$search_engine = $profile->getSearchEngine('identica_people');
|
$search_engine = $profile->getSearchEngine('identica_people');
|
||||||
|
|
||||||
$search_engine->set_sort_mode('chron');
|
$search_engine->set_sort_mode('chron');
|
||||||
// Ask for an extra to see if there's more.
|
// Ask for an extra to see if there's more.
|
||||||
$search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);
|
$search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);
|
||||||
|
@ -81,14 +75,15 @@ class PeoplesearchAction extends SearchAction
|
||||||
$terms = preg_split('/[\s,]+/', $q);
|
$terms = preg_split('/[\s,]+/', $q);
|
||||||
$results = new PeopleSearchResults($profile, $terms, $this);
|
$results = new PeopleSearchResults($profile, $terms, $this);
|
||||||
$results->show();
|
$results->show();
|
||||||
} else {
|
$profile->free();
|
||||||
$this->element('p', 'error', _('No results'));
|
$this->pagination($page > 1, $cnt > PROFILES_PER_PAGE,
|
||||||
}
|
|
||||||
|
|
||||||
$profile->free();
|
|
||||||
|
|
||||||
$this->pagination($page > 1, $cnt > PROFILES_PER_PAGE,
|
|
||||||
$page, 'peoplesearch', array('q' => $q));
|
$page, 'peoplesearch', array('q' => $q));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->element('p', 'error', _('No results.'));
|
||||||
|
$this->searchSuggestions($q);
|
||||||
|
$profile->free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,6 +166,22 @@ class PublicAction extends Action
|
||||||
$nav->show();
|
$nav->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyList()
|
||||||
|
{
|
||||||
|
$message = _('This is the public timeline for %%site.name%% but no one 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', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the content area
|
* Fill the content area
|
||||||
*
|
*
|
||||||
|
@ -189,6 +205,10 @@ class PublicAction extends Action
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->showEmptyList();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'public');
|
$this->page, 'public');
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,22 @@ class PublictagcloudAction extends Action
|
||||||
common_config('site', 'name')));
|
common_config('site', 'name')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyList()
|
||||||
|
{
|
||||||
|
$message = _('No one 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', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
function showLocalNav()
|
function showLocalNav()
|
||||||
{
|
{
|
||||||
$nav = new PublicGroupNav($this);
|
$nav = new PublicGroupNav($this);
|
||||||
|
@ -126,6 +142,8 @@ class PublictagcloudAction extends Action
|
||||||
$this->elementEnd('dd');
|
$this->elementEnd('dd');
|
||||||
$this->elementEnd('dl');
|
$this->elementEnd('dl');
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
|
} else {
|
||||||
|
$this->showEmptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,9 +97,9 @@ class RemotesubscribeAction extends Action
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
'action' => common_local_url('remotesubscribe')));
|
'action' => common_local_url('remotesubscribe')));
|
||||||
$this->elementStart('fieldset');
|
$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->hidden('token', common_session_token());
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('nickname', _('User nickname'), $this->nickname,
|
$this->input('nickname', _('User nickname'), $this->nickname,
|
||||||
|
@ -407,7 +407,7 @@ class RemotesubscribeAction extends Action
|
||||||
|
|
||||||
# Redirect to authorization service
|
# Redirect to authorization service
|
||||||
|
|
||||||
common_redirect($req->to_url());
|
common_redirect($req->to_url(), 303);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,12 +166,36 @@ class RepliesAction extends Action
|
||||||
$nl = new NoticeList($notice, $this);
|
$nl = new NoticeList($notice, $this);
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
if (0 === $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'replies',
|
$this->page, 'replies',
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
$message = sprintf(_('This is the timeline showing replies to %s but %s hasn\'t received a notice to his attention yet.'), $this->user->nickname, $this->user->nickname) . ' ';
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).');
|
||||||
|
} else {
|
||||||
|
$message .= sprintf(_('You can try to [nudge %s](../%s) or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
function isReadOnly()
|
function isReadOnly()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -162,6 +162,25 @@ class ShowfavoritesAction extends Action
|
||||||
$nav->show();
|
$nav->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
|
||||||
|
} else {
|
||||||
|
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to thier favorites :)'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the content
|
* Show the content
|
||||||
*
|
*
|
||||||
|
@ -183,9 +202,17 @@ class ShowfavoritesAction extends Action
|
||||||
$nl = new NoticeList($notice, $this);
|
$nl = new NoticeList($notice, $this);
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $nl->show();
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'showfavorites',
|
$this->page, 'showfavorites',
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showPageNotice() {
|
||||||
|
$this->element('p', 'instructions', _('This is a way to share what you like.'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,17 @@ class ShowgroupAction extends Action
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
|
if (!empty($this->group->fullname)) {
|
||||||
|
$base = $this->group->fullname . ' (' . $this->group->nickname . ')';
|
||||||
|
} else {
|
||||||
|
$base = $this->group->nickname;
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("%s group"), $this->group->nickname);
|
return sprintf(_("%s group"), $base);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%s group, page %d"),
|
return sprintf(_("%s group, page %d"),
|
||||||
$this->group->nickname,
|
$base,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,12 +54,8 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ShowstreamAction extends Action
|
class ShowstreamAction extends ProfileAction
|
||||||
{
|
{
|
||||||
var $user = null;
|
|
||||||
var $page = null;
|
|
||||||
var $profile = null;
|
|
||||||
|
|
||||||
function isReadOnly()
|
function isReadOnly()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -67,54 +63,21 @@ class ShowstreamAction extends Action
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
|
if (!empty($this->profile->fullname)) {
|
||||||
|
$base = $this->profile->fullname . ' (' . $this->user->nickname . ') ';
|
||||||
|
} else {
|
||||||
|
$base = $this->user->nickname;
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return $this->user->nickname;
|
return $base;
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%s, page %d"),
|
return sprintf(_("%s, page %d"),
|
||||||
$this->user->nickname,
|
$base,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepare($args)
|
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$nickname_arg = $this->arg('nickname');
|
|
||||||
$nickname = common_canonical_nickname($nickname_arg);
|
|
||||||
|
|
||||||
// Permanent redirect on non-canonical nickname
|
|
||||||
|
|
||||||
if ($nickname_arg != $nickname) {
|
|
||||||
$args = array('nickname' => $nickname);
|
|
||||||
if ($this->arg('page') && $this->arg('page') != 1) {
|
|
||||||
$args['page'] = $this->arg['page'];
|
|
||||||
}
|
|
||||||
common_redirect(common_local_url('showstream', $args), 301);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->user = User::staticGet('nickname', $nickname);
|
|
||||||
|
|
||||||
if (!$this->user) {
|
|
||||||
$this->clientError(_('No such user.'), 404);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->profile = $this->user->getProfile();
|
|
||||||
|
|
||||||
if (!$this->profile) {
|
|
||||||
$this->serverError(_('User has no profile.'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
|
||||||
|
|
||||||
common_set_returnto($this->selfUrl());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -140,16 +103,6 @@ class ShowstreamAction extends Action
|
||||||
$nav->show();
|
$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()
|
function showPageNoticeBlock()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -376,167 +329,41 @@ class ShowstreamAction extends Action
|
||||||
_('Subscribe'));
|
_('Subscribe'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
$message = sprintf(_('This is the timeline for %s but %s hasn\'t posted anything yet.'), $this->user->nickname, $this->user->nickname) . ' ';
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)');
|
||||||
|
} else {
|
||||||
|
$message .= sprintf(_('You can try to nudge %s or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, '@' . $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
function showNotices()
|
function showNotices()
|
||||||
{
|
{
|
||||||
$notice = $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
$notice = $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||||
|
|
||||||
$pnl = new ProfileNoticeList($notice, $this);
|
$pnl = new ProfileNoticeList($notice, $this);
|
||||||
$cnt = $pnl->show();
|
$cnt = $pnl->show();
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
|
$this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
|
||||||
'showstream', array('nickname' => $this->user->nickname));
|
'showstream', array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSections()
|
|
||||||
{
|
|
||||||
$this->showSubscriptions();
|
|
||||||
$this->showSubscribers();
|
|
||||||
$this->showGroups();
|
|
||||||
$this->showStatistics();
|
|
||||||
$cloud = new PersonalTagCloudSection($this, $this->user);
|
|
||||||
$cloud->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSubscriptions()
|
|
||||||
{
|
|
||||||
$profile = $this->user->getSubscriptions(0, PROFILES_PER_MINILIST + 1);
|
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
|
||||||
'class' => 'section'));
|
|
||||||
|
|
||||||
$this->element('h2', null, _('Subscriptions'));
|
|
||||||
|
|
||||||
if ($profile) {
|
|
||||||
$pml = new ProfileMiniList($profile, $this->user, $this);
|
|
||||||
$cnt = $pml->show();
|
|
||||||
if ($cnt == 0) {
|
|
||||||
$this->element('p', null, _('(None)'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cnt > PROFILES_PER_MINILIST) {
|
|
||||||
$this->elementStart('p');
|
|
||||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
|
||||||
array('nickname' => $this->profile->nickname)),
|
|
||||||
'class' => 'more'),
|
|
||||||
_('All subscriptions'));
|
|
||||||
$this->elementEnd('p');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSubscribers()
|
|
||||||
{
|
|
||||||
$profile = $this->user->getSubscribers(0, PROFILES_PER_MINILIST + 1);
|
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_subscribers',
|
|
||||||
'class' => 'section'));
|
|
||||||
|
|
||||||
$this->element('h2', null, _('Subscribers'));
|
|
||||||
|
|
||||||
if ($profile) {
|
|
||||||
$pml = new ProfileMiniList($profile, $this->user, $this);
|
|
||||||
$cnt = $pml->show();
|
|
||||||
if ($cnt == 0) {
|
|
||||||
$this->element('p', null, _('(None)'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cnt > PROFILES_PER_MINILIST) {
|
|
||||||
$this->elementStart('p');
|
|
||||||
$this->element('a', array('href' => common_local_url('subscribers',
|
|
||||||
array('nickname' => $this->profile->nickname)),
|
|
||||||
'class' => 'more'),
|
|
||||||
_('All subscribers'));
|
|
||||||
$this->elementEnd('p');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
|
||||||
|
|
||||||
function showStatistics()
|
|
||||||
{
|
|
||||||
// XXX: WORM cache this
|
|
||||||
$subs = new Subscription();
|
|
||||||
$subs->subscriber = $this->profile->id;
|
|
||||||
$subs_count = (int) $subs->count() - 1;
|
|
||||||
|
|
||||||
$subbed = new Subscription();
|
|
||||||
$subbed->subscribed = $this->profile->id;
|
|
||||||
$subbed_count = (int) $subbed->count() - 1;
|
|
||||||
|
|
||||||
$notices = new Notice();
|
|
||||||
$notices->profile_id = $this->profile->id;
|
|
||||||
$notice_count = (int) $notices->count();
|
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_statistics',
|
|
||||||
'class' => 'section'));
|
|
||||||
|
|
||||||
$this->element('h2', null, _('Statistics'));
|
|
||||||
|
|
||||||
// Other stats...?
|
|
||||||
$this->elementStart('dl', 'entity_member-since');
|
|
||||||
$this->element('dt', null, _('Member since'));
|
|
||||||
$this->element('dd', null, date('j M Y',
|
|
||||||
strtotime($this->profile->created)));
|
|
||||||
$this->elementEnd('dl');
|
|
||||||
|
|
||||||
$this->elementStart('dl', 'entity_subscriptions');
|
|
||||||
$this->elementStart('dt');
|
|
||||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
|
||||||
array('nickname' => $this->profile->nickname))),
|
|
||||||
_('Subscriptions'));
|
|
||||||
$this->elementEnd('dt');
|
|
||||||
$this->element('dd', null, (is_int($subs_count)) ? $subs_count : '0');
|
|
||||||
$this->elementEnd('dl');
|
|
||||||
|
|
||||||
$this->elementStart('dl', 'entity_subscribers');
|
|
||||||
$this->elementStart('dt');
|
|
||||||
$this->element('a', array('href' => common_local_url('subscribers',
|
|
||||||
array('nickname' => $this->profile->nickname))),
|
|
||||||
_('Subscribers'));
|
|
||||||
$this->elementEnd('dt');
|
|
||||||
$this->element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
|
|
||||||
$this->elementEnd('dl');
|
|
||||||
|
|
||||||
$this->elementStart('dl', 'entity_notices');
|
|
||||||
$this->element('dt', null, _('Notices'));
|
|
||||||
$this->element('dd', null, (is_int($notice_count)) ? $notice_count : '0');
|
|
||||||
$this->elementEnd('dl');
|
|
||||||
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
|
||||||
|
|
||||||
function showGroups()
|
|
||||||
{
|
|
||||||
$groups = $this->user->getGroups(0, GROUPS_PER_MINILIST + 1);
|
|
||||||
|
|
||||||
$this->elementStart('div', array('id' => 'entity_groups',
|
|
||||||
'class' => 'section'));
|
|
||||||
|
|
||||||
$this->element('h2', null, _('Groups'));
|
|
||||||
|
|
||||||
if ($groups) {
|
|
||||||
$gml = new GroupMiniList($groups, $this->user, $this);
|
|
||||||
$cnt = $gml->show();
|
|
||||||
if ($cnt == 0) {
|
|
||||||
$this->element('p', null, _('(None)'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cnt > GROUPS_PER_MINILIST) {
|
|
||||||
$this->elementStart('p');
|
|
||||||
$this->element('a', array('href' => common_local_url('usergroups',
|
|
||||||
array('nickname' => $this->profile->nickname)),
|
|
||||||
'class' => 'more'),
|
|
||||||
_('All groups'));
|
|
||||||
$this->elementEnd('p');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementEnd('div');
|
|
||||||
}
|
|
||||||
|
|
||||||
function showAnonymousMessage()
|
function showAnonymousMessage()
|
||||||
{
|
{
|
||||||
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||||
|
@ -554,6 +381,12 @@ class ShowstreamAction extends Action
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSections()
|
||||||
|
{
|
||||||
|
parent::showSections();
|
||||||
|
$cloud = new PersonalTagCloudSection($this, $this->user);
|
||||||
|
$cloud->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't show the author for a profile, since we already know who it is!
|
// We don't show the author for a profile, since we already know who it is!
|
||||||
|
|
|
@ -488,7 +488,8 @@ class SmssettingsAction extends ConnectSettingsAction
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect(common_local_url('confirmaddress',
|
common_redirect(common_local_url('confirmaddress',
|
||||||
array('code' => $code)));
|
array('code' => $code)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -85,7 +85,8 @@ class SubeditAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
common_redirect(common_local_url('subscriptions',
|
common_redirect(common_local_url('subscriptions',
|
||||||
array('nickname' => $cur->nickname)));
|
array('nickname' => $cur->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,8 @@ class SubscribeAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
||||||
$user->nickname)));
|
$user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,9 @@ class SubscribersAction extends GalleryAction
|
||||||
if ($subscribers) {
|
if ($subscribers) {
|
||||||
$subscribers_list = new SubscribersList($subscribers, $this->user, $this);
|
$subscribers_list = new SubscribersList($subscribers, $this->user, $this);
|
||||||
$cnt = $subscribers_list->show();
|
$cnt = $subscribers_list->show();
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$subscribers->free();
|
$subscribers->free();
|
||||||
|
@ -96,6 +99,25 @@ class SubscribersAction extends GalleryAction
|
||||||
$this->page, 'subscribers',
|
$this->page, 'subscribers',
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message = _('You have no subscribers. Try subscribing to people you know and they might return the favor');
|
||||||
|
} else {
|
||||||
|
$message = sprintf(_('%s has no subscribers. Want to be the first?'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscribersList extends ProfileList
|
class SubscribersList extends ProfileList
|
||||||
|
|
|
@ -95,6 +95,9 @@ class SubscriptionsAction extends GalleryAction
|
||||||
if ($subscriptions) {
|
if ($subscriptions) {
|
||||||
$subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this);
|
$subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this);
|
||||||
$cnt = $subscriptions_list->show();
|
$cnt = $subscriptions_list->show();
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$subscriptions->free();
|
$subscriptions->free();
|
||||||
|
@ -103,6 +106,25 @@ class SubscriptionsAction extends GalleryAction
|
||||||
$this->page, 'subscriptions',
|
$this->page, 'subscriptions',
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message = _('You\'re not listening to anyone\'s notices right now, try subscribing to people you know. Try [people search](%%action.peoplesearch%%), look for members in groups you\'re interested in and in our [featured users](%%action.featured%%). If you\'re a [Twitter user](%%action.twittersettings%%), you can automatically subscribe to people you already follow there.');
|
||||||
|
} else {
|
||||||
|
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscriptionsList extends ProfileList
|
class SubscriptionsList extends ProfileList
|
||||||
|
@ -117,7 +139,7 @@ class SubscriptionsList extends ProfileList
|
||||||
|
|
||||||
$this->out->elementStart('form', array('id' => 'subedit-' . $profile->id,
|
$this->out->elementStart('form', array('id' => 'subedit-' . $profile->id,
|
||||||
'method' => 'post',
|
'method' => 'post',
|
||||||
'class' => 'form_subcription_edit',
|
'class' => 'form_subscription_edit',
|
||||||
'action' => common_local_url('subedit')));
|
'action' => common_local_url('subedit')));
|
||||||
$this->out->hidden('token', common_session_token());
|
$this->out->hidden('token', common_session_token());
|
||||||
$this->out->hidden('profile', $profile->id);
|
$this->out->hidden('profile', $profile->id);
|
||||||
|
|
|
@ -45,7 +45,7 @@ class SupAction extends Action
|
||||||
function availablePeriods()
|
function availablePeriods()
|
||||||
{
|
{
|
||||||
static $periods = array(86400, 43200, 21600, 7200,
|
static $periods = array(86400, 43200, 21600, 7200,
|
||||||
3600, 1800, 600, 300, 120,
|
3600, 1800, 600, 300, 120,
|
||||||
60, 30, 15);
|
60, 30, 15);
|
||||||
$available = array();
|
$available = array();
|
||||||
foreach ($periods as $period) {
|
foreach ($periods as $period) {
|
||||||
|
|
|
@ -33,7 +33,9 @@ class TagAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->tag != $taginput) {
|
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;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
|
|
|
@ -221,7 +221,8 @@ class TagotherAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url($action, array('nickname' =>
|
common_redirect(common_local_url($action, array('nickname' =>
|
||||||
$user->nickname)));
|
$user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,10 +116,11 @@ class UnblockAction extends Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($action) {
|
if ($action) {
|
||||||
common_redirect(common_local_url($action, $args));
|
common_redirect(common_local_url($action, $args), 303);
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('subscriptions',
|
common_redirect(common_local_url('subscriptions',
|
||||||
array('nickname' => $cur->nickname)));
|
array('nickname' => $cur->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,8 @@ class UnsubscribeAction extends Action
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
||||||
$user->nickname)));
|
$user->nickname)),
|
||||||
|
303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ define('TIMESTAMP_THRESHOLD', 300);
|
||||||
class UserauthorizationAction extends Action
|
class UserauthorizationAction extends Action
|
||||||
{
|
{
|
||||||
var $error;
|
var $error;
|
||||||
var $req;
|
var $params;
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
|
@ -35,8 +35,8 @@ class UserauthorizationAction extends Action
|
||||||
# CSRF protection
|
# CSRF protection
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$req = $this->getStoredRequest();
|
$params = $this->getStoredParams();
|
||||||
$this->showForm($req, _('There was a problem with your session token. '.
|
$this->showForm($params, _('There was a problem with your session token. '.
|
||||||
'Try again, please.'));
|
'Try again, please.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -50,18 +50,13 @@ class UserauthorizationAction extends Action
|
||||||
common_redirect(common_local_url('login'));
|
common_redirect(common_local_url('login'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# this must be a new request
|
$this->validateRequest();
|
||||||
$req = $this->getNewRequest();
|
$this->storeParams($_GET);
|
||||||
if (!$req) {
|
$this->showForm($_GET);
|
||||||
$this->clientError(_('No request found!'));
|
|
||||||
}
|
|
||||||
# XXX: only validate new requests, since nonce is one-time use
|
|
||||||
$this->validateRequest($req);
|
|
||||||
$this->storeRequest($req);
|
|
||||||
$this->showForm($req);
|
|
||||||
} catch (OAuthException $e) {
|
} catch (OAuthException $e) {
|
||||||
$this->clearRequest();
|
$this->clearParams();
|
||||||
$this->clientError($e->getMessage());
|
$this->clientError($e->getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -69,9 +64,9 @@ class UserauthorizationAction extends Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showForm($req, $error=null)
|
function showForm($params, $error=null)
|
||||||
{
|
{
|
||||||
$this->req = $req;
|
$this->params = $params;
|
||||||
$this->error = $error;
|
$this->error = $error;
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
@ -91,16 +86,16 @@ class UserauthorizationAction extends Action
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$req = $this->req;
|
$params = $this->params;
|
||||||
|
|
||||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
$nickname = $params['omb_listenee_nickname'];
|
||||||
$profile = $req->get_parameter('omb_listenee_profile');
|
$profile = $params['omb_listenee_profile'];
|
||||||
$license = $req->get_parameter('omb_listenee_license');
|
$license = $params['omb_listenee_license'];
|
||||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
$fullname = $params['omb_listenee_fullname'];
|
||||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
$homepage = $params['omb_listenee_homepage'];
|
||||||
$bio = $req->get_parameter('omb_listenee_bio');
|
$bio = $params['omb_listenee_bio'];
|
||||||
$location = $req->get_parameter('omb_listenee_location');
|
$location = $params['omb_listenee_location'];
|
||||||
$avatar = $req->get_parameter('omb_listenee_avatar');
|
$avatar = $params['omb_listenee_avatar'];
|
||||||
|
|
||||||
$this->elementStart('div', 'profile');
|
$this->elementStart('div', 'profile');
|
||||||
if ($avatar) {
|
if ($avatar) {
|
||||||
|
@ -147,56 +142,56 @@ class UserauthorizationAction extends Action
|
||||||
|
|
||||||
function sendAuthorization()
|
function sendAuthorization()
|
||||||
{
|
{
|
||||||
$req = $this->getStoredRequest();
|
$params = $this->getStoredParams();
|
||||||
|
|
||||||
if (!$req) {
|
if (!$params) {
|
||||||
$this->clientError(_('No authorization request!'));
|
$this->clientError(_('No authorization request!'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$callback = $req->get_parameter('oauth_callback');
|
$callback = $params['oauth_callback'];
|
||||||
|
|
||||||
if ($this->arg('accept')) {
|
if ($this->arg('accept')) {
|
||||||
if (!$this->authorizeToken($req)) {
|
if (!$this->authorizeToken($params)) {
|
||||||
$this->clientError(_('Error authorizing token'));
|
$this->clientError(_('Error authorizing token'));
|
||||||
}
|
}
|
||||||
if (!$this->saveRemoteProfile($req)) {
|
if (!$this->saveRemoteProfile($params)) {
|
||||||
$this->clientError(_('Error saving remote profile'));
|
$this->clientError(_('Error saving remote profile'));
|
||||||
}
|
}
|
||||||
if (!$callback) {
|
if (!$callback) {
|
||||||
$this->showAcceptMessage($req->get_parameter('oauth_token'));
|
$this->showAcceptMessage($params['oauth_token']);
|
||||||
} else {
|
} else {
|
||||||
$params = array();
|
$newparams = array();
|
||||||
$params['oauth_token'] = $req->get_parameter('oauth_token');
|
$newparams['oauth_token'] = $params['oauth_token'];
|
||||||
$params['omb_version'] = OMB_VERSION_01;
|
$newparams['omb_version'] = OMB_VERSION_01;
|
||||||
$user = User::staticGet('uri', $req->get_parameter('omb_listener'));
|
$user = User::staticGet('uri', $params['omb_listener']);
|
||||||
$profile = $user->getProfile();
|
$profile = $user->getProfile();
|
||||||
if (!$profile) {
|
if (!$profile) {
|
||||||
common_log_db_error($user, 'SELECT', __FILE__);
|
common_log_db_error($user, 'SELECT', __FILE__);
|
||||||
$this->serverError(_('User without matching profile'));
|
$this->serverError(_('User without matching profile'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$params['omb_listener_nickname'] = $user->nickname;
|
$newparams['omb_listener_nickname'] = $user->nickname;
|
||||||
$params['omb_listener_profile'] = common_local_url('showstream',
|
$newparams['omb_listener_profile'] = common_local_url('showstream',
|
||||||
array('nickname' => $user->nickname));
|
array('nickname' => $user->nickname));
|
||||||
if (!is_null($profile->fullname)) {
|
if (!is_null($profile->fullname)) {
|
||||||
$params['omb_listener_fullname'] = $profile->fullname;
|
$newparams['omb_listener_fullname'] = $profile->fullname;
|
||||||
}
|
}
|
||||||
if (!is_null($profile->homepage)) {
|
if (!is_null($profile->homepage)) {
|
||||||
$params['omb_listener_homepage'] = $profile->homepage;
|
$newparams['omb_listener_homepage'] = $profile->homepage;
|
||||||
}
|
}
|
||||||
if (!is_null($profile->bio)) {
|
if (!is_null($profile->bio)) {
|
||||||
$params['omb_listener_bio'] = $profile->bio;
|
$newparams['omb_listener_bio'] = $profile->bio;
|
||||||
}
|
}
|
||||||
if (!is_null($profile->location)) {
|
if (!is_null($profile->location)) {
|
||||||
$params['omb_listener_location'] = $profile->location;
|
$newparams['omb_listener_location'] = $profile->location;
|
||||||
}
|
}
|
||||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
if ($avatar) {
|
if ($avatar) {
|
||||||
$params['omb_listener_avatar'] = $avatar->url;
|
$newparams['omb_listener_avatar'] = $avatar->url;
|
||||||
}
|
}
|
||||||
$parts = array();
|
$parts = array();
|
||||||
foreach ($params as $k => $v) {
|
foreach ($newparams as $k => $v) {
|
||||||
$parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v);
|
$parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v);
|
||||||
}
|
}
|
||||||
$query_string = implode('&', $parts);
|
$query_string = implode('&', $parts);
|
||||||
|
@ -214,12 +209,10 @@ class UserauthorizationAction extends Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorizeToken(&$req)
|
function authorizeToken(&$params)
|
||||||
{
|
{
|
||||||
$consumer_key = $req->get_parameter('oauth_consumer_key');
|
$token_field = $params['oauth_token'];
|
||||||
$token_field = $req->get_parameter('oauth_token');
|
|
||||||
$rt = new Token();
|
$rt = new Token();
|
||||||
$rt->consumer_key = $consumer_key;
|
|
||||||
$rt->tok = $token_field;
|
$rt->tok = $token_field;
|
||||||
$rt->type = 0;
|
$rt->type = 0;
|
||||||
$rt->state = 0;
|
$rt->state = 0;
|
||||||
|
@ -235,21 +228,21 @@ class UserauthorizationAction extends Action
|
||||||
|
|
||||||
# XXX: refactor with similar code in finishremotesubscribe.php
|
# XXX: refactor with similar code in finishremotesubscribe.php
|
||||||
|
|
||||||
function saveRemoteProfile(&$req)
|
function saveRemoteProfile(&$params)
|
||||||
{
|
{
|
||||||
# FIXME: we should really do this when the consumer comes
|
# FIXME: we should really do this when the consumer comes
|
||||||
# back for an access token. If they never do, we've got stuff in a
|
# back for an access token. If they never do, we've got stuff in a
|
||||||
# weird state.
|
# weird state.
|
||||||
|
|
||||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
$nickname = $params['omb_listenee_nickname'];
|
||||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
$fullname = $params['omb_listenee_fullname'];
|
||||||
$profile_url = $req->get_parameter('omb_listenee_profile');
|
$profile_url = $params['omb_listenee_profile'];
|
||||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
$homepage = $params['omb_listenee_homepage'];
|
||||||
$bio = $req->get_parameter('omb_listenee_bio');
|
$bio = $params['omb_listenee_bio'];
|
||||||
$location = $req->get_parameter('omb_listenee_location');
|
$location = $params['omb_listenee_location'];
|
||||||
$avatar_url = $req->get_parameter('omb_listenee_avatar');
|
$avatar_url = $params['omb_listenee_avatar'];
|
||||||
|
|
||||||
$listenee = $req->get_parameter('omb_listenee');
|
$listenee = $params['omb_listenee'];
|
||||||
$remote = Remote_profile::staticGet('uri', $listenee);
|
$remote = Remote_profile::staticGet('uri', $listenee);
|
||||||
|
|
||||||
if ($remote) {
|
if ($remote) {
|
||||||
|
@ -309,14 +302,11 @@ class UserauthorizationAction extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$datastore = omb_oauth_datastore();
|
|
||||||
$consumer = $this->getConsumer($datastore, $req);
|
|
||||||
$token = $this->getToken($datastore, $req, $consumer);
|
|
||||||
|
|
||||||
$sub = new Subscription();
|
$sub = new Subscription();
|
||||||
$sub->subscriber = $user->id;
|
$sub->subscriber = $user->id;
|
||||||
$sub->subscribed = $remote->id;
|
$sub->subscribed = $remote->id;
|
||||||
$sub->token = $token->key; # NOTE: request token, not valid for use!
|
$sub->token = $params['oauth_token']; # NOTE: request token, not valid for use!
|
||||||
$sub->created = DB_DataObject_Cast::dateTime(); # current time
|
$sub->created = DB_DataObject_Cast::dateTime(); # current time
|
||||||
|
|
||||||
if (!$sub->insert()) {
|
if (!$sub->insert()) {
|
||||||
|
@ -360,65 +350,59 @@ class UserauthorizationAction extends Action
|
||||||
common_show_footer();
|
common_show_footer();
|
||||||
}
|
}
|
||||||
|
|
||||||
function storeRequest($req)
|
function storeParams($params)
|
||||||
{
|
{
|
||||||
common_ensure_session();
|
common_ensure_session();
|
||||||
$_SESSION['userauthorizationrequest'] = $req;
|
$_SESSION['userauthorizationparams'] = $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearRequest()
|
function clearParams()
|
||||||
{
|
{
|
||||||
common_ensure_session();
|
common_ensure_session();
|
||||||
unset($_SESSION['userauthorizationrequest']);
|
unset($_SESSION['userauthorizationparams']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStoredRequest()
|
function getStoredParams()
|
||||||
{
|
{
|
||||||
common_ensure_session();
|
common_ensure_session();
|
||||||
$req = $_SESSION['userauthorizationrequest'];
|
$params = $_SESSION['userauthorizationparams'];
|
||||||
return $req;
|
return $params;
|
||||||
}
|
|
||||||
|
|
||||||
function getNewRequest()
|
|
||||||
{
|
|
||||||
common_remove_magic_from_request();
|
|
||||||
$req = OAuthRequest::from_request();
|
|
||||||
return $req;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Throws an OAuthException if anything goes wrong
|
# Throws an OAuthException if anything goes wrong
|
||||||
|
|
||||||
function validateRequest(&$req)
|
function validateRequest()
|
||||||
{
|
{
|
||||||
# OAuth stuff -- have to copy from OAuth.php since they're
|
/* Find token.
|
||||||
# all private methods, and there's no user-authentication method
|
TODO: If no token is passed the user should get a prompt to enter it
|
||||||
$this->checkVersion($req);
|
according to OAuth Core 1.0 */
|
||||||
$datastore = omb_oauth_datastore();
|
$t = new Token();
|
||||||
$consumer = $this->getConsumer($datastore, $req);
|
$t->tok = $_GET['oauth_token'];
|
||||||
$token = $this->getToken($datastore, $req, $consumer);
|
$t->type = 0;
|
||||||
$this->checkTimestamp($req);
|
if (!$t->find(true)) {
|
||||||
$this->checkNonce($datastore, $req, $consumer, $token);
|
throw new OAuthException("Invalid request token: " . $_GET['oauth_token']);
|
||||||
$this->checkSignature($req, $consumer, $token);
|
}
|
||||||
$this->validateOmb($req);
|
|
||||||
|
$this->validateOmb();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateOmb(&$req)
|
function validateOmb()
|
||||||
{
|
{
|
||||||
foreach (array('omb_version', 'omb_listener', 'omb_listenee',
|
foreach (array('omb_version', 'omb_listener', 'omb_listenee',
|
||||||
'omb_listenee_profile', 'omb_listenee_nickname',
|
'omb_listenee_profile', 'omb_listenee_nickname',
|
||||||
'omb_listenee_license') as $param)
|
'omb_listenee_license') as $param)
|
||||||
{
|
{
|
||||||
if (is_null($req->get_parameter($param))) {
|
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
|
||||||
throw new OAuthException("Required parameter '$param' not found");
|
throw new OAuthException("Required parameter '$param' not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Now, OMB stuff
|
# Now, OMB stuff
|
||||||
$version = $req->get_parameter('omb_version');
|
$version = $_GET['omb_version'];
|
||||||
if ($version != OMB_VERSION_01) {
|
if ($version != OMB_VERSION_01) {
|
||||||
throw new OAuthException("OpenMicroBlogging version '$version' not supported");
|
throw new OAuthException("OpenMicroBlogging version '$version' not supported");
|
||||||
}
|
}
|
||||||
$listener = $req->get_parameter('omb_listener');
|
$listener = $_GET['omb_listener'];
|
||||||
$user = User::staticGet('uri', $listener);
|
$user = User::staticGet('uri', $listener);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
throw new OAuthException("Listener URI '$listener' not found here");
|
throw new OAuthException("Listener URI '$listener' not found here");
|
||||||
|
@ -427,7 +411,7 @@ class UserauthorizationAction extends Action
|
||||||
if ($cur->id != $user->id) {
|
if ($cur->id != $user->id) {
|
||||||
throw new OAuthException("Can't add for another user!");
|
throw new OAuthException("Can't add for another user!");
|
||||||
}
|
}
|
||||||
$listenee = $req->get_parameter('omb_listenee');
|
$listenee = $_GET['omb_listenee'];
|
||||||
if (!Validate::uri($listenee) &&
|
if (!Validate::uri($listenee) &&
|
||||||
!common_valid_tag($listenee)) {
|
!common_valid_tag($listenee)) {
|
||||||
throw new OAuthException("Listenee URI '$listenee' not a recognizable URI");
|
throw new OAuthException("Listenee URI '$listenee' not a recognizable URI");
|
||||||
|
@ -450,13 +434,13 @@ class UserauthorizationAction extends Action
|
||||||
throw new OAuthException("Already subscribed to user!");
|
throw new OAuthException("Already subscribed to user!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
$nickname = $_GET['omb_listenee_nickname'];
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||||
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
||||||
}
|
}
|
||||||
$profile = $req->get_parameter('omb_listenee_profile');
|
$profile = $_GET['omb_listenee_profile'];
|
||||||
if (!common_valid_http_url($profile)) {
|
if (!common_valid_http_url($profile)) {
|
||||||
throw new OAuthException("Invalid profile URL '$profile'.");
|
throw new OAuthException("Invalid profile URL '$profile'.");
|
||||||
}
|
}
|
||||||
|
@ -465,7 +449,7 @@ class UserauthorizationAction extends Action
|
||||||
throw new OAuthException("Profile URL '$profile' is for a local user.");
|
throw new OAuthException("Profile URL '$profile' is for a local user.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$license = $req->get_parameter('omb_listenee_license');
|
$license = $_GET['omb_listenee_license'];
|
||||||
if (!common_valid_http_url($license)) {
|
if (!common_valid_http_url($license)) {
|
||||||
throw new OAuthException("Invalid license URL '$license'.");
|
throw new OAuthException("Invalid license URL '$license'.");
|
||||||
}
|
}
|
||||||
|
@ -474,23 +458,23 @@ class UserauthorizationAction extends Action
|
||||||
throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'.");
|
throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'.");
|
||||||
}
|
}
|
||||||
# optional stuff
|
# optional stuff
|
||||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
$fullname = $_GET['omb_listenee_fullname'];
|
||||||
if ($fullname && mb_strlen($fullname) > 255) {
|
if ($fullname && mb_strlen($fullname) > 255) {
|
||||||
throw new OAuthException("Full name '$fullname' too long.");
|
throw new OAuthException("Full name '$fullname' too long.");
|
||||||
}
|
}
|
||||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
$homepage = $_GET['omb_listenee_homepage'];
|
||||||
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
|
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
|
||||||
throw new OAuthException("Invalid homepage '$homepage'");
|
throw new OAuthException("Invalid homepage '$homepage'");
|
||||||
}
|
}
|
||||||
$bio = $req->get_parameter('omb_listenee_bio');
|
$bio = $_GET['omb_listenee_bio'];
|
||||||
if ($bio && mb_strlen($bio) > 140) {
|
if ($bio && mb_strlen($bio) > 140) {
|
||||||
throw new OAuthException("Bio too long '$bio'");
|
throw new OAuthException("Bio too long '$bio'");
|
||||||
}
|
}
|
||||||
$location = $req->get_parameter('omb_listenee_location');
|
$location = $_GET['omb_listenee_location'];
|
||||||
if ($location && mb_strlen($location) > 255) {
|
if ($location && mb_strlen($location) > 255) {
|
||||||
throw new OAuthException("Location too long '$location'");
|
throw new OAuthException("Location too long '$location'");
|
||||||
}
|
}
|
||||||
$avatar = $req->get_parameter('omb_listenee_avatar');
|
$avatar = $_GET['omb_listenee_avatar'];
|
||||||
if ($avatar) {
|
if ($avatar) {
|
||||||
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
|
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
|
||||||
throw new OAuthException("Invalid avatar URL '$avatar'");
|
throw new OAuthException("Invalid avatar URL '$avatar'");
|
||||||
|
@ -507,7 +491,7 @@ class UserauthorizationAction extends Action
|
||||||
throw new OAuthException("Wrong image type for '$avatar'");
|
throw new OAuthException("Wrong image type for '$avatar'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$callback = $req->get_parameter('oauth_callback');
|
$callback = $_GET['oauth_callback'];
|
||||||
if ($callback && !common_valid_http_url($callback)) {
|
if ($callback && !common_valid_http_url($callback)) {
|
||||||
throw new OAuthException("Invalid callback URL '$callback'");
|
throw new OAuthException("Invalid callback URL '$callback'");
|
||||||
}
|
}
|
||||||
|
@ -515,92 +499,4 @@ class UserauthorizationAction extends Action
|
||||||
throw new OAuthException("Callback URL '$callback' is for local site.");
|
throw new OAuthException("Callback URL '$callback' is for local site.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Snagged from OAuthServer
|
|
||||||
|
|
||||||
function checkVersion(&$req)
|
|
||||||
{
|
|
||||||
$version = $req->get_parameter("oauth_version");
|
|
||||||
if (!$version) {
|
|
||||||
$version = 1.0;
|
|
||||||
}
|
|
||||||
if ($version != 1.0) {
|
|
||||||
throw new OAuthException("OAuth version '$version' not supported");
|
|
||||||
}
|
|
||||||
return $version;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Snagged from OAuthServer
|
|
||||||
|
|
||||||
function getConsumer($datastore, $req)
|
|
||||||
{
|
|
||||||
$consumer_key = @$req->get_parameter("oauth_consumer_key");
|
|
||||||
if (!$consumer_key) {
|
|
||||||
throw new OAuthException("Invalid consumer key");
|
|
||||||
}
|
|
||||||
|
|
||||||
$consumer = $datastore->lookup_consumer($consumer_key);
|
|
||||||
if (!$consumer) {
|
|
||||||
throw new OAuthException("Invalid consumer");
|
|
||||||
}
|
|
||||||
return $consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Mostly cadged from OAuthServer
|
|
||||||
|
|
||||||
function getToken($datastore, &$req, $consumer)
|
|
||||||
{/*{{{*/
|
|
||||||
$token_field = @$req->get_parameter('oauth_token');
|
|
||||||
$token = $datastore->lookup_token($consumer, 'request', $token_field);
|
|
||||||
if (!$token) {
|
|
||||||
throw new OAuthException("Invalid $token_type token: $token_field");
|
|
||||||
}
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkTimestamp(&$req)
|
|
||||||
{
|
|
||||||
$timestamp = @$req->get_parameter('oauth_timestamp');
|
|
||||||
$now = time();
|
|
||||||
if ($now - $timestamp > TIMESTAMP_THRESHOLD) {
|
|
||||||
throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# NOTE: don't call twice on the same request; will fail!
|
|
||||||
function checkNonce(&$datastore, &$req, $consumer, $token)
|
|
||||||
{
|
|
||||||
$timestamp = @$req->get_parameter('oauth_timestamp');
|
|
||||||
$nonce = @$req->get_parameter('oauth_nonce');
|
|
||||||
$found = $datastore->lookup_nonce($consumer, $token, $nonce, $timestamp);
|
|
||||||
if ($found) {
|
|
||||||
throw new OAuthException("Nonce already used");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkSignature(&$req, $consumer, $token)
|
|
||||||
{
|
|
||||||
$signature_method = $this->getSignatureMethod($req);
|
|
||||||
$signature = $req->get_parameter('oauth_signature');
|
|
||||||
$valid_sig = $signature_method->check_signature($req,
|
|
||||||
$consumer,
|
|
||||||
$token,
|
|
||||||
$signature);
|
|
||||||
if (!$valid_sig) {
|
|
||||||
throw new OAuthException("Invalid signature");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSignatureMethod(&$req)
|
|
||||||
{
|
|
||||||
$signature_method = @$req->get_parameter("oauth_signature_method");
|
|
||||||
if (!$signature_method) {
|
|
||||||
$signature_method = "PLAINTEXT";
|
|
||||||
}
|
|
||||||
if ($signature_method != 'HMAC-SHA1') {
|
|
||||||
throw new OAuthException("Signature method '$signature_method' not supported.");
|
|
||||||
}
|
|
||||||
return omb_hmac_sha1();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,10 +139,28 @@ class UsergroupsAction extends Action
|
||||||
if ($groups) {
|
if ($groups) {
|
||||||
$gl = new GroupList($groups, $this->user, $this);
|
$gl = new GroupList($groups, $this->user, $this);
|
||||||
$cnt = $gl->show();
|
$cnt = $gl->show();
|
||||||
|
if (0 == $cnt) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||||
$this->page, 'usergroups',
|
$this->page, 'usergroups',
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
$message = sprintf(_('%s is not a member of any group.'), $this->user->nickname) . ' ';
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$current_user = common_current_user();
|
||||||
|
if ($this->user->id === $current_user->id) {
|
||||||
|
$message .= _('Try [searching for groups](%%action.groupsearch%%) and joining them.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ class Notice extends Memcached_DataObject
|
||||||
$this->blowSubsCache(true);
|
$this->blowSubsCache(true);
|
||||||
|
|
||||||
$this->query('BEGIN');
|
$this->query('BEGIN');
|
||||||
|
//Null any notices that are replies to this notice
|
||||||
|
$this->query(sprintf("UPDATE notice set reply_to = null WHERE reply_to = %d", $this->id));
|
||||||
$related = array('Reply',
|
$related = array('Reply',
|
||||||
'Fave',
|
'Fave',
|
||||||
'Notice_tag',
|
'Notice_tag',
|
||||||
|
|
145
classes/User.php
145
classes/User.php
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* Laconica - a distributed open-source microblogging tool
|
* 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
|
* 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
|
* 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/>.
|
* 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
|
* Table Definition for user
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
require_once 'Validate.php';
|
require_once 'Validate.php';
|
||||||
|
|
||||||
|
@ -79,13 +82,13 @@ class User extends Memcached_DataObject
|
||||||
function isSubscribed($other)
|
function isSubscribed($other)
|
||||||
{
|
{
|
||||||
assert(!is_null($other));
|
assert(!is_null($other));
|
||||||
# XXX: cache results of this query
|
// XXX: cache results of this query
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' => $this->id,
|
$sub = Subscription::pkeyGet(array('subscriber' => $this->id,
|
||||||
'subscribed' => $other->id));
|
'subscribed' => $other->id));
|
||||||
return (is_null($sub)) ? false : true;
|
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)
|
function updateKeys(&$orig)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +99,7 @@ class User extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($parts) == 0) {
|
if (count($parts) == 0) {
|
||||||
# No changes
|
// No changes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$toupdate = implode(', ', $parts);
|
$toupdate = implode(', ', $parts);
|
||||||
|
@ -117,7 +120,7 @@ class User extends Memcached_DataObject
|
||||||
|
|
||||||
function allowed_nickname($nickname)
|
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',
|
static $blacklist = array('rss', 'xrds', 'doc', 'main',
|
||||||
'settings', 'notice', 'user',
|
'settings', 'notice', 'user',
|
||||||
'search', 'avatar', 'tag', 'tags',
|
'search', 'avatar', 'tag', 'tags',
|
||||||
|
@ -147,7 +150,7 @@ class User extends Memcached_DataObject
|
||||||
$sub->subscriber = $this->id;
|
$sub->subscriber = $this->id;
|
||||||
$sub->subscribed = $other->id;
|
$sub->subscribed = $other->id;
|
||||||
|
|
||||||
$sub->created = common_sql_now(); # current time
|
$sub->created = common_sql_now(); // current time
|
||||||
|
|
||||||
if (!$sub->insert()) {
|
if (!$sub->insert()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -173,7 +176,7 @@ class User extends Memcached_DataObject
|
||||||
|
|
||||||
static function register($fields) {
|
static function register($fields) {
|
||||||
|
|
||||||
# MAGICALLY put fields into current scope
|
// MAGICALLY put fields into current scope
|
||||||
|
|
||||||
extract($fields);
|
extract($fields);
|
||||||
|
|
||||||
|
@ -211,11 +214,11 @@ class User extends Memcached_DataObject
|
||||||
$user->id = $id;
|
$user->id = $id;
|
||||||
$user->nickname = $nickname;
|
$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);
|
$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)) {
|
if (!empty($code)) {
|
||||||
$invite = Invitation::staticGet($code);
|
$invite = Invitation::staticGet($code);
|
||||||
|
@ -240,7 +243,7 @@ class User extends Memcached_DataObject
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Everyone is subscribed to themself
|
// Everyone is subscribed to themself
|
||||||
|
|
||||||
$subscription = new Subscription();
|
$subscription = new Subscription();
|
||||||
$subscription->subscriber = $user->id;
|
$subscription->subscriber = $user->id;
|
||||||
|
@ -273,16 +276,58 @@ class User extends Memcached_DataObject
|
||||||
$user->emailChanged();
|
$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');
|
$profile->query('COMMIT');
|
||||||
|
|
||||||
if ($email && !$user->email) {
|
if ($email && !$user->email) {
|
||||||
mail_confirm_address($user, $confirm->code, $profile->nickname, $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;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Things we do when the email changes
|
// Things we do when the email changes
|
||||||
|
|
||||||
function emailChanged()
|
function emailChanged()
|
||||||
{
|
{
|
||||||
|
@ -303,46 +348,46 @@ class User extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
|
|
||||||
# XXX: Kind of a hack.
|
// XXX: Kind of a hack.
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
# This is the stream of favorite notices, in rev chron
|
// This is the stream of favorite notices, in rev chron
|
||||||
# order. This forces it into cache.
|
// order. This forces it into cache.
|
||||||
$faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
|
$faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
while ($faves->fetch()) {
|
while ($faves->fetch()) {
|
||||||
if ($faves->id < $notice->id) {
|
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;
|
return false;
|
||||||
} else if ($faves->id == $notice->id) {
|
} 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;
|
return true;
|
||||||
}
|
}
|
||||||
$cnt++;
|
$cnt++;
|
||||||
}
|
}
|
||||||
# If we're not past the end of the cache window,
|
// If we're not past the end of the cache window,
|
||||||
# then the cache has all available faves, so this one
|
// then the cache has all available faves, so this one
|
||||||
# is not a fave.
|
// is not a fave.
|
||||||
if ($cnt < NOTICE_CACHE_WINDOW) {
|
if ($cnt < NOTICE_CACHE_WINDOW) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
# Otherwise, cache doesn't have all faves;
|
// Otherwise, cache doesn't have all faves;
|
||||||
# fall through to the default
|
// fall through to the default
|
||||||
}
|
}
|
||||||
$fave = Fave::pkeyGet(array('user_id' => $this->id,
|
$fave = Fave::pkeyGet(array('user_id' => $this->id,
|
||||||
'notice_id' => $notice->id));
|
'notice_id' => $notice->id));
|
||||||
return ((is_null($fave)) ? false : true);
|
return ((is_null($fave)) ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mutuallySubscribed($other)
|
function mutuallySubscribed($other)
|
||||||
{
|
{
|
||||||
return $this->isSubscribed($other) &&
|
return $this->isSubscribed($other) &&
|
||||||
$other->isSubscribed($this);
|
$other->isSubscribed($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mutuallySubscribedUsers()
|
function mutuallySubscribedUsers()
|
||||||
{
|
{
|
||||||
|
// 3-way join; probably should get cached
|
||||||
# 3-way join; probably should get cached
|
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
|
||||||
$qry = "SELECT $UT.* " .
|
$qry = "SELECT $UT.* " .
|
||||||
"FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
|
"FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
|
||||||
"JOIN subscription sub2 ON $UT.id = sub2.subscriber " .
|
"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);
|
$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();
|
$profile = $this->getProfile();
|
||||||
if (!$profile) {
|
if (!$profile) {
|
||||||
return null;
|
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 =
|
$qry =
|
||||||
'SELECT notice.* ' .
|
'SELECT notice.* ' .
|
||||||
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
||||||
|
@ -386,12 +431,12 @@ class User extends Memcached_DataObject
|
||||||
$offset, $limit);
|
$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');
|
$enabled = common_config('inboxes', 'enabled');
|
||||||
|
|
||||||
# Complicated code, depending on whether we support inboxes yet
|
// Complicated code, depending on whether we support inboxes yet
|
||||||
# XXX: make this go away when inboxes become mandatory
|
// XXX: make this go away when inboxes become mandatory
|
||||||
|
|
||||||
if ($enabled === false ||
|
if ($enabled === false ||
|
||||||
($enabled == 'transitional' && $this->inboxed == 0)) {
|
($enabled == 'transitional' && $this->inboxed == 0)) {
|
||||||
|
@ -401,13 +446,13 @@ class User extends Memcached_DataObject
|
||||||
'WHERE subscription.subscriber = %d ';
|
'WHERE subscription.subscriber = %d ';
|
||||||
$order = null;
|
$order = null;
|
||||||
} else if ($enabled === true ||
|
} else if ($enabled === true ||
|
||||||
($enabled == 'transitional' && $this->inboxed == 1)) {
|
($enabled == 'transitional' && $this->inboxed == 1)) {
|
||||||
|
|
||||||
$qry =
|
$qry =
|
||||||
'SELECT notice.* ' .
|
'SELECT notice.* ' .
|
||||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||||
'WHERE notice_inbox.user_id = %d ';
|
'WHERE notice_inbox.user_id = %d ';
|
||||||
# NOTE: we override ORDER
|
// NOTE: we override ORDER
|
||||||
$order = null;
|
$order = null;
|
||||||
}
|
}
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
return Notice::getStream(sprintf($qry, $this->id),
|
||||||
|
@ -416,35 +461,34 @@ class User extends Memcached_DataObject
|
||||||
$order, $since);
|
$order, $since);
|
||||||
}
|
}
|
||||||
|
|
||||||
function blowFavesCache()
|
function blowFavesCache()
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
# Faves don't happen chronologically, so we need to blow
|
// Faves don't happen chronologically, so we need to blow
|
||||||
# ;last cache, too
|
// ;last cache, too
|
||||||
$cache->delete(common_cache_key('user:faves:'.$this->id));
|
$cache->delete(common_cache_key('user:faves:'.$this->id));
|
||||||
$cache->delete(common_cache_key('user:faves:'.$this->id).';last');
|
$cache->delete(common_cache_key('user:faves:'.$this->id).';last');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSelfTags()
|
function getSelfTags()
|
||||||
{
|
{
|
||||||
return Profile_tag::getTags($this->id, $this->id);
|
return Profile_tag::getTags($this->id, $this->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSelfTags($newtags)
|
function setSelfTags($newtags)
|
||||||
{
|
{
|
||||||
return Profile_tag::setTags($this->id, $this->id, $newtags);
|
return Profile_tag::setTags($this->id, $this->id, $newtags);
|
||||||
}
|
}
|
||||||
|
|
||||||
function block($other)
|
function block($other)
|
||||||
{
|
{
|
||||||
|
// Add a new block record
|
||||||
# Add a new block record
|
|
||||||
|
|
||||||
$block = new Profile_block();
|
$block = new Profile_block();
|
||||||
|
|
||||||
# Begin a transaction
|
// Begin a transaction
|
||||||
|
|
||||||
$block->query('BEGIN');
|
$block->query('BEGIN');
|
||||||
|
|
||||||
|
@ -458,7 +502,7 @@ class User extends Memcached_DataObject
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cancel their subscription, if it exists
|
// Cancel their subscription, if it exists
|
||||||
|
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' => $other->id,
|
$sub = Subscription::pkeyGet(array('subscriber' => $other->id,
|
||||||
'subscribed' => $this->id));
|
'subscribed' => $this->id));
|
||||||
|
@ -478,8 +522,7 @@ class User extends Memcached_DataObject
|
||||||
|
|
||||||
function unblock($other)
|
function unblock($other)
|
||||||
{
|
{
|
||||||
|
// Get the block record
|
||||||
# Get the block record
|
|
||||||
|
|
||||||
$block = Profile_block::get($this->id, $other->id);
|
$block = Profile_block::get($this->id, $other->id);
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,10 @@ $config['sphinx']['port'] = 3312;
|
||||||
# require_once('plugins/GoogleAnalyticsPlugin.php');
|
# require_once('plugins/GoogleAnalyticsPlugin.php');
|
||||||
# $ga = new GoogleAnalyticsPlugin('your secret code');
|
# $ga = new GoogleAnalyticsPlugin('your secret code');
|
||||||
|
|
||||||
|
# Use Templating (template: /tpl/index.php)
|
||||||
|
# require_once('plugins/TemplatePlugin.php');
|
||||||
|
# $tpl = new TemplatePlugin();
|
||||||
|
|
||||||
#Don't allow saying the same thing more than once per hour
|
#Don't allow saying the same thing more than once per hour
|
||||||
#$config['site']['dupelimit'] = 3600;
|
#$config['site']['dupelimit'] = 3600;
|
||||||
#Don't enforce the dupe limit
|
#Don't enforce the dupe limit
|
||||||
|
@ -174,3 +178,13 @@ $config['sphinx']['port'] = 3312;
|
||||||
#http://taguri.org/ Examples:
|
#http://taguri.org/ Examples:
|
||||||
#$config['integration']['taguri'] = 'example.net,2008';
|
#$config['integration']['taguri'] = 'example.net,2008';
|
||||||
#$config['integration']['taguri'] = 'admin@example.net,2009-03-09'
|
#$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';
|
||||||
|
|
|
@ -13,7 +13,7 @@ create table profile (
|
||||||
|
|
||||||
index profile_nickname_idx (nickname),
|
index profile_nickname_idx (nickname),
|
||||||
FULLTEXT(nickname, fullname, location, bio, homepage)
|
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 (
|
create table avatar (
|
||||||
profile_id integer not null comment 'foreign key to profile table' references profile (id),
|
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',
|
modified timestamp comment 'date this record was modified',
|
||||||
|
|
||||||
index user_smsemail_idx (smsemail)
|
index user_smsemail_idx (smsemail)
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
/* remote people */
|
/* remote people */
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ create table subscription (
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table notice (
|
create table notice (
|
||||||
|
|
||||||
id integer auto_increment primary key comment 'unique identifier',
|
id integer auto_increment primary key comment 'unique identifier',
|
||||||
profile_id integer not null comment 'who made the update' references profile (id),
|
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',
|
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_profile_id_idx (profile_id),
|
||||||
index notice_created_idx (created),
|
index notice_created_idx (created),
|
||||||
FULLTEXT(content)
|
FULLTEXT(content)
|
||||||
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
create table notice_source (
|
create table notice_source (
|
||||||
code varchar(32) primary key not null comment 'source code',
|
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;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table reply (
|
create table reply (
|
||||||
|
|
||||||
notice_id integer not null comment 'notice that is the reply' references notice (id),
|
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),
|
profile_id integer not null comment 'profile replied to' references profile (id),
|
||||||
modified timestamp not null comment 'date this record was modified',
|
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;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table fave (
|
create table fave (
|
||||||
|
|
||||||
notice_id integer not null comment 'notice that is the favorite' references notice (id),
|
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),
|
user_id integer not null comment 'user who likes this notice' references user (id),
|
||||||
modified timestamp not null comment 'date this record was modified',
|
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;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table message (
|
create table message (
|
||||||
|
|
||||||
id integer auto_increment primary key comment 'unique identifier',
|
id integer auto_increment primary key comment 'unique identifier',
|
||||||
uri varchar(255) unique key comment 'universally 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),
|
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_from_idx (from_profile),
|
||||||
index message_to_idx (to_profile),
|
index message_to_idx (to_profile),
|
||||||
index message_created_idx (created)
|
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 (
|
create table notice_inbox (
|
||||||
|
|
||||||
user_id integer not null comment 'user receiving the message' references user (id),
|
user_id integer not null comment 'user receiving the message' references user (id),
|
||||||
notice_id integer not null comment 'notice received' references notice (id),
|
notice_id integer not null comment 'notice received' references notice (id),
|
||||||
created datetime not null comment 'date the notice was created',
|
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;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table profile_block (
|
create table profile_block (
|
||||||
|
|
||||||
blocker integer not null comment 'user making the block' references user (id),
|
blocker integer not null comment 'user making the block' references user (id),
|
||||||
blocked integer not null comment 'profile that is blocked' references profile (id),
|
blocked integer not null comment 'profile that is blocked' references profile (id),
|
||||||
modified timestamp comment 'date of blocking',
|
modified timestamp comment 'date of blocking',
|
||||||
|
@ -372,7 +366,6 @@ create table profile_block (
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table user_group (
|
create table user_group (
|
||||||
|
|
||||||
id integer auto_increment primary key comment 'unique identifier',
|
id integer auto_increment primary key comment 'unique identifier',
|
||||||
|
|
||||||
nickname varchar(64) unique key comment 'nickname for addressing',
|
nickname varchar(64) unique key comment 'nickname for addressing',
|
||||||
|
@ -391,10 +384,9 @@ create table user_group (
|
||||||
|
|
||||||
index user_group_nickname_idx (nickname)
|
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 (
|
create table group_member (
|
||||||
|
|
||||||
group_id integer not null comment 'foreign key to user_group' references user_group (id),
|
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),
|
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?',
|
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;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
create table related_group (
|
create table related_group (
|
||||||
|
|
||||||
group_id integer not null comment 'foreign key to user_group' references user_group (id),
|
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),
|
related_group_id integer not null comment 'foreign key to user_group' references user_group (id),
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ VALUES
|
||||||
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
|
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
|
||||||
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
|
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
|
||||||
('moconica','Moconica','http://moconica.com/', now()),
|
('moconica','Moconica','http://moconica.com/', now()),
|
||||||
|
('peoplebrowsr', 'PeopleBrowsr', 'http://www.peoplebrowsr.com/', now()),
|
||||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||||
|
@ -45,4 +46,5 @@ VALUES
|
||||||
('twitux','Twitux','http://live.gnome.org/DanielMorales/Twitux', now()),
|
('twitux','Twitux','http://live.gnome.org/DanielMorales/Twitux', now()),
|
||||||
('twitvim','TwitVim','http://vim.sourceforge.net/scripts/script.php?script_id=2204', now()),
|
('twitvim','TwitVim','http://vim.sourceforge.net/scripts/script.php?script_id=2204', now()),
|
||||||
('urfastr','urfastr','http://urfastr.net/', now()),
|
('urfastr','urfastr','http://urfastr.net/', now()),
|
||||||
('adium', 'Adium', 'http://www.adiumx.com/', now());
|
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
||||||
|
('yatca','Yatca','http://www.yatca.com/', now());
|
||||||
|
|
7
doc-src/bookmarklet
Normal file
7
doc-src/bookmarklet
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
A bookmarklet is a small piece of javascript code used as a bookmark. This one will let you post to %%site.name%% simply by selecting some text on a page and pressing the bookmarklet.
|
||||||
|
|
||||||
|
Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy.
|
||||||
|
|
||||||
|
<MTMarkdownOptions output='raw'>
|
||||||
|
<a href="javascript:var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=newnotice',l=d.location,e=encodeURIComponent,g=f+'&status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22 from '+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=800,height=570')){l.href=g;}}a();void(0);">Post to %%site.name%%</a>
|
||||||
|
</MTMarkdownOptions>
|
|
@ -30,3 +30,5 @@ Here are some documents that you might find helpful in understanding
|
||||||
* [OpenMicroBlogging](%%doc.openmublog%%) - subscribing to remote users
|
* [OpenMicroBlogging](%%doc.openmublog%%) - subscribing to remote users
|
||||||
* [Privacy](%%doc.privacy%%) - %%site.name%%'s privacy policy
|
* [Privacy](%%doc.privacy%%) - %%site.name%%'s privacy policy
|
||||||
* [Source](%%doc.source%%) - How to get the Laconica source code
|
* [Source](%%doc.source%%) - How to get the Laconica source code
|
||||||
|
* [Badge](%%doc.badge%%) - How to put a Laconica badge on your blog or homepage
|
||||||
|
* [Bookmarklet](%%doc.bookmarklet%%) - Bookmarklet for posting Web pages
|
499
js/jquery.js
vendored
499
js/jquery.js
vendored
|
@ -1,13 +1,13 @@
|
||||||
/*!
|
/*!
|
||||||
* jQuery JavaScript Library v1.3.1
|
* jQuery JavaScript Library v1.3.2
|
||||||
* http://jquery.com/
|
* http://jquery.com/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009 John Resig
|
* Copyright (c) 2009 John Resig
|
||||||
* Dual licensed under the MIT and GPL licenses.
|
* Dual licensed under the MIT and GPL licenses.
|
||||||
* http://docs.jquery.com/License
|
* http://docs.jquery.com/License
|
||||||
*
|
*
|
||||||
* Date: 2009-01-21 20:42:16 -0500 (Wed, 21 Jan 2009)
|
* Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
|
||||||
* Revision: 6158
|
* Revision: 6246
|
||||||
*/
|
*/
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
|
@ -88,14 +88,16 @@ jQuery.fn = jQuery.prototype = {
|
||||||
this.context = selector.context;
|
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
|
// Start with an empty selector
|
||||||
selector: "",
|
selector: "",
|
||||||
|
|
||||||
// The current version of jQuery being used
|
// 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
|
// The number of elements contained in the matched element set
|
||||||
size: function() {
|
size: function() {
|
||||||
|
@ -108,7 +110,7 @@ jQuery.fn = jQuery.prototype = {
|
||||||
return num === undefined ?
|
return num === undefined ?
|
||||||
|
|
||||||
// Return a 'clean' array
|
// Return a 'clean' array
|
||||||
jQuery.makeArray( this ) :
|
Array.prototype.slice.call( this ) :
|
||||||
|
|
||||||
// Return just the object
|
// Return just the object
|
||||||
this[ num ];
|
this[ num ];
|
||||||
|
@ -278,23 +280,21 @@ jQuery.fn = jQuery.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// For internal use only.
|
// 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,
|
push: [].push,
|
||||||
|
sort: [].sort,
|
||||||
|
splice: [].splice,
|
||||||
|
|
||||||
find: function( selector ) {
|
find: function( selector ) {
|
||||||
if ( this.length === 1 && !/,/.test(selector) ) {
|
if ( this.length === 1 ) {
|
||||||
var ret = this.pushStack( [], "find", selector );
|
var ret = this.pushStack( [], "find", selector );
|
||||||
ret.length = 0;
|
ret.length = 0;
|
||||||
jQuery.find( selector, this[0], ret );
|
jQuery.find( selector, this[0], ret );
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
var elems = jQuery.map(this, function(elem){
|
return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
|
||||||
return jQuery.find( selector, elem );
|
return jQuery.find( selector, elem );
|
||||||
});
|
})), "find", selector );
|
||||||
|
|
||||||
return this.pushStack( /[^+>] [^+>]/.test( selector ) ?
|
|
||||||
jQuery.unique( elems ) :
|
|
||||||
elems, "find", selector );
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -310,33 +310,37 @@ jQuery.fn = jQuery.prototype = {
|
||||||
// attributes in IE that are actually only stored
|
// attributes in IE that are actually only stored
|
||||||
// as properties will not be copied (such as the
|
// as properties will not be copied (such as the
|
||||||
// the name attribute on an input).
|
// the name attribute on an input).
|
||||||
var clone = this.cloneNode(true),
|
var html = this.outerHTML;
|
||||||
container = document.createElement("div");
|
if ( !html ) {
|
||||||
container.appendChild(clone);
|
var div = this.ownerDocument.createElement("div");
|
||||||
return jQuery.clean([container.innerHTML])[0];
|
div.appendChild( this.cloneNode(true) );
|
||||||
|
html = div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
|
||||||
} else
|
} else
|
||||||
return this.cloneNode(true);
|
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
|
// Copy the events from the original to the clone
|
||||||
if ( events === true )
|
if ( events === true ) {
|
||||||
this.find("*").andSelf().each(function(i){
|
var orig = this.find("*").andSelf(), i = 0;
|
||||||
if (this.nodeType == 3)
|
|
||||||
return;
|
|
||||||
var events = jQuery.data( this, "events" );
|
|
||||||
|
|
||||||
for ( var type in events )
|
ret.find("*").andSelf().each(function(){
|
||||||
for ( var handler in events[ type ] )
|
if ( this.nodeName !== orig[i].nodeName )
|
||||||
jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
|
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 the cloned set
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -355,14 +359,18 @@ jQuery.fn = jQuery.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
closest: function( selector ) {
|
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(){
|
return this.map(function(){
|
||||||
var cur = this;
|
var cur = this;
|
||||||
while ( cur && cur.ownerDocument ) {
|
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;
|
return cur;
|
||||||
|
}
|
||||||
cur = cur.parentNode;
|
cur = cur.parentNode;
|
||||||
|
closer++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -475,7 +483,7 @@ jQuery.fn = jQuery.prototype = {
|
||||||
html: function( value ) {
|
html: function( value ) {
|
||||||
return value === undefined ?
|
return value === undefined ?
|
||||||
(this[0] ?
|
(this[0] ?
|
||||||
this[0].innerHTML :
|
this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
|
||||||
null) :
|
null) :
|
||||||
this.empty().append( value );
|
this.empty().append( value );
|
||||||
},
|
},
|
||||||
|
@ -507,13 +515,13 @@ jQuery.fn = jQuery.prototype = {
|
||||||
if ( this[0] ) {
|
if ( this[0] ) {
|
||||||
var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
|
var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
|
||||||
scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
|
scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
|
||||||
first = fragment.firstChild,
|
first = fragment.firstChild;
|
||||||
extra = this.length > 1 ? fragment.cloneNode(true) : fragment;
|
|
||||||
|
|
||||||
if ( first )
|
if ( first )
|
||||||
for ( var i = 0, l = this.length; i < l; i++ )
|
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 )
|
if ( scripts )
|
||||||
jQuery.each( scripts, evalScript );
|
jQuery.each( scripts, evalScript );
|
||||||
}
|
}
|
||||||
|
@ -636,9 +644,7 @@ jQuery.extend({
|
||||||
|
|
||||||
// Evalulates a script in a global context
|
// Evalulates a script in a global context
|
||||||
globalEval: function( data ) {
|
globalEval: function( data ) {
|
||||||
data = jQuery.trim( data );
|
if ( data && /\S/.test(data) ) {
|
||||||
|
|
||||||
if ( data ) {
|
|
||||||
// Inspired by code by Andrea Giammarchi
|
// Inspired by code by Andrea Giammarchi
|
||||||
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
|
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
|
||||||
var head = document.getElementsByTagName("head")[0] || document.documentElement,
|
var head = document.getElementsByTagName("head")[0] || document.documentElement,
|
||||||
|
@ -741,26 +747,32 @@ jQuery.extend({
|
||||||
elem.style[ name ] = old[ name ];
|
elem.style[ name ] = old[ name ];
|
||||||
},
|
},
|
||||||
|
|
||||||
css: function( elem, name, force ) {
|
css: function( elem, name, force, extra ) {
|
||||||
if ( name == "width" || name == "height" ) {
|
if ( name == "width" || name == "height" ) {
|
||||||
var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
|
var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
|
||||||
|
|
||||||
function getWH() {
|
function getWH() {
|
||||||
val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
|
val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
|
||||||
var padding = 0, border = 0;
|
|
||||||
|
if ( extra === "border" )
|
||||||
|
return;
|
||||||
|
|
||||||
jQuery.each( which, function() {
|
jQuery.each( which, function() {
|
||||||
padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
|
if ( !extra )
|
||||||
border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
|
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();
|
getWH();
|
||||||
else
|
else
|
||||||
jQuery.swap( elem, props, getWH );
|
jQuery.swap( elem, props, getWH );
|
||||||
|
|
||||||
return Math.max(0, val);
|
return Math.max(0, Math.round(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
return jQuery.curCSS( elem, name, force );
|
return jQuery.curCSS( elem, name, force );
|
||||||
|
@ -866,7 +878,7 @@ jQuery.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trim whitespace, otherwise indexOf won't work as expected
|
// 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 =
|
var wrap =
|
||||||
// option or optgroup
|
// option or optgroup
|
||||||
|
@ -906,11 +918,12 @@ jQuery.extend({
|
||||||
if ( !jQuery.support.tbody ) {
|
if ( !jQuery.support.tbody ) {
|
||||||
|
|
||||||
// String was a <table>, *may* have spurious <tbody>
|
// String was a <table>, *may* have spurious <tbody>
|
||||||
var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
|
var hasBody = /<tbody/i.test(elem),
|
||||||
div.firstChild && div.firstChild.childNodes :
|
tbody = !tags.indexOf("<table") && !hasBody ?
|
||||||
|
div.firstChild && div.firstChild.childNodes :
|
||||||
|
|
||||||
// String was a bare <thead> or <tfoot>
|
// String was a bare <thead> or <tfoot>
|
||||||
wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
|
wrap[1] == "<table>" && !hasBody ?
|
||||||
div.childNodes :
|
div.childNodes :
|
||||||
[];
|
[];
|
||||||
|
|
||||||
|
@ -1189,13 +1202,16 @@ jQuery.each({
|
||||||
insertAfter: "after",
|
insertAfter: "after",
|
||||||
replaceAll: "replaceWith"
|
replaceAll: "replaceWith"
|
||||||
}, function(name, original){
|
}, function(name, original){
|
||||||
jQuery.fn[ name ] = function() {
|
jQuery.fn[ name ] = function( selector ) {
|
||||||
var args = arguments;
|
var ret = [], insert = jQuery( selector );
|
||||||
|
|
||||||
return this.each(function(){
|
for ( var i = 0, l = insert.length; i < l; i++ ) {
|
||||||
for ( var i = 0, length = args.length; i < length; i++ )
|
var elems = (i > 0 ? this.clone(true) : this).get();
|
||||||
jQuery( args[ i ] )[ original ]( this );
|
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() {
|
empty: function() {
|
||||||
// Remove element nodes and prevent memory leaks
|
// Remove element nodes and prevent memory leaks
|
||||||
jQuery( ">*", this ).remove();
|
jQuery(this).children().remove();
|
||||||
|
|
||||||
// Remove any remaining nodes
|
// Remove any remaining nodes
|
||||||
while ( this.firstChild )
|
while ( this.firstChild )
|
||||||
|
@ -1402,7 +1418,7 @@ jQuery.fn.extend({
|
||||||
*/
|
*/
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]+['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
|
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
|
||||||
done = 0,
|
done = 0,
|
||||||
toString = Object.prototype.toString;
|
toString = Object.prototype.toString;
|
||||||
|
|
||||||
|
@ -1507,6 +1523,19 @@ var Sizzle = function(selector, context, results, seed) {
|
||||||
|
|
||||||
if ( extra ) {
|
if ( extra ) {
|
||||||
Sizzle( extra, context, results, seed );
|
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;
|
return results;
|
||||||
|
@ -1548,7 +1577,8 @@ Sizzle.find = function(expr, context, isXML){
|
||||||
};
|
};
|
||||||
|
|
||||||
Sizzle.filter = function(expr, set, inplace, not){
|
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 ) {
|
while ( expr && set.length ) {
|
||||||
for ( var type in Expr.filter ) {
|
for ( var type in Expr.filter ) {
|
||||||
|
@ -1561,7 +1591,7 @@ Sizzle.filter = function(expr, set, inplace, not){
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Expr.preFilter[ type ] ) {
|
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 ) {
|
if ( !match ) {
|
||||||
anyFound = found = true;
|
anyFound = found = true;
|
||||||
|
@ -1606,8 +1636,6 @@ Sizzle.filter = function(expr, set, inplace, not){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr = expr.replace(/\s*,\s*/, "");
|
|
||||||
|
|
||||||
// Improper expression
|
// Improper expression
|
||||||
if ( expr == old ) {
|
if ( expr == old ) {
|
||||||
if ( anyFound == null ) {
|
if ( anyFound == null ) {
|
||||||
|
@ -1645,26 +1673,33 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
relative: {
|
relative: {
|
||||||
"+": function(checkSet, part){
|
"+": function(checkSet, part, isXML){
|
||||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
var isPartStr = typeof part === "string",
|
||||||
var elem = checkSet[i];
|
isTag = isPartStr && !/\W/.test(part),
|
||||||
if ( elem ) {
|
isPartStrNotTag = isPartStr && !isTag;
|
||||||
var cur = elem.previousSibling;
|
|
||||||
while ( cur && cur.nodeType !== 1 ) {
|
if ( isTag && !isXML ) {
|
||||||
cur = cur.previousSibling;
|
part = part.toUpperCase();
|
||||||
}
|
}
|
||||||
checkSet[i] = typeof part === "string" ?
|
|
||||||
cur || false :
|
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
|
||||||
cur === part;
|
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 );
|
Sizzle.filter( part, checkSet, true );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
">": function(checkSet, part, isXML){
|
">": 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();
|
part = isXML ? part : part.toUpperCase();
|
||||||
|
|
||||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
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++ ) {
|
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||||
var elem = checkSet[i];
|
var elem = checkSet[i];
|
||||||
if ( elem ) {
|
if ( elem ) {
|
||||||
checkSet[i] = typeof part === "string" ?
|
checkSet[i] = isPartStr ?
|
||||||
elem.parentNode :
|
elem.parentNode :
|
||||||
elem.parentNode === part;
|
elem.parentNode === part;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( typeof part === "string" ) {
|
if ( isPartStr ) {
|
||||||
Sizzle.filter( part, checkSet, true );
|
Sizzle.filter( part, checkSet, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"": function(checkSet, part, isXML){
|
"": function(checkSet, part, isXML){
|
||||||
var doneName = "done" + (done++), checkFn = dirCheck;
|
var doneName = done++, checkFn = dirCheck;
|
||||||
|
|
||||||
if ( !part.match(/\W/) ) {
|
if ( !part.match(/\W/) ) {
|
||||||
var nodeCheck = part = isXML ? part : part.toUpperCase();
|
var nodeCheck = part = isXML ? part : part.toUpperCase();
|
||||||
|
@ -1700,7 +1735,7 @@ var Expr = Sizzle.selectors = {
|
||||||
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
|
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
|
||||||
},
|
},
|
||||||
"~": function(checkSet, part, isXML){
|
"~": function(checkSet, part, isXML){
|
||||||
var doneName = "done" + (done++), checkFn = dirCheck;
|
var doneName = done++, checkFn = dirCheck;
|
||||||
|
|
||||||
if ( typeof part === "string" && !part.match(/\W/) ) {
|
if ( typeof part === "string" && !part.match(/\W/) ) {
|
||||||
var nodeCheck = part = isXML ? part : part.toUpperCase();
|
var nodeCheck = part = isXML ? part : part.toUpperCase();
|
||||||
|
@ -1718,8 +1753,16 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NAME: function(match, context, isXML){
|
NAME: function(match, context, isXML){
|
||||||
if ( typeof context.getElementsByName !== "undefined" && !isXML ) {
|
if ( typeof context.getElementsByName !== "undefined" ) {
|
||||||
return context.getElementsByName(match[1]);
|
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){
|
TAG: function(match, context){
|
||||||
|
@ -1727,13 +1770,16 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preFilter: {
|
preFilter: {
|
||||||
CLASS: function(match, curLoop, inplace, result, not){
|
CLASS: function(match, curLoop, inplace, result, not, isXML){
|
||||||
match = " " + match[1].replace(/\\/g, "") + " ";
|
match = " " + match[1].replace(/\\/g, "") + " ";
|
||||||
|
|
||||||
var elem;
|
if ( isXML ) {
|
||||||
for ( var i = 0; (elem = curLoop[i]) != null; i++ ) {
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
|
||||||
if ( elem ) {
|
if ( elem ) {
|
||||||
if ( not ^ (" " + elem.className + " ").indexOf(match) >= 0 ) {
|
if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
|
||||||
if ( !inplace )
|
if ( !inplace )
|
||||||
result.push( elem );
|
result.push( elem );
|
||||||
} else if ( inplace ) {
|
} else if ( inplace ) {
|
||||||
|
@ -1764,14 +1810,14 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to normal caching system
|
// TODO: Move to normal caching system
|
||||||
match[0] = "done" + (done++);
|
match[0] = done++;
|
||||||
|
|
||||||
return match;
|
return match;
|
||||||
},
|
},
|
||||||
ATTR: function(match){
|
ATTR: function(match, curLoop, inplace, result, not, isXML){
|
||||||
var name = match[1].replace(/\\/g, "");
|
var name = match[1].replace(/\\/g, "");
|
||||||
|
|
||||||
if ( Expr.attrMap[name] ) {
|
if ( !isXML && Expr.attrMap[name] ) {
|
||||||
match[1] = Expr.attrMap[name];
|
match[1] = Expr.attrMap[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1784,7 +1830,7 @@ var Expr = Sizzle.selectors = {
|
||||||
PSEUDO: function(match, curLoop, inplace, result, not){
|
PSEUDO: function(match, curLoop, inplace, result, not){
|
||||||
if ( match[1] === "not" ) {
|
if ( match[1] === "not" ) {
|
||||||
// If we're dealing with a complex expression, or a simple one
|
// 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);
|
match[3] = Sizzle(match[3], null, null, curLoop);
|
||||||
} else {
|
} else {
|
||||||
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
|
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
|
||||||
|
@ -1793,7 +1839,7 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1890,47 +1936,6 @@ var Expr = Sizzle.selectors = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filter: {
|
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){
|
PSEUDO: function(elem, match, i, array){
|
||||||
var name = match[1], filter = Expr.filters[ name ];
|
var name = match[1], filter = Expr.filters[ name ];
|
||||||
|
|
||||||
|
@ -1950,6 +1955,49 @@ var Expr = Sizzle.selectors = {
|
||||||
return true;
|
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){
|
ID: function(elem, match){
|
||||||
return elem.nodeType === 1 && elem.getAttribute("id") === 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;
|
return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
|
||||||
},
|
},
|
||||||
CLASS: function(elem, match){
|
CLASS: function(elem, match){
|
||||||
return match.test( elem.className );
|
return (" " + (elem.className || elem.getAttribute("class")) + " ")
|
||||||
|
.indexOf( match ) > -1;
|
||||||
},
|
},
|
||||||
ATTR: function(elem, match){
|
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 ?
|
return result == null ?
|
||||||
type === "!=" :
|
type === "!=" :
|
||||||
type === "=" ?
|
type === "=" ?
|
||||||
|
@ -1969,8 +2027,8 @@ var Expr = Sizzle.selectors = {
|
||||||
value.indexOf(check) >= 0 :
|
value.indexOf(check) >= 0 :
|
||||||
type === "~=" ?
|
type === "~=" ?
|
||||||
(" " + value + " ").indexOf(check) >= 0 :
|
(" " + value + " ").indexOf(check) >= 0 :
|
||||||
!match[4] ?
|
!check ?
|
||||||
result :
|
value && result !== false :
|
||||||
type === "!=" ?
|
type === "!=" ?
|
||||||
value != check :
|
value != check :
|
||||||
type === "^=" ?
|
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
|
// Check to see if the browser returns elements by name when
|
||||||
// querying by getElementById (and provide a workaround)
|
// querying by getElementById (and provide a workaround)
|
||||||
(function(){
|
(function(){
|
||||||
|
@ -2099,7 +2190,8 @@ try {
|
||||||
|
|
||||||
// Check to see if an attribute returns normalized href attributes
|
// Check to see if an attribute returns normalized href attributes
|
||||||
div.innerHTML = "<a href='#'></a>";
|
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){
|
Expr.attrHandle.href = function(elem){
|
||||||
return elem.getAttribute("href", 2);
|
return elem.getAttribute("href", 2);
|
||||||
};
|
};
|
||||||
|
@ -2136,29 +2228,50 @@ if ( document.querySelectorAll ) (function(){
|
||||||
Sizzle.matches = oldSizzle.matches;
|
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.order.splice(1, 0, "CLASS");
|
||||||
Expr.find.CLASS = function(match, context) {
|
Expr.find.CLASS = function(match, context, isXML) {
|
||||||
return context.getElementsByClassName(match[1]);
|
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
|
||||||
|
return context.getElementsByClassName(match[1]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
})();
|
||||||
|
|
||||||
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
|
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
|
||||||
|
var sibDir = dir == "previousSibling" && !isXML;
|
||||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||||
var elem = checkSet[i];
|
var elem = checkSet[i];
|
||||||
if ( elem ) {
|
if ( elem ) {
|
||||||
|
if ( sibDir && elem.nodeType === 1 ){
|
||||||
|
elem.sizcache = doneName;
|
||||||
|
elem.sizset = i;
|
||||||
|
}
|
||||||
elem = elem[dir];
|
elem = elem[dir];
|
||||||
var match = false;
|
var match = false;
|
||||||
|
|
||||||
while ( elem && elem.nodeType ) {
|
while ( elem ) {
|
||||||
var done = elem[doneName];
|
if ( elem.sizcache === doneName ) {
|
||||||
if ( done ) {
|
match = checkSet[elem.sizset];
|
||||||
match = checkSet[ done ];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( elem.nodeType === 1 && !isXML )
|
if ( elem.nodeType === 1 && !isXML ){
|
||||||
elem[doneName] = i;
|
elem.sizcache = doneName;
|
||||||
|
elem.sizset = i;
|
||||||
|
}
|
||||||
|
|
||||||
if ( elem.nodeName === cur ) {
|
if ( elem.nodeName === cur ) {
|
||||||
match = elem;
|
match = elem;
|
||||||
|
@ -2174,22 +2287,28 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function dirCheck( 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++ ) {
|
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||||
var elem = checkSet[i];
|
var elem = checkSet[i];
|
||||||
if ( elem ) {
|
if ( elem ) {
|
||||||
|
if ( sibDir && elem.nodeType === 1 ) {
|
||||||
|
elem.sizcache = doneName;
|
||||||
|
elem.sizset = i;
|
||||||
|
}
|
||||||
elem = elem[dir];
|
elem = elem[dir];
|
||||||
var match = false;
|
var match = false;
|
||||||
|
|
||||||
while ( elem && elem.nodeType ) {
|
while ( elem ) {
|
||||||
if ( elem[doneName] ) {
|
if ( elem.sizcache === doneName ) {
|
||||||
match = checkSet[ elem[doneName] ];
|
match = checkSet[elem.sizset];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( elem.nodeType === 1 ) {
|
if ( elem.nodeType === 1 ) {
|
||||||
if ( !isXML )
|
if ( !isXML ) {
|
||||||
elem[doneName] = i;
|
elem.sizcache = doneName;
|
||||||
|
elem.sizset = i;
|
||||||
|
}
|
||||||
if ( typeof cur !== "string" ) {
|
if ( typeof cur !== "string" ) {
|
||||||
if ( elem === cur ) {
|
if ( elem === cur ) {
|
||||||
match = true;
|
match = true;
|
||||||
|
@ -2248,15 +2367,11 @@ jQuery.expr = Sizzle.selectors;
|
||||||
jQuery.expr[":"] = jQuery.expr.filters;
|
jQuery.expr[":"] = jQuery.expr.filters;
|
||||||
|
|
||||||
Sizzle.selectors.filters.hidden = function(elem){
|
Sizzle.selectors.filters.hidden = function(elem){
|
||||||
return "hidden" === elem.type ||
|
return elem.offsetWidth === 0 || elem.offsetHeight === 0;
|
||||||
jQuery.css(elem, "display") === "none" ||
|
|
||||||
jQuery.css(elem, "visibility") === "hidden";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Sizzle.selectors.filters.visible = function(elem){
|
Sizzle.selectors.filters.visible = function(elem){
|
||||||
return "hidden" !== elem.type &&
|
return elem.offsetWidth > 0 || elem.offsetHeight > 0;
|
||||||
jQuery.css(elem, "display") !== "none" &&
|
|
||||||
jQuery.css(elem, "visibility") !== "hidden";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Sizzle.selectors.filters.animated = function(elem){
|
Sizzle.selectors.filters.animated = function(elem){
|
||||||
|
@ -2552,7 +2667,8 @@ jQuery.event = {
|
||||||
var all, handlers;
|
var all, handlers;
|
||||||
|
|
||||||
event = arguments[0] = jQuery.event.fix( event || window.event );
|
event = arguments[0] = jQuery.event.fix( event || window.event );
|
||||||
|
event.currentTarget = this;
|
||||||
|
|
||||||
// Namespaced event handlers
|
// Namespaced event handlers
|
||||||
var namespaces = event.type.split(".");
|
var namespaces = event.type.split(".");
|
||||||
event.type = namespaces.shift();
|
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(){
|
jQuery.each(elems, function(){
|
||||||
if ( this.fn.call(this.elem, event, this.fn.data) === false )
|
if ( this.fn.call(this.elem, event, this.fn.data) === false )
|
||||||
stop = false;
|
return (stop = false);
|
||||||
});
|
});
|
||||||
|
|
||||||
return stop;
|
return stop;
|
||||||
|
@ -2949,7 +3069,7 @@ function bindReady(){
|
||||||
|
|
||||||
// If IE and not an iframe
|
// If IE and not an iframe
|
||||||
// continually check to see if the document is ready
|
// 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;
|
if ( jQuery.isReady ) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -3079,12 +3199,11 @@ jQuery( window ).bind( 'unload', function(){
|
||||||
// document.body must exist before we can do this
|
// document.body must exist before we can do this
|
||||||
jQuery(function(){
|
jQuery(function(){
|
||||||
var div = document.createElement("div");
|
var div = document.createElement("div");
|
||||||
div.style.width = "1px";
|
div.style.width = div.style.paddingLeft = "1px";
|
||||||
div.style.paddingLeft = "1px";
|
|
||||||
|
|
||||||
document.body.appendChild( div );
|
document.body.appendChild( div );
|
||||||
jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
|
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(){
|
.filter(function(){
|
||||||
return this.name && !this.disabled &&
|
return this.name && !this.disabled &&
|
||||||
(this.checked || /select|textarea/i.test(this.nodeName) ||
|
(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){
|
.map(function(i, elem){
|
||||||
var val = jQuery(this).val();
|
var val = jQuery(this).val();
|
||||||
|
@ -3371,6 +3490,9 @@ jQuery.extend({
|
||||||
done = true;
|
done = true;
|
||||||
success();
|
success();
|
||||||
complete();
|
complete();
|
||||||
|
|
||||||
|
// Handle memory leak in IE
|
||||||
|
script.onload = script.onreadystatechange = null;
|
||||||
head.removeChild( script );
|
head.removeChild( script );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3686,9 +3808,15 @@ jQuery.fn.extend({
|
||||||
elemdisplay[ tagName ] = display;
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -3702,8 +3830,14 @@ jQuery.fn.extend({
|
||||||
var old = jQuery.data(this[i], "olddisplay");
|
var old = jQuery.data(this[i], "olddisplay");
|
||||||
if ( !old && old !== "none" )
|
if ( !old && old !== "none" )
|
||||||
jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
|
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";
|
this[i].style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -3915,7 +4049,7 @@ jQuery.fx.prototype = {
|
||||||
|
|
||||||
t.elem = this.elem;
|
t.elem = this.elem;
|
||||||
|
|
||||||
if ( t() && jQuery.timers.push(t) == 1 ) {
|
if ( t() && jQuery.timers.push(t) && !timerId ) {
|
||||||
timerId = setInterval(function(){
|
timerId = setInterval(function(){
|
||||||
var timers = jQuery.timers;
|
var timers = jQuery.timers;
|
||||||
|
|
||||||
|
@ -3925,6 +4059,7 @@ jQuery.fx.prototype = {
|
||||||
|
|
||||||
if ( !timers.length ) {
|
if ( !timers.length ) {
|
||||||
clearInterval( timerId );
|
clearInterval( timerId );
|
||||||
|
timerId = undefined;
|
||||||
}
|
}
|
||||||
}, 13);
|
}, 13);
|
||||||
}
|
}
|
||||||
|
@ -4193,22 +4328,21 @@ jQuery.each( ['Left', 'Top'], function(i, name) {
|
||||||
jQuery.each([ "Height", "Width" ], function(i, name){
|
jQuery.each([ "Height", "Width" ], function(i, name){
|
||||||
|
|
||||||
var tl = i ? "Left" : "Top", // top or left
|
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
|
// innerHeight and innerWidth
|
||||||
jQuery.fn["inner" + name] = function(){
|
jQuery.fn["inner" + name] = function(){
|
||||||
return this[ name.toLowerCase() ]() +
|
return this[0] ?
|
||||||
num(this, "padding" + tl) +
|
jQuery.css( this[0], lower, false, "padding" ) :
|
||||||
num(this, "padding" + br);
|
null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// outerHeight and outerWidth
|
// outerHeight and outerWidth
|
||||||
jQuery.fn["outer" + name] = function(margin) {
|
jQuery.fn["outer" + name] = function(margin) {
|
||||||
return this["inner" + name]() +
|
return this[0] ?
|
||||||
num(this, "border" + tl + "Width") +
|
jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
|
||||||
num(this, "border" + br + "Width") +
|
null;
|
||||||
(margin ?
|
|
||||||
num(this, "margin" + tl) + num(this, "margin" + br) : 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var type = name.toLowerCase();
|
var type = name.toLowerCase();
|
||||||
|
@ -4238,4 +4372,5 @@ jQuery.each([ "Height", "Width" ], function(i, name){
|
||||||
this.css( type, typeof size === "string" ? size : size + "px" );
|
this.css( type, typeof size === "string" ? size : size + "px" );
|
||||||
};
|
};
|
||||||
|
|
||||||
});})();
|
});
|
||||||
|
})();
|
||||||
|
|
10
js/jquery.min.js
vendored
10
js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -97,9 +97,18 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
$this->startHTML();
|
$this->startHTML();
|
||||||
Event::handle('EndShowHTML', array($this));
|
Event::handle('EndShowHTML', array($this));
|
||||||
}
|
}
|
||||||
|
if (Event::handle('StartShowHead', array($this))) {
|
||||||
$this->showHead();
|
$this->showHead();
|
||||||
|
Event::handle('EndShowHead', array($this));
|
||||||
|
}
|
||||||
|
if (Event::handle('StartShowBody', array($this))) {
|
||||||
$this->showBody();
|
$this->showBody();
|
||||||
|
Event::handle('EndShowBody', array($this));
|
||||||
|
}
|
||||||
|
if (Event::handle('StartEndHTML', array($this))) {
|
||||||
$this->endHTML();
|
$this->endHTML();
|
||||||
|
Event::handle('EndEndHTML', array($this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -326,7 +335,9 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
*/
|
*/
|
||||||
function showBody()
|
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'));
|
$this->elementStart('div', array('id' => 'wrap'));
|
||||||
if (Event::handle('StartShowHeader', array($this))) {
|
if (Event::handle('StartShowHeader', array($this))) {
|
||||||
$this->showHeader();
|
$this->showHeader();
|
||||||
|
@ -400,13 +411,8 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
$this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
||||||
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
||||||
}
|
|
||||||
$this->menuItem(common_local_url('peoplesearch'),
|
|
||||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
|
||||||
if ($user) {
|
|
||||||
$this->menuItem(common_local_url('profilesettings'),
|
$this->menuItem(common_local_url('profilesettings'),
|
||||||
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
||||||
|
|
||||||
if (common_config('xmpp', 'enabled')) {
|
if (common_config('xmpp', 'enabled')) {
|
||||||
$this->menuItem(common_local_url('imsettings'),
|
$this->menuItem(common_local_url('imsettings'),
|
||||||
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
||||||
|
@ -414,20 +420,28 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
$this->menuItem(common_local_url('smssettings'),
|
$this->menuItem(common_local_url('smssettings'),
|
||||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||||
}
|
}
|
||||||
|
$this->menuItem(common_local_url('invite'),
|
||||||
|
_('Invite'),
|
||||||
|
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||||
|
common_config('site', 'name')),
|
||||||
|
false, 'nav_invitecontact');
|
||||||
$this->menuItem(common_local_url('logout'),
|
$this->menuItem(common_local_url('logout'),
|
||||||
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
||||||
} else {
|
}
|
||||||
$this->menuItem(common_local_url('login'),
|
else {
|
||||||
_('Login'), _('Login to the site'), false, 'nav_login');
|
|
||||||
if (!common_config('site', 'closed')) {
|
if (!common_config('site', 'closed')) {
|
||||||
$this->menuItem(common_local_url('register'),
|
$this->menuItem(common_local_url('register'),
|
||||||
_('Register'), _('Create an account'), false, 'nav_register');
|
_('Register'), _('Create an account'), false, 'nav_register');
|
||||||
}
|
}
|
||||||
$this->menuItem(common_local_url('openidlogin'),
|
$this->menuItem(common_local_url('openidlogin'),
|
||||||
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
||||||
|
$this->menuItem(common_local_url('login'),
|
||||||
|
_('Login'), _('Login to the site'), false, 'nav_login');
|
||||||
}
|
}
|
||||||
$this->menuItem(common_local_url('doc', array('title' => 'help')),
|
$this->menuItem(common_local_url('doc', array('title' => 'help')),
|
||||||
_('Help'), _('Help me!'), false, 'nav_help');
|
_('Help'), _('Help me!'), false, 'nav_help');
|
||||||
|
$this->menuItem(common_local_url('peoplesearch'),
|
||||||
|
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||||
Event::handle('EndPrimaryNav', array($this));
|
Event::handle('EndPrimaryNav', array($this));
|
||||||
}
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
@ -604,7 +618,10 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
{
|
{
|
||||||
$this->elementStart('div', array('id' => 'aside_primary',
|
$this->elementStart('div', array('id' => 'aside_primary',
|
||||||
'class' => 'aside'));
|
'class' => 'aside'));
|
||||||
|
if (Event::handle('StartShowExportData', array($this))) {
|
||||||
$this->showExportData();
|
$this->showExportData();
|
||||||
|
Event::handle('EndShowExportData', array($this));
|
||||||
|
}
|
||||||
if (Event::handle('StartShowSections', array($this))) {
|
if (Event::handle('StartShowSections', array($this))) {
|
||||||
$this->showSections();
|
$this->showSections();
|
||||||
Event::handle('EndShowSections', array($this));
|
Event::handle('EndShowSections', array($this));
|
||||||
|
@ -919,11 +936,15 @@ class Action extends HTMLOutputter // lawsuit
|
||||||
*
|
*
|
||||||
* @return string current URL
|
* @return string current URL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function selfUrl()
|
function selfUrl()
|
||||||
{
|
{
|
||||||
$action = $this->trimmed('action');
|
$action = $this->trimmed('action');
|
||||||
$args = $this->args;
|
$args = $this->args;
|
||||||
unset($args['action']);
|
unset($args['action']);
|
||||||
|
if (array_key_exists('submit', $args)) {
|
||||||
|
unset($args['submit']);
|
||||||
|
}
|
||||||
foreach (array_keys($_COOKIE) as $cookie) {
|
foreach (array_keys($_COOKIE) as $cookie) {
|
||||||
unset($args[$cookie]);
|
unset($args[$cookie]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
define('LACONICA_VERSION', '0.7.2.1');
|
define('LACONICA_VERSION', '0.7.3');
|
||||||
|
|
||||||
define('AVATAR_PROFILE_SIZE', 96);
|
define('AVATAR_PROFILE_SIZE', 96);
|
||||||
define('AVATAR_STREAM_SIZE', 48);
|
define('AVATAR_STREAM_SIZE', 48);
|
||||||
|
@ -87,6 +87,8 @@ $config =
|
||||||
'closed' => false,
|
'closed' => false,
|
||||||
'inviteonly' => false,
|
'inviteonly' => false,
|
||||||
'private' => false,
|
'private' => false,
|
||||||
|
'ssl' => 'never',
|
||||||
|
'sslserver' => null,
|
||||||
'dupelimit' => 60), # default for same person saying the same thing
|
'dupelimit' => 60), # default for same person saying the same thing
|
||||||
'syslog' =>
|
'syslog' =>
|
||||||
array('appname' => 'laconica', # for syslog
|
array('appname' => 'laconica', # for syslog
|
||||||
|
@ -151,6 +153,9 @@ $config =
|
||||||
array('notify' => array()),
|
array('notify' => array()),
|
||||||
'inboxes' =>
|
'inboxes' =>
|
||||||
array('enabled' => true), # on by default for new sites
|
array('enabled' => true), # on by default for new sites
|
||||||
|
'newuser' =>
|
||||||
|
array('subscribe' => null,
|
||||||
|
'welcome' => null),
|
||||||
);
|
);
|
||||||
|
|
||||||
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
||||||
|
|
|
@ -57,9 +57,14 @@ class FeaturedUsersSection extends ProfileSection
|
||||||
$quoted[] = "'$nick'";
|
$quoted[] = "'$nick'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$table = "user";
|
||||||
|
if(common_config('db','quote_identifiers')) {
|
||||||
|
$table = '"' . $table . '"';
|
||||||
|
}
|
||||||
|
|
||||||
$qry = 'SELECT profile.* ' .
|
$qry = 'SELECT profile.* ' .
|
||||||
'FROM profile JOIN user on profile.id = user.id ' .
|
'FROM profile JOIN '. $table .' on profile.id = '. $table .'.id ' .
|
||||||
'WHERE user.nickname in (' . implode(',', $quoted) . ') ' .
|
'WHERE '. $table .'.nickname in (' . implode(',', $quoted) . ') ' .
|
||||||
'ORDER BY profile.created DESC ';
|
'ORDER BY profile.created DESC ';
|
||||||
|
|
||||||
$limit = PROFILES_PER_SECTION + 1;
|
$limit = PROFILES_PER_SECTION + 1;
|
||||||
|
|
|
@ -50,7 +50,7 @@ class GalleryAction extends Action
|
||||||
if ($this->arg('page') && $this->arg('page') != 1) {
|
if ($this->arg('page') && $this->arg('page') != 1) {
|
||||||
$args['page'] = $this->arg['page'];
|
$args['page'] = $this->arg['page'];
|
||||||
}
|
}
|
||||||
common_redirect(common_local_url('subscriptions', $args), 301);
|
common_redirect(common_local_url($this->trimmed('action'), $args), 301);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ class GalleryAction extends Action
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
|
|
||||||
$this->tag = $this->trimmed('tag');
|
$this->tag = $this->trimmed('tag');
|
||||||
|
$this->q = $this->trimmed('q');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,7 @@ class GalleryAction extends Action
|
||||||
# Post from the tag dropdown; redirect to a GET
|
# Post from the tag dropdown; redirect to a GET
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
common_redirect($this->selfUrl(), 307);
|
common_redirect($this->selfUrl(), 303);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +137,7 @@ class GalleryAction extends Action
|
||||||
'method' => 'post'));
|
'method' => 'post'));
|
||||||
$this->dropdown('tag', _('Tag'), $content,
|
$this->dropdown('tag', _('Tag'), $content,
|
||||||
_('Choose a tag to narrow list'), false, $tag);
|
_('Choose a tag to narrow list'), false, $tag);
|
||||||
$this->submit('go', _('Go'));
|
$this->submit('submit', _('Go'));
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
|
@ -33,7 +33,7 @@ if (!defined('LACONICA')) {
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/grouplist.php';
|
require_once INSTALLDIR.'/lib/grouplist.php';
|
||||||
|
|
||||||
define('GROUPS_PER_MINILIST', 80);
|
define('GROUPS_PER_MINILIST', 27);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Widget to show a list of groups, good for sidebar
|
* Widget to show a list of groups, good for sidebar
|
||||||
|
@ -75,8 +75,9 @@ class GroupMiniList extends GroupList
|
||||||
'href' => $this->group->homeUrl(),
|
'href' => $this->group->homeUrl(),
|
||||||
'rel' => 'contact group',
|
'rel' => 'contact group',
|
||||||
'class' => 'url'));
|
'class' => 'url'));
|
||||||
$logo = ($this->group->stream_logo) ?
|
|
||||||
$this->group->stream_logo : User_group::defaultLogo(AVATAR_STREAM_SIZE);
|
$logo = ($this->group->mini_logo) ?
|
||||||
|
$this->group->mini_logo : User_group::defaultLogo(AVATAR_MINI_SIZE);
|
||||||
|
|
||||||
$this->out->element('img', array('src' => $logo,
|
$this->out->element('img', array('src' => $logo,
|
||||||
'width' => AVATAR_MINI_SIZE,
|
'width' => AVATAR_MINI_SIZE,
|
||||||
|
|
|
@ -137,6 +137,9 @@ class MailboxAction extends PersonalAction
|
||||||
$message->free();
|
$message->free();
|
||||||
unset($message);
|
unset($message);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$this->element('p', 'guide', _('You have no private messages. You can send private message to engage other users in conversation. People can send you messages for your eyes only.'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessages()
|
function getMessages()
|
||||||
|
|
|
@ -258,8 +258,12 @@ class NoticeListItem extends Widget
|
||||||
function showAuthor()
|
function showAuthor()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('span', 'vcard author');
|
$this->out->elementStart('span', 'vcard author');
|
||||||
$this->out->elementStart('a', array('href' => $this->profile->profileurl,
|
$attrs = array('href' => $this->profile->profileurl,
|
||||||
'class' => 'url'));
|
'class' => 'url');
|
||||||
|
if (!empty($this->profile->fullname)) {
|
||||||
|
$attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
|
||||||
|
}
|
||||||
|
$this->out->elementStart('a', $attrs);
|
||||||
$this->showAvatar();
|
$this->showAvatar();
|
||||||
$this->showNickname();
|
$this->showNickname();
|
||||||
$this->out->elementEnd('a');
|
$this->out->elementEnd('a');
|
||||||
|
@ -387,6 +391,7 @@ class NoticeListItem extends Widget
|
||||||
case 'xmpp':
|
case 'xmpp':
|
||||||
case 'mail':
|
case 'mail':
|
||||||
case 'omb':
|
case 'omb':
|
||||||
|
case 'system':
|
||||||
case 'api':
|
case 'api':
|
||||||
$this->out->element('dd', null, $source_name);
|
$this->out->element('dd', null, $source_name);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -160,7 +160,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
|
||||||
$auth_request->addExtension($sreg_request);
|
$auth_request->addExtension($sreg_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
$trust_root = common_path('');
|
$trust_root = common_root_url(true);
|
||||||
$process_url = common_local_url($returnto);
|
$process_url = common_local_url($returnto);
|
||||||
|
|
||||||
if ($auth_request->shouldSendRedirect()) {
|
if ($auth_request->shouldSendRedirect()) {
|
||||||
|
@ -171,7 +171,7 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
|
||||||
} else if (Auth_OpenID::isFailure($redirect_url)) {
|
} else if (Auth_OpenID::isFailure($redirect_url)) {
|
||||||
return sprintf(_('Could not redirect to server: %s'), $redirect_url->message);
|
return sprintf(_('Could not redirect to server: %s'), $redirect_url->message);
|
||||||
} else {
|
} else {
|
||||||
common_redirect($redirect_url);
|
common_redirect($redirect_url, 303);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Generate form markup and render it.
|
// Generate form markup and render it.
|
||||||
|
|
242
lib/profileaction.php
Normal file
242
lib/profileaction.php
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Common parent of Personal and Profile actions
|
||||||
|
*
|
||||||
|
* 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 Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
|
* @copyright 2008-2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/lib/profileminilist.php';
|
||||||
|
require_once INSTALLDIR.'/lib/groupminilist.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profile action common superclass
|
||||||
|
*
|
||||||
|
* Abstracts out common code from profile and personal tabs
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProfileAction extends Action
|
||||||
|
{
|
||||||
|
var $user = null;
|
||||||
|
var $page = null;
|
||||||
|
var $profile = null;
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$nickname_arg = $this->arg('nickname');
|
||||||
|
$nickname = common_canonical_nickname($nickname_arg);
|
||||||
|
|
||||||
|
// Permanent redirect on non-canonical nickname
|
||||||
|
|
||||||
|
if ($nickname_arg != $nickname) {
|
||||||
|
$args = array('nickname' => $nickname);
|
||||||
|
if ($this->arg('page') && $this->arg('page') != 1) {
|
||||||
|
$args['page'] = $this->arg['page'];
|
||||||
|
}
|
||||||
|
common_redirect(common_local_url($this->trimmed('action'), $args), 301);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->user = User::staticGet('nickname', $nickname);
|
||||||
|
|
||||||
|
if (!$this->user) {
|
||||||
|
$this->clientError(_('No such user.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->profile = $this->user->getProfile();
|
||||||
|
|
||||||
|
if (!$this->profile) {
|
||||||
|
$this->serverError(_('User has no profile.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
|
|
||||||
|
common_set_returnto($this->selfUrl());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSections()
|
||||||
|
{
|
||||||
|
$this->showSubscriptions();
|
||||||
|
$this->showSubscribers();
|
||||||
|
$this->showGroups();
|
||||||
|
$this->showStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSubscriptions()
|
||||||
|
{
|
||||||
|
$profile = $this->user->getSubscriptions(0, PROFILES_PER_MINILIST + 1);
|
||||||
|
|
||||||
|
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
||||||
|
'class' => 'section'));
|
||||||
|
|
||||||
|
$this->element('h2', null, _('Subscriptions'));
|
||||||
|
|
||||||
|
if ($profile) {
|
||||||
|
$pml = new ProfileMiniList($profile, $this->user, $this);
|
||||||
|
$cnt = $pml->show();
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->element('p', null, _('(None)'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cnt > PROFILES_PER_MINILIST) {
|
||||||
|
$this->elementStart('p');
|
||||||
|
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||||
|
array('nickname' => $this->profile->nickname)),
|
||||||
|
'class' => 'more'),
|
||||||
|
_('All subscriptions'));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSubscribers()
|
||||||
|
{
|
||||||
|
$profile = $this->user->getSubscribers(0, PROFILES_PER_MINILIST + 1);
|
||||||
|
|
||||||
|
$this->elementStart('div', array('id' => 'entity_subscribers',
|
||||||
|
'class' => 'section'));
|
||||||
|
|
||||||
|
$this->element('h2', null, _('Subscribers'));
|
||||||
|
|
||||||
|
if ($profile) {
|
||||||
|
$pml = new ProfileMiniList($profile, $this->user, $this);
|
||||||
|
$cnt = $pml->show();
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->element('p', null, _('(None)'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cnt > PROFILES_PER_MINILIST) {
|
||||||
|
$this->elementStart('p');
|
||||||
|
$this->element('a', array('href' => common_local_url('subscribers',
|
||||||
|
array('nickname' => $this->profile->nickname)),
|
||||||
|
'class' => 'more'),
|
||||||
|
_('All subscribers'));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStatistics()
|
||||||
|
{
|
||||||
|
// XXX: WORM cache this
|
||||||
|
$subs = new Subscription();
|
||||||
|
$subs->subscriber = $this->profile->id;
|
||||||
|
$subs_count = (int) $subs->count() - 1;
|
||||||
|
|
||||||
|
$subbed = new Subscription();
|
||||||
|
$subbed->subscribed = $this->profile->id;
|
||||||
|
$subbed_count = (int) $subbed->count() - 1;
|
||||||
|
|
||||||
|
$notices = new Notice();
|
||||||
|
$notices->profile_id = $this->profile->id;
|
||||||
|
$notice_count = (int) $notices->count();
|
||||||
|
|
||||||
|
$this->elementStart('div', array('id' => 'entity_statistics',
|
||||||
|
'class' => 'section'));
|
||||||
|
|
||||||
|
$this->element('h2', null, _('Statistics'));
|
||||||
|
|
||||||
|
// Other stats...?
|
||||||
|
$this->elementStart('dl', 'entity_member-since');
|
||||||
|
$this->element('dt', null, _('Member since'));
|
||||||
|
$this->element('dd', null, date('j M Y',
|
||||||
|
strtotime($this->profile->created)));
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_subscriptions');
|
||||||
|
$this->elementStart('dt');
|
||||||
|
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||||
|
array('nickname' => $this->profile->nickname))),
|
||||||
|
_('Subscriptions'));
|
||||||
|
$this->elementEnd('dt');
|
||||||
|
$this->element('dd', null, (is_int($subs_count)) ? $subs_count : '0');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_subscribers');
|
||||||
|
$this->elementStart('dt');
|
||||||
|
$this->element('a', array('href' => common_local_url('subscribers',
|
||||||
|
array('nickname' => $this->profile->nickname))),
|
||||||
|
_('Subscribers'));
|
||||||
|
$this->elementEnd('dt');
|
||||||
|
$this->element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_notices');
|
||||||
|
$this->element('dt', null, _('Notices'));
|
||||||
|
$this->element('dd', null, (is_int($notice_count)) ? $notice_count : '0');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showGroups()
|
||||||
|
{
|
||||||
|
$groups = $this->user->getGroups(0, GROUPS_PER_MINILIST + 1);
|
||||||
|
|
||||||
|
$this->elementStart('div', array('id' => 'entity_groups',
|
||||||
|
'class' => 'section'));
|
||||||
|
|
||||||
|
$this->element('h2', null, _('Groups'));
|
||||||
|
|
||||||
|
if ($groups) {
|
||||||
|
$gml = new GroupMiniList($groups, $this->user, $this);
|
||||||
|
$cnt = $gml->show();
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->element('p', null, _('(None)'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cnt > GROUPS_PER_MINILIST) {
|
||||||
|
$this->elementStart('p');
|
||||||
|
$this->element('a', array('href' => common_local_url('usergroups',
|
||||||
|
array('nickname' => $this->profile->nickname)),
|
||||||
|
'class' => 'more'),
|
||||||
|
_('All groups'));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ if (!defined('LACONICA')) {
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/profilelist.php';
|
require_once INSTALLDIR.'/lib/profilelist.php';
|
||||||
|
|
||||||
define('PROFILES_PER_MINILIST', 80);
|
define('PROFILES_PER_MINILIST', 27);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Widget to show a list of profiles, good for sidebar
|
* Widget to show a list of profiles, good for sidebar
|
||||||
|
|
|
@ -107,6 +107,9 @@ class Router
|
||||||
$m->connect('main/'.$a, array('action' => $a));
|
$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'));
|
$m->connect('main/tagother/:id', array('action' => 'tagother'));
|
||||||
|
|
||||||
// these take a code
|
// these take a code
|
||||||
|
|
|
@ -133,5 +133,31 @@ class SearchAction extends Action
|
||||||
$this->showResults($q, $page);
|
$this->showResults($q, $page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function searchSuggestions($q) {
|
||||||
|
$qe = urlencode($q);
|
||||||
|
$message = sprintf(_(<<<E_O_T
|
||||||
|
* Make sure all words are spelled correctly.
|
||||||
|
* Try different keywords.
|
||||||
|
* Try more general keywords.
|
||||||
|
* Try fewer keywords.
|
||||||
|
|
||||||
|
You can also try your search on other engines:
|
||||||
|
|
||||||
|
* [Twingly](http://www.twingly.com/search?q=%s&content=microblog&site=identi.ca)
|
||||||
|
* [Tweet scan](http://www.tweetscan.com/indexi.php?s=%s)
|
||||||
|
* [Google](http://www.google.com/search?q=site%%3A%%%%site.server%%%%+%s)
|
||||||
|
* [Yahoo](http://search.yahoo.com/search?p=site%%3A%%%%site.server%%%%+%s)
|
||||||
|
|
||||||
|
|
||||||
|
E_O_T
|
||||||
|
), $qe, $qe, $qe, $qe);
|
||||||
|
$this->elementStart('dl', array('id' => 'help_search', 'class' => 'help'));
|
||||||
|
$this->element('dt', null, _('Search help'));
|
||||||
|
$this->elementStart('dd', 'instructions');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$this->elementEnd('dd');
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,9 @@ class SettingsAction extends Action
|
||||||
common_set_returnto($this->selfUrl());
|
common_set_returnto($this->selfUrl());
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
if ($user->hasOpenID()) {
|
if ($user->hasOpenID()) {
|
||||||
common_redirect(common_local_url('openidlogin'));
|
common_redirect(common_local_url('openidlogin'), 303);
|
||||||
} else {
|
} else {
|
||||||
common_redirect(common_local_url('login'));
|
common_redirect(common_local_url('login'), 303);
|
||||||
}
|
}
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
$this->handlePost();
|
$this->handlePost();
|
||||||
|
|
229
lib/twitter.php
229
lib/twitter.php
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
define("TWITTER_SERVICE", 1); // Twitter is foreign_service ID 1
|
define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1
|
||||||
|
|
||||||
function get_twitter_data($uri, $screen_name, $password)
|
function get_twitter_data($uri, $screen_name, $password)
|
||||||
{
|
{
|
||||||
|
@ -45,6 +45,10 @@ function get_twitter_data($uri, $screen_name, $password)
|
||||||
if ($errmsg) {
|
if ($errmsg) {
|
||||||
common_debug("Twitter bridge - cURL error: $errmsg - trying to load: $uri with user $screen_name.",
|
common_debug("Twitter bridge - cURL error: $errmsg - trying to load: $uri with user $screen_name.",
|
||||||
__FILE__);
|
__FILE__);
|
||||||
|
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "cURL error: $errmsg - trying to load: $uri with user $screen_name.\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
@ -52,63 +56,141 @@ function get_twitter_data($uri, $screen_name, $password)
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function twitter_user_info($screen_name, $password)
|
function twitter_json_data($uri, $screen_name, $password)
|
||||||
{
|
{
|
||||||
|
$json_data = get_twitter_data($uri, $screen_name, $password);
|
||||||
|
|
||||||
$uri = "http://twitter.com/users/show/$screen_name.json";
|
if (!$json_data) {
|
||||||
$data = get_twitter_data($uri, $screen_name, $password);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($json_data);
|
||||||
|
|
||||||
if (!$data) {
|
if (!$data) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$twit_user = json_decode($data);
|
return $data;
|
||||||
|
|
||||||
if (!$twit_user) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $twit_user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_twitter_user($fuser, $twitter_id, $screen_name)
|
function twitter_user_info($screen_name, $password)
|
||||||
{
|
{
|
||||||
|
$uri = "http://twitter.com/users/show/$screen_name.json";
|
||||||
|
return twitter_json_data($uri, $screen_name, $password);
|
||||||
|
}
|
||||||
|
|
||||||
$original = clone($fuser);
|
function twitter_friends_ids($screen_name, $password)
|
||||||
$fuser->nickname = $screen_name;
|
{
|
||||||
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
$uri = "http://twitter.com/friends/ids/$screen_name.json";
|
||||||
$result = $fuser->updateKeys($original);
|
return twitter_json_data($uri, $screen_name, $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_twitter_user($twitter_id, $screen_name)
|
||||||
|
{
|
||||||
|
$uri = 'http://twitter.com/' . $screen_name;
|
||||||
|
|
||||||
|
$fuser = new Foreign_user();
|
||||||
|
|
||||||
|
$fuser->query('BEGIN');
|
||||||
|
|
||||||
|
// Dropping down to SQL because regular db_object udpate stuff doesn't seem
|
||||||
|
// to work so good with tables that have multiple column primary keys
|
||||||
|
|
||||||
|
// Any time we update the uri for a forein user we have to make sure there
|
||||||
|
// are no dupe entries first -- unique constraint on the uri column
|
||||||
|
|
||||||
|
$qry = 'UPDATE foreign_user set uri = \'\' WHERE uri = ';
|
||||||
|
$qry .= '\'' . $uri . '\'' . ' AND service = ' . TWITTER_SERVICE;
|
||||||
|
|
||||||
|
$result = $fuser->query($qry);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
common_debug("Removed uri ($uri) from another foreign_user who was squatting on it.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print("Removed uri ($uri) from another Twitter user who was squatting on it.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the user
|
||||||
|
$qry = 'UPDATE foreign_user SET nickname = ';
|
||||||
|
$qry .= '\'' . $screen_name . '\'' . ', uri = \'' . $uri . '\' ';
|
||||||
|
$qry .= 'WHERE id = ' . $twitter_id . ' AND service = ' . TWITTER_SERVICE;
|
||||||
|
|
||||||
|
$result = $fuser->query($qry);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
"Couldn't update foreign_user data for Twitter user: $screen_name");
|
||||||
common_log_db_error($fuser, 'UPDATE', __FILE__);
|
common_log_db_error($fuser, 'UPDATE', __FILE__);
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "UPDATE failed: for Twitter user: $twitter_id - $screen_name. - ";
|
||||||
|
print common_log_objstring($fuser) . "\n";
|
||||||
|
$error = &PEAR::getStaticProperty('DB_DataObject','lastError');
|
||||||
|
print "DB_DataObject Error: " . $error->getMessage() . "\n";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$fuser->query('COMMIT');
|
||||||
|
|
||||||
|
$fuser->free();
|
||||||
|
unset($fuser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_twitter_user($twitter_id, $screen_name)
|
function add_twitter_user($twitter_id, $screen_name)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$new_uri = 'http://twitter.com/' . $screen_name;
|
||||||
|
|
||||||
|
// Clear out any bad old foreign_users with the new user's legit URL
|
||||||
|
// This can happen when users move around or fakester accounts get
|
||||||
|
// repoed, and things like that.
|
||||||
|
$luser = new Foreign_user();
|
||||||
|
$luser->uri = $new_uri;
|
||||||
|
$luser->service = TWITTER_SERVICE;
|
||||||
|
$result = $luser->delete();
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - removed invalid Twitter user squatting on uri: $new_uri");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Removed invalid Twitter user squatting on uri: $new_uri\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$luser->free();
|
||||||
|
unset($luser);
|
||||||
|
|
||||||
// Otherwise, create a new Twitter user
|
// Otherwise, create a new Twitter user
|
||||||
$fuser = DB_DataObject::factory('foreign_user');
|
$fuser = new Foreign_user();
|
||||||
|
|
||||||
$fuser->nickname = $screen_name;
|
$fuser->nickname = $screen_name;
|
||||||
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
||||||
$fuser->id = $twitter_id;
|
$fuser->id = $twitter_id;
|
||||||
$fuser->service = TWITTER_SERVICE; // Twitter
|
$fuser->service = TWITTER_SERVICE;
|
||||||
$fuser->created = common_sql_now();
|
$fuser->created = common_sql_now();
|
||||||
$result = $fuser->insert();
|
$result = $fuser->insert();
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_debug("Twitter bridge - failed to add new Twitter user: $twitter_id - $screen_name.");
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - failed to add new Twitter user: $twitter_id - $screen_name.");
|
||||||
common_log_db_error($fuser, 'INSERT', __FILE__);
|
common_log_db_error($fuser, 'INSERT', __FILE__);
|
||||||
return false;
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "INSERT failed: could not add new Twitter user: $twitter_id - $screen_name. - ";
|
||||||
|
print common_log_objstring($fuser) . "\n";
|
||||||
|
$error = &PEAR::getStaticProperty('DB_DataObject','lastError');
|
||||||
|
print "DB_DataObject Error: " . $error->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
common_debug("Twitter bridge - Added new Twitter user: $screen_name ($twitter_id).");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Added new Twitter user: $screen_name ($twitter_id).\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
common_debug("Twitter bridge - Added new Twitter user: $screen_name ($twitter_id).");
|
return $result;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates or Updates a Twitter user
|
// Creates or Updates a Twitter user
|
||||||
|
@ -117,53 +199,87 @@ function save_twitter_user($twitter_id, $screen_name)
|
||||||
|
|
||||||
// Check to see whether the Twitter user is already in the system,
|
// Check to see whether the Twitter user is already in the system,
|
||||||
// and update its screen name and uri if so.
|
// and update its screen name and uri if so.
|
||||||
$fuser = Foreign_user::getForeignUser($twitter_id, 1);
|
$fuser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE);
|
||||||
|
|
||||||
if ($fuser) {
|
if ($fuser) {
|
||||||
|
|
||||||
|
$result = true;
|
||||||
|
|
||||||
// Only update if Twitter screen name has changed
|
// Only update if Twitter screen name has changed
|
||||||
if ($fuser->nickname != $screen_name) {
|
if ($fuser->nickname != $screen_name) {
|
||||||
|
$result = update_twitter_user($twitter_id, $screen_name);
|
||||||
|
|
||||||
common_debug('Twitter bridge - Updated nickname (and URI) for Twitter user ' .
|
common_debug('Twitter bridge - Updated nickname (and URI) for Twitter user ' .
|
||||||
"$fuser->id to $screen_name, was $fuser->nickname");
|
"$fuser->id to $screen_name, was $fuser->nickname");
|
||||||
|
|
||||||
return update_twitter_user($fuser, $twitter_id, $screen_name);
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print 'Updated nickname (and URI) for Twitter user ' .
|
||||||
|
"$fuser->id to $screen_name, was $fuser->nickname\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return add_twitter_user($twitter_id, $screen_name);
|
return add_twitter_user($twitter_id, $screen_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$fuser->free();
|
||||||
|
unset($fuser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function retreive_twitter_friends($twitter_id, $screen_name, $password)
|
function retreive_twitter_friends($twitter_id, $screen_name, $password)
|
||||||
{
|
{
|
||||||
|
$friends = array();
|
||||||
|
|
||||||
$uri = "http://twitter.com/statuses/friends/$twitter_id.json?page=";
|
$uri = "http://twitter.com/statuses/friends/$twitter_id.json?page=";
|
||||||
$twitter_user = twitter_user_info($screen_name, $password);
|
$friends_ids = twitter_friends_ids($screen_name, $password);
|
||||||
|
|
||||||
// Calculate how many pages to get...
|
if (!$friends_ids) {
|
||||||
$pages = ceil($twitter_user->friends_count / 100);
|
return $friends;
|
||||||
|
|
||||||
if ($pages == 0) {
|
|
||||||
common_debug("Twitter bridge - Twitter user $screen_name has no friends! Lame.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$friends = array();
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Twitter 'social graph' ids method says $screen_name has " .
|
||||||
|
count($friends_ids) . " friends.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate how many pages to get...
|
||||||
|
$pages = ceil(count($friends_ids) / 100);
|
||||||
|
|
||||||
|
if ($pages == 0) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - $screen_name seems to have no friends.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "$screen_name seems to have no friends.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for ($i = 1; $i <= $pages; $i++) {
|
for ($i = 1; $i <= $pages; $i++) {
|
||||||
|
|
||||||
$data = get_twitter_data($uri . $i, $screen_name, $password);
|
$data = get_twitter_data($uri . $i, $screen_name, $password);
|
||||||
|
|
||||||
if (!$data) {
|
if (!$data) {
|
||||||
return null;
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - Couldn't retrieve page $i of $screen_name's friends.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Couldn't retrieve page $i of $screen_name's friends.\n";
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$more_friends = json_decode($data);
|
$more_friends = json_decode($data);
|
||||||
|
|
||||||
if (!$more_friends) {
|
if (!$more_friends) {
|
||||||
return null;
|
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - No data for page $i of $screen_name's friends.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "No data for page $i of $screen_name's friends.\n";
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$friends = array_merge($friends, $more_friends);
|
$friends = array_merge($friends, $more_friends);
|
||||||
|
@ -177,19 +293,27 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password)
|
||||||
|
|
||||||
$friends = retreive_twitter_friends($twitter_id, $screen_name, $password);
|
$friends = retreive_twitter_friends($twitter_id, $screen_name, $password);
|
||||||
|
|
||||||
if (is_null($friends)) {
|
if (empty($friends)) {
|
||||||
common_debug("Twitter bridge - Couldn't get friends data from Twitter.");
|
common_debug("Twitter bridge - Couldn't get friends data from Twitter for $screen_name.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Couldn't get friends data from Twitter for $screen_name.\n";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($friends as $friend) {
|
foreach ($friends as $friend) {
|
||||||
|
|
||||||
$friend_name = $friend->screen_name;
|
$friend_name = $friend->screen_name;
|
||||||
$friend_id = $friend->id;
|
$friend_id = (int) $friend->id;
|
||||||
|
|
||||||
// Update or create the Foreign_user record
|
// Update or create the Foreign_user record
|
||||||
if (!save_twitter_user($friend_id, $friend_name)) {
|
if (!save_twitter_user($friend_id, $friend_name)) {
|
||||||
return false;
|
common_log(LOG_WARNING,
|
||||||
|
"Twitter bridge - couldn't save $screen_name's friend, $friend_name.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "Couldn't save $screen_name's friend, $friend_name.\n";
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if there's a related local user
|
// Check to see if there's a related local user
|
||||||
|
@ -199,8 +323,20 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password)
|
||||||
|
|
||||||
// Get associated user and subscribe her
|
// Get associated user and subscribe her
|
||||||
$friend_user = User::staticGet('id', $flink->user_id);
|
$friend_user = User::staticGet('id', $flink->user_id);
|
||||||
subs_subscribe_to($user, $friend_user);
|
if (!empty($friend_user)) {
|
||||||
common_debug("Twitter bridge - subscribed $friend_user->nickname to $user->nickname.");
|
$result = subs_subscribe_to($user, $friend_user);
|
||||||
|
|
||||||
|
if ($result === true) {
|
||||||
|
common_debug("Twitter bridge - subscribed $friend_user->nickname to $user->nickname.");
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print("Subscribed $friend_user->nickname to $user->nickname.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "$result ($friend_user->nickname to $user->nickname)\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +354,7 @@ function is_twitter_bound($notice, $flink) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +362,10 @@ function broadcast_twitter($notice)
|
||||||
{
|
{
|
||||||
$success = true;
|
$success = true;
|
||||||
|
|
||||||
$flink = Foreign_link::getByUserID($notice->profile_id,
|
$flink = Foreign_link::getByUserID($notice->profile_id,
|
||||||
TWITTER_SERVICE);
|
TWITTER_SERVICE);
|
||||||
|
|
||||||
// XXX: Not sure WHERE to check whether a notice should go to
|
// XXX: Not sure WHERE to check whether a notice should go to
|
||||||
// Twitter. Should we even put in the queue if it shouldn't? --Zach
|
// Twitter. Should we even put in the queue if it shouldn't? --Zach
|
||||||
if (!is_null($flink) && is_twitter_bound($notice, $flink)) {
|
if (!is_null($flink) && is_twitter_bound($notice, $flink)) {
|
||||||
|
|
||||||
|
@ -244,7 +380,7 @@ function broadcast_twitter($notice)
|
||||||
$options = array(
|
$options = array(
|
||||||
CURLOPT_USERPWD => "$twitter_user:$twitter_password",
|
CURLOPT_USERPWD => "$twitter_user:$twitter_password",
|
||||||
CURLOPT_POST => true,
|
CURLOPT_POST => true,
|
||||||
CURLOPT_POSTFIELDS =>
|
CURLOPT_POSTFIELDS =>
|
||||||
array(
|
array(
|
||||||
'status' => $statustxt,
|
'status' => $statustxt,
|
||||||
'source' => common_config('integration', 'source')
|
'source' => common_config('integration', 'source')
|
||||||
|
@ -292,7 +428,6 @@ function broadcast_twitter($notice)
|
||||||
$success = false;
|
$success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
72
lib/util.php
72
lib/util.php
|
@ -581,10 +581,8 @@ function common_shorten_link($url, $reverse = false)
|
||||||
|
|
||||||
function common_xml_safe_str($str)
|
function common_xml_safe_str($str)
|
||||||
{
|
{
|
||||||
$xmlStr = htmlentities(iconv('UTF-8', 'UTF-8//IGNORE', $str), ENT_NOQUOTES, 'UTF-8');
|
// Neutralize control codes and surrogates
|
||||||
|
return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
|
||||||
// Replace control, formatting, and surrogate characters with '*', ala Twitter
|
|
||||||
return preg_replace('/[\p{Cc}\p{Cf}\p{Cs}]/u', '*', $str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_tag_link($tag)
|
function common_tag_link($tag)
|
||||||
|
@ -622,9 +620,13 @@ function common_at_link($sender_id, $nickname)
|
||||||
$url = $recipient->profileurl;
|
$url = $recipient->profileurl;
|
||||||
}
|
}
|
||||||
$xs = new XMLStringer(false);
|
$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('span', 'vcard');
|
||||||
$xs->elementStart('a', array('href' => $url,
|
$xs->elementStart('a', $attrs);
|
||||||
'class' => 'url'));
|
|
||||||
$xs->element('span', 'fn nickname', $nickname);
|
$xs->element('span', 'fn nickname', $nickname);
|
||||||
$xs->elementEnd('a');
|
$xs->elementEnd('a');
|
||||||
$xs->elementEnd('span');
|
$xs->elementEnd('span');
|
||||||
|
@ -639,10 +641,14 @@ function common_group_link($sender_id, $nickname)
|
||||||
$sender = Profile::staticGet($sender_id);
|
$sender = Profile::staticGet($sender_id);
|
||||||
$group = User_group::staticGet('nickname', common_canonical_nickname($nickname));
|
$group = User_group::staticGet('nickname', common_canonical_nickname($nickname));
|
||||||
if ($group && $sender->isMember($group)) {
|
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 = new XMLStringer();
|
||||||
$xs->elementStart('span', 'vcard');
|
$xs->elementStart('span', 'vcard');
|
||||||
$xs->elementStart('a', array('href' => $group->permalink(),
|
$xs->elementStart('a', $attrs);
|
||||||
'class' => 'url'));
|
|
||||||
$xs->element('span', 'fn nickname', $nickname);
|
$xs->element('span', 'fn nickname', $nickname);
|
||||||
$xs->elementEnd('a');
|
$xs->elementEnd('a');
|
||||||
$xs->elementEnd('span');
|
$xs->elementEnd('span');
|
||||||
|
@ -713,25 +719,46 @@ function common_relative_profile($sender, $nickname, $dt=null)
|
||||||
|
|
||||||
function common_local_url($action, $args=null, $params=null, $fragment=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();
|
$r = Router::get();
|
||||||
$path = $r->build($action, $args, $params, $fragment);
|
$path = $r->build($action, $args, $params, $fragment);
|
||||||
|
|
||||||
|
$ssl = in_array($action, $sensitive);
|
||||||
|
|
||||||
if (common_config('site','fancy')) {
|
if (common_config('site','fancy')) {
|
||||||
$url = common_path(mb_substr($path, 1));
|
$url = common_path(mb_substr($path, 1), $ssl);
|
||||||
} else {
|
} else {
|
||||||
if (mb_strpos($path, '/index.php') === 0) {
|
if (mb_strpos($path, '/index.php') === 0) {
|
||||||
$url = common_path(mb_substr($path, 1));
|
$url = common_path(mb_substr($path, 1), $ssl);
|
||||||
} else {
|
} else {
|
||||||
$url = common_path('index.php'.$path);
|
$url = common_path('index.php'.$path, $ssl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_path($relative)
|
function common_path($relative, $ssl=false)
|
||||||
{
|
{
|
||||||
$pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
|
$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)
|
function common_date_string($dt)
|
||||||
|
@ -821,7 +848,7 @@ function common_redirect($url, $code=307)
|
||||||
303 => "See Other",
|
303 => "See Other",
|
||||||
307 => "Temporary Redirect");
|
307 => "Temporary Redirect");
|
||||||
|
|
||||||
header("Status: ${code} $status[$code]");
|
header('HTTP/1.1 '.$code.' '.$status[$code]);
|
||||||
header("Location: $url");
|
header("Location: $url");
|
||||||
|
|
||||||
$xo = new XMLOutputter();
|
$xo = new XMLOutputter();
|
||||||
|
@ -923,9 +950,9 @@ function common_profile_url($nickname)
|
||||||
|
|
||||||
// Should make up a reasonable root URL
|
// 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
|
// returns $bytes bytes of random data as a hexadecimal string
|
||||||
|
@ -1294,3 +1321,16 @@ function common_compatible_license($from, $to)
|
||||||
// XXX: better compatibility check needed here!
|
// XXX: better compatibility check needed here!
|
||||||
return ($from == $to);
|
return ($from == $to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a quoted table name, if required according to config
|
||||||
|
*/
|
||||||
|
function common_database_tablename($tablename)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(common_config('db','quote_identifiers')) {
|
||||||
|
$tablename = '"'. $tablename .'"';
|
||||||
|
}
|
||||||
|
//table prefixes could be added here later
|
||||||
|
return $tablename;
|
||||||
|
}
|
|
@ -105,12 +105,13 @@ class LinkbackPlugin extends Plugin
|
||||||
$pb = $match[1];
|
$pb = $match[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
$tb = $this->getTrackback($result->body, $result->final_url);
|
if (!empty($pb)) {
|
||||||
|
|
||||||
if (!empty($tb)) {
|
|
||||||
$this->trackback($result->final_url, $tb);
|
|
||||||
} else if (!empty($pb)) {
|
|
||||||
$this->pingback($result->final_url, $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;
|
return $orig;
|
||||||
|
|
344
plugins/TemplatePlugin.php
Normal file
344
plugins/TemplatePlugin.php
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin to render old skool templates
|
||||||
|
*
|
||||||
|
* Captures rendered parts from the output buffer, passes them through a template file: tpl/index.html
|
||||||
|
* Adds an API method at index.php/template/update which lets you overwrite the template file
|
||||||
|
* Requires username/password and a single POST parameter called "template"
|
||||||
|
* The method is disabled unless the user is #1, the first user of the system
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Brian Hendrickson <brian@megapump.com>
|
||||||
|
* @copyright 2009 Megapump, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://megapump.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
define('TEMPLATEPLUGIN_VERSION', '0.1');
|
||||||
|
|
||||||
|
class TemplatePlugin extends Plugin {
|
||||||
|
|
||||||
|
var $blocks = array();
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
// capture the RouterInitialized event
|
||||||
|
// and connect a new API method
|
||||||
|
// for updating the template
|
||||||
|
function onRouterInitialized( &$m ) {
|
||||||
|
$m->connect( 'template/update', array(
|
||||||
|
'action' => 'template',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// <%styles%>
|
||||||
|
// <%scripts%>
|
||||||
|
// <%search%>
|
||||||
|
// <%feeds%>
|
||||||
|
// <%description%>
|
||||||
|
// <%head%>
|
||||||
|
function onStartShowHead( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
$act->extraHead();
|
||||||
|
$this->blocks['head'] = $act->xw->flush();
|
||||||
|
$act->showStylesheets();
|
||||||
|
$this->blocks['styles'] = $act->xw->flush();
|
||||||
|
$act->showScripts();
|
||||||
|
$this->blocks['scripts'] = $act->xw->flush();
|
||||||
|
$act->showFeeds();
|
||||||
|
$this->blocks['feeds'] = $act->xw->flush();
|
||||||
|
$act->showOpenSearch();
|
||||||
|
$this->blocks['search'] = $act->xw->flush();
|
||||||
|
$act->showDescription();
|
||||||
|
$this->blocks['description'] = $act->xw->flush();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%bodytext%>
|
||||||
|
function onStartShowContentBlock( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function onEndShowContentBlock( &$act ) {
|
||||||
|
$this->blocks['bodytext'] = $act->xw->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%localnav%>
|
||||||
|
function onStartShowLocalNavBlock( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function onEndShowLocalNavBlock( &$act ) {
|
||||||
|
$this->blocks['localnav'] = $act->xw->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%export%>
|
||||||
|
function onStartShowExportData( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function onEndShowExportData( &$act ) {
|
||||||
|
$this->blocks['export'] = $act->xw->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%subscriptions%>
|
||||||
|
// <%subscribers%>
|
||||||
|
// <%groups%>
|
||||||
|
// <%statistics%>
|
||||||
|
// <%cloud%>
|
||||||
|
// <%groupmembers%>
|
||||||
|
// <%groupstatistics%>
|
||||||
|
// <%groupcloud%>
|
||||||
|
// <%popular%>
|
||||||
|
// <%groupsbyposts%>
|
||||||
|
// <%featuredusers%>
|
||||||
|
// <%groupsbymembers%>
|
||||||
|
function onStartShowSections( &$act ) {
|
||||||
|
global $action;
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
switch ($action) {
|
||||||
|
case "showstream":
|
||||||
|
$act->showSubscriptions();
|
||||||
|
$this->blocks['subscriptions'] = $act->xw->flush();
|
||||||
|
$act->showSubscribers();
|
||||||
|
$this->blocks['subscribers'] = $act->xw->flush();
|
||||||
|
$act->showGroups();
|
||||||
|
$this->blocks['groups'] = $act->xw->flush();
|
||||||
|
$act->showStatistics();
|
||||||
|
$this->blocks['statistics'] = $act->xw->flush();
|
||||||
|
$cloud = new PersonalTagCloudSection($act, $act->user);
|
||||||
|
$cloud->show();
|
||||||
|
$this->blocks['cloud'] = $act->xw->flush();
|
||||||
|
break;
|
||||||
|
case "showgroup":
|
||||||
|
$act->showMembers();
|
||||||
|
$this->blocks['groupmembers'] = $act->xw->flush();
|
||||||
|
$act->showStatistics();
|
||||||
|
$this->blocks['groupstatistics'] = $act->xw->flush();
|
||||||
|
$cloud = new GroupTagCloudSection($act, $act->group);
|
||||||
|
$cloud->show();
|
||||||
|
$this->blocks['groupcloud'] = $act->xw->flush();
|
||||||
|
break;
|
||||||
|
case "public":
|
||||||
|
$pop = new PopularNoticeSection($act);
|
||||||
|
$pop->show();
|
||||||
|
$this->blocks['popular'] = $act->xw->flush();
|
||||||
|
$gbp = new GroupsByPostsSection($act);
|
||||||
|
$gbp->show();
|
||||||
|
$this->blocks['groupsbyposts'] = $act->xw->flush();
|
||||||
|
$feat = new FeaturedUsersSection($act);
|
||||||
|
$feat->show();
|
||||||
|
$this->blocks['featuredusers'] = $act->xw->flush();
|
||||||
|
break;
|
||||||
|
case "groups":
|
||||||
|
$gbp = new GroupsByPostsSection($act);
|
||||||
|
$gbp->show();
|
||||||
|
$this->blocks['groupsbyposts'] = $act->xw->flush();
|
||||||
|
$gbm = new GroupsByMembersSection($act);
|
||||||
|
$gbm->show();
|
||||||
|
$this->blocks['groupsbymembers'] = $act->xw->flush();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%logo%>
|
||||||
|
// <%nav%>
|
||||||
|
// <%notice%>
|
||||||
|
// <%noticeform%>
|
||||||
|
function onStartShowHeader( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
$act->showLogo();
|
||||||
|
$this->blocks['logo'] = $act->xw->flush();
|
||||||
|
$act->showPrimaryNav();
|
||||||
|
$this->blocks['nav'] = $act->xw->flush();
|
||||||
|
$act->showSiteNotice();
|
||||||
|
$this->blocks['notice'] = $act->xw->flush();
|
||||||
|
if (common_logged_in()) {
|
||||||
|
$act->showNoticeForm();
|
||||||
|
} else {
|
||||||
|
$act->showAnonymousMessage();
|
||||||
|
}
|
||||||
|
$this->blocks['noticeform'] = $act->xw->flush();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <%secondarynav%>
|
||||||
|
// <%licenses%>
|
||||||
|
function onStartShowFooter( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
$act->showSecondaryNav();
|
||||||
|
$this->blocks['secondarynav'] = $act->xw->flush();
|
||||||
|
$act->showLicenses();
|
||||||
|
$this->blocks['licenses'] = $act->xw->flush();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// capture the EndHTML event
|
||||||
|
// and include the template
|
||||||
|
function onEndEndHTML($act) {
|
||||||
|
|
||||||
|
global $action, $tags;
|
||||||
|
|
||||||
|
// set the action and title values
|
||||||
|
$vars = array(
|
||||||
|
'action'=>$action,
|
||||||
|
'title'=>$act->title(). " - ". common_config('site', 'name')
|
||||||
|
);
|
||||||
|
|
||||||
|
// use the PHP template
|
||||||
|
// unless laconica config:
|
||||||
|
// $config['template']['mode'] = 'html';
|
||||||
|
if (!(common_config('template', 'mode') == 'html')) {
|
||||||
|
$tpl_file = 'tpl/index.php';
|
||||||
|
$tags = array_merge($vars,$this->blocks);
|
||||||
|
include $tpl_file;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tpl_file = 'tpl/index.html';
|
||||||
|
|
||||||
|
// read the static template
|
||||||
|
$output = file_get_contents( $tpl_file );
|
||||||
|
|
||||||
|
$tags = array();
|
||||||
|
|
||||||
|
// get a list of the <%tags%> in the template
|
||||||
|
$pattern='/<%([a-z]+)%>/';
|
||||||
|
|
||||||
|
if ( 1 <= preg_match_all( $pattern, $output, $found ))
|
||||||
|
$tags[] = $found;
|
||||||
|
|
||||||
|
// for each found tag, set its value from the rendered blocks
|
||||||
|
foreach( $tags[0][1] as $pos=>$tag ) {
|
||||||
|
if (isset($this->blocks[$tag]))
|
||||||
|
$vars[$tag] = $this->blocks[$tag];
|
||||||
|
|
||||||
|
// didn't find a block for the tag
|
||||||
|
elseif (!isset($vars[$tag]))
|
||||||
|
$vars[$tag] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace the tags in the template
|
||||||
|
foreach( $vars as $key=>$val )
|
||||||
|
$output = str_replace( '<%'.$key.'%>', $val, $output );
|
||||||
|
|
||||||
|
echo $output;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// catching the StartShowHTML event to halt the rendering
|
||||||
|
function onStartShowHTML( &$act ) {
|
||||||
|
$this->clear_xmlWriter($act);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the xmlWriter
|
||||||
|
function clear_xmlWriter( &$act ) {
|
||||||
|
$act->xw->openMemory();
|
||||||
|
$act->xw->setIndent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action for updating the template remotely
|
||||||
|
*
|
||||||
|
* "template/update" -- a POST method that requires a single
|
||||||
|
* parameter "template", containing the new template code
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Brian Hendrickson <brian@megapump.com>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://megapump.com/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TemplateAction extends Action
|
||||||
|
{
|
||||||
|
|
||||||
|
function prepare($args) {
|
||||||
|
parent::prepare($args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle($args) {
|
||||||
|
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
||||||
|
|
||||||
|
// not authenticated, show login form
|
||||||
|
header('WWW-Authenticate: Basic realm="Laconica API"');
|
||||||
|
|
||||||
|
// cancelled the browser login form
|
||||||
|
$this->clientError(_('Authentication error!'), $code = 401);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$nick = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
$pass = $_SERVER['PHP_AUTH_PW'];
|
||||||
|
|
||||||
|
// check username and password
|
||||||
|
$user = common_check_user($nick,$pass);
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
|
||||||
|
// verify that user is admin
|
||||||
|
if (!($user->id == 1))
|
||||||
|
$this->clientError(_('only User #1 can update the template'), $code = 401);
|
||||||
|
|
||||||
|
// open the old template
|
||||||
|
$tpl_file = 'tpl/index.html';
|
||||||
|
$fp = fopen( $tpl_file, 'w+' );
|
||||||
|
|
||||||
|
// overwrite with the new template
|
||||||
|
fwrite($fp, $this->arg('template'));
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
header('HTTP/1.1 200 OK');
|
||||||
|
header('Content-type: text/plain');
|
||||||
|
print "Template Updated!";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// bad username and password
|
||||||
|
$this->clientError(_('Authentication error!'), $code = 401);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for retrieving a laconica display section
|
||||||
|
*
|
||||||
|
* requires one parameter, the name of the section
|
||||||
|
* section names are listed in the comments of the TemplatePlugin class
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Brian Hendrickson <brian@megapump.com>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://megapump.com/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function section($tagname) {
|
||||||
|
global $tags;
|
||||||
|
if (isset($tags[$tagname]))
|
||||||
|
return $tags[$tagname];
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
# This version needs to match the tarball and unpacked directory name.
|
||||||
|
%define LACVER 0.7.3
|
||||||
|
|
||||||
BuildRequires: php-pear
|
BuildRequires: php-pear
|
||||||
BuildRequires: httpd-devel
|
BuildRequires: httpd-devel
|
||||||
|
|
||||||
Name: laconica
|
Name: laconica
|
||||||
Version: 0.7.2
|
Version: %{LACVER}
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
License: GAGPL v3 or later
|
License: GAGPL v3 or later
|
||||||
Source: laconica-0.7.2.tar.gz
|
Source: laconica-%{version}.tar.gz
|
||||||
Group: Applications/Internet
|
Group: Applications/Internet
|
||||||
Summary: Laconica, the Open Source microblogging platform
|
Summary: Laconica, the Open Source microblogging platform
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
|
@ -49,6 +52,8 @@ cp -a * %{buildroot}%{wwwpath}
|
||||||
mkdir -p %{buildroot}%{_datadir}/laconica
|
mkdir -p %{buildroot}%{_datadir}/laconica
|
||||||
cp -a db %{buildroot}%{_datadir}/laconica/db
|
cp -a db %{buildroot}%{_datadir}/laconica/db
|
||||||
|
|
||||||
|
mkdir -p %{buildroot}%{_datadir}/laconica/avatar
|
||||||
|
|
||||||
mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d
|
mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d
|
||||||
cat > %{buildroot}%{_sysconfdir}/httpd/conf.d/laconica.conf <<"EOF"
|
cat > %{buildroot}%{_sysconfdir}/httpd/conf.d/laconica.conf <<"EOF"
|
||||||
Alias /laconica/ "/var/www/laconica/"
|
Alias /laconica/ "/var/www/laconica/"
|
||||||
|
@ -74,6 +79,12 @@ rm -rf %buildroot
|
||||||
%config(noreplace) %{_sysconfdir}/httpd/conf.d/laconica.conf
|
%config(noreplace) %{_sysconfdir}/httpd/conf.d/laconica.conf
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Apr 03 2009 Zach Copley <zach@controlyourself.ca> - 0.7.3
|
||||||
|
- Changed version number to 0.7.3.
|
||||||
|
|
||||||
|
* Fri Mar 13 2009 Ken Sedgwick <ksedgwic@bonsai.com> - 0.7.2.1-1
|
||||||
|
- Factored laconica version to the first line of the file.
|
||||||
|
|
||||||
* Wed Mar 03 2009 Zach Copley <zach@controlyourself.ca> - 0.7.2
|
* Wed Mar 03 2009 Zach Copley <zach@controlyourself.ca> - 0.7.2
|
||||||
- Changed version number to 0.7.2.
|
- Changed version number to 0.7.2.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# Abort if called from a web server
|
// Abort if called from a web server
|
||||||
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
print "This script must be run from the command line\n";
|
print "This script must be run from the command line\n";
|
||||||
exit();
|
exit();
|
||||||
|
@ -27,11 +27,16 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
define('LACONICA', true);
|
define('LACONICA', true);
|
||||||
|
|
||||||
|
// Uncomment this to get useful console output
|
||||||
|
//define('SCRIPT_DEBUG', true);
|
||||||
|
|
||||||
require_once(INSTALLDIR . '/lib/common.php');
|
require_once(INSTALLDIR . '/lib/common.php');
|
||||||
|
|
||||||
$flink = new Foreign_link();
|
$flink = new Foreign_link();
|
||||||
$flink->service = 1; // Twitter
|
$flink->service = 1; // Twitter
|
||||||
$flink->find();
|
$cnt = $flink->find();
|
||||||
|
|
||||||
|
print "Updating Twitter friends subscriptions for $cnt users.\n";
|
||||||
|
|
||||||
while ($flink->fetch()) {
|
while ($flink->fetch()) {
|
||||||
|
|
||||||
|
@ -39,20 +44,30 @@ while ($flink->fetch()) {
|
||||||
|
|
||||||
$user = User::staticGet($flink->user_id);
|
$user = User::staticGet($flink->user_id);
|
||||||
|
|
||||||
print "Updating Twitter friends for user $user->nickname ($user->id)\n";
|
if (empty($user)) {
|
||||||
|
common_log(LOG_WARNING, "Unmatched user for ID " . $flink->user_id);
|
||||||
|
print "Unmatched user for ID $flink->user_id\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Updating Twitter friends for $user->nickname (Laconica ID: $user->id)... ";
|
||||||
|
|
||||||
$fuser = $flink->getForeignUser();
|
$fuser = $flink->getForeignUser();
|
||||||
|
|
||||||
$result = save_twitter_friends($user, $fuser->id, $fuser->nickname, $flink->credentials);
|
if (empty($fuser)) {
|
||||||
|
common_log(LOG_WARNING, "Unmatched user for ID " . $flink->user_id);
|
||||||
|
print "Unmatched user for ID $flink->user_id\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($result == false) {
|
$result = save_twitter_friends($user, $fuser->id,
|
||||||
print "Problems updating Twitter friends! Check the log.\n";
|
$fuser->nickname, $flink->credentials);
|
||||||
exit(1);
|
if (defined('SCRIPT_DEBUG')) {
|
||||||
|
print "\nDONE\n";
|
||||||
|
} else {
|
||||||
|
print "DONE\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,12 +83,13 @@ left:0;
|
||||||
border:0;
|
border:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#page_notice .error,
|
.error,
|
||||||
#page_notice .success {
|
.success {
|
||||||
padding:4px 7px;
|
padding:4px 7px;
|
||||||
border-radius:4px;
|
border-radius:4px;
|
||||||
-moz-border-radius:4px;
|
-moz-border-radius:4px;
|
||||||
-webkit-border-radius:4px;
|
-webkit-border-radius:4px;
|
||||||
|
margin-bottom:18px;
|
||||||
}
|
}
|
||||||
form label.submit {
|
form label.submit {
|
||||||
display:none;
|
display:none;
|
||||||
|
@ -216,6 +217,9 @@ margin-right:0;
|
||||||
address .fn {
|
address .fn {
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
}
|
}
|
||||||
|
address img + .fn {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
width:100%;
|
width:100%;
|
||||||
|
@ -247,6 +251,7 @@ position:absolute;
|
||||||
top:65px;
|
top:65px;
|
||||||
right:18px;
|
right:18px;
|
||||||
width:250px;
|
width:250px;
|
||||||
|
width:24%;
|
||||||
}
|
}
|
||||||
#page_notice {
|
#page_notice {
|
||||||
clear:both;
|
clear:both;
|
||||||
|
@ -256,9 +261,8 @@ margin-bottom:18px;
|
||||||
|
|
||||||
#anon_notice {
|
#anon_notice {
|
||||||
float:left;
|
float:left;
|
||||||
width:432px;
|
width:43.2%;
|
||||||
width:28.052em;
|
padding:1.1%;
|
||||||
padding:11px;
|
|
||||||
border-radius:7px;
|
border-radius:7px;
|
||||||
-moz-border-radius:7px;
|
-moz-border-radius:7px;
|
||||||
-webkit-border-radius:7px;
|
-webkit-border-radius:7px;
|
||||||
|
@ -366,7 +370,9 @@ margin-right:4px;
|
||||||
|
|
||||||
#wrap {
|
#wrap {
|
||||||
margin:0 auto;
|
margin:0 auto;
|
||||||
width:1003px;
|
width:100%;
|
||||||
|
min-width:760px;
|
||||||
|
max-width:1003px;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,14 +384,17 @@ margin-bottom:1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content {
|
#content {
|
||||||
width:644px;
|
width:64.009%;
|
||||||
padding:18px;
|
min-height:259px;
|
||||||
|
padding:1.795%;
|
||||||
float:left;
|
float:left;
|
||||||
border-radius:7px;
|
border-radius:7px;
|
||||||
-moz-border-radius:7px;
|
-moz-border-radius:7px;
|
||||||
-moz-border-radius-topleft:0;
|
-moz-border-radius-topleft:0;
|
||||||
-webkit-border-radius:7px;
|
-webkit-border-radius:7px;
|
||||||
-webkit-border-top-left-radius:0;
|
-webkit-border-top-left-radius:0;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content_inner {
|
#content_inner {
|
||||||
|
@ -395,10 +404,11 @@ float:left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#aside_primary {
|
#aside_primary {
|
||||||
width:280px;
|
width:27.917%;
|
||||||
|
min-height:259px;
|
||||||
float:left;
|
float:left;
|
||||||
margin-left:4px;
|
margin-left:0.385%;
|
||||||
padding:18px;
|
padding:1.795%;
|
||||||
border-radius:7px;
|
border-radius:7px;
|
||||||
-moz-border-radius:7px;
|
-moz-border-radius:7px;
|
||||||
-webkit-border-radius:7px;
|
-webkit-border-radius:7px;
|
||||||
|
@ -406,9 +416,8 @@ border-width:1px;
|
||||||
border-style:solid;
|
border-style:solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Start: FORM NOTICE*/
|
|
||||||
#form_notice {
|
#form_notice {
|
||||||
width:458px;
|
width:45.664%;
|
||||||
float:left;
|
float:left;
|
||||||
position:relative;
|
position:relative;
|
||||||
line-height:1;
|
line-height:1;
|
||||||
|
@ -425,7 +434,7 @@ float:left;
|
||||||
border-radius:7px;
|
border-radius:7px;
|
||||||
-moz-border-radius:7px;
|
-moz-border-radius:7px;
|
||||||
-webkit-border-radius:7px;
|
-webkit-border-radius:7px;
|
||||||
width:370px;
|
width:80.789%;
|
||||||
height:67px;
|
height:67px;
|
||||||
line-height:1.5;
|
line-height:1.5;
|
||||||
padding:7px 7px 16px 7px;
|
padding:7px 7px 16px 7px;
|
||||||
|
@ -455,27 +464,27 @@ line-height:1.15;
|
||||||
padding:1px 2px;
|
padding:1px 2px;
|
||||||
}
|
}
|
||||||
#form_notice #notice_action-submit {
|
#form_notice #notice_action-submit {
|
||||||
width:60px;
|
width:14%;
|
||||||
padding:8px;
|
height:47px;
|
||||||
|
padding:0;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
bottom:0;
|
bottom:0;
|
||||||
right:0;
|
right:0;
|
||||||
}
|
}
|
||||||
#form_notice label[for=to] {
|
#form_notice label[for=to] {
|
||||||
margin-top:11px;
|
margin-top:7px;
|
||||||
}
|
}
|
||||||
#form_notice select[id=to] {
|
#form_notice select[id=to] {
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
margin-left:18px;
|
margin-left:18px;
|
||||||
float:left;
|
float:left;
|
||||||
}
|
}
|
||||||
/*end FORM NOTICE*/
|
|
||||||
|
|
||||||
|
|
||||||
/* entity_profile */
|
/* entity_profile */
|
||||||
.entity_profile {
|
.entity_profile {
|
||||||
position:relative;
|
position:relative;
|
||||||
width:475px;
|
width:67.702%;
|
||||||
min-height:123px;
|
min-height:123px;
|
||||||
float:left;
|
float:left;
|
||||||
margin-bottom:18px;
|
margin-bottom:18px;
|
||||||
|
@ -505,7 +514,6 @@ margin-bottom:18px;
|
||||||
.entity_profile .entity_tags {
|
.entity_profile .entity_tags {
|
||||||
margin-left:113px;
|
margin-left:113px;
|
||||||
margin-bottom:4px;
|
margin-bottom:4px;
|
||||||
width:322px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity_profile .entity_fn,
|
.entity_profile .entity_fn,
|
||||||
|
@ -533,14 +541,14 @@ display:none;
|
||||||
.entity_profile h2 {
|
.entity_profile h2 {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* entity_profile */
|
/* entity_profile */
|
||||||
|
|
||||||
|
|
||||||
/*entity_actions*/
|
/*entity_actions*/
|
||||||
.entity_actions {
|
.entity_actions {
|
||||||
float:right;
|
float:right;
|
||||||
margin-left:28px;
|
margin-left:4.35%;
|
||||||
|
max-width:25%;
|
||||||
}
|
}
|
||||||
.entity_actions h2 {
|
.entity_actions h2 {
|
||||||
display:none;
|
display:none;
|
||||||
|
@ -681,7 +689,7 @@ float:none;
|
||||||
.profile .entity_profile .entity_note,
|
.profile .entity_profile .entity_note,
|
||||||
.profile .entity_profile .entity_url,
|
.profile .entity_profile .entity_url,
|
||||||
.profile .entity_profile .entity_tags,
|
.profile .entity_profile .entity_tags,
|
||||||
.profile .entity_profile .form_subcription_edit {
|
.profile .entity_profile .form_subscription_edit {
|
||||||
margin-left:59px;
|
margin-left:59px;
|
||||||
clear:none;
|
clear:none;
|
||||||
display:block;
|
display:block;
|
||||||
|
@ -693,7 +701,7 @@ margin-right:11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.profile .entity_profile .form_subcription_edit label {
|
.profile .entity_profile .form_subscription_edit label {
|
||||||
font-weight:normal;
|
font-weight:normal;
|
||||||
margin-right:11px;
|
margin-right:11px;
|
||||||
}
|
}
|
||||||
|
@ -908,8 +916,6 @@ display:none;
|
||||||
border:0;
|
border:0;
|
||||||
padding:0;
|
padding:0;
|
||||||
}
|
}
|
||||||
/*END: NOTICES */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#new_group, #group_search {
|
#new_group, #group_search {
|
||||||
|
@ -1140,4 +1146,16 @@ clear:both;
|
||||||
margin-bottom:0;
|
margin-bottom:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.instructions ul {
|
||||||
|
list-style-position:inside;
|
||||||
|
}
|
||||||
|
.instructions p,
|
||||||
|
.instructions ul {
|
||||||
|
margin-bottom:18px;
|
||||||
|
}
|
||||||
|
.help dt {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.guide {
|
||||||
|
clear:both;
|
||||||
|
}
|
|
@ -1,8 +1,21 @@
|
||||||
/* IE specific styles */
|
/* IE specific styles */
|
||||||
|
legend {
|
||||||
#aside_primary {
|
margin-left:-7px;
|
||||||
padding-left:11px;
|
|
||||||
}
|
}
|
||||||
|
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 {
|
.notice-options input.submit {
|
||||||
font-size:0;
|
font-size:0;
|
||||||
margin-top:3px;
|
margin-top:3px;
|
||||||
|
@ -11,15 +24,9 @@ text-align:right;
|
||||||
text-indent:0;
|
text-indent:0;
|
||||||
width:24px;
|
width:24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.checkbox {
|
|
||||||
top:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
margin-left:-7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notice div.entry-content .timestamp a {
|
.notice div.entry-content .timestamp a {
|
||||||
margin-right:4px;
|
margin-right:4px;
|
||||||
}
|
}
|
||||||
|
.entity_profile {
|
||||||
|
width:64%;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
/* IE6 specific styles */
|
/* 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_nickname,
|
||||||
.entity_profile .entity_location,
|
.entity_profile .entity_location,
|
||||||
.entity_profile .entity_url,
|
.entity_profile .entity_url,
|
||||||
|
@ -9,6 +22,9 @@ margin-left:0;
|
||||||
.entity_profile .entity_depiction {
|
.entity_profile .entity_depiction {
|
||||||
margin-bottom:123px;
|
margin-bottom:123px;
|
||||||
}
|
}
|
||||||
|
.entity_actions {
|
||||||
|
width:20%;
|
||||||
|
}
|
||||||
.notice div.entry-content {
|
.notice div.entry-content {
|
||||||
width:63%;
|
width:63%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ p { orphans: 2; widows: 1; }
|
||||||
.entity_actions,
|
.entity_actions,
|
||||||
.notice-options,
|
.notice-options,
|
||||||
#aside_primary,
|
#aside_primary,
|
||||||
.form_subcription_edit .submit {
|
.form_subscription_edit .submit {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
font-size:1em;
|
font-size:1em;
|
||||||
}
|
}
|
||||||
address {
|
address {
|
||||||
margin-right:71px;
|
margin-right:7.18%;
|
||||||
}
|
|
||||||
address .fn {
|
|
||||||
display:none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input, textarea, select, option {
|
input, textarea, select, option {
|
||||||
|
@ -40,7 +37,6 @@ background:none;
|
||||||
|
|
||||||
input.submit,
|
input.submit,
|
||||||
#form_notice.warning #notice_text-count,
|
#form_notice.warning #notice_text-count,
|
||||||
#nav_register a,
|
|
||||||
.form_settings .form_note,
|
.form_settings .form_note,
|
||||||
.entity_remote_subscribe {
|
.entity_remote_subscribe {
|
||||||
background-color:#A9BF4F;
|
background-color:#A9BF4F;
|
||||||
|
@ -51,7 +47,6 @@ input:focus, textarea:focus, select:focus,
|
||||||
border-color:#A9BF4F;
|
border-color:#A9BF4F;
|
||||||
}
|
}
|
||||||
input.submit,
|
input.submit,
|
||||||
#nav_register a,
|
|
||||||
.entity_remote_subscribe {
|
.entity_remote_subscribe {
|
||||||
color:#fff;
|
color:#fff;
|
||||||
}
|
}
|
||||||
|
@ -100,13 +95,6 @@ cursor:wait;
|
||||||
text-indent:-9999px;
|
text-indent:-9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#nav_register a {
|
|
||||||
text-decoration:none;
|
|
||||||
font-weight:bold;
|
|
||||||
padding:2px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content,
|
#content,
|
||||||
#site_nav_local_views a,
|
#site_nav_local_views a,
|
||||||
#aside_primary {
|
#aside_primary {
|
||||||
|
@ -125,10 +113,10 @@ background-color:rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#page_notice .error {
|
.error {
|
||||||
background-color:#F7E8E8;
|
background-color:#F7E8E8;
|
||||||
}
|
}
|
||||||
#page_notice .success {
|
.success {
|
||||||
background-color:#EFF3DC;
|
background-color:#EFF3DC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
font-size:1em;
|
font-size:1em;
|
||||||
}
|
}
|
||||||
address {
|
address {
|
||||||
margin-right:71px;
|
margin-right:7.18%;
|
||||||
}
|
|
||||||
address .fn {
|
|
||||||
display:none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input, textarea, select, option {
|
input, textarea, select, option {
|
||||||
|
@ -40,7 +37,6 @@ background:none;
|
||||||
|
|
||||||
input.submit,
|
input.submit,
|
||||||
#form_notice.warning #notice_text-count,
|
#form_notice.warning #notice_text-count,
|
||||||
#nav_register a,
|
|
||||||
.form_settings .form_note,
|
.form_settings .form_note,
|
||||||
.entity_remote_subscribe {
|
.entity_remote_subscribe {
|
||||||
background-color:#9BB43E;
|
background-color:#9BB43E;
|
||||||
|
@ -51,7 +47,6 @@ input:focus, textarea:focus, select:focus,
|
||||||
border-color:#9BB43E;
|
border-color:#9BB43E;
|
||||||
}
|
}
|
||||||
input.submit,
|
input.submit,
|
||||||
#nav_register a,
|
|
||||||
.entity_remote_subscribe {
|
.entity_remote_subscribe {
|
||||||
color:#fff;
|
color:#fff;
|
||||||
}
|
}
|
||||||
|
@ -100,12 +95,6 @@ cursor:wait;
|
||||||
text-indent:-9999px;
|
text-indent:-9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav_register a {
|
|
||||||
text-decoration:none;
|
|
||||||
font-weight:bold;
|
|
||||||
padding:2px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content,
|
#content,
|
||||||
#site_nav_local_views a,
|
#site_nav_local_views a,
|
||||||
#aside_primary {
|
#aside_primary {
|
||||||
|
@ -124,10 +113,10 @@ background-color:rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#page_notice .error {
|
.error {
|
||||||
background-color:#F7E8E8;
|
background-color:#F7E8E8;
|
||||||
}
|
}
|
||||||
#page_notice .success {
|
.success {
|
||||||
background-color:#EFF3DC;
|
background-color:#EFF3DC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
tpl/index.php
Normal file
47
tpl/index.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<title><?php echo section('title'); ?></title>
|
||||||
|
<?php echo section('styles'); ?>
|
||||||
|
<?php echo section('scripts'); ?>
|
||||||
|
<?php echo section('search'); ?>
|
||||||
|
<?php echo section('feeds'); ?>
|
||||||
|
<?php echo section('description'); ?>
|
||||||
|
<?php echo section('head'); ?>
|
||||||
|
</head>
|
||||||
|
<body id="<?php echo section('action'); ?>">
|
||||||
|
<div id="wrap">
|
||||||
|
<div id="header">
|
||||||
|
<?php echo section('logo'); ?>
|
||||||
|
<?php echo section('nav'); ?>
|
||||||
|
<?php echo section('notice'); ?>
|
||||||
|
<?php echo section('noticeform'); ?>
|
||||||
|
</div>
|
||||||
|
<div id="core">
|
||||||
|
<?php echo section('localnav'); ?>
|
||||||
|
<?php echo section('bodytext'); ?>
|
||||||
|
<div id="aside_primary" class="aside">
|
||||||
|
<?php echo section('export'); ?>
|
||||||
|
<?php echo section('subscriptions'); ?>
|
||||||
|
<?php echo section('subscribers'); ?>
|
||||||
|
<?php echo section('groups'); ?>
|
||||||
|
<?php echo section('statistics'); ?>
|
||||||
|
<?php echo section('cloud'); ?>
|
||||||
|
<?php echo section('groupmembers'); ?>
|
||||||
|
<?php echo section('groupstatistics'); ?>
|
||||||
|
<?php echo section('groupcloud'); ?>
|
||||||
|
<?php echo section('popular'); ?>
|
||||||
|
<?php echo section('groupsbyposts'); ?>
|
||||||
|
<?php echo section('featuredusers'); ?>
|
||||||
|
<?php echo section('groupsbymembers'); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<?php echo section('secondarynav'); ?>
|
||||||
|
<?php echo section('licenses'); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user