Merge branch '0.8.x' of git@gitorious.org:laconica/mainline into 0.8.x
This commit is contained in:
commit
2087ae621c
@ -382,13 +382,7 @@ class AvatarsettingsAction extends AccountSettingsAction
|
|||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
parent::showStylesheets();
|
||||||
$jcropStyle =
|
$this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
|
||||||
common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
|
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => $jcropStyle,
|
|
||||||
'media' => 'screen, projection, tv'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -402,13 +396,8 @@ class AvatarsettingsAction extends AccountSettingsAction
|
|||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
|
||||||
if ($this->mode == 'crop') {
|
if ($this->mode == 'crop') {
|
||||||
$jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
|
$this->script('js/jcrop/jquery.Jcrop.pack.js');
|
||||||
$jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
|
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||||
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $jcropPack));
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $jcropGo));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ class FinishopenidloginAction extends Action
|
|||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -389,7 +389,7 @@ class FinishopenidloginAction extends Action
|
|||||||
{
|
{
|
||||||
if (!Validate::string($str, array('min_length' => 1,
|
if (!Validate::string($str, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!User::allowed_nickname($str)) {
|
if (!User::allowed_nickname($str)) {
|
||||||
|
@ -428,13 +428,7 @@ class GrouplogoAction extends GroupDesignAction
|
|||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
parent::showStylesheets();
|
||||||
$jcropStyle =
|
$this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
|
||||||
common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
|
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => $jcropStyle,
|
|
||||||
'media' => 'screen, projection, tv'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -448,13 +442,8 @@ class GrouplogoAction extends GroupDesignAction
|
|||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
|
||||||
if ($this->mode == 'crop') {
|
if ($this->mode == 'crop') {
|
||||||
$jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
|
$this->script('js/jcrop/jquery.Jcrop.pack.js');
|
||||||
$jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
|
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||||
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $jcropPack));
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $jcropGo));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
// Some validation
|
// Some validation
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||||
return;
|
return;
|
||||||
} else if (!User::allowed_nickname($nickname)) {
|
} else if (!User::allowed_nickname($nickname)) {
|
||||||
|
@ -79,7 +79,7 @@ class UpdateprofileAction extends Action
|
|||||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
$nickname = $req->get_parameter('omb_listenee_nickname');
|
||||||
if ($nickname && !Validate::string($nickname, array('min_length' => 1,
|
if ($nickname && !Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
$this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
$this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ class UserauthorizationAction extends Action
|
|||||||
$nickname = $_GET['omb_listenee_nickname'];
|
$nickname = $_GET['omb_listenee_nickname'];
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
||||||
}
|
}
|
||||||
$profile = $_GET['omb_listenee_profile'];
|
$profile = $_GET['omb_listenee_profile'];
|
||||||
|
@ -383,9 +383,7 @@ function runDbScript($filename, $conn, $type='mysql')
|
|||||||
|
|
||||||
?>
|
?>
|
||||||
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
|
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
|
||||||
<!DOCTYPE html
|
<!DOCTYPE html>
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
|
||||||
<head>
|
<head>
|
||||||
<title>Install Laconica</title>
|
<title>Install Laconica</title>
|
||||||
|
@ -193,21 +193,12 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
if (Event::handle('StartShowStyles', array($this))) {
|
if (Event::handle('StartShowStyles', array($this))) {
|
||||||
|
|
||||||
if (Event::handle('StartShowLaconicaStyles', array($this))) {
|
if (Event::handle('StartShowLaconicaStyles', array($this))) {
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
$this->cssLink('css/display.css',null,'screen, projection, tv');
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
|
|
||||||
'media' => 'screen, projection, tv'));
|
|
||||||
if (common_config('site', 'mobile')) {
|
if (common_config('site', 'mobile')) {
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
// TODO: "handheld" CSS for other mobile devices
|
||||||
'type' => 'text/css',
|
$this->cssLink('css/mobile.css','base','only screen and (max-device-width: 480px)'); // Mobile WebKit
|
||||||
'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION,
|
|
||||||
// TODO: "handheld" CSS for other mobile devices
|
|
||||||
'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit
|
|
||||||
}
|
}
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
$this->cssLink('css/print.css','base','print');
|
||||||
'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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,26 +244,14 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
{
|
{
|
||||||
if (Event::handle('StartShowScripts', array($this))) {
|
if (Event::handle('StartShowScripts', array($this))) {
|
||||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
$this->script('js/jquery.min.js');
|
||||||
'src' => common_path('js/jquery.min.js')),
|
$this->script('js/jquery.form.js');
|
||||||
' ');
|
$this->script('js/jquery.joverlay.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/jquery.joverlay.min.js')),
|
|
||||||
' ');
|
|
||||||
|
|
||||||
Event::handle('EndShowJQueryScripts', array($this));
|
Event::handle('EndShowJQueryScripts', array($this));
|
||||||
}
|
}
|
||||||
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
$this->script('js/xbImportNode.js');
|
||||||
'src' => common_path('js/xbImportNode.js')),
|
$this->script('js/util.js');
|
||||||
' ');
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
|
|
||||||
' ');
|
|
||||||
// Frame-busting code to avoid clickjacking attacks.
|
// Frame-busting code to avoid clickjacking attacks.
|
||||||
$this->element('script', array('type' => 'text/javascript'),
|
$this->element('script', array('type' => 'text/javascript'),
|
||||||
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||||
|
@ -311,13 +311,7 @@ class DesignSettingsAction extends AccountSettingsAction
|
|||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
parent::showStylesheets();
|
||||||
$farbtasticStyle =
|
$this->cssLink('css/farbtastic.css','base','screen, projection, tv');
|
||||||
common_path('theme/base/css/farbtastic.css?version='.LACONICA_VERSION);
|
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => $farbtasticStyle,
|
|
||||||
'media' => 'screen, projection, tv'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -330,13 +324,8 @@ class DesignSettingsAction extends AccountSettingsAction
|
|||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
|
||||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
$this->script('js/farbtastic/farbtastic.js');
|
||||||
$userDesignGo = common_path('js/userdesign.go.js');
|
$this->script('js/farbtastic/farbtastic.go.js');
|
||||||
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $farbtasticPack));
|
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
|
||||||
'src' => $userDesignGo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,34 +95,13 @@ class FacebookAction extends Action
|
|||||||
|
|
||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
$this->cssLink('css/display.css', 'base');
|
||||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
$this->cssLink('css/facebookapp.css', 'base');
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
|
||||||
|
|
||||||
$theme = common_config('site', 'theme');
|
|
||||||
|
|
||||||
$ts = filemtime(INSTALLDIR. '/theme/' . $theme .'/css/display.css');
|
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => theme_path('css/display.css', null) . '?ts=' . $ts));
|
|
||||||
|
|
||||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.css');
|
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => theme_path('css/facebookapp.css', 'base') . '?ts=' . $ts));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
$this->script('js/facebookapp.js');
|
||||||
$ts = filemtime(INSTALLDIR.'/js/facebookapp.js');
|
|
||||||
|
|
||||||
$this->element('script', array('src' => common_path('js/facebookapp.js') . '?ts=' . $ts));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,10 +109,11 @@ class HTMLOutputter extends XMLOutputter
|
|||||||
header('Content-Type: '.$type);
|
header('Content-Type: '.$type);
|
||||||
|
|
||||||
$this->extraHeaders();
|
$this->extraHeaders();
|
||||||
|
if( ! substr($type,0,strlen('text/html'))=='text/html' ){
|
||||||
$this->startXML('html',
|
// Browsers don't like it when <?xml it output for non-xhtml documents
|
||||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
$this->xw->startDocument('1.0', 'UTF-8');
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
}
|
||||||
|
$this->xw->writeDTD('html', $public, $system);
|
||||||
|
|
||||||
$language = $this->getLanguage();
|
$language = $this->getLanguage();
|
||||||
|
|
||||||
@ -338,6 +339,51 @@ class HTMLOutputter extends XMLOutputter
|
|||||||
'title' => $title));
|
'title' => $title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* output a script (almost always javascript) tag
|
||||||
|
*
|
||||||
|
* @param string $src relative or absolute script path
|
||||||
|
* @param string $type 'type' attribute value of the tag
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function script($src, $type='text/javascript')
|
||||||
|
{
|
||||||
|
$url = parse_url($src);
|
||||||
|
if(! ($url->scheme || $url->host || $url->query || $url->fragment))
|
||||||
|
{
|
||||||
|
$src = common_path($src) . '?version=' . LACONICA_VERSION;
|
||||||
|
}
|
||||||
|
$this->element('script', array('type' => $type,
|
||||||
|
'src' => $src),
|
||||||
|
' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* output a css link
|
||||||
|
*
|
||||||
|
* @param string $src relative path within the theme directory, or an absolute path
|
||||||
|
* @param string $theme 'theme' that contains the stylesheet
|
||||||
|
* @param string media 'media' attribute of the tag
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function cssLink($src,$theme=null,$media=null)
|
||||||
|
{
|
||||||
|
if (!$theme) {
|
||||||
|
$theme = common_config('site', 'theme');
|
||||||
|
}
|
||||||
|
$url = parse_url($src);
|
||||||
|
if(! ($url->scheme || $url->host || $url->query || $url->fragment))
|
||||||
|
{
|
||||||
|
$src = theme_path($src) . '?version=' . LACONICA_VERSION;
|
||||||
|
}
|
||||||
|
$this->element('link', array('rel' => 'stylesheet',
|
||||||
|
'type' => 'text/css',
|
||||||
|
'href' => $src,
|
||||||
|
'media' => $media));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* output an HTML textarea and associated elements
|
* output an HTML textarea and associated elements
|
||||||
*
|
*
|
||||||
|
@ -47,9 +47,7 @@ class FBC_XDReceiverAction extends Action
|
|||||||
header('Expires:');
|
header('Expires:');
|
||||||
header('Pragma:');
|
header('Pragma:');
|
||||||
|
|
||||||
$this->startXML('html',
|
$this->startXML('html');
|
||||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
|
||||||
|
|
||||||
$language = $this->getLanguage();
|
$language = $this->getLanguage();
|
||||||
|
|
||||||
@ -58,10 +56,7 @@ class FBC_XDReceiverAction extends Action
|
|||||||
'lang' => $language));
|
'lang' => $language));
|
||||||
$this->elementStart('head');
|
$this->elementStart('head');
|
||||||
$this->element('title', null, 'cross domain receiver page');
|
$this->element('title', null, 'cross domain receiver page');
|
||||||
$this->element('script',
|
$this->script('http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js');
|
||||||
array('src' =>
|
|
||||||
'http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js',
|
|
||||||
'type' => 'text/javascript'), '');
|
|
||||||
$this->elementEnd('head');
|
$this->elementEnd('head');
|
||||||
$this->elementStart('body');
|
$this->elementStart('body');
|
||||||
$this->elementEnd('body');
|
$this->elementEnd('body');
|
||||||
|
@ -238,7 +238,7 @@ class FBConnectauthAction extends Action
|
|||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -418,7 +418,7 @@ class FBConnectauthAction extends Action
|
|||||||
{
|
{
|
||||||
if (!Validate::string($str, array('min_length' => 1,
|
if (!Validate::string($str, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => NICKNAME_FMT))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!User::allowed_nickname($str)) {
|
if (!User::allowed_nickname($str)) {
|
||||||
|
@ -82,9 +82,7 @@ class FBConnectPlugin extends Plugin
|
|||||||
|
|
||||||
$action->extraHeaders();
|
$action->extraHeaders();
|
||||||
|
|
||||||
$action->startXML('html',
|
$action->startXML('html');
|
||||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
|
||||||
|
|
||||||
$language = $action->getLanguage();
|
$language = $action->getLanguage();
|
||||||
|
|
||||||
@ -146,11 +144,7 @@ class FBConnectPlugin extends Plugin
|
|||||||
function onEndShowFooter($action)
|
function onEndShowFooter($action)
|
||||||
{
|
{
|
||||||
if ($this->reqFbScripts($action)) {
|
if ($this->reqFbScripts($action)) {
|
||||||
|
$action->script('http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php');
|
||||||
$action->element('script',
|
|
||||||
array('type' => 'text/javascript',
|
|
||||||
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
|
||||||
'');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,10 +152,7 @@ class FBConnectPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
|
|
||||||
if ($this->reqFbScripts($action)) {
|
if ($this->reqFbScripts($action)) {
|
||||||
|
$action->cssLink('plugins/FBConnect/FBConnectPlugin.css');
|
||||||
$action->element('link', array('rel' => 'stylesheet',
|
|
||||||
'type' => 'text/css',
|
|
||||||
'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
62
plugins/InfiniteScroll/InfiniteScrollPlugin.php
Normal file
62
plugins/InfiniteScroll/InfiniteScrollPlugin.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Plugin to enable Infinite Scrolling
|
||||||
|
*
|
||||||
|
* 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 Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
|
||||||
|
* @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 InfiniteScrollPlugin extends Plugin
|
||||||
|
{
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndShowScripts($action)
|
||||||
|
{
|
||||||
|
$action->script('plugins/InfiniteScroll/jquery.infinitescroll.min.js');
|
||||||
|
$loading_image = common_path('plugins/InfiniteScroll/ajax-loader.gif');
|
||||||
|
$js_string = <<<EOT
|
||||||
|
<script type="text/javascript">
|
||||||
|
jQuery(document).ready(function($){
|
||||||
|
$('notices_primary').infinitescroll({
|
||||||
|
nextSelector : "li.nav_next a",
|
||||||
|
loadingImg : "$loading_image",
|
||||||
|
text : "<em>Loading the next set of posts...</em>",
|
||||||
|
donetext : "<em>Congratulations, you\'ve reached the end of the Internet.</em>",
|
||||||
|
navSelector : "div.pagination",
|
||||||
|
contentSelector : "#notices_primary",
|
||||||
|
itemSelector : "ol.notices"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
EOT;
|
||||||
|
$action->raw($js_string);
|
||||||
|
}
|
||||||
|
}
|
BIN
plugins/InfiniteScroll/ajax-loader.gif
Normal file
BIN
plugins/InfiniteScroll/ajax-loader.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
251
plugins/InfiniteScroll/jquery.infinitescroll.js
Normal file
251
plugins/InfiniteScroll/jquery.infinitescroll.js
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
// Infinite Scroll jQuery plugin
|
||||||
|
// copyright Paul Irish, licensed GPL & MIT
|
||||||
|
// version 1.2.090804
|
||||||
|
|
||||||
|
// home and docs: http://www.infinite-scroll.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
// todo: add preloading option.
|
||||||
|
|
||||||
|
;(function($){
|
||||||
|
|
||||||
|
$.fn.infinitescroll = function(options,callback){
|
||||||
|
|
||||||
|
// console log wrapper.
|
||||||
|
function debug(){
|
||||||
|
if (opts.debug) { window.console && console.log.call(console,arguments)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab each selector option and see if any fail.
|
||||||
|
function areSelectorsValid(opts){
|
||||||
|
for (var key in opts){
|
||||||
|
if (key.indexOf && key.indexOf('Selector') && $(opts[key]).length === 0){
|
||||||
|
debug('Your ' + key + ' found no elements.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// find the number to increment in the path.
|
||||||
|
function determinePath(path){
|
||||||
|
|
||||||
|
path.match(relurl) ? path.match(relurl)[2] : path;
|
||||||
|
|
||||||
|
// there is a 2 in the url surrounded by slashes, e.g. /page/2/
|
||||||
|
if ( path.match(/^(.*?)\b2\b(.*?$)/) ){
|
||||||
|
path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
|
||||||
|
} else
|
||||||
|
// if there is any 2 in the url at all.
|
||||||
|
if (path.match(/^(.*?)2(.*?$)/)){
|
||||||
|
debug('Trying backup next selector parse technique. Treacherous waters here, matey.');
|
||||||
|
path = path.match(/^(.*?)2(.*?$)/).slice(1);
|
||||||
|
} else {
|
||||||
|
debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
|
||||||
|
props.isInvalidPage = true; //prevent it from running on this page.
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 'document' means the full document usually, but sometimes the content of the overflow'd div in local mode
|
||||||
|
function getDocumentHeight(){
|
||||||
|
// weird doubletouch of scrollheight because http://soulpass.com/2006/07/24/ie-and-scrollheight/
|
||||||
|
return opts.localMode ? ($(props.container)[0].scrollHeight && $(props.container)[0].scrollHeight)
|
||||||
|
// needs to be document's height. (not props.container's) html's height is wrong in IE.
|
||||||
|
: $(document).height()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function isNearBottom(opts,props){
|
||||||
|
|
||||||
|
// distance remaining in the scroll
|
||||||
|
// computed as: document height - distance already scroll - viewport height - buffer
|
||||||
|
var pixelsFromWindowBottomToBottom = getDocumentHeight() -
|
||||||
|
(opts.localMode ? $(props.container).scrollTop() :
|
||||||
|
// have to do this bs because safari doesnt report a scrollTop on the html element
|
||||||
|
($(props.container).scrollTop() || $(props.container.ownerDocument.body).scrollTop())) -
|
||||||
|
$(opts.localMode ? props.container : window).height();
|
||||||
|
|
||||||
|
debug('math:',pixelsFromWindowBottomToBottom, props.pixelsFromNavToBottom);
|
||||||
|
|
||||||
|
// if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
|
||||||
|
return (pixelsFromWindowBottomToBottom - opts.bufferPx < props.pixelsFromNavToBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDoneMsg(){
|
||||||
|
props.loadingMsg
|
||||||
|
.find('img').hide()
|
||||||
|
.parent()
|
||||||
|
.find('div').html(opts.donetext).animate({opacity: 1},2000).fadeOut('normal');
|
||||||
|
|
||||||
|
// user provided callback when done
|
||||||
|
opts.errorCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function infscrSetup(path,opts,props,callback){
|
||||||
|
|
||||||
|
if (props.isDuringAjax || props.isInvalidPage || props.isDone) return;
|
||||||
|
|
||||||
|
if ( !isNearBottom(opts,props) ) return;
|
||||||
|
|
||||||
|
// we dont want to fire the ajax multiple times
|
||||||
|
props.isDuringAjax = true;
|
||||||
|
|
||||||
|
// show the loading message and hide the previous/next links
|
||||||
|
props.loadingMsg.appendTo( opts.contentSelector ).show();
|
||||||
|
$( opts.navSelector ).hide();
|
||||||
|
|
||||||
|
// increment the URL bit. e.g. /page/3/
|
||||||
|
props.currPage++;
|
||||||
|
|
||||||
|
debug('heading into ajax',path);
|
||||||
|
|
||||||
|
// if we're dealing with a table we can't use DIVs
|
||||||
|
var box = $(opts.contentSelector).is('table') ? $('<tbody/>') : $('<div/>');
|
||||||
|
|
||||||
|
box
|
||||||
|
.attr('id','infscr-page-'+props.currPage)
|
||||||
|
.addClass('infscr-pages')
|
||||||
|
.appendTo( opts.contentSelector )
|
||||||
|
.load( path.join( props.currPage ) + ' ' + opts.itemSelector,null,function(){
|
||||||
|
|
||||||
|
// if we've hit the last page...
|
||||||
|
if (props.isDone){
|
||||||
|
showDoneMsg();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// if it didn't return anything
|
||||||
|
if (box.children().length == 0){
|
||||||
|
// fake an ajaxError so we can quit.
|
||||||
|
$.event.trigger( "ajaxError", [{status:404}] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// fadeout currently makes the <em>'d text ugly in IE6
|
||||||
|
props.loadingMsg.fadeOut('normal' );
|
||||||
|
|
||||||
|
// smooth scroll to ease in the new content
|
||||||
|
if (opts.animate){
|
||||||
|
var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px';
|
||||||
|
$('html,body').animate({scrollTop: scrollTo}, 800,function(){ props.isDuringAjax = false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass in the new DOM element as context for the callback
|
||||||
|
callback.call( box[0] );
|
||||||
|
|
||||||
|
if (!opts.animate) props.isDuringAjax = false; // once the call is done, we can allow it again.
|
||||||
|
}
|
||||||
|
}); // end of load()
|
||||||
|
|
||||||
|
|
||||||
|
} // end of infscrSetup()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// lets get started.
|
||||||
|
|
||||||
|
var opts = $.extend({}, $.infinitescroll.defaults, options);
|
||||||
|
var props = $.infinitescroll; // shorthand
|
||||||
|
callback = callback || function(){};
|
||||||
|
|
||||||
|
if (!areSelectorsValid(opts)){ return false; }
|
||||||
|
|
||||||
|
// we doing this on an overflow:auto div?
|
||||||
|
props.container = opts.localMode ? this : document.documentElement;
|
||||||
|
|
||||||
|
// contentSelector we'll use for our .load()
|
||||||
|
opts.contentSelector = opts.contentSelector || this;
|
||||||
|
|
||||||
|
|
||||||
|
// get the relative URL - everything past the domain name.
|
||||||
|
var relurl = /(.*?\/\/).*?(\/.*)/;
|
||||||
|
var path = $(opts.nextSelector).attr('href');
|
||||||
|
|
||||||
|
|
||||||
|
if (!path) { debug('Navigation selector not found'); return; }
|
||||||
|
|
||||||
|
// set the path to be a relative URL from root.
|
||||||
|
path = determinePath(path);
|
||||||
|
|
||||||
|
|
||||||
|
// reset scrollTop in case of page refresh:
|
||||||
|
if (opts.localMode) $(props.container)[0].scrollTop = 0;
|
||||||
|
|
||||||
|
// distance from nav links to bottom
|
||||||
|
// computed as: height of the document + top offset of container - top offset of nav link
|
||||||
|
props.pixelsFromNavToBottom = getDocumentHeight() +
|
||||||
|
$(props.container).offset().top -
|
||||||
|
$(opts.navSelector).offset().top;
|
||||||
|
|
||||||
|
// define loading msg
|
||||||
|
props.loadingMsg = $('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="'+
|
||||||
|
opts.loadingImg+'" /><div>'+opts.loadingText+'</div></div>');
|
||||||
|
// preload the image
|
||||||
|
(new Image()).src = opts.loadingImg;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// set up our bindings
|
||||||
|
$(document).ajaxError(function(e,xhr,opt){
|
||||||
|
debug('Page not found. Self-destructing...');
|
||||||
|
|
||||||
|
// die if we're out of pages.
|
||||||
|
if (xhr.status == 404){
|
||||||
|
showDoneMsg();
|
||||||
|
props.isDone = true;
|
||||||
|
$(opts.localMode ? this : window).unbind('scroll.infscr');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// bind scroll handler to element (if its a local scroll) or window
|
||||||
|
$(opts.localMode ? this : window)
|
||||||
|
.bind('scroll.infscr', function(){ infscrSetup(path,opts,props,callback); } )
|
||||||
|
.trigger('scroll.infscr'); // trigger the event, in case it's a short page
|
||||||
|
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
} // end of $.fn.infinitescroll()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// options and read-only properties object
|
||||||
|
|
||||||
|
$.infinitescroll = {
|
||||||
|
defaults : {
|
||||||
|
debug : false,
|
||||||
|
preload : false,
|
||||||
|
nextSelector : "div.navigation a:first",
|
||||||
|
loadingImg : "http://www.infinite-scroll.com/loading.gif",
|
||||||
|
loadingText : "<em>Loading the next set of posts...</em>",
|
||||||
|
donetext : "<em>Congratulations, you've reached the end of the internet.</em>",
|
||||||
|
navSelector : "div.navigation",
|
||||||
|
contentSelector : null, // not really a selector. :) it's whatever the method was called on..
|
||||||
|
extraScrollPx : 150,
|
||||||
|
itemSelector : "div.post",
|
||||||
|
animate : false,
|
||||||
|
localMode : false,
|
||||||
|
bufferPx : 40,
|
||||||
|
errorCallback : function(){}
|
||||||
|
},
|
||||||
|
loadingImg : undefined,
|
||||||
|
loadingMsg : undefined,
|
||||||
|
container : undefined,
|
||||||
|
currPage : 1,
|
||||||
|
currDOMChunk : null, // defined in setup()'s load()
|
||||||
|
isDuringAjax : false,
|
||||||
|
isInvalidPage : false,
|
||||||
|
isDone : false // for when it goes all the way through the archive.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
})(jQuery);
|
8
plugins/InfiniteScroll/jquery.infinitescroll.min.js
vendored
Normal file
8
plugins/InfiniteScroll/jquery.infinitescroll.min.js
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
// Infinite Scroll jQuery plugin
|
||||||
|
// copyright Paul Irish, licensed GPL & MIT
|
||||||
|
// version 1.2.090804
|
||||||
|
|
||||||
|
// home and docs: http://www.infinite-scroll.com
|
||||||
|
*/
|
||||||
|
(function(A){A.fn.infinitescroll=function(N,L){function E(){if(B.debug){window.console&&console.log.call(console,arguments)}}function G(P){for(var O in P){if(O.indexOf&&O.indexOf("Selector")&&A(P[O]).length===0){E("Your "+O+" found no elements.");return false}return true}}function K(O){O.match(C)?O.match(C)[2]:O;if(O.match(/^(.*?)\b2\b(.*?$)/)){O=O.match(/^(.*?)\b2\b(.*?$)/).slice(1)}else{if(O.match(/^(.*?)2(.*?$)/)){E("Trying backup next selector parse technique. Treacherous waters here, matey.");O=O.match(/^(.*?)2(.*?$)/).slice(1)}else{E("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.");H.isInvalidPage=true}}return O}function I(){return B.localMode?(A(H.container)[0].scrollHeight&&A(H.container)[0].scrollHeight):A(document).height()}function F(Q,P){var O=I()-(Q.localMode?A(P.container).scrollTop():(A(P.container).scrollTop()||A(P.container.ownerDocument.body).scrollTop()))-A(Q.localMode?P.container:window).height();E("math:",O,P.pixelsFromNavToBottom);return(O-Q.bufferPx<P.pixelsFromNavToBottom)}function J(){H.loadingMsg.find("img").hide().parent().find("div").html(B.donetext).animate({opacity:1},2000).fadeOut("normal");B.errorCallback()}function D(R,Q,O,S){if(O.isDuringAjax||O.isInvalidPage||O.isDone){return }if(!F(Q,O)){return }O.isDuringAjax=true;O.loadingMsg.appendTo(Q.contentSelector).show();A(Q.navSelector).hide();O.currPage++;E("heading into ajax",R);var P=A(Q.contentSelector).is("table")?A("<tbody/>"):A("<div/>");P.attr("id","infscr-page-"+O.currPage).addClass("infscr-pages").appendTo(Q.contentSelector).load(R.join(O.currPage)+" "+Q.itemSelector,null,function(){if(O.isDone){J();return false}else{if(P.children().length==0){A.event.trigger("ajaxError",[{status:404}])}O.loadingMsg.fadeOut("normal");if(Q.animate){var T=A(window).scrollTop()+A("#infscr-loading").height()+Q.extraScrollPx+"px";A("html,body").animate({scrollTop:T},800,function(){O.isDuringAjax=false})}S.call(P[0]);if(!Q.animate){O.isDuringAjax=false}}})}var B=A.extend({},A.infinitescroll.defaults,N);var H=A.infinitescroll;L=L||function(){};if(!G(B)){return false}H.container=B.localMode?this:document.documentElement;B.contentSelector=B.contentSelector||this;var C=/(.*?\/\/).*?(\/.*)/;var M=A(B.nextSelector).attr("href");if(!M){E("Navigation selector not found");return }M=K(M);if(B.localMode){A(H.container)[0].scrollTop=0}H.pixelsFromNavToBottom=I()+A(H.container).offset().top-A(B.navSelector).offset().top;H.loadingMsg=A('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="'+B.loadingImg+'" /><div>'+B.loadingText+"</div></div>");(new Image()).src=B.loadingImg;A(document).ajaxError(function(P,Q,O){E("Page not found. Self-destructing...");if(Q.status==404){J();H.isDone=true;A(B.localMode?this:window).unbind("scroll.infscr")}});A(B.localMode?this:window).bind("scroll.infscr",function(){D(M,B,H,L)}).trigger("scroll.infscr");return this};A.infinitescroll={defaults:{debug:false,preload:false,nextSelector:"div.navigation a:first",loadingImg:"http://www.infinite-scroll.com/loading.gif",loadingText:"<em>Loading the next set of posts...</em>",donetext:"<em>Congratulations, you've reached the end of the internet.</em>",navSelector:"div.navigation",contentSelector:null,extraScrollPx:150,itemSelector:"div.post",animate:false,localMode:false,bufferPx:40,errorCallback:function(){}},loadingImg:undefined,loadingMsg:undefined,container:undefined,currPage:1,currDOMChunk:null,isDuringAjax:false,isInvalidPage:false,isDone:false}})(jQuery);
|
6
plugins/InfiniteScroll/readme.txt
Normal file
6
plugins/InfiniteScroll/readme.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Infinite Scroll adds the following functionality to your Laconica installation: When a user scrolls towards the bottom of the page, the next page of notices is automatically retrieved and appended. This means they never need to click "Next Page", which dramatically increases stickiness.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
Add "addPlugin('InfiniteScroll');" to the bottom of your config.php
|
||||||
|
That's it!
|
@ -84,9 +84,7 @@ class RealtimePlugin extends Plugin
|
|||||||
$scripts = $this->_getScripts();
|
$scripts = $this->_getScripts();
|
||||||
|
|
||||||
foreach ($scripts as $script) {
|
foreach ($scripts as $script) {
|
||||||
$action->element('script', array('type' => 'text/javascript',
|
$action->script($script);
|
||||||
'src' => $script),
|
|
||||||
' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
@ -201,8 +199,8 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
function _getScripts()
|
function _getScripts()
|
||||||
{
|
{
|
||||||
return array(common_path('plugins/Realtime/realtimeupdate.js'),
|
return array('plugins/Realtime/realtimeupdate.js',
|
||||||
common_path('plugins/Realtime/json2.js'));
|
'plugins/Realtime/json2.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
function _updateInitialize($timeline, $user_id)
|
function _updateInitialize($timeline, $user_id)
|
||||||
|
@ -65,9 +65,7 @@ class recaptcha extends Plugin
|
|||||||
|
|
||||||
$action->extraHeaders();
|
$action->extraHeaders();
|
||||||
|
|
||||||
$action->startXML('html',
|
$action->startXML('html');
|
||||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
|
||||||
|
|
||||||
$action->raw('<style type="text/css">#recaptcha_area{float:left;}</style>');
|
$action->raw('<style type="text/css">#recaptcha_area{float:left;}</style>');
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html>
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title><?php echo section('title'); ?></title>
|
<title><?php echo section('title'); ?></title>
|
||||||
@ -44,4 +42,4 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user