Merge branch '0.7.x' into 0.8.x

This commit is contained in:
Evan Prodromou 2009-02-28 21:11:16 -08:00
commit fc44c9a7f4
19 changed files with 405 additions and 177 deletions

View File

@ -88,3 +88,9 @@ StartShowLocalNavBlock: Showing the local nav menu
EndShowLocalNavBlock: At the end of the local nav menu EndShowLocalNavBlock: At the end of the local nav menu
- $action: the current action - $action: the current action
StartShowHTML: Chance to set document content type, charset, language, DOCTYPE and html element properties
- $action: the current action
EndShowHTML: Showing after the html element
- $action: the current action

View File

@ -324,13 +324,12 @@ class AvatarsettingsAction extends AccountSettingsAction
return; return;
} }
// If image is not being cropped assume pos & dimentions of original // If image is not being cropped assume pos & dimensions of original.
$dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0; $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
$dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0; $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
$dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$filedata['width']; $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$filedata['width'];
$dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height']; $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height'];
$size = min($dest_w, $dest_h); $size = min($dest_w, $dest_h, MAX_ORIGINAL);
$size = ($size > MAX_ORIGINAL) ? MAX_ORIGINAL:$size;
$user = common_current_user(); $user = common_current_user();
$profile = $user->getProfile(); $profile = $user->getProfile();
@ -343,6 +342,7 @@ class AvatarsettingsAction extends AccountSettingsAction
unset($_SESSION['FILEDATA']); unset($_SESSION['FILEDATA']);
$this->mode = 'upload'; $this->mode = 'upload';
$this->showForm(_('Avatar updated.'), true); $this->showForm(_('Avatar updated.'), true);
common_broadcast_profile($profile);
} else { } else {
$this->showForm(_('Failed updating avatar.')); $this->showForm(_('Failed updating avatar.'));
} }

View File

@ -283,7 +283,7 @@ class FinishremotesubscribeAction extends Action
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$result = $fetcher->post($req->get_normalized_http_url(), $result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), $req->to_postdata(),
array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); array('User-Agent: Laconica/' . LACONICA_VERSION));
common_debug('got result: "'.print_r($result,true).'"', __FILE__); common_debug('got result: "'.print_r($result,true).'"', __FILE__);

View File

@ -253,7 +253,7 @@ class NewnoticeAction extends Action
} }
} }
$notice_form = new NoticeForm($this, $content); $notice_form = new NoticeForm($this, '', $content);
$notice_form->show(); $notice_form->show();
} }

View File

