commit 673944a4a974d5d9328797b9c65e7361aff02077
parent 5171263f2d2c77402b4f585dfe7d71a69ad3b5cd
Author: markseu <mark2011@mayberg.se>
Date: Wed, 1 May 2013 22:16:05 +0200
Hello application interface
Diffstat:
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