summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorEvan Prodromou <evan@controlyourself.ca>2009-01-20 23:13:02 -0500
committerEvan Prodromou <evan@controlyourself.ca>2009-01-20 23:13:02 -0500
commit4b9df58c90e25ea79aeec64c6e96f828fe06d7df (patch)
treeac237014d015535d07babba42d40d86608de0ec5 /lib
parentbd056218f9a595184ac7bcac0c1dc6a8981d7af2 (diff)
parent65bfda33b8464caf14ce268c9bea2e7eceb27fe5 (diff)
Merge branch 'master' into groups
Conflicts: .gitignore
Diffstat (limited to 'lib')
-rw-r--r--lib/accountsettingsaction.php134
-rw-r--r--lib/action.php519
-rw-r--r--lib/blockform.php143
-rw-r--r--lib/common.php8
-rw-r--r--lib/connectsettingsaction.php129
-rw-r--r--lib/disfavorform.php154
-rw-r--r--lib/facebookaction.php252
-rw-r--r--lib/facebookutil.php189
-rw-r--r--lib/favorform.php153
-rw-r--r--lib/feedlist.php158
-rw-r--r--lib/form.php168
-rw-r--r--lib/htmloutputter.php353
-rw-r--r--lib/logingroupnav.php96
-rw-r--r--lib/mailbox.php237
-rw-r--r--lib/messageform.php152
-rw-r--r--lib/microid.php97
-rw-r--r--lib/noticeform.php169
-rw-r--r--lib/noticelist.php218
-rw-r--r--lib/nudgeform.php105
-rw-r--r--lib/personal.php220
-rw-r--r--lib/personalgroupnav.php135
-rw-r--r--lib/profilelist.php189
-rw-r--r--lib/publicgroupnav.php92
-rw-r--r--lib/rssaction.php97
-rw-r--r--lib/settingsaction.php189
-rw-r--r--lib/stream.php26
-rw-r--r--lib/subscribeform.php130
-rw-r--r--lib/theme.php53
-rw-r--r--lib/unblockform.php141
-rw-r--r--lib/unsubscribeform.php129
-rw-r--r--lib/util.php666
-rw-r--r--lib/widget.php82
-rw-r--r--lib/xmloutputter.php242
33 files changed, 4458 insertions, 1367 deletions
diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php
new file mode 100644
index 000000000..46090b8c1
--- /dev/null
+++ b/lib/accountsettingsaction.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Base class for account settings 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 Settings
+ * @package Laconica
+ * @author Evan Prodromou <evan@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/settingsaction.php';
+
+/**
+ * Base class for account settings actions
+ *
+ * @category Settings
+ * @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/
+ *
+ * @see Widget
+ */
+
+class AccountSettingsAction extends SettingsAction
+{
+ /**
+ * Show the local navigation menu
+ *
+ * This is the same for all settings, so we show it here.
+ *
+ * @return void
+ */
+
+ function showLocalNav()
+ {
+ $menu = new AccountSettingsNav($this);
+ $menu->show();
+ }
+}
+
+/**
+ * A widget for showing the settings group local nav menu
+ *
+ * @category Widget
+ * @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/
+ *
+ * @see HTMLOutputter
+ */
+
+class AccountSettingsNav extends Widget
+{
+ var $action = null;
+
+ /**
+ * Construction
+ *
+ * @param Action $action current action, used for output
+ */
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ /**
+ * Show the menu
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ # action => array('prompt', 'title')
+ $menu =
+ array('profilesettings' =>
+ array(_('Profile'),
+ _('Change your profile settings')),
+ 'avatarsettings' =>
+ array(_('Avatar'),
+ _('Upload an avatar')),
+ 'passwordsettings' =>
+ array(_('Password'),
+ _('Change your password')),
+ 'emailsettings' =>
+ array(_('Email'),
+ _('Change email handling')),
+ 'openidsettings' =>
+ array(_('OpenID'),
+ _('Add or remove OpenIDs')),
+ 'othersettings' =>
+ array(_('Other'),
+ _('Other options')));
+
+ $action_name = $this->action->trimmed('action');
+ $this->action->elementStart('ul', array('class' => 'nav'));
+
+ foreach ($menu as $menuaction => $menudesc) {
+ $this->action->menuItem(common_local_url($menuaction),
+ $menudesc[0],
+ $menudesc[1],
+ $action_name === $menuaction);
+ }
+
+ $this->action->elementEnd('ul');
+ }
+}
diff --git a/lib/action.php b/lib/action.php
index 486b40387..5987abf3c 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -1,9 +1,12 @@
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * Base class for all actions (~views)
+ *
+ * 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.
@@ -15,19 +18,61 @@
*
* 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 Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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);
}
-class Action // lawsuit
-{
+require_once INSTALLDIR.'/lib/noticeform.php';
+require_once INSTALLDIR.'/lib/htmloutputter.php';
+/**
+ * Base class for all actions
+ *
+ * This is the base class for all actions in the package. An action is
+ * more or less a "view" in an MVC framework.
+ *
+ * Actions are responsible for extracting and validating parameters; using
+ * model classes to read and write to the database; and doing ouput.
+ *
+ * @category Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class Action extends HTMLOutputter // lawsuit
+{
var $args;
- function Action()
+ /**
+ * Constructor
+ *
+ * Just wraps the HTMLOutputter constructor.
+ *
+ * @param string $output URI to output to, default = stdout
+ * @param boolean $indent Whether to indent output, default true
+ *
+ * @see XMLOutputter::__construct
+ * @see HTMLOutputter::__construct
+ */
+
+ function __construct($output='php://output', $indent=true)
{
+ parent::__construct($output, $indent);
}
// For initializing members of the class
@@ -38,10 +83,388 @@ class Action // lawsuit
return true;
}
+ function showPage()
+ {
+ $this->startHTML();
+ $this->showHead();
+ $this->showBody();
+ $this->endHTML();
+ }
+
+ function showHead()
+ {
+ // XXX: attributes (profile?)
+ $this->elementStart('head');
+ $this->showTitle();
+ $this->showStylesheets();
+ $this->showScripts();
+ $this->showOpenSearch();
+ $this->showFeeds();
+ $this->showDescription();
+ $this->extraHead();
+ $this->elementEnd('head');
+ }
+
+ function showTitle()
+ {
+ $this->element('title', null,
+ sprintf(_("%s - %s"),
+ $this->title(),
+ common_config('site', 'name')));
+ }
+
+ // SHOULD overload
+
+ function title()
+ {
+ return _("Untitled page");
+ }
+
+ function showStylesheets()
+ {
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION,
+ 'media' => 'screen, projection, tv'));
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => theme_path('css/thickbox.css', 'base') . '?version=' . LACONICA_VERSION,
+ 'media' => 'screen, projection, tv'));
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
+ 'media' => 'screen, projection, tv'));
+ $this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
+ 'href="'.theme_path('css/ie.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
+ foreach (array(6,7) as $ver) {
+ if (file_exists(theme_file('ie'.$ver.'.css'))) {
+ // Yes, IE people should be put in jail.
+ $this->comment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
+ 'href="'.theme_path('css/ie'.$ver.'.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
+ }
+ }
+ }
+
+ function showScripts()
+ {
+ $this->element('script', array('type' => 'text/javascript',
+ 'src' => common_path('js/jquery.min.js')),
+ ' ');
+ $this->element('script', array('type' => 'text/javascript',
+ 'src' => common_path('js/jquery.form.js')),
+ ' ');
+ $this->element('script', array('type' => 'text/javascript',
+ 'src' => common_path('js/xbImportNode.js')),
+ ' ');
+ $this->element('script', array('type' => 'text/javascript',
+ 'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
+ ' ');
+ }
+
+ function showOpenSearch()
+ {
+ $this->element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
+ 'href' => common_local_url('opensearch', array('type' => 'people')),
+ 'title' => common_config('site', 'name').' People Search'));
+
+ $this->element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
+ 'href' => common_local_url('opensearch', array('type' => 'notice')),
+ 'title' => common_config('site', 'name').' Notice Search'));
+ }
+
+ // MAY overload
+
+ function showFeeds()
+ {
+ // does nothing by default
+ }
+
+ // SHOULD overload
+
+ function showDescription()
+ {
+ // does nothing by default
+ }
+
+ // MAY overload
+
+ function extraHead()
+ {
+ // does nothing by default
+ }
+
+ function showBody()
+ {
+ $this->elementStart('body', array('id' => $this->trimmed('action')));
+ $this->elementStart('div', 'wrap');
+ $this->showHeader();
+ $this->showCore();
+ $this->showFooter();
+ $this->elementEnd('div');
+ $this->elementEnd('body');
+ }
+
+ function showHeader()
+ {
+ $this->elementStart('div', array('id' => 'header'));
+ $this->showLogo();
+ $this->showPrimaryNav();
+ $this->showSiteNotice();
+ if (common_logged_in()) {
+ $this->showNoticeForm();
+ } else {
+ $this->showAnonymousMessage();
+ }
+ $this->elementEnd('div');
+ }
+
+ function showLogo()
+ {
+ $this->elementStart('address', array('id' => 'site_contact',
+ 'class' => 'vcard'));
+ $this->elementStart('a', array('class' => 'url home bookmark',
+ 'href' => common_local_url('public')));
+ if (common_config('site', 'logo') || file_exists(theme_file('logo.png')))
+ {
+ $this->element('img', array('class' => 'logo photo',
+ 'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : theme_path('logo.png'),
+ 'alt' => common_config('site', 'name')));
+ }
+ $this->element('span', array('class' => 'fn org'), common_config('site', 'name'));
+ $this->elementEnd('a');
+ $this->elementEnd('address');
+ }
+
+ function showPrimaryNav()
+ {
+ $this->elementStart('dl', array('id' => 'site_nav_global_primary'));
+ $this->element('dt', null, _('Primary site navigation'));
+ $this->elementStart('dd');
+ $user = common_current_user();
+ $this->elementStart('ul', array('class' => 'nav'));
+ if ($user) {
+ $this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
+ _('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'),
+ _('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
+ $this->menuItem(common_local_url('imsettings'),
+ _('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
+ $this->menuItem(common_local_url('logout'),
+ _('Logout'), _('Logout from the site'), false, 'nav_logout');
+ } else {
+ $this->menuItem(common_local_url('login'),
+ _('Login'), _('Login to the site'), false, 'nav_login');
+ if (!common_config('site', 'closed')) {
+ $this->menuItem(common_local_url('register'),
+ _('Register'), _('Create an account'), false, 'nav_register');
+ }
+ $this->menuItem(common_local_url('openidlogin'),
+ _('OpenID'), _('Login with OpenID'), false, 'nav_openid');
+ }
+ $this->menuItem(common_local_url('doc', array('title' => 'help')),
+ _('Help'), _('Help me!'), false, 'nav_help');
+ $this->elementEnd('ul');
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+
+ // Revist. Should probably do an hAtom pattern here
+ function showSiteNotice()
+ {
+ $text = common_config('site', 'notice');
+ if ($text) {
+ $this->elementStart('dl', array('id' => 'site_notice',
+ 'class' => 'system_notice'));
+ $this->element('dt', null, _('Site notice'));
+ $this->element('dd', null, $text);
+ $this->elementEnd('dl');
+ }
+ }
+
+ // MAY overload if no notice form needed... or direct message box????
+
+ function showNoticeForm()
+ {
+ $notice_form = new NoticeForm($this);
+ $notice_form->show();
+ }
+
+ function showAnonymousMessage()
+ {
+ // needs to be defined by the class
+ }
+
+ function showCore()
+ {
+ $this->elementStart('div', array('id' => 'core'));
+ $this->showLocalNavBlock();
+ $this->showContentBlock();
+ $this->showAside();
+ $this->elementEnd('div');
+ }
+
+ function showLocalNavBlock()
+ {
+ $this->elementStart('dl', array('id' => 'site_nav_local_views'));
+ $this->element('dt', null, _('Local views'));
+ $this->elementStart('dd');
+ $this->showLocalNav();
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+
+ // SHOULD overload
+
+ function showLocalNav()
+ {
+ // does nothing by default
+ }
+
+ function showContentBlock()
+ {
+ $this->elementStart('div', array('id' => 'content'));
+ $this->showPageTitle();
+ $this->showPageNoticeBlock();
+ $this->elementStart('div', array('id' => 'content_inner'));
+ // show the actual content (forms, lists, whatever)
+ $this->showContent();
+ $this->elementEnd('div');
+ $this->elementEnd('div');
+ }
+
+ function showPageTitle() {
+ $this->element('h1', NULL, $this->title());
+ }
+
+ function showPageNoticeBlock()
+ {
+ $this->elementStart('dl', array('id' => 'page_notice',
+ 'class' => 'system_notice'));
+ $this->element('dt', null, _('Page notice'));
+ $this->elementStart('dd');
+ $this->showPageNotice();
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+
+ // SHOULD overload (unless there's not a notice)
+
+ function showPageNotice()
+ {
+ }
+
+ // MUST overload
+
+ function showContent()
+ {
+ }
+
+ function showAside()
+ {
+ $this->elementStart('div', array('id' => 'aside_primary',
+ 'class' => 'aside'));
+ $this->showExportData();
+ $this->showSections();
+ $this->elementEnd('div');
+ }
+
+ // MAY overload if there are feeds
+
+ function showExportData()
+ {
+ // is there structure to this?
+ // list of (visible!) feed links
+ // can we reuse list of feeds from showFeeds() ?
+ }
+
+ // SHOULD overload
+
+ function showSections() {
+ // for each section, show it
+ }
+
+ function showFooter()
+ {
+ $this->elementStart('div', array('id' => 'footer'));
+ $this->showSecondaryNav();
+ $this->showLicenses();
+ $this->elementEnd('div');
+ }
+
+ function showSecondaryNav()
+ {
+ $this->elementStart('dl', array('id' => 'site_nav_global_secondary'));
+ $this->element('dt', null, _('Secondary site navigation'));
+ $this->elementStart('dd', null);
+ $this->elementStart('ul', array('class' => 'nav'));
+ $this->menuItem(common_local_url('doc', array('title' => 'help')),
+ _('Help'));
+ $this->menuItem(common_local_url('doc', array('title' => 'about')),
+ _('About'));
+ $this->menuItem(common_local_url('doc', array('title' => 'faq')),
+ _('FAQ'));
+ $this->menuItem(common_local_url('doc', array('title' => 'privacy')),
+ _('Privacy'));
+ $this->menuItem(common_local_url('doc', array('title' => 'source')),
+ _('Source'));
+ $this->menuItem(common_local_url('doc', array('title' => 'contact')),
+ _('Contact'));
+ $this->elementEnd('ul');
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+
+ function showLicenses()
+ {
+ $this->elementStart('dl', array('id' => 'licenses'));
+ $this->showLaconicaLicense();
+ $this->showContentLicense();
+ $this->elementEnd('dl');
+ }
+
+ function showLaconicaLicense()
+ {
+ $this->element('dt', array('id' => 'site_laconica_license'), _('Laconica software license'));
+ $this->elementStart('dd', null);
+ if (common_config('site', 'broughtby')) {
+ $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
+ } else {
+ $instr = _('**%%site.name%%** is a microblogging service. ');
+ }
+ $instr .= sprintf(_('It runs the [Laconica](http://laconi.ca/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), LACONICA_VERSION);
+ $output = common_markup_to_html($instr);
+ $this->raw($output);
+ $this->elementEnd('dd');
+ // do it
+ }
+
+ function showContentLicense()
+ {
+ $this->element('dt', array('id' => 'site_content_license'), _('Laconica software license'));
+ $this->elementStart('dd', array('id' => 'site_content_license_cc'));
+ $this->elementStart('p');
+ $this->element('img', array('id' => 'license_cc',
+ 'src' => common_config('license', 'image'),
+ 'alt' => common_config('license', 'title')));
+ //TODO: This is dirty: i18n
+ $this->text(_('All '.common_config('site', 'name').' content and data are available under the '));
+ $this->element('a', array('class' => 'license',
+ 'rel' => 'external license',
+ 'href' => common_config('license', 'url')),
+ common_config('license', 'title'));
+ $this->text(_('license.'));
+ $this->elementEnd('p');
+ $this->elementEnd('dd');
+ }
+
// For comparison with If-Last-Modified
// If not applicable, return null
- function last_modified()
+ function lastModified()
{
return null;
}
@@ -51,7 +474,7 @@ class Action // lawsuit
return null;
}
- function is_readonly()
+ function isReadOnly()
{
return false;
}
@@ -76,7 +499,7 @@ class Action // lawsuit
function handle($argarray=null)
{
- $lm = $this->last_modified();
+ $lm = $this->lastModified();
$etag = $this->etag();
if ($etag) {
@@ -90,7 +513,7 @@ class Action // lawsuit
$ims = strtotime($if_modified_since);
if ($lm <= $ims) {
if (!$etag ||
- $this->_has_etag($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) {
+ $this->_hasEtag($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) {
header('HTTP/1.1 304 Not Modified');
// Better way to do this?
exit(0);
@@ -100,7 +523,7 @@ class Action // lawsuit
}
}
- function _has_etag($etag, $if_none_match)
+ function _hasEtag($etag, $if_none_match)
{
return ($if_none_match) && in_array($etag, explode(',', $if_none_match));
}
@@ -120,21 +543,21 @@ class Action // lawsuit
}
}
- function server_error($msg, $code=500)
+ function serverError($msg, $code=500)
{
$action = $this->trimmed('action');
common_debug("Server error '$code' on '$action': $msg", __FILE__);
common_server_error($msg, $code);
}
- function client_error($msg, $code=400)
+ function clientError($msg, $code=400)
{
$action = $this->trimmed('action');
common_debug("User error '$code' on '$action': $msg", __FILE__);
common_user_error($msg, $code);
}
- function self_url()
+ function selfUrl()
{
$action = $this->trimmed('action');
$args = $this->args;
@@ -145,17 +568,63 @@ class Action // lawsuit
return common_local_url($action, $args);
}
- function nav_menu($menu)
+ // Added @id to li for some control.
+ // XXX: We might want to move this to htmloutputter.php
+
+ function menuItem($url, $text, $title=null, $is_selected=false, $id=null)
{
- $action = $this->trimmed('action');
- common_element_start('ul', array('id' => 'nav_views'));
- foreach ($menu as $menuaction => $menudesc) {
- common_menu_item(common_local_url($menuaction,
- isset($menudesc[2]) ? $menudesc[2] : null),
- $menudesc[0],
- $menudesc[1],
- $action == $menuaction);
- }
- common_element_end('ul');
+ $lattrs = array();
+ if ($is_selected) {
+ $lattrs['class'] = 'current';
+ }
+
+ (is_null($id)) ? $lattrs : $lattrs['id'] = $id;
+
+ $this->elementStart('li', $lattrs);
+ $attrs['href'] = $url;
+ if ($title) {
+ $attrs['title'] = $title;
+ }
+ $this->element('a', $attrs, $text);
+ $this->elementEnd('li');
+ }
+
+ // Does a little before-after block for next/prev page
+
+ function pagination($have_before, $have_after, $page, $action, $args=null)
+ {
+ if ($have_before || $have_after) {
+ $this->elementStart('div', array('class' => 'pagination'));
+ $this->elementStart('dl', null);
+ $this->element('dt', null, _('Pagination'));
+ $this->elementStart('dd', null);
+ $this->elementStart('ul', array('class' => 'nav'));
+ }
+
+ if ($have_before) {
+ $pargs = array('page' => $page-1);
+ $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
+
+ $this->elementStart('li', array('class' => 'nav_prev'));
+ $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'prev'),
+ _('After'));
+ $this->elementEnd('li');
+ }
+
+ if ($have_after) {
+ $pargs = array('page' => $page+1);
+ $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
+ $this->elementStart('li', array('class' => 'nav_next'));
+ $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'next'),
+ _('Before'));
+ $this->elementEnd('li');
+ }
+
+ if ($have_before || $have_after) {
+ $this->elementEnd('ul');
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ $this->elementEnd('div');
+ }
}
}
diff --git a/lib/blockform.php b/lib/blockform.php
new file mode 100644
index 000000000..b7790681d
--- /dev/null
+++ b/lib/blockform.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for blocking a user
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for blocking a user
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see UnblockForm
+ */
+
+class BlockForm extends Form
+{
+ /**
+ * Profile of user to block
+ */
+
+ var $profile = null;
+
+ /**
+ * Return-to args
+ */
+
+ var $args = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile profile of user to block
+ * @param array $args return-to args
+ */
+
+ function __construct($out=null, $profile=null, $args=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ $this->args = $args;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'block-' . $this->profile->id;
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+
+ function formClass()
+ {
+ return 'form_user_block';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('block');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('blockto-' . $this->profile->id,
+ $this->profile->id,
+ 'blockto');
+ if ($this->args) {
+ foreach ($this->args as $k => $v) {
+ $this->out->hidden('returnto-' . $k, $v);
+ }
+ }
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Block'));
+ }
+}
diff --git a/lib/common.php b/lib/common.php
index 74c992f1c..1068d4c13 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -79,7 +79,7 @@ $config =
'license' =>
array('url' => 'http://creativecommons.org/licenses/by/3.0/',
'title' => 'Creative Commons Attribution 3.0',
- 'image' => 'http://i.creativecommons.org/l/by/3.0/88x31.png'),
+ 'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
'mail' =>
array('backend' => 'mail',
'params' => null),
@@ -163,11 +163,17 @@ require_once(INSTALLDIR.'/lib/subs.php');
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
require_once(INSTALLDIR.'/lib/twitter.php');
+// XXX: other formats here
+
+define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER);
+
function __autoload($class)
{
if ($class == 'OAuthRequest') {
require_once('OAuth.php');
} else if (file_exists(INSTALLDIR.'/classes/' . $class . '.php')) {
require_once(INSTALLDIR.'/classes/' . $class . '.php');
+ } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($class) . '.php')) {
+ require_once(INSTALLDIR.'/lib/' . strtolower($class) . '.php');
}
}
diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php
new file mode 100644
index 000000000..30629680e
--- /dev/null
+++ b/lib/connectsettingsaction.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Base class for connection settings 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 Settings
+ * @package Laconica
+ * @author Evan Prodromou <evan@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/settingsaction.php';
+
+/**
+ * Base class for connection settings actions
+ *
+ * @category Settings
+ * @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/
+ *
+ * @see Widget
+ */
+
+class ConnectSettingsAction extends SettingsAction
+{
+ /**
+ * Show the local navigation menu
+ *
+ * This is the same for all settings, so we show it here.
+ *
+ * @return void
+ */
+
+ function showLocalNav()
+ {
+ $menu = new ConnectSettingsNav($this);
+ $menu->show();
+ }
+}
+
+/**
+ * A widget for showing the connect group local nav menu
+ *
+ * @category Widget
+ * @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/
+ *
+ * @see HTMLOutputter
+ */
+
+class ConnectSettingsNav extends Widget
+{
+ var $action = null;
+
+ /**
+ * Construction
+ *
+ * @param Action $action current action, used for output
+ */
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ /**
+ * Show the menu
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ # action => array('prompt', 'title')
+ $menu =
+ array('imsettings' =>
+ array(_('IM'),
+ _('Updates by instant messenger (IM)')),
+ 'smssettings' =>
+ array(_('SMS'),
+ _('Updates by SMS')),
+ 'twittersettings' =>
+ array(_('Twitter'),
+ _('Twitter integration options')));
+
+ $action_name = $this->action->trimmed('action');
+ $this->action->elementStart('ul', array('class' => 'nav'));
+
+ foreach ($menu as $menuaction => $menudesc) {
+ if ($menuaction == 'imsettings' &&
+ !common_config('xmpp', 'enabled')) {
+ continue;
+ }
+ $this->action->menuItem(common_local_url($menuaction),
+ $menudesc[0],
+ $menudesc[1],
+ $action_name === $menuaction);
+ }
+
+ $this->action->elementEnd('ul');
+ }
+}
diff --git a/lib/disfavorform.php b/lib/disfavorform.php
new file mode 100644
index 000000000..45a9ddb1d
--- /dev/null
+++ b/lib/disfavorform.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for disfavoring a notice
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for disfavoring a notice
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see FavorForm
+ */
+
+class DisfavorForm extends Form
+{
+ /**
+ * Notice to disfavor
+ */
+
+ var $notice = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to disfavor
+ */
+
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out);
+
+ $this->notice = $notice;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'disfavor-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('disfavor');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+
+ function sessionToken()
+ {
+ $this->out->hidden('token-' . $this->notice->id,
+ common_session_token());
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ $this->out->element('legend', null, _('Disfavor this notice'));
+ }
+
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('notice-n'.$this->notice->id,
+ $this->notice->id,
+ 'notice');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('disfavor-submit-' . $this->notice->id,
+ _('Disfavor favorite'), 'submit', null, _('Disfavor this notice'));
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form_disfavor';
+ }
+
+}
diff --git a/lib/facebookaction.php b/lib/facebookaction.php
index 3a00c71dd..6d42596e8 100644
--- a/lib/facebookaction.php
+++ b/lib/facebookaction.php
@@ -17,9 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
-require_once(INSTALLDIR.'/lib/facebookutil.php');
+require_once INSTALLDIR.'/lib/facebookutil.php';
class FacebookAction extends Action
{
@@ -29,96 +31,236 @@ class FacebookAction extends Action
parent::handle($args);
}
- function show_header($selected = 'Home', $msg = null, $success = false)
- {
+ function showLogo(){
- start_fbml();
+ global $xw;
- # Add a timestamp to the CSS file so Facebook cache wont ignore our changes
- $ts = filemtime(theme_file('facebookapp.css'));
- $cssurl = theme_path('facebookapp.css') . "?ts=$ts";
+ $this->showStylesheets();
+ $this->showScripts();
- common_element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => $cssurl));
+ $this->elementStart('a', array('class' => 'url home bookmark',
+ 'href' => common_local_url('public')));
+ if (common_config('site', 'logo') || file_exists(theme_file('logo.png'))) {
+ $this->element('img', array('class' => 'logo photo',
+ 'src' => (common_config('site', 'logo')) ?
+ common_config('site', 'logo') : theme_path('logo.png'),
+ 'alt' => common_config('site', 'name')));
+ }
+
+ $this->element('span', array('class' => 'fn org'), common_config('site', 'name'));
+ $this->elementEnd('a');
+
+ }
- common_element('fb:dashboard');
+ function showHeader($msg = null, $success = false)
+ {
+ startFBML();
- common_element_start('fb:tabs');
- common_element('fb:tab-item', array('title' => 'Home',
- 'href' => 'index.php',
- 'selected' => ($selected == 'Home')));
- common_element('fb:tab-item', array('title' => 'Invite',
- 'href' => 'invite.php',
- 'selected' => ($selected == 'Invite')));
- common_element('fb:tab-item', array('title' => 'Settings',
- 'href' => 'settings.php',
- 'selected' => ($selected == 'Settings')));
- common_element_end('fb:tabs');
+ $this->elementStart('fb:if-section-not-added', array('section' => 'profile'));
+ $this->elementStart('span', array('id' => 'add_to_profile'));
+ $this->element('fb:add-section-button', array('section' => 'profile'));
+ $this->elementEnd('span');
+ $this->elementEnd('fb:if-section-not-added');
+ $this->showLogo();
if ($msg) {
if ($success) {
- common_element('fb:success', array('message' => $msg));
+ $this->element('fb:success', array('message' => $msg));
} else {
// XXX do an error message here
}
}
- common_element_start('div', 'main_body');
+ $this->elementStart('div', 'main_body');
+
+ }
+
+ function showNav($selected = 'Home')
+ {
+
+ $this->elementStart('dl', array("id" => 'site_nav_local_views'));
+ $this->element('dt', null, _('Local Views'));
+ $this->elementStart('dd');
+
+ $this->elementStart('ul', array('class' => 'nav'));
+
+ $this->elementStart('li', array('class' =>
+ ($selected == 'Home') ? 'current' : 'facebook_home'));
+ $this->element('a',
+ array('href' => 'index.php', 'title' => _('Home')), _('Home'));
+ $this->elementEnd('li');
+
+ $this->elementStart('li',
+ array('class' =>
+ ($selected == 'Invite') ? 'current' : 'facebook_invite'));
+ $this->element('a',
+ array('href' => 'invite.php', 'title' => _('Invite')), _('Invite'));
+ $this->elementEnd('li');
+
+ $this->elementStart('li',
+ array('class' =>
+ ($selected == 'Settings') ? 'current' : 'facebook_settings'));
+ $this->element('a',
+ array('href' => 'settings.php',
+ 'title' => _('Settings')), _('Settings'));
+ $this->elementEnd('li');
+
+ $this->elementEnd('ul');
+
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+
+ }
+
+ function showFooter()
+ {
+ $this->elementEnd('div');
+ $this->endXml();
+ }
+
+ function showInstructions()
+ {
+ global $xw;
+
+ $this->elementStart('dl', array('class' => 'system_notice'));
+ $this->element('dt', null, 'Page Notice');
+
+ $loginmsg_part1 = _('To use the %s Facebook Application you need to login ' .
+ 'with your username and password. Don\'t have a username yet? ');
+ $loginmsg_part2 = _(' a new account.');
+
+ $this->elementStart('dd');
+ $this->elementStart('p');
+ $this->text(sprintf($loginmsg_part1, common_config('site', 'name')));
+ $this->element('a',
+ array('href' => common_local_url('register')), _('Register'));
+ $this->text($loginmsg_part2);
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+
+ function showStylesheets()
+ {
+ global $xw;
+
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => getFacebookBaseCSS()));
+
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => getFacebookThemeCSS()));
}
- function show_footer()
+ function showScripts()
{
- common_element_end('div');
- common_end_xml();
+ global $xw;
+
+ $this->element('script', array('type' => 'text/javascript',
+ 'src' => getFacebookJS()));
+
}
function showLoginForm($msg = null)
{
- start_fbml();
+ startFBML();
+
+ $this->showStylesheets();
+ $this->showScripts();
- common_element_start('a', array('href' => 'http://identi.ca'));
- common_element('img', array('src' => 'http://theme.identi.ca/identica/logo.png',
- 'alt' => 'Identi.ca',
- 'id' => 'logo'));
- common_element_end('a');
+ $this->showLogo();
+
+ $this->elementStart('div', array('class' => 'content'));
+ $this->element('h1', null, _('Login'));
if ($msg) {
- common_element('fb:error', array('message' => $msg));
+ $this->element('fb:error', array('message' => $msg));
}
- common_element("h2", null,
- _('To add the Identi.ca application, you need to log into your Identi.ca account.'));
-
+ $this->showInstructions();
- common_element_start('div', array('class' => 'instructions'));
- common_element_start('p');
- common_raw('Login with your username and password. Don\'t have a username yet?'
- .' <a href="http://identi.ca/main/register">Register</a> a new account.');
- common_element_end('p');
- common_element_end('div');
+ $this->elementStart('div', array('id' => 'content_inner'));
- common_element_start('div', array('id' => 'content'));
- common_element_start('form', array('method' => 'post',
+ $this->elementStart('form', array('method' => 'post',
+ 'class' => 'form_settings',
'id' => 'login',
'action' => 'index.php'));
- common_input('nickname', _('Nickname'));
- common_password('password', _('Password'));
- common_submit('submit', _('Login'));
- common_element_end('form');
+ $this->elementStart('fieldset');
+ $this->element('legend', null, _('Login to site'));
+
+ $this->elementStart('ul', array('class' => 'form_datas'));
+ $this->elementStart('li');
+ $this->input('nickname', _('Nickname'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->password('password', _('Password'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
- common_element_start('p');
- common_element('a', array('href' => common_local_url('recoverpassword')),
+ $this->submit('submit', _('Login'));
+ $this->elementEnd('form');
+
+ $this->elementStart('p');
+ $this->element('a', array('href' => common_local_url('recoverpassword')),
_('Lost or forgotten password?'));
- common_element_end('p');
- common_element_end('div');
+ $this->elementEnd('p');
+
+ $this->elementEnd('div');
- common_end_xml();
+ $this->endXml();
}
+ function showNoticeForm($user)
+ {
+
+ global $xw;
+
+ $this->elementStart('form', array('id' => 'form_notice',
+ 'method' => 'post',
+ 'action' => 'index.php'));
+
+ $this->elementStart('fieldset');
+ $this->element('legend', null, 'Send a notice');
+
+ $this->elementStart('ul', 'form_datas');
+ $this->elementStart('li', array('id' => 'noticcommon_elemente_text'));
+ $this->element('label', array('for' => 'notice_data-text'),
+ sprintf(_('What\'s up, %s?'), $user->nickname));
+
+ $this->element('textarea', array('id' => 'notice_data-text',
+ 'cols' => 35,
+ 'rows' => 4,
+ 'name' => 'status_textarea'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+
+ $this->elementStart('dl', 'form_note');
+ $this->element('dt', null, _('Available characters'));
+ $this->element('dd', array('id' => 'notice_text-count'),
+ '140');
+ $this->elementEnd('dl');
+
+ $this->elementStart('ul', array('class' => 'form_actions'));
+
+ $this->elementStart('li', array('id' => 'notice_submit'));
+
+ $this->submit('submit', _('Send'));
+
+ /*
+ $this->element('input', array('id' => 'notice_action-submit',
+ 'class' => 'submit',
+ 'name' => 'status_submit',
+ 'type' => 'submit',
+ 'value' => _('Send')));
+ */
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
}
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 2529b8a4b..a133ce8ba 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -17,10 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-require_once(INSTALLDIR.'/extlib/facebook/facebook.php');
-require_once(INSTALLDIR.'/lib/noticelist.php');
+require_once INSTALLDIR.'/extlib/facebook/facebook.php';
+require_once INSTALLDIR.'/lib/noticelist.php';
define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2
+define("FACEBOOK_NOTICE_PREFIX", 1);
+define("FACEBOOK_PROMPTED_UPDATE_PREF", 2);
// Gets all the notices from users with a Facebook link since a given ID
function get_facebook_notices($since)
@@ -42,7 +44,7 @@ function get_facebook()
return new Facebook($apikey, $secret);
}
-function start_fbml($indent = true)
+function startFBML($indent = true)
{
global $xw;
$xw = new XMLWriter();
@@ -94,7 +96,7 @@ function update_profile_box($facebook, $fbuid, $user, $notice)
$xw = new XMLWriter();
$xw->openMemory();
- $item = new NoticeListItem($notice);
+ $item = new FacebookNoticeListItem($notice);
$item->show();
$fbml = "<fb:wide>$style " . $xw->outputMemory(false) . "</fb:wide>";
@@ -104,3 +106,182 @@ function update_profile_box($facebook, $fbuid, $user, $notice)
$facebook->api_client->profile_setFBML(null, $fbuid, $fbml, null, null, $fbml_main);
}
+
+function getFacebookBaseCSS()
+{
+ # Add a timestamp to the CSS file so Facebook cache wont ignore our changes
+ $ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.base.css');
+ $cssurl = INSTALLDIR.'/theme/base/css/facebookapp.base.css' . "?ts=$ts";
+ return $cssurl;
+}
+
+function getFacebookThemeCSS()
+{
+ # Add a timestamp to the CSS file so Facebook cache wont ignore our changes
+ $ts = filemtime(theme_file('css/facebookapp.theme.css'));
+ $cssurl = theme_path('css/facebookapp.theme.css') . "?ts=$ts";
+ return $cssurl;
+}
+
+function getFacebookJS() {
+
+ # Add a timestamp to the FBJS file so Facebook cache wont ignore our changes
+ $ts = filemtime(INSTALLDIR.'/js/facebookapp.js');
+ $jsurl = common_path('js/facebookapp.js') . "?ts=$ts";
+ return $jsurl;
+}
+
+
+// Does a little before-after block for next/prev page
+
+function facebookPagination($have_before, $have_after, $page, $action, $args=null)
+{
+
+ if ($have_before || $have_after) {
+ common_element_start('div', array('id' => 'pagination'));
+ common_element_start('ul', array('id' => 'nav_pagination'));
+ }
+
+ if ($have_before) {
+ $pargs = array('page' => $page-1);
+ $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
+
+ common_element_start('li', 'before');
+ common_element('a', array('href' => "index.php?page=$newargs[page]", 'rel' => 'prev'),
+ _('« After'));
+ common_element_end('li');
+ }
+
+ if ($have_after) {
+ $pargs = array('page' => $page+1);
+ $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
+ common_element_start('li', 'after');
+ common_element('a', array('href' => "index.php?page=$newargs[page]", 'rel' => 'next'),
+ _('Before »'));
+ common_element_end('li');
+ }
+
+ if ($have_before || $have_after) {
+ common_element_end('ul');
+ common_element_end('div');
+ }
+}
+
+
+class FacebookNoticeList extends NoticeList
+{
+ /**
+ * show the list of notices
+ *
+ * "Uses up" the stream by looping through it. So, probably can't
+ * be called twice on the same list.
+ *
+ * @return int count of notices listed.
+ */
+
+ function show()
+ {
+ common_element_start('div', array('id' =>'notices_primary'));
+ common_element('h2', null, _('Notices'));
+ common_element_start('ul', array('class' => 'notices'));
+
+ $cnt = 0;
+
+ while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
+ $cnt++;
+
+ if ($cnt > NOTICES_PER_PAGE) {
+ break;
+ }
+
+ $item = $this->newListItem($this->notice);
+ $item->show();
+ }
+
+ common_element_end('ul');
+ common_element_end('div');
+
+ return $cnt;
+ }
+
+ /**
+ * returns a new list item for the current notice
+ *
+ * Overridden to return a Facebook specific list item.
+ *
+ * @param Notice $notice the current notice
+ *
+ * @return FacebookNoticeListItem a list item for displaying the notice
+ * formatted for display in the Facebook App.
+ */
+
+ function newListItem($notice)
+ {
+ return new FacebookNoticeListItem($notice);
+ }
+
+}
+
+class FacebookNoticeListItem extends NoticeListItem
+{
+ /**
+ * recipe function for displaying a single notice in the Facebook App.
+ *
+ * Overridden to strip out some of the controls that we don't
+ * want to be available.
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ $this->showStart();
+
+ common_element_start('div', 'entry-title');
+ $this->showAuthor();
+ $this->showContent();
+ common_element_end('div');
+
+ common_element_start('div', 'entry-content');
+ $this->showNoticeLink();
+ $this->showNoticeSource();
+ $this->showReplyTo();
+ common_element_end('div');
+
+ $this->showEnd();
+ }
+
+ function showStart()
+ {
+ // XXX: RDFa
+ // TODO: add notice_type class e.g., notice_video, notice_image
+ common_element_start('li', array('class' => 'hentry notice',
+ 'id' => 'notice-' . $this->notice->id));
+ }
+
+ function showNoticeLink()
+ {
+ $noticeurl = common_local_url('shownotice',
+ array('notice' => $this->notice->id));
+ // XXX: we need to figure this out better. Is this right?
+ if (strcmp($this->notice->uri, $noticeurl) != 0 &&
+ preg_match('/^http/', $this->notice->uri)) {
+ $noticeurl = $this->notice->uri;
+ }
+
+ common_element_start('dl', 'timestamp');
+ common_element('dt', null, _('Published'));
+ common_element_start('dd', null);
+ common_element_start('a', array('rel' => 'bookmark',
+ 'href' => $noticeurl));
+ $dt = common_date_iso8601($this->notice->created);
+ common_element('abbr', array('class' => 'published',
+ 'title' => $dt),
+ common_date_string($this->notice->created));
+ common_element_end('a');
+ common_element_end('dd');
+ common_element_end('dl');
+ }
+
+}
+
diff --git a/lib/favorform.php b/lib/favorform.php
new file mode 100644
index 000000000..f3a7a9756
--- /dev/null
+++ b/lib/favorform.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for favoring a notice
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for favoring a notice
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see DisfavorForm
+ */
+
+class FavorForm extends Form
+{
+ /**
+ * Notice to favor
+ */
+
+ var $notice = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to favor
+ */
+
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out);
+
+ $this->notice = $notice;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'favor-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('favor');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+
+ function sessionToken()
+ {
+ $this->out->hidden('token-' . $this->notice->id,
+ common_session_token());
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ $this->out->element('legend', null, _('Favor this notice'));
+ }
+
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('notice-n'.$this->notice->id,
+ $this->notice->id,
+ 'notice');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('favor-submit-' . $this->notice->id,
+ _('Favor'), 'submit', null, _('Favor this notice'));
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form_favor';
+ }
+}
diff --git a/lib/feedlist.php b/lib/feedlist.php
new file mode 100644
index 000000000..47d909e96
--- /dev/null
+++ b/lib/feedlist.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Widget for showing a list of feeds
+ *
+ * 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 Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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);
+}
+
+/**
+ * Widget for showing a list of feeds
+ *
+ * Typically used for Action::showExportList()
+ *
+ * @category Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see Action::showExportList()
+ */
+
+class FeedList extends Widget
+{
+ var $action = null;
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ function show($feeds)
+ {
+ $this->out->elementStart('div', array('id' => 'export_data',
+ 'class' => 'section'));
+ $this->out->element('h2', null, _('Export data'));
+ $this->out->elementStart('ul', array('class' => 'xoxo'));
+
+ foreach ($feeds as $key => $value) {
+ $this->feedItem($feeds[$key]);
+ }
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('div');
+ }
+
+ function feedItem($feed)
+ {
+ $nickname = $this->action->trimmed('nickname');
+
+ switch($feed['item']) {
+ case 'notices': default:
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "$nickname's ".$feed['version']." notice feed";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'allrss':
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = $feed['version']." feed for $nickname and friends";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'repliesrss':
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = $feed['version']." feed for replies to $nickname";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'publicrss':
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "Public timeline ".$feed['version']." feed";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'publicatom':
+ $feed_classname = "atom";
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "Public timeline ".$feed['version']." feed";
+ $feed['textContent'] = "Atom";
+ break;
+
+ case 'tagrss':
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = $feed['version']." feed for this tag";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'favoritedrss':
+ $feed_classname = $feed['type'];
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "Favorited ".$feed['version']." feed";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'foaf':
+ $feed_classname = "foaf";
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "$nickname's FOAF file";
+ $feed['textContent'] = "FOAF";
+ break;
+
+ case 'favoritesrss':
+ $feed_classname = "favorites";
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "Feed for favorites of $nickname";
+ $feed['textContent'] = "RSS";
+ break;
+
+ case 'usertimeline':
+ $feed_classname = "atom";
+ $feed_mimetype = "application/".$feed['type']."+xml";
+ $feed_title = "$nickname's ".$feed['version']." notice feed";
+ $feed['textContent'] = "Atom";
+ break;
+ }
+ $this->out->elementStart('li');
+ $this->out->element('a', array('href' => $feed['href'],
+ 'class' => $feed_classname,
+ 'type' => $feed_mimetype,
+ 'title' => $feed_title),
+ $feed['textContent']);
+ $this->out->elementEnd('li');
+ }
+}
diff --git a/lib/form.php b/lib/form.php
new file mode 100644
index 000000000..011d4bfc9
--- /dev/null
+++ b/lib/form.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Base class for forms
+ *
+ * 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 Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/widget.php';
+
+/**
+ * Base class for forms
+ *
+ * We have a lot of common forms (subscribe, fave, delete) and this superclass
+ * lets us abstract out the basic features of the form.
+ *
+ * @category Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class Form extends Widget
+{
+ /**
+ * Show the form
+ *
+ * Uses a recipe to output the form.
+ *
+ * @return void
+ * @see Widget::show()
+ */
+
+ function show()
+ {
+ $this->out->elementStart('form',
+ array('id' => $this->id(),
+ 'class' => $this->formClass(),
+ 'method' => 'post',
+ 'action' => $this->action()));
+ $this->out->elementStart('fieldset');
+ $this->formLegend();
+ $this->sessionToken();
+ $this->formData();
+ $this->formActions();
+ $this->out->elementEnd('fieldset');
+ $this->out->elementEnd('form');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+
+ function sessionToken()
+ {
+ $this->out->hidden('token', common_session_token());
+ }
+
+
+ /**
+ * Name of the form
+ *
+ * Sub-classes should overload this with the name of their form.
+ *
+ * @return void
+ */
+
+ function formLegend()
+ {
+ }
+
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return null;
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form';
+ }
+}
diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php
new file mode 100644
index 000000000..1e164933c
--- /dev/null
+++ b/lib/htmloutputter.php
@@ -0,0 +1,353 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Low-level generator for HTML
+ *
+ * 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 Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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/xmloutputter.php';
+
+define('PAGE_TYPE_PREFS',
+ 'text/html,application/xhtml+xml,'.
+ 'application/xml;q=0.3,text/xml;q=0.2');
+
+/**
+ * Low-level generator for HTML
+ *
+ * Abstracts some of the code necessary for HTML generation. Especially
+ * has methods for generating HTML form elements. Note that these have
+ * been created kind of haphazardly, not with an eye to making a general
+ * HTML-creation class.
+ *
+ * @category Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see Action
+ * @see XMLOutputter
+ */
+
+class HTMLOutputter extends XMLOutputter
+{
+ /**
+ * Constructor
+ *
+ * Just wraps the XMLOutputter constructor.
+ *
+ * @param string $output URI to output to, default = stdout
+ * @param boolean $indent Whether to indent output, default true
+ */
+
+ function __construct($output='php://output', $indent=true)
+ {
+ parent::__construct($output, $indent);
+ }
+
+ /**
+ * Start an HTML document
+ *
+ * If $type isn't specified, will attempt to do content negotiation.
+ *
+ * Attempts to do content negotiation for language, also.
+ *
+ * @param string $type MIME type to use; default is to do negotation.
+ *
+ * @todo extract content negotiation code to an HTTP module or class.
+ *
+ * @return void
+ */
+
+ function startHTML($type=null)
+ {
+ if (!$type) {
+ $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
+ $_SERVER['HTTP_ACCEPT'] : null;
+
+ // XXX: allow content negotiation for RDF, RSS, or XRDS
+
+ $cp = common_accept_to_prefs($httpaccept);
+ $sp = common_accept_to_prefs(PAGE_TYPE_PREFS);
+
+ $type = common_negotiate_type($cp, $sp);
+
+ if (!$type) {
+ common_user_error(_('This page is not available in a '.
+ 'media type you accept'), 406);
+ exit(0);
+ }
+ }
+
+ header('Content-Type: '.$type);
+
+ $this->startXML('html',
+ '-//W3C//DTD XHTML 1.0 Strict//EN',
+ 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
+
+ // FIXME: correct language for interface
+
+ $language = common_language();
+
+ $this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
+ 'xml:lang' => $language,
+ 'lang' => $language));
+ }
+
+ /**
+ * Ends an HTML document
+ *
+ * @return void
+ */
+ function endHTML()
+ {
+ $this->elementEnd('html');
+ $this->endXML();
+ }
+
+ /**
+ * Output an HTML text input element
+ *
+ * Despite the name, it is specifically for outputting a
+ * text input element, not other <input> elements. It outputs
+ * a cluster of elements, including a <label> and an associated
+ * instructions span.
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of label for the element
+ * @param string $value value of the element, default null
+ * @param string $instructions instructions for valid input
+ *
+ * @todo add a $name parameter
+ * @todo add a $maxLength parameter
+ * @todo add a $size parameter
+ *
+ * @return void
+ */
+
+ function input($id, $label, $value=null, $instructions=null)
+ {
+ $this->element('label', array('for' => $id), $label);
+ $attrs = array('name' => $id,
+ 'type' => 'text',
+ 'id' => $id);
+ if ($value) {
+ $attrs['value'] = htmlspecialchars($value);
+ }
+ $this->element('input', $attrs);
+ if ($instructions) {
+ $this->element('p', 'form_guide', $instructions);
+ }
+ }
+
+ /**
+ * output an HTML checkbox and associated elements
+ *
+ * Note that the value is default 'true' (the string), which can
+ * be used by Action::boolean()
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of label for the element
+ * @param string $checked if the box is checked, default false
+ * @param string $instructions instructions for valid input
+ * @param string $value value of the checkbox, default 'true'
+ * @param string $disabled show the checkbox disabled, default false
+ *
+ * @return void
+ *
+ * @todo add a $name parameter
+ */
+
+ function checkbox($id, $label, $checked=false, $instructions=null,
+ $value='true', $disabled=false)
+ {
+ $attrs = array('name' => $id,
+ 'type' => 'checkbox',
+ 'class' => 'checkbox',
+ 'id' => $id);
+ if ($value) {
+ $attrs['value'] = htmlspecialchars($value);
+ }
+ if ($checked) {
+ $attrs['checked'] = 'checked';
+ }
+ if ($disabled) {
+ $attrs['disabled'] = 'true';
+ }
+ $this->element('input', $attrs);
+ $this->text(' ');
+ $this->element('label', array('class' => 'checkbox',
+ 'for' => $id),
+ $label);
+ $this->text(' ');
+ if ($instructions) {
+ $this->element('p', 'form_guide', $instructions);
+ }
+ }
+
+ /**
+ * output an HTML combobox/select and associated elements
+ *
+ * $content is an array of key-value pairs for the dropdown, where
+ * the key is the option value attribute and the value is the option
+ * text. (Careful on the overuse of 'value' here.)
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of label for the element
+ * @param array $content options array, value => text
+ * @param string $instructions instructions for valid input
+ * @param string $blank_select whether to have a blank entry, default false
+ * @param string $selected selected value, default null
+ *
+ * @return void
+ *
+ * @todo add a $name parameter
+ */
+
+ function dropdown($id, $label, $content, $instructions=null,
+ $blank_select=false, $selected=null)
+ {
+ $this->element('label', array('for' => $id), $label);
+ $this->elementStart('select', array('id' => $id, 'name' => $id));
+ if ($blank_select) {
+ $this->element('option', array('value' => ''));
+ }
+ foreach ($content as $value => $option) {
+ if ($value == $selected) {
+ $this->element('option', array('value' => $value,
+ 'selected' => $value),
+ $option);
+ } else {
+ $this->element('option', array('value' => $value), $option);
+ }
+ }
+ $this->elementEnd('select');
+ if ($instructions) {
+ $this->element('p', 'form_guide', $instructions);
+ }
+ }
+
+ /**
+ * output an HTML hidden element
+ *
+ * $id is re-used as name
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $value hidden element value, default null
+ * @param string $name name, if different than ID
+ *
+ * @return void
+ */
+
+ function hidden($id, $value, $name=null)
+ {
+ $this->element('input', array('name' => ($name) ? $name : $id,
+ 'type' => 'hidden',
+ 'id' => $id,
+ 'value' => $value));
+ }
+
+ /**
+ * output an HTML password input and associated elements
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of label for the element
+ * @param string $instructions instructions for valid input
+ *
+ * @return void
+ *
+ * @todo add a $name parameter
+ */
+
+ function password($id, $label, $instructions=null)
+ {
+ $this->element('label', array('for' => $id), $label);
+ $attrs = array('name' => $id,
+ 'type' => 'password',
+ 'class' => 'password',
+ 'id' => $id);
+ $this->element('input', $attrs);
+ if ($instructions) {
+ $this->element('p', 'form_guide', $instructions);
+ }
+ }
+
+ /**
+ * output an HTML submit input and associated elements
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of the button
+ * @param string $cls class of the button, default 'submit'
+ * @param string $name name, if different than ID
+ *
+ * @return void
+ *
+ * @todo add a $name parameter
+ */
+
+ function submit($id, $label, $cls='submit', $name=null, $title=null)
+ {
+ $this->element('input', array('type' => 'submit',
+ 'id' => $id,
+ 'name' => ($name) ? $name : $id,
+ 'class' => $cls,
+ 'value' => $label,
+ 'title' => $title));
+ }
+
+ /**
+ * output an HTML textarea and associated elements
+ *
+ * @param string $id element ID, must be unique on page
+ * @param string $label text of label for the element
+ * @param string $content content of the textarea, default none
+ * @param string $instructions instructions for valid input
+ *
+ * @return void
+ *
+ * @todo add a $name parameter
+ * @todo add a $cols parameter
+ * @todo add a $rows parameter
+ */
+
+ function textarea($id, $label, $content=null, $instructions=null)
+ {
+ $this->element('label', array('for' => $id), $label);
+ $this->element('textarea', array('rows' => 3,
+ 'cols' => 40,
+ 'name' => $id,
+ 'id' => $id),
+ ($content) ? $content : '');
+ if ($instructions) {
+ $this->element('p', 'form_guide', $instructions);
+ }
+ }
+}
diff --git a/lib/logingroupnav.php b/lib/logingroupnav.php
new file mode 100644
index 000000000..8c03eccea
--- /dev/null
+++ b/lib/logingroupnav.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Menu for login group of 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 Menu
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 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/widget.php';
+
+/**
+ * Menu for login group of actions
+ *
+ * @category Output
+ * @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/
+ *
+ * @see Widget
+ */
+
+class LoginGroupNav extends Widget
+{
+ var $action = null;
+
+ /**
+ * Construction
+ *
+ * @param Action $action current action, used for output
+ */
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ /**
+ * Show the menu
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ // action => array('prompt', 'title')
+ $menu =
+ array('login' =>
+ array(_('Login'),
+ _('Login with a username and password')),
+ 'register' =>
+ array(_('Register'),
+ _('Sign up for a new account')),
+ 'openid' =>
+ array(_('OpenID'),
+ _('Login or register with OpenID')));
+
+ $action_name = $this->action->trimmed('action');
+ $this->action->elementStart('ul', array('class' => 'nav'));
+
+ foreach ($menu as $menuaction => $menudesc) {
+ $this->action->menuItem(common_local_url($menuaction),
+ $menudesc[0],
+ $menudesc[1],
+ $action_name === $menuaction);
+ }
+
+ $this->action->elementEnd('ul');
+ }
+}
diff --git a/lib/mailbox.php b/lib/mailbox.php
index bdc360a35..9af0dbd2f 100644
--- a/lib/mailbox.php
+++ b/lib/mailbox.php
@@ -49,6 +49,23 @@ define('MESSAGES_PER_PAGE', 20);
class MailboxAction extends PersonalAction
{
+ var $page = null;
+
+ 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;
+ }
+
+ return true;
+ }
+
/**
* output page based on arguments
*
@@ -61,134 +78,42 @@ class MailboxAction extends PersonalAction
{
parent::handle($args);
- $nickname = common_canonical_nickname($this->arg('nickname'));
-
- $user = User::staticGet('nickname', $nickname);
-
- if (!$user) {
- $this->client_error(_('No such user.'), 404);
+ if (!$this->user) {
+ $this->clientError(_('No such user.'), 404);
return;
}
$cur = common_current_user();
- if (!$cur || $cur->id != $user->id) {
- $this->client_error(_('Only the user can read their own mailboxes.'),
- 403);
- return;
- }
-
- $profile = $user->getProfile();
-
- if (!$profile) {
- $this->server_error(_('User has no profile.'));
+ if (!$cur || $cur->id != $this->user->id) {
+ $this->clientError(_('Only the user can read their own mailboxes.'),
+ 403);
return;
}
- $page = $this->trimmed('page');
-
- if (!$page) {
- $page = 1;
- }
-
- $this->showPage($user, $page);
+ $this->showPage();
}
- /**
- * returns the title of the page
- *
- * @param User $user current user
- * @param int $page current page
- *
- * @return string localised title of the page
- */
-
- function getTitle($user, $page)
+ function showLocalNav()
{
- return '';
+ $nav = new PersonalGroupNav($this);
+ $nav->show();
}
- /**
- * instructions for using this page
- *
- * @return string localised instructions for using the page
- */
-
- function getInstructions()
+ function showNoticeForm()
{
- return '';
+ $message_form = new MessageForm($this);
+ $message_form->show();
}
- /**
- * do structured output for the "instructions" are of the page
- *
- * @return void
- */
-
- function showTop()
+ function showContent()
{
- $cur = common_current_user();
-
- common_message_form(null, $cur, null);
-
- $this->views_menu();
- }
-
- /**
- * show a full page of output
- *
- * @param User $user The current user
- * @param int $page The page the user is on
- *
- * @return void
- */
-
- function showPage($user, $page)
- {
- common_show_header($this->getTitle($user, $page),
- null, null,
- array($this, 'showTop'));
-
- $this->showBox($user, $page);
-
- common_show_footer();
- }
-
- /**
- * retrieve the messages appropriate for this mailbox
- *
- * Does a query for the right messages
- *
- * @param User $user The current user
- * @param int $page The page the user is on
- *
- * @return Message data object with stream for messages
- */
-
- function getMessages($user, $page)
- {
- return null;
- }
-
- /**
- * show the messages for a mailbox in list format
- *
- * Includes the pagination links (before, after).
- *
- * @param User $user The current user
- * @param int $page The page the user is on
- *
- * @return void
- */
-
- function showBox($user, $page)
- {
- $message = $this->getMessages($user, $page);
+ $message = $this->getMessages();
if ($message) {
$cnt = 0;
- common_element_start('ul', array('id' => 'messages'));
+ $this->elementStart('ul', array('id' => 'messages'));
while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
$cnt++;
@@ -200,17 +125,22 @@ class MailboxAction extends PersonalAction
$this->showMessage($message);
}
- common_element_end('ul');
+ $this->elementEnd('ul');
- common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
- $page, $this->trimmed('action'),
- array('nickname' => $user->nickname));
+ $this->pagination($this->page > 1, $cnt > MESSAGES_PER_PAGE,
+ $this->page, $this->trimmed('action'),
+ array('nickname' => $this->user->nickname));
$message->free();
unset($message);
}
}
+ function getMessages()
+ {
+ return null;
+ }
+
/**
* returns the profile we want to show with the message
*
@@ -229,6 +159,9 @@ class MailboxAction extends PersonalAction
/**
* show a single message in the list format
*
+ * XXX: This needs to be extracted out into a MessageList similar
+ * to NoticeList.
+ *
* @param Message $message the message to show
*
* @return void
@@ -236,14 +169,14 @@ class MailboxAction extends PersonalAction
function showMessage($message)
{
- common_element_start('li', array('class' => 'message_single',
+ $this->elementStart('li', array('class' => 'message_single',
'id' => 'message-' . $message->id));
$profile = $this->getMessageProfile($message);
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
- common_element_start('a', array('href' => $profile->profileurl));
- common_element('img', array('src' => ($avatar) ?
+ $this->elementStart('a', array('href' => $profile->profileurl));
+ $this->element('img', array('src' => ($avatar) ?
common_avatar_display_url($avatar) :
common_default_avatar(AVATAR_STREAM_SIZE),
'class' => 'avatar stream',
@@ -252,14 +185,14 @@ class MailboxAction extends PersonalAction
'alt' =>
($profile->fullname) ? $profile->fullname :
$profile->nickname));
- common_element_end('a');
- common_element('a', array('href' => $profile->profileurl,
+ $this->elementEnd('a');
+ $this->element('a', array('href' => $profile->profileurl,
'class' => 'nickname'),
$profile->nickname);
// FIXME: URL, image, video, audio
- common_element_start('p', array('class' => 'content'));
- common_raw($message->rendered);
- common_element_end('p');
+ $this->elementStart('p', array('class' => 'content'));
+ $this->raw($message->rendered);
+ $this->elementEnd('p');
$messageurl = common_local_url('showmessage',
array('message' => $message->id));
@@ -269,18 +202,72 @@ class MailboxAction extends PersonalAction
preg_match('/^http/', $message->uri)) {
$messageurl = $message->uri;
}
- common_element_start('p', 'time');
- common_element('a', array('class' => 'permalink',
+ $this->elementStart('p', 'time');
+ $this->element('a', array('class' => 'permalink',
'href' => $messageurl,
'title' => common_exact_date($message->created)),
common_date_string($message->created));
if ($message->source) {
- common_text(_(' from '));
- $this->source_link($message->source);
+ $this->text(_(' from '));
+ $this->showSource($message->source);
}
- common_element_end('p');
+ $this->elementEnd('p');
- common_element_end('li');
+ $this->elementEnd('li');
}
+
+ /**
+ * Show the page notice
+ *
+ * Shows instructions for the page
+ *
+ * @return void
+ */
+
+ function showPageNotice()
+ {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Show the source of the message
+ *
+ * Returns either the name (and link) of the API client that posted the notice,
+ * or one of other other channels.
+ *
+ * @param string $source the source of the message
+ *
+ * @return void
+ */
+
+ function showSource($source)
+ {
+ $source_name = _($source);
+ switch ($source) {
+ case 'web':
+ case 'xmpp':
+ case 'mail':
+ case 'omb':
+ case 'api':
+ $this->element('span', 'noticesource', $source_name);
+ break;
+ default:
+ $ns = Notice_source::staticGet($source);
+ if ($ns) {
+ $this->element('a', array('href' => $ns->url),
+ $ns->name);
+ } else {
+ $this->element('span', 'noticesource', $source_name);
+ }
+ break;
+ }
+ return;
+ }
+
}
diff --git a/lib/messageform.php b/lib/messageform.php
new file mode 100644
index 000000000..eca39cc06
--- /dev/null
+++ b/lib/messageform.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for posting a direct message
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for posting a direct message
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class MessageForm extends Form
+{
+ /**
+ * User to send a direct message to
+ */
+
+ var $to = null;
+
+ /**
+ * Pre-filled content of the form
+ */
+
+ var $content = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param User $to user to send a message to
+ * @param string $content content to pre-fill
+ */
+
+ function __construct($out=null, $to=null, $content=null)
+ {
+ parent::__construct($out);
+
+ $this->to = $to;
+ $this->content = $content;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'message_form';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('newmessage');
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $user = common_current_user();
+
+ $mutual_users = $user->mutuallySubscribedUsers();
+
+ $mutual = array();
+
+ while ($mutual_users->fetch()) {
+ if ($mutual_users->id != $user->id) {
+ $mutual[$mutual_users->id] = $mutual_users->nickname;
+ }
+ }
+
+ $mutual_users->free();
+ unset($mutual_users);
+
+ $this->out->dropdown('to', _('To'), $mutual, null, false,
+ $this->to->id);
+
+ $this->out->elementStart('p');
+
+ $this->out->element('textarea', array('id' => 'message_content',
+ 'cols' => 60,
+ 'rows' => 3,
+ 'name' => 'content'),
+ ($this->content) ? $this->content : '');
+
+ $this->out->elementEnd('p');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->element('input', array('id' => 'message_send',
+ 'name' => 'message_send',
+ 'type' => 'submit',
+ 'value' => _('Send')));
+ }
+} \ No newline at end of file
diff --git a/lib/microid.php b/lib/microid.php
new file mode 100644
index 000000000..806b7ee7d
--- /dev/null
+++ b/lib/microid.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Microid class
+ *
+ * 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 ID
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 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);
+}
+
+/**
+ * A class for microids
+ *
+ * @category ID
+ * @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/
+ * @see http://microid.org/
+ */
+
+class Microid
+{
+ /** Agent part of the ID. */
+
+ var $agent = null;
+
+ /** Resource part of the ID. */
+
+ var $resource = null;
+
+ /**
+ * Constructor
+ *
+ * @param string $agent Agent of the ID
+ * @param string $resource Resource part
+ */
+
+ function __construct($agent, $resource)
+ {
+ $this->agent = $agent;
+ $this->resource = $resource;
+
+ }
+
+ /**
+ * Generate a MicroID string
+ *
+ * @return string MicroID for agent and resource
+ */
+
+ function toString()
+ {
+ $agent_proto = $this->_getProto($this->agent);
+ $resource_proto = $this->_getProto($this->resource);
+
+ return $agent_proto.'+'.$resource_proto.':sha1:'.
+ sha1(sha1($this->agent).sha1($this->resource));
+ }
+
+ /**
+ * Utility for getting the protocol part of a URI
+ *
+ * @param string $uri URI to parse
+ *
+ * @return string scheme part of the URI
+ */
+
+ function _getProto($uri)
+ {
+ $colon = strpos($uri, ':');
+ return substr($uri, 0, $colon);
+ }
+}
diff --git a/lib/noticeform.php b/lib/noticeform.php
new file mode 100644
index 000000000..f0205f1c1
--- /dev/null
+++ b/lib/noticeform.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for posting a notice
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for posting a notice
+ *
+ * Frequently-used form for posting a notice
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class NoticeForm extends Form
+{
+ /**
+ * Current action, used for returning to this page.
+ */
+
+ var $action = null;
+
+ /**
+ * Pre-filled content of the form
+ */
+
+ var $content = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param string $action action to return to, if any
+ * @param string $content content to pre-fill
+ */
+
+ function __construct($out=null, $action=null, $content=null)
+ {
+ parent::__construct($out);
+
+ $this->action = $action;
+ $this->content = $content;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'form_notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('newnotice');
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ $this->out->element('legend', null, _('Send a notice'));
+ }
+
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $user = common_current_user();
+
+ $this->out->elementStart('ul', 'form_data');
+ $this->out->elementStart('li', array('id' => 'notice_text'));
+ $this->out->element('label', array('for' => 'notice_data-text'),
+ sprintf(_('What\'s up, %s?'), $user->nickname));
+ // XXX: vary by defined max size
+ $this->out->element('textarea', array('id' => 'notice_data-text',
+ 'cols' => 35,
+ 'rows' => 4,
+ 'name' => 'status_textarea'),
+ ($this->content) ? $this->content : '');
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+
+ $this->out->elementStart('dl', 'form_note');
+ $this->out->element('dt', null, _('Available characters'));
+ $this->out->element('dd', array('id' => 'notice_text-count'),
+ '140');
+ $this->out->elementEnd('dl');
+
+ if ($this->action) {
+ $this->out->hidden('notice_return-to', $this->action, 'returnto');
+ }
+ $this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->elementStart('ul', 'form_actions');
+ $this->out->elementStart('li', array('id' => 'notice_submit'));
+ $this->out->element('input', array('id' => 'notice_action-submit',
+ 'class' => 'submit',
+ 'name' => 'status_submit',
+ 'type' => 'submit',
+ 'value' => _('Send')));
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+ }
+}
diff --git a/lib/noticelist.php b/lib/noticelist.php
index 71db067d0..c57d6ce19 100644
--- a/lib/noticelist.php
+++ b/lib/noticelist.php
@@ -31,6 +31,9 @@ if (!defined('LACONICA')) {
exit(1);
}
+require_once INSTALLDIR.'/lib/favorform.php';
+require_once INSTALLDIR.'/lib/disfavorform.php';
+
/**
* widget for displaying a list of notices
*
@@ -50,7 +53,7 @@ if (!defined('LACONICA')) {
* @see ProfileNoticeList
*/
-class NoticeList
+class NoticeList extends Widget
{
/** the current stream of notices being displayed. */
@@ -62,8 +65,9 @@ class NoticeList
* @param Notice $notice stream of notices from DB_DataObject
*/
- function __construct($notice)
+ function __construct($notice, $out=null)
{
+ parent::__construct($out);
$this->notice = $notice;
}
@@ -78,7 +82,9 @@ class NoticeList
function show()
{
- common_element_start('ul', array('id' => 'notices'));
+ $this->out->elementStart('div', array('id' =>'notices_primary'));
+ $this->out->element('h2', null, _('Notices'));
+ $this->out->elementStart('ul', array('class' => 'notices'));
$cnt = 0;
@@ -93,7 +99,8 @@ class NoticeList
$item->show();
}
- common_element_end('ul');
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('div');
return $cnt;
}
@@ -111,7 +118,7 @@ class NoticeList
function newListItem($notice)
{
- return new NoticeListItem($notice);
+ return new NoticeListItem($notice, $this->out);
}
}
@@ -133,7 +140,7 @@ class NoticeList
* @see ProfileNoticeListItem
*/
-class NoticeListItem
+class NoticeListItem extends Widget
{
/** The notice this item will show. */
@@ -151,8 +158,9 @@ class NoticeListItem
* @param Notice $notice The notice we'll display
*/
- function __construct($notice)
+ function __construct($notice, $out=null)
{
+ parent::__construct($out);
$this->notice = $notice;
$this->profile = $notice->getProfile();
}
@@ -169,17 +177,36 @@ class NoticeListItem
function show()
{
$this->showStart();
- $this->showFaveForm();
+ $this->showNotice();
+ $this->showNoticeInfo();
+ $this->showNoticeOptions();
+ $this->showEnd();
+ }
+
+ function showNotice()
+ {
+ $this->out->elementStart('div', 'entry-title');
$this->showAuthor();
$this->showContent();
- $this->startTimeSection();
+ $this->out->elementEnd('div');
+ }
+
+ function showNoticeInfo()
+ {
+ $this->out->elementStart('div', 'entry-content');
$this->showNoticeLink();
$this->showNoticeSource();
$this->showReplyTo();
+ $this->out->elementEnd('div');
+ }
+
+ function showNoticeOptions()
+ {
+ $this->out->elementStart('div', 'notice-options');
+ $this->showFaveForm();
$this->showReplyLink();
$this->showDeleteLink();
- $this->endTimeSection();
- $this->showEnd();
+ $this->out->elementEnd('div');
}
/**
@@ -191,8 +218,9 @@ class NoticeListItem
function showStart()
{
// XXX: RDFa
- common_element_start('li', array('class' => 'notice_single hentry',
- 'id' => 'notice-' . $this->notice->id));
+ // TODO: add notice_type class e.g., notice_video, notice_image
+ $this->out->elementStart('li', array('class' => 'hentry notice',
+ 'id' => 'notice-' . $this->notice->id));
}
/**
@@ -206,9 +234,11 @@ class NoticeListItem
$user = common_current_user();
if ($user) {
if ($user->hasFave($this->notice)) {
- common_disfavor_form($this->notice);
+ $disfavor = new DisfavorForm($this->out, $this->notice);
+ $disfavor->show();
} else {
- common_favor_form($this->notice);
+ $favor = new FavorForm($this->out, $this->notice);
+ $favor->show();
}
}
}
@@ -223,10 +253,13 @@ class NoticeListItem
function showAuthor()
{
- common_element_start('span', 'vcard author');
+ $this->out->elementStart('span', 'vcard author');
+ $this->out->elementStart('a', array('href' => $this->profile->profileurl,
+ 'class' => 'url'));
$this->showAvatar();
$this->showNickname();
- common_element_end('span');
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('span');
}
/**
@@ -241,18 +274,17 @@ class NoticeListItem
function showAvatar()
{
$avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE);
- common_element_start('a', array('href' => $this->profile->profileurl));
- common_element('img', array('src' => ($avatar) ?
- common_avatar_display_url($avatar) :
- common_default_avatar(AVATAR_STREAM_SIZE),
- 'class' => 'avatar stream photo',
- 'width' => AVATAR_STREAM_SIZE,
- 'height' => AVATAR_STREAM_SIZE,
- 'alt' =>
- ($this->profile->fullname) ?
- $this->profile->fullname :
- $this->profile->nickname));
- common_element_end('a');
+
+ $this->out->element('img', array('src' => ($avatar) ?
+ common_avatar_display_url($avatar) :
+ common_default_avatar(AVATAR_STREAM_SIZE),
+ 'class' => 'avatar photo',
+ 'width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'alt' =>
+ ($this->profile->fullname) ?
+ $this->profile->fullname :
+ $this->profile->nickname));
}
/**
@@ -265,9 +297,8 @@ class NoticeListItem
function showNickname()
{
- common_element('a', array('href' => $this->profile->profileurl,
- 'class' => 'nickname fn url'),
- $this->profile->nickname);
+ $this->out->element('span', array('class' => 'nickname fn'),
+ $this->profile->nickname);
}
/**
@@ -283,31 +314,16 @@ class NoticeListItem
function showContent()
{
// FIXME: URL, image, video, audio
- common_element_start('p', array('class' => 'content entry-title'));
+ $this->out->elementStart('p', array('class' => 'entry-content'));
if ($this->notice->rendered) {
- common_raw($this->notice->rendered);
+ $this->out->raw($this->notice->rendered);
} else {
// XXX: may be some uncooked notices in the DB,
// we cook them right now. This should probably disappear in future
// versions (>> 0.4.x)
- common_raw(common_render_content($this->notice->content, $this->notice));
+ $this->out->raw(common_render_content($this->notice->content, $this->notice));
}
- common_element_end('p');
- }
-
- /**
- * show the "time" section of a notice
- *
- * This is the greyed-out section that appears beneath the content, including
- * links to delete or reply to the notice. Probably should be called something
- * else.
- *
- * @return void
- */
-
- function startTimeSection()
- {
- common_element_start('p', 'time');
+ $this->out->elementEnd('p');
}
/**
@@ -328,14 +344,18 @@ class NoticeListItem
preg_match('/^http/', $this->notice->uri)) {
$noticeurl = $this->notice->uri;
}
- common_element_start('a', array('class' => 'permalink',
- 'rel' => 'bookmark',
- 'href' => $noticeurl));
+ $this->out->elementStart('dl', 'timestamp');
+ $this->out->element('dt', null, _('Published'));
+ $this->out->elementStart('dd', null);
+ $this->out->elementStart('a', array('rel' => 'bookmark',
+ 'href' => $noticeurl));
$dt = common_date_iso8601($this->notice->created);
- common_element('abbr', array('class' => 'published',
- 'title' => $dt),
- common_date_string($this->notice->created));
- common_element_end('a');
+ $this->out->element('abbr', array('class' => 'published',
+ 'title' => $dt),
+ common_date_string($this->notice->created));
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
/**
@@ -350,26 +370,31 @@ class NoticeListItem
function showNoticeSource()
{
if ($this->notice->source) {
- common_element('span', null, _(' from '));
+ $this->out->elementStart('dl', 'device');
+ $this->out->element('dt', null, _('From'));
$source_name = _($this->notice->source);
switch ($this->notice->source) {
- case 'web':
- case 'xmpp':
- case 'mail':
- case 'omb':
- case 'api':
- common_element('span', 'noticesource', $source_name);
+ case 'web':
+ case 'xmpp':
+ case 'mail':
+ case 'omb':
+ case 'api':
+ $this->out->element('dd', 'noticesource', $source_name);
break;
- default:
+ default:
$ns = Notice_source::staticGet($this->notice->source);
if ($ns) {
- common_element('a', array('href' => $ns->url),
- $ns->name);
+ $this->out->elementStart('dd', null);
+ $this->out->element('a', array('href' => $ns->url,
+ 'rel' => 'external'),
+ $ns->name);
+ $this->out->elementEnd('dd');
} else {
- common_element('span', 'noticesource', $source_name);
+ $this->out->element('dd', 'noticesource', $source_name);
}
break;
}
+ $this->out->elementEnd('dl');
}
}
@@ -387,11 +412,14 @@ class NoticeListItem
if ($this->notice->reply_to) {
$replyurl = common_local_url('shownotice',
array('notice' => $this->notice->reply_to));
- common_text(' (');
- common_element('a', array('class' => 'inreplyto',
- 'href' => $replyurl),
- _('in reply to...'));
- common_text(')');
+ $this->out->elementStart('dl', 'response');
+ $this->out->element('dt', null, _('To'));
+ $this->out->elementStart('dd');
+ $this->out->element('a', array('href' => $replyurl,
+ 'rel' => 'in-reply-to'),
+ _('in reply to'));
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
}
@@ -409,16 +437,13 @@ class NoticeListItem
$reply_url = common_local_url('newnotice',
array('replyto' => $this->profile->nickname));
- $reply_js =
- 'return doreply("'.$this->profile->nickname.'",'.$this->notice->id.');';
-
- common_element_start('a',
- array('href' => $reply_url,
- 'onclick' => $reply_js,
- 'title' => _('reply'),
- 'class' => 'replybutton'));
- common_raw(' &#8594;');
- common_element_end('a');
+ $this->out->elementStart('dl', 'notice_reply');
+ $this->out->element('dt', null, _('Reply to this notice'));
+ $this->out->elementStart('dd');
+ $this->out->element('a', array('href' => $reply_url,
+ 'title' => _('Reply to this notice')), _('Reply'));
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
/**
@@ -433,26 +458,17 @@ class NoticeListItem
if ($user && $this->notice->profile_id == $user->id) {
$deleteurl = common_local_url('deletenotice',
array('notice' => $this->notice->id));
- common_element_start('a', array('class' => 'deletenotice',
- 'href' => $deleteurl,
- 'title' => _('delete')));
- common_raw(' &#215;');
- common_element_end('a');
+ $this->out->elementStart('dl', 'notice_delete');
+ $this->out->element('dt', null, _('Delete this notice'));
+ $this->out->elementStart('dd');
+ $this->out->element('a', array('href' => $deleteurl,
+ 'title' => _('Delete this notice')), _('Delete'));
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
}
/**
- * end the time section
- *
- * @return void
- */
-
- function endTimeSection()
- {
- common_element_end('p');
- }
-
- /**
* finish the notice
*
* Close the last elements in the notice list item
@@ -462,6 +478,6 @@ class NoticeListItem
function showEnd()
{
- common_element_end('li');
+ $this->out->elementEnd('li');
}
}
diff --git a/lib/nudgeform.php b/lib/nudgeform.php
new file mode 100644
index 000000000..7d04e11e4
--- /dev/null
+++ b/lib/nudgeform.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for nudging a user
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for nudging a user
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see DisfavorForm
+ */
+
+class NudgeForm extends Form
+{
+ /**
+ * Profile of user to nudge
+ */
+
+ var $profile = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile profile of user to nudge
+ */
+
+ function __construct($out=null, $profile=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'nudge';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('nudge',
+ array('nickname' => $this->profile->nickname));
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Send a nudge'));
+ }
+} \ No newline at end of file
diff --git a/lib/personal.php b/lib/personal.php
index 02b01fece..900df0257 100644
--- a/lib/personal.php
+++ b/lib/personal.php
@@ -1,9 +1,12 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * User profile page
+ *
+ * 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.
@@ -15,199 +18,44 @@
*
* 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); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Base class for user profile page
+ *
+ * @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 PersonalAction extends Action
{
-
- function is_readonly()
- {
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
- common_set_returnto($this->self_url());
- }
-
- function views_menu()
- {
-
- $user = null;
- $action = $this->trimmed('action');
- $nickname = $this->trimmed('nickname');
-
- if ($nickname) {
- $user = User::staticGet('nickname', $nickname);
- $user_profile = $user->getProfile();
- } else {
- $user_profile = false;
- }
- common_element_start('ul', array('id' => 'nav_views'));
+ var $user = null;
- common_menu_item(common_local_url('all', array('nickname' =>
- $nickname)),
- _('Personal'),
- sprintf(_('%s and friends'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
- $action == 'all');
- common_menu_item(common_local_url('replies', array('nickname' =>
- $nickname)),
- _('Replies'),
- sprintf(_('Replies to %s'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
- $action == 'replies');
- common_menu_item(common_local_url('showstream', array('nickname' =>
- $nickname)),
- _('Profile'),
- ($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname,
- $action == 'showstream');
- common_menu_item(common_local_url('showfavorites', array('nickname' =>
- $nickname)),
- _('Favorites'),
- sprintf(_('%s\'s favorite notices'), ($user_profile) ? $user_profile->getBestName() : _('User')),
- $action == 'showfavorites');
-
- $cur = common_current_user();
-
- if ($cur && $cur->id == $user->id) {
-
- common_menu_item(common_local_url('inbox', array('nickname' =>
- $nickname)),
- _('Inbox'),
- _('Your incoming messages'),
- $action == 'inbox');
- common_menu_item(common_local_url('outbox', array('nickname' =>
- $nickname)),
- _('Outbox'),
- _('Your sent messages'),
- $action == 'outbox');
- }
-
- common_element_end('ul');
- }
-
- function show_feeds_list($feeds)
+ function isReadOnly()
{
- common_element_start('div', array('class' => 'feeds'));
- common_element('p', null, 'Feeds:');
- common_element_start('ul', array('class' => 'xoxo'));
-
- foreach ($feeds as $key => $value) {
- $this->common_feed_item($feeds[$key]);
- }
- common_element_end('ul');
- common_element_end('div');
+ return true;
}
- function common_feed_item($feed)
+ function handle($args)
{
- $nickname = $this->trimmed('nickname');
-
- switch($feed['item']) {
- case 'notices': default:
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "$nickname's ".$feed['version']." notice feed";
- $feed['textContent'] = "RSS";
- break;
-
- case 'allrss':
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = $feed['version']." feed for $nickname and friends";
- $feed['textContent'] = "RSS";
- break;
-
- case 'repliesrss':
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = $feed['version']." feed for replies to $nickname";
- $feed['textContent'] = "RSS";
- break;
-
- case 'publicrss':
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "Public timeline ".$feed['version']." feed";
- $feed['textContent'] = "RSS";
- break;
-
- case 'publicatom':
- $feed_classname = "atom";
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "Public timeline ".$feed['version']." feed";
- $feed['textContent'] = "Atom";
- break;
-
- case 'tagrss':
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = $feed['version']." feed for this tag";
- $feed['textContent'] = "RSS";
- break;
-
- case 'favoritedrss':
- $feed_classname = $feed['type'];
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "Favorited ".$feed['version']." feed";
- $feed['textContent'] = "RSS";
- break;
-
- case 'foaf':
- $feed_classname = "foaf";
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "$nickname's FOAF file";
- $feed['textContent'] = "FOAF";
- break;
-
- case 'favoritesrss':
- $feed_classname = "favorites";
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "Feed for favorites of $nickname";
- $feed['textContent'] = "RSS";
- break;
-
- case 'usertimeline':
- $feed_classname = "atom";
- $feed_mimetype = "application/".$feed['type']."+xml";
- $feed_title = "$nickname's ".$feed['version']." notice feed";
- $feed['textContent'] = "Atom";
- break;
- }
- common_element_start('li');
- common_element('a', array('href' => $feed['href'],
- 'class' => $feed_classname,
- 'type' => $feed_mimetype,
- 'title' => $feed_title),
- $feed['textContent']);
- common_element_end('li');
+ parent::handle($args);
+ common_set_returnto($this->selfUrl());
}
-
- function source_link($source)
- {
- $source_name = _($source);
- switch ($source) {
- case 'web':
- case 'xmpp':
- case 'mail':
- case 'omb':
- case 'api':
- common_element('span', 'noticesource', $source_name);
- break;
- default:
- $ns = Notice_source::staticGet($source);
- if ($ns) {
- common_element('a', array('href' => $ns->url),
- $ns->name);
- } else {
- common_element('span', 'noticesource', $source_name);
- }
- break;
- }
- return;
- }
}
diff --git a/lib/personalgroupnav.php b/lib/personalgroupnav.php
new file mode 100644
index 000000000..63e6138df
--- /dev/null
+++ b/lib/personalgroupnav.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Base class for all actions (~views)
+ *
+ * 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 Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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/widget.php';
+
+/**
+ * Base class for all actions
+ *
+ * This is the base class for all actions in the package. An action is
+ * more or less a "view" in an MVC framework.
+ *
+ * Actions are responsible for extracting and validating parameters; using
+ * model classes to read and write to the database; and doing ouput.
+ *
+ * @category Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class PersonalGroupNav extends Widget
+{
+ var $action = null;
+
+ /**
+ * Construction
+ *
+ * @param Action $action current action, used for output
+ */
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ /**
+ * Show the menu
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ $user = null;
+
+ // FIXME: we should probably pass this in
+
+ $action = $this->action->trimmed('action');
+ $nickname = $this->action->trimmed('nickname');
+
+ if ($nickname) {
+ $user = User::staticGet('nickname', $nickname);
+ $user_profile = $user->getProfile();
+ } else {
+ $user_profile = false;
+ }
+
+ $this->out->elementStart('ul', array('class' => 'nav'));
+
+ $this->out->menuItem(common_local_url('all', array('nickname' =>
+ $nickname)),
+ _('Personal'),
+ sprintf(_('%s and friends'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
+ $action == 'all', 'nav_timeline_personal');
+ $this->out->menuItem(common_local_url('replies', array('nickname' =>
+ $nickname)),
+ _('Replies'),
+ sprintf(_('Replies to %s'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
+ $action == 'replies', 'nav_timeline_replies');
+ $this->out->menuItem(common_local_url('showstream', array('nickname' =>
+ $nickname)),
+ _('Profile'),
+ ($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname,
+ $action == 'showstream', 'nav_profile');
+ $this->out->menuItem(common_local_url('showfavorites', array('nickname' =>
+ $nickname)),
+ _('Favorites'),
+ sprintf(_('%s\'s favorite notices'), ($user_profile) ? $user_profile->getBestName() : _('User')),
+ $action == 'showfavorites', 'nav_timeline_favorites');
+
+ $cur = common_current_user();
+
+ if ($cur && $cur->id == $user->id) {
+
+ $this->out->menuItem(common_local_url('inbox', array('nickname' =>
+ $nickname)),
+ _('Inbox'),
+ _('Your incoming messages'),
+ $action == 'inbox');
+ $this->out->menuItem(common_local_url('outbox', array('nickname' =>
+ $nickname)),
+ _('Outbox'),
+ _('Your sent messages'),
+ $action == 'outbox');
+ }
+
+ $this->out->elementEnd('ul');
+ }
+}
diff --git a/lib/profilelist.php b/lib/profilelist.php
index bda05daf3..f7ed5d19c 100644
--- a/lib/profilelist.php
+++ b/lib/profilelist.php
@@ -1,10 +1,13 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * Widget to show a list of profiles
+ *
+ * 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.
@@ -16,30 +19,56 @@
*
* 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 Public
+ * @package Laconica
+ * @author Evan Prodromou <evan@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); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/widget.php';
define('PROFILES_PER_PAGE', 20);
-class ProfileList
-{
+/**
+ * Widget to show a list of profiles
+ *
+ * @category Public
+ * @package Laconica
+ * @author Zach Copley <zach@controlyourself.ca>
+ * @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 ProfileList extends Widget
+{
+ /** Current profile, profile query. */
var $profile = null;
+ /** Owner of this list */
var $owner = null;
+ /** Action object using us. */
var $action = null;
function __construct($profile, $owner=null, $action=null)
{
+ parent::__construct($action);
+
$this->profile = $profile;
$this->owner = $owner;
$this->action = $action;
}
- function show_list()
+ function show()
{
- common_element_start('ul', array('id' => 'profiles', 'class' => 'profile_list'));
+ $this->out->elementStart('ul', 'profiles');
$cnt = 0;
@@ -48,71 +77,77 @@ class ProfileList
if($cnt > PROFILES_PER_PAGE) {
break;
}
- $this->show();
+ $this->showProfile();
}
- common_element_end('ul');
+ $this->out->elementEnd('ul');
return $cnt;
}
- function show()
+ function showProfile()
{
-
- common_element_start('li', array('class' => 'profile_single',
- 'id' => 'profile-' . $this->profile->id));
+ $this->out->elementStart('li', array('class' => 'profile',
+ 'id' => 'profile-' . $this->profile->id));
$user = common_current_user();
- if ($user && $user->id != $this->profile->id) {
- # XXX: special-case for user looking at own
- # subscriptions page
- if ($user->isSubscribed($this->profile)) {
- common_unsubscribe_form($this->profile);
- } else {
- common_subscribe_form($this->profile);
- }
- }
+
+ $this->out->elementStart('div', array('id' => 'user_profile',
+ 'class' => 'vcard'));
$avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE);
- common_element_start('a', array('href' => $this->profile->profileurl));
- common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE),
- 'class' => 'avatar stream',
+ $this->out->elementStart('a', array('href' => $this->profile->profileurl,
+ 'class' => 'url'));
+ $this->out->element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE),
+ 'class' => 'photo avatar',
'width' => AVATAR_STREAM_SIZE,
'height' => AVATAR_STREAM_SIZE,
'alt' =>
($this->profile->fullname) ? $this->profile->fullname :
$this->profile->nickname));
- common_element_end('a');
- common_element_start('p');
- common_element_start('a', array('href' => $this->profile->profileurl,
- 'class' => 'nickname'));
- common_raw($this->highlight($this->profile->nickname));
- common_element_end('a');
+ $hasFN = ($this->profile->fullname) ? 'nickname' : 'fn nickname';
+ $this->out->elementStart('span', $hasFN);
+ $this->out->raw($this->highlight($this->profile->nickname));
+ $this->out->elementEnd('span');
+ $this->out->elementEnd('a');
+
if ($this->profile->fullname) {
- common_text(' | ');
- common_element_start('span', 'fullname');
- common_raw($this->highlight($this->profile->fullname));
- common_element_end('span');
+ $this->out->elementStart('dl', 'user_fn');
+ $this->out->element('dt', null, 'Full name');
+ $this->out->elementStart('dd');
+ $this->out->elementStart('span', 'fn');
+ $this->out->raw($this->highlight($this->profile->fullname));
+ $this->out->elementEnd('span');
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
if ($this->profile->location) {
- common_text(' | ');
- common_element_start('span', 'location');
- common_raw($this->highlight($this->profile->location));
- common_element_end('span');
+ $this->out->elementStart('dl', 'user_location');
+ $this->out->element('dt', null, _('Location'));
+ $this->out->elementStart('dd', 'location');
+ $this->out->raw($this->highlight($this->profile->location));
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
- common_element_end('p');
if ($this->profile->homepage) {
- common_element_start('p', 'website');
- common_element_start('a', array('href' => $this->profile->homepage));
- common_raw($this->highlight($this->profile->homepage));
- common_element_end('a');
- common_element_end('p');
+ $this->out->elementStart('dl', 'user_url');
+ $this->out->element('dt', null, _('URL'));
+ $this->out->elementStart('dd');
+ $this->out->elementStart('a', array('href' => $this->profile->homepage,
+ 'class' => 'url'));
+ $this->out->raw($this->highlight($this->profile->homepage));
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
if ($this->profile->bio) {
- common_element_start('p', 'bio');
- common_raw($this->highlight($this->profile->bio));
- common_element_end('p');
+ $this->out->elementStart('dl', 'user_note');
+ $this->out->element('dt', null, _('Note'));
+ $this->out->elementStart('dd', 'note');
+ $this->out->raw($this->highlight($this->profile->bio));
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
# If we're on a list with an owner (subscriptions or subscribers)...
@@ -121,49 +156,61 @@ class ProfileList
# Get tags
$tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
- common_element_start('div', 'tags_user');
- common_element_start('dl');
- common_element_start('dt');
+ $this->out->elementStart('dl', 'user_tags');
+ $this->out->elementStart('dt');
if ($user->id == $this->owner->id) {
- common_element('a', array('href' => common_local_url('tagother',
+ $this->out->element('a', array('href' => common_local_url('tagother',
array('id' => $this->profile->id))),
_('Tags'));
} else {
- common_text(_('Tags'));
+ $this->out->text(_('Tags'));
}
- common_text(":");
- common_element_end('dt');
- common_element_start('dd');
+ $this->out->elementEnd('dt');
+ $this->out->elementStart('dd');
if ($tags) {
- common_element_start('ul', 'tags xoxo');
+ $this->out->elementStart('ul', 'tags xoxo');
foreach ($tags as $tag) {
- common_element_start('li');
- common_element('a', array('rel' => 'tag',
+ $this->out->elementStart('li');
+ $this->element('span', 'mark_hash', '#');
+ $this->out->element('a', array('rel' => 'tag',
'href' => common_local_url($this->action,
array('nickname' => $this->owner->nickname,
'tag' => $tag))),
$tag);
- common_element_end('li');
+ $this->out->elementEnd('li');
}
- common_element_end('ul');
+ $this->out->elementEnd('ul');
} else {
- common_text(_('(none)'));
+ $this->out->text(_('(none)'));
}
- common_element_end('dd');
- common_element_end('dl');
- common_element_end('div');
+ $this->out->elementEnd('dd');
+ $this->out->elementEnd('dl');
}
if ($user && $user->id == $this->owner->id) {
- $this->show_owner_controls($this->profile);
+ $this->showOwnerControls($this->profile);
+ }
+
+ $this->out->elementEnd('div');
+
+ if ($user && $user->id != $this->profile->id) {
+ # XXX: special-case for user looking at own
+ # subscriptions page
+ if ($user->isSubscribed($this->profile)) {
+ $usf = new UnsubscribeForm($this->out, $this->profile);
+ $usf->show();
+ } else {
+ $sf = new SubscribeForm($this->out, $this->profile);
+ $sf->show();
+ }
}
- common_element_end('li');
+ $this->out->elementEnd('li');
}
/* Override this in subclasses. */
- function show_owner_controls($profile)
+ function showOwnerControls($profile)
{
return;
}
@@ -172,4 +219,4 @@ class ProfileList
{
return htmlspecialchars($text);
}
-} \ No newline at end of file
+}
diff --git a/lib/publicgroupnav.php b/lib/publicgroupnav.php
new file mode 100644
index 000000000..8dd97a3b7
--- /dev/null
+++ b/lib/publicgroupnav.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Menu for public group of 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 Menu
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 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/widget.php';
+
+/**
+ * Menu for public group of actions
+ *
+ * @category Output
+ * @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/
+ *
+ * @see Widget
+ */
+
+class PublicGroupNav extends Widget
+{
+ var $action = null;
+
+ /**
+ * Construction
+ *
+ * @param Action $action current action, used for output
+ */
+
+ function __construct($action=null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ }
+
+ /**
+ * Show the menu
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ $action_name = $this->action->trimmed('action');
+
+ $this->action->elementStart('ul', array('class' => 'nav'));
+
+ $this->out->menuItem(common_local_url('public'), _('Public'),
+ _('Public timeline'), $action_name == 'public', 'nav_timeline_public');
+
+ $this->out->menuItem(common_local_url('publictagcloud'), _('Recent tags'),
+ _('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags');
+
+ if (count(common_config('nickname', 'featured')) > 0) {
+ $this->out->menuItem(common_local_url('featured'), _('Featured'),
+ _('Featured users'), $action_name == 'featured', 'nav_featured');
+ }
+
+ $this->out->menuItem(common_local_url('favorited'), _('Popular'),
+ _("Popular notices"), $action_name == 'favorited', 'nav_timeline_favorited');
+
+ $this->action->elementEnd('ul');
+ }
+}
diff --git a/lib/rssaction.php b/lib/rssaction.php
index 9564cfb46..2c532912b 100644
--- a/lib/rssaction.php
+++ b/lib/rssaction.php
@@ -1,9 +1,12 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * Base class for RSS 1.0 feed 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.
@@ -15,6 +18,14 @@
*
* 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 Mail
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Earle Martin <earle@downlode.org>
+ * @copyright 2008-9 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); }
@@ -23,35 +34,84 @@ define('DEFAULT_RSS_LIMIT', 48);
class Rss10Action extends Action
{
-
# This will contain the details of each feed item's author and be used to generate SIOC data.
+
var $creators = array();
+ var $limit = DEFAULT_RSS_LIMIT;
+
+ /**
+ * Constructor
+ *
+ * Just wraps the Action constructor.
+ *
+ * @param string $output URI to output to, default = stdout
+ * @param boolean $indent Whether to indent output, default true
+ *
+ * @see Action::__construct
+ */
- function is_readonly()
+ function __construct($output='php://output', $indent=true)
+ {
+ parent::__construct($output, $indent);
+ }
+
+ /**
+ * Do we need to write to the database?
+ *
+ * @return boolean true
+ */
+
+ function isReadonly()
{
return true;
}
+ /**
+ * Read arguments and initialize members
+ *
+ * @param array $args Arguments from $_REQUEST
+ * @return boolean success
+ */
+
+ function prepare($args)
+ {
+ $this->limit = (int) $this->trimmed('limit');
+ if ($this->limit == 0) {
+ $this->limit = DEFAULT_RSS_LIMIT;
+ }
+ return true;
+ }
+
+ /**
+ * Handle a request
+ *
+ * @param array $args Arguments from $_REQUEST
+ *
+ * @return void
+ */
+
function handle($args)
{
parent::handle($args);
- $limit = (int) $this->trimmed('limit');
- if ($limit == 0) {
- $limit = DEFAULT_RSS_LIMIT;
- }
$this->show_rss($limit);
}
- function init()
- {
- return true;
- }
-
- function get_notices()
+ /**
+ * Get the notices to output in this stream
+ *
+ * @return array an array of Notice objects sorted in reverse chron
+ */
+
+ function getNotices()
{
return array();
}
+ /**
+ * Get a description of the channel
+ *
+ * Returns an array with the following
+ * @return array
function get_channel()
{
return array('url' => '',
@@ -67,11 +127,6 @@ class Rss10Action extends Action
function show_rss($limit=0)
{
-
- if (!$this->init()) {
- return;
- }
-
$notices = $this->get_notices($limit);
$this->init_rss();
diff --git a/lib/settingsaction.php b/lib/settingsaction.php
index 03bac3a93..dfe1f114b 100644
--- a/lib/settingsaction.php
+++ b/lib/settingsaction.php
@@ -1,9 +1,12 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * Base class for settings 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.
@@ -15,125 +18,133 @@
*
* 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 Settings
+ * @package Laconica
+ * @author Evan Prodromou <evan@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); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Base class for settings group of actions
+ *
+ * @category Settings
+ * @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/
+ *
+ * @see Widget
+ */
class SettingsAction extends Action
{
+ /**
+ * A message for the user.
+ */
+
+ var $msg = null;
+
+ /**
+ * Whether the message is a good one or a bad one.
+ */
+
+ var $success = false;
+
+ /**
+ * Handle input and output a page
+ *
+ * @param array $args $_REQUEST arguments
+ *
+ * @return void
+ */
function handle($args)
{
parent::handle($args);
if (!common_logged_in()) {
- common_user_error(_('Not logged in.'));
+ $this->clientError(_('Not logged in.'));
return;
} else if (!common_is_real_login()) {
- # Cookie theft means that automatic logins can't
- # change important settings or see private info, and
- # _all_ our settings are important
- common_set_returnto($this->self_url());
+ // Cookie theft means that automatic logins can't
+ // change important settings or see private info, and
+ // _all_ our settings are important
+ common_set_returnto($this->selfUrl());
common_redirect(common_local_url('login'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $this->handle_post();
+ $this->handlePost();
} else {
- $this->show_form();
+ $this->showForm();
}
}
- # override!
- function handle_post()
- {
- return false;
- }
+ /**
+ * Handle a POST request
+ *
+ * @return boolean success flag
+ */
- function show_form($msg=null, $success=false)
+ function handlePost()
{
return false;
}
- function message($msg, $success)
- {
- if ($msg) {
- common_element('div', ($success) ? 'success' : 'error',
- $msg);
- }
- }
+ /**
+ * show the settings form
+ *
+ * @param string $msg an extra message for the user
+ * @param string $success good message or bad message?
+ *
+ * @return void
+ */
- function form_header($title, $msg=NULL, $success=false)
+ function showForm($msg=null, $success=false)
{
- common_show_header($title,
- array($this, 'show_header'),
- array($msg, $success),
- array($this, 'show_top'));
- }
+ $this->msg = $msg;
+ $this->success = $success;
- function show_header()
- {
- common_element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => common_path('js/jcrop/jquery.Jcrop.css?version='.LACONICA_VERSION),
- 'media' => 'screen, projection, tv'));
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jcrop/jquery.Jcrop.pack.js')));
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jcrop/jquery.Jcrop.go.js')));
+ $this->showPage();
}
- function show_top($arr)
+ /**
+ * show human-readable instructions for the page
+ *
+ * @return void
+ */
+
+ function showPageNotice()
{
- $msg = $arr[0];
- $success = $arr[1];
- if ($msg) {
- $this->message($msg, $success);
+ if ($this->msg) {
+ $this->element('div', ($this->success) ? 'success' : 'error',
+ $this->msg);
} else {
- $inst = $this->get_instructions();
+ $inst = $this->getInstructions();
$output = common_markup_to_html($inst);
- common_element_start('div', 'instructions');
- common_raw($output);
- common_element_end('div');
+
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
}
- $this->settings_menu();
}
- function settings_menu()
+ /**
+ * instructions recipe for sub-classes
+ *
+ * Subclasses should override this to return readable instructions. They'll
+ * be processed by common_markup_to_html().
+ *
+ * @return string instructions text
+ */
+
+ function getInstructions()
{
- # action => array('prompt', 'title')
- $menu =
- array('profilesettings' =>
- array(_('Profile'),
- _('Change your profile settings')),
- 'emailsettings' =>
- array(_('Email'),
- _('Change email handling')),
- 'openidsettings' =>
- array(_('OpenID'),
- _('Add or remove OpenIDs')),
- 'smssettings' =>
- array(_('SMS'),
- _('Updates by SMS')),
- 'imsettings' =>
- array(_('IM'),
- _('Updates by instant messenger (IM)')),
- 'twittersettings' =>
- array(_('Twitter'),
- _('Twitter integration options')),
- 'othersettings' =>
- array(_('Other'),
- _('Other options')));
-
- $action = $this->trimmed('action');
- common_element_start('ul', array('id' => 'nav_views'));
- foreach ($menu as $menuaction => $menudesc) {
- if ($menuaction == 'imsettings' &&
- !common_config('xmpp', 'enabled')) {
- continue;
- }
- common_menu_item(common_local_url($menuaction),
- $menudesc[0],
- $menudesc[1],
- $action == $menuaction);
- }
- common_element_end('ul');
+ return '';
}
+
}
diff --git a/lib/stream.php b/lib/stream.php
index 73758adee..0cb9e0bf4 100644
--- a/lib/stream.php
+++ b/lib/stream.php
@@ -24,32 +24,6 @@ require_once(INSTALLDIR.'/lib/noticelist.php');
class StreamAction extends PersonalAction
{
-
- function public_views_menu()
- {
-
- $action = $this->trimmed('action');
-
- common_element_start('ul', array('id' => 'nav_views'));
-
- common_menu_item(common_local_url('public'), _('Public'),
- _('Public timeline'), $action == 'public');
-
- common_menu_item(common_local_url('tag'), _('Recent tags'),
- _('Recent tags'), $action == 'tag');
-
- if (count(common_config('nickname', 'featured')) > 0) {
- common_menu_item(common_local_url('featured'), _('Featured'),
- _('Featured users'), $action == 'featured');
- }
-
- common_menu_item(common_local_url('favorited'), _('Popular'),
- _("Popular notices"), $action == 'favorited');
-
- common_element_end('ul');
-
- }
-
function show_notice_list($notice)
{
$nl = new NoticeList($notice);
diff --git a/lib/subscribeform.php b/lib/subscribeform.php
new file mode 100644
index 000000000..231e740a7
--- /dev/null
+++ b/lib/subscribeform.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for subscribing to a user
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for subscribing to a user
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see UnsubscribeForm
+ */
+
+class SubscribeForm extends Form
+{
+ /**
+ * Profile of user to subscribe to
+ */
+
+ var $profile = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile profile of user to subscribe to
+ */
+
+ function __construct($out=null, $profile=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'subscribe-' . $this->profile->id;
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_user_subscribe';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('subscribe');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('subscribeto-' . $this->profile->id,
+ $this->profile->id,
+ 'subscribeto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Subscribe'));
+ }
+}
diff --git a/lib/theme.php b/lib/theme.php
index 6f365bd99..95030affe 100644
--- a/lib/theme.php
+++ b/lib/theme.php
@@ -1,9 +1,12 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
*
- * This program is free software: you can redistribute it and/or modify
+ * Utilities for theme files and paths
+ *
+ * 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.
@@ -15,19 +18,51 @@
*
* 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 Paths
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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); }
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Gets the full path of a file in a theme dir based on its relative name
+ *
+ * @param string $relative relative path within the theme directory
+ * @param string $theme name of the theme; defaults to current theme
+ *
+ * @return string File path to the theme file
+ */
-function theme_file($relative)
+function theme_file($relative, $theme=null)
{
- $theme = common_config('site', 'theme');
+ if (!$theme) {
+ $theme = common_config('site', 'theme');
+ }
return INSTALLDIR.'/theme/'.$theme.'/'.$relative;
}
-function theme_path($relative)
+/**
+ * Gets the full URL of a file in a theme dir based on its relative name
+ *
+ * @param string $relative relative path within the theme directory
+ * @param string $theme name of the theme; defaults to current theme
+ *
+ * @return string URL of the file
+ */
+
+function theme_path($relative, $theme=null)
{
- $theme = common_config('site', 'theme');
+ if (!$theme) {
+ $theme = common_config('site', 'theme');
+ }
$server = common_config('theme', 'server');
if ($server) {
return 'http://'.$server.'/'.$theme.'/'.$relative;
diff --git a/lib/unblockform.php b/lib/unblockform.php
new file mode 100644
index 000000000..025011a82
--- /dev/null
+++ b/lib/unblockform.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for unblocking a user
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for unblocking a user
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see BlockForm
+ */
+
+class UnblockForm extends Form
+{
+ /**
+ * Profile of user to unblock
+ */
+
+ var $profile = null;
+
+ /**
+ * Return-to args
+ */
+
+ var $args = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile profile of user to unblock
+ * @param array $args return-to args
+ */
+
+ function __construct($out=null, $profile=null, $args=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ $this->args = $args;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'unblock-' . $this->profile->id;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+
+ function formClass()
+ {
+ return 'form_user_unblock';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('unblock');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('unblockto-' . $this->profile->id,
+ $this->profile->id,
+ 'unblockto');
+ if ($this->args) {
+ foreach ($this->args as $k => $v) {
+ $this->out->hidden('returnto-' . $k, $v);
+ }
+ }
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Unblock'));
+ }
+}
diff --git a/lib/unsubscribeform.php b/lib/unsubscribeform.php
new file mode 100644
index 000000000..092369db7
--- /dev/null
+++ b/lib/unsubscribeform.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Form for unsubscribing from a user
+ *
+ * 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 Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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/form.php';
+
+/**
+ * Form for unsubscribing from a user
+ *
+ * @category Form
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see SubscribeForm
+ */
+
+class UnsubscribeForm extends Form
+{
+ /**
+ * Profile of user to unsubscribe from
+ */
+
+ var $profile = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile profile of user to unsub from
+ */
+
+ function __construct($out=null, $profile=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'unsubscribe-' . $this->profile->id;
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_user_unsubscribe';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('unsubscribe');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('unsubscribeto-' . $this->profile->id,
+ $this->profile->id,
+ 'unsubscribeto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Unsubscribe'));
+ }
+}
diff --git a/lib/util.php b/lib/util.php
index fbe04c6c4..73c4cdcc8 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* XXX: break up into separate modules (HTTP, HTML, user, files) */
+/* XXX: break up into separate modules (HTTP, user, files) */
// Show a server error
@@ -79,65 +79,6 @@ function common_user_error($msg, $code=400)
common_show_footer();
}
-$xw = null;
-
-// Start an HTML element
-function common_element_start($tag, $attrs=null)
-{
- global $xw;
- $xw->startElement($tag);
- if (is_array($attrs)) {
- foreach ($attrs as $name => $value) {
- $xw->writeAttribute($name, $value);
- }
- } else if (is_string($attrs)) {
- $xw->writeAttribute('class', $attrs);
- }
-}
-
-function common_element_end($tag)
-{
- static $empty_tag = array('base', 'meta', 'link', 'hr',
- 'br', 'param', 'img', 'area',
- 'input', 'col');
- global $xw;
- // XXX: check namespace
- if (in_array($tag, $empty_tag)) {
- $xw->endElement();
- } else {
- $xw->fullEndElement();
- }
-}
-
-function common_element($tag, $attrs=null, $content=null)
-{
- common_element_start($tag, $attrs);
- global $xw;
- if (!is_null($content)) {
- $xw->text($content);
- }
- common_element_end($tag);
-}
-
-function common_start_xml($doc=null, $public=null, $system=null, $indent=true)
-{
- global $xw;
- $xw = new XMLWriter();
- $xw->openURI('php://output');
- $xw->setIndent($indent);
- $xw->startDocument('1.0', 'UTF-8');
- if ($doc) {
- $xw->writeDTD($doc, $public, $system);
- }
-}
-
-function common_end_xml()
-{
- global $xw;
- $xw->endDocument();
- $xw->flush();
-}
-
function common_init_locale($language=null)
{
if(!$language) {
@@ -167,346 +108,6 @@ function common_init_language()
}
}
-define('PAGE_TYPE_PREFS', 'text/html,application/xhtml+xml,application/xml;q=0.3,text/xml;q=0.2');
-
-function common_show_header($pagetitle, $callable=null, $data=null, $headercall=null)
-{
-
- global $config, $xw;
- global $action; /* XXX: kind of cheating here. */
-
- common_start_html();
-
- common_element_start('head');
- common_element('title', null,
- $pagetitle . " - " . $config['site']['name']);
- common_element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('display.css') . '?version=' . LACONICA_VERSION,
- 'media' => 'screen, projection, tv'));
- foreach (array(6,7) as $ver) {
- if (file_exists(theme_file('ie'.$ver.'.css'))) {
- // Yes, IE people should be put in jail.
- $xw->writeComment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
- 'href="'.theme_path('ie'.$ver.'.css').'?version='.LACONICA_VERSION.'" /><![endif]');
- }
- }
-
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jquery.min.js')),
- ' ');
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jquery.form.js')),
- ' ');
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/xbImportNode.js')),
- ' ');
- common_element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
- ' ');
- common_element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
- 'href' => common_local_url('opensearch', array('type' => 'people')),
- 'title' => common_config('site', 'name').' People Search'));
-
- common_element('link', array('rel' => 'search', 'type' => 'application/opensearchdescription+xml',
- 'href' => common_local_url('opensearch', array('type' => 'notice')),
- 'title' => common_config('site', 'name').' Notice Search'));
-
- if ($callable) {
- if ($data) {
- call_user_func($callable, $data);
- } else {
- call_user_func($callable);
- }
- }
- common_element_end('head');
- common_element_start('body', $action);
- common_element_start('div', array('id' => 'wrap'));
- common_element_start('div', array('id' => 'header'));
- common_nav_menu();
- if ((isset($config['site']['logo']) && is_string($config['site']['logo']) && (strlen($config['site']['logo']) > 0))
- || file_exists(theme_file('logo.png')))
- {
- common_element_start('a', array('href' => common_local_url('public')));
- common_element('img', array('src' => isset($config['site']['logo']) ?
- ($config['site']['logo']) : theme_path('logo.png'),
- 'alt' => $config['site']['name'],
- 'id' => 'logo'));
- common_element_end('a');
- } else {
- common_element_start('p', array('id' => 'branding'));
- common_element('a', array('href' => common_local_url('public')),
- $config['site']['name']);
- common_element_end('p');
- }
-
- common_element('h1', 'pagetitle', $pagetitle);
-
- if ($headercall) {
- if ($data) {
- call_user_func($headercall, $data);
- } else {
- call_user_func($headercall);
- }
- }
- common_element_end('div');
- common_element_start('div', array('id' => 'content'));
-}
-
-function common_start_html($type=null, $indent=true)
-{
-
- if (!$type) {
- $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null;
-
- // XXX: allow content negotiation for RDF, RSS, or XRDS
-
- $type = common_negotiate_type(common_accept_to_prefs($httpaccept),
- common_accept_to_prefs(PAGE_TYPE_PREFS));
-
- if (!$type) {
- common_user_error(_('This page is not available in a media type you accept'), 406);
- exit(0);
- }
- }
-
- header('Content-Type: '.$type);
-
- common_start_xml('html',
- '-//W3C//DTD XHTML 1.0 Strict//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd', $indent);
-
- // FIXME: correct language for interface
-
- $language = common_language();
-
- common_element_start('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
- 'xml:lang' => $language,
- 'lang' => $language));
-}
-
-function common_show_footer()
-{
- global $xw, $config;
- common_element_end('div'); // content div
- common_foot_menu();
- common_element_start('div', array('id' => 'footer'));
- common_element_start('div', 'laconica');
- if (common_config('site', 'broughtby')) {
- $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
- } else {
- $instr = _('**%%site.name%%** is a microblogging service. ');
- }
- $instr .= sprintf(_('It runs the [Laconica](http://laconi.ca/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), LACONICA_VERSION);
- $output = common_markup_to_html($instr);
- common_raw($output);
- common_element_end('div');
- common_element('img', array('id' => 'cc',
- 'src' => $config['license']['image'],
- 'alt' => $config['license']['title']));
- common_element_start('p');
- common_text(_('Unless otherwise specified, contents of this site are copyright by the contributors and available under the '));
- common_element('a', array('class' => 'license',
- 'rel' => 'license',
- 'href' => $config['license']['url']),
- $config['license']['title']);
- common_text(_('. Contributors should be attributed by full name or nickname.'));
- common_element_end('p');
- common_element_end('div');
- common_element_end('div');
- common_element_end('body');
- common_element_end('html');
- common_end_xml();
-}
-
-function common_text($txt)
-{
- global $xw;
- $xw->text($txt);
-}
-
-function common_raw($xml)
-{
- global $xw;
- $xw->writeRaw($xml);
-}
-
-function common_nav_menu()
-{
- $user = common_current_user();
- common_element_start('ul', array('id' => 'nav'));
- if ($user) {
- common_menu_item(common_local_url('all', array('nickname' => $user->nickname)),
- _('Home'));
- }
- common_menu_item(common_local_url('peoplesearch'), _('Search'));
- if ($user) {
- common_menu_item(common_local_url('profilesettings'),
- _('Settings'));
- common_menu_item(common_local_url('invite'),
- _('Invite'));
- common_menu_item(common_local_url('logout'),
- _('Logout'));
- } else {
- common_menu_item(common_local_url('login'), _('Login'));
- if (!common_config('site', 'closed')) {
- common_menu_item(common_local_url('register'), _('Register'));
- }
- common_menu_item(common_local_url('openidlogin'), _('OpenID'));
- }
- common_menu_item(common_local_url('doc', array('title' => 'help')),
- _('Help'));
- common_element_end('ul');
-}
-
-function common_foot_menu()
-{
- common_element_start('ul', array('id' => 'nav_sub'));
- common_menu_item(common_local_url('doc', array('title' => 'help')),
- _('Help'));
- common_menu_item(common_local_url('doc', array('title' => 'about')),
- _('About'));
- common_menu_item(common_local_url('doc', array('title' => 'faq')),
- _('FAQ'));
- common_menu_item(common_local_url('doc', array('title' => 'privacy')),
- _('Privacy'));
- common_menu_item(common_local_url('doc', array('title' => 'source')),
- _('Source'));
- common_menu_item(common_local_url('doc', array('title' => 'contact')),
- _('Contact'));
- common_element_end('ul');
-}
-
-function common_menu_item($url, $text, $title=null, $is_selected=false)
-{
- $lattrs = array();
- if ($is_selected) {
- $lattrs['class'] = 'current';
- }
- common_element_start('li', $lattrs);
- $attrs['href'] = $url;
- if ($title) {
- $attrs['title'] = $title;
- }
- common_element('a', $attrs, $text);
- common_element_end('li');
-}
-
-function common_input($id, $label, $value=null,$instructions=null)
-{
- common_element_start('p');
- common_element('label', array('for' => $id), $label);
- $attrs = array('name' => $id,
- 'type' => 'text',
- 'class' => 'input_text',
- 'id' => $id);
- if ($value) {
- $attrs['value'] = htmlspecialchars($value);
- }
- common_element('input', $attrs);
- if ($instructions) {
- common_element('span', 'input_instructions', $instructions);
- }
- common_element_end('p');
-}
-
-function common_checkbox($id, $label, $checked=false, $instructions=null, $value='true', $disabled=false)
-{
- common_element_start('p');
- $attrs = array('name' => $id,
- 'type' => 'checkbox',
- 'class' => 'checkbox',
- 'id' => $id);
- if ($value) {
- $attrs['value'] = htmlspecialchars($value);
- }
- if ($checked) {
- $attrs['checked'] = 'checked';
- }
- if ($disabled) {
- $attrs['disabled'] = 'true';
- }
- common_element('input', $attrs);
- common_text(' ');
- common_element('label', array('class' => 'checkbox_label', 'for' => $id), $label);
- common_text(' ');
- if ($instructions) {
- common_element('span', 'input_instructions', $instructions);
- }
- common_element_end('p');
-}
-
-function common_dropdown($id, $label, $content, $instructions=null, $blank_select=false, $selected=null)
-{
- common_element_start('p');
- common_element('label', array('for' => $id), $label);
- common_element_start('select', array('id' => $id, 'name' => $id));
- if ($blank_select) {
- common_element('option', array('value' => ''));
- }
- foreach ($content as $value => $option) {
- if ($value == $selected) {
- common_element('option', array('value' => $value, 'selected' => $value), $option);
- } else {
- common_element('option', array('value' => $value), $option);
- }
- }
- common_element_end('select');
- if ($instructions) {
- common_element('span', 'input_instructions', $instructions);
- }
- common_element_end('p');
-}
-function common_hidden($id, $value)
-{
- common_element('input', array('name' => $id,
- 'type' => 'hidden',
- 'id' => $id,
- 'value' => $value));
-}
-
-function common_password($id, $label, $instructions=null)
-{
- common_element_start('p');
- common_element('label', array('for' => $id), $label);
- $attrs = array('name' => $id,
- 'type' => 'password',
- 'class' => 'password',
- 'id' => $id);
- common_element('input', $attrs);
- if ($instructions) {
- common_element('span', 'input_instructions', $instructions);
- }
- common_element_end('p');
-}
-
-function common_submit($id, $label, $cls='submit')
-{
- global $xw;
- common_element_start('p');
- common_element('input', array('type' => 'submit',
- 'id' => $id,
- 'name' => $id,
- 'class' => $cls,
- 'value' => $label));
- common_element_end('p');
-}
-
-function common_textarea($id, $label, $content=null, $instructions=null)
-{
- common_element_start('p');
- common_element('label', array('for' => $id), $label);
- common_element('textarea', array('rows' => 3,
- 'cols' => 40,
- 'name' => $id,
- 'id' => $id),
- ($content) ? $content : '');
- if ($instructions) {
- common_element('span', 'input_instructions', $instructions);
- }
- common_element_end('p');
-}
-
function common_timezone()
{
if (common_logged_in()) {
@@ -970,7 +571,7 @@ function common_tag_link($tag)
{
$canonical = common_canonical_tag($tag);
$url = common_local_url('tag', array('tag' => $canonical));
- return '<a href="' . htmlspecialchars($url) . '" rel="tag" class="hashlink">' . htmlspecialchars($tag) . '</a>';
+ return '<span class="tag"><a href="' . htmlspecialchars($url) . '" rel="tag">' . htmlspecialchars($tag) . '</a></span>';
}
function common_canonical_tag($tag)
@@ -988,7 +589,7 @@ function common_at_link($sender_id, $nickname)
$sender = Profile::staticGet($sender_id);
$recipient = common_relative_profile($sender, common_canonical_nickname($nickname));
if ($recipient) {
- return '<a href="'.htmlspecialchars($recipient->profileurl).'" class="atlink">'.$nickname.'</a>';
+ return '<span class="vcard"><a href="'.htmlspecialchars($recipient->profileurl).'" class="url"><span class="fn nickname">'.$nickname.'</span></a></span>';
} else {
return $nickname;
}
@@ -1005,7 +606,7 @@ function common_at_hash_link($sender_id, $tag)
$url = common_local_url('subscriptions',
array('nickname' => $user->nickname,
'tag' => $tag));
- return '<a href="'.htmlspecialchars($url).'" class="atlink">'.$tag.'</a>';
+ return '<span class="tag"><a href="'.htmlspecialchars($url).'" rel="tag">'.$tag.'</a></span>';
} else {
return $tag;
}
@@ -1169,6 +770,8 @@ function common_fancy_url($action, $args=null)
return common_path('main/openid');
case 'profilesettings':
return common_path('settings/profile');
+ case 'passwordsettings':
+ return common_path('settings/password');
case 'emailsettings':
return common_path('settings/email');
case 'openidsettings':
@@ -1251,6 +854,8 @@ function common_fancy_url($action, $args=null)
return common_path($path);
case 'imsettings':
return common_path('settings/im');
+ case 'avatarsettings':
+ return common_path('settings/avatar');
case 'peoplesearch':
return common_path('search/people' . (($args) ? ('?' . http_build_query($args)) : ''));
case 'noticesearch':
@@ -1260,13 +865,11 @@ function common_fancy_url($action, $args=null)
case 'avatarbynickname':
return common_path($args['nickname'].'/avatar/'.$args['size']);
case 'tag':
- if (isset($args['tag']) && $args['tag']) {
- $path = 'tag/' . $args['tag'];
- unset($args['tag']);
- } else {
- $path = 'tags';
- }
+ $path = 'tag/' . $args['tag'];
+ unset($args['tag']);
return common_path($path . (($args) ? ('?' . http_build_query($args)) : ''));
+ case 'publictagcloud':
+ return common_path('tags');
case 'peopletag':
$path = 'peopletag/' . $args['tag'];
unset($args['tag']);
@@ -1694,39 +1297,6 @@ function common_profile_url($nickname)
return common_local_url('showstream', array('nickname' => $nickname));
}
-// Don't call if nobody's logged in
-
-function common_notice_form($action=null, $content=null)
-{
- $user = common_current_user();
- assert(!is_null($user));
- common_element_start('form', array('id' => 'status_form',
- 'method' => 'post',
- 'action' => common_local_url('newnotice')));
- common_element_start('p');
- common_element('label', array('for' => 'status_textarea',
- 'id' => 'status_label'),
- sprintf(_('What\'s up, %s?'), $user->nickname));
- common_element('span', array('id' => 'counter', 'class' => 'counter'), '140');
- common_element('textarea', array('id' => 'status_textarea',
- 'cols' => 60,
- 'rows' => 3,
- 'name' => 'status_textarea'),
- ($content) ? $content : '');
- common_hidden('token', common_session_token());
- if ($action) {
- common_hidden('returnto', $action);
- }
- // set by JavaScript
- common_hidden('inreplyto', 'false');
- common_element('input', array('id' => 'status_submit',
- 'name' => 'status_submit',
- 'type' => 'submit',
- 'value' => _('Send')));
- common_element_end('p');
- common_element_end('form');
-}
-
// Should make up a reasonable root URL
function common_root_url()
@@ -1858,41 +1428,6 @@ function common_valid_tag($tag)
return false;
}
-// Does a little before-after block for next/prev page
-
-function common_pagination($have_before, $have_after, $page, $action, $args=null)
-{
-
- if ($have_before || $have_after) {
- common_element_start('div', array('id' => 'pagination'));
- common_element_start('ul', array('id' => 'nav_pagination'));
- }
-
- if ($have_before) {
- $pargs = array('page' => $page-1);
- $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
-
- common_element_start('li', 'before');
- common_element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'prev'),
- _('« After'));
- common_element_end('li');
- }
-
- if ($have_after) {
- $pargs = array('page' => $page+1);
- $newargs = ($args) ? array_merge($args,$pargs) : $pargs;
- common_element_start('li', 'after');
- common_element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'next'),
- _('Before »'));
- common_element_end('li');
- }
-
- if ($have_before || $have_after) {
- common_element_end('ul');
- common_element_end('div');
- }
-}
-
/* Following functions are copied from MediaWiki GlobalFunctions.php
* and written by Evan Prodromou. */
@@ -2105,111 +1640,11 @@ function common_session_token()
return $_SESSION['token'];
}
-function common_disfavor_form($notice)
-{
- common_element_start('form', array('id' => 'disfavor-' . $notice->id,
- 'method' => 'post',
- 'class' => 'disfavor',
- 'action' => common_local_url('disfavor')));
-
- common_element('input', array('type' => 'hidden',
- 'name' => 'token-'. $notice->id,
- 'id' => 'token-'. $notice->id,
- 'class' => 'token',
- 'value' => common_session_token()));
-
- common_element('input', array('type' => 'hidden',
- 'name' => 'notice',
- 'id' => 'notice-n'. $notice->id,
- 'class' => 'notice',
- 'value' => $notice->id));
-
- common_element('input', array('type' => 'submit',
- 'id' => 'disfavor-submit-' . $notice->id,
- 'name' => 'disfavor-submit-' . $notice->id,
- 'class' => 'disfavor',
- 'value' => 'Disfavor favorite',
- 'title' => 'Remove this message from favorites'));
- common_element_end('form');
-}
-
-function common_favor_form($notice)
-{
- common_element_start('form', array('id' => 'favor-' . $notice->id,
- 'method' => 'post',
- 'class' => 'favor',
- 'action' => common_local_url('favor')));
-
- common_element('input', array('type' => 'hidden',
- 'name' => 'token-'. $notice->id,
- 'id' => 'token-'. $notice->id,
- 'class' => 'token',
- 'value' => common_session_token()));
-
- common_element('input', array('type' => 'hidden',
- 'name' => 'notice',
- 'id' => 'notice-n'. $notice->id,
- 'class' => 'notice',
- 'value' => $notice->id));
-
- common_element('input', array('type' => 'submit',
- 'id' => 'favor-submit-' . $notice->id,
- 'name' => 'favor-submit-' . $notice->id,
- 'class' => 'favor',
- 'value' => 'Add to favorites',
- 'title' => 'Add this message to favorites'));
- common_element_end('form');
-}
-
-function common_nudge_form($profile)
-{
- common_element_start('form', array('id' => 'nudge', 'method' => 'post',
- 'action' => common_local_url('nudge', array('nickname' => $profile->nickname))));
- common_hidden('token', common_session_token());
- common_element('input', array('type' => 'submit',
- 'class' => 'submit',
- 'value' => _('Send a nudge')));
- common_element_end('form');
-}
function common_nudge_response()
{
common_element('p', array('id' => 'nudge_response'), _('Nudge sent!'));
}
-function common_subscribe_form($profile)
-{
- common_element_start('form', array('id' => 'subscribe-' . $profile->id,
- 'method' => 'post',
- 'class' => 'subscribe',
- 'action' => common_local_url('subscribe')));
- common_hidden('token', common_session_token());
- common_element('input', array('id' => 'subscribeto-' . $profile->id,
- 'name' => 'subscribeto',
- 'type' => 'hidden',
- 'value' => $profile->id));
- common_element('input', array('type' => 'submit',
- 'class' => 'submit',
- 'value' => _('Subscribe')));
- common_element_end('form');
-}
-
-function common_unsubscribe_form($profile)
-{
- common_element_start('form', array('id' => 'unsubscribe-' . $profile->id,
- 'method' => 'post',
- 'class' => 'unsubscribe',
- 'action' => common_local_url('unsubscribe')));
- common_hidden('token', common_session_token());
- common_element('input', array('id' => 'unsubscribeto-' . $profile->id,
- 'name' => 'unsubscribeto',
- 'type' => 'hidden',
- 'value' => $profile->id));
- common_element('input', array('type' => 'submit',
- 'class' => 'submit',
- 'value' => _('Unsubscribe')));
- common_element_end('form');
-}
-
// XXX: Refactor this code
function common_profile_new_message_nudge ($cur, $profile)
{
@@ -2241,47 +1676,6 @@ function common_keyize($str)
return $str;
}
-function common_message_form($content, $user, $to)
-{
-
- common_element_start('form', array('id' => 'message_form',
- 'method' => 'post',
- 'action' => common_local_url('newmessage')));
-
- $mutual_users = $user->mutuallySubscribedUsers();
-
- $mutual = array();
-
- while ($mutual_users->fetch()) {
- if ($mutual_users->id != $user->id) {
- $mutual[$mutual_users->id] = $mutual_users->nickname;
- }
- }
-
- $mutual_users->free();
- unset($mutual_users);
-
- common_dropdown('to', _('To'), $mutual, null, false, $to->id);
-
- common_element_start('p');
-
- common_element('textarea', array('id' => 'message_content',
- 'cols' => 60,
- 'rows' => 3,
- 'name' => 'content'),
- ($content) ? $content : '');
-
- common_element('input', array('id' => 'message_send',
- 'name' => 'message_send',
- 'type' => 'submit',
- 'value' => _('Send')));
-
- common_hidden('token', common_session_token());
-
- common_element_end('p');
- common_element_end('form');
-}
-
function common_memcache()
{
static $cache = null;
@@ -2308,39 +1702,3 @@ function common_compatible_license($from, $to)
// XXX: better compatibility check needed here!
return ($from == $to);
}
-
-/* These are almost identical, so we use a helper function */
-
-function common_block_form($profile, $args=null)
-{
- common_blocking_form('block', _('Block'), $profile, $args);
-}
-
-function common_unblock_form($profile, $args=null)
-{
- common_blocking_form('unblock', _('Unblock'), $profile, $args);
-}
-
-function common_blocking_form($type, $label, $profile, $args=null)
-{
- common_element_start('form', array('id' => $type . '-' . $profile->id,
- 'method' => 'post',
- 'class' => $type,
- 'action' => common_local_url($type)));
- common_hidden('token', common_session_token());
- common_element('input', array('id' => $type . 'to-' . $profile->id,
- 'name' => $type . 'to',
- 'type' => 'hidden',
- 'value' => $profile->id));
- common_element('input', array('type' => 'submit',
- 'class' => 'submit',
- 'name' => $type,
- 'value' => $label));
- if ($args) {
- foreach ($args as $k => $v) {
- common_hidden('returnto-' . $k, $v);
- }
- }
- common_element_end('form');
- return;
-}
diff --git a/lib/widget.php b/lib/widget.php
new file mode 100644
index 000000000..c70505c44
--- /dev/null
+++ b/lib/widget.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Base class for UI widgets
+ *
+ * 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 Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 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);
+}
+
+/**
+ * Base class for UI widgets
+ *
+ * A widget is a cluster of HTML elements that provide some functionality
+ * that's used on different parts of the site. Examples would be profile
+ * lists, notice lists, navigation menus (tabsets) and common forms.
+ *
+ * @category Widget
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ *
+ * @see HTMLOutputter
+ */
+
+class Widget
+{
+ /**
+ * HTMLOutputter to use for output
+ */
+
+ var $out = null;
+
+ /**
+ * Prepare the widget for use
+ *
+ * @param HTMLOutputter $out output helper, defaults to null
+ */
+
+ function __construct($out=null)
+ {
+ $this->out = $out;
+ }
+
+ /**
+ * Show the widget
+ *
+ * Emit the HTML for the widget, using the configured outputter.
+ *
+ * @return void
+ */
+
+ function show()
+ {
+ }
+}
diff --git a/lib/xmloutputter.php b/lib/xmloutputter.php
new file mode 100644
index 000000000..64935da40
--- /dev/null
+++ b/lib/xmloutputter.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Low-level generator for XML
+ *
+ * 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 Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @copyright 2008 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);
+}
+
+/**
+ * Low-level generator for XML
+ *
+ * This is a thin wrapper around PHP's XMLWriter. The main
+ * advantage is the element() method, which simplifies outputting
+ * an element.
+ *
+ * @category Output
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@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/
+ * @see Action
+ * @see HTMLOutputter
+ */
+
+class XMLOutputter
+{
+ /**
+ * Wrapped XMLWriter object, which does most of the heavy lifting
+ * for output.
+ */
+
+ var $xw = null;
+
+ /**
+ * Constructor
+ *
+ * Initializes the wrapped XMLWriter.
+ *
+ * @param string $output URL for outputting, defaults to stdout
+ * @param boolean $indent Whether to indent output, default true
+ */
+
+ function __construct($output='php://output', $indent=true)
+ {
+ $this->xw = new XMLWriter();
+ $this->xw->openURI($output);
+ $this->xw->setIndent($indent);
+ }
+
+ /**
+ * Start a new XML document
+ *
+ * @param string $doc document element
+ * @param string $public public identifier
+ * @param string $system system identifier
+ *
+ * @return void
+ */
+
+ function startXML($doc=null, $public=null, $system=null)
+ {
+ $this->xw->startDocument('1.0', 'UTF-8');
+ if ($doc) {
+ $this->xw->writeDTD($doc, $public, $system);
+ }
+ }
+
+ /**
+ * finish an XML document
+ *
+ * It's probably a bad idea to continue to use this object
+ * after calling endXML().
+ *
+ * @return void
+ */
+
+ function endXML()
+ {
+ $this->xw->endDocument();
+ $this->xw->flush();
+ }
+
+ /**
+ * output an XML element
+ *
+ * Utility for outputting an XML element. A convenient wrapper
+ * for a bunch of longer XMLWriter calls. This is best for
+ * when an element doesn't have any sub-elements; if that's the
+ * case, use elementStart() and elementEnd() instead.
+ *
+ * The $content element will be escaped for XML. If you need
+ * raw output, use elementStart() and elementEnd() with a call
+ * to raw() in the middle.
+ *
+ * If $attrs is a string instead of an array, it will be treated
+ * as the class attribute of the element.
+ *
+ * @param string $tag Element type or tagname
+ * @param array $attrs Array of element attributes, as
+ * key-value pairs
+ * @param string $content string content of the element
+ *
+ * @return void
+ */
+
+ function element($tag, $attrs=null, $content=null)
+ {
+ $this->elementStart($tag, $attrs);
+ if (!is_null($content)) {
+ $this->xw->text($content);
+ }
+ $this->elementEnd($tag);
+ }
+
+ /**
+ * output a start tag for an element
+ *
+ * Mostly used for when an element has content that's
+ * not a simple string.
+ *
+ * If $attrs is a string instead of an array, it will be treated
+ * as the class attribute of the element.
+ *
+ * @param string $tag Element type or tagname
+ * @param array $attrs Array of element attributes
+ *
+ * @return void
+ */
+
+ function elementStart($tag, $attrs=null)
+ {
+ $this->xw->startElement($tag);
+ if (is_array($attrs)) {
+ foreach ($attrs as $name => $value) {
+ $this->xw->writeAttribute($name, $value);
+ }
+ } else if (is_string($attrs)) {
+ $this->xw->writeAttribute('class', $attrs);
+ }
+ }
+
+ /**
+ * output an end tag for an element
+ *
+ * Used in conjunction with elementStart(). $tag param
+ * should match the elementStart() param.
+ *
+ * For HTML 4 compatibility, this method will force
+ * a full end element (</tag>) even if the element is
+ * empty, except for a handful of exception tagnames.
+ * This is a hack.
+ *
+ * @param string $tag Element type or tagname.
+ *
+ * @return void
+ */
+
+ function elementEnd($tag)
+ {
+ static $empty_tag = array('base', 'meta', 'link', 'hr',
+ 'br', 'param', 'img', 'area',
+ 'input', 'col');
+ // XXX: check namespace
+ if (in_array($tag, $empty_tag)) {
+ $this->xw->endElement();
+ } else {
+ $this->xw->fullEndElement();
+ }
+ }
+
+ /**
+ * output plain text
+ *
+ * Text will be escaped. If you need it not to be,
+ * use raw() instead.
+ *
+ * @param string $txt Text to output.
+ *
+ * @return void
+ */
+
+ function text($txt)
+ {
+ $this->xw->text($txt);
+ }
+
+ /**
+ * output raw xml
+ *
+ * This will spit out its argument verbatim -- no escaping is
+ * done.
+ *
+ * @param string $xml XML to output.
+ *
+ * @return void
+ */
+
+ function raw($xml)
+ {
+ $this->xw->writeRaw($xml);
+ }
+
+ /**
+ * output a comment
+ *
+ * @param string $txt text of the comment
+ *
+ * @return void
+ */
+
+ function comment($txt)
+ {
+ $this->xw->writeComment($txt);
+ }
+}