@ -113,123 +113,58 @@ class NoticesearchAction extends SearchAction
} else { } else {
$cnt = $notice->find(); $cnt = $notice->find();
} }
if ($cnt > 0) { if ($cnt === 0) {
$terms = preg_split('/[\s,]+/', $q);
$this->elementStart('ul', array('class' => 'notices'));
for ($i = 0; $i < min($cnt, NOTICES_PER_PAGE); $i++) {
if ($notice->fetch()) {
$this->showNotice($notice, $terms);
} else {
// shouldn't happen!
break;
}
}
$this->elementEnd('ul');
} else {
$this->element('p', 'error', _('No results')); $this->element('p', 'error', _('No results'));
}
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
$page, 'noticesearch', array('q' => $q));
}
/**
* Show notice
*
* @param class $notice notice
* @param array $terms terms to highlight
*
* @return void
*
* @todo refactor and combine with StreamAction::showNotice()
*/
function showNotice($notice, $terms)
{
$profile = $notice->getProfile();
if (!$profile) {
common_log_db_error($notice, 'SELECT', __FILE__);
$this->serverError(_('Notice without matching profile'));
return; return;
} }
// XXX: RDFa $terms = preg_split('/[\s,]+/', $q);
$this->elementStart('li', array('class' => 'hentry notice', $nl = new SearchNoticeList($notice, $this, $terms);
'id' => 'notice-' . $notice->id));
$this->elementStart('div', 'entry-title'); $cnt = $nl->show();
$this->elementStart('span', 'vcard author');
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
$this->elementStart('a', array('href' => $profile->profileurl,
'class' => 'url'));
$this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE),
'class' => 'avatar photo',
'width' => AVATAR_STREAM_SIZE,
'height' => AVATAR_STREAM_SIZE,
'alt' =>
($profile->fullname) ? $profile->fullname :
$profile->nickname));
$this->element('span', 'nickname fn', $profile->nickname);
$this->elementEnd('a');
$this->elementEnd('span');
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'noticesearch', array('q' => $q));
}
function isReadOnly()
{
return true;
}
}
class SearchNoticeList extends NoticeList {
function __construct($notice, $out=null, $terms)
{
parent::__construct($notice, $out);
$this->terms = $terms;
}
function newListItem($notice)
{
return new SearchNoticeListItem($notice, $this->out, $this->terms);
}
}
class SearchNoticeListItem extends NoticeListItem {
function __construct($notice, $out=null, $terms)
{
parent::__construct($notice, $out);
$this->terms = $terms;
}
function showContent()
{
// FIXME: URL, image, video, audio // FIXME: URL, image, video, audio
$this->elementStart('p', array('class' => 'entry-content')); $this->out->elementStart('p', array('class' => 'entry-content'));
if ($notice->rendered) { if ($this->notice->rendered) {
$this->raw($this->highlight($notice->rendered, $terms)); $this->out->raw($this->highlight($this->notice->rendered, $this->terms));
} else { } else {
// XXX: may be some uncooked notices in the DB, // XXX: may be some uncooked notices in the DB,
// we cook them right now. This should probably disappear in future // we cook them right now. This should probably disappear in future
// versions (>> 0.4.x) // versions (>> 0.4.x)
$this->raw($this->highlight(common_render_content($notice->content, $notice), $terms)); $this->out->raw($this->highlight(common_render_content($this->notice->content, $this->notice), $this->terms));
} }
$this->elementEnd('p'); $this->out->elementEnd('p');
$this->elementEnd('div');
$noticeurl = common_local_url('shownotice', array('notice' => $notice->id));
$this->elementStart('div', 'entry-content');
$this->elementStart('dl', 'timestamp');
$this->element('dt', null, _('Published'));
$this->elementStart('dd', null);
$this->elementStart('a', array('rel' => 'bookmark',
'href' => $noticeurl));
$dt = common_date_iso8601($notice->created);
$this->element('abbr', array('class' => 'published',
'title' => $dt),
common_date_string($notice->created));
$this->elementEnd('a');
$this->elementEnd('dd');
$this->elementEnd('dl');
if ($notice->reply_to) {
$replyurl = common_local_url('shownotice',
array('notice' => $this->notice->reply_to));
$this->elementStart('dl', 'response');
$this->element('dt', null, _('To'));
$this->elementStart('dd');
$this->element('a', array('href' => $replyurl,
'rel' => 'in-reply-to'),
_('in reply to'));
$this->elementEnd('dd');
$this->elementEnd('dl');
}
$this->elementEnd('div');
$this->elementStart('div', 'notice-options');
$reply_url = common_local_url('newnotice',
array('replyto' => $profile->nickname));
$this->elementStart('dl', 'notice_reply');
$this->element('dt', null, _('Reply to this notice'));
$this->elementStart('dd');
$this->elementStart('a', array('href' => $reply_url,
'title' => _('Reply to this notice')));
$this->text(_('Reply'));
$this->element('span', 'notice_id', $notice->id);
$this->elementEnd('a');
$this->elementEnd('dd');
$this->elementEnd('dl');
$this->elementEnd('div');
$this->elementEnd('li');
} }
/** /**
@ -242,7 +177,7 @@ class NoticesearchAction extends SearchAction
*/ */
function highlight($text, $terms) function highlight($text, $terms)
{ {
/* Highligh serach terms */ /* Highligh search terms */
$pattern = '/('.implode('|', array_map('htmlspecialchars', $terms)).')/i'; $pattern = '/('.implode('|', array_map('htmlspecialchars', $terms)).')/i';
$result = preg_replace($pattern, '<strong>\\1</strong>', $text); $result = preg_replace($pattern, '<strong>\\1</strong>', $text);
@ -253,10 +188,5 @@ class NoticesearchAction extends SearchAction
} while ($count); } while ($count);
return $result; return $result;
} }
function isReadOnly()
{
return true;
}
} }

