diff --git a/.htaccess b/.htaccess index c3d4405..699247f 100644 --- a/.htaccess +++ b/.htaccess @@ -13,5 +13,5 @@ RewriteRule ^(cache|content|system)/ error [L] RewriteCond %{REQUEST_FILENAME} -f RewriteRule ^[^\.]+$ - [T=text/html,L] -ErrorDocument 404 /error404.html +ErrorDocument 404 /error.html diff --git a/README.md b/README.md index 30f1478..1f36a6a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Yellow 0.5.2 +Yellow 0.5.3 ============ [![Yellow](https://raw.githubusercontent.com/wiki/datenstrom/yellow/images/yellow.jpg)](http://datenstrom.se/yellow) @@ -9,11 +9,8 @@ How do I install this? 1. [Download Yellow and unzip it](https://github.com/datenstrom/yellow/archive/master.zip). 2. Copy all files to your web hosting. 3. Open your website in a web browser. - -How do I get started? ---------------------- -Start by editing your website. Just give it a try. -For more information see [Yellow documentation](https://github.com/datenstrom/yellow/wiki). + +Installing is unzipping one file and you are ready to go. [Learn more](https://github.com/datenstrom/yellow/wiki). License ------- diff --git a/system/config/config.ini b/system/config/config.ini index c6cd784..2b2812f 100644 --- a/system/config/config.ini +++ b/system/config/config.ini @@ -3,8 +3,7 @@ sitename = Yellow author = Yellow language = en -theme = default -template = default +theme = flatsite // timeZone = UTC // serverScheme = http @@ -18,14 +17,14 @@ systemDir = system/ configDir = system/config/ coreDir = system/core/ pluginDir = system/plugins/ -snippetDir = system/snippets/ -templateDir = system/templates/ themeDir = system/themes/ +snippetDir = system/themes/snippets/ +templateDir = system/themes/templates/ mediaDir = media/ imageDir = media/images/ staticDir = cache/ staticDefaultFile = index.html -staticErrorFile = error404.html +staticErrorFile = error.html contentDir = content/ contentRootDir = default/ contentHomeDir = home/ @@ -33,18 +32,19 @@ contentDefaultFile = page.txt contentPagination = page contentExtension = .txt configExtension = .ini -errorPageFile = error(.*).txt -newPageFile = new(.*).txt -textStringFile = language(.*).ini +textFile = language-(.*).ini +errorFile = page-error-(.*).txt robotsTextFile = robots.txt -parser = markdownextra +template = default +parser = markdown parserSafeMode = 0 multiLanguageMode = 0 +commandlineIgnoreLocation = +commandlineSystemFile = .htaccess webinterfaceLocation = /edit/ webinterfaceServerScheme = http webinterfaceUserHashAlgorithm = bcrypt webinterfaceUserHashCost = 10 webinterfaceUserFile = user.ini -webinterfaceFilePrefix = published -commandlineIgnoreLocation = -commandlineSystemFile = .htaccess +webinterfaceNewFile = page-new-(.*).txt +webinterfaceMetaFilePrefix = published diff --git a/system/config/error401.txt b/system/config/page-error-401.txt similarity index 100% rename from system/config/error401.txt rename to system/config/page-error-401.txt diff --git a/system/config/error404.txt b/system/config/page-error-404.txt similarity index 100% rename from system/config/error404.txt rename to system/config/page-error-404.txt diff --git a/system/config/error424.txt b/system/config/page-error-424.txt similarity index 100% rename from system/config/error424.txt rename to system/config/page-error-424.txt diff --git a/system/config/error500.txt b/system/config/page-error-500.txt similarity index 100% rename from system/config/error500.txt rename to system/config/page-error-500.txt diff --git a/system/config/newpage.txt b/system/config/page-new-default.txt similarity index 100% rename from system/config/newpage.txt rename to system/config/page-new-default.txt diff --git a/system/core/core-commandline.php b/system/core/core-commandline.php index ee49798..6919d26 100755 --- a/system/core/core-commandline.php +++ b/system/core/core-commandline.php @@ -1,20 +1,20 @@ yellow = $yellow; @@ -22,15 +22,6 @@ class YellowCommandline $this->yellow->config->setDefault("commandlineSystemFile", ".htaccess"); } - // Handle command help - function onCommandHelp() - { - $help .= "version\n"; - $help .= "build [DIRECTORY LOCATION]\n"; - $help .= "clean [DIRECTORY LOCATION]\n"; - return $help; - } - // Handle command function onCommand($args) { @@ -51,6 +42,15 @@ class YellowCommandline return $statusCode; } + // Handle command help + function onCommandHelp() + { + $help .= "version\n"; + $help .= "build [DIRECTORY LOCATION]\n"; + $help .= "clean [DIRECTORY LOCATION]\n"; + return $help; + } + // Show available commands function helpCommand() { @@ -93,34 +93,38 @@ class YellowCommandline return $statusCode; } - // Build static directories and files + // Build static pages and files function buildStatic($path, $location) { $this->yellow->toolbox->timerStart($time); $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/'); $this->content = $this->media = $this->system = $this->error = $statusCode = 0; - $this->locationsArguments = $this->locationsPagination = array(); + $this->locationsArgs = $this->locationsArgsPagination = array(); if(empty($location)) { $statusCode = $this->cleanStatic($path, $location); foreach($this->getStaticLocations() as $location) { - $statusCode = max($statusCode, $this->buildStaticRequest($path, $location, true)); + $statusCode = max($statusCode, $this->buildStaticPage($path, $location, true)); } - foreach($this->locationsArguments as $location) + foreach($this->locationsArgs as $location) { - $statusCode = max($statusCode, $this->buildStaticRequest($path, $location, true)); + $statusCode = max($statusCode, $this->buildStaticPage($path, $location, true)); } - foreach($this->locationsPagination as $location) + foreach($this->locationsArgsPagination as $location) { + if(substru($location, -1) != ':') + { + $statusCode = max($statusCode, $this->buildStaticPage($path, $location, false, true)); + } for($pageNumber=2; $pageNumber<=999; ++$pageNumber) { - $statusCodeLocation = $this->buildStaticRequest($path, $location.$pageNumber, false, true); + $statusCodeLocation = $this->buildStaticPage($path, $location.$pageNumber, false, true); $statusCode = max($statusCode, $statusCodeLocation); if($statusCodeLocation == 0) break; } } - $statusCode = max($statusCode, $this->buildStaticError($path, 404)); + $statusCode = max($statusCode, $this->buildStaticPage($path, "/error", false, false, true)); foreach($this->getStaticFilesMedia($path) as $fileNameSource=>$fileNameDest) { $statusCode = max($statusCode, $this->buildStaticFile($fileNameSource, $fileNameDest, true)); @@ -130,66 +134,33 @@ class YellowCommandline $statusCode = max($statusCode, $this->buildStaticFile($fileNameSource, $fileNameDest, false)); } } else { - $statusCode = $this->buildStaticRequest($path, $location); + $statusCode = $this->buildStaticPage($path, $location); } $this->yellow->toolbox->timerStop($time); if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic time:$time ms\n"; return $statusCode; } - // Build static request - function buildStaticRequest($path, $location, $analyse = false, $probe = false) + // Build static page + function buildStaticPage($path, $location, $analyse = false, $probe = false, $error = false) { ob_start(); $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1"; $_SERVER["SERVER_NAME"] = $this->yellow->config->get("serverName"); $_SERVER["REQUEST_URI"] = $this->yellow->config->get("serverBase").$location; - $_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php"; + $_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."/yellow.php"; $_REQUEST = array(); $statusCode = $this->yellow->request(); - if($statusCode < 400) + if($statusCode<400 || $error) { - $fileName = $this->yellow->toolbox->findStaticFileFromLocation($location, $path, - $this->yellow->config->get("staticDefaultFile")); $fileData = ob_get_contents(); $modified = strtotime($this->yellow->page->getHeader("Last-Modified")); - if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) || - !$this->yellow->toolbox->modifyFile($fileName, $modified)) + if($statusCode>=301 && $statusCode<=303) { - $statusCode = 500; - $this->yellow->page->error($statusCode, "Can't write file '$fileName'!"); + $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location")); + $modified = time(); } - } - ob_end_clean(); - if($statusCode==200 && $analyse) $this->analyseStaticContent($fileData); - if($statusCode==404 && $probe) $statusCode = 0; - if($statusCode != 0) ++$this->content; - if($statusCode >= 400) - { - ++$this->error; - echo "ERROR building content location '$location', ".$this->yellow->page->getStatusCode(true)."\n"; - } - if(defined("DEBUG") && DEBUG>=3) echo $fileData; - if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticRequest status:$statusCode location:$location\n"; - return $statusCode; - } - - // Build static error - function buildStaticError($path, $statusCodeRequest) - { - ob_start(); - $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1"; - $_SERVER["SERVER_NAME"] = $this->yellow->config->get("serverName"); - $_SERVER["REQUEST_URI"] = $this->yellow->config->get("serverBase")."/"; - $_SERVER["SCRIPT_NAME"] = $this->yellow->config->get("serverBase")."yellow.php"; - $_REQUEST = array(); - $fileName = "$path/".$this->yellow->config->get("staticErrorFile"); - $statusCode = $this->yellow->request($statusCodeRequest); - if($statusCode == $statusCodeRequest) - { - $statusCode = 200; - $fileData = ob_get_contents(); - $modified = strtotime($this->yellow->page->getHeader("Last-Modified")); + $fileName = $this->getStaticFile($path, $location, $statusCode); if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) || !$this->yellow->toolbox->modifyFile($fileName, $modified)) { @@ -199,13 +170,17 @@ class YellowCommandline } } ob_end_clean(); - ++$this->system; + if($statusCode==200 && $analyse) $this->analyseStaticPage($fileData); + if($statusCode==404 && $error) $statusCode = 200; + if($statusCode==404 && $probe) $statusCode = 0; + if($statusCode != 0) ++$this->content; if($statusCode >= 400) { ++$this->error; - echo "ERROR building error file, ".$this->yellow->page->getStatusCode(true)."\n"; + echo "ERROR building content location '$location', ".$this->yellow->page->getStatusCode(true)."\n"; } - if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticError status:$statusCode file:$fileName\n"; + if(defined("DEBUG") && DEBUG>=3) echo $fileData; + if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticPage status:$statusCode location:$location\n"; return $statusCode; } @@ -226,8 +201,8 @@ class YellowCommandline return $statusCode; } - // Analyse static content, detect locations with arguments and pagination - function analyseStaticContent($text) + // Analyse static page, detect locations with arguments + function analyseStaticPage($text) { $serverName = $this->yellow->config->get("serverName"); $serverBase = $this->yellow->config->get("serverBase"); @@ -243,20 +218,20 @@ class YellowCommandline if(!$this->yellow->toolbox->isLocationArgs($match)) continue; if(substru($match, 0, strlenu($serverBase)) != $serverBase) continue; $location = rawurldecode(substru($match, strlenu($serverBase))); - if(!$this->yellow->toolbox->isPaginationLocation($location, $pagination)) + if(!$this->yellow->toolbox->isLocationArgsPagination($location, $pagination)) { $location = rtrim($location, '/').'/'; - if(is_null($this->locationsArguments[$location])) + if(is_null($this->locationsArgs[$location])) { - $this->locationsArguments[$location] = $location; - if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticContent type:arguments location:$location\n"; + $this->locationsArgs[$location] = $location; + if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticPage detected location:$location\n"; } } else { $location = rtrim($location, "0..9"); - if(is_null($this->locationsPagination[$location])) + if(is_null($this->locationsArgsPagination[$location])) { - $this->locationsPagination[$location] = $location; - if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticContent type:pagination location:$location\n"; + $this->locationsArgsPagination[$location] = $location; + if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticPage detected location:$location\n"; } } } @@ -297,9 +272,9 @@ class YellowCommandline function cleanStaticDirectory($path) { $statusCode = 200; - if($this->isYellowDirectory($path)) + if(is_dir($path)) { - if(is_file("$path/yellow.php") || $path=="/" || !$this->yellow->toolbox->deleteDirectory($path, true)) + if(!$this->checkStaticDirectory($path) || !$this->yellow->toolbox->deleteDirectory($path, true)) { $statusCode = 500; echo "ERROR cleaning pages: Can't delete directory '$path'!\n"; @@ -312,18 +287,13 @@ class YellowCommandline function cleanStaticFile($path, $location) { $statusCode = 200; - $fileName = $this->yellow->toolbox->findStaticFileFromLocation($location, $path, - $this->yellow->config->get("staticDefaultFile")); - if($this->isYellowDirectory($path) && is_file($fileName)) + $fileName = $this->getStaticFile($path, $location, $statusCode); + if(is_file($fileName)) { - $entry = basename($fileName); - if($entry!="yellow.php" && substru($entry, 0, 1)!=".") + if(!$this->checkStaticDirectory($path) || !$this->yellow->toolbox->deleteFile($fileName)) { - if(!$this->yellow->toolbox->deleteFile($fileName)) - { - $statusCode = 500; - echo "ERROR cleaning pages: Can't delete file '$fileName'!\n"; - } + $statusCode = 500; + echo "ERROR cleaning pages: Can't delete file '$fileName'!\n"; } } return $statusCode; @@ -352,7 +322,20 @@ class YellowCommandline $serverName = $this->yellow->config->get("serverName"); $serverBase = $this->yellow->config->get("serverBase"); return !empty($serverScheme) && !empty($serverName) && - $this->yellow->toolbox->isValidLocation($serverBase) && $serverBase!="/"; + $this->yellow->lookup->isValidLocation($serverBase) && $serverBase!="/"; + } + + // Check static directory + function checkStaticDirectory($path) + { + $ok = false; + if(!empty($path)) + { + if($path == rtrim($this->yellow->config->get("staticDir"), '/')) $ok = true; + if(is_file("$path/".$this->yellow->config->get("commandlineSystemFile"))) $ok = true; + if(is_file("$path/yellow.php")) $ok = false; + } + return $ok; } // Return static locations from file system @@ -409,6 +392,29 @@ class YellowCommandline return $files; } + // Return static file + function getStaticFile($path, $location, $statusCode) + { + if($statusCode < 400) + { + $fileName = $path.$location; + if(!$this->yellow->lookup->isFileLocation($location)) $fileName .= $this->yellow->config->get("staticDefaultFile"); + } else if($statusCode == 404) { + $fileName = $path."/".$this->yellow->config->get("staticErrorFile"); + } + return $fileName; + } + + // Return static redirect + function getStaticRedirect($location) + { + $output = "\n\n"; + $output .= "\n"; + $output .= "\n"; + $output .= "\n"; + return $output; + } + // Return command help function getCommandHelp() { @@ -436,12 +442,6 @@ class YellowCommandline usort($data, strnatcasecmp); return $data; } - - // Check if directory contains Yellow files - function isYellowDirectory($path) - { - return is_file("$path/yellow.php") || is_file("$path/".$this->yellow->config->get("commandlineSystemFile")); - } } $yellow->plugins->register("commandline", "YellowCommandline", YellowCommandline::Version); diff --git a/system/core/core-webinterface.css b/system/core/core-webinterface.css index 0a2b3f8..8f19472 100644 --- a/system/core/core-webinterface.css +++ b/system/core/core-webinterface.css @@ -1,4 +1,4 @@ -/* Yellow web interface 0.5.1 */ +/* Yellow web interface 0.5.3 */ .yellow-bar { position:relative; overflow:hidden; line-height:2em; margin-bottom:10px; } .yellow-bar-left { display:block; float:left; } diff --git a/system/core/core-webinterface.js b/system/core/core-webinterface.js index d86af9d..ab9ece3 100644 --- a/system/core/core-webinterface.js +++ b/system/core/core-webinterface.js @@ -4,7 +4,7 @@ // Yellow main API var yellow = { - version: "0.5.1", + version: "0.5.3", action: function(text) { yellow.webinterface.action(text); }, onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); }, onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); }, diff --git a/system/core/core-webinterface.php b/system/core/core-webinterface.php index 88fbcab..1cc67c0 100755 --- a/system/core/core-webinterface.php +++ b/system/core/core-webinterface.php @@ -5,7 +5,7 @@ // Web interface core plugin class YellowWebinterface { - const Version = "0.5.1"; + const Version = "0.5.3"; var $yellow; //access to API var $active; //web interface is active? (boolean) var $userLoginFailed; //web interface login failed? (boolean) @@ -15,7 +15,7 @@ class YellowWebinterface var $rawDataSource; //raw data of page for comparison var $rawDataEdit; //raw data of page for editing - // Handle plugin initialisation + // Handle initialisation function onLoad($yellow) { $this->yellow = $yellow; @@ -27,7 +27,8 @@ class YellowWebinterface $this->yellow->config->setDefault("webinterfaceUserHashAlgorithm", "bcrypt"); $this->yellow->config->setDefault("webinterfaceUserHashCost", "10"); $this->yellow->config->setDefault("webinterfaceUserFile", "user.ini"); - $this->yellow->config->setDefault("webinterfaceFilePrefix", "published"); + $this->yellow->config->setDefault("webinterfaceNewFile", "page-new-(.*).txt"); + $this->yellow->config->setDefault("webinterfaceMetaFilePrefix", "published"); $this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile")); } @@ -44,17 +45,17 @@ class YellowWebinterface if(rtrim($location, '/') == rtrim($activeLocation, '/')) { $statusCode = 301; - $locationHeader = $this->yellow->toolbox->getLocationHeader( + $location = $this->yellow->lookup->normaliseUrl( $this->yellow->config->get("webinterfaceServerScheme"), $this->yellow->config->get("webinterfaceServerName"), $base, $activeLocation); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $this->yellow->sendStatus($statusCode, $location); } } return $statusCode; } // Handle page meta data parsing - function onParseMeta($page, $text) + function onParseMeta($page) { if($this->isActive() && $this->isUser()) { @@ -71,41 +72,35 @@ class YellowWebinterface } } - // Handle page extra header - function onHeaderExtra($page) + // Handle page extra HTML data + function onExtra() { - $header = ""; + $output = ""; if($this->isActive()) { $location = $this->yellow->config->getHtml("serverBase").$this->yellow->config->getHtml("pluginLocation"); - $header .= "\n"; - $header .= "\n"; - $header .= "\n"; + $output .= "\n"; + $output .= "yellow.text = ".json_encode($this->yellow->text->getData("webinterface", $language)).";\n"; + if(defined("DEBUG")) $output .= "yellow.debug = ".json_encode(DEBUG).";\n"; + $output .= "// ]]>\n"; + $output .= "\n"; } - return $header; - } - - // Handle command help - function onCommandHelp() - { - return "user EMAIL PASSWORD [NAME LANGUAGE HOME]\n"; + return $output; } // Handle command @@ -120,6 +115,12 @@ class YellowWebinterface return $statusCode; } + // Handle command help + function onCommandHelp() + { + return "user EMAIL PASSWORD [NAME LANGUAGE HOME]\n"; + } + // Create or update user account function userCommand($args) { @@ -180,11 +181,12 @@ class YellowWebinterface { $statusCode = $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); } else { - if($this->yellow->toolbox->isFileLocation($location) && $this->yellow->isContentDirectory("$location/")) + if($this->yellow->isRequestContentDirectory($location)) { $statusCode = 301; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, "$location/"); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->isFileLocation($location) ? "$location/" : "/".$this->yellow->getRequestLanguage()."/"; + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); } else { $statusCode = $this->userPermission ? 424 : 404; $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); @@ -207,8 +209,8 @@ class YellowWebinterface if($this->yellow->toolbox->createFile($page->fileName, $page->rawData)) { $statusCode = 303; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $page->location); + $this->yellow->sendStatus($statusCode, $location); } else { $statusCode = 500; $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); @@ -239,8 +241,8 @@ class YellowWebinterface $this->yellow->toolbox->createFile($page->fileName, $page->rawData)) { $statusCode = 303; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $page->location); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $page->location); + $this->yellow->sendStatus($statusCode, $location); } else { $statusCode = 500; $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); @@ -265,8 +267,8 @@ class YellowWebinterface if(!is_file($fileName) || $this->yellow->toolbox->deleteFile($fileName)) { $statusCode = 303; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); } else { $statusCode = 500; $this->yellow->processRequest($serverScheme, $serverName, $base, $location, $fileName, false); @@ -284,12 +286,12 @@ class YellowWebinterface if(substru($location, 0, strlenu($home)) == $home) { $statusCode = 303; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); } else { $statusCode = 302; - $locationHeader = $this->yellow->toolbox->getLocationHeader($serverScheme, $serverName, $base, $home); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $home); + $this->yellow->sendStatus($statusCode, $location); } return $statusCode; } @@ -300,11 +302,11 @@ class YellowWebinterface $statusCode = 302; $this->users->destroyCookie("login"); $this->users->email = ""; - $locationHeader = $this->yellow->toolbox->getLocationHeader( + $location = $this->yellow->lookup->normaliseUrl( $this->yellow->config->get("serverScheme"), $this->yellow->config->get("serverName"), $this->yellow->config->get("serverBase"), $location); - $this->yellow->sendStatus($statusCode, $locationHeader, false); + $this->yellow->sendStatus($statusCode, $location); return $statusCode; } @@ -390,14 +392,11 @@ class YellowWebinterface { $page = new YellowPage($this->yellow); $page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); - $page->parseData($rawData, false); - $page->fileName = $this->yellow->toolbox->findFileFromTitle( - $page->get($this->yellow->config->get("webinterfaceFilePrefix")), $page->get("title"), $fileName, - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); - $page->location = $this->yellow->toolbox->findLocationFromFile( - $page->fileName, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), + $page->parseData($rawData, false, 0); + $page->fileName = $this->yellow->lookup->findFileFromTitle( + $page->get($this->yellow->config->get("webinterfaceMetaFilePrefix")), $page->get("title"), $fileName, $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); + $page->location = $this->yellow->lookup->findLocationFromFile($page->fileName); if($this->yellow->pages->find($page->location)) { preg_match("/^(.*?)(\d*)$/", $page->get("title"), $matches); @@ -407,13 +406,10 @@ class YellowWebinterface for(; $titleNumber<=999; ++$titleNumber) { $page->rawData = $this->updateDataTitle($rawData, $titleText.$titleNumber); - $page->fileName = $this->yellow->toolbox->findFileFromTitle( - $page->get($this->yellow->config->get("webinterfaceFilePrefix")), $titleText.$titleNumber, $fileName, - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); - $page->location = $this->yellow->toolbox->findLocationFromFile( - $page->fileName, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), + $page->fileName = $this->yellow->lookup->findFileFromTitle( + $page->get($this->yellow->config->get("webinterfaceMetaFilePrefix")), $titleText.$titleNumber, $fileName, $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); + $page->location = $this->yellow->lookup->findLocationFromFile($page->fileName); if(!$this->yellow->pages->find($page->location)) { $ok = true; break; } } if(!$ok) $page->error(500, "Page '".$page->get("title")."' can not be created!"); @@ -427,23 +423,20 @@ class YellowWebinterface { $page = new YellowPage($this->yellow); $page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); - $page->parseData($this->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), false); + $page->parseData($this->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), false, 0); if(empty($page->rawData)) $page->error(500, "Page has been modified by someone else!"); - if($this->yellow->toolbox->isFileLocation($location) && !$page->isError()) + if($this->yellow->lookup->isFileLocation($location) && !$page->isError()) { $pageSource = new YellowPage($this->yellow); $pageSource->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); - $pageSource->parseData($rawDataSource, false); - $prefix = $this->yellow->config->get("webinterfaceFilePrefix"); + $pageSource->parseData($rawDataSource, false, 0); + $prefix = $this->yellow->config->get("webinterfaceMetaFilePrefix"); if($pageSource->get($prefix)!=$page->get($prefix) || $pageSource->get("title")!=$page->get("title")) { - $page->fileName = $this->yellow->toolbox->findFileFromTitle( + $page->fileName = $this->yellow->lookup->findFileFromTitle( $page->get($prefix), $page->get("title"), $fileName, $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); - $page->location = $this->yellow->toolbox->findLocationFromFile( - $page->fileName, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); + $page->location = $this->yellow->lookup->findLocationFromFile($page->fileName); if($pageSource->location!=$page->location && $this->yellow->pages->find($page->location)) { $page->error(500, "Page '".$page->get("title")."' already exists!"); @@ -457,12 +450,9 @@ class YellowWebinterface // Return content data for new page function getDataNew($title = "") { - $fileName = $this->yellow->toolbox->findFileFromLocation( - $this->yellow->page->location, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); - $fileName = $this->yellow->toolbox->findFileNew($fileName, - $this->yellow->config->get("configDir"), $this->yellow->config->get("newPageFile"), + $fileName = $this->yellow->lookup->findFileFromLocation($this->yellow->page->location); + $fileName = $this->yellow->lookup->findFileNew($fileName, + $this->yellow->config->get("configDir"), $this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("contentDefaultFile")); $fileData = $this->yellow->toolbox->getFileData($fileName); $fileData = preg_replace("/@datetime/i", date("Y-m-d H:i:s"), $fileData); diff --git a/system/core/core.php b/system/core/core.php index 066859b..f358fd5 100755 --- a/system/core/core.php +++ b/system/core/core.php @@ -5,27 +5,30 @@ // Yellow main class class Yellow { - const Version = "0.5.2"; + const Version = "0.5.3"; var $page; //current page var $pages; //pages from file system + var $files; //files from file system + var $plugins; //plugins var $config; //configuration var $text; //text strings - var $plugins; //plugins + var $lookup; //location and file lookup var $toolbox; //toolbox with helpers function __construct() { $this->page = new YellowPage($this); $this->pages = new YellowPages($this); + $this->files = new YellowFiles($this); + $this->plugins = new YellowPlugins($this); $this->config = new YellowConfig($this); $this->text = new YellowText($this); + $this->lookup = new YellowLookup($this); $this->toolbox = new YellowToolbox(); - $this->plugins = new YellowPlugins(); $this->config->setDefault("sitename", "Yellow"); $this->config->setDefault("author", "Yellow"); $this->config->setDefault("language", "en"); $this->config->setDefault("theme", "default"); - $this->config->setDefault("template", "default"); $this->config->setDefault("timeZone", $this->toolbox->getTimeZone()); $this->config->setDefault("serverScheme", $this->toolbox->getServerScheme()); $this->config->setDefault("serverName", $this->toolbox->getServerName()); @@ -35,16 +38,16 @@ class Yellow $this->config->setDefault("themeLocation", "/media/themes/"); $this->config->setDefault("systemDir", "system/"); $this->config->setDefault("configDir", "system/config/"); - $this->config->setDefault("staticDir", "cache/"); - $this->config->setDefault("staticDefaultFile", "index.html"); - $this->config->setDefault("staticErrorFile", "error404.html"); $this->config->setDefault("coreDir", "system/core/"); $this->config->setDefault("pluginDir", "system/plugins/"); - $this->config->setDefault("snippetDir", "system/snippets/"); - $this->config->setDefault("templateDir", "system/templates/"); $this->config->setDefault("themeDir", "system/themes/"); + $this->config->setDefault("snippetDir", "system/themes/snippets/"); + $this->config->setDefault("templateDir", "system/themes/templates/"); $this->config->setDefault("mediaDir", "media/"); $this->config->setDefault("imageDir", "media/images/"); + $this->config->setDefault("staticDir", "cache/"); + $this->config->setDefault("staticDefaultFile", "index.html"); + $this->config->setDefault("staticErrorFile", "error.html"); $this->config->setDefault("contentDir", "content/"); $this->config->setDefault("contentRootDir", "default/"); $this->config->setDefault("contentHomeDir", "home/"); @@ -53,24 +56,24 @@ class Yellow $this->config->setDefault("contentExtension", ".txt"); $this->config->setDefault("configExtension", ".ini"); $this->config->setDefault("configFile", "config.ini"); - $this->config->setDefault("errorPageFile", "error(.*).txt"); - $this->config->setDefault("newPageFile", "new(.*).txt"); - $this->config->setDefault("textStringFile", "text(.*).ini"); + $this->config->setDefault("textFile", "language-(.*).ini"); + $this->config->setDefault("errorFile", "page-error-(.*).txt"); $this->config->setDefault("robotsTextFile", "robots.txt"); - $this->config->setDefault("parser", "markdownextra"); + $this->config->setDefault("template", "default"); + $this->config->setDefault("parser", "markdown"); $this->config->setDefault("parserSafeMode", "0"); $this->config->setDefault("multiLanguageMode", "0"); $this->config->load($this->config->get("configDir").$this->config->get("configFile")); - $this->text->load($this->config->get("configDir").$this->config->get("textStringFile")); + $this->text->load($this->config->get("configDir").$this->config->get("textFile")); $this->updateConfig(); } // Handle request - function request($statusCodeRequest = 0) + function request() { - $this->toolbox->timerStart($time); ob_start(); $statusCode = 0; + $this->toolbox->timerStart($time); list($serverScheme, $serverName, $base, $location, $fileName) = $this->getRequestInformation(); $this->page->setRequestInformation($serverScheme, $serverName, $base, $location, $fileName); foreach($this->plugins->plugins as $key=>$value) @@ -87,10 +90,9 @@ class Yellow $this->pages->requestHandler = "core"; $statusCode = $this->processRequest($serverScheme, $serverName, $base, $location, $fileName, true); } - if($statusCodeRequest >= 400) $this->page->error($statusCodeRequest, "Request error"); if($this->page->isError()) $statusCode = $this->processRequestError(); - ob_end_flush(); $this->toolbox->timerStop($time); + ob_end_flush(); if(defined("DEBUG") && DEBUG>=1) echo "Yellow::request status:$statusCode location:$location
\n"; if(defined("DEBUG") && DEBUG>=1) echo "Yellow::request time:$time ms
\n"; return $statusCode; @@ -99,37 +101,33 @@ class Yellow // Process request function processRequest($serverScheme, $serverName, $base, $location, $fileName, $cacheable) { + $statusCode = 0; if(is_readable($fileName)) { - if($cacheable) $fileName = $this->getStaticFile($location, $fileName); if($this->toolbox->isRequestCleanUrl($location)) { $statusCode = 303; $locationArgs = $this->toolbox->getLocationArgsCleanUrl($this->config->get("contentPagination")); - $locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location.$locationArgs); - $this->sendStatus($statusCode, $locationHeader, false); - } else if($this->isStaticFile($fileName)) { - $statusCode = 200; - $statusCode = $this->sendFile($statusCode, $fileName, $cacheable); - } else { - $statusCode = 200; - $fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode); - $statusCode = $this->sendPage(); + $location = $this->lookup->normaliseUrl($serverScheme, $serverName, $base, $location.$locationArgs); + $this->sendStatus($statusCode, $location); } } else { - if($cacheable) $fileName = $this->getStaticFile("", ""); - if(($this->toolbox->isFileLocation($location) && $this->isContentDirectory("$location/")) || - ($location=="/" && $this->config->get("multiLanguageMode"))) + if($this->isRequestContentDirectory($location)) { $statusCode = 301; - $location = $this->toolbox->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage()."/"; - $locationHeader = $this->toolbox->getLocationHeader($serverScheme, $serverName, $base, $location); - $this->sendStatus($statusCode, $locationHeader, false); - } else if($this->isStaticFile($fileName)) { - $statusCode = 404; + $location = $this->lookup->isFileLocation($location) ? "$location/" : "/".$this->getRequestLanguage()."/"; + $location = $this->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->sendStatus($statusCode, $location); + } + } + if($statusCode == 0) + { + $statusCode = is_readable($fileName) ? 200 : 404; + $fileName = $this->getStaticFileFromCache($location, $fileName, $cacheable, $statusCode); + if($this->isStaticFile($fileName)) + { $statusCode = $this->sendFile($statusCode, $fileName, $cacheable); } else { - $statusCode = 404; $fileName = $this->readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode); $statusCode = $this->sendPage(); } @@ -137,7 +135,7 @@ class Yellow if(defined("DEBUG") && DEBUG>=1) { $handler = $this->getRequestHandler(); - echo "Yellow::processRequest handler:$handler file:$fileName
\n"; + echo "Yellow::processRequest file:$fileName handler:$handler
\n"; } return $statusCode; } @@ -153,17 +151,17 @@ class Yellow if(defined("DEBUG") && DEBUG>=1) { $handler = $this->getRequestHandler(); - echo "Yellow::processRequestError handler:$handler file:$fileName
\n"; + echo "Yellow::processRequestError file:$fileName handler:$handler
\n"; } return $statusCode; } - // Read page from file + // Read page function readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode, $pageError = "") { if($statusCode >= 400) { - $fileName = $this->config->get("configDir").$this->config->get("errorPageFile"); + $fileName = $this->config->get("configDir").$this->config->get("errorFile"); $fileName = strreplaceu("(.*)", $statusCode, $fileName); $cacheable = false; } @@ -178,29 +176,25 @@ class Yellow // Send page response function sendPage() { - $this->page->parseResponse(); + $this->page->parsePage(); $statusCode = $this->page->statusCode; $lastModifiedFormatted = $this->page->getHeader("Last-Modified"); - if($statusCode==200 && $this->page->isCacheable() && $this->toolbox->isFileNotModified($lastModifiedFormatted)) + if($statusCode==200 && $this->page->isCacheable() && $this->toolbox->isRequestNotModified($lastModifiedFormatted)) { $statusCode = 304; - $this->page->clean($statusCode); - } - if($this->page->isExisting("pageClean")) ob_clean(); - if(PHP_SAPI != "cli") - { + @header($this->toolbox->getHttpStatusFormatted($statusCode)); + } else { @header($this->toolbox->getHttpStatusFormatted($statusCode)); foreach($this->page->headerData as $key=>$value) @header("$key: $value"); - } else { - if($statusCode>=301 && $statusCode<=303) $this->sendStaticRedirect(); + if(!is_null($this->page->outputData)) echo $this->page->outputData; } if(defined("DEBUG") && DEBUG>=1) { foreach($this->page->headerData as $key=>$value) echo "Yellow::sendPage $key: $value
\n"; - $fileNameTemplate = $this->config->get("templateDir").$this->page->get("template").".php"; $fileNameTheme = $this->config->get("themeDir").$this->page->get("theme").".css"; + $templateName = $this->page->get("template"); $parserName = $this->page->get("parser"); - echo "Yellow::sendPage template:$fileNameTemplate theme:$fileNameTheme parser:$parserName
\n"; + echo "Yellow::sendPage theme:$fileNameTheme template:$templateName parser:$parserName
\n"; } return $statusCode; } @@ -209,7 +203,7 @@ class Yellow function sendFile($statusCode, $fileName, $cacheable) { $lastModifiedFormatted = $this->toolbox->getHttpDateFormatted(filemtime($fileName)); - if($statusCode==200 && $cacheable && $this->toolbox->isFileNotModified($lastModifiedFormatted)) + if($statusCode==200 && $cacheable && $this->toolbox->isRequestNotModified($lastModifiedFormatted)) { $statusCode = 304; @header($this->toolbox->getHttpStatusFormatted($statusCode)); @@ -224,29 +218,16 @@ class Yellow } // Send status response - function sendStatus($statusCode, $responseHeader, $cacheable) + function sendStatus($statusCode, $location = "") { - if(PHP_SAPI != "cli") + if(!empty($location)) $this->page->clean($statusCode, $location); + @header($this->toolbox->getHttpStatusFormatted($statusCode)); + foreach($this->page->headerData as $key=>$value) @header("$key: $value"); + if(defined("DEBUG") && DEBUG>=1) { - @header($this->toolbox->getHttpStatusFormatted($statusCode)); - if(!$cacheable) @header("Cache-Control: no-cache, must-revalidate"); - if(!empty($responseHeader)) @header($responseHeader); - } else { - if(!empty($responseHeader)) $this->page->header($responseHeader); - if($statusCode>=301 && $statusCode<=303) $this->sendStaticRedirect(); + foreach($this->page->headerData as $key=>$value) echo "Yellow::sendStatus $key: $value
\n"; } } - - // Send static redirect response - function sendStaticRedirect() - { - $lastModifiedFormatted = $this->toolbox->getHttpDateFormatted(time()); - if(!$this->page->isHeader("Last-Modified")) $this->page->setHeader("Last-Modified", $lastModifiedFormatted); - echo "\n\n"; - echo "\n"; - echo "page->getHeader("Location"))."\" />\n"; - echo "\n"; - } // Return request information function getRequestInformation($serverScheme = "", $serverName = "", $base = "") @@ -271,20 +252,14 @@ class Yellow $fileName = $this->config->get("configDir").$this->config->get("robotsTextFile"); } } - if(empty($fileName)) - { - $fileName = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"), - $this->config->get("contentRootDir"), $this->config->get("contentHomeDir"), - $this->config->get("contentDefaultFile"), $this->config->get("contentExtension")); - } + if(empty($fileName)) $fileName = $this->lookup->findFileFromLocation($location); return array($serverScheme, $serverName, $base, $location, $fileName); } // Return request language function getRequestLanguage() { - $languages = $this->toolbox->findRootLanguages($this->config->get("contentDir"), $this->config->get("contentRootDir")); - return $this->toolbox->detectBrowserLanguage($languages, $this->config->get("language")); + return $this->toolbox->detectBrowserLanguage($this->pages->getLanguages(), $this->config->get("language")); } // Return request handler @@ -293,16 +268,17 @@ class Yellow return $this->pages->requestHandler; } - // Return static file - function getStaticFile($location, $fileName) + // Return static file from cache if available + function getStaticFileFromCache($location, $fileName, $cacheable, $statusCode) { - if(PHP_SAPI != "cli") + if(PHP_SAPI != "cli" && $cacheable) { - if(!empty($location)) + if($statusCode == 200) { - $fileNameStatic = $this->toolbox->findStaticFileFromLocation($location, - $this->config->get("staticDir"), $this->config->get("staticDefaultFile")); - } else { + $location .= $this->toolbox->getLocationArgs(); + $fileNameStatic = rtrim($this->config->get("staticDir"), '/').$location; + if(!$this->lookup->isFileLocation($location)) $fileNameStatic .= $this->config->get("staticDefaultFile"); + } else if($statusCode == 404) { $fileNameStatic = $this->config->get("staticDir").$this->config->get("staticErrorFile"); } if(is_readable($fileNameStatic)) $fileName = $fileNameStatic; @@ -316,26 +292,30 @@ class Yellow $staticDirLength = strlenu($this->config->get("staticDir")); $systemDirLength = strlenu($this->config->get("systemDir")); return substru($fileName, 0, $staticDirLength) == $this->config->get("staticDir") || - substru($fileName, 0, $systemDirLength) == $this->config->get("systemDir"); + substru($fileName, 0, $systemDirLength) == $this->config->get("systemDir"); } - // Check if content directory - function isContentDirectory($location) + // Check if request can be redirected into content directory + function isRequestContentDirectory($location) { - $path = $this->toolbox->findFileFromLocation($location, $this->config->get("contentDir"), - $this->config->get("contentRootDir"), $this->config->get("contentHomeDir"), "", ""); - return is_dir($path); + $ok = false; + if($this->lookup->isFileLocation($location)) + { + $path = $this->lookup->findFileFromLocation("$location/", true); + $ok = is_dir($path); + } else if($location=="/") { + $ok = $this->config->get("multiLanguageMode"); + } + return $ok; } // Update configuration function updateConfig() { - date_default_timezone_set($this->config->get("timeZone")); - list($pathRoot, $pathHome) = $this->toolbox->findRootConfig($this->config->get("contentDir"), - $this->config->get("contentRootDir"), $this->config->get("contentHomeDir"), - $this->config->get("multiLanguageMode")); + list($pathRoot, $pathHome) = $this->lookup->getContentInformation(); $this->config->set("contentRootDir", $pathRoot); $this->config->set("contentHomeDir", $pathHome); + date_default_timezone_set($this->config->get("timeZone")); } // Execute command @@ -356,7 +336,7 @@ class Yellow // Execute template function template($name) { - $fileNameTemplate = $this->config->get("templateDir")."$name.php"; + $fileNameTemplate = $this->config->get("templateDir")."$name.html"; if(is_file($fileNameTemplate)) { $this->page->setLastModified(filemtime($fileNameTemplate)); @@ -364,6 +344,7 @@ class Yellow require($fileNameTemplate); } else { $this->page->error(500, "Template '$name' does not exist!"); + echo "Template error
\n"; } } @@ -379,6 +360,7 @@ class Yellow require($fileNameSnippet); } else { $this->page->error(500, "Snippet '$name' does not exist!"); + echo "Snippet error
\n"; } } @@ -403,11 +385,14 @@ class YellowPage var $metaDataOffsetBytes; //meta data offset var $metaData; //meta data var $headerData; //response header - var $parserData; //content data of page + var $outputData; //response output + var $pages; //page collection var $parser; //content parser + var $parserData; //content data of page var $parserSafeMode; //page is parsed in safe mode? (boolean) - var $active; //page is active location? (boolean) + var $available; //page is available? (boolean) var $visible; //page is visible location? (boolean) + var $active; //page is active location? (boolean) var $cacheable; //page is cacheable? (boolean) var $statusCode; //status code @@ -416,6 +401,7 @@ class YellowPage $this->yellow = $yellow; $this->metaData = array(); $this->headerData = array(); + $this->pages = new YellowPageCollection($yellow); } // Set request information @@ -429,17 +415,16 @@ class YellowPage } // Parse page data - function parseData($rawData, $cacheable, $statusCode = 0, $pageError = "") + function parseData($rawData, $cacheable, $statusCode, $pageError = "") { $this->lastModified = 0; $this->rawData = $rawData; - $this->parserData = ""; $this->parser = NULL; + $this->parserData = ""; $this->parserSafeMode = $this->yellow->config->get("parserSafeMode"); - $this->active = $this->yellow->toolbox->isActiveLocation($this->location, $this->yellow->page->location, - $this->yellow->pages->getHomeLocation($this->yellow->page->location)); - $this->visible = $this->yellow->toolbox->isVisibleLocation($this->location, $this->fileName, - $this->yellow->config->get("contentDir")); + $this->available = true; + $this->visible = $this->yellow->lookup->isVisibleLocation($this->location, $this->fileName); + $this->active = $this->yellow->lookup->isActiveLocation($this->location, $this->yellow->page->location); $this->cacheable = $cacheable; $this->statusCode = $statusCode; $this->parseMeta($pageError); @@ -465,48 +450,59 @@ class YellowPage function parseMeta($pageError = "") { $this->metaData = array(); - $this->set("title", $this->yellow->toolbox->createTextTitle($this->location)); - $this->set("sitename", $this->yellow->config->get("sitename")); - $this->set("author", $this->yellow->config->get("author")); - $this->set("language", $this->yellow->toolbox->findLanguageFromFile($this->fileName, - $this->yellow->config->get("contentDir"), $this->yellow->config->get("contentRootDir"), - $this->yellow->config->get("language"))); - $this->set("theme", $this->yellow->toolbox->findNameFromFile($this->fileName, - $this->yellow->config->get("themeDir"), $this->yellow->config->get("theme"), ".css")); - $this->set("template", $this->yellow->toolbox->findNameFromFile($this->fileName, - $this->yellow->config->get("templateDir"), $this->yellow->config->get("template"), ".php")); - $this->set("modified", date("Y-m-d H:i:s", $this->yellow->toolbox->findModifiedFromFile($this->fileName))); - $this->set("parser", $this->yellow->config->get("parser")); - - if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)[\r\n]+\-\-\-[\r\n]+/s", $this->rawData, $parsed)) + if(!is_null($this->rawData)) { - $this->metaDataOffsetBytes = strlenb($parsed[0]); - foreach(preg_split("/[\r\n]+/", $parsed[2]) as $line) + $this->set("title", $this->yellow->toolbox->createTextTitle($this->location)); + $this->set("sitename", $this->yellow->config->get("sitename")); + $this->set("author", $this->yellow->config->get("author")); + $this->set("language", $this->yellow->lookup->findLanguageFromFile($this->fileName, + $this->yellow->config->get("language"))); + $this->set("theme", $this->yellow->lookup->findNameFromFile($this->fileName, + $this->yellow->config->get("themeDir"), $this->yellow->config->get("theme"), ".css")); + $this->set("template", $this->yellow->lookup->findNameFromFile($this->fileName, + $this->yellow->config->get("templateDir"), $this->yellow->config->get("template"), ".html")); + $this->set("modified", date("Y-m-d H:i:s", $this->yellow->toolbox->getFileModified($this->fileName))); + $this->set("parser", $this->yellow->config->get("parser")); + + if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)[\r\n]+\-\-\-[\r\n]+/s", $this->rawData, $parts)) { - preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); - if(!empty($matches[1]) && !strempty($matches[2])) $this->set(lcfirst($matches[1]), $matches[2]); + $this->metaDataOffsetBytes = strlenb($parts[0]); + foreach(preg_split("/[\r\n]+/", $parts[2]) as $line) + { + preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && !strempty($matches[2])) $this->set(lcfirst($matches[1]), $matches[2]); + } + } else if(preg_match("/^(\xEF\xBB\xBF)?([^\r\n]+)[\r\n]+=+[\r\n]+/", $this->rawData, $parts)) { + $this->metaDataOffsetBytes = strlenb($parts[0]); + $this->set("title", $parts[2]); } - } else if(preg_match("/^(\xEF\xBB\xBF)?([^\r\n]+)[\r\n]+=+[\r\n]+/", $this->rawData, $parsed)) { - $this->metaDataOffsetBytes = strlenb($parsed[0]); - $this->set("title", $parsed[2]); + + $titleHeader = ($this->location == $this->yellow->pages->getHomeLocation($this->location)) ? + $this->get("sitename") : $this->get("title")." - ".$this->get("sitename"); + if($this->get("titleContent") == "-") $this->set("titleContent", ""); + if(!$this->isExisting("titleContent")) $this->set("titleContent", $this->get("title")); + if(!$this->isExisting("titleHeader")) $this->set("titleHeader", $titleHeader); + if(!$this->isExisting("titleNavigation")) $this->set("titleNavigation", $this->get("title")); + $this->set("pageRead", $this->yellow->lookup->normaliseUrl( + $this->yellow->config->get("serverScheme"), + $this->yellow->config->get("serverName"), + $this->yellow->config->get("serverBase"), $this->location)); + $this->set("pageEdit", $this->yellow->lookup->normaliseUrl( + $this->yellow->config->get("webinterfaceServerScheme"), + $this->yellow->config->get("webinterfaceServerName"), + $this->yellow->config->get("serverBase"), + rtrim($this->yellow->config->get("webinterfaceLocation"), '/').$this->location)); + $this->set("pageFile", $this->yellow->lookup->normaliseFile($this->fileName)); + if($this->get("status") == "hidden") $this->available = false; + } else { + $this->set("type", $this->yellow->toolbox->getFileExtension($this->fileName)); + $this->set("modified", date("Y-m-d H:i:s", $this->yellow->toolbox->getFileModified($this->fileName))); + $this->set("pageFile", $this->yellow->lookup->normaliseFile($this->fileName, true)); } - - $titleHeader = ($this->location == $this->yellow->pages->getHomeLocation($this->location)) ? - $this->get("sitename") : $this->get("title")." - ".$this->get("sitename"); - if($this->get("titleContent") == "-") $this->set("titleContent", ""); - if(!$this->isExisting("titleContent")) $this->set("titleContent", $this->get("title")); - if(!$this->isExisting("titleHeader")) $this->set("titleHeader", $titleHeader); - if(!$this->isExisting("titleNavigation")) $this->set("titleNavigation", $this->get("title")); - $this->set("pageRead", $this->yellow->toolbox->getUrl( - $this->yellow->config->get("serverScheme"), $this->yellow->config->get("serverName"), - $this->yellow->config->get("serverBase"), $this->location)); - $this->set("pageEdit", $this->yellow->toolbox->getUrl( - $this->yellow->config->get("webinterfaceServerScheme"), $this->yellow->config->get("webinterfaceServerName"), - $this->yellow->config->get("serverBase"), rtrim($this->yellow->config->get("webinterfaceLocation"), '/').$this->location)); if(!empty($pageError)) $this->set("pageError", $pageError); foreach($this->yellow->plugins->plugins as $key=>$value) { - if(method_exists($value["obj"], "onParseMeta")) $value["obj"]->onParseMeta($this, $this->rawData); + if(method_exists($value["obj"], "onParseMeta")) $value["obj"]->onParseMeta($this); } } @@ -518,52 +514,69 @@ class YellowPage if($this->yellow->plugins->isExisting($this->get("parser"))) { $plugin = $this->yellow->plugins->plugins[$this->get("parser")]; - if(method_exists($plugin["obj"], "onParseContentText")) + if(method_exists($plugin["obj"], "onParseContentRaw")) { $this->parser = $plugin["obj"]; - $this->parserData = $this->parser->onParseContentText($this, $this->getContent(true)); + $this->parserData = $this->parser->onParseContentRaw($this, $this->getContent(true)); foreach($this->yellow->plugins->plugins as $key=>$value) { - if(method_exists($value["obj"], "onParseContent")) + if(method_exists($value["obj"], "onParseContentText")) { - $output = $value["obj"]->onParseContent($this, $this->parserData); + $output = $value["obj"]->onParseContentText($this, $this->parserData); if(!is_null($output)) { $this->parserData = $output; } } } - if(!$this->isExisting("description")) - { - $this->set("description", $this->yellow->toolbox->createTextDescription($this->parserData, 150)); - } - if(!$this->isExisting("keywords")) - { - $this->set("keywords", $this->yellow->toolbox->createTextKeywords($this->get("title"), 10)); - } } + } else { + $this->parserData = $this->getContent(true); + $this->parserData = preg_replace("/@pageError/i", $this->get("pageError"), $this->parserData); } - if(defined("DEBUG") && DEBUG>=2) echo "YellowPage::parseContent location:".$this->location."
\n"; + if(!$this->isExisting("description")) + { + $this->set("description", $this->yellow->toolbox->createTextDescription($this->parserData, 150)); + } + if(!$this->isExisting("keywords")) + { + $this->set("keywords", $this->yellow->toolbox->createTextKeywords($this->get("title"), 10)); + } + if(defined("DEBUG") && DEBUG>=3) echo "YellowPage::parseContent location:".$this->location."
\n"; } } - // Parse page custom type - function parseType($name, $text, $typeShortcut) + // Parse page content block + function parseContentBlock($name, $text, $typeShortcut) { $output = NULL; foreach($this->yellow->plugins->plugins as $key=>$value) { - if(method_exists($value["obj"], "onParseType")) + if(method_exists($value["obj"], "onParseContentBlock")) { - $output = $value["obj"]->onParseType($this, $name, $text, $typeShortcut); + $output = $value["obj"]->onParseContentBlock($this, $name, $text, $typeShortcut); if(!is_null($output)) break; } } - if(defined("DEBUG") && DEBUG>=3 && !empty($name)) echo "YellowPage::parseType name:$name shortcut:$typeShortcut
\n"; + if(defined("DEBUG") && DEBUG>=3 && !empty($name)) echo "YellowPage::parseContentBlock name:$name shortcut:$typeShortcut
\n"; return $output; } - // Parse page response - function parseResponse() + // Parse page + function parsePage() { - $this->yellow->template($this->get("template")); + $this->outputData = NULL; + if(!$this->isError()) + { + foreach($this->yellow->plugins->plugins as $key=>$value) + { + if(method_exists($value["obj"], "onParsePage")) $value["obj"]->onParsePage(); + } + } + if(is_null($this->outputData)) + { + ob_start(); + $this->yellow->template($this->get("template")); + $this->outputData = ob_get_contents(); + ob_end_clean(); + } if(!$this->isCacheable()) $this->setHeader("Cache-Control", "no-cache, must-revalidate"); if(!$this->isHeader("Content-Type")) $this->setHeader("Content-Type", "text/html; charset=utf-8"); if(!$this->isHeader("Content-Modified")) $this->setHeader("Content-Modified", $this->getModified(true)); @@ -580,30 +593,17 @@ class YellowPage { $this->error(500, "Parser '".$this->get("parser")."' does not exist!"); } - if($this->statusCode==200 && - !$this->yellow->toolbox->isValidContentType($this->getHeader("Content-Type"), $this->getLocation())) + if($this->yellow->getRequestHandler()=="core" && $this->isExisting("redirect") && $this->statusCode==200) { - $this->error(500, "Type '".$this->getHeader("Content-Type")."' does not match file name!"); + $location = $this->yellow->lookup->normaliseLocation($this->get("redirect"), $this->base, $this->location); + $location = $this->yellow->lookup->normaliseUrl($this->serverScheme, $this->serverName, "", $location); + $this->clean(301, $location); } - if($this->statusCode==200 && $this->yellow->getRequestHandler()=="core" && $this->isExisting("redirect")) + if($this->yellow->getRequestHandler()=="core" && !$this->isAvailable() && $this->statusCode==200) { - $location = $this->yellow->toolbox->normaliseLocation($this->get("redirect"), $this->base, $this->location); - $locationHeader = $this->yellow->toolbox->getLocationHeader($this->serverScheme, $this->serverName, "", $location); - $this->clean(301, $locationHeader); - $this->setHeader("Cache-Control", "no-cache, must-revalidate"); + $this->error(404); } - } - - // Set page response header - function setHeader($key, $value) - { - $this->headerData[$key] = $value; - } - - // Return page response header - function getHeader($key) - { - return $this->isHeader($key) ? $this->headerData[$key] : ""; + if($this->isExisting("pageClean")) $this->page->outputData = NULL; } // Set page meta data @@ -624,10 +624,10 @@ class YellowPage return htmlspecialchars($this->get($key)); } - // Return page meta data as human readable date + // Return page meta data as language specific date function getDate($key, $dateFormat = "") { - if($this->yellow->text->isExisting($dateFormat)) + if(!empty($dateFormat)) { $format = $this->yellow->text->get($dateFormat); } else { @@ -650,17 +650,6 @@ class YellowPage return $text; } - // Return page extra header, HTML encoded - function getHeaderExtra() - { - $header = ""; - foreach($this->yellow->plugins->plugins as $key=>$value) - { - if(method_exists($value["obj"], "onHeaderExtra")) $header .= $value["obj"]->onHeaderExtra($this); - } - return $header; - } - // Return parent page relative to current page, NULL if none function getParent() { @@ -683,13 +672,31 @@ class YellowPage function getSiblings($showInvisible = false) { $parentLocation = $this->yellow->pages->getParentLocation($this->location); - return $this->yellow->pages->findChildren($parentLocation, $showInvisible); + return $this->yellow->pages->getChildren($parentLocation, $showInvisible); } // Return page collection with child pages relative to current page function getChildren($showInvisible = false) { - return $this->yellow->pages->findChildren($this->location, $showInvisible); + return $this->yellow->pages->getChildren($this->location, $showInvisible); + } + + // Return page collection with media files for current page + function getFiles($showInvisible = false) + { + return $this->yellow->files->index($showInvisible, true)->filter("pageFile", $this->get("pageFile")); + } + + // Set page collection with additional pages for current page + function setPages($pages) + { + $this->pages = $pages; + } + + // Return page collection with additional pages for current page + function getPages() + { + return $this->pages; } // Return absolute page location @@ -701,7 +708,36 @@ class YellowPage // Return page URL with server scheme and server name function getUrl() { - return $this->yellow->toolbox->getUrl($this->serverScheme, $this->serverName, $this->base, $this->location); + return $this->yellow->lookup->normaliseUrl($this->serverScheme, $this->serverName, $this->base, $this->location); + } + + // Return page extra HTML data + function getExtra() + { + $output = ""; + foreach($this->yellow->plugins->plugins as $key=>$value) + { + if(method_exists($value["obj"], "onExtra")) $output .= $value["obj"]->onExtra(); + } + return $output; + } + + // Set page response output + function setOutput($output) + { + $this->outputData = $output; + } + + // Set page response header + function setHeader($key, $value) + { + $this->headerData[$key] = $value; + } + + // Return page response header + function getHeader($key) + { + return $this->isHeader($key) ? $this->headerData[$key] : ""; } // Return page content modification date, Unix time or HTTP format @@ -748,23 +784,50 @@ class YellowPage } // Respond with status code, no page content - function clean($statusCode, $responseHeader = "") + function clean($statusCode, $location = "") { if(!$this->isExisting("pageClean") && $statusCode>0) { $this->statusCode = $statusCode; $this->lastModified = 0; $this->headerData = array(); - if(!empty($responseHeader)) $this->header($responseHeader); + if(!empty($location)) + { + $this->setHeader("Location", $location); + $this->setHeader("Cache-Control", "no-cache, must-revalidate"); + } $this->set("pageClean", (string)$statusCode); } } - // Add page response header, HTTP format - function header($responseHeader) + // Check if page is available + function isAvailable() { - $tokens = explode(':', $responseHeader, 2); - $this->setHeader(trim($tokens[0]), trim($tokens[1])); + return $this->available; + } + + // Check if page is visible + function isVisible() + { + return $this->visible; + } + + // Check if page is within current request + function isActive() + { + return $this->active; + } + + // Check if page is cacheable + function isCacheable() + { + return $this->cacheable; + } + + // Check if page with error + function isError() + { + return $this->isExisting("pageError"); } // Check if response header exists @@ -772,36 +835,12 @@ class YellowPage { return !is_null($this->headerData[$key]); } - + // Check if page meta data exists function isExisting($key) { return !is_null($this->metaData[$key]); } - - // Check if page with error - function isError() - { - return $this->isExisting("pageError"); - } - - // Check if page is within current HTTP request - function isActive() - { - return $this->active; - } - - // Check if page is visible in navigation - function isVisible() - { - return $this->visible; - } - - // Check if page is cacheable - function isCacheable() - { - return $this->cacheable; - } } // Yellow page collection as array @@ -809,7 +848,7 @@ class YellowPageCollection extends ArrayObject { var $yellow; //access to API var $filterValue; //current page filter value - var $paginationPage; //current page number in pagination + var $paginationNumber; //current page number in pagination var $paginationCount; //highest page number in pagination function __construct($yellow) @@ -861,6 +900,18 @@ class YellowPageCollection extends ArrayObject return $this; } + // Filter page collection by file + function match($regex = "/.*/") + { + $array = array(); + foreach($this->getArrayCopy() as $page) + { + if(preg_match($regex, basename($page->fileName))) array_push($array, $page); + } + $this->exchangeArray($array); + return $this; + } + // Merge page collection function merge($input) { @@ -910,23 +961,24 @@ class YellowPageCollection extends ArrayObject // Paginate page collection function pagination($limit, $reverse = true) { - $array = $this->getArrayCopy(); - if($reverse) $array = array_reverse($array); - $this->paginationPage = 1; + $this->paginationNumber = 1; $this->paginationCount = ceil($this->count() / $limit); - if($limit < $this->count()) + $pagination = $this->yellow->config->get("contentPagination"); + if(isset($_REQUEST[$pagination])) $this->paginationNumber = intval($_REQUEST[$pagination]); + if($this->paginationNumber > $this->paginationCount) $this->paginationNumber = 0; + if($this->paginationNumber >= 1) { - $pagination = $this->yellow->config->get("contentPagination"); - if(isset($_REQUEST[$pagination])) $this->paginationPage = max(1, $_REQUEST[$pagination]); + $array = $this->getArrayCopy(); + if($reverse) $array = array_reverse($array); + $this->exchangeArray(array_slice($array, ($this->paginationNumber - 1) * $limit, $limit)); } - $this->exchangeArray(array_slice($array, ($this->paginationPage - 1) * $limit, $limit)); return $this; } // Return current page number in pagination - function getPaginationPage() + function getPaginationNumber() { - return $this->paginationPage; + return $this->paginationNumber; } // Return highest page number in pagination @@ -936,7 +988,7 @@ class YellowPageCollection extends ArrayObject } // Return absolute location for a page in pagination - function getLocationPage($pageNumber) + function getPaginationLocation($pageNumber) { if($pageNumber>=1 && $pageNumber<=$this->paginationCount) { @@ -949,19 +1001,19 @@ class YellowPageCollection extends ArrayObject } // Return absolute location for previous page in pagination - function getLocationPrevious() + function getPaginationPrevious() { - $pageNumber = $this->paginationPage; + $pageNumber = $this->paginationNumber; $pageNumber = ($pageNumber>1 && $pageNumber<=$this->paginationCount) ? $pageNumber-1 : 0; - return $this->getLocationPage($pageNumber); + return $this->getPaginationLocation($pageNumber); } // Return absolute location for next page in pagination - function getLocationNext() + function getPaginationNext() { - $pageNumber = $this->paginationPage; + $pageNumber = $this->paginationNumber; $pageNumber = ($pageNumber>=1 && $pageNumber<$this->paginationCount) ? $pageNumber+1 : 0; - return $this->getLocationPage($pageNumber); + return $this->getPaginationLocation($pageNumber); } // Return current page filter @@ -978,26 +1030,14 @@ class YellowPageCollection extends ArrayObject return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($modified) : $modified; } - // Return first page in page collection - function first() - { - return $this->offsetGet(0); - } - - // Return last page in page collection - function last() - { - return $this->offsetGet($this->count()-1); - } - - // Check if there is an active pagination + // Check if there is a pagination function isPagination() { return $this->paginationCount > 1; } } -// Yellow pages from file system +// Yellow pages class YellowPages { var $yellow; //access to API @@ -1011,130 +1051,29 @@ class YellowPages $this->pages = array(); } - // Return page collection with all pages from file system - function index($showInvisible = false, $showMulti = false, $levelMax = 0) - { - $rootLocation = $showMulti ? "" : $this->getRootLocation($this->yellow->page->location); - return $this->findChildrenRecursive($rootLocation, $showInvisible, $levelMax); - } - - // Return page collection with top-level navigation - function top($showInvisible = false) - { - $rootLocation = $this->getRootLocation($this->yellow->page->location); - return $this->findChildren($rootLocation, $showInvisible); - } - - // Return page collection with path ancestry - function path($location, $absoluteLocation = false) - { - $pages = new YellowPageCollection($this->yellow); - if($page = $this->find($location, $absoluteLocation)) - { - $pages->prepend($page); - for(; $parent = $page->getParent(); $page=$parent) $pages->prepend($parent); - $home = $this->find($this->getHomeLocation($page->location)); - if($home && $home->location!=$page->location) $pages->prepend($home); - } - return $pages; - } - - // Return page collection with multiple languages - function multi($location, $absoluteLocation = false, $showInvisible = false) - { - $pages = new YellowPageCollection($this->yellow); - if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); - $postfix = substru($location, strlenu($this->getRootLocation($location)) - 4); - $this->scanChildren(""); - foreach($this->pages[""] as $page) - { - if($content = $this->find(substru($page->location, 4).$postfix)) - { - if($content->isVisible() || $showInvisible) $pages->append($content); - } - } - return $pages; - } - - // Return empty page collection - function create() - { - return new YellowPageCollection($this->yellow); - } - - // Return one page from file system, NULL if not found - function find($location, $absoluteLocation = false) - { - if(!$this->yellow->toolbox->isRootLocation($location)) - { - if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); - $parentLocation = $this->getParentLocation($location); - $this->scanChildren($parentLocation); - foreach($this->pages[$parentLocation] as $page) if($page->location == $location) { $found = true; break; } - } - return $found ? $page : NULL; - } - - // Find child pages - function findChildren($location, $showInvisible = false) - { - $pages = new YellowPageCollection($this->yellow); - $this->scanChildren($location); - foreach($this->pages[$location] as $page) - { - if($page->isVisible() || $showInvisible) - { - if(!$this->yellow->toolbox->isRootLocation($page->location)) $pages->append($page); - } - } - return $pages; - } - - // Find child pages recursively - function findChildrenRecursive($location, $showInvisible = false, $levelMax = 0) - { - --$levelMax; - $pages = new YellowPageCollection($this->yellow); - $this->scanChildren($location); - foreach($this->pages[$location] as $page) - { - if($page->isVisible() || $showInvisible) - { - if(!$this->yellow->toolbox->isRootLocation($page->location)) $pages->append($page); - if(!$this->yellow->toolbox->isFileLocation($page->location) && $levelMax!=0) - { - $pages->merge($this->findChildrenRecursive($page->location, $showInvisible, $levelMax)); - } - } - } - return $pages; - } - - // Scan child pages on demand - function scanChildren($location) + // Scan file system on demand + function scanLocation($location) { if(is_null($this->pages[$location])) { - if(defined("DEBUG") && DEBUG>=2) echo "YellowPages::scanChildren location:$location
\n"; + if(defined("DEBUG") && DEBUG>=2) echo "YellowPages::scanLocation location:$location
\n"; $this->pages[$location] = array(); $serverScheme = $this->yellow->page->serverScheme; $serverName = $this->yellow->page->serverName; $base = $this->yellow->page->base; if(empty($location)) { - $rootLocations = $this->yellow->toolbox->findRootLocations($this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir")); + $rootLocations = $this->yellow->lookup->findRootLocations(); foreach($rootLocations as $rootLocation) { + list($rootLocation, $fileName) = explode(' ', $rootLocation, 2); $page = new YellowPage($this->yellow); - $page->setRequestInformation($serverScheme, $serverName, $base, $rootLocation, ""); - $page->parseData("", false); + $page->setRequestInformation($serverScheme, $serverName, $base, $rootLocation, $fileName); + $page->parseData("", false, 0); array_push($this->pages[$location], $page); } } else { - $fileNames = $this->yellow->toolbox->findChildrenFromLocation($location, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")); + $fileNames = $this->yellow->lookup->findChildrenFromLocation($location); foreach($fileNames as $fileName) { $fileHandle = @fopen($fileName, "r"); @@ -1149,15 +1088,128 @@ class YellowPages } $page = new YellowPage($this->yellow); $page->setRequestInformation($serverScheme, $serverName, $base, - $this->yellow->toolbox->findLocationFromFile($fileName, $this->yellow->config->get("contentDir"), - $this->yellow->config->get("contentRootDir"), $this->yellow->config->get("contentHomeDir"), - $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")), - $fileName); + $this->yellow->lookup->findLocationFromFile($fileName), $fileName); $page->parseData($fileData, false, $statusCode); array_push($this->pages[$location], $page); } } } + return $this->pages[$location]; + } + + // Return page from file system, NULL if not found + function find($location, $absoluteLocation = false) + { + if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); + foreach($this->scanLocation($this->getParentLocation($location)) as $page) + { + if($page->location == $location) + { + if(!$this->yellow->lookup->isRootLocation($page->location)) { $found = true; break; } + } + } + return $found ? $page : NULL; + } + + // Return page collection with all pages + function index($showInvisible = false, $showMultiLanguage = false, $levelMax = 0) + { + $rootLocation = $showMultiLanguage ? "" : $this->getRootLocation($this->yellow->page->location); + return $this->getChildrenRecursive($rootLocation, $showInvisible, $levelMax); + } + + // Return page collection with top-level navigation + function top($showInvisible = false) + { + $rootLocation = $this->getRootLocation($this->yellow->page->location); + return $this->getChildren($rootLocation, $showInvisible); + } + + // Return page collection with path ancestry + function path($location, $absoluteLocation = false) + { + $pages = new YellowPageCollection($this->yellow); + if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); + if($page = $this->find($location)) + { + $pages->prepend($page); + for(; $parent = $page->getParent(); $page=$parent) $pages->prepend($parent); + $home = $this->find($this->getHomeLocation($page->location)); + if($home && $home->location!=$page->location) $pages->prepend($home); + } + return $pages; + } + + // Return page collection with multiple languages + function multi($location, $absoluteLocation = false, $showInvisible = false) + { + $pages = new YellowPageCollection($this->yellow); + if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); + $locationEnd = substru($location, strlenu($this->getRootLocation($location)) - 4); + foreach($this->scanLocation("") as $page) + { + if($content = $this->find(substru($page->location, 4).$locationEnd)) + { + if($content->isAvailable() && ($content->isVisible() || $showInvisible)) + { + if(!$this->yellow->lookup->isRootLocation($content->location)) $pages->append($content); + } + } + } + return $pages; + } + + // Return page collection that's empty + function clean() + { + return new YellowPageCollection($this->yellow); + } + + // Return available languages + function getLanguages($showInvisible = false) + { + $languages = array(); + foreach($this->scanLocation("") as $page) + { + if($page->isAvailable() && ($page->isVisible() || $showInvisible)) + { + array_push($languages, $page->get("language")); + } + } + return $languages; + } + + // Return child pages + function getChildren($location, $showInvisible = false) + { + $pages = new YellowPageCollection($this->yellow); + foreach($this->scanLocation($location) as $page) + { + if($page->isAvailable() && ($page->isVisible() || $showInvisible)) + { + if(!$this->yellow->lookup->isRootLocation($page->location)) $pages->append($page); + } + } + return $pages; + } + + // Return child pages recursively + function getChildrenRecursive($location, $showInvisible = false, $levelMax = 0) + { + --$levelMax; + $pages = new YellowPageCollection($this->yellow); + foreach($this->scanLocation($location) as $page) + { + if($page->isAvailable() && ($page->isVisible() || $showInvisible)) + { + if(!$this->yellow->lookup->isRootLocation($page->location)) $pages->append($page); + if(!$this->yellow->lookup->isFileLocation($page->location) && $levelMax!=0) + { + $pages->merge($this->getChildrenRecursive($page->location, $showInvisible, $levelMax)); + } + } + } + return $pages; } // Return root location @@ -1166,8 +1218,7 @@ class YellowPages $rootLocation = "root/"; if($this->yellow->config->get("multiLanguageMode")) { - $this->scanChildren(""); - foreach($this->pages[""] as $page) + foreach($this->scanLocation("") as $page) { $token = substru($page->location, 4); if($token!="/" && substru($location, 0, strlenu($token))==$token) { $rootLocation = "root$token"; break; } @@ -1185,24 +1236,225 @@ class YellowPages // Return parent location function getParentLocation($location) { - $prefix = rtrim(substru($this->getRootLocation($location), 4), '/'); - if(preg_match("#^($prefix.*\/).+?$#", $location, $matches)) + $token = rtrim(substru($this->getRootLocation($location), 4), '/'); + if(preg_match("#^($token.*\/).+?$#", $location, $matches)) { - if($matches[1]!="$prefix/" || $this->yellow->toolbox->isFileLocation($location)) $parentLocation = $matches[1]; + if($matches[1]!="$token/" || $this->yellow->lookup->isFileLocation($location)) $parentLocation = $matches[1]; } - if(empty($parentLocation)) $parentLocation = "root$prefix/"; + if(empty($parentLocation)) $parentLocation = "root$token/"; return $parentLocation; } // Return top-level location function getParentTopLocation($location) { - $prefix = rtrim(substru($this->getRootLocation($location), 4), '/'); - if(preg_match("#^($prefix.+?\/)#", $location, $matches)) $parentTopLocation = $matches[1]; - if(empty($parentTopLocation)) $parentTopLocation = "$prefix/"; + $token = rtrim(substru($this->getRootLocation($location), 4), '/'); + if(preg_match("#^($token.+?\/)#", $location, $matches)) $parentTopLocation = $matches[1]; + if(empty($parentTopLocation)) $parentTopLocation = "$token/"; return $parentTopLocation; } } + +// Yellow files +class YellowFiles +{ + var $yellow; //access to API + var $files; //scanned files + + function __construct($yellow) + { + $this->yellow = $yellow; + $this->files = array(); + } + + // Scan file system on demand + function scanLocation($location) + { + if(is_null($this->files[$location])) + { + if(defined("DEBUG") && DEBUG>=2) echo "YellowFiles::scanLocation location:$location
\n"; + $this->files[$location] = array(); + $serverScheme = $this->yellow->page->serverScheme; + $serverName = $this->yellow->page->serverName; + $base = $this->yellow->page->base; + if(empty($location)) + { + $fileNames = array($this->yellow->config->get("mediaDir")); + } else { + $fileNames = array(); + $path = substru($location, 1); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, true) as $entry) + { + array_push($fileNames, $entry."/"); + } + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, false, true) as $entry) + { + array_push($fileNames, $entry); + } + } + foreach($fileNames as $fileName) + { + $file = new YellowPage($this->yellow); + $file->setRequestInformation($serverScheme, $serverName, $base, "/".$fileName, $fileName); + $file->parseData(NULL, false, 0); + array_push($this->files[$location], $file); + } + } + return $this->files[$location]; + } + + // Return page with media file information, NULL if not found + function find($location, $absoluteLocation = false) + { + if($absoluteLocation) $location = substru($location, strlenu($this->yellow->page->base)); + foreach($this->scanLocation($this->getParentLocation($location)) as $file) + { + if($file->location == $location) { $found = true; break; } + } + return $found ? $file : NULL; + } + + // Return page collection with all media files + function index($showInvisible = false, $showMultiPass = false, $levelMax = 0) + { + return $this->getChildrenRecursive("", $showInvisible, $levelMax); + } + + // Return page collection that's empty + function clean() + { + return new YellowPageCollection($this->yellow); + } + + // Return child files + function getChildren($location, $showInvisible = false) + { + $files = new YellowPageCollection($this->yellow); + foreach($this->scanLocation($location) as $file) + { + if($file->isAvailable() && ($file->isVisible() || $showInvisible)) + { + $files->append($file); + } + } + return $files; + } + + // Return child files recursively + function getChildrenRecursive($location, $showInvisible = false, $levelMax = 0) + { + --$levelMax; + $files = new YellowPageCollection($this->yellow); + foreach($this->scanLocation($location) as $file) + { + if($file->isAvailable() && ($file->isVisible() || $showInvisible)) + { + $files->append($file); + if(!$this->yellow->lookup->isFileLocation($file->location) && $levelMax!=0) + { + $files->merge($this->getChildrenRecursive($file->location, $showInvisible, $levelMax)); + } + } + } + return $files; + } + + // Return home location + function getHomeLocation($location) + { + return "/".$this->yellow->config->get("mediaDir"); + } + + // Return parent location + function getParentLocation($location) + { + $token = rtrim("/".$this->yellow->config->get("mediaDir"), '/'); + if(preg_match("#^($token.*\/).+?$#", $location, $matches)) + { + if($matches[1]!="$token/" || $this->yellow->lookup->isFileLocation($location)) $parentLocation = $matches[1]; + } + if(empty($parentLocation)) $parentLocation = ""; + return $parentLocation; + } + + // Return top-level location + function getParentTopLocation($location) + { + $token = rtrim("/".$this->yellow->config->get("mediaDir"), '/'); + if(preg_match("#^($token.+?\/)#", $location, $matches)) $parentTopLocation = $matches[1]; + if(empty($parentTopLocation)) $parentTopLocation = "$token/"; + return $parentTopLocation; + } +} + +// Yellow plugins +class YellowPlugins +{ + var $yellow; //access to API + var $plugins; //registered plugins + var $modified; //plugin modification date + + function __construct($yellow) + { + $this->yellow = $yellow; + $this->plugins = array(); + $this->modified = 0; + } + + // Load plugins + function load() + { + $path = $this->yellow->config->get("coreDir"); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^core-.*\.php$/", true, false) as $entry) + { + $this->modified = max($this->modified, filemtime($entry)); + global $yellow; + require_once($entry); + } + $path = $this->yellow->config->get("pluginDir"); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.php$/", true, false) as $entry) + { + $this->modified = max($this->modified, filemtime($entry)); + global $yellow; + require_once($entry); + } + foreach($this->plugins as $key=>$value) + { + $this->plugins[$key]["obj"] = new $value["class"]; + if(defined("DEBUG") && DEBUG>=3) echo "YellowPlugins::load class:$value[class] $value[version]
\n"; + if(method_exists($this->plugins[$key]["obj"], "onLoad")) $this->plugins[$key]["obj"]->onLoad($yellow); + } + } + + // Register plugin + function register($name, $class, $version) + { + if(!$this->isExisting($name)) + { + $this->plugins[$name] = array(); + $this->plugins[$name]["class"] = $class; + $this->plugins[$name]["version"] = $version; + } + } + + // Return plugin + function get($name) + { + return $this->plugins[$name]["obj"]; + } + + // Return plugins modification date, Unix time or HTTP format + function getModified($httpFormat = false) + { + return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($this->modified) : $this->modified; + } + + // Check if plugin exists + function isExisting($name) + { + return !is_null($this->plugins[$name]); + } +} // Yellow configuration class YellowConfig @@ -1455,66 +1707,393 @@ class YellowText return !is_null($this->text[$language]) && !is_null($this->text[$language][$key]); } } - -// Yellow plugins -class YellowPlugins -{ - var $plugins; //registered plugins - var $modified; //plugin modification date - function __construct() +// Yellow location and file lookup +class YellowLookup +{ + var $yellow; //access to API + + function __construct($yellow) { - $this->plugins = array(); - $this->modified = 0; + $this->yellow = $yellow; } - // Load plugins - function load() + // Return root locations + function findRootLocations($includePath = true) { - global $yellow; - $path = $yellow->config->get("coreDir"); - foreach($yellow->toolbox->getDirectoryEntries($path, "/^core-.*\.php$/", true, false) as $entry) require_once($entry); - $path = $yellow->config->get("pluginDir"); - foreach($yellow->toolbox->getDirectoryEntries($path, "/^.*\.php$/", true, false) as $entry) + $locations = array(); + $pathBase = $this->yellow->config->get("contentDir"); + $pathRoot = $this->yellow->config->get("contentRootDir"); + if(!empty($pathRoot)) { - $this->modified = max($this->modified, filemtime($entry)); - require_once($entry); + foreach($this->yellow->toolbox->getDirectoryEntries($pathBase, "/.*/", true, true, false) as $entry) + { + $token = $this->normaliseName($entry)."/"; + if($token == $pathRoot) $token = ""; + array_push($locations, $includePath ? "root/$token $pathBase$entry/" : "root/$token"); + if(defined("DEBUG") && DEBUG>=2) echo "YellowLookup::findRootLocations root/$token
\n"; + } + } else { + array_push($locations, $includePath ? "root/ $pathBase" : "root/"); } - foreach($this->plugins as $key=>$value) + return $locations; + } + + // Return location from file path + function findLocationFromFile($fileName) + { + $location = "/"; + $pathBase = $this->yellow->config->get("contentDir"); + $pathRoot = $this->yellow->config->get("contentRootDir"); + $pathHome = $this->yellow->config->get("contentHomeDir"); + $fileDefault = $this->yellow->config->get("contentDefaultFile"); + $fileExtension = $this->yellow->config->get("contentExtension"); + if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) { - $this->plugins[$key]["obj"] = new $value["class"]; - if(defined("DEBUG") && DEBUG>=3) echo "YellowPlugins::load class:$value[class] $value[version]
\n"; - if(method_exists($this->plugins[$key]["obj"], "onLoad")) $this->plugins[$key]["obj"]->onLoad($yellow); + $fileName = substru($fileName, strlenu($pathBase)); + $tokens = explode('/', $fileName); + if(!empty($pathRoot)) + { + $token = $this->normaliseName($tokens[0]).'/'; + if($token!=$pathRoot) $location .= $token; + array_shift($tokens); + } + for($i=0; $inormaliseName($tokens[$i]).'/'; + if($i || $token!=$pathHome) $location .= $token; + } + $token = $this->normaliseName($tokens[$i]); + $fileFolder = $this->normaliseName($tokens[$i-1]).$fileExtension; + if($token!=$fileDefault && $token!=$fileFolder) $location .= $this->normaliseName($tokens[$i], true, true); + $extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos) : ""; + if($extension != $fileExtension) $invalid = true; + } else { + $invalid = true; } - } - - // Register plugin - function register($name, $class, $version) - { - if(!$this->isExisting($name)) + if(defined("DEBUG") && DEBUG>=2) { - $this->plugins[$name] = array(); - $this->plugins[$name]["class"] = $class; - $this->plugins[$name]["version"] = $version; + $debug = ($invalid ? "INVALID" : $location)." <- $pathBase$fileName"; + echo "YellowLookup::findLocationFromFile $debug
\n"; } + return $invalid ? "" : $location; } - // Return plugin object - function get($name) + // Return file path from location + function findFileFromLocation($location, $directory = false) { - return $this->plugins[$name]["obj"]; + $path = $pathBase = $this->yellow->config->get("contentDir"); + $pathRoot = $this->yellow->config->get("contentRootDir"); + $pathHome = $this->yellow->config->get("contentHomeDir"); + $fileDefault = $this->yellow->config->get("contentDefaultFile"); + $fileExtension = $this->yellow->config->get("contentExtension"); + $tokens = explode('/', $location); + if($this->isRootLocation($location)) + { + if(!empty($pathRoot)) + { + $token = (count($tokens) > 2) ? $tokens[1] : rtrim($pathRoot, '/'); + $path .= $this->findFileDirectory($path, $token, true, true, $found, $invalid); + } + } else { + if(!empty($pathRoot)) + { + if(count($tokens) > 2) + { + if($this->normaliseName($tokens[1]) == $this->normaliseName($pathRoot)) $invalid = true; + $path .= $this->findFileDirectory($path, $tokens[1], false, true, $found, $invalid); + if($found) array_shift($tokens); + } + if(!$found) $path .= $this->findFileDirectory($path, rtrim($pathRoot, '/'), true, true, $found, $invalid); + + } + if(count($tokens) > 2) + { + if($this->normaliseName($tokens[1]) == $this->normaliseName($pathHome)) $invalid = true; + for($i=1; $ifindFileDirectory($path, $tokens[$i], true, true, $found, $invalid); + } + } else { + $i = 1; + $tokens[0] = rtrim($pathHome, '/'); + $path .= $this->findFileDirectory($path, $tokens[0], true, true, $found, $invalid); + } + if(!$directory) + { + $fileFolder = $tokens[$i-1].$fileExtension; + if(!empty($tokens[$i])) + { + $token = $tokens[$i].$fileExtension; + if($token==$fileDefault || $token==$fileFolder) $invalid = true; + $path .= $this->findFileDirectory($path, $token, true, false, $found, $invalid); + } else { + $path .= $this->findFileDefault($path, $fileDefault, $fileFolder); + } + if(defined("DEBUG") && DEBUG>=2) + { + $debug = "$location -> ".($invalid ? "INVALID" : $path); + echo "YellowLookup::findFileFromLocation $debug
\n"; + } + } + } + return $invalid ? "" : $path; } - // Return plugins modification date, Unix time or HTTP format - function getModified($httpFormat = false) + // Return file or directory that matches token + function findFileDirectory($path, $token, $tokenFailback, $directory, &$found, &$invalid) { - return $httpFormat ? $this->yellow->toolbox->getHttpDateFormatted($this->modified) : $this->modified; + if($this->normaliseName($token) != $token) $invalid = true; + if(!$invalid) + { + $regex = "/^[\d\-\_\.]*".strreplaceu('-', '.', $token)."$/"; + foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, false, $directory, false) as $entry) + { + if($this->normaliseName($entry) == $token) { $token = $entry; $found = true; break; } + } + } + if($directory) $token .= '/'; + return ($tokenFailback || $found) ? $token : ""; } - // Check if plugin exists - function isExisting($name) + // Return default file in directory + function findFileDefault($path, $fileDefault, $fileFolder) { - return !is_null($this->plugins[$name]); + $token = $fileDefault; + if(!is_file($path."/".$fileDefault)) + { + $regex = "/^[\d\-\_\.]*($fileDefault|$fileFolder)$/"; + foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false, false) as $entry) + { + if($this->normaliseName($entry) == $fileDefault) { $token = $entry; break; } + if($this->normaliseName($entry) == $fileFolder) { $token = $entry; break; } + } + } + return $token; + } + + // Return children from location + function findChildrenFromLocation($location) + { + $fileNames = array(); + $fileDefault = $this->yellow->config->get("contentDefaultFile"); + $fileExtension = $this->yellow->config->get("contentExtension"); + if(!$this->isFileLocation($location)) + { + $path = $this->findFileFromLocation($location, true); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, false) as $entry) + { + $fileFolder = $this->normaliseName($entry).$fileExtension; + $token = $this->findFileDefault($path.$entry, $fileDefault, $fileFolder); + array_push($fileNames, $path.$entry."/".$token); + } + if(!$this->isRootLocation($location)) + { + $fileFolder = $this->normaliseName(basename($path)).$fileExtension; + $regex = "/^.*\\".$fileExtension."$/"; + foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false, false) as $entry) + { + if($this->normaliseName($entry) == $fileDefault) continue; + if($this->normaliseName($entry) == $fileFolder) continue; + if($this->normaliseName($entry, true, true) == "") continue; + array_push($fileNames, $path.$entry); + } + } + } + return $fileNames; + } + + // Return language from file path + function findLanguageFromFile($fileName, $languageDefault) + { + $language = $languageDefault; + $pathBase = $this->yellow->config->get("contentDir"); + $pathRoot = $this->yellow->config->get("contentRootDir"); + if(!empty($pathRoot)) + { + $fileName = substru($fileName, strlenu($pathBase)); + if(preg_match("/^(.+?)\//", $fileName, $matches)) $name = $this->normaliseName($matches[1]); + if(strlenu($name) == 2) $language = $name; + } + return $language; + } + + // Return theme/template name from file path + function findNameFromFile($fileName, $pathBase, $nameDefault, $fileExtension) + { + $name = ""; + if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]); + if(!is_file("$pathBase$name$fileExtension")) $name = $this->normaliseName($nameDefault); + return $name; + } + + // Return file path for new page + function findFileNew($fileName, $pathBase, $fileNew, $fileDefault) + { + if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]); + $fileName = strreplaceu("(.*)", $name, $pathBase.$fileNew); + if(!is_file($fileName)) + { + $name = $this->normaliseName($fileDefault, true, true); + $fileName = strreplaceu("(.*)", $name, $pathBase.$fileNew); + } + return $fileName; + } + + // Return file path from title + function findFileFromTitle($titlePrefix, $titleText, $fileName, $fileDefault, $fileExtension) + { + preg_match("/^([\d\-\_\.]*)(.*)$/", $titlePrefix, $matches); + if(preg_match("/\d$/", $matches[1])) $matches[1] .= '-'; + $titleText = $this->normaliseName($titleText, false, false, true); + preg_match("/^([\d\-\_\.]*)(.*)$/", $matches[1].$titleText, $matches); + $fileNamePrefix = $matches[1]; + $fileNameText = empty($matches[2]) ? $fileDefault : $matches[2].$fileExtension; + return dirname($fileName)."/".$fileNamePrefix.$fileNameText; + } + + // Normalise file/directory/other name + function normaliseName($text, $removePrefix = true, $removeExtension = false, $filterStrict = false) + { + if($removeExtension) $text = ($pos = strrposu($text, '.')) ? substru($text, 0, $pos) : $text; + if($removePrefix) if(preg_match("/^[\d\-\_\.]+(.*)$/", $text, $matches)) $text = $matches[1]; + if($filterStrict) $text = strreplaceu('.', '-', strtoloweru($text)); + return preg_replace("/[^\pL\d\-\_\.]/u", "-", rtrim($text, '/')); + } + + // Normalise content/media file name + function normaliseFile($fileName, $convertExtension = false) + { + $fileName = basename($fileName); + if($convertExtension) + { + $fileName = ($pos = strposu($fileName, '.')) ? substru($fileName, 0, $pos) : $fileName; + $fileName .= $this->yellow->config->get("contentExtension"); + } + return $fileName; + } + + // Normalise location, make absolute location + function normaliseLocation($location, $pageBase, $pageLocation, $staticLocation = "", $filterStrict = true) + { + if(!preg_match("/^\w+:/", trim(html_entity_decode($location, ENT_QUOTES, "UTF-8")))) + { + if(empty($staticLocation) || !preg_match("#^$staticLocation#", $location)) + { + if(preg_match("/^\#/", $location)) + { + $location = $pageBase.$pageLocation.$location; + } else if(!preg_match("/^\//", $location)) { + $location = $this->getDirectoryLocation($pageBase.$pageLocation).$location; + } else if(!preg_match("#^$pageBase#", $location)) { + $location = $pageBase.$location; + } + } + } else { + if($filterStrict && !preg_match("/^(http|https|ftp|mailto):/", $location)) $location = "error-xss-filter"; + } + return $location; + } + + // Normalise URL, make absolute URL + function normaliseUrl($serverScheme, $serverName, $base, $location) + { + if(!preg_match("/^\w+:/", $location)) + { + $url = "$serverScheme://$serverName$base$location"; + } else { + $url = $location; + } + return $url; + } + + // Return content information + function getContentInformation() + { + $path = $pathBase = $this->yellow->config->get("contentDir"); + $pathRoot = $this->yellow->config->get("contentRootDir"); + $pathHome = $this->yellow->config->get("contentHomeDir"); + if(!$this->yellow->config->get("multiLanguageMode")) $pathRoot = ""; + if(!empty($pathRoot)) + { + $token = $root = rtrim($pathRoot, '/'); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, false) as $entry) + { + if(empty($firstRoot)) { $firstRoot = $token = $entry; } + if($this->normaliseName($entry) == $root) { $token = $entry; break; } + } + $pathRoot = $this->normaliseName($token)."/"; + $path .= "$firstRoot/"; + } + if(!empty($pathHome)) + { + $token = $home = rtrim($pathHome, '/'); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, false) as $entry) + { + if(empty($firstHome)) { $firstHome = $token = $entry; } + if($this->normaliseName($entry) == $home) { $token = $entry; break; } + } + $pathHome = $this->normaliseName($token)."/"; + } + return array($pathRoot, $pathHome); + } + + // Return directory location + function getDirectoryLocation($location) + { + return ($pos = strrposu($location, '/')) ? substru($location, 0, $pos+1) : "/"; + } + + // Check if location is specifying root + function isRootLocation($location) + { + return $location[0] != "/"; + } + + // Check if location is specifying file or directory + function isFileLocation($location) + { + return substru($location, -1, 1) != "/"; + } + + // Check if location is visible + function isVisibleLocation($location, $fileName) + { + $visible = true; + $pathBase = $this->yellow->config->get("contentDir"); + if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) + { + $fileName = substru($fileName, strlenu($pathBase)); + $tokens = explode('/', $fileName); + for($i=0; $iyellow->pages->getHomeLocation($currentLocation)) + { + $active = substru($currentLocation, 0, strlenu($location))==$location; + } else { + $active = $this->getDirectoryLocation($currentLocation)==$location; + } + return $active; + } + + // Check if location is valid + function isValidLocation($location) + { + $string = ""; + $tokens = explode('/', $location); + for($i=1; $inormaliseName($tokens[$i]); + return $location == $string; } } @@ -1578,7 +2157,8 @@ class YellowToolbox } if(preg_match("/^(.*?\/)([^\/]+:.*)$/", $location, $matches)) { - $location = $matches[1]; + $_SERVER["LOCATION"] = $location = $matches[1]; + $_SERVER["LOCATION_ARGS"] = $matches[2]; foreach(explode('/', $matches[2]) as $token) { preg_match("/^(.*?):(.*)$/", $token, $matches); @@ -1597,25 +2177,21 @@ class YellowToolbox // Return location arguments from current HTTP request function getLocationArgs() { - if(preg_match("/^(.*?\/)([^\/]+:.*)$/", $this->getLocation(), $matches)) $locationArgs = $matches[2]; - return $locationArgs; + return $_SERVER["LOCATION_ARGS"]; } // Return location arguments from current HTTP request, modify an argument function getLocationArgsNew($arg, $pagination) { preg_match("/^(.*?):(.*)$/", $arg, $args); - if(preg_match("/^(.*?\/)([^\/]+:.*)$/", $this->getLocation(), $matches)) + foreach(explode('/', $_SERVER["LOCATION_ARGS"]) as $token) { - foreach(explode('/', $matches[2]) as $token) + preg_match("/^(.*?):(.*)$/", $token, $matches); + if($matches[1] == $args[1]) { $matches[2] = $args[2]; $found = true; } + if(!empty($matches[1]) && !strempty($matches[2])) { - preg_match("/^(.*?):(.*)$/", $token, $matches); - if($matches[1] == $args[1]) { $matches[2] = $args[2]; $found = true; } - if(!empty($matches[1]) && !strempty($matches[2])) - { - if(!empty($locationArgs)) $locationArgs .= '/'; - $locationArgs .= "$matches[1]:$matches[2]"; - } + if(!empty($locationArgs)) $locationArgs .= '/'; + $locationArgs .= "$matches[1]:$matches[2]"; } } if(!$found && !empty($args[1]) && !strempty($args[2])) @@ -1625,7 +2201,7 @@ class YellowToolbox } if(!empty($locationArgs)) { - if(!$this->isPaginationLocation($locationArgs, $pagination)) $locationArgs .= '/'; + if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; $locationArgs = $this->normaliseArgs($locationArgs, false, false); } return $locationArgs; @@ -1646,419 +2222,34 @@ class YellowToolbox } if(!empty($locationArgs)) { - if(!$this->isPaginationLocation($locationArgs, $pagination)) $locationArgs .= '/'; + if(!$this->isLocationArgsPagination($locationArgs, $pagination)) $locationArgs .= '/'; $locationArgs = $this->normaliseArgs($locationArgs, false, false); } return $locationArgs; } - // Return location header with URL - function getLocationHeader($serverScheme, $serverName, $base, $location) - { - return "Location: ".$this->getUrl($serverScheme, $serverName, $base, $location); - } - // Check if location contains location arguments function isLocationArgs($location) { return preg_match("/[^\/]+:.*$/", $location); } - // Check if location contains pagination - function isPaginationLocation($location, $pagination) + // Check if location contains pagination arguments + function isLocationArgsPagination($location, $pagination) { - return preg_match("/^(.*\/)?$pagination:\d*$/", $location); + return preg_match("/^(.*\/)?$pagination:.*$/", $location); } - // Check if location is specifying root - function isRootLocation($location) - { - return $location[0] != "/"; - } - - // Check if location is specifying file or directory - function isFileLocation($location) - { - return substru($location, -1, 1) != "/"; - } - - // Check if file is unmodified since last HTTP request - function isFileNotModified($lastModifiedFormatted) - { - return isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$lastModifiedFormatted; - } - // Check if clean URL is requested function isRequestCleanUrl($location) { - return (isset($_GET["clean-url"]) || isset($_POST["clean-url"])) && !$this->isFileLocation($location); - } - - // Check if content type is valid for location - function isValidContentType($contentType, $location) - { - $ok = false; - $extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : ""; - $tokens = explode(';', $contentType); - if($tokens[0] == "text/html") - { - if($this->isFileLocation($location)) - { - if(empty($extension) || preg_match("/^\.(html|md)$/", $extension)) $ok = true; - } else { - $ok = true; - } - } else { - if($this->isFileLocation($location)) - { - if(!empty($extension) && preg_match("/^.*$extension$/", $tokens[0])) $ok = true; - } - } - return $ok; - } - - // Check if location is valid - function isValidLocation($location) - { - $string = ""; - $tokens = explode('/', $location); - for($i=1; $inormaliseName($tokens[$i]); - return $location == $string; - } - - // Check if location is within current HTTP request - function isActiveLocation($location, $currentLocation, $homeLocation) - { - if($location != $homeLocation) - { - $active = substru($currentLocation, 0, strlenu($location))==$location; - } else { - $active = $this->getDirectoryLocation($currentLocation)==$location; - } - return $active; - } - - // Check if location is visible in navigation - function isVisibleLocation($location, $fileName, $pathBase) - { - $visible = true; - if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) - { - $fileName = substru($fileName, strlenu($pathBase)); - $tokens = explode('/', $fileName); - for($i=0; $igetDirectoryEntries($path, "/.*/", true, true, false) as $entry) - { - if(empty($firstRoot)) { $firstRoot = $token = $entry; } - if($this->normaliseName($entry) == $root) { $token = $entry; break; } - } - $pathRoot = $this->normaliseName($token)."/"; - $path .= "$firstRoot/"; - } - if(!empty($pathHome)) - { - $token = $home = rtrim($pathHome, '/'); - foreach($this->getDirectoryEntries($path, "/.*/", true, true, false) as $entry) - { - if(empty($firstHome)) { $firstHome = $token = $entry; } - if($this->normaliseName($entry) == $home) { $token = $entry; break; } - } - $pathHome = $this->normaliseName($token)."/"; - } - return array($pathRoot, $pathHome); - } - - // Return root languages - function findRootLanguages($pathBase, $pathRoot, $includeInvisible = false) - { - $languages = array(); - if(!empty($pathRoot)) - { - foreach($this->getDirectoryEntries($pathBase, "/.*/", true, true, false) as $entry) - { - if($includeInvisible || preg_match("/^[\d\-\_\.]+(.*)$/", $entry)) - { - $token = $this->normaliseName($entry); - if(strlenu($token) == 2) array_push($languages, $token); - } - } - } - return $languages; - } - - // Return root locations - function findRootLocations($pathBase, $pathRoot) - { - $locations = array("root/"); - if(!empty($pathRoot)) - { - $root = rtrim($pathRoot, '/'); - foreach($this->getDirectoryEntries($pathBase, "/.*/", true, true, false) as $entry) - { - $token = $this->normaliseName($entry); - if($token != $root) array_push($locations, "root/$token/"); - } - } - return $locations; - } - - // Return location from file path - function findLocationFromFile($fileName, $pathBase, $pathRoot, $pathHome, $fileDefault, $fileExtension) - { - $location = "/"; - if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) - { - $fileName = substru($fileName, strlenu($pathBase)); - $tokens = explode('/', $fileName); - if(!empty($pathRoot)) - { - $token = $this->normaliseName($tokens[0]).'/'; - if($token!=$pathRoot) $location .= $token; - array_shift($tokens); - } - for($i=0; $inormaliseName($tokens[$i]).'/'; - if($i || $token!=$pathHome) $location .= $token; - } - $token = $this->normaliseName($tokens[$i]); - $fileFolder = $this->normaliseName($tokens[$i-1]).$fileExtension; - if($token!=$fileDefault && $token!=$fileFolder) $location .= $this->normaliseName($tokens[$i], true, true); - $extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos) : ""; - if($extension != $fileExtension) $invalid = true; - } else { - $invalid = true; - } - if(defined("DEBUG") && DEBUG>=2) - { - $debug = ($invalid ? "INVALID" : $location)." <- $pathBase$fileName"; - echo "YellowToolbox::findLocationFromFile $debug
\n"; - } - return $invalid ? "" : $location; - } - - // Return file path from location - function findFileFromLocation($location, $pathBase, $pathRoot, $pathHome, $fileDefault, $fileExtension) - { - $path = $pathBase; - $tokens = explode('/', $location); - if($this->isRootLocation($location)) - { - if(!empty($pathRoot)) - { - $token = (count($tokens) > 2) ? $tokens[1] : rtrim($pathRoot, '/'); - $path .= $this->findFileDirectory($path, $token, true, true, $found, $invalid); - } - } else { - if(!empty($pathRoot)) - { - if(count($tokens) > 2) - { - if($this->normaliseName($tokens[1]) == $this->normaliseName($pathRoot)) $invalid = true; - $path .= $this->findFileDirectory($path, $tokens[1], false, true, $found, $invalid); - if($found) array_shift($tokens); - } - if(!$found) $path .= $this->findFileDirectory($path, rtrim($pathRoot, '/'), true, true, $found, $invalid); - - } - if(count($tokens) > 2) - { - if($this->normaliseName($tokens[1]) == $this->normaliseName($pathHome)) $invalid = true; - for($i=1; $ifindFileDirectory($path, $tokens[$i], true, true, $found, $invalid); - } - } else { - $i = 1; - $tokens[0] = rtrim($pathHome, '/'); - $path .= $this->findFileDirectory($path, $tokens[0], true, true, $found, $invalid); - } - if(!empty($fileDefault) && !empty($fileExtension)) - { - $fileFolder = $tokens[$i-1].$fileExtension; - if(!empty($tokens[$i])) - { - $token = $tokens[$i].$fileExtension; - if($token==$fileDefault || $token==$fileFolder) $invalid = true; - $path .= $this->findFileDirectory($path, $token, true, false, $found, $invalid); - } else { - $path .= $this->findFileDefault($path, $fileDefault, $fileFolder); - } - if(defined("DEBUG") && DEBUG>=2) - { - $debug = "$location -> ".($invalid ? "INVALID" : $path); - echo "YellowToolbox::findFileFromLocation $debug
\n"; - } - } - } - return $invalid ? "" : $path; - } - - // Return static file path from location - function findStaticFileFromLocation($location, $path, $fileDefault) - { - $path = rtrim($path, '/').$location; - if(!$this->isFileLocation($location)) $path .= $fileDefault; - return $path; + return (isset($_GET["clean-url"]) || isset($_POST["clean-url"])) && substru($location, -1, 1)=="/"; } - // Return file or directory that matches token - function findFileDirectory($path, $token, $tokenFailback, $directory, &$found, &$invalid) + // Check if unmodified since last HTTP request + function isRequestNotModified($lastModifiedFormatted) { - if($this->normaliseName($token) != $token) $invalid = true; - if(!$invalid) - { - $regex = "/^[\d\-\_\.]*".strreplaceu('-', '.', $token)."$/"; - foreach($this->getDirectoryEntries($path, $regex, false, $directory, false) as $entry) - { - if($this->normaliseName($entry) == $token) { $token = $entry; $found = true; break; } - } - } - if($directory) $token .= '/'; - return ($tokenFailback || $found) ? $token : ""; - } - - // Return default file in directory - function findFileDefault($path, $fileDefault, $fileFolder) - { - $token = $fileDefault; - if(!is_file($path."/".$fileDefault)) - { - $regex = "/^[\d\-\_\.]*($fileDefault|$fileFolder)$/"; - foreach($this->getDirectoryEntries($path, $regex, true, false, false) as $entry) - { - if($this->normaliseName($entry) == $fileDefault) { $token = $entry; break; } - if($this->normaliseName($entry) == $fileFolder) { $token = $entry; break; } - } - } - return $token; - } - - // Return children from location - function findChildrenFromLocation($location, $pathBase, $pathRoot, $pathHome, $fileDefault, $fileExtension) - { - $fileNames = array(); - if(!$this->isFileLocation($location)) - { - $path = $this->findFileFromLocation($location, $pathBase, $pathRoot, $pathHome, "", ""); - foreach($this->getDirectoryEntries($path, "/.*/", true, true, false) as $entry) - { - $fileFolder = $this->normaliseName($entry).$fileExtension; - $token = $this->findFileDefault($path.$entry, $fileDefault, $fileFolder); - array_push($fileNames, $path.$entry."/".$token); - } - if(!$this->isRootLocation($location)) - { - $fileFolder = $this->normaliseName(basename($path)).$fileExtension; - $regex = "/^.*\\".$fileExtension."$/"; - foreach($this->getDirectoryEntries($path, $regex, true, false, false) as $entry) - { - if($this->normaliseName($entry) == $fileDefault) continue; - if($this->normaliseName($entry) == $fileFolder) continue; - if($this->normaliseName($entry, true, true) == "") continue; - array_push($fileNames, $path.$entry); - } - } - } - return $fileNames; - } - - // Return modification date from file path, Unix time - function findModifiedFromFile($fileName) - { - $modified = is_readable($fileName) ? filemtime($fileName) : 0; - if($modified == 0) - { - $path = dirname($fileName); - $modified = is_readable($path) ? filemtime($path) : 0; - } - return $modified; - } - - // Return theme/template name from file path - function findNameFromFile($fileName, $pathBase, $nameDefault, $fileExtension) - { - $name = ""; - if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]); - if(!is_file("$pathBase$name$fileExtension")) $name = $this->normaliseName($nameDefault); - return $name; - } - - // Return language from file path - function findLanguageFromFile($fileName, $pathBase, $pathRoot, $languageDefault) - { - $language = $languageDefault; - if(!empty($pathRoot)) - { - $fileName = substru($fileName, strlenu($pathBase)); - if(preg_match("/^(.+?)\//", $fileName, $matches)) $name = $this->normaliseName($matches[1]); - if(strlenu($name) == 2) $language = $name; - } - return $language; - } - - // Return file path for new page - function findFileNew($fileName, $pathBase, $fileNew, $fileDefault) - { - if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]); - $fileName = strreplaceu("(.*)", $name, $pathBase.$fileNew); - if(!is_file($fileName)) - { - $name = $this->normaliseName($fileDefault, true, true); - $fileName = strreplaceu("(.*)", $name, $pathBase.$fileNew); - } - return $fileName; - } - - // Return file path from title - function findFileFromTitle($titlePrefix, $titleText, $fileName, $fileDefault, $fileExtension) - { - preg_match("/^([\d\-\_\.]*)(.*)$/", $titlePrefix, $matches); - if(preg_match("/\d$/", $matches[1])) $matches[1] .= '-'; - $titleText = $this->normaliseName($titleText, false, false, true); - preg_match("/^([\d\-\_\.]*)(.*)$/", $matches[1].$titleText, $matches); - $fileNamePrefix = $matches[1]; - $fileNameText = empty($matches[2]) ? $fileDefault : $matches[2].$fileExtension; - return dirname($fileName)."/".$fileNamePrefix.$fileNameText; - } - - // Normalise location, make absolute location - function normaliseLocation($location, $pageBase, $pageLocation, $staticLocation = "", $filterStrict = true) - { - if(!preg_match("/^\w+:/", trim(html_entity_decode($location, ENT_QUOTES, "UTF-8")))) - { - if(empty($staticLocation) || !preg_match("#^$staticLocation#", $location)) - { - if(preg_match("/^\#/", $location)) - { - $location = $pageBase.$pageLocation.$location; - } else if(!preg_match("/^\//", $location)) { - $location = $this->getDirectoryLocation($pageBase.$pageLocation).$location; - } else if(!preg_match("#^$pageBase#", $location)) { - $location = $pageBase.$location; - } - } - } else { - if($filterStrict && !preg_match("/^(http|https|ftp|mailto):/", $location)) $location = "error-xss-filter"; - } - return $location; + return isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$lastModifiedFormatted; } // Normalise location arguments @@ -2069,15 +2260,6 @@ class YellowToolbox return strreplaceu(array('%3A','%2F'), array(':','/'), rawurlencode($text)); } - // Normalise file/directory/other name - function normaliseName($text, $removePrefix = true, $removeExtension = false, $filterStrict = false) - { - if($removeExtension) $text = ($pos = strrposu($text, '.')) ? substru($text, 0, $pos) : $text; - if($removePrefix) if(preg_match("/^[\d\-\_\.]+(.*)$/", $text, $matches)) $text = $matches[1]; - if($filterStrict) $text = strreplaceu('.', '-', strtoloweru($text)); - return preg_replace("/[^\pL\d\-\_\.]/u", "-", rtrim($text, '/')); - } - // Normalise text into UTF-8 NFC function normaliseUnicode($text) { @@ -2136,31 +2318,14 @@ class YellowToolbox "jpg" => "image/jpeg", "png" => "image/png", "txt" => "text/plain", - "woff" => "application/font-woff"); + "woff" => "application/font-woff", + "xml" => "text/xml; charset=utf-8"); $contentType = "text/html; charset=utf-8"; - $extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : ""; + $extension = $this->getFileExtension($fileName); if(array_key_exists(strtoloweru($extension), $mimeTypes)) $contentType = $mimeTypes[$extension]; return $contentType; } - // Return URL - function getUrl($serverScheme, $serverName, $base, $location) - { - if(!preg_match("/^\w+:/", $location)) - { - $url = "$serverScheme://$serverName$base$location"; - } else { - $url = $location; - } - return $url; - } - - // Return directory location - function getDirectoryLocation($location) - { - return ($pos = strrposu($location, '/')) ? substru($location, 0, $pos+1) : "/"; - } - // Return files and directories function getDirectoryEntries($path, $regex = "/.*/", $sort = true, $directories = true, $includePath = true) { @@ -2230,6 +2395,24 @@ class YellowToolbox return is_readable($fileName) ? file_get_contents($fileName) : ""; } + // Return file extension + function getFileExtension($fileName) + { + return strtoloweru(($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : ""); + } + + // Return file modification date, Unix time + function getFileModified($fileName) + { + $modified = is_readable($fileName) ? filemtime($fileName) : 0; + if($modified == 0) + { + $path = dirname($fileName); + $modified = is_readable($path) ? filemtime($path) : 0; + } + return $modified; + } + // Create file function createFile($fileName, $fileData, $mkdir = false) { @@ -2282,7 +2465,17 @@ class YellowToolbox { return @unlink($fileName); } - + + // Return lines from text string + function getTextLines($text) + { + $lines = array(); + $split = preg_split("/(\R)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE); + for($i=0; $iyellow = $yellow; } // Handle page content parsing of raw format - function onParseContentText($page, $text) + function onParseContentRaw($page, $text) { - $markdown = new YellowMarkdownExtraParser($this->yellow, $page); + $markdown = new YellowMarkdownParser($this->yellow, $page); return $markdown->transform($text); } } -// Markdown extra parser -class YellowMarkdownExtraParser extends MarkdownExtraParser +// Markdown parser +class YellowMarkdownParser extends MarkdownExtraParser { var $yellow; //access to API var $page; //access to page @@ -38,7 +38,7 @@ class YellowMarkdownExtraParser extends MarkdownExtraParser $this->no_entities = $page->parserSafeMode; $this->url_filter_func = function($url) use ($yellow, $page) { - return $yellow->toolbox->normaliseLocation($url, $page->base, $page->location, + return $yellow->lookup->normaliseLocation($url, $page->base, $page->location, $yellow->config->get("serverBase").$yellow->config->get("imageLocation"), $page->parserSafeMode && $page->statusCode==200); }; @@ -57,7 +57,7 @@ class YellowMarkdownExtraParser extends MarkdownExtraParser // Return unique id attribute function getIdAttribute($text) { - $text = $this->yellow->toolbox->normaliseName($text, true, false, true); + $text = $this->yellow->lookup->normaliseName($text, true, false, true); $text = trim(preg_replace("/-+/", "-", $text), "-"); if(is_null($this->idAttributes[$text])) { @@ -83,9 +83,9 @@ class YellowMarkdownExtraParser extends MarkdownExtraParser function _doAutoLinks_shortcut_callback($matches) { $text = preg_replace("/\s+/s", " ", $matches[2]); - $output = $this->page->parseType($matches[1], $text, true); + $output = $this->page->parseContentBlock($matches[1], $text, true); if(is_null($output)) $output = htmlspecialchars($matches[0], ENT_NOQUOTES); - return $this->hashBlock($output); + return substr($output, 0, 4)=="hashBlock($output) : $this->hashPart($output); } // Handle comments @@ -101,7 +101,7 @@ class YellowMarkdownExtraParser extends MarkdownExtraParser function _doFencedCodeBlocks_callback($matches) { $text = $matches[4]; - $output = $this->page->parseType($matches[2], $text, false); + $output = $this->page->parseContentBlock($matches[2], $text, false); if(is_null($output)) { $attr = $this->doExtraAttributes("pre", $dummy =& $matches[3]); @@ -3325,5 +3325,5 @@ class MarkdownExtraParser extends MarkdownParser { } -$yellow->plugins->register("markdownextra", "YellowMarkdownExtra", YellowMarkdownExtra::Version); +$yellow->plugins->register("markdown", "YellowMarkdown", YellowMarkdown::Version); ?> \ No newline at end of file diff --git a/system/snippets/pagination.php b/system/snippets/pagination.php deleted file mode 100755 index c062989..0000000 --- a/system/snippets/pagination.php +++ /dev/null @@ -1,11 +0,0 @@ -getSnippetArgs() ?> -isPagination()): ?> - - diff --git a/system/themes/default.css b/system/themes/default.css deleted file mode 100644 index 98816ea..0000000 --- a/system/themes/default.css +++ /dev/null @@ -1,59 +0,0 @@ -/* Default theme 0.5.2 */ -/* Designer: Datenstrom Sweden */ - -html, body, div, form, pre, span, tr, th, td { margin:0; padding:0; border:0; vertical-align:baseline; } -body { - margin:1em; - background-color:#fff; color:#717171; - font-family:"Helvetica Neue",Helvetica,sans-serif; - font-size:1.0em; - font-weight:200; - line-height:1.5; -} -h1, h2, h3, h4, h5, h6 { color:#07d; font-weight:normal; } -hr { height:1px; background:#ddd; border:0; } -strong { font-weight:bold; } -code { font-size:1.1em; } -a { color:#07d; } -a:hover { color:#07d; text-decoration:underline; } -a, img { border:none; text-decoration:none; } -.sitename h1 { margin-top:0.5em; margin-bottom:0em; font-size:2.2em; font-weight:500; } -.sitename h1 a { color:#111; text-decoration:none; } -.navigation { margin-bottom:1em; line-height:2em; } -.navigation a { color:#111; padding:0 0.3em; display:inline-block; } -.navigation a:hover { color:#07d; } -.navigation ul { margin:0 -0.3em; padding:0; list-style:none; } -.navigation li { display:inline; } -.content h1 a:hover { text-decoration:none; } -.content img { max-width:100%; height:auto; } -.content form { margin:1em 0; } -.content table { border-spacing:0; border-collapse:collapse; } -.content th { text-align:left; padding:0.3em; border-bottom:1px solid #ddd;} -.content td { text-align:left; padding:0.3em; border-top:1px solid #ddd;} -.content .flexible { position:relative; padding-bottom:56.25%; padding-top:30px; } -.content .flexible iframe { position:absolute; top:0; left:0; width:100%; height:100%; } -.content .toc { margin:0; padding:0; list-style:none; } -.pagination { margin:1em 0; } -.footer { margin-top:1em; } -.footer a { color:#717171; } -.footer a:hover { color:#07d; text-decoration:underline; } -.left { float:left; margin:0 1em 0 0; } -.center { display:block; margin:0 auto; } -.right { float:right; margin:0 0 0 1em; } - -/* Responsive and print */ - -.page { margin:0 auto; max-width:62em; } - -@media screen and (min-width:62em) { - body { width:60em; margin:1em auto; } -} -@media screen and (max-width:30em) { - body { margin:0.5em; font-size:0.9em; } - .sitename h1, h1, h2 { font-size:1.3em; } - .sitename h1, .sitename, .navigation, .footer, .page { margin:0; padding:0; border:0; } -} -@media print { - body, h1, h2, h3, h4, h5, h6 { background-color:white; color:black; } - .page { border:none !important; } -} \ No newline at end of file diff --git a/system/themes/flatsite.css b/system/themes/flatsite.css new file mode 100644 index 0000000..3d7a95b --- /dev/null +++ b/system/themes/flatsite.css @@ -0,0 +1,101 @@ +/* Flatsite theme 0.1.7 */ +/* Designer: Mark Mayberg */ + +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,700); +html, body, div, form, pre, span, tr, th, td { margin:0; padding:0; border:0; vertical-align:baseline; } +body { + margin:1em; + background-color:#fff; color:#717171; + font-family:'Open Sans',sans-serif; + font-size:1.0em; + font-weight:300; + line-height:1.5; +} +h1, h2, h3, h4, h5, h6 { color:#07d; font-weight:normal; } +h1 { font-size:2.0em; } +hr { height:1px; background:#ddd; border:0; } +strong { font-weight:bold; } +code { font-size:1.1em; } +a { color:#07d; } +a:hover { color:#07d; text-decoration:underline; } +a, img { border:none; text-decoration:none; } +.sitename { display:block; float:left; } +.sitename h1 { margin:0; } +.sitename h1 a { color:#111; text-decoration:none; } +.navigation { display:block; float:right; } +.navigation { margin-top:0.9em; margin-bottom:0.9em; line-height:2em; } +.navigation a { padding:0 0.3em; display:inline-block; } +.navigation ul { margin:0 -0.3em; padding:0; list-style:none; } +.navigation li { display:inline; } +.content { clear:both; } +.content h1 a:hover { text-decoration:none; } +.content img { max-width:100%; height:auto; } +.content form { margin:1em 0; } +.content table { border-spacing:0; border-collapse:collapse; } +.content th { text-align:left; padding:0.3em; border-bottom:1px solid #ddd;} +.content td { text-align:left; padding:0.3em; border-top:1px solid #ddd;} +.content .flexible { position:relative; padding-bottom:56.25%; padding-top:30px; } +.content .flexible iframe { position:absolute; top:0; left:0; width:100%; height:100%; } +.content .toc { margin:0; padding:0; list-style:none; } +.content code { border:1px solid #ddd; border-radius:3px; padding:0 0.5em; } +.content pre>code { border:none; padding:0; } +.content pre { border:1px solid #ddd; border-radius:3px; padding:1em; overflow:hidden; } +.content .imagelist { margin:0; padding:0; list-style:none; } +.content .themes { margin:0; padding:0; list-style:none; width:100%; } +.content .themes li { padding-bottom:1em; text-align:center; white-space:nowrap; display:inline-block; width:24%; } +.pagination { margin:1em 0; } +.footer { margin-top:2em; } +.footer a { color:#07d; } +.footer a:hover { color:#07d; text-decoration:underline; } +.left { float:left; margin:0 1em 0 0; } +.center { display:block; margin:0 auto; } +.right { float:right; margin:0 0 0 1em; } + +/* Forms and buttons */ + +.form-control { + margin:0; padding:2px 4px; + display:inline-block; + background-color:#fff; color:#555; + background-image:linear-gradient(to bottom, #fff, #fff); + border:1px solid #bbb; + border-radius:4px; + font-size:0.9em; font-family:inherit; font-weight:normal; line-height:1; +} +.btn { + margin:0; padding:4px 22px; + display:inline-block; min-width:8em; + background-color:#eaeaea; color:#333333; + background-image:linear-gradient(to bottom, #f8f8f8, #e1e1e1); + border:1px solid #bbb; + border-color:#c1c1c1 #c1c1c1 #aaaaaa; + border-radius:4px; + outline-offset:-2px; + font-size:0.9em; font-family:inherit; font-weight:normal; line-height:1; + text-align:center; text-decoration:none; +} +.btn:hover, .btn:focus, .btn:active { + color:#333333; + background-image:none; + text-decoration:none; +} +.btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); } + +/* Responsive and print */ + +.page { margin:0 auto; max-width:1000px; } + +@media screen and (min-width:62em) { + body { width:60em; margin:1em auto; } + .page{ margin:0; max-width:none; } +} +@media screen and (max-width:30em) { + body { margin:0.5em; font-size:0.9em; } + .sitename h1, h1, h2 { font-size:1.2em; } + .sitename h1, .header, .navigation, .footer, .page { margin:0; padding:0; } + .sitename, .navigation { float:none; } +} +@media print { + body, h1, h2, h3, h4, h5, h6 { background-color:white; color:black; } + .page { border:none !important; } +} \ No newline at end of file diff --git a/system/snippets/content.php b/system/themes/snippets/content.php similarity index 100% rename from system/snippets/content.php rename to system/themes/snippets/content.php diff --git a/system/snippets/footer.php b/system/themes/snippets/footer.php similarity index 100% rename from system/snippets/footer.php rename to system/themes/snippets/footer.php diff --git a/system/snippets/header.php b/system/themes/snippets/header.php similarity index 95% rename from system/snippets/header.php rename to system/themes/snippets/header.php index 1e67137..01dc1f5 100755 --- a/system/snippets/header.php +++ b/system/themes/snippets/header.php @@ -11,7 +11,7 @@ <?php echo $yellow->page->getHtml("titleHeader") ?> config->get("imageLocation")."icon.png" ?>" /> config->get("themeLocation").$yellow->page->get("theme").".css" ?>" /> -page->getHeaderExtra() ?> +page->getExtra() ?>
diff --git a/system/snippets/navigation.php b/system/themes/snippets/navigation.php similarity index 100% rename from system/snippets/navigation.php rename to system/themes/snippets/navigation.php diff --git a/system/themes/snippets/pagination.php b/system/themes/snippets/pagination.php new file mode 100755 index 0000000..3a7cf4c --- /dev/null +++ b/system/themes/snippets/pagination.php @@ -0,0 +1,11 @@ +getSnippetArgs() ?> +isPagination()): ?> + + diff --git a/system/snippets/sitename.php b/system/themes/snippets/sitename.php similarity index 100% rename from system/snippets/sitename.php rename to system/themes/snippets/sitename.php diff --git a/system/templates/default.php b/system/themes/templates/default.html similarity index 69% rename from system/templates/default.php rename to system/themes/templates/default.html index 2a4cadf..a576c2c 100755 --- a/system/templates/default.php +++ b/system/themes/templates/default.html @@ -1,4 +1,3 @@ - snippet("header") ?> snippet("sitename") ?> snippet("navigation") ?>