mikuli.cz

:)
git clone https://git.sr.ht/~ashymad/mikuli.cz
Log | Files | Refs

commit 673944a4a974d5d9328797b9c65e7361aff02077
parent 5171263f2d2c77402b4f585dfe7d71a69ad3b5cd
Author: markseu <mark2011@mayberg.se>
Date:   Wed,  1 May 2013 22:16:05 +0200

Hello application interface

Diffstat:
MREADME.md | 2+-
Msystem/config/error424.txt | 4++--
Msystem/config/text_english.ini | 1-
Msystem/core/core.php | 628++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msystem/core/core_webinterface.css | 71++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msystem/core/core_webinterface.js | 141+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msystem/core/core_webinterface.php | 36++++++++++++++++++++++++------------
Msystem/templates/default.php | 3++-
8 files changed, 602 insertions(+), 284 deletions(-)

diff --git a/README.md b/README.md @@ -9,7 +9,7 @@ How do I install this? Copy all files to your web server hosting. Open your website in a browser, that's it! -Installation requirements are Apache, mod_rewrite and PHP 5.3. +Installation requirements are Apache, mod_rewrite, PHP 5.3 and multibyte support. Need help? Have a question? --------------------------- diff --git a/system/config/error424.txt b/system/config/error424.txt @@ -1,4 +1,4 @@ --- Title: Page does not exist --- -You can [create this page](javascript:yellow.onShow('yellowpaneedit');). -\ No newline at end of file +You can [create this page](javascript:yellow.onShow('yellow-paneedit');). +\ No newline at end of file diff --git a/system/config/text_english.ini b/system/config/text_english.ini @@ -10,7 +10,6 @@ webinterfaceLoginEmail = Email: webinterfaceLoginPassword = Password: webinterfaceLoginButton = Login webinterfaceSaveButton = Save -webinterfaceCancelButton = Cancel webinterfaceEdit = Edit webinterfaceShow = Show webinterfaceUser = User diff --git a/system/core/core.php b/system/core/core.php @@ -1,13 +1,13 @@ <?php // Copyright (c) 2013 Datenstrom, http://www.datenstrom.se // This file may be used and distributed under the terms of the public license. - + // Yellow main class class Yellow { - const Version = "0.1.0"; + const Version = "0.1.1"; var $page; //current page data - var $pages; //current page tree, top level + var $pages; //current page tree from file system var $toolbox; //toolbox with helpers var $config; //site configuration var $text; //site text strings @@ -122,7 +122,7 @@ class Yellow { header($this->toolbox->getHttpStatusFormated($statusCode)); header("Content-Type: text/html; charset=UTF-8"); - $fileName = str_replace("(.*)", $statusCode, $this->config->get("configDir").$this->config->get("errorPageFile")); + $fileName = strreplaceu("(.*)", $statusCode, $this->config->get("configDir").$this->config->get("errorPageFile")); $fileHandle = @fopen($fileName, "r"); if($fileHandle) { @@ -132,7 +132,7 @@ class Yellow die("Configuration problem: Can't open file '$fileName'!"); } } - if($fileData != "") $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode); + if(!empty($fileData)) $this->sendPage($baseLocation, $location, $fileName, $fileData, $statusCode); if(defined("DEBUG") && DEBUG>=1) echo "Yellow::processRequestFile base:$baseLocation file:$fileName<br>\n"; return $statusCode; } @@ -141,45 +141,16 @@ class Yellow function sendStatus($statusCode, $text = "") { header($this->toolbox->getHttpStatusFormated($statusCode)); - if($text != "") header($text); + if(!empty($text)) header($text); } // Send page response function sendPage($baseLocation, $location, $fileName, $fileData, $statusCode) { - $this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config); - $this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->toolbox, $this->config); + $this->pages = new Yellow_Pages($baseLocation, $this->toolbox, $this->config, $this->plugins); + $this->page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $this->pages, true); $this->text->setLanguage($this->page->get("language")); - $text = $this->page->getContentRawText(); - foreach($this->plugins->plugins as $key=>$value) - { - if(method_exists($value["obj"], "onParseBefore")) - { - $text = $value["obj"]->onParseBefore($text, $statusCode); - } - } - if(!$this->plugins->isExisting($this->page->get("parser"))) die("Parser '".$this->page->get("parser")."' does not exist!"); - $this->page->parser = $this->plugins->plugins[$this->page->get("parser")]["obj"]; - $text = $this->page->parser->parse($text); - foreach($this->plugins->plugins as $key=>$value) - { - if(method_exists($value["obj"], "onParseAfter")) - { - $text = $value["obj"]->onParseAfter($text, $statusCode); - } - } - $this->page->setContent($text); - - if(!$this->page->isExisting("description")) - { - $this->page->set("description", $this->toolbox->createTextDescription($this->page->getContent(), 150)); - } - if(!$this->page->isExisting("keywords")) - { - $this->page->set("keywords", $this->toolbox->createTextKeywords($this->page->get("title"), 10)); - } - $fileName = $this->config->get("templateDir").$this->page->get("template").$this->config->get("systemExtension"); if(!is_file($fileName)) die("Template '".$this->page->get("template")."' does not exist!"); global $yellow; @@ -211,23 +182,22 @@ class Yellow { $location = $this->toolbox->getRequestLocation(); $location = $this->toolbox->normaliseLocation($location); - $position = strlen($baseLocation); - return substr($location, $position); + return substru($location, strlenu($baseLocation)); } // Return content file name from location function getContentFileName($location) { return $this->toolbox->findFileFromLocation($location, - $this->config->get("contentDir"), $this->config->get("contentHomeDir"), - $this->config->get("contentDefaultFile"), $this->config->get("contentExtension")); + $this->config->get("contentDir"), $this->config->get("contentHomeDir"), + $this->config->get("contentDefaultFile"), $this->config->get("contentExtension")); } // Return content directory from location function getContentDirectory($location) { return $this->toolbox->findFileFromLocation($location, - $this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", ""); + $this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", ""); } // Register plugin @@ -236,28 +206,31 @@ class Yellow $this->plugins->register($name, $class, $version); } } - + // Yellow page data class Yellow_Page { - var $baseLocation; //base location - var $location; //page location - var $fileName; //content file name - var $parser; //content parser - var $metaData; //meta data of page - var $rawData; //raw data of page (unparsed) - var $rawTextPos; //raw text of page (unparsed) - var $active; //page is active? - var $hidden; //page is hidden? - - function __construct($baseLocation, $location, $fileName, $rawData, $toolbox, $config) + var $baseLocation; //base location + var $location; //page location + var $fileName; //content file name + var $parser; //content parser + var $metaData; //meta data of page + var $rawData; //raw data of page (unparsed) + var $rawTextOffsetBytes; //raw text of page (unparsed) + var $pages; //access to file system + var $active; //page is active? + var $hidden; //page is hidden in navigation? + + function __construct($baseLocation, $location, $fileName, $rawData, $pages, $parseContent = false) { $this->baseLocation = $baseLocation; $this->location = $location; $this->fileName = $fileName; - $this->setRawData($rawData, $toolbox, $config); - $this->active = $toolbox->isActiveLocation($baseLocation, $location); - $this->hidden = $toolbox->isHiddenLocation($baseLocation, $location, $fileName, $config->get("contentDir")); + $this->setRawData($rawData, $pages->toolbox, $pages->config); + $this->pages = $pages; + $this->active = $pages->toolbox->isActiveLocation($baseLocation, $location); + $this->hidden = $pages->toolbox->isHiddenLocation($baseLocation, $location, $fileName, $pages->config->get("contentDir")); + if($parseContent) $this->parseContent(); } // Set page raw data @@ -265,7 +238,7 @@ class Yellow_Page { $this->metaData = array(); $this->rawData = $rawData; - $this->rawTextPos = 0; + $this->rawTextOffsetBytes = 0; $this->set("title", $toolbox->createTextTitle($this->location)); $this->set("author", $config->get("author")); $this->set("language", $config->get("language")); @@ -274,17 +247,45 @@ class Yellow_Page if(preg_match("/^(\-\-\-[\r\n]+)(.+?)([\r\n]+\-\-\-[\r\n]+)/s", $rawData, $parsed)) { - $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]) + strlen($parsed[3]); + $this->rawTextOffsetBytes = strlenb($parsed[0]); preg_match_all("/([^\:\r\n]+)\s*\:\s*([^\r\n]+)/s", $parsed[2], $matches, PREG_SET_ORDER); - foreach($matches as $match) - { - $this->set(strtolower($match[1]), $match[2]); - } + foreach($matches as $match) $this->set(strtoloweru($match[1]), $match[2]); } else if(preg_match("/^([^\r\n]+)([\r\n]+=+[\r\n]+)/", $rawData, $parsed)) { - $this->rawTextPos = strlen($parsed[1]) + strlen($parsed[2]); + $this->rawTextOffsetBytes = strlenb($parsed[0]); $this->set("title", $parsed[1]); } } + + // Parse page content on demand + function parseContent() + { + if(empty($this->parser->html)) + { + if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Page::parseContent location:".$this->location."<br/>\n"; + $text = $this->getContentRawText(); + foreach($this->pages->plugins->plugins as $key=>$value) + { + if(method_exists($value["obj"], "onParseBefore")) $text = $value["obj"]->onParseBefore($text, $statusCode); + } + if(!$this->pages->plugins->isExisting($this->get("parser"))) die("Parser '".$this->get("parser")."' does not exist!"); + $this->parser = $this->pages->plugins->plugins[$this->get("parser")]["obj"]; + $text = $this->parser->parse($text); + foreach($this->pages->plugins->plugins as $key=>$value) + { + if(method_exists($value["obj"], "onParseAfter")) $text = $value["obj"]->onParseAfter($text, $statusCode); + } + $this->setContent($text); + + if(!$this->isExisting("description")) + { + $this->set("description", $this->pages->toolbox->createTextDescription($this->getContent(), 150)); + } + if(!$this->isExisting("keywords")) + { + $this->set("keywords", $this->pages->toolbox->createTextKeywords($this->get("title"), 10)); + } + } + } // Set page meta data function set($key, $value) @@ -319,13 +320,14 @@ class Yellow_Page // Return page content, HTML encoded function getContent() { + $this->parseContent(); return $this->parser->html; } // Return page content, raw text function getContentRawText() { - return substr($this->rawData, $this->rawTextPos); + return substrb($this->rawData, $this->rawTextOffsetBytes); } // Return absolut page location @@ -334,87 +336,264 @@ class Yellow_Page return $this->baseLocation.$this->location; } + // Return page modification time (Unix time UTC) + function getModified() + { + return filemtime($this->fileName); + } + + // Return child pages relative to current page + function getChildren($hidden = false) + { + return $this->pages->findChildren($this->location, $hidden); + } + + // Return pages on the same level as current page + function getSiblings($hidden = false) + { + $parentLocation = $this->pages->getParentLocation($this->location); + return $this->pages->findChildren($parentLocation, $hidden); + } + + // Return parent page relative to current page + function getParent() + { + $parentLocation = $this->pages->getParentLocation($this->location); + return $this->pages->findPage($parentLocation); + } + // Check if meta data exists function isExisting($key) { return !is_null($this->metaData[$key]); } - // Check if page is active + // Check if page is within current HTTP request function isActive() { return $this->active; } - // Check if page is active + // Check if page is hidden in navigation function isHidden() { return $this->hidden; } } -// Yellow page tree from file system -class Yellow_Pages +// Yellow page collection as array +class Yellow_PageCollection extends ArrayObject { - var $pages; //scanned pages + var $baseLocation; //base location + var $location; //collection location + var $paginationPage; //current page number in pagination + var $paginationCount; //highest page number in pagination + var $toolbox; //access to toolbox - function __construct($baseLocation, $toolbox, $config) + function __construct($input, $baseLocation, $location, $toolbox) { - $this->scan($baseLocation, $toolbox, $config); - } + parent::__construct($input); + $this->baseLocation = $baseLocation; + $this->location = $location; + $this->toolbox = $toolbox; + } - // Scan top-level pages - function scan($baseLocation, $toolbox, $config) + // Filter page collection by meta data + function filter($key, $value, $exactMatch = true) { - $this->pages = array(); - foreach($toolbox->getDirectoryEntries($config->get("contentDir"), "/.*/", true) as $entry) + if(!empty($key)) { - $fileName = $config->get("contentDir").$entry."/".$config->get("contentDefaultFile"); - $location = $toolbox->findLocationFromFile($fileName, $config->get("contentDir"), $config->get("contentHomeDir"), - $config->get("contentDefaultFile"), $config->get("contentExtension")); - $fileHandle = @fopen($fileName, "r"); - if($fileHandle) + $array = array(); + $value = strtoloweru($value); + $valueLength = strlenu($value); + foreach($this->getArrayCopy() as $page) { - $fileData = fread($fileHandle, 4096); - fclose($fileHandle); - } else { - $fileData = ""; + if($page->isExisting($key)) + { + foreach(preg_split("/,\s*/", strtoloweru($page->get($key))) as $valuePage) + { + $length = $exactMatch ? strlenu($valuePage) : $valueLength; + if($value == substru($valuePage, 0, $length)) array_push($array, $page); + } + } } - $page = new Yellow_Page($baseLocation, $location, $fileName, $fileData, $toolbox, $config); - array_push($this->pages, $page); + $this->exchangeArray($array); } + return $this; + } + + // Reverse page collection + function reverse($entriesMax = 0) + { + $this->exchangeArray(array_reverse($this->getArrayCopy())); + return $this; + } + + // Paginate page collection + function pagination($limit, $reverse = true) + { + $array = $this->getArrayCopy(); + if($reverse) $array = array_reverse($array); + $this->paginationPage = 1; + $this->paginationCount = ceil($this->count() / $limit); + if($limit < $this->count() && isset($_REQUEST["page"])) $this->paginationPage = max(1, $_REQUEST["page"]); + $this->exchangeArray(array_slice($array, ($this->paginationPage - 1) * $limit, $limit)); + return $this; + } + + // Return current page number in pagination + function getPaginationPage() + { + return $this->$paginationPage; + } + + // Return highest page number in pagination + function getPaginationCount() + { + return $this->paginationCount; } - // Return top-level pages - function root($showHidden = false) + // Return absolut location for a page in pagination + function getLocationPage($pageNumber) { - $pages = array(); - foreach($this->pages as $page) + if($pageNumber>=1 && $pageNumber<=$this->paginationCount) { - if($showHidden || !$page->isHidden()) array_push($pages, $page); + $locationArgs = $this->toolbox->getRequestLocationArgs($pageNumber>1 ? "page:$pageNumber" : "page:"); + $location = $this->baseLocation.$this->location.$locationArgs; } - return $pages; + return $location; } -} -// Yellow toolbox with helpers -class Yellow_Toolbox + // Return absolut location for previous page in pagination + function getLocationPrevious() + { + $pageNumber = $this->paginationPage; + $pageNumber = ($pageNumber>1 && $pageNumber<=$this->paginationCount) ? $pageNumber-1 : 0; + return $this->getLocationPage($pageNumber); + } + + // Return absolut location for next page in pagination + function getLocationNext() + { + $pageNumber = $this->paginationPage; + $pageNumber = ($pageNumber>=1 && $pageNumber<$this->paginationCount) ? $pageNumber+1 : 0; + return $this->getLocationPage($pageNumber); + } + + // Check if there is an active pagination + function isPagination() + { + return $this->paginationCount > 1; + } +} + +// Yellow page tree from file system +class Yellow_Pages { - // Return location from current HTTP request - static function getRequestLocation() + var $baseLocation; //base location + var $pages; //scanned pages + var $toolbox; //access to toolbox + var $config; //access to configuration + var $plugins; //access to plugins + + function __construct($baseLocation, $toolbox, $config, $plugins) { - $uri = $_SERVER["REQUEST_URI"]; - return ($pos = strpos($uri, '?')) ? substr($uri, 0, $pos) : $uri; + $this->baseLocation = $baseLocation; + $this->pages = array(); + $this->toolbox = $toolbox; + $this->config = $config; + $this->plugins = $plugins; + } + + // Return top-level navigation pages + function root($hidden = false) + { + return $this->findChildren("", $hidden); + } + + // Return child pages for a location + function findChildren($location, $hidden = false) + { + $pages = new Yellow_PageCollection(array(), $this->baseLocation, $location, $this->toolbox); + $this->scanChildren($location); + foreach($this->pages[$location] as $page) + { + if($hidden || !$page->isHidden()) $pages->append($page); + } + return $pages; } - // Return arguments from current HTTP request - static function getRequestLocationArguments() + // Return page for a location, false if not found + function findPage($location) { - $uri = $_SERVER["REQUEST_URI"]; - return ($pos = strpos($uri, '?')) ? substr($uri, $pos+1) : ""; + $parentLocation = $this->getParentLocation($location); + $this->scanChildren($parentLocation); + foreach($this->pages[$parentLocation] as $page) + { + if($this->baseLocation.$location == $page->getLocation()) return $page; + } + return false; + } + + // Scan child pages on demand + function scanChildren($location) + { + if(is_null($this->pages[$location])) + { + if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Pages::scanChildren location:$location<br/>\n"; + $this->pages[$location] = array(); + $path = $this->config->get("contentDir"); + if(!empty($location)) + { + $path = $this->toolbox->findFileFromLocation($location, + $this->config->get("contentDir"), $this->config->get("contentHomeDir"), "", ""); + } + $fileNames = array(); + foreach($this->toolbox->getDirectoryEntries($path, "/.*/", true) as $entry) + { + array_push($fileNames, $path.$entry."/".$this->config->get("contentDefaultFile")); + } + $fileRegex = "/.*\\".$this->config->get("contentExtension")."/"; + foreach($this->toolbox->getDirectoryEntries($path, $fileRegex, true, false) as $entry) + { + if($entry == $this->config->get("contentDefaultFile")) continue; + array_push($fileNames, $path.$entry); + } + foreach($fileNames as $fileName) + { + $childLocation = $this->toolbox->findLocationFromFile($fileName, + $this->config->get("contentDir"), $this->config->get("contentHomeDir"), + $this->config->get("contentDefaultFile"), $this->config->get("contentExtension")); + $fileHandle = @fopen($fileName, "r"); + if($fileHandle) + { + $fileData = fread($fileHandle, 4096); + fclose($fileHandle); + } else { + $fileData = ""; + } + $page = new Yellow_Page($this->baseLocation, $childLocation, $fileName, $fileData, $this); + array_push($this->pages[$location], $page); + } + } } - // Return base location + // Return parent navigation location + function getParentLocation($location) + { + $parentLocation = ""; + if(preg_match("/^(.*\/)(.+?)$/", $location, $matches)) + { + $parentLocation = $matches[1]!="/" ? $matches[1] : ""; + } + return $parentLocation; + } +} + +// Yellow toolbox with helpers +class Yellow_Toolbox +{ + // Return base location from current HTTP request static function getBaseLocation() { $baseLocation = "/"; @@ -422,27 +601,73 @@ class Yellow_Toolbox return $baseLocation; } - // Normalise location and remove incorrect path tokens - static function normaliseLocation($location) + // Return location from current HTTP request + static function getRequestLocation() + { + $uri = $_SERVER["REQUEST_URI"]; + return ($pos = strposu($uri, '?')) ? substru($uri, 0, $pos) : $uri; + } + + // Return arguments from current HTTP request + static function getRequestLocationArgs($arg = "", $encodeArgs = true) + { + preg_match("/^(.*?):(.*)$/", $arg, $args); + if(preg_match("/^(.*?\/)(\w+:.*)$/", rawurldecode(self::getRequestLocation()), $matches)) + { + 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]) && !empty($matches[2])) + { + if(!empty($locationArgs)) $locationArgs .= '/'; + $locationArgs .= "$matches[1]:$matches[2]"; + } + } + } + if(!$found && !empty($args[1]) && !empty($args[2])) + { + if(!empty($locationArgs)) $locationArgs .= '/'; + $locationArgs .= "$args[1]:$args[2]"; + } + if($encodeArgs) + { + $locationArgs = rawurlencode($locationArgs); + $locationArgs = strreplaceu(array('%3A','%2F'), array(':','/'), $locationArgs); + } + return $locationArgs; + } + + // Normalise location and remove unwanted path tokens + static function normaliseLocation($location, $removeArgs = true) { - $str = str_replace('\\', '/', rawurldecode($location)); - $location = ($str[0]=='/') ? '' : '/'; - for($pos=0; $pos<strlen($str); ++$pos) + $string = strreplaceu('\\', '/', rawurldecode($location)); + $location = ($string[0]=='/') ? '' : '/'; + for($pos=0; $pos<strlenb($string); ++$pos) { - if($str[$pos] == '/') + if($string[$pos] == '/') { - if($str[$pos+1] == '/') continue; - if($str[$pos+1] == '.') + if($string[$pos+1] == '/') continue; + if($string[$pos+1] == '.') { - $posNew = $pos+1; while($str[$posNew] == '.') ++$posNew; - if($str[$posNew]=='/' || $str[$posNew]=='') + $posNew = $pos+1; while($string[$posNew] == '.') ++$posNew; + if($string[$posNew]=='/' || $string[$posNew]=='') { $pos = $posNew-1; continue; } } } - $location .= $str[$pos]; + $location .= $string[$pos]; + } + if($removeArgs && preg_match("/^(.*?\/)(\w+:.*)$/", $location, $matches)) + { + $location = $matches[1]; + foreach(explode('/', $matches[2]) as $token) + { + preg_match("/^(.*?):(.*)$/", $token, $matches); + if(!empty($matches[1]) && !empty($matches[2])) $_REQUEST[$matches[1]] = $matches[2]; + } } return $location; } @@ -450,27 +675,27 @@ class Yellow_Toolbox // Check if location is specifying file or directory static function isFileLocation($location) { - return substr($location,-1,1) != "/"; + return substru($location, -1, 1) != "/"; } // Check if location is within current HTTP request static function isActiveLocation($baseLocation, $location) { - $currentLocation = substr(self::getRequestLocation(), strlen($baseLocation)); + $currentLocation = substru(self::getRequestLocation(), strlenu($baseLocation)); if($location != "/") { - $active = substr($currentLocation, 0, strlen($location))==$location; + $active = substru($currentLocation, 0, strlenu($location))==$location; } else { $active = $currentLocation==$location; } return $active; } - // Check if location is within visible collection + // Check if location is hidden in navigation static function isHiddenLocation($baseLocation, $location, $fileName, $pathBase) { $hidden = false; - if(substr($fileName, 0, strlen($pathBase)) == $pathBase) $fileName = substr($fileName, strlen($pathBase)); + if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) $fileName = substru($fileName, strlenu($pathBase)); $tokens = explode('/', $fileName); for($i=0; $i<count($tokens)-1; ++$i) { @@ -487,49 +712,48 @@ class Yellow_Toolbox static function findFileFromLocation($location, $pathBase, $pathHome, $fileDefault, $fileExtension) { $path = $pathBase; - if($location != "/") + $tokens = explode('/', $location); + if(count($tokens) > 2) { - $tokens = explode('/', $location); for($i=1; $i<count($tokens)-1; ++$i) { + if(preg_match("/^[\d\-\.]+/", $tokens[$i])) $duplicate = true; $entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i]."$/"); - if(!empty($entries)) $tokens[$i] = $entries[0]; - $path .= "$tokens[$i]/"; - } - if($tokens[$i] != "") - { - $path .= $tokens[$i].$fileExtension; - } else { - $path .= $fileDefault; + $path .= empty($entries) ? "$tokens[$i]/" : "$entries[0]/"; } + if($path == $pathBase.$pathHome) $duplicate = true; + } else { - $path .= $pathHome.$fileDefault; + $i = 1; + $path .= $pathHome; } - return $path; + if($tokens[$i] != "") + { + if(preg_match("/^[\d\-\.]+/", $tokens[$i])) $duplicate = true; + $entries = self::getDirectoryEntries($path, "/^[\d\-\.]+".$tokens[$i].$fileExtension."$/", false, false); + $path .= empty($entries) ? $tokens[$i].$fileExtension : $entries[0]; + } else { + $path .= $fileDefault; + } + return $duplicate ? "" : $path; } // Find location from file path static function findLocationFromFile($fileName, $pathBase, $pathHome, $fileDefault, $fileExtension) { $location = "/"; - if(substr($fileName, 0, strlen($pathBase)) == $pathBase) $fileName = substr($fileName, strlen($pathBase)); - if(substr($fileName, 0, strlen($pathHome)) != $pathHome) + if(substru($fileName, 0, strlenu($pathBase)) == $pathBase) $fileName = substru($fileName, strlenu($pathBase)); + if(substru($fileName, 0, strlenu($pathHome)) == $pathHome) $fileName = substru($fileName, strlenu($pathHome)); + $tokens = explode('/', $fileName); + for($i=0; $i<count($tokens)-1; ++$i) { - $tokens = explode('/', $fileName); - for($i=0; $i<count($tokens)-1; ++$i) - { - if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1]; - $location .= "$tokens[$i]/"; - } - if($tokens[$i] != $fileDefault) - { - $location .= substr($tokens[$i], 0, -strlen($fileExtension)-1); - } - } else { - if($fileName != $pathHome.$fileDefault) - { - $location .= substr($fileName, $pathHome, -strlen($fileExtension)-1); - } + if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1]; + $location .= "$tokens[$i]/"; + } + if($tokens[$i] != $fileDefault) + { + if(preg_match("/^[\d\-\.]+(.*)$/", $tokens[$i], $matches)) $tokens[$i] = $matches[1]; + $location .= substru($tokens[$i], 0, -strlenu($fileExtension)); } return $location; } @@ -541,6 +765,7 @@ class Yellow_Toolbox { case 301: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Moved permanently"; break; case 302: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Moved temporarily"; break; + case 303: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Reload please"; break; case 304: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Not modified"; break; case 401: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Unauthorised"; break; case 404: $text = "$_SERVER[SERVER_PROTOCOL] $statusCode Not found"; break; @@ -559,7 +784,7 @@ class Yellow_Toolbox { while(($entry = readdir($dirHandle)) !== false) { - if(substr($entry, 0, 1) == ".") continue; + if(substru($entry, 0, 1) == ".") continue; if(preg_match($regex, $entry)) { if($directories) @@ -576,36 +801,67 @@ class Yellow_Toolbox return $entries; } - // Create description from text - static function createTextDescription($text, $lengthMax) + // Create description from text string + static function createTextDescription($text, $lengthMax, $removeHtml = true) { - $description = ""; - preg_match_all("/\<p\>(.+?\<\/p\>)/s", $text, $parsedDescription, PREG_SET_ORDER); - foreach($parsedDescription as $matches) + if(preg_match("/<h1>.*<\/h1>(.*)/si", $text, $matches)) $text = $matches[1]; + if($removeHtml) { - preg_match_all("/([^\<]*)[^\>]+./s", $matches[1], $parsedUndoTag, PREG_SET_ORDER); - if(count($parsedUndoTag) > 0) + while(true) { - if(!empty($description)) $description .= " "; - foreach($parsedUndoTag as $matchTag) - { - $description .= preg_replace("/[\\x00-\\x1f]+/s", " ", $matchTag[1]); - } + $elementFound = preg_match("/<\s*?(\/?\w*).*?\>/s", $text, $matches, PREG_OFFSET_CAPTURE, $offsetBytes); + $element = $matches[0][0]; + $elementName = $matches[1][0]; + $elementOffsetBytes = $elementFound ? $matches[0][1] : strlenb($text); + $string = html_entity_decode(substrb($text, $offsetBytes, $elementOffsetBytes - $offsetBytes), ENT_QUOTES, "UTF-8"); + if(preg_match("/^(blockquote|br|div|h\d|hr|li|ol|p|pre|ul)/i", $elementName)) $string .= ' '; + $string = preg_replace("/\s+/s", " ", $string); + if(substru($string, 0 , 1)==" " && (empty($output) || substru($output, -1)==' ')) $string = substru($string, 1); + $length = strlenu($string); + $output .= substru($string, 0, $length < $lengthMax ? $length : $lengthMax-1); + $lengthMax -= $length; + if($lengthMax<=0 || !$elementFound) break; + $offsetBytes = $elementOffsetBytes + strlenb($element); } - if(strlen($description) > $lengthMax) + $output = rtrim($output); + if($lengthMax <= 0) $output .= '…'; + } else { + $elementsOpen = array(); + while(true) { - $description = substr($description, 0, $lengthMax-3)."..."; - break; + $elementFound = preg_match("/&.*?\;|<\s*?(\/?\w*)\s*?(.*?)\s*?\>/s", $text, $matches, PREG_OFFSET_CAPTURE, $offsetBytes); + $element = $matches[0][0]; + $elementName = $matches[1][0]; + $elementOffsetBytes = $elementFound ? $matches[0][1] : strlenb($text); + $string = substrb($text, $offsetBytes, $elementOffsetBytes - $offsetBytes); + $length = strlenu($string); + $output .= substru($string, 0, $length < $lengthMax ? $length : $lengthMax-1); + $lengthMax -= $length + ($element[0]=='&' ? 1 : 0); + if($lengthMax<=0 || !$elementFound) break; + if(!empty($elementName)) + { + if(!preg_match("/^(\/|area|br|col|hr|img|input|col|param)/i", $elementName)) + { + if(substru($matches[2][0], -1) != '/') array_push($elementsOpen, $elementName); + } else { + array_pop($elementsOpen); + } + } + $output .= $element; + $offsetBytes = $elementOffsetBytes + strlenb($element); } + $output = rtrim($output); + if($lengthMax <= 0) $output .= '…'; + for($t=count($elementsOpen)-1; $t>=0; --$t) $output .= "</".$elementsOpen[$t].">"; } - return $description; + return $output; } // Create keywords from text string static function createTextKeywords($text, $keywordsMax) { - $tokens = preg_split("/[,\s\(\)]/", strtolower($text)); - foreach($tokens as $key => $value) if(strlen($value) < 3) unset($tokens[$key]); + $tokens = preg_split("/[,\s\(\)]/", strtoloweru($text)); + foreach($tokens as $key=>$value) if(strlenu($value) < 3) unset($tokens[$key]); return implode(", ", array_slice(array_unique($tokens), 0, $keywordsMax)); } @@ -617,14 +873,14 @@ class Yellow_Toolbox } // Detect web browser language - function detectBrowserLanguage($languagesAllowed, $languageDefault) + static function detectBrowserLanguage($languagesAllowed, $languageDefault) { $language = $languageDefault; if(isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) { foreach(preg_split("/,\s*/", $_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $string) { - $tokens = split(";", $string, 2); + $tokens = explode(';', $string, 2); if(in_array($tokens[0], $languagesAllowed)) { $language = $tokens[0]; @@ -642,7 +898,7 @@ class Yellow_Toolbox $fileHandle = @fopen($fileName, "rb"); if($fileHandle) { - if(substr($fileName, -3) == "png") + if(substru($fileName, -3) == "png") { $dataSignature = fread($fileHandle, 8); $dataHeader = fread($fileHandle, 25); @@ -651,7 +907,7 @@ class Yellow_Toolbox $width = (ord($dataHeader[10])<<8) + ord($dataHeader[11]); $height = (ord($dataHeader[14])<<8) + ord($dataHeader[15]); } - } else if(substr($fileName, -3) == "jpg") { + } else if(substru($fileName, -3) == "jpg") { $dataSignature = fread($fileHandle, 11); $dataHeader = fread($fileHandle, 147); $dataHeader = fread($fileHandle, 16); @@ -702,7 +958,7 @@ class Yellow_Config { if(preg_match("/^\//", $line)) continue; preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches); - if($matches[1]!="" && $matches[2]!="") + if(!empty($matches[1]) && !empty($matches[2])) { $this->set($matches[1], $matches[2]); if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Config::load key:$matches[1] $matches[2]<br/>\n"; @@ -745,7 +1001,7 @@ class Yellow_Config } else { foreach($this->config as $key=>$value) { - if(substr($key, -strlen($filterEnd)) == $filterEnd) $config[$key] = $value; + if(substru($key, -strlenu($filterEnd)) == $filterEnd) $config[$key] = $value; } } return $config; @@ -784,13 +1040,13 @@ class Yellow_Text foreach($fileData as $line) { preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches); - if($matches[1]=="language" && $matches[2]!="") { $language = $matches[2]; break; } + if($matches[1]=="language" && !empty($matches[2])) { $language = $matches[2]; break; } } foreach($fileData as $line) { if(preg_match("/^\//", $line)) continue; preg_match("/^\s*(.*?)\s*=\s*(.*?)\s*$/", $line, $matches); - if($language!="" && $matches[1]!="" && $matches[2]!="") + if(!empty($language) && !empty($matches[1]) && !empty($matches[2])) { $this->setLanguageText($language, $matches[1], $matches[2]); if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Text::load key:$matches[1] $matches[2]<br/>\n"; @@ -837,8 +1093,8 @@ class Yellow_Text } else { foreach($this->text[$language] as $key=>$value) { - if(substr($key, 0, strlen("language")) == "language") $text[$key] = $value; - if(substr($key, 0, strlen($filterStart)) == $filterStart) $text[$key] = $value; + if(substru($key, 0, strlenu("language")) == "language") $text[$key] = $value; + if(substru($key, 0, strlenu($filterStart)) == $filterStart) $text[$key] = $value; } } } @@ -902,4 +1158,16 @@ class Yellow_Plugins return !is_null($this->plugins[$name]); } } + +// Unicode support for PHP 5 +mb_internal_encoding("UTF-8"); +function strlenu() { return call_user_func_array("mb_strlen", func_get_args()); } +function strposu() { return call_user_func_array("mb_strpos", func_get_args()); } +function strreplaceu() { return call_user_func_array("str_replace", func_get_args()); } +function strtoloweru() { return call_user_func_array("mb_strtolower", func_get_args()); } +function strtoupperu() { return call_user_func_array("mb_strtoupper", func_get_args()); } +function substru() { return call_user_func_array("mb_substr", func_get_args()); } +function strlenb() { return call_user_func_array("strlen", func_get_args()); } +function strposb() { return call_user_func_array("strpos", func_get_args()); } +function substrb() { return call_user_func_array("substr", func_get_args()); } ?> \ No newline at end of file diff --git a/system/core/core_webinterface.css b/system/core/core_webinterface.css @@ -1,25 +1,50 @@ -.yellowlogin { width:600px; position:absolute; top:5px; padding:30px; border:1px solid #ccc; background:#fff; color:#000; } -.yellowlogin h1 { margin:0px; padding:0px; } -.yellowlogin p { margin:0.5em; text-align:right; } +.yellow-login { + width:600px; position:absolute; top:5px; padding:30px; + border:1px solid #ccc; border-radius:4px; + background-color:#fff; color:#000; } +.yellow-login h1 { margin:0px; padding:0px; } +.yellow-login p { margin:0.5em; text-align:right; } -.yellowbar { width:600px; position:absolute; top:1px; background:#fff; color:#000; } -.yellowbar img { vertical-align:top; } -.yellowbar button { color:#05d; padding-left:0.5em; padding-right:0.5em; } -.yellowbar button:hover { color:#f00; } -.yellowbarleft { margin-left:0px; display:block; float:left; height:100%; } -.yellowbarright { margin-right:0px; display:block; float:right; height:100%; } -.yellowbarlink { cursor:pointer; font:inherit; background:none; border:none; margin:0px padding:0px; } -.yellowbubble { -webkit-border-radius:4px; -moz-border-radius:4px; border-radius:4px; } +.yellow-bar { width:600px; position:absolute; top:1px; background-color:#fff; color:#000; } +.yellow-bar img { vertical-align:top; } +.yellow-bar button { color:#05d; padding-left:0.5em; padding-right:0.5em; } +.yellow-bar button:hover { color:#f00; } +.yellow-barleft { margin-left:0px; display:block; float:left; height:100%; } +.yellow-barright { margin-right:0px; display:block; float:right; height:100%; } +.yellow-barlink { cursor:pointer; font:inherit; background:none; border:none; margin:0px padding:0px; } -.yellowpane { position:absolute; display:none; margin:0px; padding:5px; border:solid 1px #ccc; background:#fff; color:#000; z-index:10; } -.yellowpane a { text-decoration:none; color:#000; } -.yellowpane a:hover { text-decoration:none; color:#f00; } -.yellowpane p { margin:0.5em; } -.yellowpane ul { list-style:none; margin:0em 0.5em; padding:0px; } +.yellow-pane { + position:absolute; display:none; margin:0px; padding:5px; z-index:10; + border:1px solid #ccc; border-radius:4px; + background-color:#fff; color:#000; } +.yellow-panebubble { } +.yellow-pane a { text-decoration:none; color:#000; } +.yellow-pane a:hover { text-decoration:none; color:#f00; } +.yellow-pane p { margin:0.5em; } +.yellow-pane ul { list-style:none; margin:0em 0.5em; padding:0px; } -#yellowpaneedit { } -#yellowpaneshow { min-width:250px; overflow:auto; } -#yellowpaneuser { } -#yellowedittext { margin:0px; margin-bottom:5px; padding:5px; border:solid 1px #ccc; resize:none; font-size:0.9em } -#yelloweditbuttons { margin-bottom:5px; width:100%; } -#yelloweditbuttons input { margin-left:5px; } -\ No newline at end of file +.yellow-btn { + margin:0px; + padding:4px 22px; + font-size:0.9em; + background-color:#eaeaea; color:#333333; + background-image:linear-gradient(to bottom, #ffffff, #e1e1e1); + background-repeat:repeat-x; + border:1px solid #ccc; + border-color:#d1d1d1 #d1d1d1 #aaaaaa; + border-radius:4px; + outline-offset:-2px; } +.yellow-btn:hover, .yellow-btn:focus, .yellow-btn:active { background-image:none; } +.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); } +.yellow-btn-warn { + text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25); + background-color:#c33c35; color:#ffffff; + background-image:linear-gradient(to bottom, #ee5f5b, #bd362f); + border-color:#b13121 #b13121 #802020; } +.yellow-btn-warn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.3); } + +#yellow-paneedit { } +#yellow-paneshow { min-width:250px; overflow:auto; } +#yellow-paneuser { } +#yellow-edittext { margin:0px; margin-bottom:5px; padding:5px; border:1px solid #ccc; resize:none; font-size:0.9em } +#yellow-editbuttons { margin-bottom:5px; width:100%; } +\ No newline at end of file diff --git a/system/core/core_webinterface.js b/system/core/core_webinterface.js @@ -4,11 +4,11 @@ // Yellow main API var yellow = { - version: "0.0.0", //Hello web interface! - onClick: function(e) { yellow.webinterface.hidePanesOnClick(e); }, - onShow: function(id) { yellow.webinterface.showPane(id); }, - onReset: function(id) { yellow.webinterface.resetPane(id); }, + version: "0.1.0", + onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); }, + onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); }, onResize: function() { yellow.webinterface.resizePanes(); }, + onShow: function(id) { yellow.webinterface.showPane(id); }, webinterface:{}, page:{}, pages:{}, toolbox:{}, config:{}, text:{} } @@ -23,8 +23,9 @@ yellow.webinterface = init: function() { this.intervalId = setInterval("yellow.webinterface.create()", 1); - window.onresize = yellow.onResize; - document.onclick = yellow.onClick; + yellow.toolbox.addEvent(window, "resize", yellow.onResize); + yellow.toolbox.addEvent(document, "click", yellow.onClick); + yellow.toolbox.addEvent(document, "keydown", yellow.onKeydown); }, // Create action bar and panes @@ -37,34 +38,34 @@ yellow.webinterface = { var location = yellow.config.baseLocation+yellow.config.pluginsLocation; var element = document.createElement("div"); - element.className = "yellowbar"; - element.setAttribute("id", "yellowbar"); + element.className = "yellow-bar"; + element.setAttribute("id", "yellow-bar"); element.innerHTML = - "<div class=\"yellowbarleft\">"+ + "<div class=\"yellow-barleft\">"+ "<img src=\""+location+"core_webinterface.png\" width=\"16\" height=\"16\"> Yellow"+ - "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneedit');\">"+this.getText("Edit")+"</button>"+ - "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneshow');\">"+this.getText("Show")+"</button>"+ + "<button class=\"yellow-barlink\" onclick=\"yellow.onShow('yellow-paneedit');\">"+this.getText("Edit")+"</button>"+ + "<button class=\"yellow-barlink\" onclick=\"yellow.onShow('yellow-paneshow');\">"+this.getText("Show")+"</button>"+ "</div>"+ - "<div class=\"yellowbarright\">"+ - "<button class=\"yellowbarlink\" onclick=\"yellow.onShow('yellowpaneuser');\" id=\"yellowusername\">"+this.getText("User")+"</button>"+ + "<div class=\"yellow-barright\">"+ + "<button class=\"yellow-barlink\" onclick=\"yellow.onShow('yellow-paneuser');\" id=\"yellow-username\">"+this.getText("User")+"</button>"+ "</div>"; body.insertBefore(element, body.firstChild); - yellow.toolbox.insertAfter(this.createPane("yellowpaneedit"), body.firstChild); - yellow.toolbox.insertAfter(this.createPane("yellowpaneshow", yellow.pages), body.firstChild); - yellow.toolbox.insertAfter(this.createPane("yellowpaneuser"), body.firstChild); - yellow.toolbox.setText(document.getElementById("yellowusername"), yellow.config.userName+" ↓"); - yellow.toolbox.setText(document.getElementById("yellowedittext"), yellow.page.rawData); + yellow.toolbox.insertAfter(this.createPane("yellow-paneedit"), body.firstChild); + yellow.toolbox.insertAfter(this.createPane("yellow-paneshow", yellow.pages), body.firstChild); + yellow.toolbox.insertAfter(this.createPane("yellow-paneuser"), body.firstChild); + yellow.toolbox.setText(document.getElementById("yellow-username"), yellow.config.userName+" ↓"); + yellow.toolbox.setText(document.getElementById("yellow-edittext"), yellow.page.rawData); } else { var element = document.createElement("div"); - element.className = "yellowlogin yellowbubble"; - element.setAttribute("id", "yellowlogin"); + element.className = "yellow-login"; + element.setAttribute("id", "yellow-login"); element.innerHTML = "<form method=\"post\" name=\"formlogin\">"+ "<input type=\"hidden\" name=\"action\" value=\"login\"/>"+ "<h1>"+this.getText("LoginText")+"</h1>"+ "<p>"+this.getText("LoginEmail")+" <input name=\"email\" maxlength=\"64\" /></p>"+ "<p>"+this.getText("LoginPassword")+" <input type=\"password\" name=\"password\" maxlength=\"64\" /></p>"+ - "<p><input type=\"submit\" value=\""+this.getText("LoginButton")+"\"/></p>"+ + "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\"/></p>"+ "</form>"; body.insertBefore(element, body.firstChild); } @@ -78,19 +79,18 @@ yellow.webinterface = { if(yellow.debug) console.log("yellow.webinterface.createPane id:"+id); var outDiv = document.createElement("div"); - if(id == "yellowpaneedit") + if(id == "yellow-paneedit") { outDiv.innerHTML = "<p>Editing page...</p>"+ "<form method=\"post\" name=\"formeditor\">"+ "<input type=\"hidden\" name=\"action\" value=\"edit\"/>"+ - "<textarea id=\"yellowedittext\" name=\"rawdata\"></textarea>"+ - "<div id=\"yelloweditbuttons\">"+ - "<input type=\"submit\" value=\""+this.getText("SaveButton")+"\"/>"+ - "<input type=\"button\" value=\""+this.getText("CancelButton")+"\" onclick=\"yellow.onReset('yellowpaneedit');\"/>"+ + "<textarea id=\"yellow-edittext\" name=\"rawdata\"></textarea>"+ + "<div id=\"yellow-editbuttons\">"+ + "<input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SaveButton")+"\"/>"+ "</div>"+ "</form>"; - } else if(id == "yellowpaneshow") { + } else if(id == "yellow-paneshow") { outDiv.innerHTML = "<p>Showing files...</p>"; for(var n in data) { @@ -103,7 +103,7 @@ yellow.webinterface = outUl.appendChild(outLi); outDiv.appendChild(outUl); } - } else if(id == "yellowpaneuser") { + } else if(id == "yellow-paneuser") { outDiv.innerHTML = "<p>"+yellow.config.userEmail+"</p>"+ "<form method=\"post\" name=\"formlogout\">"+ @@ -112,68 +112,67 @@ yellow.webinterface = "</form>"; } var element = document.createElement("div"); - element.className = "yellowpane yellowbubble"; + element.className = "yellow-pane yellow-panebubble"; element.setAttribute("id", id); + element.style.display = "none"; element.appendChild(outDiv); return element; }, - // Reset pane - resetPane: function(id) - { - if(id == "yellowpaneedit") - { - document.formeditor.reset(); - yellow.toolbox.setText(document.getElementById("yellowedittext"), yellow.page.rawData); - this.hidePane(id); - } - }, - // Show pane showPane: function(id) { - if(document.getElementById(id).style.display == "block") + if(document.getElementById(id).style.display != "block") { this.hidePanes(); - } else { - this.hidePanes(); if(yellow.debug) console.log("yellow.webinterface.showPane id:"+id); document.getElementById(id).style.display = "block"; this.resizePanes(true); + } else { + this.hidePane(id); } }, // Hide pane hidePane: function(id) { - if(document.getElementById(id)) document.getElementById(id).style.display = "none"; + if(document.getElementById(id).style.display != "none") + { + if(yellow.debug) console.log("yellow.webinterface.hidePane id:"+id); + document.getElementById(id).style.display = "none"; + } }, // Hide all panes hidePanes: function() { - for(var element=document.getElementById("yellowbar"); element; element=element.nextSibling) + for(var element=document.getElementById("yellow-bar"); element; element=element.nextSibling) { - if(element.className && element.className.indexOf("yellowpane")>=0) + if(element.className && element.className.indexOf("yellow-pane")>=0) { this.hidePane(element.getAttribute("id")); } } }, - // Hide all panes on mouse click - hidePanesOnClick: function(e) + // Hide all panes on mouse click outside + hidePanesOnClick: function(element) { - var element = yellow.toolbox.getElementForEvent(e); while(element = element.parentNode) { if(element.className) { - if(element.className.indexOf("yellowpane")>=0 || element.className.indexOf("yellowbar")>=0) return; + if(element.className.indexOf("yellow-pane")>=0 || element.className.indexOf("yellow-bar")>=0) return; } } this.hidePanes(); }, + + // Hide all panes on ESC key + hidePanesOnKeydown: function(keycode) + { + if(keycode == 27) this.hidePanes(); + }, // Resize panes, recalculate height and width where needed resizePanes: function(force) @@ -190,28 +189,28 @@ yellow.webinterface = interfaceHeight = window.document.body.clientHeight; } } - if((interfaceHeight!=this.heightOld || force) && document.getElementById("yellowbar")) + if((interfaceHeight!=this.heightOld || force) && document.getElementById("yellow-bar")) { this.heightOld = interfaceHeight; - var elementBar = document.getElementById("yellowbar"); + var elementBar = document.getElementById("yellow-bar"); var borderRadius = 6; var panePadding = 5; var editPadding = 5; var interfaceTop = elementBar.offsetHeight + 1; interfaceHeight -= interfaceTop + borderRadius*2; - if(yellow.debug) console.log("yellow.webinterface.resizePanes windowY:"+interfaceHeight+" actionbarY:"+document.getElementById("yellowbar").offsetHeight+" buttonsY:"+document.getElementById("yelloweditbuttons").offsetHeight+" editorX:"+document.getElementById("yellowpaneedit").offsetWidth); + if(yellow.debug) console.log("yellow.webinterface.resizePanes windowY:"+interfaceHeight+" actionbarY:"+document.getElementById("yellow-bar").offsetHeight+" buttonsY:"+document.getElementById("yellow-editbuttons").offsetHeight+" editorX:"+document.getElementById("yellow-paneedit").offsetWidth); - this.setPaneHeight(document.getElementById("yellowpaneedit"), interfaceHeight, null, interfaceTop); - this.setPaneHeight(document.getElementById("yellowpaneshow"), null, interfaceHeight, interfaceTop); - this.setPaneHeight(document.getElementById("yellowpaneuser"), null, null, interfaceTop); + this.setPaneHeight(document.getElementById("yellow-paneedit"), interfaceHeight, null, interfaceTop); + this.setPaneHeight(document.getElementById("yellow-paneshow"), null, interfaceHeight, interfaceTop); + this.setPaneHeight(document.getElementById("yellow-paneuser"), null, null, interfaceTop); var editTextHeight = interfaceHeight - panePadding*2 - editPadding*2 - 10 - - (document.getElementById("yellowedittext").offsetTop-document.getElementById("yellowpaneedit").getElementsByTagName("p")[0].offsetTop) - - document.getElementById("yelloweditbuttons").offsetHeight; - document.getElementById("yellowpaneedit").style.width = Math.max(0, elementBar.offsetWidth - panePadding*2) + "px"; - document.getElementById("yellowedittext").style.height = Math.max(0, editTextHeight) + "px"; - document.getElementById("yellowedittext").style.width = Math.max(0, document.getElementById("yellowpaneedit").offsetWidth - 2 - panePadding*2 - editPadding*2) + "px"; - document.getElementById("yellowpaneuser").style.marginLeft = Math.max(0, elementBar.offsetWidth - document.getElementById("yellowpaneuser").offsetWidth) + "px"; + - (document.getElementById("yellow-edittext").offsetTop-document.getElementById("yellow-paneedit").getElementsByTagName("p")[0].offsetTop) + - document.getElementById("yellow-editbuttons").offsetHeight; + document.getElementById("yellow-paneedit").style.width = Math.max(0, elementBar.offsetWidth - panePadding*2) + "px"; + document.getElementById("yellow-edittext").style.height = Math.max(0, editTextHeight) + "px"; + document.getElementById("yellow-edittext").style.width = Math.max(0, document.getElementById("yellow-paneedit").offsetWidth - 2 - panePadding*2 - editPadding*2) + "px"; + document.getElementById("yellow-paneuser").style.marginLeft = Math.max(0, elementBar.offsetWidth - document.getElementById("yellow-paneuser").offsetWidth) + "px"; } }, @@ -250,11 +249,25 @@ yellow.toolbox = referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling); }, - // Return element for event - getElementForEvent: function(e) + // Add event handler + addEvent: function(element, type, handler) + { + if(element.addEventListener) element.addEventListener(type, handler, false); + else element.attachEvent('on'+type, handler); + }, + + // Return element of event + getEventElement: function(e) { e = e ? e : window.event; return e.target ? e.target : e.srcElement; + }, + + // Return keycode of event + getEventKeycode: function(e) + { + e = e ? e : window.event; + return e.keyCode } } diff --git a/system/core/core_webinterface.php b/system/core/core_webinterface.php @@ -5,7 +5,7 @@ // Web interface core plugin class Yellow_Webinterface { - const Version = "0.0.0"; //Hello web interface! + const Version = "0.1.0"; var $yellow; //access to API var $users; //web interface users var $activeLocation; //web interface location? (boolean) @@ -92,11 +92,10 @@ class Yellow_Webinterface { if($this->isWebinterfaceLocation() && $this->isUser()) { - $this->yellow->toolbox->timerStart($time); $baseLocation = $this->yellow->config->get("baseLocation"); - $webinterfaceLocation = rtrim($this->yellow->config->get("webinterfaceLocation"), '/'); - $text = preg_replace("#<a(.*?)href=\"$baseLocation(?!$webinterfaceLocation)(.*?)\"(.*?)>#", - "<a$1href=\"$baseLocation$webinterfaceLocation$2\"$3>", $text); + $webinterfaceLocation = trim($this->yellow->config->get("webinterfaceLocation"), '/'); + $text = preg_replace("#<a(.*?)href=\"$baseLocation/(?!$webinterfaceLocation)(.*?)\"(.*?)>#", + "<a$1href=\"$baseLocation/$webinterfaceLocation/$2\"$3>", $text); } return $text; } @@ -107,7 +106,7 @@ class Yellow_Webinterface $statusCode = 0; if($_POST["action"] == "edit") { - if(strlen($_POST["rawdata"])) + if(!empty($_POST["rawdata"])) { $fileHandle = @fopen($fileName, "w"); if($fileHandle) @@ -117,7 +116,12 @@ class Yellow_Webinterface } else { die("Configuration problem: Can't write page '$fileName'!"); } + $statusCode = 303; + $this->yellow->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$baseLocation$location"); } + } else if($_POST["action"]== "login") { + $statusCode = 303; + $this->yellow->sendStatus($statusCode, "Location: http://$_SERVER[SERVER_NAME]$baseLocation$location"); } else if($_POST["action"]== "logout") { $this->users->destroyCookie("login"); $this->activeUserEmail = ""; @@ -143,8 +147,8 @@ class Yellow_Webinterface // Check web interface location function checkWebinterfaceLocation($location) { - $locationLength = strlen($this->yellow->config->get("webinterfaceLocation")); - $this->activeLocation = substr($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation"); + $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation")); + $this->activeLocation = substru($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation"); return $this->isWebinterfaceLocation(); } @@ -193,7 +197,7 @@ class Yellow_Webinterface return !empty($this->activeUserEmail); } - // Return page tree with content/media information + // Return page tree with content information (2 levels) function getPagesData() { $data = array(); @@ -201,7 +205,15 @@ class Yellow_Webinterface { $data[$page->fileName] = array(); $data[$page->fileName]["location"] = $page->getLocation(); + $data[$page->fileName]["modified"] = $page->getModified(); $data[$page->fileName]["title"] = $page->getTitle(); + foreach($page->getChildren(true) as $page) + { + $data[$page->fileName] = array(); + $data[$page->fileName]["location"] = $page->getLocation(); + $data[$page->fileName]["modified"] = $page->getModified(); + $data[$page->fileName]["title"] = $page->getTitle(); + } } return $data; } @@ -236,8 +248,8 @@ class Yellow_WebinterfaceUsers foreach($fileData as $line) { if(preg_match("/^\//", $line)) continue; - preg_match("/^(.*?)\s*,(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); - if($matches[1]!="" && $matches[2]!="" && $matches[3]!="" && $matches[4]!="") + preg_match("/^(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches); + if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4])) { $this->setUser($matches[1], $matches[2], $matches[3], $matches[4]); if(defined("DEBUG") && DEBUG>=3) echo "Yellow_WebinterfaceUsers::load email:$matches[1] $matches[3]<br/>\n"; @@ -254,7 +266,7 @@ class Yellow_WebinterfaceUsers $this->users[$email]["password"] = $password; $this->users[$email]["name"] = $name; $this->users[$email]["language"] = $language; - $this->users[$email]["session"] = hash("sha256", $email.$password.strrev($email.$password)); + $this->users[$email]["session"] = hash("sha256", $email.$password.$password.$email); } // Check user login diff --git a/system/templates/default.php b/system/templates/default.php @@ -4,4 +4,4 @@ <h1><?php echo $yellow->page->getTitle() ?></h1> <?php echo $yellow->page->getContent() ?> </div> -<?php $yellow->snippet("footer") ?> +<?php $yellow->snippet("footer") ?> +\ No newline at end of file