View File

@ -321,8 +321,7 @@ class RemotesubscribeAction extends Action
$result = $fetcher->post($req->get_normalized_http_url(), $result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), $req->to_postdata(),
array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); array('User-Agent: Laconica/' . LACONICA_VERSION));
if ($result->status != 200) { if ($result->status != 200) {
return null; return null;
} }

View File

@ -162,7 +162,13 @@ class UpdateprofileAction extends Action
if ($avatar) { if ($avatar) {
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar'); $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
copy($avatar, $temp_filename); copy($avatar, $temp_filename);
if (!$profile->setOriginal($temp_filename)) { $imagefile = new ImageFile($profile->id, $temp_filename);
$filename = Avatar::filename($profile->id,
image_type_to_extension($imagefile->type),
null,
common_timestamp());
rename($temp_filename, Avatar::path($filename));
if (!$profile->setOriginal($filename)) {
$this->serverError(_('Could not save avatar info'), 500); $this->serverError(_('Could not save avatar info'), 500);
return false; return false;
} }

View File

@ -105,7 +105,7 @@ class UserauthorizationAction extends Action
$this->elementStart('div', 'profile'); $this->elementStart('div', 'profile');
if ($avatar) { if ($avatar) {
$this->element('img', array('src' => $avatar, $this->element('img', array('src' => $avatar,
'class' => 'avatar profile', 'class' => 'avatar',
'width' => AVATAR_PROFILE_SIZE, 'width' => AVATAR_PROFILE_SIZE,
'height' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE,
'alt' => $nickname)); 'alt' => $nickname));

View File

@ -4,7 +4,7 @@
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Profile_tag extends Memcached_DataObject class Profile_tag extends Memcached_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
@ -23,45 +23,46 @@ class Profile_tag extends Memcached_DataObject
###END_AUTOCODE ###END_AUTOCODE
static function getTags($tagger, $tagged) { static function getTags($tagger, $tagged) {
$tags = array(); $tags = array();
# XXX: store this in memcached # XXX: store this in memcached
$profile_tag = new Profile_tag(); $profile_tag = new Profile_tag();
$profile_tag->tagger = $tagger; $profile_tag->tagger = $tagger;
$profile_tag->tagged = $tagged; $profile_tag->tagged = $tagged;
$profile_tag->find(); $profile_tag->find();
while ($profile_tag->fetch()) { while ($profile_tag->fetch()) {
$tags[] = $profile_tag->tag; $tags[] = $profile_tag->tag;
} }
$profile_tag->free(); $profile_tag->free();
return $tags; return $tags;
} }
static function setTags($tagger, $tagged, $newtags) { static function setTags($tagger, $tagged, $newtags) {
$newtags = array_unique($newtags);
$oldtags = Profile_tag::getTags($tagger, $tagged); $oldtags = Profile_tag::getTags($tagger, $tagged);
# Delete stuff that's old that not in new # Delete stuff that's old that not in new
$to_delete = array_diff($oldtags, $newtags); $to_delete = array_diff($oldtags, $newtags);
# Insert stuff that's in new and not in old # Insert stuff that's in new and not in old
$to_insert = array_diff($newtags, $oldtags); $to_insert = array_diff($newtags, $oldtags);
$profile_tag = new Profile_tag(); $profile_tag = new Profile_tag();
$profile_tag->tagger = $tagger; $profile_tag->tagger = $tagger;
$profile_tag->tagged = $tagged; $profile_tag->tagged = $tagged;
$profile_tag->query('BEGIN'); $profile_tag->query('BEGIN');
foreach ($to_delete as $deltag) { foreach ($to_delete as $deltag) {
$profile_tag->tag = $deltag; $profile_tag->tag = $deltag;
$result = $profile_tag->delete(); $result = $profile_tag->delete();
@ -70,7 +71,7 @@ class Profile_tag extends Memcached_DataObject
return false; return false;
} }
} }
foreach ($to_insert as $instag) { foreach ($to_insert as $instag) {
$profile_tag->tag = $instag; $profile_tag->tag = $instag;
$result = $profile_tag->insert(); $result = $profile_tag->insert();
@ -79,12 +80,12 @@ class Profile_tag extends Memcached_DataObject
return false; return false;
} }
} }
$profile_tag->query('COMMIT'); $profile_tag->query('COMMIT');
return true; return true;
} }
# Return profiles with a given tag # Return profiles with a given tag
static function getTagged($tagger, $tag) { static function getTagged($tagger, $tag) {
$profile = new Profile(); $profile = new Profile();

View File

@ -173,7 +173,7 @@ create table token (
tok char(32) not null comment 'identifying value', tok char(32) not null comment 'identifying value',
secret char(32) not null comment 'secret value', secret char(32) not null comment 'secret value',
type tinyint not null default 0 comment 'request or access', type tinyint not null default 0 comment 'request or access',
state tinyint default 0 comment 'for requests; 0 = initial, 1 = authorized, 2 = used', state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
created datetime not null comment 'date this record was created', created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified', modified timestamp comment 'date this record was modified',
@ -346,7 +346,7 @@ create table notice_inbox (
user_id integer not null comment 'user receiving the message' references user (id), user_id integer not null comment 'user receiving the message' references user (id),
notice_id integer not null comment 'notice received' references notice (id), notice_id integer not null comment 'notice received' references notice (id),
created datetime not null comment 'date the notice was created', created datetime not null comment 'date the notice was created',
source tinyint default 1 comment 'reason it is in the inbox; 1=subscription', source tinyint default 1 comment 'reason it is in the inbox, 1=subscription',
constraint primary key (user_id, notice_id), constraint primary key (user_id, notice_id),
index notice_inbox_notice_id_idx (notice_id) index notice_inbox_notice_id_idx (notice_id)

213
install.php Normal file
View File

@ -0,0 +1,213 @@
<?
define('INSTALLDIR', dirname(__FILE__));
function main()
{
if (!checkPrereqs())
{
return;
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
handlePost();
} else {
showForm();
}
}
function checkPrereqs()
{
if (file_exists(INSTALLDIR.'/config.php')) {
?><p class="error">Config file &quot;config.php&quot; already exists.</p>
<?
return false;
}
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
?><p class="error">Require PHP version 5 or greater.</p><?
return false;
}
$reqs = array('gd', 'mysql', 'curl',
'xmlwriter', 'mbstring',
'gettext');
foreach ($reqs as $req) {
if (!checkExtension($req)) {
?><p class="error">Cannot load required extension &quot;<?= $req ?>&quot;.</p><?
return false;
}
}
if (!is_writable(INSTALLDIR)) {
?><p class="error">Cannot write config file to &quot;<?= INSTALLDIR ?>&quot;.</p>
<p>On your server, try this command:</p>
<blockquote>chmod a+w <?= INSTALLDIR ?></blockquote>
<?
return false;
}
if (!is_writable(INSTALLDIR.'/avatar/')) {
?><p class="error">Cannot write avatar directory &quot;<?= INSTALLDIR ?>/avatar/&quot;.</p>
<p>On your server, try this command:</p>
<blockquote>chmod a+w <?= INSTALLDIR ?>/avatar/</blockquote>
<?
return false;
}
return true;
}
function checkExtension($name)
{
if (!extension_loaded($name)) {
if (!dl($name.'.so')) {
return false;
}
}
return true;
}
function showForm()
{
?>
<p>Enter your database connection information below to initialize the database.</p>
<form method='post' action='install.php'>
<fieldset>
<ul class='form_data'>
<li>
<label for='sitename'>Site name</label>
<input type='text' id='sitename' name='sitename' />
<p>The name of your site</p>
</li>
<li>
<li>
<label for='host'>Hostname</label>
<input type='text' id='host' name='host' />
<p>Database hostname</p>
</li>
<li>
<label for='host'>Database</label>
<input type='text' id='database' name='database' />
<p>Database name</p>
</li>
<li>
<label for='username'>Username</label>
<input type='text' id='username' name='username' />
<p>Database username</p>
</li>
<li>
<label for='password'>Password</label>
<input type='password' id='password' name='password' />
<p>Database password</p>
</li>
</ul>
<input type='submit' name='submit' value='Submit'>
</fieldset>
</form>
<?
}
function updateStatus($status, $error=false)
{
?>
<li>
<?
print $status;
?>
</li>
<?
}
function handlePost()
{
?>
<ul>
<?
$host = $_POST['host'];
$database = $_POST['database'];
$username = $_POST['username'];
$password = $_POST['password'];
$sitename = $_POST['sitename'];
updateStatus("Starting installation...");
updateStatus("Checking database...");
$conn = mysql_connect($host, $username, $password);
if (!$conn) {
updateStatus("Can't connect to server '$host' as '$username'.", true);
showForm();
return;
}
updateStatus("Changing to database...");
$res = mysql_select_db($database, $conn);
if (!$res) {
updateStatus("Can't change to database.", true);
showForm();
return;
}
updateStatus("Running database script...");
$res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
if ($res === false) {
updateStatus("Can't run database script.", true);
showForm();
return;
}
updateStatus("Writing config file...");
$sqlUrl = "mysqli://$username:$password@$host/$database";
$res = writeConf($sitename, $sqlUrl);
if (!$res) {
updateStatus("Can't write config file.", true);
showForm();
return;
}
updateStatus("Done!");
?>
</ul>
<?
}
function writeConf($sitename, $sqlUrl)
{
$res = file_put_contents(INSTALLDIR.'/config.php',
"<?\n".
"\$config['site']['name'] = \"$sitename\";\n\n".
"\$config['db']['database'] = \"$sqlUrl\";\n\n");
return $res;
}
function runDbScript($filename, $conn)
{
$sql = trim(file_get_contents($filename));
$stmts = explode(';', $sql);
foreach ($stmts as $stmt) {
$stmt = trim($stmt);
if (!mb_strlen($stmt)) {
continue;
}
$res = mysql_query($stmt, $conn);
if ($res === false) {
return $res;
}
}
return true;
}
?>
<html>
<head>
<title>Install Laconica</title>
<link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.7.1" media="screen, projection, tv"/>
<link rel="stylesheet" type="text/css" href="theme/base/css/modal.css?version=0.7.1" media="screen, projection, tv"/>
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.7.1" media="screen, projection, tv"/>
</head>
<body>
<div id="wrap">
<div id="core">
<div id="content">
<h1>Install Laconica</h1>
<? main() ?>
</div>
</div>
</div>
</body>
</html>

View File

@ -93,7 +93,10 @@ class Action extends HTMLOutputter // lawsuit
*/ */
function showPage() function showPage()
{ {
$this->startHTML(); if (Event::handle('StartShowHTML', array($this))) {
$this->startHTML();
Event::handle('EndShowHTML', array($this));
}
$this->showHead(); $this->showHead();
$this->showBody(); $this->showBody();
$this->endHTML(); $this->endHTML();
@ -173,6 +176,10 @@ class Action extends HTMLOutputter // lawsuit
// TODO: "handheld" CSS for other mobile devices // TODO: "handheld" CSS for other mobile devices
'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit 'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit
} }
$this->element('link', array('rel' => 'stylesheet',
'type' => 'text/css',
'href' => theme_path('css/print.css', 'base') . '?version=' . LACONICA_VERSION,
'media' => 'print'));
Event::handle('EndShowLaconicaStyles', array($this)); Event::handle('EndShowLaconicaStyles', array($this));
} }
if (Event::handle('StartShowUAStyles', array($this))) { if (Event::handle('StartShowUAStyles', array($this))) {

View File

@ -178,12 +178,25 @@ if (strlen($_path) > 0) {
$_config_files[] = INSTALLDIR.'/config.php'; $_config_files[] = INSTALLDIR.'/config.php';
$_have_a_config = false;
foreach ($_config_files as $_config_file) { foreach ($_config_files as $_config_file) {
if (file_exists($_config_file)) { if (file_exists($_config_file)) {
include_once($_config_file); include_once($_config_file);
$_have_a_config = true;
} }
} }
// XXX: Throw a conniption if database not installed
// Fixup for laconica.ini
$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1);
if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
$config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini';
}
// XXX: how many of these could be auto-loaded on use? // XXX: how many of these could be auto-loaded on use?
require_once('Validate.php'); require_once('Validate.php');

View File

@ -94,40 +94,43 @@ function get_nice_language_list()
* Get a list of all languages that are enabled in the default config * Get a list of all languages that are enabled in the default config
* *
* This should ONLY be called when setting up the default config in common.php. * This should ONLY be called when setting up the default config in common.php.
* Any other attempt to get a list of lanugages should instead call * Any other attempt to get a list of languages should instead call
* common_config('site','languages') * common_config('site','languages')
* *
* @return array mapping of language codes to language info * @return array mapping of language codes to language info
*/ */
function get_all_languages() { function get_all_languages() {
return array( return array(
'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'), 'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'),
'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'), 'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'),
'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'), 'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'),
'de' => array('q' => 0.5, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'), 'de' => array('q' => 0.5, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'),
'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'), 'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'),
'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), 'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'),
'en-gb' => array('q' => 0.3, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'), 'en-gb' => array('q' => 0.3, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'),
'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English', 'direction' => 'ltr'), 'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English', 'direction' => 'ltr'),
'es' => array('q' => 0.5, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'), 'es' => array('q' => 0.5, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'),
'fr-fr' => array('q' => 0.2, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'), 'fi' => array('q' => 0.5, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'ltr'), 'fr-fr' => array('q' => 0.2, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'),
'it' => array('q' => 0.9, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'rtl'), 'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'),
'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), 'it' => array('q' => 0.9, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'),
# 'ko' => array('q' => 0, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'), 'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'),
'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), # 'ko' => array('q' => 0, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'),
'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (bokmal)', 'direction' => 'ltr'), 'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'),
'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'), 'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'), 'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
# 'pt' => array('q' => 0, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'), 'nn' => array('q' => 0.1, 'lang' => 'nn_NO', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'),
'pt-br' => array('q' => 0.7, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'), 'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'),
'ru' => array('q' => 0.1, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'), 'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'),
'sv' => array('q' => 0.9, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'), # 'pt' => array('q' => 0, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'),
'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'), 'pt-br' => array('q' => 0.7, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'),
'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'), 'ru' => array('q' => 0.1, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'),
'uk' => array('q' => 0.7, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'), 'sv' => array('q' => 0.9, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'),
'vi' => array('q' => 0.7, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'), 'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'),
'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'), 'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'),
'zh-hant' => array('q' => 0.2, 'lang' => 'zh_hant', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'), 'uk' => array('q' => 0.7, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'),
'vi' => array('q' => 0.7, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'),
'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'),
'zh-hant' => array('q' => 0.2, 'lang' => 'zh_hant', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'),
); );
} }

