Merge branch 'branch_2.3' of ssh://shish@marigold.shishnet.org/home/shish/git/shimmie2 into branch_2.3
This commit is contained in:
commit
88c7233ced
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class DowntimeTest extends ShimmieWebTestCase {
|
||||
class DowntimeTest extends SCoreWebTestCase {
|
||||
function testDowntime() {
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("setup");
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
class DowntimeTheme Extends Themelet {
|
||||
/*
|
||||
/**
|
||||
* Show the admin that downtime mode is enabled
|
||||
*/
|
||||
public function display_notification(Page $page) {
|
||||
@ -9,7 +9,7 @@ class DowntimeTheme Extends Themelet {
|
||||
"<span style='font-size: 1.5em'><b>DOWNTIME MODE IS ON!</b></span>", "left", 0));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Display $message and exit
|
||||
*/
|
||||
public function display_message($message) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class IPBanTest extends ShimmieWebTestCase {
|
||||
class IPBanTest extends SCoreWebTestCase {
|
||||
function testIPBan() {
|
||||
$this->get_page('ip_ban/list');
|
||||
$this->assertResponse(403);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class NewsTest extends ShimmieWebTestCase {
|
||||
class NewsTest extends SCoreWebTestCase {
|
||||
function testNews() {
|
||||
$this->log_in_as_admin();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class PMTest extends ShimmieWebTestCase {
|
||||
class PMTest extends SCoreWebTestCase {
|
||||
function testPM() {
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("user/test");
|
||||
|
@ -19,14 +19,10 @@
|
||||
* <code>/random_image/download/size:1024x768+cute</code>
|
||||
*/
|
||||
|
||||
class RandomImage implements Extension {
|
||||
var $theme;
|
||||
|
||||
public function receive_event(Event $event) {
|
||||
class RandomImage extends SimpleExtension {
|
||||
public function onPageRequest($event) {
|
||||
global $config, $database, $page, $user;
|
||||
if(is_null($this->theme)) $this->theme = get_theme_object($this);
|
||||
|
||||
if(($event instanceof PageRequestEvent) && $event->page_matches("random_image")) {
|
||||
if($event->page_matches("random_image")) {
|
||||
if($event->count_args() == 1) {
|
||||
$action = $event->get_arg(0);
|
||||
$search_terms = array();
|
||||
@ -50,14 +46,16 @@ class RandomImage implements Extension {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(($event instanceof SetupBuildingEvent)) {
|
||||
public function onSetupBuilding($event) {
|
||||
$sb = new SetupBlock("Random Image");
|
||||
$sb->add_bool_option("show_random_block", "Show Random Block: ");
|
||||
$event->panel->add_block($sb);
|
||||
}
|
||||
|
||||
if($event instanceof PostListBuildingEvent) {
|
||||
public function onPostListBuilding($event) {
|
||||
global $config, $page;
|
||||
if($config->get_bool("show_random_block")) {
|
||||
$image = Image::by_random($event->search_terms);
|
||||
if(!is_null($image)) {
|
||||
@ -65,7 +63,5 @@ class RandomImage implements Extension {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
add_event_listener(new RandomImage());
|
||||
?>
|
||||
|
@ -6,6 +6,19 @@
|
||||
* Description: adds unit testing to SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page unittests Unit Tests
|
||||
*
|
||||
* Each extension should (although doesn't technically have to) come with a
|
||||
* test.php file, for example ext/index/test.php. The SimpleSCoreTest
|
||||
* extension will look for these files and load any SCoreWebTestCase classes
|
||||
* it finds inside them, then run them and report whether or not the test
|
||||
* passes.
|
||||
*
|
||||
* For Shimmie2 specific extensions, there is a ShimmieWebTestCase class which
|
||||
* includes functions to upload and delete images.
|
||||
*/
|
||||
|
||||
require_once('simpletest/web_tester.php');
|
||||
require_once('simpletest/unit_tester.php');
|
||||
require_once('simpletest/reporter.php');
|
||||
@ -15,6 +28,9 @@ define('USER_PASS', "test");
|
||||
define('ADMIN_NAME', "demo");
|
||||
define('ADMIN_PASS', "demo");
|
||||
|
||||
/**
|
||||
* A set of common SCore activities to test
|
||||
*/
|
||||
class SCoreWebTestCase extends WebTestCase {
|
||||
protected function get_page($page) {
|
||||
$url = "http://".$_SERVER["HTTP_HOST"].get_base_href().'/'.make_link($page);
|
||||
@ -49,6 +65,9 @@ class SCoreWebTestCase extends WebTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of common Shimmie activities to test
|
||||
*/
|
||||
class ShimmieWebTestCase extends SCoreWebTestCase {
|
||||
protected function post_image($filename, $tags) {
|
||||
$image_id = -1;
|
||||
@ -81,6 +100,7 @@ class ShimmieWebTestCase extends SCoreWebTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
class TestFinder extends TestSuite {
|
||||
function TestFinder($hint) {
|
||||
if(strpos($hint, "..") !== FALSE) return;
|
||||
|
@ -2,6 +2,7 @@
|
||||
class SimpleSCoreTestTheme extends Themelet {
|
||||
}
|
||||
|
||||
/** @private */
|
||||
class SCoreReporter extends HtmlReporter {
|
||||
var $current_html = "";
|
||||
var $clear_modules = array();
|
||||
|
@ -8,22 +8,19 @@
|
||||
* This extension sets the "description" meta tag in the header
|
||||
* of pages so that search engines can pick it up
|
||||
*/
|
||||
class SiteDescription implements Extension {
|
||||
public function receive_event(Event $event) {
|
||||
global $config, $database, $page, $user;
|
||||
if($event instanceof PageRequestEvent) {
|
||||
class SiteDescription extends SimpleExtension {
|
||||
public function onPageRequest(PageRequestEvent $event) {
|
||||
global $config, $page;
|
||||
if(strlen($config->get_string("site_description")) > 0) {
|
||||
$description = $config->get_string("site_description");
|
||||
$page->add_header("<meta name=\"description\" content=\"$description\">");
|
||||
}
|
||||
}
|
||||
|
||||
if($event instanceof SetupBuildingEvent) {
|
||||
public function onSetupBuilding(SetupBuildingEvent $event) {
|
||||
$sb = new SetupBlock("Site Description");
|
||||
$sb->add_longtext_option("site_description");
|
||||
$event->panel->add_block($sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
add_event_listener(new SiteDescription());
|
||||
?>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class SiteDescriptionTest extends ShimmieWebTestCase {
|
||||
class SiteDescriptionTest extends SCoreWebTestCase {
|
||||
function testSiteDescription() {
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page('setup');
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class WikiTest extends ShimmieWebTestCase {
|
||||
class WikiTest extends SCoreWebTestCase {
|
||||
function testWiki() {
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("wiki");
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class WikiTheme {
|
||||
class WikiTheme extends Themelet {
|
||||
/*
|
||||
* Show a page
|
||||
*
|
||||
|
43
core/README
43
core/README
@ -1,43 +0,0 @@
|
||||
|
||||
The Highest Level
|
||||
~~~~~~~~~~~~~~~~~
|
||||
index.php takes care of loading the globals:
|
||||
|
||||
$config -- some variety of Config class
|
||||
$database -- a class used to get raw SQL access
|
||||
$page -- a GenericPage object, a data structure which holds all the page parts
|
||||
$user -- the currently logged in User
|
||||
|
||||
then it sends an InitExtEvent and PageRequestEvent, these can each trigger
|
||||
more events of their own.
|
||||
|
||||
Once the chain of events comes to an end, the $page object is passed
|
||||
to the theme's layout.class.php to be turned into HTML
|
||||
|
||||
|
||||
Events and Extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
An event is a little blob of data saying "something happened", possibly
|
||||
"something happened, here's the specific data". Events are sent with the
|
||||
send_event() function.
|
||||
|
||||
An extension is something which is capable of reacting to events. They
|
||||
register themselves using the add_event_listener() command. (Although for
|
||||
subclasses of SimpleExtension, registration is handled automatically).
|
||||
|
||||
|
||||
Themes
|
||||
~~~~~~
|
||||
Each extension has a theme with a specific name -- the extension Cake which
|
||||
is stored in ext/cake/main.php will have a theme called CakeTheme stored in
|
||||
ext/cake/theme.php. If you want to customise it, create a class in the file
|
||||
themes/mytheme/cake.theme.php called CustomCakeTheme which extends CakeTheme
|
||||
and overrides some of its methods.
|
||||
|
||||
Generally an extension should only deal with processing data; whenever it
|
||||
wants to display something, it should pass the $page data structure along
|
||||
with the data to be displayed to the theme object, and the theme will add
|
||||
the data into the page.
|
||||
|
||||
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* A basic chunk of a page
|
||||
*/
|
||||
@ -10,20 +6,20 @@ class Block {
|
||||
/**
|
||||
* The block's title
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
var $header;
|
||||
/**
|
||||
* The content
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
var $body;
|
||||
/**
|
||||
* Where the block should be placed. The default theme supports
|
||||
* "main" and "left", other themes can add their own areas
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
var $section;
|
||||
/**
|
||||
@ -31,7 +27,7 @@ class Block {
|
||||
* numbers appear lower. The scale is 0-100 by convention,
|
||||
* though any number or string will work.
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
var $position;
|
||||
|
||||
|
@ -3,17 +3,13 @@
|
||||
* Functions which are only in some versions of PHP,
|
||||
* or only implemented on some platforms
|
||||
*
|
||||
* @ignore
|
||||
* @package SCore
|
||||
* \privatesection
|
||||
*/
|
||||
|
||||
# (PHP 5 >= 5.2.1)
|
||||
# Based on http://www.phpit.net/
|
||||
# article/creating-zip-tar-archives-dynamically-php/2/
|
||||
if(!function_exists('sys_get_temp_dir')) {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function sys_get_temp_dir() {
|
||||
// Try to get from environment variable
|
||||
if(!empty($_ENV['TMP'])) {
|
||||
@ -46,9 +42,6 @@ function sys_get_temp_dir() {
|
||||
# (PHP >= 5.1)
|
||||
# from http://www.php.net/inet_pton
|
||||
if(!function_exists('inet_pton')) {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function inet_pton($ip) {
|
||||
# ipv4
|
||||
if(strpos($ip, '.') !== FALSE) {
|
||||
@ -70,9 +63,6 @@ function inet_pton($ip) {
|
||||
# (PHP >= 5.1)
|
||||
# from http://www.php.net/inet_ntop
|
||||
if(!function_exists('inet_ntop')) {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function inet_ntop($ip) {
|
||||
if (strlen($ip)==4) {
|
||||
// ipv4
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* an abstract interface for altering a name:value pair list
|
||||
*/
|
||||
@ -29,8 +25,6 @@ interface Config {
|
||||
/**
|
||||
* Common methods for manipulating the list, loading and saving is
|
||||
* left to the concrete implementation
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
abstract class BaseConfig implements Config {
|
||||
var $values = array();
|
||||
@ -106,8 +100,6 @@ abstract class BaseConfig implements Config {
|
||||
* $config['foo'] = "bar";
|
||||
* $config['baz'] = "qux";
|
||||
* ?>
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
class StaticConfig extends BaseConfig {
|
||||
public function __construct($filename) {
|
||||
@ -135,12 +127,12 @@ class StaticConfig extends BaseConfig {
|
||||
* Loads the config list from a table in a given database, the table should
|
||||
* be called config and have the schema:
|
||||
*
|
||||
* \code
|
||||
* CREATE TABLE config(
|
||||
* name VARCHAR(255) NOT NULL,
|
||||
* value TEXT
|
||||
* );
|
||||
*
|
||||
* @ignore
|
||||
* \endcode
|
||||
*/
|
||||
class DatabaseConfig extends BaseConfig {
|
||||
var $database = null;
|
||||
|
@ -1,16 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
require_once "compat.inc.php";
|
||||
$ADODB_CACHE_DIR=sys_get_temp_dir();
|
||||
require_once "lib/adodb/adodb.inc.php";
|
||||
require_once "lib/adodb/adodb-exceptions.inc.php";
|
||||
|
||||
/**#@+
|
||||
* @ignore
|
||||
*/
|
||||
/** @privatesection */
|
||||
// Querylet {{{
|
||||
class Querylet {
|
||||
var $sql;
|
||||
@ -202,7 +196,7 @@ class MemCache implements CacheEngine {
|
||||
public function get_misses() {return $this->misses;}
|
||||
}
|
||||
// }}}
|
||||
/**#@-*/
|
||||
/** @publicsection */
|
||||
|
||||
/**
|
||||
* A class for controlled database access
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic parent class for all events.
|
||||
*
|
||||
@ -14,7 +10,9 @@ abstract class Event {
|
||||
|
||||
|
||||
/**
|
||||
* A wake-up call for extensions
|
||||
* A wake-up call for extensions. Upon recieving an InitExtEvent an extension
|
||||
* should check that it's database tables are there and install them if not,
|
||||
* and set any defaults with Config::set_default_int() and such.
|
||||
*/
|
||||
class InitExtEvent extends Event {}
|
||||
|
||||
@ -111,28 +109,28 @@ class LogEvent extends Event {
|
||||
/**
|
||||
* a category, normally the extension name
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
var $section;
|
||||
|
||||
/**
|
||||
* See python...
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
var $priority = 0;
|
||||
|
||||
/**
|
||||
* Free text to be logged
|
||||
*
|
||||
* @var text
|
||||
* @retval text
|
||||
*/
|
||||
var $message;
|
||||
|
||||
/**
|
||||
* The time that the event was created
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
var $time;
|
||||
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* A base exception to be caught by the upper levels
|
||||
*/
|
||||
|
@ -1,6 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
* \page eande Events and Extensions
|
||||
*
|
||||
* An event is a little blob of data saying "something happened", possibly
|
||||
* "something happened, here's the specific data". Events are sent with the
|
||||
* send_event() function. Since events can store data, they can be used to
|
||||
* return data to the extension which sent them, for example:
|
||||
*
|
||||
* \code
|
||||
* $tfe = new TextFormattingEvent($original_text);
|
||||
* send_event($tfe);
|
||||
* $formatted_text = $tfe->formatted;
|
||||
* \endcode
|
||||
*
|
||||
* An extension is something which is capable of reacting to events. They
|
||||
* register themselves using the add_event_listener() function, after which
|
||||
* events will be sent to the object's recieve_event() function.
|
||||
*
|
||||
* SimpleExtension subclasses are slightly different -- they are registered
|
||||
* automatically, and events are sent to a named method, eg PageRequestEvent
|
||||
* will be sent to onPageRequest()
|
||||
*
|
||||
*
|
||||
* \page hello The Hello World Extension
|
||||
*
|
||||
* \code
|
||||
* // ext/hello/main.php
|
||||
* public class Hello extends SimpleExtension {
|
||||
* public void onPageRequest(PageRequestEvent $event) {
|
||||
* global $page, $user;
|
||||
* $this->theme->display_hello($page, $user);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // ext/hello/theme.php
|
||||
* public class HelloTheme extends Themelet {
|
||||
* public void display_hello(Page $page, User $user) {
|
||||
* $page->add_block(new Block("Hello!", "Hello there ".html_escape($user->name));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // ext/hello/test.php
|
||||
* public class HelloTest extends ShimmieWebTestCase {
|
||||
* public void testHello() {
|
||||
* $this->get_page("post/list");
|
||||
* $this->assertText("Hello there");
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // themes/mytheme/hello.theme.php
|
||||
* public class CustomHelloTheme extends HelloTheme {
|
||||
* public function display_hello(Page $page, User $user) {
|
||||
* $h_user = html_escape($user->name);
|
||||
* $page->add_block(new Block(
|
||||
* "Hello!",
|
||||
* "Hello there $h_user, look at my snazzy custom theme!"
|
||||
* );
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -19,7 +78,7 @@ interface Extension {
|
||||
* priority, so no need for register_extension(new Foo())
|
||||
*
|
||||
* Hopefully this removes as much copy & paste code from the extension
|
||||
* files as possible \o/
|
||||
* files as possible~
|
||||
*
|
||||
* The original concept came from Artanis's SimpleExtension extension
|
||||
* --> http://github.com/Artanis/simple-extension/tree/master
|
||||
|
@ -2,8 +2,21 @@
|
||||
/**
|
||||
* All the imageboard-specific bits of code should be in this file, everything
|
||||
* else in /core should be standard SCore bits.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page search Shimmie2: Searching
|
||||
*
|
||||
* @package SCore
|
||||
* The current search system is built of several search item -> image ID list
|
||||
* translators, eg:
|
||||
*
|
||||
* \li the item "fred" will search the image_tags table to find image IDs with the fred tag
|
||||
* \li the item "size=640x480" will search the images table to find image IDs of 640x480 images
|
||||
*
|
||||
* So the search "fred size=640x480" will calculate two lists and take the
|
||||
* intersection. (There are some optimisations in there making it more
|
||||
* complicated behind the scenes, but as long as you can turn a single word
|
||||
* into a list of image IDs, making a search plugin should be simple)
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||||
@ -42,7 +55,7 @@ class Image {
|
||||
/**
|
||||
* Find an image by ID
|
||||
*
|
||||
* @var Image
|
||||
* @retval Image
|
||||
*/
|
||||
public static function by_id($id) {
|
||||
assert(is_numeric($id));
|
||||
@ -55,7 +68,7 @@ class Image {
|
||||
/**
|
||||
* Find an image by hash
|
||||
*
|
||||
* @var Image
|
||||
* @retval Image
|
||||
*/
|
||||
public static function by_hash($hash) {
|
||||
assert(is_string($hash));
|
||||
@ -68,7 +81,7 @@ class Image {
|
||||
/**
|
||||
* Pick a random image out of a set
|
||||
*
|
||||
* @var Image
|
||||
* @retval Image
|
||||
*/
|
||||
public static function by_random($tags=array()) {
|
||||
assert(is_array($tags));
|
||||
@ -145,7 +158,7 @@ class Image {
|
||||
* Rather than simply $this_id + 1, one must take into account
|
||||
* deleted images and search queries
|
||||
*
|
||||
* @var Image
|
||||
* @retval Image
|
||||
*/
|
||||
public function get_next($tags=array(), $next=true) {
|
||||
assert(is_array($tags));
|
||||
@ -177,7 +190,7 @@ class Image {
|
||||
/**
|
||||
* The reverse of get_next
|
||||
*
|
||||
* @var Image
|
||||
* @retval Image
|
||||
*/
|
||||
public function get_prev($tags=array()) {
|
||||
return $this->get_next($tags, false);
|
||||
@ -186,7 +199,7 @@ class Image {
|
||||
/**
|
||||
* Find the User who owns this Image
|
||||
*
|
||||
* @var User
|
||||
* @retval User
|
||||
*/
|
||||
public function get_owner() {
|
||||
return User::by_id($this->owner_id);
|
||||
@ -223,7 +236,7 @@ class Image {
|
||||
/**
|
||||
* Get the URL for the full size image
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_image_link() {
|
||||
global $config;
|
||||
@ -242,7 +255,7 @@ class Image {
|
||||
* Get a short link to the full size image
|
||||
*
|
||||
* @deprecated
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_short_link() {
|
||||
global $config;
|
||||
@ -252,7 +265,7 @@ class Image {
|
||||
/**
|
||||
* Get the URL for the thumbnail
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_thumb_link() {
|
||||
global $config;
|
||||
@ -271,7 +284,7 @@ class Image {
|
||||
* Get the tooltip for this image, formatted according to the
|
||||
* configured template
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_tooltip() {
|
||||
global $config;
|
||||
@ -281,7 +294,7 @@ class Image {
|
||||
/**
|
||||
* Figure out where the full size image is on disk
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_image_filename() {
|
||||
$hash = $this->hash;
|
||||
@ -293,7 +306,7 @@ class Image {
|
||||
/**
|
||||
* Figure out where the thumbnail is on disk
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_thumb_filename() {
|
||||
$hash = $this->hash;
|
||||
@ -304,7 +317,7 @@ class Image {
|
||||
/**
|
||||
* Get the original filename
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_filename() {
|
||||
return $this->filename;
|
||||
@ -315,7 +328,7 @@ class Image {
|
||||
*
|
||||
* FIXME: now we handle more than just images
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_mime_type() {
|
||||
return "image/".($this->ext);
|
||||
@ -324,7 +337,7 @@ class Image {
|
||||
/**
|
||||
* Get the image's filename extension
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_ext() {
|
||||
return $this->ext;
|
||||
@ -333,7 +346,7 @@ class Image {
|
||||
/**
|
||||
* Get the image's source URL
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function get_source() {
|
||||
return $this->source;
|
||||
@ -418,9 +431,9 @@ class Image {
|
||||
}
|
||||
|
||||
/**
|
||||
* ...?
|
||||
* Someone please explain this
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
public function parse_link_template($tmpl, $_escape="url_escape") {
|
||||
global $config;
|
||||
|
@ -1,15 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
* \page themes Themes
|
||||
*
|
||||
* Each extension has a theme with a specific name -- eg. the extension Setup
|
||||
* which is stored in ext/setup/main.php will have a theme called SetupTheme
|
||||
* stored in ext/setup/theme.php. If you want to customise it, create a class
|
||||
* in the file themes/mytheme/setup.theme.php called CustomSetupTheme which
|
||||
* extends SetupTheme and overrides some of its methods.
|
||||
*
|
||||
* Generally an extension should only deal with processing data; whenever it
|
||||
* wants to display something, it should pass the $page data structure along
|
||||
* with the data to be displayed to the theme object, and the theme will add
|
||||
* the data into the page.
|
||||
*
|
||||
* A page should make sure that all the data it outputs is free from dangerous
|
||||
* data by using html_escape(), url_escape(), or int_escape() as appropriate.
|
||||
*
|
||||
* Because some HTML can be placed anywhere according to the theme, coming up
|
||||
* with the correct way to link to a page can be hard -- thus we have the
|
||||
* make_link() function, which will take a path like "post/list" and turn it
|
||||
* into a full and correct link, eg /myboard/post/list, /foo/index.php?q=post/list,
|
||||
* etc depending on how things are set up. This should always be used to link
|
||||
* to pages rather than hardcoding a path.
|
||||
*
|
||||
* Various other common functions are available as part of the Themelet class.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A data structure for holding all the bits of data that make up a page.
|
||||
*
|
||||
* The various extensions all add whatever they want to this structure,
|
||||
* then layout.class.php turns it into HTML
|
||||
* then Layout turns it into HTML
|
||||
*/
|
||||
class GenericPage {
|
||||
class Page {
|
||||
var $mode = "page";
|
||||
var $type = "text/html";
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
/** @private */
|
||||
function _new_user($row) {
|
||||
return new User($row);
|
||||
}
|
||||
@ -94,7 +88,7 @@ class User {
|
||||
/**
|
||||
* Test if this user is anonymous (not logged in)
|
||||
*
|
||||
* @var bool
|
||||
* @retval bool
|
||||
*/
|
||||
public function is_anonymous() {
|
||||
global $config;
|
||||
@ -104,7 +98,7 @@ class User {
|
||||
/**
|
||||
* Test if this user is an administrator
|
||||
*
|
||||
* @var bool
|
||||
* @retval bool
|
||||
*/
|
||||
public function is_admin() {
|
||||
return $this->admin;
|
||||
|
@ -1,9 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @package SCore
|
||||
*/
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||||
* Input / Output Sanitising *
|
||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
@ -11,7 +6,7 @@
|
||||
/**
|
||||
* Make some data safe for printing into HTML
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function html_escape($input) {
|
||||
return htmlentities($input, ENT_QUOTES, "UTF-8");
|
||||
@ -20,7 +15,7 @@ function html_escape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in integer context
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
function int_escape($input) {
|
||||
return (int)$input;
|
||||
@ -29,7 +24,7 @@ function int_escape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in URL context
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function url_escape($input) {
|
||||
$input = str_replace('^', '^^', $input);
|
||||
@ -41,7 +36,7 @@ function url_escape($input) {
|
||||
/**
|
||||
* Make sure some data is safe to be used in SQL context
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function sql_escape($input) {
|
||||
global $database;
|
||||
@ -51,7 +46,7 @@ function sql_escape($input) {
|
||||
/**
|
||||
* Turn a human readable filesize into an integer, eg 1KB -> 1024
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
function parse_shorthand_int($limit) {
|
||||
if(is_numeric($limit)) {
|
||||
@ -77,7 +72,7 @@ function parse_shorthand_int($limit) {
|
||||
/**
|
||||
* Turn an integer into a human readable filesize, eg 1024 -> 1KB
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function to_shorthand_int($int) {
|
||||
if($int >= pow(1024, 3)) {
|
||||
@ -103,7 +98,7 @@ function to_shorthand_int($int) {
|
||||
* Figure out the correct way to link to a page, taking into account
|
||||
* things like the nice URLs setting
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function make_link($page=null, $query=null) {
|
||||
global $config;
|
||||
@ -132,6 +127,10 @@ function make_link($page=null, $query=null) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a link to a static file in the current theme's
|
||||
* directory
|
||||
*/
|
||||
function theme_file($filepath) {
|
||||
global $config;
|
||||
$theme = $config->get_string("theme","default");
|
||||
@ -144,21 +143,21 @@ function theme_file($filepath) {
|
||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
function version_check() {
|
||||
function _version_check() {
|
||||
if(version_compare(PHP_VERSION, "5.0.0") == -1) {
|
||||
print <<<EOD
|
||||
print "
|
||||
Currently SCore Engine doesn't support versions of PHP lower than 5.0.0 --
|
||||
PHP4 and earlier are officially dead according to their creators,
|
||||
please tell your host to upgrade.
|
||||
EOD;
|
||||
";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
function check_cli() {
|
||||
if(isset($_SERVER['REMOTE_ADDR'])) {
|
||||
@ -171,7 +170,7 @@ function check_cli() {
|
||||
/**
|
||||
* $db is the connection object
|
||||
*
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
function _count_execs($db, $sql, $inputarray) {
|
||||
global $_execs;
|
||||
@ -213,9 +212,9 @@ function get_theme_object(Extension $class, $fatal=true) {
|
||||
/**
|
||||
* Compare two Block objects, used to sort them before being displayed
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
function blockcmp($a, $b) {
|
||||
function blockcmp(Block $a, Block $b) {
|
||||
if($a->position == $b->position) {
|
||||
return 0;
|
||||
}
|
||||
@ -227,7 +226,7 @@ function blockcmp($a, $b) {
|
||||
/**
|
||||
* Figure out PHP's internal memory limit
|
||||
*
|
||||
* @var int
|
||||
* @retval int
|
||||
*/
|
||||
function get_memory_limit() {
|
||||
global $config;
|
||||
@ -257,7 +256,7 @@ function get_memory_limit() {
|
||||
* Get the currently active IP, masked to make it not change when the last
|
||||
* octet or two change, for use in session cookies and such
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function get_session_ip($config) {
|
||||
$mask = $config->get_string("session_hash_mask", "255.255.0.0");
|
||||
@ -271,7 +270,7 @@ function get_session_ip($config) {
|
||||
*
|
||||
* PHP really, really sucks.
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function get_base_href() {
|
||||
$possible_vars = array('SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO');
|
||||
@ -292,7 +291,7 @@ function get_base_href() {
|
||||
* A shorthand way to send a TextFormattingEvent and get the
|
||||
* results
|
||||
*
|
||||
* @var string
|
||||
* @retval string
|
||||
*/
|
||||
function format_text($string) {
|
||||
$tfe = new TextFormattingEvent($string);
|
||||
@ -312,10 +311,16 @@ if(!defined("LOG_INFO")) define("LOG_INFO", 20);
|
||||
if(!defined("LOG_DEBUG")) define("LOG_DEBUG", 10);
|
||||
if(!defined("LOG_NOTSET")) define("LOG_NOTSET", 0);
|
||||
|
||||
/**
|
||||
* A shorthand way to send a LogEvent
|
||||
*/
|
||||
function log_msg($section, $priority, $message) {
|
||||
send_event(new LogEvent($section, $priority, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
* A shorthand way to send a LogEvent
|
||||
*/
|
||||
function log_info($section, $message) {
|
||||
log_msg($section, LOG_INFO, $message);
|
||||
}
|
||||
@ -328,7 +333,7 @@ function log_info($section, $message) {
|
||||
/**
|
||||
* Remove an item from an array
|
||||
*
|
||||
* @var array
|
||||
* @retval array
|
||||
*/
|
||||
function array_remove($array, $to_remove) {
|
||||
$array = array_unique($array);
|
||||
@ -344,7 +349,7 @@ function array_remove($array, $to_remove) {
|
||||
/**
|
||||
* Add an item to an array
|
||||
*
|
||||
* @var array
|
||||
* @retval array
|
||||
*/
|
||||
function array_add($array, $element) {
|
||||
$array[] = $element;
|
||||
@ -355,7 +360,7 @@ function array_add($array, $element) {
|
||||
/**
|
||||
* Return the unique elements of an array, case insensitively
|
||||
*
|
||||
* @var array
|
||||
* @retval array
|
||||
*/
|
||||
function array_iunique($array) {
|
||||
$ok = array();
|
||||
@ -378,7 +383,7 @@ function array_iunique($array) {
|
||||
*
|
||||
* from http://uk.php.net/network
|
||||
*
|
||||
* @var bool
|
||||
* @retval bool
|
||||
*/
|
||||
function ip_in_range($IP, $CIDR) {
|
||||
list ($net, $mask) = split ("/", $CIDR);
|
||||
@ -446,33 +451,7 @@ function full_copy($source, $target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function stripslashes_r($arr) {
|
||||
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function sanitise_environment() {
|
||||
if(DEBUG) {
|
||||
error_reporting(E_ALL);
|
||||
assert_options(ASSERT_ACTIVE, 1);
|
||||
assert_options(ASSERT_BAIL, 1);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
if(get_magic_quotes_gpc()) {
|
||||
$_GET = stripslashes_r($_GET);
|
||||
$_POST = stripslashes_r($_POST);
|
||||
$_COOKIE = stripslashes_r($_COOKIE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
function weighted_random($weights) {
|
||||
$total = 0;
|
||||
@ -493,9 +472,7 @@ function weighted_random($weights) {
|
||||
* Event API *
|
||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
/** @private */
|
||||
$_event_listeners = array();
|
||||
|
||||
/**
|
||||
@ -509,9 +486,7 @@ function add_event_listener(Extension $extension, $pos=50) {
|
||||
$_event_listeners[$pos] = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
/** @private */
|
||||
$_event_count = 0;
|
||||
|
||||
/**
|
||||
@ -605,13 +580,33 @@ function print_GET() {
|
||||
* Request initialisation stuff *
|
||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/** @privatesection */
|
||||
|
||||
function _stripslashes_r($arr) {
|
||||
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
|
||||
}
|
||||
|
||||
function _sanitise_environment() {
|
||||
if(DEBUG) {
|
||||
error_reporting(E_ALL);
|
||||
assert_options(ASSERT_ACTIVE, 1);
|
||||
assert_options(ASSERT_BAIL, 1);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
if(get_magic_quotes_gpc()) {
|
||||
$_GET = _stripslashes_r($_GET);
|
||||
$_POST = _stripslashes_r($_POST);
|
||||
$_COOKIE = _stripslashes_r($_COOKIE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn ^^ into ^ and ^s into /
|
||||
*
|
||||
* Necessary because various servers and various clients
|
||||
* think that / is special...
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
function _decaret($str) {
|
||||
$out = "";
|
||||
@ -628,9 +623,6 @@ function _decaret($str) {
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function _get_query_parts() {
|
||||
if(isset($_GET["q"])) {
|
||||
$path = $_GET["q"];
|
||||
@ -660,9 +652,6 @@ function _get_query_parts() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function _get_page_request() {
|
||||
global $config;
|
||||
$args = _get_query_parts();
|
||||
@ -674,9 +663,6 @@ function _get_page_request() {
|
||||
return new PageRequestEvent($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function _get_user() {
|
||||
global $config, $database;
|
||||
$user = null;
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
/* AdminBuildingEvent {{{
|
||||
*
|
||||
/**
|
||||
* Sent when the admin page is ready to be added to
|
||||
*/
|
||||
class AdminBuildingEvent extends Event {
|
||||
@ -9,7 +8,6 @@ class AdminBuildingEvent extends Event {
|
||||
$this->page = $page;
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
class AdminPage implements Extension {
|
||||
var $theme;
|
||||
|
@ -7,7 +7,8 @@
|
||||
* Description: A thing for point & click extension management
|
||||
*/
|
||||
|
||||
class ExtensionInfo { // {{{
|
||||
/** @private */
|
||||
class ExtensionInfo {
|
||||
var $ext_name, $name, $link, $author, $email, $description, $documentation, $version;
|
||||
|
||||
function ExtensionInfo($main) {
|
||||
@ -66,7 +67,7 @@ class ExtensionInfo { // {{{
|
||||
private function is_enabled($fname) {
|
||||
return file_exists("ext/$fname");
|
||||
}
|
||||
} // }}}
|
||||
}
|
||||
|
||||
class ExtManager extends SimpleExtension {
|
||||
public function onPageRequest($event) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class ExtManagerTest extends ShimmieWebTestCase {
|
||||
class ExtManagerTest extends SCoreWebTestCase {
|
||||
function testAuth() {
|
||||
$this->get_page('ext_manager');
|
||||
$this->assertResponse(403);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class Handle404Test extends ShimmieWebTestCase {
|
||||
class Handle404Test extends SCoreWebTestCase {
|
||||
function test404Handler() {
|
||||
$this->get_page('not/a/page');
|
||||
$this->assertResponse(404);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class SetupTest extends ShimmieWebTestCase {
|
||||
class SetupTest extends SCoreWebTestCase {
|
||||
function testAuth() {
|
||||
$this->get_page('setup');
|
||||
$this->assertResponse(403);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class UserPageTest extends ShimmieWebTestCase {
|
||||
class UserPageTest extends SCoreWebTestCase {
|
||||
function testUserPage() {
|
||||
$this->get_page('user');
|
||||
$this->assertTitle("Not Logged In");
|
||||
|
59
index.php
59
index.php
@ -1,4 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* \mainpage Shimmie2 / SCore Documentation
|
||||
*
|
||||
* SCore is a framework designed for writing flexible, extendable applications.
|
||||
* Whereas most PHP apps are built monolithicly, score's event-based nature
|
||||
* allows parts to be mixed and matched. For instance, the most famous
|
||||
* collection of score extensions is the Shimmie image board, which includes
|
||||
* user management, a wiki, a private messaging system, etc. But one could
|
||||
* easily remove the image board bits and simply have a wiki with users and
|
||||
* PMs; or one could replace it with a blog module; or one could have a blog
|
||||
* which links to images on an image board, with no wiki or messaging, and so
|
||||
* on and so on...
|
||||
*
|
||||
* To learn about the innards of SCore, start with the \ref overview.
|
||||
*
|
||||
*
|
||||
* \page overview High Level Overview
|
||||
*
|
||||
* Dijkstra will kill me for personifying my architecture, but I can't think
|
||||
* of a better way without going into all the little details.
|
||||
*
|
||||
* There are a bunch of Extension subclasses, they talk to eachother by sending
|
||||
* and recieving Event subclasses. The topic of conversation is decided by the
|
||||
* initial PageRequestEvent, and each extension puts its notes into the shared
|
||||
* Page data store. Once the conversation is over, the Page is passed to the
|
||||
* current theme's Layout class which will tidy up the data and present it to
|
||||
* the user.
|
||||
*
|
||||
* To learn more about the architecture:
|
||||
*
|
||||
* \li \ref eande
|
||||
* \li \ref themes
|
||||
*
|
||||
* To learn more about practical development:
|
||||
*
|
||||
* \li \ref scglobals
|
||||
* \li \ref unittests
|
||||
* \li \ref hello
|
||||
*
|
||||
* \page scglobals SCore Globals
|
||||
*
|
||||
* There are four global variables which are pretty essential to most extensions:
|
||||
*
|
||||
* \li $config -- some variety of Config subclass
|
||||
* \li $database -- a Database object used to get raw SQL access
|
||||
* \li $page -- a Page to holds all the loose bits of extension output
|
||||
* \li $user -- the currently logged in User
|
||||
*
|
||||
* Each of these can be imported at the start of a function with eg "global $page, $user;"
|
||||
*/
|
||||
|
||||
// set up and purify the environment
|
||||
define("DEBUG", true);
|
||||
define("SCORE_VERSION", 's2hack');
|
||||
@ -10,8 +61,8 @@ if(!file_exists("config.php")) {
|
||||
}
|
||||
|
||||
require_once "core/util.inc.php";
|
||||
version_check();
|
||||
sanitise_environment();
|
||||
_version_check();
|
||||
_sanitise_environment();
|
||||
|
||||
|
||||
try {
|
||||
@ -31,7 +82,7 @@ try {
|
||||
// load the theme parts
|
||||
$_theme = $config->get_string("theme", "default");
|
||||
if(!file_exists("themes/$_theme")) $_theme = "default";
|
||||
require_once "themes/$_theme/page.class.php";
|
||||
if(file_exists("themes/$_theme/custompage.class.php")) require_once "themes/$_theme/custompage.class.php";
|
||||
require_once "themes/$_theme/layout.class.php";
|
||||
require_once "themes/$_theme/themelet.class.php";
|
||||
|
||||
@ -63,7 +114,7 @@ try {
|
||||
|
||||
|
||||
// start the page generation waterfall
|
||||
$page = new Page();
|
||||
$page = class_exists("CustomPage") ? new CustomPage() : new Page();
|
||||
$user = _get_user($config, $database);
|
||||
send_event(new InitExtEvent());
|
||||
send_event(_get_page_request());
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class Page extends GenericPage {
|
||||
class CustomPage extends Page {
|
||||
var $left_enabled = true;
|
||||
public function disable_left() {
|
||||
$this->left_enabled = false;
|
@ -1,7 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A class to turn a Page data structure into a blob of HTML
|
||||
*/
|
||||
class Layout {
|
||||
function display_page($page) {
|
||||
/**
|
||||
* turns the Page into HTML
|
||||
*/
|
||||
public function display_page(Page $page) {
|
||||
global $config;
|
||||
|
||||
$theme_name = $config->get_string('theme', 'default');
|
||||
@ -71,7 +76,10 @@ $header_html
|
||||
EOD;
|
||||
}
|
||||
|
||||
function block_to_html($block, $hidable=false, $salt="") {
|
||||
/**
|
||||
* A handy function which does exactly what it says in the method name
|
||||
*/
|
||||
private function block_to_html($block, $hidable=false, $salt="") {
|
||||
$h = $block->header;
|
||||
$b = $block->body;
|
||||
$html = "";
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Page extends GenericPage {
|
||||
// no changes from default
|
||||
}
|
||||
?>
|
@ -1,6 +1,11 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A customised version of the Setup theme
|
||||
*/
|
||||
class CustomSetupTheme extends SetupTheme {
|
||||
/**
|
||||
* Turn a SetupBlock into HTML... with rounded corners.
|
||||
*/
|
||||
protected function sb_to_html(SetupBlock $block) {
|
||||
return "
|
||||
<div class='rr setupblock'>
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A collection of common functions for theme parts
|
||||
*/
|
||||
class Themelet {
|
||||
/**
|
||||
* Generic error message display
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class Page extends GenericPage {
|
||||
class CustomPage extends Page {
|
||||
var $left_enabled = true;
|
||||
public function disable_left() {
|
||||
$this->left_enabled = false;
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Page extends GenericPage {
|
||||
// no changes from default
|
||||
}
|
||||
?>
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Page extends GenericPage {
|
||||
// no changes from default
|
||||
}
|
||||
?>
|
Loading…
x
Reference in New Issue
Block a user