diff --git a/app/controllers/pages_controller.php b/app/controllers/pages_controller.php index 137eab636..12a27db40 100644 --- a/app/controllers/pages_controller.php +++ b/app/controllers/pages_controller.php @@ -2,7 +2,7 @@ class PagesController extends PagesHelper { - function view () { + function display () { if (!func_num_args()) $this->redirect('/'); diff --git a/app/views/layouts/ajax.thtml b/app/views/layouts/ajax.thtml new file mode 100644 index 000000000..c5fb84980 --- /dev/null +++ b/app/views/layouts/ajax.thtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/config/paths.php b/config/paths.php index 00bb762f8..f78c95578 100644 --- a/config/paths.php +++ b/config/paths.php @@ -64,6 +64,18 @@ define ('HELPERS', APP.'helpers'.DS); */ define ('VIEWS', APP.'views'.DS); +/** + * Path to the application view layouts directory. + */ +define ('LAYOUTS', APP.'views'.DS.'layouts'.DS); + +/** + * Path to the application view elements directory. + * It's supposed to hold pieces of PHP/HTML that are used on multiple pages + * and are not linked to a particular layout (like polls, footers and so on) + */ +define ('ELEMENTS', APP.'views'.DS.'elements'.DS); + /** * Path to the configuration files directory. */ diff --git a/config/routes.php b/config/routes.php index 687d62042..732811c1f 100644 --- a/config/routes.php +++ b/config/routes.php @@ -33,21 +33,21 @@ */ /** - * Here, we are connecting '/' (base path) to controller called 'Pages', and - * its action called 'index' - note there are no additional params passed. + * Here, we are connecting '/' (base path) to controller called 'Pages', + * its action called 'display', and we pass a param to select the view file + * to use (in this case, /app/views/pages/home.thtml)... */ -$Route->connect ('/', array('controller'=>'Pages', 'action'=>'view', 'home')); +$Route->connect ('/', array('controller'=>'Pages', 'action'=>'display', 'home')); /** - * Here we connect url '/test' to our test controller. This is helpfull in + * ...and connect the rest of 'Pages' controller's urls. + */ +$Route->connect ('/pages/*', array('controller'=>'Pages', 'action'=>'display')); + +/** + * Then we connect url '/test' to our test controller. This is helpfull in * developement. */ $Route->connect ('/test', array('controller'=>'Tests', 'action'=>'test_all')); -/** - * Now we connect the rest of Pages controller's urls - * This needs to be the last one, as it takes in any and all remaining urls - */ -$Route->connect ('/pages/*', array('controller'=>'Pages', 'action'=>'view')); - -?> \ No newline at end of file +?> diff --git a/config/routes.php.default b/config/routes.php.default index cd54581ac..3712d7621 100644 --- a/config/routes.php.default +++ b/config/routes.php.default @@ -33,20 +33,21 @@ */ /** - * Here, we are connecting '/' (base path) to controller called 'Pages', and - * its action called 'index' - note there are no additional params passed. + * Here, we are connecting '/' (base path) to controller called 'Pages', + * its action called 'display', and we pass a param to select the view file + * to use (in this case, /app/views/pages/home.thtml)... */ -$Route->connect ('/', array('controller'=>'Pages', 'action'=>'view', 'home')); +$Route->connect ('/', array('controller'=>'Pages', 'action'=>'display', 'home')); /** - * Here we connect url '/test' to our test controller. This is helpfull in + * ...and connect the rest of 'Pages' controller's urls. + */ +$Route->connect ('/pages/*', array('controller'=>'Pages', 'action'=>'display')); + +/** + * Then we connect url '/test' to our test controller. This is helpfull in * developement. */ $Route->connect ('/test', array('controller'=>'Tests', 'action'=>'test_all')); -/** - * Now we connect the rest of Pages controller's urls - * This needs to be the last one, as it takes in any and all remaining urls - */ -$Route->connect ('/pages/*', array('controller'=>'Pages', 'action'=>'view')); ?> \ No newline at end of file diff --git a/config/tags.php b/config/tags.php index ac3782beb..88fc93dc8 100644 --- a/config/tags.php +++ b/config/tags.php @@ -135,4 +135,14 @@ define('TAG_CSS', ''); */ define('TAG_CHARSET', ''); +/** + * Tag template for inline JavaScript + */ +define('TAG_JAVASCRIPT', ''); + +/** + * Tag template for included JavaScript + */ +define('TAG_JAVASCRIPT_INCLUDE', ''); + ?> diff --git a/index.php b/index.php index df5eb0ed9..3a5079c26 100644 --- a/index.php +++ b/index.php @@ -14,8 +14,9 @@ ////////////////////////////////////////////////////////////////////////// /** - * This file collects requests if no mod_rewrite is avilable and / is used - * instead of /public/ as a web root. + * This file collects requests if: + * - no mod_rewrite is avilable or .htaccess files are not supported + * - /public is not set as a web root. * * @filesource * @author Cake Authors/Developers @@ -28,20 +29,21 @@ * @lastmodified $Date$ * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ + /** - * Get Cake's root directory - */ + * Get Cake's root directory + */ define ('DS', DIRECTORY_SEPARATOR); define ('ROOT', dirname(__FILE__).DS); /** - * We need to redefine some constants and variables, so that Cake knows it is - * working without mod_rewrite. + * We need to redefine some constants and variables, so that Cake knows it is + * working without mod_rewrite. */ define ('BASE_URL', $_SERVER['SCRIPT_NAME']); $_GET['url'] = ltrim($_SERVER['PATH_INFO'],'/'); -require (ROOT.'public/dispatch.php'); +require (ROOT.'public/index.php'); ?> \ No newline at end of file diff --git a/libs/bake.php b/libs/bake.php index da1f5ee6e..d78a2d806 100644 --- a/libs/bake.php +++ b/libs/bake.php @@ -203,6 +203,7 @@ class %sTest extends TestCase { * @uses Bake::actions Adds one action for each run. */ function newView ($controller, $name) { + $controller = Inflector::pluralize($controller); $dir = Inflector::underscore($controller); $path = $dir.DS.strtolower($name).".thtml"; $this->createDir(VIEWS.$dir); @@ -218,6 +219,7 @@ class %sTest extends TestCase { * @param string $name * @param array $actions * @access private + * @uses Inflector::pluralize() * @uses Bake::makeController() * @uses Bake::makeControllerTest() * @uses Bake::makeHelper() @@ -225,6 +227,7 @@ class %sTest extends TestCase { * @uses Bake::actions Adds one action for each run. */ function newController ($name, $actions=array()) { + $name = Inflector::pluralize($name); $this->makeController($name, $actions); $this->makeControllerTest($name); $this->makeHelper($name); diff --git a/libs/basics.php b/libs/basics.php index 9cf5afc7a..0f75de07e 100644 --- a/libs/basics.php +++ b/libs/basics.php @@ -101,10 +101,10 @@ function config () { foreach ($args as $arg) { if (file_exists(CONFIGS.$arg.'.php')) { require_once (CONFIGS.$arg.'.php'); - return true; + if (count($args) == 1) return true; } else { - return false; + if (count($args) == 1) return false; } } } @@ -305,7 +305,7 @@ class NeatArray { } /** - * Counts repeating words. + * Counts repeating strings and returns an array of totals. * * @param int $sortedBy 1 sorts by values, 2 by keys, default null (no sort) * @return array @@ -344,6 +344,49 @@ class NeatArray { return $this->value; } + /** + * Extracts a value from all array items + * + * @return array + * @access public + * @uses NeatArray::value + */ + function extract ($name) { + $out = array(); + foreach ($this->value as $val) { + if (isset($val[$name])) + $out[] = $val[$name]; + } + return $out; + } + + function unique () { + return array_unique($this->value); + } + + function makeUnique () { + return $this->value = array_unique($this->value); + } + + function joinWith ($his, $onMine, $onHis=null) { + if (empty($onHis)) $onHis = $onMine; + + $his = new NeatArray($his); + + $out = array(); + foreach ($this->value as $key=>$val) { + if ($fromHis = $his->findIn($onHis, $val[$onMine])) { + list($fromHis) = array_values($fromHis); + $out[$key] = array_merge($val, $fromHis); + } + else { + $out[$key] = $val; + } + } + + return $this->value = $out; + } + } ?> diff --git a/libs/controller.php b/libs/controller.php index eac3a4107..d30244a98 100644 --- a/libs/controller.php +++ b/libs/controller.php @@ -37,7 +37,7 @@ /** * Enter description here... */ -uses('model', 'template', 'inflector'); +uses('model', 'template', 'inflector', 'folder'); /** * Enter description here... @@ -110,6 +110,7 @@ class Controller extends Template { die("Controller::__construct() : Can't get or parse my own class name, exiting."); $this->name = strtolower($r[1]); + $this->viewpath = Inflector::underscore($r[1]); $model_class = Inflector::singularize($this->name); if (($this->uses === false) && class_exists($model_class)) { @@ -243,6 +244,41 @@ class Controller extends Template { return sprintf(TAG_FORM, $this->parseHtmlOptions($html_options, '')); } +/** + * Creates a generic html tag (no content) + * + * Examples: + * * tag("br") =>
+ * * tag("input", array("type" => "text")) => + * + * @param string $name name of element + * @param array $options html options + * @param bool $open is the tag open or closed (default closed "/>") + * @return string html tag + */ + function tag($name, $options=null, $open=false) { + $tag = "<$name ". $this->parseHtmlOptions($options); + $tag .= $open? ">" : " />"; + return $tag; + } + +/** + * Creates a generic html tag with content + * + * Examples: + * * content_tag("p", "Hello world!") =>

Hello world!

+ * * content_tag("div", content_tag("p", "Hello world!"), array("class" => "strong")) => + *

Hello world!

+ * + * @param string $name name of element + * @param array $options html options + * @param bool $open is the tag open or closed (default closed "/>") + * @return string html tag + */ + function contentTag($name, $content, $options=null) { + return "<$name ". $this->parseHtmlOptions($options). ">$content"; + } + /** * Enter description here... * @@ -426,7 +462,26 @@ class Controller extends Template { return sprintf(TAG_CHARSET, $charset); } +/** + * Returns a javascript script tag + * + * @param string $script the javascript + * @return string + */ + function javascriptTag ($script) { + return sprintf(TAG_JAVASCRIPT, $script); + } +/** + * Returns a javascript include tag + * + * @param string $url url to javascript file. + * @return string + */ + function javascriptIncludeTag ($url) { + return sprintf(TAG_JAVASCRIPT_INCLUDE, $this->base.$url); + } + /** * Enter description here... * @@ -471,6 +526,29 @@ class Controller extends Template { return join("\n", $out); } +/** + * Generates a nested \n"; + + return $out; + } /** * Enter description here... diff --git a/libs/dbo.php b/libs/dbo.php index 161572114..2a7a105ab 100644 --- a/libs/dbo.php +++ b/libs/dbo.php @@ -177,17 +177,49 @@ class DBO extends Object { var $_queriesLog=array(); // specific for each database, implemented in db drivers - function connect ($config) { die('Please implement DBO::connect() first.'); } - function disconnect () { die('Please implement DBO::disconnect() first.'); } - function execute ($sql) { die('Please implement DBO::execute() first.'); } - function fetchRow ($result) { die('Please implement DBO::fetchRow() first.'); } - function tables() { die('Please implement DBO::tables() first.'); } - function fields ($table_name) { die('Please implement DBO::fields() first.'); } - function prepare ($data) { die('Please implement DBO::prepare() first.'); } - function lastError () { die('Please implement DBO::lastError() first.'); } - function lastAffected () { die('Please implement DBO::lastAffected() first.'); } - function lastNumRows ($result){ die('Please implement DBO::lastNumRows() first.'); } - function lastInsertId () { die('Please implement DBO::lastInsertId() first.'); } + function connect ($config) { + die('Please implement DBO::connect() first.'); + } + + function disconnect () { + die('Please implement DBO::disconnect() first.'); + } + + function execute ($sql) { + die('Please implement DBO::execute() first.'); + } + + function fetchRow ($result) { + die('Please implement DBO::fetchRow() first.'); + } + + function tables() { + die('Please implement DBO::tables() first.'); + } + + function fields ($table_name) { + die('Please implement DBO::fields() first.'); + } + + function prepare ($data) { + die('Please implement DBO::prepare() first.'); + } + + function lastError ($result) { + die('Please implement DBO::lastError() first.'); + } + + function lastAffected () { + die('Please implement DBO::lastAffected() first.'); + } + + function lastNumRows ($result) { + die('Please implement DBO::lastNumRows() first.'); + } + + function lastInsertId () { + die('Please implement DBO::lastInsertId() first.'); + } /** * Enter description here... diff --git a/libs/dbo_mysql.php b/libs/dbo_mysql.php index 90fcb37b1..d6948adaa 100644 --- a/libs/dbo_mysql.php +++ b/libs/dbo_mysql.php @@ -41,7 +41,7 @@ * */ -uses('object', 'dbo'); +uses('dbo'); /** * Enter description here... * diff --git a/libs/dbo_postgres.php b/libs/dbo_postgres.php index c1618c931..6e86bf56b 100644 --- a/libs/dbo_postgres.php +++ b/libs/dbo_postgres.php @@ -32,14 +32,12 @@ /** * Enter description here... - * */ uses('object', 'dbo'); /** * Enter description here... * - * * @package cake * @subpackage cake.libs * @since Cake v 1.0.0.114 @@ -147,7 +145,7 @@ class DBO_Postgres extends DBO { * @return unknown */ function prepare ($data) { - return "'".str_replace('"', '\"', str_replace('$', '$', $data))."'"; + return "'".pg_escape_string($data)."'"; } /** diff --git a/libs/dispatcher.php b/libs/dispatcher.php index 73e523c9f..aedf8668d 100644 --- a/libs/dispatcher.php +++ b/libs/dispatcher.php @@ -84,7 +84,7 @@ class Dispatcher extends Object { if (empty($params['controller'])) $this->errorNoController($url); - $ctrl_name = ucfirst($params['controller']); + $ctrl_name = Inflector::camelize($params['controller']); $ctrl_class = $ctrl_name.'Controller'; // if specified controller class doesn't exist @@ -162,11 +162,11 @@ class Dispatcher extends Object { // if document root ends with 'public', it's probably correctly set $r = null; - if (!ereg('/^.*/public(\/)?$/', $doc_root)) - return preg_match('/^(.*)\/public\/index\.php$/', $script_name, $r)? $r[1]: false; - // document root is probably not set to Cake 'public' dir - else + if (ereg('/^.*/public(\/)?$/', $doc_root)) return preg_match('/^(.*)\/index\.php$/', $script_name, $r)? $r[1]: false; + else + // document root is probably not set to Cake 'public' dir + return preg_match('/^(.*)\/public\/index\.php$/', $script_name, $r)? $r[1]: false; } /** diff --git a/libs/flay.php b/libs/flay.php index 8c980846c..5bca13fd2 100644 --- a/libs/flay.php +++ b/libs/flay.php @@ -78,18 +78,24 @@ class Flay extends Object { * @param unknown_type $text * @return unknown */ - function toHtml ($text=null, $stripTags=false) { + function toHtml ($text=null, $bare=false, $allowHtml=false) { + + if (empty($text) && empty($this->text)) + return false; + $text = $text? $text: $this->text; - if ($stripTags) - $text = strip_tags($text); - // trim whitespace and disable all HTML - $text = str_replace('<', '<', str_replace('>', '>', trim($text))); + if ($allowHtml) + $text = trim($text); + else + $text = str_replace('<', '<', str_replace('>', '>', trim($text))); - // multi-paragraph functions - $text = preg_replace('#(?:[\n]{0,2})"""(.*)"""(?:[\n]{0,2})#s', "\n\n%BLOCKQUOTE%\n\n\\1\n\n%ENDBLOCKQUOTE%\n\n", $text); - $text = preg_replace('#(?:[\n]{0,2})===(.*)===(?:[\n]{0,2})#s', "\n\n%CENTER%\n\n\\1\n\n%ENDCENTER%\n\n", $text); + if (!$bare) { + // multi-paragraph functions + $text = preg_replace('#(?:[\n]{0,2})"""(.*)"""(?:[\n]{0,2})#s', "\n\n%BLOCKQUOTE%\n\n\\1\n\n%ENDBLOCKQUOTE%\n\n", $text); + $text = preg_replace('#(?:[\n]{0,2})===(.*)===(?:[\n]{0,2})#s', "\n\n%CENTER%\n\n\\1\n\n%ENDCENTER%\n\n", $text); + } // pre-parse newlines $text = preg_replace("#\r\n#", "\n", $text); @@ -102,21 +108,24 @@ class Flay extends Object { if ($line) { - // pre-parse links - $links = array(); - $regs = null; - if (preg_match_all('#\[([^\[]{4,})\]#', $line, $regs)) { - foreach ($regs[1] as $reg) { - $links[] = $reg; - $line = str_replace("[{$reg}]",'%LINK'.(count($links)-1).'%', $line); + if (!$bare) { + // pre-parse links + $links = array(); + $regs = null; + if (preg_match_all('#\[([^\[]{4,})\]#', $line, $regs)) { + foreach ($regs[1] as $reg) { + $links[] = $reg; + $line = str_replace("[{$reg}]",'%LINK'.(count($links)-1).'%', $line); + } } + + // MAIN TEXT FUNCTIONS + // bold + $line = ereg_replace("\*([^\*]*)\*", "\\1", $line); + // italic + $line = ereg_replace("_([^_]*)_", "\\1", $line); } - // MAIN TEXT FUNCTIONS - // bold - $line = ereg_replace("\*([^\*]*)\*", "\\1", $line); - // italic - $line = ereg_replace("_([^_]*)_", "\\1", $line); // entities $line = str_replace(' - ', ' – ', $line); $line = str_replace(' -- ', ' — ', $line); @@ -131,32 +140,34 @@ class Flay extends Object { $line = str_replace($email, "{$email}", $line); } } - // guess links - $urls = null; - if (preg_match_all("#((?:http|https|ftp|nntp)://[^ ]+)#", $line, $urls)) { - foreach ($urls[1] as $url) { - $line = str_replace($url, "{$url}", $line); + + if (!$bare) { + // guess links + $urls = null; + if (preg_match_all("#((?:http|https|ftp|nntp)://[^ ]+)#", $line, $urls)) { + foreach ($urls[1] as $url) { + $line = str_replace($url, "{$url}", $line); + } } - } - if (preg_match_all("#(www\.[^ ]+)#", $line, $urls)) { - foreach ($urls[1] as $url) { - $line = str_replace($url, "{$url}", $line); + if (preg_match_all("#(www\.[^ ]+)#", $line, $urls)) { + foreach ($urls[1] as $url) { + $line = str_replace($url, "{$url}", $line); + } } - } - - // re-parse links - if (count($links)) { - for ($ii=0; $ii"; - elseif (preg_match('#^([^\]\ ]+)(?: ([^\]]+))?$#', $links[$ii], $regs)) - $with = "".(isset($regs[2])? $regs[2]: $regs[1]).""; - else - $with = $links[$ii]; + if (preg_match('#\.(jpg|jpeg|gif|png)$#', $links[$ii])) + $with = "\"\""; + elseif (preg_match('#^([^\]\ ]+)(?: ([^\]]+))?$#', $links[$ii], $regs)) + $with = "".(isset($regs[2])? $regs[2]: $regs[1]).""; + else + $with = $links[$ii]; - $line = str_replace("%LINK{$ii}%", $with, $line); + $line = str_replace("%LINK{$ii}%", $with, $line); + } } } @@ -165,14 +176,72 @@ class Flay extends Object { } } - // re-parse multilines - $out = str_replace('

%BLOCKQUOTE%

', "
", $out); - $out = str_replace('

%ENDBLOCKQUOTE%

', "
", $out); - $out = str_replace('

%CENTER%

', "
", $out); - $out = str_replace('

%ENDCENTER%

', "
", $out); + if (!$bare) { + // re-parse multilines + $out = str_replace('

%BLOCKQUOTE%

', "
", $out); + $out = str_replace('

%ENDBLOCKQUOTE%

', "
", $out); + $out = str_replace('

%CENTER%

', "
", $out); + $out = str_replace('

%ENDCENTER%

', "
", $out); + } return $out; } + + function extractWords ($string) { + return preg_split('/[\s,\.:\/="!\(\)<>~\[\]]+/', $string); + } + + function markedSnippets ($words, $string, $max_snippets=5) { + + $string = strip_tags($string); + + $snips = array(); + $rest = $string; + foreach ($words as $word) { + if (preg_match_all("/[\s,]+.{0,40}{$word}.{0,40}[\s,]+/i", $rest, $r)) { + foreach ($r as $result) + $rest = str_replace($result, '', $rest); + $snips = array_merge($snips, $r[0]); + } + } + + if (count($snips) > $max_snippets) $snips = array_slice($snips, 0, $max_snippets); + $joined = join(' ... ', $snips); + $snips = $joined? "... {$joined} ...": substr($string, 0, 80).'...'; + + return Flay::colorMark($words, $snips); + } + + function colorMark($words, $string) { + $colors = array('yl','gr','rd','bl','fu','cy'); + + $nextColorIndex = 0; + foreach ($words as $word) { + $string = preg_replace("/({$word})/i", '\\1", $string); + $nextColorIndex++; + } + + return $string; + } + + function toClean ($text) { + return strip_tags(html_entity_decode($text, ENT_QUOTES)); + } + + function fragment ($text, $length, $elipsis='...') { + $soft=$length-5; + $hard=$length+5; + $rx = '/(.{'.$soft.','.$hard.'})[\s,\.:\/="!\(\)<>~\[\]]+.*/'; + if (preg_match($rx, $text, $r)) { + $out = $r[1]; + } + else { + $out = substr($text,0,$length); + } + + $out = $out.(strlen($out) \ No newline at end of file diff --git a/libs/legacy.php b/libs/legacy.php index 6ff5c0614..7fdceefda 100644 --- a/libs/legacy.php +++ b/libs/legacy.php @@ -59,4 +59,40 @@ function old_libs () { } } +/** + * Replace file_get_contents() + * + * @category PHP + * @package PHP_Compat + * @link http://php.net/function.file_get_contents + * @author Aidan Lister + * @version $Revision$ + * @internal resource_context is not supported + * @since PHP 5 + * @require PHP 4.0.0 (user_error) + */ +if (!function_exists('file_get_contents')) { + function file_get_contents($filename, $incpath = false, $resource_context = null) + { + if (false === $fh = fopen($filename, 'rb', $incpath)) { + user_error('file_get_contents() failed to open stream: No such file or directory', + E_USER_WARNING); + return false; + } + + clearstatcache(); + if ($fsize = @filesize($filename)) { + $data = fread($fh, $fsize); + } else { + $data = ''; + while (!feof($fh)) { + $data .= fread($fh, 8192); + } + } + + fclose($fh); + return $data; + } +} + ?> \ No newline at end of file diff --git a/libs/model.php b/libs/model.php index 9bfcb66d6..f167d5fa1 100644 --- a/libs/model.php +++ b/libs/model.php @@ -147,10 +147,13 @@ class Model extends Object { * * @param unknown_type $id */ - function __construct ($id=false) { + function __construct ($id=false, $db=null) { global $DB; - $this->db = &$DB; + if ($db) + $this->db = $db; + else + $this->db = &$DB; if ($id) $this->id = $id; @@ -302,7 +305,11 @@ class Model extends Object { * @param string $name * @return field contents */ - function field ($name) { + function field ($name, $conditions=null) { + if ($conditions) { + $data = $this->find($conditions); + return $data[$name]; + } if (isset($this->data[$name])) return $this->data[$name]; else { diff --git a/libs/template.php b/libs/template.php index 3590a9435..75b728b31 100644 --- a/libs/template.php +++ b/libs/template.php @@ -208,7 +208,7 @@ class Template extends Object { $layout_fn = $this->_getLayoutFn(); $data_for_layout = array_merge($this->_view_vars, array( - 'title_for_layout'=>$this->_page_title !== false? $this->_page_title: ucfirst($this->name), + 'title_for_layout'=>$this->_page_title !== false? $this->_page_title: Inflector::humanize($this->viewpath), 'content_for_layout'=>$content_for_layout)); if (is_file($layout_fn)) { @@ -229,6 +229,21 @@ class Template extends Object { } } +/** + * Renders a piece of PHP with provided params and returns HTML, XML, or any other string. + * + * @param unknown_type $content_for_layout + * @return unknown + */ + function renderElement ($name, $params=array()) { + $fn = ELEMENTS.$name.'.thtml'; + + if (!file_exists($fn)) + return "(Error rendering {$name})"; + + return $this->_render($fn, $params); + } + /** * Enter description here... * @@ -245,7 +260,7 @@ class Template extends Object { * @return unknown */ function _getViewFn($action) { - return VIEWS.$this->name.DS."{$action}.thtml"; + return VIEWS.$this->viewpath.DS."{$action}.thtml"; } /** diff --git a/libs/time.php b/libs/time.php index da0da6cb0..552ac9217 100644 --- a/libs/time.php +++ b/libs/time.php @@ -110,12 +110,86 @@ class Time extends Object { /** * Enter description here... * - * @param unknown_type $date_string + * @param string $date_string * @return unknown */ function fromString ($date_string) { return strtotime($date_string); } + +/** + * Formats date for Atom RSS feeds + * + * @param datetime $date + * @return string + */ + function toRss ($date) { + return date('Y-m-d', $date).'T'.date('H:i:s', $date).'Z'; + } + +/** + * This function returns either a relative date or a formatted date depending + * on the difference between the current datetime and the datetime passed. + * $datetime should be in a strtotime parsable format like MySQL datetime. + * + * Relative dates look something like this: + * 3 weeks, 4 days ago + * 15 seconds ago + * Formatted dates look like this: + * on 02/18/2004 + * + * The function includes 'ago' or 'on' and assumes you'll properly add a word + * like 'Posted ' before the function output. + * + * @param $datetimne time in strtotime parsable format + * @return string relative time string. + */ + + function timeAgoInWords ($datetime) { + + $in_seconds=strtotime($datetime); + $diff = time()-$in_seconds; + $months = floor($diff/2419200); + $diff -= $months*2419200; + $weeks = floor($diff/604800); + $diff -= $weeks*604800; + $days = floor($diff/86400); + $diff -= $days*86400; + $hours = floor($diff/3600); + $diff -= $hours*3600; + $minutes = floor($diff/60); + $diff -= $minutes*60; + $seconds = $diff; + + if ($months>0) { + // over a month old, just show date (mm/dd/yyyy format) + return 'on '.date("j/n/Y", $in_seconds); + } else { + $relative_date=''; + if ($weeks>0) { + // weeks and days + $relative_date .= ($relative_date?', ':'').$weeks.' week'.($weeks>1?'s':''); + $relative_date .= $days>0?($relative_date?', ':'').$days.' day'.($days>1?'s':''):''; + } elseif ($days>0) { + // days and hours + $relative_date .= ($relative_date?', ':'').$days.' day'.($days>1?'s':''); + $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hour'.($hours>1?'s':''):''; + } elseif ($hours>0) { + // hours and minutes + $relative_date .= ($relative_date?', ':'').$hours.' hour'.($hours>1?'s':''); + $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' minute'.($minutes>1?'s':''):''; + } elseif ($minutes>0) { + // minutes only + $relative_date .= ($relative_date?', ':'').$minutes.' minute'.($minutes>1?'s':''); + } else { + // seconds only + $relative_date .= ($relative_date?', ':'').$seconds.' second'.($seconds>1?'s':''); + } + } + // show relative date and add proper verbiage + return $relative_date.' ago'; + } + } ?> \ No newline at end of file diff --git a/public/js/prototype.js b/public/js/prototype.js deleted file mode 100644 index b7647f271..000000000 --- a/public/js/prototype.js +++ /dev/null @@ -1,765 +0,0 @@ -/* Prototype: an object-oriented Javascript library, version 1.2.1 - * (c) 2005 Sam Stephenson - * - * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff - * against the source tree, available from the Prototype darcs repository. - * - * Prototype is freely distributable under the terms of an MIT-style license. - * - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.2.1' -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.prototype.extend = function(object) { - for (property in object) { - this[property] = object[property]; - } - return this; -} - -Function.prototype.bind = function(object) { - var method = this; - return function() { - method.apply(object, arguments); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var method = this; - return function(event) { - method.call(object, event || window.event); - } -} - -Number.prototype.toColorPart = function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; -} - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - - this.registerCallback(); - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} - -/*--------------------------------------------------------------------------*/ - -if (!Array.prototype.push) { - Array.prototype.push = function() { - var startLength = this.length; - for (var i = 0; i < arguments.length; i++) - this[startLength + i] = arguments[i]; - return this.length; - } -} - -if (!Function.prototype.apply) { - // Based on code from http://www.youngpup.net/ - Function.prototype.apply = function(object, parameters) { - var parameterStrings = new Array(); - if (!object) object = window; - if (!parameters) parameters = new Array(); - - for (var i = 0; i < parameters.length; i++) - parameterStrings[i] = 'x[' + i + ']'; - - object.__apply__ = this; - var result = eval('obj.__apply__(' + - parameterStrings[i].join(', ') + ')'); - object.__apply__ = null; - - return result; - } -} - -/*--------------------------------------------------------------------------*/ - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - emptyFunction: function() {} -} - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - }.extend(options || {}); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = (new Ajax.Base()).extend({ - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - - try { - if (this.options.method == 'get') - url += '?' + this.options.parameters + '&_='; - - this.transport.open(this.options.method, url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version); - - if (this.options.method == 'post') { - this.transport.setRequestHeader('Connection', 'close'); - this.transport.setRequestHeader('Content-type', - 'application/x-www-form-urlencoded'); - } - - this.transport.send(this.options.method == 'post' ? - this.options.parameters + '&_=' : null); - - } catch (e) { - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - (this.options['on' + event] || Ajax.emptyFunction)(this.transport); - } -}); - -Ajax.Updater = Class.create(); -Ajax.Updater.prototype = (new Ajax.Base()).extend({ - initialize: function(container, url, options) { - this.container = $(container); - this.setOptions(options); - - if (this.options.asynchronous) { - this.onComplete = this.options.onComplete; - this.options.onComplete = this.updateContent.bind(this); - } - - this.request = new Ajax.Request(url, this.options); - - if (!this.options.asynchronous) - this.updateContent(); - }, - - updateContent: function() { - if (this.options.insertion) { - new this.options.insertion(this.container, - this.request.transport.responseText); - } else { - this.container.innerHTML = this.request.transport.responseText; - } - - if (this.onComplete) { - setTimeout((function() {this.onComplete(this.request)}).bind(this), 10); - } - } -}); - -/*--------------------------------------------------------------------------*/ - -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - $(element).focus(); - $(element).select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - focusFirstElement: function(form) { - form = $(form); - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - if (element.type != 'hidden' && !element.disabled) { - Field.activate(element); - break; - } - } - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return encodeURIComponent(parameter[0]) + '=' + - encodeURIComponent(parameter[1]); - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - var index = element.selectedIndex; - var value = element.options[index].value || element.options[index].text; - return [element.name, (index >= 0) ? value : '']; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - - this.registerCallback(); - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({ - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = (new Abstract.TimedObserver()).extend({ - getValue: function() { - return Form.serialize(this.element); - } -}); - - -/*--------------------------------------------------------------------------*/ - -document.getElementsByClassName = function(className) { - var children = document.getElementsByTagName('*') || document.all; - var elements = new Array(); - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - var classNames = child.className.split(' '); - for (var j = 0; j < classNames.length; j++) { - if (classNames[j] == className) { - elements.push(child); - break; - } - } - } - - return elements; -} - -/*--------------------------------------------------------------------------*/ - -var Element = { - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = - (element.style.display == 'none' ? '' : 'none'); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - } -} - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content; - - if (this.adjacency && this.element.insertAdjacentHTML) { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.fragment = this.range.createContextualFragment(this.content); - this.insertContent(); - } - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({ - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, this.element); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({ - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function() { - this.element.insertBefore(this.fragment, this.element.firstChild); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({ - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function() { - this.element.appendChild(this.fragment); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, - this.element.nextSibling); - } -}); - -/*--------------------------------------------------------------------------*/ - -var Effect = new Object(); - -Effect.Highlight = Class.create(); -Effect.Highlight.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 153; - this.finish = 255; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.highlight(this.element, this.current); - this.current += 17; - this.timer = setTimeout(this.fade.bind(this), 250); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - highlight: function(element, current) { - element.style.backgroundColor = "#ffff" + current.toColorPart(); - } -} - - -Effect.Fade = Class.create(); -Effect.Fade.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 100; - this.finish = 0; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) { this.element.style.display = 'none'; return; } - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current -= 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current <= this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - } -} - -Effect.Scale = Class.create(); -Effect.Scale.prototype = { - initialize: function(element, percent) { - this.element = $(element); - this.startScale = 1.0; - this.startHeight = this.element.offsetHeight; - this.startWidth = this.element.offsetWidth; - this.currentHeight = this.startHeight; - this.currentWidth = this.startWidth; - this.finishScale = (percent/100) /*//*/; - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_scale) { - clearTimeout(this.element.effect_scale.timer); - this.startScale = this.element.effect_scale.currentScale; - this.startHeight = this.element.effect_scale.startHeight; - this.startWidth = this.element.effect_scale.startWidth; - if(this.element.effect_scale.sizeEm) - this.sizeEm = this.element.effect_scale.sizeEm; - } - this.element.effect_scale = this; - this.currentScale = this.startScale; - this.factor = this.finishScale - this.startScale; - this.options = arguments[2] || {}; - this.scale(); - }, - - scale: function() { - if (this.isFinished()) { - this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em"; - if(this.options.complete) this.options.complete(this); - return; - } - if (this.timer) clearTimeout(this.timer); - if (this.options.step) this.options.step(this); - this.setDimensions(this.element, this.currentWidth, this.currentHeight); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em"; - this.currentScale += (this.factor/10) /*//*/; - this.currentWidth = this.startWidth * this.currentScale; - this.currentHeight = this.startHeight * this.currentScale; - this.timer = setTimeout(this.scale.bind(this), 50); - }, - - isFinished: function() { - return (this.factor < 0) ? - this.currentScale <= this.finishScale : this.currentScale >= this.finishScale; - }, - - setDimensions: function(element, width, height) { - element.style.width = width + 'px'; - element.style.height = height + 'px'; - } -} - -Effect.Squish = Class.create(); -Effect.Squish.prototype = { - initialize: function(element) { - this.element = $(element); - new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } ); - }, - hide: function() { - this.element.style.display = 'none'; - } -} - -Effect.Puff = Class.create(); -Effect.Puff.prototype = { - initialize: function(element) { - this.element = $(element); - this.opacity = 100; - this.startTop = this.element.top || this.element.offsetTop; - this.startLeft = this.element.left || this.element.offsetLeft; - new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } ); - }, - fade: function(effect) { - topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2; - leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2; - this.element.style.position='absolute'; - this.element.style.top = this.startTop-topd + "px"; - this.element.style.left = this.startLeft-leftd + "px"; - this.opacity -= 10; - this.setOpacity(this.element, this.opacity); - if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari - }, - hide: function() { - this.element.style.display = 'none'; - }, - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - } -} - -Effect.Appear = Class.create(); -Effect.Appear.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 0; - this.finish = 100; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current += 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - element.style.display = ''; - } -} - -Effect.ContentZoom = Class.create(); -Effect.ContentZoom.prototype = { - initialize: function(element, percent) { - this.element = $(element); - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_contentzoom) { - this.sizeEm = this.element.effect_contentzoom.sizeEm; - } - this.element.effect_contentzoom = this; - this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/; - if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; }; - } -} diff --git a/scripts/bake.bat b/scripts/bake.bat index 1c8cdd926..56f476d02 100644 --- a/scripts/bake.bat +++ b/scripts/bake.bat @@ -1 +1 @@ -@php -q add.php %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file +@php -q scripts\bake.php %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file