View File

@ -206,7 +206,7 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
$result = $fetcher->post($req->get_normalized_http_url(), $result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), $req->to_postdata(),
array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); array('User-Agent: Laconica/' . LACONICA_VERSION));
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
@ -291,7 +291,7 @@ function omb_update_profile($profile, $remote_profile, $subscription)
common_debug('postdata = '.$req->to_postdata(), __FILE__); common_debug('postdata = '.$req->to_postdata(), __FILE__);
$result = $fetcher->post($req->get_normalized_http_url(), $result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), $req->to_postdata(),
array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); array('User-Agent: Laconica/' . LACONICA_VERSION));
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);

View File

@ -116,6 +116,12 @@ class Router
$m->connect('main/openid', array('action' => 'openidlogin')); $m->connect('main/openid', array('action' => 'openidlogin'));
$m->connect('main/remote', array('action' => 'remotesubscribe')); $m->connect('main/remote', array('action' => 'remotesubscribe'));
$m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+'));
foreach (array('requesttoken', 'accesstoken', 'userauthorization',
'postnotice', 'updateprofile', 'finishremotesubscribe') as $action) {
$m->connect('index.php?action=' . $action, array('action' => $action));
}
// settings // settings
@ -128,6 +134,7 @@ class Router
foreach (array('group', 'people', 'notice') as $s) { foreach (array('group', 'people', 'notice') as $s) {
$m->connect('search/'.$s, array('action' => $s.'search')); $m->connect('search/'.$s, array('action' => $s.'search'));
$m->connect('search/'.$s.'?q=:q', array('action' => $s.'search'), array('q' => '.+'));
} }
$m->connect('search/notice/rss', array('action' => 'noticesearchrss')); $m->connect('search/notice/rss', array('action' => 'noticesearchrss'));
@ -135,6 +142,9 @@ class Router
// notice // notice
$m->connect('notice/new', array('action' => 'newnotice')); $m->connect('notice/new', array('action' => 'newnotice'));
$m->connect('notice/new?replyto=:replyto',
array('action' => 'newnotice'),
array('replyto' => '[A-Za-z0-9_-]+'));
$m->connect('notice/:notice', $m->connect('notice/:notice',
array('action' => 'shownotice'), array('action' => 'shownotice'),
array('notice' => '[0-9]+')); array('notice' => '[0-9]+'));
@ -150,6 +160,7 @@ class Router
array('id' => '[0-9]+')); array('id' => '[0-9]+'));
$m->connect('message/new', array('action' => 'newmessage')); $m->connect('message/new', array('action' => 'newmessage'));
$m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]'));
$m->connect('message/:message', $m->connect('message/:message',
array('action' => 'showmessage'), array('action' => 'showmessage'),
array('message' => '[0-9]+')); array('message' => '[0-9]+'));
@ -416,4 +427,4 @@ class Router
return $this->m->generate($args, $params, $fragment); return $this->m->generate($args, $params, $fragment);
} }
} }

View File

@ -456,6 +456,9 @@ function common_replace_urls_callback($text, $callback) {
if (!in_array($url_parts[2], $tlds)) continue; if (!in_array($url_parts[2], $tlds)) continue;
// Make sure we didn't capture a hash tag
if (strpos($url, '#') === 0) continue;
// Put the url back the way we found it. // Put the url back the way we found it.
$url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);

View File

@ -297,7 +297,7 @@ padding:4px 11px;
border-width:1px; border-width:1px;
border-style:solid; border-style:solid;
border-bottom:0; border-bottom:0;
text-shadow: 4px 4px 4px #ddd; text-shadow: 2px 2px 2px #ddd;
font-weight:bold; font-weight:bold;
} }
#site_nav_local_views .nav { #site_nav_local_views .nav {

36
theme/base/css/print.css Normal file
View File

@ -0,0 +1,36 @@
/** theme: base
*
* @package Laconica
* @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/
*/
a:after { background-color:#fff; }
a:not([href^="#"]):after { content:" ( "attr(href)" ) "; }
img { border:none; }
p { orphans: 2; widows: 1; }
#site_nav_global_primary,
#site_nav_local_views,
#form_notice,
.pagination,
#site_nav_global_secondary,
.entity_actions,
.notice-options,
#aside_primary,
.form_subcription_edit .submit {
display:none;
}
.timestamp dt, .timestamp dd,
.device dt, .device dd {
display:inline;
}
.profiles li,
.notices li {
margin-bottom:18px;
}