Kaynağa Gözat

System update (better content handling)

markseu 8 yıl önce
ebeveyn
işleme
3c7c88ddf3

+ 9 - 9
system/config/config.ini

@@ -54,12 +54,12 @@ UpdateThemesUrl: https://github.com/datenstrom/yellow-themes
 UpdateInformationFile: update.ini
 UpdateVersionFile: version.ini
 UpdateResourceFile: resource.ini
-WebinterfaceLocation: /edit/
-WebinterfaceNewFile: page-new-(.*).txt
-WebinterfaceMetaFilePrefix: published
-WebinterfaceUserFile: user.ini
-WebinterfaceUserPasswordMinLength: 4
-WebinterfaceUserHashAlgorithm: bcrypt
-WebinterfaceUserHashCost: 10
-WebinterfaceUserStatus: active
-WebinterfaceUserHome: /
+EditLocation: /edit/
+EditNewFile: page-new-(.*).txt
+EditUserFile: user.ini
+EditUserPasswordMinLength: 4
+EditUserHashAlgorithm: bcrypt
+EditUserHashCost: 10
+EditUserStatus: active
+EditUserHome: /
+EditLoginRestrictions: 0

+ 1 - 1
system/config/page-error-500.txt

@@ -1,4 +1,4 @@
 ---
 Title: Server error
 ---
-Something went wrong. @pageerror
+Something went wrong. [yellow error]

+ 12 - 11
system/plugins/commandline.php → system/plugins/command.php

@@ -1,11 +1,11 @@
 <?php
-// Commandline plugin, https://github.com/datenstrom/yellow-plugins/tree/master/commandline
+// Command plugin, https://github.com/datenstrom/yellow-plugins/tree/master/command
 // Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
-class YellowCommandline
+class YellowCommand
 {
-	const VERSION = "0.6.19";
+	const VERSION = "0.7.1";
 	var $yellow;					//access to API
 	var $files;						//number of files
 	var $errors;					//number of errors
@@ -45,7 +45,7 @@ class YellowCommandline
 	// Show available commands
 	function helpCommand()
 	{
-		echo "Yellow ".YellowCore::VERSION."\n";
+		echo "Datenstrom Yellow ".YellowCore::VERSION."\n";
 		$lineCounter = 0;
 		foreach($this->getCommandHelp() as $line) echo (++$lineCounter>1 ? "        " : "Syntax: ")."yellow.php $line\n";
 		return 200;
@@ -175,7 +175,7 @@ class YellowCommandline
 			++$this->errors;
 			echo "ERROR building location '$location', ".$this->yellow->page->getStatusCode(true)."\n";
 		}
-		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticFile status:$statusCode location:$location<br/>\n";
+		if(defined("DEBUG") && DEBUG>=1) echo "YellowCommand::buildStaticFile status:$statusCode location:$location<br/>\n";
 		return $statusCode;
 	}
 	
@@ -188,6 +188,7 @@ class YellowCommandline
 		$_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
 		$_SERVER["SERVER_NAME"] = $serverName;
 		$_SERVER["SERVER_PORT"] = $serverPort;
+		$_SERVER["REQUEST_METHOD"] = "GET";
 		$_SERVER["REQUEST_URI"] = $base.$location;
 		$_SERVER["SCRIPT_NAME"] = $base."/yellow.php";
 		$_SERVER["REMOTE_ADDR"] = "127.0.0.1";
@@ -219,14 +220,14 @@ class YellowCommandline
 				if(is_null($this->locationsArgs[$location]))
 				{
 					$this->locationsArgs[$location] = $location;
-					if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location<br/>\n";
+					if(defined("DEBUG") && DEBUG>=2) echo "YellowCommand::analyseStaticFile detected location:$location<br/>\n";
 				}
 			} else {
 				$location = rtrim($location, "0..9");
 				if(is_null($this->locationsArgsPagination[$location]))
 				{
 					$this->locationsArgsPagination[$location] = $location;
-					if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location<br/>\n";
+					if(defined("DEBUG") && DEBUG>=2) echo "YellowCommand::analyseStaticFile detected location:$location<br/>\n";
 				}
 			}
 		}
@@ -300,7 +301,7 @@ class YellowCommandline
 		$statusCode = 0;
 		foreach($this->yellow->plugins->plugins as $key=>$value)
 		{
-			if($key=="commandline") continue;
+			if($key=="command") continue;
 			if(method_exists($value["obj"], "onCommand"))
 			{
 				$statusCode = $value["obj"]->onCommand(func_get_args());
@@ -314,7 +315,7 @@ class YellowCommandline
 	function versionCommand($args)
 	{
 		$serverVersion = $this->yellow->toolbox->getServerVersion();
-		echo "Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
+		echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
 		list($command) = $args;
 		list($statusCode, $dataCurrent) = $this->getSoftwareVersion();
 		list($statusCode, $dataLatest) = $this->getSoftwareVersion(true);
@@ -460,5 +461,5 @@ class YellowCommandline
 	}
 }
 	
-$yellow->plugins->register("commandline", "YellowCommandline", YellowCommandline::VERSION);
-?>
+$yellow->plugins->register("command", "YellowCommand", YellowCommand::VERSION);
+?>

+ 180 - 174
system/plugins/core.php

@@ -5,7 +5,7 @@
 
 class YellowCore
 {
-	const VERSION = "0.6.9";
+	const VERSION = "0.7.1";
 	var $page;				//current page
 	var $pages;				//pages from file system
 	var $files;				//files from file system
@@ -90,7 +90,7 @@ class YellowCore
 		if(defined("DEBUG") && DEBUG>=2)
 		{
 			$serverVersion = $this->toolbox->getServerVersion();
-			echo "Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br/>\n";
+			echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br/>\n";
 		}
 		$this->config->load($this->config->get("configDir").$this->config->get("configFile"));
 		$this->text->load($this->config->get("pluginDir").$this->config->get("textFile"));
@@ -126,7 +126,6 @@ class YellowCore
 		ob_start();
 		$statusCode = 0;
 		$this->toolbox->timerStart($time);
-		$this->toolbox->normaliseRequest();
 		list($scheme, $address, $base, $location, $fileName) = $this->getRequestInformation();
 		$this->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
 		foreach($this->plugins->plugins as $key=>$value)
@@ -393,7 +392,6 @@ class YellowPage
 	var $base;					//base location
 	var $location;				//page location
 	var $fileName;				//content file name
-	var $lastModified;			//last modification date
 	var $rawData;				//raw data of page
 	var $metaDataOffsetBytes;	//meta data offset
 	var $metaData;				//meta data
@@ -408,6 +406,7 @@ class YellowPage
 	var $visible;				//page is visible location? (boolean)
 	var $active;				//page is active location? (boolean)
 	var $cacheable;				//page is cacheable? (boolean)
+	var $lastModified;			//last modification date
 	var $statusCode;			//status code
 
 	function __construct($yellow)
@@ -432,7 +431,6 @@ class YellowPage
 	// Parse page data
 	function parseData($rawData, $cacheable, $statusCode, $pageError = "")
 	{
-		$this->lastModified = 0;
 		$this->rawData = $rawData;
 		$this->parser = null;
 		$this->parserData = "";
@@ -441,6 +439,7 @@ class YellowPage
 		$this->visible = $this->yellow->lookup->isVisibleLocation($this->location, $this->fileName);
 		$this->active = $this->yellow->lookup->isActiveLocation($this->location, $this->yellow->page->location);
 		$this->cacheable = $cacheable;
+		$this->lastModified = 0;
 		$this->statusCode = $statusCode;
 		$this->parseMeta($pageError);
 	}
@@ -463,14 +462,9 @@ class YellowPage
 		if(!is_null($this->rawData))
 		{
 			$this->set("title", $this->yellow->toolbox->createTextTitle($this->location));
-			$this->set("language", $this->yellow->lookup->findLanguageFromFile($this->fileName,
-				$this->yellow->config->get("language")));
-			$this->set("theme", $this->yellow->lookup->findNameFromFile($this->fileName,
-				$this->yellow->config->get("assetDir"), $this->yellow->config->get("theme"), ".css"));
-			$this->set("template", $this->yellow->lookup->findNameFromFile($this->fileName,
-				$this->yellow->config->get("templateDir"), $this->yellow->config->get("template"), ".html"));
+			$this->set("language", $this->yellow->lookup->findLanguageFromFile($this->fileName, $this->yellow->config->get("language")));
 			$this->set("modified", date("Y-m-d H:i:s", $this->yellow->toolbox->getFileModified($this->fileName)));
-			$this->parseMetaData(array("sitename", "siteicon", "tagline", "author", "navigation", "sidebar", "parser"));
+			$this->parseMetaRaw(array("theme", "template", "sitename", "siteicon", "tagline", "author", "navigation", "sidebar", "parser"));
 			$titleHeader = ($this->location==$this->yellow->pages->getHomeLocation($this->location)) ?
 				$this->get("sitename") : $this->get("title")." - ".$this->get("sitename");
 			if(!$this->isExisting("titleContent")) $this->set("titleContent", $this->get("title"));
@@ -485,12 +479,12 @@ class YellowPage
 				$this->yellow->config->get("serverScheme"),
 				$this->yellow->config->get("serverAddress"),
 				$this->yellow->config->get("serverBase"),
-				rtrim($this->yellow->config->get("webinterfaceLocation"), '/').$this->location));
-			$this->set("pageFile", $this->yellow->lookup->normaliseFile($this->fileName));
+				rtrim($this->yellow->config->get("editLocation"), '/').$this->location));
+			$this->set("pageFile", $this->yellow->lookup->getPageFile($this->fileName));
 		} else {
 			$this->set("type", $this->yellow->toolbox->getFileExtension($this->fileName));
 			$this->set("modified", date("Y-m-d H:i:s", $this->yellow->toolbox->getFileModified($this->fileName)));
-			$this->set("pageFile", $this->yellow->lookup->normaliseFile($this->fileName, true));
+			$this->set("pageFile", $this->yellow->lookup->getPageFile($this->fileName, true));
 		}
 		if(!empty($pageError)) $this->set("pageError", $pageError);
 		foreach($this->yellow->plugins->plugins as $key=>$value)
@@ -499,15 +493,15 @@ class YellowPage
 		}
 	}
 	
-	// Parse page meta data from configuration and raw data
-	function parseMetaData($defaultKeys)
+	// Parse page meta data from raw data
+	function parseMetaRaw($defaultKeys)
 	{
 		foreach($defaultKeys as $key)
 		{
 			$value = $this->yellow->config->get($key);
 			if(!empty($key) && !strempty($value)) $this->set($key, $value);
 		}
-		if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)[\r\n]+\-\-\-[\r\n]+/s", $this->rawData, $parts))
+		if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)\-\-\-[\r\n]+/s", $this->rawData, $parts))
 		{
 			$this->metaDataOffsetBytes = strlenb($parts[0]);
 			foreach(preg_split("/[\r\n]+/", $parts[2]) as $line)
@@ -535,7 +529,6 @@ class YellowPage
 					$this->parserData = $this->getContent(true, $sizeMax);
 					$this->parserData = preg_replace("/@pageRead/i", $this->get("pageRead"), $this->parserData);
 					$this->parserData = preg_replace("/@pageEdit/i", $this->get("pageEdit"), $this->parserData);
-					$this->parserData = preg_replace("/@pageError/i", $this->get("pageError"), $this->parserData);
 					$this->parserData = $this->parser->onParseContentRaw($this, $this->parserData);
 					foreach($this->yellow->plugins->plugins as $key=>$value)
 					{
@@ -548,7 +541,7 @@ class YellowPage
 				}
 			} else {
 				$this->parserData = $this->getContent(true, $sizeMax);
-				$this->parserData = preg_replace("/@pageError/i", $this->get("pageError"), $this->parserData);
+				$this->parserData = preg_replace("/\[yellow error\]/i", $this->get("pageError"), $this->parserData);
 			}
 			if(!$this->isExisting("description"))
 			{
@@ -578,18 +571,16 @@ class YellowPage
 		{
 			if($name=="yellow" && $shortcut)
 			{
-				$output = "Yellow ".YellowCore::VERSION;
-				if(!empty($text))
+				$output = "Datenstrom Yellow ".YellowCore::VERSION;
+				if($text=="error") $output = $this->get("pageError");
+				if($text=="version")
 				{
 					$output = "<span class=\"".htmlspecialchars($name)."\">\n";
-					if($text=="version")
+					$serverVersion = $this->yellow->toolbox->getServerVersion();
+					$output .= "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br />\n";
+					foreach(array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData()) as $key=>$value)
 					{
-						$serverVersion = $this->yellow->toolbox->getServerVersion();
-						$output .= "Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br />\n";
-						foreach(array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData()) as $key=>$value)
-						{
-							$output .= htmlspecialchars("$key $value")."<br />\n";
-						}
+						$output .= htmlspecialchars("$key $value")."<br />\n";
 					}
 					$output .= "</span>\n";
 					if($this->parserSafeMode) $this->error(500, "Yellow '$text' is not available in safe mode!");
@@ -1430,7 +1421,7 @@ class YellowPages
 		return $pages;
 	}
 	
-	// Return child pages recursively
+	// Return sub pages
 	function getChildrenRecursive($location, $showInvisible = false, $levelMax = 0)
 	{
 		--$levelMax;
@@ -1579,7 +1570,7 @@ class YellowFiles
 		return $files;
 	}
 	
-	// Return child files recursively
+	// Return sub files
 	function getChildrenRecursive($location, $showInvisible = false, $levelMax = 0)
 	{
 		--$levelMax;
@@ -1642,11 +1633,6 @@ class YellowPlugins
 	// Load plugins
 	function load($path = "")
 	{
-		if(count($this->yellow->config->config)==0) //TODO: remove later, backwards compability for old Yellow version
-		{
-			$this->yellow->load();
-			return;
-		}
 		$path = empty($path) ? $this->yellow->config->get("pluginDir") : $path;
 		foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.php$/", true, false) as $entry)
 		{
@@ -1769,6 +1755,12 @@ class YellowThemes
 		}
 	}
 	
+	// Return theme
+	function get($name)
+	{
+		return $this->theme[$name]["obj"];
+	}
+	
 	// Return theme version
 	function getData()
 	{
@@ -1841,11 +1833,11 @@ class YellowConfig
 		foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
 		{
 			preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-			$keyOriginal = $matches[1]; $keySearch = strtoloweru($matches[1]); $keyFound = "";
-			foreach($config as $key=>$value) if(strtoloweru($key)==$keySearch) { $keyFound = $key; break; }
+			$keySearch = lcfirst($matches[1]); $keyFound = "";
+			foreach($config as $key=>$value) if(lcfirst($key)==$keySearch) { $keyFound = $key; break; }
 			if(!empty($keyFound))
 			{
-				$fileDataNew .= "$keyOriginal: $config[$keyFound]\n";
+				$fileDataNew .= "$matches[1]: $config[$keyFound]\n";
 				unset($config[$keyFound]);
 			} else {
 				$fileDataNew .= $line;
@@ -1853,7 +1845,7 @@ class YellowConfig
 		}
 		foreach($config as $key=>$value)
 		{
-			$fileDataNew .= "$key: $value\n";
+			$fileDataNew .= ucfirst($key).": $value\n";
 		}
 		return $this->yellow->toolbox->createFile($fileName, $fileDataNew);
 	}
@@ -2074,7 +2066,7 @@ class YellowText
 
 class YellowLookup
 {
-	var $yellow;		//access to API
+	var $yellow;			//access to API
 	var $requestHandler;	//request handler name
 	var $commandHandler;	//command handler name
 	var $snippetArgs;		//snippet arguments
@@ -2106,9 +2098,9 @@ class YellowLookup
 			foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, false) as $entry)
 			{
 				if(empty($firstRoot)) { $firstRoot = $token = $entry; }
-				if($this->normaliseName($entry)==$root) { $token = $entry; break; }
+				if($this->normaliseToken($entry)==$root) { $token = $entry; break; }
 			}
-			$pathRoot = $this->normaliseName($token)."/";
+			$pathRoot = $this->normaliseToken($token)."/";
 			$path .= "$firstRoot/";
 		}
 		if(!empty($pathHome))
@@ -2117,9 +2109,9 @@ class YellowLookup
 			foreach($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", true, true, false) as $entry)
 			{
 				if(empty($firstHome)) { $firstHome = $token = $entry; }
-				if($this->normaliseName($entry)==$home) { $token = $entry; break; }
+				if($this->normaliseToken($entry)==$home) { $token = $entry; break; }
 			}
-			$pathHome = $this->normaliseName($token)."/";
+			$pathHome = $this->normaliseToken($token)."/";
 		}
 		return array($pathRoot, $pathHome);
 	}
@@ -2134,7 +2126,7 @@ class YellowLookup
 		{
 			foreach($this->yellow->toolbox->getDirectoryEntries($pathBase, "/.*/", true, true, false) as $entry)
 			{
-				$token = $this->normaliseName($entry)."/";
+				$token = $this->normaliseToken($entry)."/";
 				if($token==$pathRoot) $token = "";
 				array_push($locations, $includePath ? "root/$token $pathBase$entry/" : "root/$token");
 				if(defined("DEBUG") && DEBUG>=2) echo "YellowLookup::findRootLocations root/$token<br/>\n";
@@ -2160,18 +2152,18 @@ class YellowLookup
 			$tokens = explode('/', $fileName);
 			if(!empty($pathRoot))
 			{
-				$token = $this->normaliseName($tokens[0]).'/';
+				$token = $this->normaliseToken($tokens[0]).'/';
 				if($token!=$pathRoot) $location .= $token;
 				array_shift($tokens);
 			}
 			for($i=0; $i<count($tokens)-1; ++$i)
 			{
-				$token = $this->normaliseName($tokens[$i]).'/';
+				$token = $this->normaliseToken($tokens[$i]).'/';
 				if($i || $token!=$pathHome) $location .= $token;
 			}
-			$token = $this->normaliseName($tokens[$i]);
-			$fileFolder = $this->normaliseName($tokens[$i-1]).$fileExtension;
-			if($token!=$fileDefault && $token!=$fileFolder) $location .= $this->normaliseName($tokens[$i], true, true);
+			$token = $this->normaliseToken($tokens[$i], $fileExtension);
+			$fileFolder = $this->normaliseToken($tokens[$i-1], $fileExtension);
+			if($token!=$fileDefault && $token!=$fileFolder) $location .= $this->normaliseToken($tokens[$i], $fileExtension, true);
 			$extension = ($pos = strrposu($fileName, '.')) ? substru($fileName, $pos) : "";
 			if($extension!=$fileExtension) $invalid = true;
 		} else {
@@ -2199,40 +2191,40 @@ class YellowLookup
 			if(!empty($pathRoot))
 			{
 				$token = (count($tokens)>2) ? $tokens[1] : rtrim($pathRoot, '/');
-				$path .= $this->findFileDirectory($path, $token, true, true, $found, $invalid);
+				$path .= $this->findFileDirectory($path, $token, "", true, true, $found, $invalid);
 			}
 		} else {
 			if(!empty($pathRoot))
 			{
 				if(count($tokens)>2)
 				{
-					if($this->normaliseName($tokens[1])==$this->normaliseName($pathRoot)) $invalid = true;
-					$path .= $this->findFileDirectory($path, $tokens[1], false, true, $found, $invalid);
+					if($this->normaliseToken($tokens[1])==$this->normaliseToken(rtrim($pathRoot, '/'))) $invalid = true;
+					$path .= $this->findFileDirectory($path, $tokens[1], "", true, false, $found, $invalid);
 					if($found) array_shift($tokens);
 				}
-				if(!$found) $path .= $this->findFileDirectory($path, rtrim($pathRoot, '/'), true, true, $found, $invalid);
+				if(!$found) $path .= $this->findFileDirectory($path, rtrim($pathRoot, '/'), "", true, true, $found, $invalid);
 				
 			}
 			if(count($tokens)>2)
 			{
-				if($this->normaliseName($tokens[1])==$this->normaliseName($pathHome)) $invalid = true;
+				if($this->normaliseToken($tokens[1])==$this->normaliseToken(rtrim($pathHome, '/'))) $invalid = true;
 				for($i=1; $i<count($tokens)-1; ++$i)
 				{
-					$path .= $this->findFileDirectory($path, $tokens[$i], true, true, $found, $invalid);
+					$path .= $this->findFileDirectory($path, $tokens[$i], "", true, true, $found, $invalid);
 				}
 			} else {
 				$i = 1;
 				$tokens[0] = rtrim($pathHome, '/');
-				$path .= $this->findFileDirectory($path, $tokens[0], true, true, $found, $invalid);
+				$path .= $this->findFileDirectory($path, $tokens[0], "", true, true, $found, $invalid);
 			}
 			if(!$directory)
 			{
-				if(!empty($tokens[$i]))
+				if(!strempty($tokens[$i]))
 				{
 					$token = $tokens[$i].$fileExtension;
 					$fileFolder = $tokens[$i-1].$fileExtension;
 					if($token==$fileDefault || $token==$fileFolder) $invalid = true;
-					$path .= $this->findFileDirectory($path, $token, true, false, $found, $invalid);
+					$path .= $this->findFileDirectory($path, $token, $fileExtension, false, true, $found, $invalid);
 				} else {
 					$path .= $this->findFileDefault($path, $fileDefault, $fileExtension, false);
 				}
@@ -2247,19 +2239,19 @@ class YellowLookup
 	}
 	
 	// Return file or directory that matches token
-	function findFileDirectory($path, $token, $tokenFailback, $directory, &$found, &$invalid)
+	function findFileDirectory($path, $token, $fileExtension, $directory, $default, &$found, &$invalid)
 	{
-		if($this->normaliseName($token)!=$token) $invalid = true;
+		if($this->normaliseToken($token, $fileExtension)!=$token) $invalid = true;
 		if(!$invalid)
 		{
 			$regex = "/^[\d\-\_\.]*".strreplaceu('-', '.', $token)."$/";
 			foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, false, $directory, false) as $entry)
 			{
-				if($this->normaliseName($entry)==$token) { $token = $entry; $found = true; break; }
+				if($this->normaliseToken($entry, $fileExtension)==$token) { $token = $entry; $found = true; break; }
 			}
 		}
 		if($directory) $token .= '/';
-		return ($tokenFailback || $found) ? $token : "";
+		return ($default || $found) ? $token : "";
 	}
 	
 	// Return default file in directory
@@ -2268,17 +2260,68 @@ class YellowLookup
 		$token = $fileDefault;
 		if(!is_file($path."/".$fileDefault))
 		{
-			$fileFolder = $this->normaliseName(basename($path)).$fileExtension;
+			$fileFolder = $this->normaliseToken(basename($path), $fileExtension);
 			$regex = "/^[\d\-\_\.]*($fileDefault|$fileFolder)$/";
 			foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false, false) as $entry)
 			{
-				if($this->normaliseName($entry)==$fileDefault) { $token = $entry; break; }
-				if($this->normaliseName($entry)==$fileFolder) { $token = $entry; break; }
+				if($this->normaliseToken($entry, $fileExtension)==$fileDefault) { $token = $entry; break; }
+				if($this->normaliseToken($entry, $fileExtension)==$fileFolder) { $token = $entry; break; }
 			}
 		}
 		return $includePath ? "$path/$token" : $token;
 	}
 	
+	// Return new file
+	function findFileNew($location, $filePrefix = "")
+	{
+		$fileName = $this->findFileFromLocation($location);
+		if(!empty($filePrefix) && !empty($fileName))
+		{
+			preg_match("/^([\d\-\_\.]*)(.*)$/", $filePrefix, $matches);
+			$filePrefix = empty($matches[1]) ? "" : $matches[1].'-';
+			$fileText = $this->normaliseName(basename($fileName), true, true);
+			if(preg_match("/^[\d\-\_\.]*$/", $fileText) && !empty($filePrefix)) $filePrefix = "";
+			$fileName = dirname($fileName)."/".$filePrefix.$fileText.$this->yellow->config->get("contentExtension");
+		}
+		if(!is_dir(dirname($fileName)))
+		{
+			$tokens = explode('/', $fileName);
+			for($i=0; $i<count($tokens)-1; ++$i)
+			{
+				if(!is_dir($path.$tokens[$i]))
+				{
+					if(!preg_match("/^[\d\-\_\.]+(.*)$/", $tokens[$i]))
+					{
+						$number = 1;
+						foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^[\d\-\_\.]+(.*)$/", true, true, false) as $entry)
+						{
+							if($number!=1 && $number!=intval($entry)) break;
+							$number = intval($entry)+1;
+						}
+						$tokens[$i] = "$number-".$tokens[$i];
+					}
+					$tokens[$i] = $this->normaliseName($tokens[$i], false, false, true);
+				}
+				$path .= $tokens[$i]."/";
+			}
+			$fileName = $path.$tokens[$i];
+		}
+		return $fileName;
+	}
+	
+	// Return static file if possible
+	function findFileStatic($location, $fileName, $cacheable)
+	{
+		if($cacheable)
+		{
+			$location .= $this->yellow->toolbox->getLocationArgs();
+			$fileNameStatic = rtrim($this->yellow->config->get("staticDir"), '/').$location;
+			if(!$this->isFileLocation($location)) $fileNameStatic .= $this->yellow->config->get("staticDefaultFile");
+			if(is_readable($fileNameStatic)) $fileName = $fileNameStatic;
+		}
+		return $fileName;
+	}
+	
 	// Return children from location
 	function findChildrenFromLocation($location)
 	{
@@ -2295,13 +2338,12 @@ class YellowLookup
 			}
 			if(!$this->isRootLocation($location))
 			{
-				$fileFolder = $this->normaliseName(basename($path)).$fileExtension;
+				$fileFolder = $this->normaliseToken(basename($path), $fileExtension);
 				$regex = "/^.*\\".$fileExtension."$/";
 				foreach($this->yellow->toolbox->getDirectoryEntries($path, $regex, true, false, false) as $entry)
 				{
-					if($this->normaliseName($entry)==$fileDefault) continue;
-					if($this->normaliseName($entry)==$fileFolder) continue;
-					if($this->normaliseName($entry, true, true)=="") continue;
+					if($this->normaliseToken($entry, $fileExtension)==$fileDefault) continue;
+					if($this->normaliseToken($entry, $fileExtension)==$fileFolder) continue;
 					array_push($fileNames, $path.$entry);
 				}
 			}
@@ -2318,48 +2360,13 @@ class YellowLookup
 		if(!empty($pathRoot))
 		{
 			$fileName = substru($fileName, strlenu($pathBase));
-			if(preg_match("/^(.+?)\//", $fileName, $matches)) $name = $this->normaliseName($matches[1]);
+			if(preg_match("/^(.+?)\//", $fileName, $matches)) $name = $this->normaliseToken($matches[1]);
 			if(strlenu($name)==2) $language = $name;
 		}
 		return $language;
 	}
 
-	// Return theme/template name from file path
-	function findNameFromFile($fileName, $pathBase, $nameDefault, $fileExtension)
-	{
-		$name = "";
-		if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]);
-		if(!is_file("$pathBase$name$fileExtension")) $name = $this->normaliseName($nameDefault);
-		return $name;
-	}
-	
-	// Return file path from config
-	function findFileFromConfig($fileName, $fileNameBase, $nameDefault)
-	{
-		$pathBase = $this->yellow->config->get("configDir");
-		if(preg_match("/^.*\/(.+?)$/", dirname($fileName), $matches)) $name = $this->normaliseName($matches[1]);
-		$fileName = strreplaceu("(.*)", $name, $pathBase.$fileNameBase);
-		if(!is_file($fileName))
-		{
-			$name = $this->normaliseName($nameDefault);
-			$fileName = strreplaceu("(.*)", $name, $pathBase.$fileNameBase);
-		}
-		return $fileName;
-	}
-	
-	// Return file path from title
-	function findFileFromTitle($titlePrefix, $titleText, $fileName, $fileDefault, $fileExtension)
-	{
-		preg_match("/^([\d\-\_\.]*)(.*)$/", $titlePrefix, $matches);
-		if(preg_match("/\d$/", $matches[1])) $matches[1] .= '-';
-		$titleText = $this->normaliseName($titleText, false, false, true);
-		preg_match("/^([\d\-\_\.]*)(.*)$/", $matches[1].$titleText, $matches);
-		$fileNamePrefix = $matches[1];
-		$fileNameText = empty($matches[2]) ? $fileDefault : $matches[2].$fileExtension;
-		return dirname($fileName)."/".$fileNamePrefix.$fileNameText;
-	}
-	
-	// Return file path for media location
+	// Return file path from media location
 	function findFileFromMedia($location)
 	{
 		if($this->isFileLocation($location))
@@ -2373,7 +2380,7 @@ class YellowLookup
 		return $fileName;
 	}
 	
-	// Return file path for system location
+	// Return file path from system location
 	function findFileFromSystem($location)
 	{
 		if(preg_match("/\.(css|ico|js|jpg|png|svg|txt|woff|woff2)$/", $location))
@@ -2393,64 +2400,21 @@ class YellowLookup
 		return $fileName;
 	}
 	
-	// Return file path for static file, if possible
-	function findFileStatic($location, $fileName, $cacheable)
+	// Normalise file/directory token
+	function normaliseToken($text, $fileExtension = "", $removeExtension = false)
 	{
-		if($cacheable)
-		{
-			$location .= $this->yellow->toolbox->getLocationArgs();
-			$fileNameStatic = rtrim($this->yellow->config->get("staticDir"), '/').$location;
-			if(!$this->isFileLocation($location)) $fileNameStatic .= $this->yellow->config->get("staticDefaultFile");
-			if(is_readable($fileNameStatic)) $fileName = $fileNameStatic;
-		}
-		return $fileName;
+		if(!empty($fileExtension)) $text = ($pos = strrposu($text, '.')) ? substru($text, 0, $pos) : $text;
+		if(preg_match("/^[\d\-\_\.]+(.*)$/", $text, $matches) && !empty($matches[1])) $text = $matches[1];
+		return preg_replace("/[^\pL\d\-\_]/u", "-", $text).($removeExtension ? "" : $fileExtension);
 	}
 	
-	// Return file path for new page
-	function findFilePageNew($fileName, $prefix = "")
-	{
-		$tokens = explode('/', $fileName);
-		for($i=0; $i<count($tokens)-1; ++$i)
-		{
-			if(!is_dir($path.$tokens[$i]))
-			{
-				if(!preg_match("/^[\d\-\_\.]+(.*)$/", $tokens[$i]))
-				{
-					$number = 1;
-					foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^[\d\-\_\.]+(.*)$/", true, true, false) as $entry)
-					{
-						if($number!=1 && $number!=intval($entry)) break;
-						$number = intval($entry)+1;
-					}
-					$tokens[$i] = (empty($prefix) ? "$number-" : $prefix).$tokens[$i];
-				}
-				$tokens[$i] = $this->normaliseName($tokens[$i], false, false, true);
-			}
-			$path .= $tokens[$i]."/";
-		}
-		$path .= $tokens[$i];
-		return $path;
-	}
-
-	// Normalise file/directory/other name
-	function normaliseName($text, $removePrefix = true, $removeExtension = false, $filterStrict = false)
+	// Normalise name
+	function normaliseName($text, $removePrefix = false, $removeExtension = false, $filterStrict = false)
 	{
 		if($removeExtension) $text = ($pos = strrposu($text, '.')) ? substru($text, 0, $pos) : $text;
-		if($removePrefix) if(preg_match("/^[\d\-\_\.]+(.*)$/", $text, $matches)) $text = $matches[1];
-		if($filterStrict) $text = strreplaceu('.', '-', strtoloweru($text));
-		return preg_replace("/[^\pL\d\-\_\.]/u", "-", rtrim($text, '/'));
-	}
-	
-	// Normalise content/media file name
-	function normaliseFile($fileName, $convertExtension = false)
-	{
-		$fileName = basename($fileName);
-		if($convertExtension)
-		{
-			$fileName = ($pos = strposu($fileName, '.')) ? substru($fileName, 0, $pos) : $fileName;
-			$fileName .= $this->yellow->config->get("contentExtension");
-		}
-		return $fileName;
+		if($removePrefix && preg_match("/^[\d\-\_\.]+(.*)$/", $text, $matches) && !empty($matches[1])) $text = $matches[1];
+		if($filterStrict) $text = strtoloweru($text);
+		return preg_replace("/[^\pL\d\-\_]/u", "-", $text);
 	}
 	
 	// Normalise array, make keys with same upper/lower case
@@ -2514,6 +2478,18 @@ class YellowLookup
 		return array($scheme, $address, $base);
 	}
 	
+	// Return page file name
+	function getPageFile($fileName, $convertExtension = false)
+	{
+		$fileName = basename($fileName);
+		if($convertExtension)
+		{
+			$fileName = ($pos = strposu($fileName, '.')) ? substru($fileName, 0, $pos) : $fileName;
+			$fileName .= $this->yellow->config->get("contentExtension");
+		}
+		return $fileName;
+	}
+	
 	// Return directory location
 	function getDirectoryLocation($location)
 	{
@@ -2799,17 +2775,6 @@ class YellowToolbox
 		return isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) && $_SERVER["HTTP_IF_MODIFIED_SINCE"]==$lastModifiedFormatted;
 	}
 	
-	// Normalise request data, take care of magic quotes
-	function normaliseRequest()
-	{
-		if(get_magic_quotes_gpc())
-		{
-			function stripArray($data) { return is_array($data) ? array_map("stripArray", $data) : stripslashes($data); }
-			$requestData = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
-			foreach($requestData as &$data) $data = stripArray($data);
-		}
-	}
-	
 	// Normalise path or location, take care of relative path tokens
 	function normaliseTokens($text, $prependSlash = false)
 	{
@@ -3094,7 +3059,7 @@ class YellowToolbox
 		return strtoloweru(($pos = strrposu($fileName, '.')) ? substru($fileName, $pos+1) : "");
 	}
 	
-	// Return lines from text string, newline separated
+	// Return lines from text string, including newline
 	function getTextLines($text)
 	{
 		$lines = array();
@@ -3269,6 +3234,47 @@ class YellowToolbox
 		return $ok;
 	}
 	
+	// Return meta data from raw data
+	function getMetaData($rawData, $key)
+	{
+		$value = "";
+		if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)\-\-\-[\r\n]+(.*)$/s", $rawData, $parts))
+		{
+			$key = lcfirst($key);
+			foreach($this->getTextLines($parts[2]) as $line)
+			{
+				preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+				if(lcfirst($matches[1])==$key && !strempty($matches[2])) { $value = $matches[2]; break; }
+			}
+		}
+		return $value;
+	}
+	
+	// Set meta data in raw data
+	function setMetaData($rawData, $key, $value)
+	{
+		if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)\-\-\-[\r\n]+(.*)$/s", $rawData, $parts))
+		{
+			$key = lcfirst($key);
+			foreach($this->getTextLines($parts[2]) as $line)
+			{
+				preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+				if(lcfirst($matches[1])==$key)
+				{
+					$rawDataNew .= "$matches[1]: $value\n";
+					$found = true;
+				} else {
+					$rawDataNew .= $line;
+				}
+			}
+			if(!$found) $rawDataNew .= ucfirst($key).": $value\n";
+			$rawDataNew = $parts[1]."---\n".$rawDataNew."---\n".$parts[3];
+		} else {
+			$rawDataNew = $rawData;
+		}
+		return $rawDataNew;
+	}
+	
 	// Detect web browser language
 	function detectBrowserLanguage($languages, $languageDefault)
 	{

+ 1 - 1
system/plugins/webinterface.css → system/plugins/edit.css

@@ -1,4 +1,4 @@
-/* Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface */
+/* Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit */
 /* Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se */
 /* This file may be used and distributed under the terms of the public license. */
 

+ 32 - 29
system/plugins/webinterface.js → system/plugins/edit.js

@@ -1,20 +1,21 @@
-// Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface
+// Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit
 // Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 var yellow =
 {
-	action: function(action, status, args) { yellow.webinterface.action(action, status, args); },
-	onLoad: function() { yellow.webinterface.loadInterface(); },
-	onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); },
-	onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); },
-	onUpdate: function() { yellow.webinterface.updatePane(yellow.webinterface.paneId, yellow.webinterface.paneAction, yellow.webinterface.paneStatus); },
-	onResize: function() { yellow.webinterface.resizePane(yellow.webinterface.paneId, yellow.webinterface.paneAction, yellow.webinterface.paneStatus); }
+	action: function(action, status, args) { yellow.edit.action(action, status, args); },
+	onLoad: function() { yellow.edit.load(); },
+	onClick: function(e) { yellow.edit.hidePanesOnClick(yellow.toolbox.getEventElement(e)); },
+	onKeydown: function(e) { yellow.edit.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); },
+	onUpdate: function() { yellow.edit.updatePane(yellow.edit.paneId, yellow.edit.paneAction, yellow.edit.paneStatus); },
+	onResize: function() { yellow.edit.resizePane(yellow.edit.paneId, yellow.edit.paneAction, yellow.edit.paneStatus); }
 };
 
-yellow.webinterface =
+yellow.edit =
 {
 	paneId: 0,			//visible pane ID
+	paneActionOld: 0,	//previous pane action
 	paneAction: 0,		//current pane action
 	paneStatus: 0,		//current pane status
 	intervalId: 0,		//timer interval ID
@@ -41,14 +42,14 @@ yellow.webinterface =
 			case "edit":		this.showPane("yellow-pane-edit", action, status, true); break;
 			case "delete":		this.showPane("yellow-pane-edit", action, status, true); break;
 			case "user":		this.showPane("yellow-pane-user", action, status); break;
+			case "help":		this.hidePane(this.paneId); location.href = this.getText("UserHelpUrl", "yellow"); break;
 			case "send":		this.sendPane(this.paneId, this.paneAction); break;
 			case "close":		this.hidePane(this.paneId); break;
-			case "help":		this.hidePane(this.paneId); location.href = this.getText("UserHelpUrl", "yellow"); break;
 		}
 	},
 	
-	// Initialise interface
-	loadInterface: function()
+	// Load interface
+	load: function()
 	{
 		var body = document.getElementsByTagName("body")[0];
 		if(body && body.firstChild && !document.getElementById("yellow-bar"))
@@ -63,7 +64,7 @@ yellow.webinterface =
 	// Create bar
 	createBar: function(barId)
 	{
-		if(yellow.config.debug) console.log("yellow.webinterface.createBar id:"+barId);
+		if(yellow.config.debug) console.log("yellow.edit.createBar id:"+barId);
 		var elementBar = document.createElement("div");
 		elementBar.className = "yellow-bar";
 		elementBar.setAttribute("id", barId);
@@ -92,7 +93,7 @@ yellow.webinterface =
 	// Create pane
 	createPane: function(paneId, paneAction, paneStatus)
 	{
-		if(yellow.config.debug) console.log("yellow.webinterface.createPane id:"+paneId);
+		if(yellow.config.debug) console.log("yellow.edit.createPane id:"+paneId);
 		var elementPane = document.createElement("div");
 		elementPane.className = "yellow-pane";
 		elementPane.setAttribute("id", paneId);
@@ -120,13 +121,13 @@ yellow.webinterface =
 				"<h1>"+this.getText("LoginTitle")+"</h1>"+
 				"<div id=\"yellow-pane-login-fields\">"+
 				"<input type=\"hidden\" name=\"action\" value=\"login\" />"+
-				"<p><label for=\"yellow-pane-login-email\">"+this.getText("LoginEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-login-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(yellow.config.loginEmail)+"\" /></p>"+
-				"<p><label for=\"yellow-pane-login-password\">"+this.getText("LoginPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-login-password\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(yellow.config.loginPassword)+"\" /></p>"+
+				"<p><label for=\"yellow-pane-login-email\">"+this.getText("LoginEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-login-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(yellow.config.editLoginEmail)+"\" /></p>"+
+				"<p><label for=\"yellow-pane-login-password\">"+this.getText("LoginPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-login-password\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(yellow.config.editLoginPassword)+"\" /></p>"+
 				"<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\" /></p>"+
 				"</div>"+
 				"<div id=\"yellow-pane-login-buttons\">"+
-				"<p><a href=\"#\" onclick=\"yellow.action('recover'); return false;\">"+this.getText("LoginRecover")+"</a><p>"+
-				"<p><a href=\"#\" onclick=\"yellow.action('signup'); return false;\">"+this.getText("LoginSignup")+"</a><p>"+
+				"<p><a href=\"#\" onclick=\"yellow.action('recover'); return false;\" id=\"yellow-pane-login-recover\">"+this.getText("LoginRecover")+"</a><p>"+
+				"<p><a href=\"#\" onclick=\"yellow.action('signup'); return false;\" id=\"yellow-pane-login-signup\">"+this.getText("LoginSignup")+"</a><p>"+
 				"</div>"+
 				"</form>";
 				break;
@@ -226,14 +227,14 @@ yellow.webinterface =
 	// Update pane
 	updatePane: function(paneId, paneAction, paneStatus, init)
 	{
-		if(yellow.config.debug) console.log("yellow.webinterface.updatePane id:"+paneId);
+		if(yellow.config.debug) console.log("yellow.edit.updatePane id:"+paneId);
 		var showFields = paneStatus!="next" && paneStatus!="done" && paneStatus!="expired";
 		switch(paneId)
 		{
 			case "yellow-pane-login":
-				if(yellow.config.loginRestrictions)
+				if(yellow.config.editLoginRestrictions)
 				{
-					yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-buttons"), false);
+					yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-signup"), false);
 				}
 				break;
 			case "yellow-pane-signup":
@@ -266,7 +267,7 @@ yellow.webinterface =
 				}
 				break;
 			case "yellow-pane-version":
-				if(paneStatus=="none" && yellow.config.pluginUpdate)
+				if(paneStatus=="none" && yellow.config.userUpdate)
 				{
 					document.getElementById("yellow-pane-version-status").innerHTML = this.getText("VersionStatusCheck");
 					document.getElementById("yellow-pane-version-fields").innerHTML = "";
@@ -280,11 +281,12 @@ yellow.webinterface =
 			case "yellow-pane-edit":
 				if(init)
 				{
-					var title = yellow.page.title;
+					var title;
 					var string = yellow.page.rawDataEdit;
 					switch(paneAction)
 					{
 						case "create":	title = this.getText("CreateTitle"); string = yellow.page.rawDataNew; break;
+						case "edit":	title = yellow.page.title ? yellow.page.title : this.getText("Edit"); break;
 						case "delete":	title = this.getText("DeleteTitle"); break;
 					}
 					document.getElementById("yellow-pane-edit-title").innerHTML = yellow.toolbox.encodeHtml(title);
@@ -363,7 +365,7 @@ yellow.webinterface =
 			if(!element) element = this.createPane(paneId, paneAction, paneStatus);
 			if(!yellow.toolbox.isVisible(element))
 			{
-				if(yellow.config.debug) console.log("yellow.webinterface.showPane id:"+paneId);
+				if(yellow.config.debug) console.log("yellow.edit.showPane id:"+paneId);
 				yellow.toolbox.setVisible(element, true);
 				if(modal)
 				{
@@ -374,7 +376,7 @@ yellow.webinterface =
 				this.paneAction = paneAction;
 				this.paneStatus = paneStatus;
 				this.resizePane(paneId, paneAction, paneStatus);
-				this.updatePane(paneId, paneAction, paneStatus, true);
+				this.updatePane(paneId, paneAction, paneStatus, this.paneActionOld!=this.paneAction);
 			}
 		} else {
 			this.hidePane(this.paneId);
@@ -387,11 +389,12 @@ yellow.webinterface =
 		var element = document.getElementById(paneId);
 		if(yellow.toolbox.isVisible(element))
 		{
-			if(yellow.config.debug) console.log("yellow.webinterface.hidePane id:"+paneId);
+			if(yellow.config.debug) console.log("yellow.edit.hidePane id:"+paneId);
 			yellow.toolbox.removeClass(document.body, "yellow-body-modal-open");
 			yellow.toolbox.removeValue("meta[name=viewport]", "content", ", maximum-scale=1, user-scalable=0");
 			yellow.toolbox.setVisible(element, false);
 			this.paneId = 0;
+			this.paneActionOld = this.paneAction;
 			this.paneAction = 0;
 			this.paneStatus = 0;
 		}
@@ -431,7 +434,7 @@ yellow.webinterface =
 	// Send pane
 	sendPane: function(paneId, paneAction, paneStatus, paneArgs)
 	{
-		if(yellow.config.debug) console.log("yellow.webinterface.sendPane id:"+paneId);
+		if(yellow.config.debug) console.log("yellow.edit.sendPane id:"+paneId);
 		if(paneId=="yellow-pane-edit")
 		{
 			paneAction = this.getPaneAction(paneId, paneAction);
@@ -490,7 +493,7 @@ yellow.webinterface =
 			for(var language in yellow.config.serverLanguages)
 			{
 				var checked = language==this.getRequest("language") ? " checked=\"checked\"" : "";
-				languages += "<label for=\""+paneId+"-"+language+"\"><input type=\"radio\" name=\"language\" id=\""+paneId+"-"+language+"\" value=\""+language+"\""+checked+"> "+yellow.config.serverLanguages[language]+"</label><br />";
+				languages += "<label for=\""+paneId+"-"+language+"\"><input type=\"radio\" name=\"language\" id=\""+paneId+"-"+language+"\" value=\""+language+"\""+checked+"> "+yellow.toolbox.encodeHtml(yellow.config.serverLanguages[language])+"</label><br />";
 			}
 			languages += "</p>";
 		}
@@ -508,7 +511,7 @@ yellow.webinterface =
 	// Return text string
 	getText: function(key, prefix, postfix)
 	{
-		if(!prefix) prefix = "webinterface";
+		if(!prefix) prefix = "edit";
 		if(!postfix) postfix = "";
 		key = prefix + key.charAt(0).toUpperCase() + key.slice(1) + postfix.charAt(0).toUpperCase() + postfix.slice(1);
 		return (key in yellow.text) ? yellow.text[key] : "["+key+"]";
@@ -805,4 +808,4 @@ yellow.toolbox =
 	}
 };
 
-yellow.webinterface.intervalId = setInterval("yellow.onLoad()", 1);
+yellow.edit.intervalId = setInterval("yellow.onLoad()", 1);

+ 223 - 188
system/plugins/webinterface.php → system/plugins/edit.php

@@ -1,15 +1,15 @@
 <?php
-// Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface
+// Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit
 // Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
-class YellowWebinterface
+class YellowEdit
 {
-	const VERSION = "0.6.21";
+	const VERSION = "0.7.1";
 	var $yellow;			//access to API
-	var $response;			//web interface response
-	var $users;				//web interface users
-	var $merge;				//web interface merge
+	var $response;			//web response
+	var $users;				//user accounts
+	var $merge;				//text merge
 
 	// Handle initialisation
 	function onLoad($yellow)
@@ -18,16 +18,18 @@ class YellowWebinterface
 		$this->response = new YellowResponse($yellow);
 		$this->users = new YellowUsers($yellow);
 		$this->merge = new YellowMerge($yellow);
-		$this->yellow->config->setDefault("webinterfaceLocation", "/edit/");
-		$this->yellow->config->setDefault("webinterfaceNewFile", "page-new-(.*).txt");
-		$this->yellow->config->setDefault("webinterfaceMetaFilePrefix", "published");
-		$this->yellow->config->setDefault("webinterfaceUserFile", "user.ini");
-		$this->yellow->config->setDefault("webinterfaceUserPasswordMinLength", "4");
-		$this->yellow->config->setDefault("webinterfaceUserHashAlgorithm", "bcrypt");
-		$this->yellow->config->setDefault("webinterfaceUserHashCost", "10");
-		$this->yellow->config->setDefault("webinterfaceUserStatus", "active");
-		$this->yellow->config->setDefault("webinterfaceUserHome", "/");
-		$this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"));
+		$this->yellow->config->setDefault("editLocation", "/edit/");
+		$this->yellow->config->setDefault("editNewFile", "page-new-(.*).txt");
+		$this->yellow->config->setDefault("editUserFile", "user.ini");
+		$this->yellow->config->setDefault("editUserPasswordMinLength", "4");
+		$this->yellow->config->setDefault("editUserHashAlgorithm", "bcrypt");
+		$this->yellow->config->setDefault("editUserHashCost", "10");
+		$this->yellow->config->setDefault("editUserStatus", "active");
+		$this->yellow->config->setDefault("editUserHome", "/");
+		$this->yellow->config->setDefault("editLoginEmail", "");
+		$this->yellow->config->setDefault("editLoginPassword", "");
+		$this->yellow->config->setDefault("editLoginRestrictions", "0");
+		$this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile"));
 	}
 
 	// Handle startup
@@ -44,7 +46,7 @@ class YellowWebinterface
 		{
 			$scheme = $this->yellow->config->get("serverScheme");
 			$address = $this->yellow->config->get("serverAddress");
-			$base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"), '/');
+			$base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("editLocation"), '/');
 			list($scheme, $address, $base, $location, $fileName) = $this->yellow->getRequestInformation($scheme, $address, $base);
 			$this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
 			$statusCode = $this->processRequest($scheme, $address, $base, $location, $fileName);
@@ -90,8 +92,8 @@ class YellowWebinterface
 		if($name=="header" && $this->response->isActive())
 		{
 			$pluginLocation = $this->yellow->config->get("serverBase").$this->yellow->config->get("pluginLocation");
-			$output = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"{$pluginLocation}webinterface.css\" />\n";
-			$output .= "<script type=\"text/javascript\" src=\"{$pluginLocation}webinterface.js\"></script>\n";
+			$output = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"{$pluginLocation}edit.css\" />\n";
+			$output .= "<script type=\"text/javascript\" src=\"{$pluginLocation}edit.js\"></script>\n";
 			$output .= "<script type=\"text/javascript\">\n";
 			$output .= "// <![CDATA[\n";
 			$output .= "yellow.page = ".json_encode($this->response->getPageData()).";\n";
@@ -129,7 +131,7 @@ class YellowWebinterface
 		list($command, $path) = $args;
 		if($path=="all")
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			if(!$this->users->clean($fileNameUser)) $statusCode = 500;
 			if($statusCode==500) echo "ERROR cleaning configuration: Can't write file '$fileNameUser'!\n";
 		}
@@ -152,13 +154,13 @@ class YellowWebinterface
 			}
 			if($status=="ok")
 			{
-				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 				$status = $this->users->update($fileNameUser, $email, $password, $name, $language, "active") ? "ok" : "error";
 				if($status=="error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n";
 			}
 			if($status=="ok")
 			{
-				$algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm");
+				$algorithm = $this->yellow->config->get("editUserHashAlgorithm");
 				$status = substru($this->users->getHash($email), 0, 5)!="error-hash" ? "ok" : "error";
 				if($status=="error") echo "ERROR updating configuration: Hash algorithm '$algorithm' not supported!\n";
 			}
@@ -209,7 +211,7 @@ class YellowWebinterface
 				case "reconfirm":	$statusCode = $this->processRequestReconfirm($scheme, $address, $base, $location, $fileName); break;
 				case "change":		$statusCode = $this->processRequestChange($scheme, $address, $base, $location, $fileName); break;
 			}
-			if($this->response->action=="fail") $this->yellow->page->error(500, "Login failed, [please log in](javascript:yellow.action('login');)!");
+			if($this->response->action=="fail") $this->yellow->page->error(500, "Login failed, <a href=\"javascript:yellow.action('login');\">please log in</a>!");
 		}
 		return $statusCode;
 	}
@@ -283,7 +285,7 @@ class YellowWebinterface
 		if($this->response->status=="ok" && $this->users->isTaken($email)) $this->response->status = "next";
 		if($this->response->status=="ok")
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->response->status = $this->users->update($fileNameUser, $email, $password, $name, "", "unconfirmed") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 		}
@@ -305,7 +307,7 @@ class YellowWebinterface
 		$this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
 		if($this->response->status=="ok")
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "unapproved") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 		}
@@ -327,7 +329,7 @@ class YellowWebinterface
 		$this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
 		if($this->response->status=="ok")
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 		}
@@ -350,7 +352,6 @@ class YellowWebinterface
 		if(empty($_REQUEST["id"]))
 		{
 			if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $this->response->status = "invalid";
-			if($this->response->status=="ok" && $this->response->isLoginRestrictions()) $this->response->status = "next";
 			if($this->response->status=="ok" && !$this->users->isExisting($email)) $this->response->status = "next";
 			if($this->response->status=="ok")
 			{
@@ -365,7 +366,7 @@ class YellowWebinterface
 				if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
 				if($this->response->status=="ok")
 				{
-					$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+					$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 					$this->response->status = $this->users->update($fileNameUser, $email, $password) ? "ok" : "error";
 					if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 				}
@@ -400,14 +401,14 @@ class YellowWebinterface
 			if($this->response->status=="ok" && $email!=$emailSource)
 			{
 				$pending = $emailSource;
-				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 				$this->response->status = $this->users->update($fileNameUser, $email, "no", $name, $language, "unconfirmed", "", $pending) ? "ok" : "error";
 				if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 			}
 			if($this->response->status=="ok")
 			{
 				$pending = $email.':'.(empty($password) ? $this->users->getHash($emailSource) : $this->users->createHash($password));
-				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 				$this->response->status = $this->users->update($fileNameUser, $emailSource, "", $name, $language, "", "", $pending) ? "ok" : "error";
 				if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 			}
@@ -420,7 +421,7 @@ class YellowWebinterface
 		} else {
 			if($this->response->status=="ok")
 			{
-				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+				$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 				$this->response->status = $this->users->update($fileNameUser, $email, "", $name, $language) ? "done" : "error";
 				if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 			}
@@ -450,7 +451,7 @@ class YellowWebinterface
 		}
 		if($this->response->status=="ok")
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "unchanged") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 		}
@@ -477,7 +478,7 @@ class YellowWebinterface
 		}
 		if($this->response->status=="ok" && $email!=$emailSource)
 		{
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->users->users[$emailSource]["pending"] = "none";
 			$this->response->status = $this->users->update($fileNameUser, $emailSource, "", "", "", "inactive") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
@@ -486,7 +487,7 @@ class YellowWebinterface
 		{
 			$this->users->users[$email]["hash"] = $hash;
 			$this->users->users[$email]["pending"] = "none";
-			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
+			$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
 			$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "ok" : "error";
 			if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 		}
@@ -529,7 +530,7 @@ class YellowWebinterface
 					{
 						if(!is_null($dataModified[$key]) && !is_null($dataLatest[$key]))
 						{
-							$rawData = $this->yellow->text->getTextHtml("webinterfaceVersionUpdateModified", $this->response->language)." - <a href=\"#\" onclick=\"yellow.action('update','update','".$this->yellow->toolbox->normaliseArgs("option:force/feature:$key")."'); return false;\">".$this->yellow->text->getTextHtml("webinterfaceVersionUpdateForce", $this->response->language)."</a>";
+							$rawData = $this->yellow->text->getTextHtml("editVersionUpdateModified", $this->response->language)." - <a href=\"#\" onclick=\"yellow.action('update','update','".$this->yellow->toolbox->normaliseArgs("option:force/feature:$key")."'); return false;\">".$this->yellow->text->getTextHtml("editVersionUpdateForce", $this->response->language)."</a>";
 							$rawData = preg_replace("/@software/i", htmlspecialchars("$key $dataLatest[$key]"), $rawData);
 							if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "<br />\n";
 							$this->response->rawDataOutput .= $rawData;
@@ -575,7 +576,7 @@ class YellowWebinterface
 		if(!$this->response->isUserRestrictions() && !empty($_POST["rawdataedit"]))
 		{
 			$this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
-			$rawData = $this->response->normaliseText(rawurldecode($_POST["rawdataedit"]));
+			$rawData = rawurldecode($_POST["rawdataedit"]);
 			$page = $this->response->getPageNew($scheme, $address, $base, $location, $fileName, $rawData);
 			if(!$page->isError())
 			{
@@ -605,12 +606,12 @@ class YellowWebinterface
 		if(!$this->response->isUserRestrictions() && !empty($_POST["rawdataedit"]))
 		{
 			$this->response->rawDataSource = rawurldecode($_POST["rawdatasource"]);
-			$this->response->rawDataEdit = $this->response->normaliseText(rawurldecode($_POST["rawdataedit"]));
-			$page = $this->response->getPageUpdate($scheme, $address, $base, $location, $fileName,
+			$this->response->rawDataEdit = rawurldecode($_POST["rawdataedit"]);
+			$page = $this->response->getPageEdit($scheme, $address, $base, $location, $fileName,
 				$this->response->rawDataSource, $this->response->rawDataEdit, $this->yellow->toolbox->readFile($fileName));
 			if(!$page->isError())
 			{
-				if($this->yellow->toolbox->renameFile($fileName, $page->fileName) &&
+				if($this->yellow->toolbox->renameFile($fileName, $page->fileName, true) &&
 				   $this->yellow->toolbox->createFile($page->fileName, $page->rawData))
 				{
 					$statusCode = 303;
@@ -637,43 +638,51 @@ class YellowWebinterface
 		if(!$this->response->isUserRestrictions() && is_file($fileName))
 		{
 			$this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
-			if($this->yellow->lookup->isFileLocation($location))
+			$page = $this->response->getPageDelete($scheme, $address, $base, $location, $fileName, $this->response->rawDataSource);
+			if(!$page->isError())
 			{
-				if($this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir")))
+				if($this->yellow->lookup->isFileLocation($location))
 				{
-					$statusCode = 303;
-					$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
-					$this->yellow->sendStatus($statusCode, $location);
+					if($this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir")))
+					{
+						$statusCode = 303;
+						$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+						$this->yellow->sendStatus($statusCode, $location);
+					} else {
+						$statusCode = 500;
+						$this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+						$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
+					}
 				} else {
-					$statusCode = 500;
-					$this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
-					$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
+					if($this->yellow->toolbox->deleteDirectory(dirname($fileName), $this->yellow->config->get("trashDir")))
+					{
+						$statusCode = 303;
+						$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+						$this->yellow->sendStatus($statusCode, $location);
+					} else {
+						$statusCode = 500;
+						$this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+						$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
+					}
 				}
 			} else {
-				if($this->yellow->toolbox->deleteDirectory(dirname($fileName), $this->yellow->config->get("trashDir")))
-				{
-					$statusCode = 303;
-					$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
-					$this->yellow->sendStatus($statusCode, $location);
-				} else {
-					$statusCode = 500;
-					$this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
-					$this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
-				}
+				$statusCode = 500;
+				$this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+				$this->yellow->page->error($statusCode, $page->get("pageError"));
 			}
 		}
 		return $statusCode;
 	}
 
-	// Check web interface request
+	// Check request
 	function checkRequest($location)
 	{
-		$locationLength = strlenu($this->yellow->config->get("webinterfaceLocation"));
-		$this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("webinterfaceLocation");
+		$locationLength = strlenu($this->yellow->config->get("editLocation"));
+		$this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("editLocation");
 		return $this->response->isActive();
 	}
 	
-	// Check web interface user
+	// Check user
 	function checkUser($scheme, $address, $base, $location, $fileName)
 	{
 		if($_POST["action"]=="login")
@@ -685,7 +694,7 @@ class YellowWebinterface
 				$this->response->createCookie($scheme, $address, $base, $email);
 				$this->response->userEmail = $email;
 				$this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
-				$this->response->language = $this->response->getLanguage($email);
+				$this->response->language = $this->getUserLanguage($email);
 			} else {
 				$this->response->action = "fail";
 			}
@@ -695,7 +704,7 @@ class YellowWebinterface
 			{
 				$this->response->userEmail = $email;
 				$this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
-				$this->response->language = $this->response->getLanguage($email);
+				$this->response->language = $this->getUserLanguage($email);
 			} else {
 				$this->response->action = "fail";
 			}
@@ -709,30 +718,30 @@ class YellowWebinterface
 		$status = null;
 		foreach($this->yellow->plugins->plugins as $key=>$value)
 		{
-			if(method_exists($value["obj"], "onUserAccount"))
+			if(method_exists($value["obj"], "onEditUserAccount"))
 			{
-				$status = $value["obj"]->onUserAccount($email, $password, $action, $status, $this->users);
+				$status = $value["obj"]->onEditUserAccount($email, $password, $action, $this->users);
 				if(!is_null($status)) break;
 			}
 		}
 		if(is_null($status))
 		{
 			$status = "ok";
-			if(!empty($password) && strlenu($password)<$this->yellow->config->get("webinterfaceUserPasswordMinLength")) $status = "weak";
+			if(!empty($password) && strlenu($password)<$this->yellow->config->get("editUserPasswordMinLength")) $status = "weak";
 			if(!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) $status = "invalid";
 		}
 		return $status;
 	}
 	
-	// Return user restrictions to change page
+	// Return user restrictions
 	function getUserRestrictions($email, $location, $fileName)
 	{
 		$userRestrictions = null;
 		foreach($this->yellow->plugins->plugins as $key=>$value)
 		{
-			if(method_exists($value["obj"], "onUserRestrictions"))
+			if(method_exists($value["obj"], "onEditUserRestrictions"))
 			{
-				$userRestrictions = $value["obj"]->onUserRestrictions($email, $location, $fileName, $this->users);
+				$userRestrictions = $value["obj"]->onEditUserRestrictions($email, $location, $fileName, $this->users);
 				if(!is_null($userRestrictions)) break;
 			}
 		}
@@ -743,15 +752,23 @@ class YellowWebinterface
 		}
 		return $userRestrictions;
 	}
+	
+	// Return user language
+	function getUserLanguage($email)
+	{
+		$language = $this->users->getLanguage($email);
+		if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
+		return $language;
+	}
 }
 	
 class YellowResponse
 {
 	var $yellow;			//access to API
-	var $webinterface;		//access to web interface
+	var $plugin;			//access to plugin
 	var $userEmail;			//user email
 	var $userRestrictions;	//user can change page? (boolean)
-	var $active;			//web interface is active? (boolean)
+	var $active;			//location is active? (boolean)
 	var $rawDataSource;		//raw data of page for comparison
 	var $rawDataEdit;		//raw data of page for editing
 	var $rawDataOutput;		//raw data of dynamic output
@@ -762,7 +779,7 @@ class YellowResponse
 	function __construct($yellow)
 	{
 		$this->yellow = $yellow;
-		$this->webinterface = $yellow->plugins->get("webinterface");
+		$this->plugin = $yellow->plugins->get("edit");
 	}
 	
 	// Return new page
@@ -771,77 +788,78 @@ class YellowResponse
 		$page = new YellowPage($this->yellow);
 		$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
 		$page->parseData($rawData, false, 0);
-		if($this->yellow->lookup->isFileLocation($location) || is_file($fileName))
+		$this->editContentFile($page, "create");
+		if($this->yellow->lookup->isFileLocation($location) || $this->yellow->pages->find($page->location))
 		{
-			$page->fileName = $this->yellow->lookup->findFileFromTitle(
-				$page->get($this->yellow->config->get("webinterfaceMetaFilePrefix")), $page->get("title"), $fileName,
-				$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
-			$page->location = $this->yellow->lookup->findLocationFromFile($page->fileName);
-			if($this->yellow->pages->find($page->location))
+			$page->location = $this->getLocationNew($page->rawData, $page->location, $page->get("pageNewLocation"));
+			$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
+			while($this->yellow->pages->find($page->location) || empty($page->fileName))
 			{
-				preg_match("/^(.*?)(\d*)$/", $page->get("title"), $matches);
-				$titleText = $matches[1];
-				$titleNumber = $matches[2];
-				if(strempty($titleNumber)) { $titleNumber = 2; $titleText = $titleText.' '; }
-				for(; $titleNumber<=999; ++$titleNumber)
-				{
-					$page->rawData = $this->updateTextTitle($rawData, $titleText.$titleNumber);
-					$page->fileName = $this->yellow->lookup->findFileFromTitle(
-						$page->get($this->yellow->config->get("webinterfaceMetaFilePrefix")), $titleText.$titleNumber, $fileName,
-						$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
-					$page->location = $this->yellow->lookup->findLocationFromFile($page->fileName);
-					if(!$this->yellow->pages->find($page->location)) { $ok = true; break; }
-				}
-				if(!$ok) $page->error(500, "Page '".$page->get("title")."' can not be created!");
+				$page->rawData = $this->yellow->toolbox->setMetaData($page->rawData, "title", $this->getTitleNext($page->rawData));
+				$page->location = $this->getLocationNew($page->rawData, $page->location, $page->get("pageNewLocation"));
+				$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
+				if(++$pageCounter>999) break;
 			}
+			if($this->yellow->pages->find($page->location) || empty($page->fileName))
+			{
+				$page->error(500, "Page '".$page->get("title")."' is not possible!");
+			}
+		} else {
+			$page->fileName = $this->yellow->lookup->findFileNew($page->location);
 		}
-		if(!is_dir(dirname($page->fileName)))
-		{
-			preg_match("/^([\d\-\_\.]*)(.*)$/", $page->get("title"), $matches);
-			if(preg_match("/\d$/", $matches[1])) $matches[1] .= '-';
-			$page->fileName = $this->yellow->lookup->findFilePageNew($fileName, $matches[1]);
-			$page->location = $this->yellow->lookup->findLocationFromFile($page->fileName);
-		}
-		if($this->webinterface->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
+		if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
 		{
-			$page->error(500, "Page '".$page->get("title")."' is not allowed!");
+			$page->error(500, "Page '".$page->get("title")."' is restricted!");
 		}
 		return $page;
 	}
 	
 	// Return modified page
-	function getPageUpdate($scheme, $address, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile)
+	function getPageEdit($scheme, $address, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile)
 	{
 		$page = new YellowPage($this->yellow);
 		$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
-		$page->parseData($this->webinterface->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), false, 0);
+		$page->parseData($this->plugin->merge->merge($rawDataSource, $rawDataEdit, $rawDataFile), false, 0);
+		$this->editContentFile($page, "edit");
 		if(empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
 		if($this->yellow->lookup->isFileLocation($location) && !$page->isError())
 		{
 			$pageSource = new YellowPage($this->yellow);
 			$pageSource->setRequestInformation($scheme, $address, $base, $location, $fileName);
 			$pageSource->parseData($rawDataSource, false, 0);
-			$prefix = $this->yellow->config->get("webinterfaceMetaFilePrefix");
-			if($pageSource->get($prefix)!=$page->get($prefix) || $pageSource->get("title")!=$page->get("title"))
+			if(substrb($pageSource->rawData, 0, $pageSource->metaDataOffsetBytes) !=
+			   substrb($page->rawData, 0, $page->metaDataOffsetBytes))
 			{
-				$page->fileName = $this->yellow->lookup->findFileFromTitle(
-					$page->get($prefix), $page->get("title"), $fileName,
-					$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
-				$page->location = $this->yellow->lookup->findLocationFromFile($page->fileName);
-				if($pageSource->location!=$page->location)
+				$page->location = $this->getLocationNew($page->rawData, $page->location, $page->get("pageNewLocation"));
+				$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
+				if($page->location!=$pageSource->location)
 				{
-					if(!$this->yellow->lookup->isFileLocation($page->location))
+					if(!$this->yellow->lookup->isFileLocation($page->location) || empty($page->fileName))
 					{
-						$page->error(500, "Page '".$page->get("title")."' is not allowed!");
+						$page->error(500, "Page '".$page->get("title")."' is not possible!");
 					} else if($this->yellow->pages->find($page->location)) {
 						$page->error(500, "Page '".$page->get("title")."' already exists!");
 					}
 				}
 			}
 		}
-		if($this->webinterface->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
+		if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
 		{
-			$page->error(500, "Page '".$page->get("title")."' is not allowed!");
+			$page->error(500, "Page '".$page->get("title")."' is restricted!");
+		}
+		return $page;
+	}
+	
+	// Return deleted page
+	function getPageDelete($scheme, $address, $base, $location, $fileName, $rawDataSource)
+	{
+		$page = new YellowPage($this->yellow);
+		$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
+		$page->parseData($rawDataSource, false, 0);
+		$this->editContentFile($page, "delete");
+		if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
+		{
+			$page->error(500, "Page '".$page->get("title")."' is restricted!");
 		}
 		return $page;
 	}
@@ -852,7 +870,7 @@ class YellowResponse
 		$data = array();
 		if($this->isUser())
 		{
-			$data["title"] = $this->getPageTitle($this->rawDataEdit);
+			$data["title"] = $this->yellow->toolbox->getMetaData($this->rawDataEdit, "title");
 			$data["rawDataSource"] = $this->rawDataSource;
 			$data["rawDataEdit"] = $this->rawDataEdit;
 			$data["rawDataNew"] = $this->getRawDataNew();
@@ -877,13 +895,13 @@ class YellowResponse
 		if($this->isUser())
 		{
 			$data["userEmail"] = $this->userEmail;
-			$data["userName"] = $this->webinterface->users->getName($this->userEmail);
-			$data["userLanguage"] = $this->webinterface->users->getLanguage($this->userEmail);
-			$data["userStatus"] = $this->webinterface->users->getStatus($this->userEmail);
-			$data["userHome"] = $this->webinterface->users->getHome($this->userEmail);
+			$data["userName"] = $this->plugin->users->getName($this->userEmail);
+			$data["userLanguage"] = $this->plugin->users->getLanguage($this->userEmail);
+			$data["userStatus"] = $this->plugin->users->getStatus($this->userEmail);
+			$data["userHome"] = $this->plugin->users->getHome($this->userEmail);
 			$data["userRestrictions"] = intval($this->isUserRestrictions());
 			$data["userWebmaster"] = intval($this->isUserWebmaster());
-			$data["pluginUpdate"] = intval($this->yellow->plugins->isExisting("update"));
+			$data["userUpdate"] = intval($this->yellow->plugins->isExisting("update"));
 			$data["serverLanguages"] = array();
 			foreach($this->yellow->text->getLanguages() as $language)
 			{
@@ -892,11 +910,11 @@ class YellowResponse
 			$data["serverScheme"] = $this->yellow->config->get("serverScheme");
 			$data["serverAddress"] = $this->yellow->config->get("serverAddress");
 			$data["serverBase"] = $this->yellow->config->get("serverBase");
-			$data["serverVersion"] = "Yellow ".YellowCore::VERSION;
+			$data["serverVersion"] = "Datenstrom Yellow ".YellowCore::VERSION;
 		} else {
-			$data["loginEmail"] = $this->yellow->config->get("loginEmail");
-			$data["loginPassword"] = $this->yellow->config->get("loginPassword");
-			$data["loginRestrictions"] = intval($this->isLoginRestrictions());
+			$data["editLoginEmail"] = $this->yellow->config->get("editLoginEmail");
+			$data["editLoginPassword"] = $this->yellow->config->get("editLoginPassword");
+			$data["editLoginRestrictions"] = intval($this->isLoginRestrictions());
 		}
 		if(defined("DEBUG") && DEBUG>=1) $data["debug"] = DEBUG;
 		return $data;
@@ -918,80 +936,85 @@ class YellowResponse
 	function getTextData()
 	{
 		$textLanguage = $this->yellow->text->getData("language", $this->language);
-		$textWebinterface = $this->yellow->text->getData("webinterface", $this->language);
+		$textEdit = $this->yellow->text->getData("edit", $this->language);
 		$textYellow = $this->yellow->text->getData("yellow", $this->language);
-		return array_merge($textLanguage, $textWebinterface, $textYellow);
+		return array_merge($textLanguage, $textEdit, $textYellow);
 	}
 	
 	// Return raw data for new page
 	function getRawDataNew($location = "")
 	{
-		$fileName = $this->yellow->lookup->findFileFromLocation($this->yellow->page->location);
-		$fileName = $this->yellow->lookup->findFileFromConfig($fileName,
-			$this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("template"));
+		foreach($this->yellow->pages->path($this->yellow->page->location)->reverse() as $page)
+		{
+			if($page->isExisting("templateNew"))
+			{
+				$name = $this->yellow->lookup->normaliseName($page->get("templateNew"));
+				$fileName = strreplaceu("(.*)", $name, $this->yellow->config->get("configDir").$this->yellow->config->get("editNewFile"));
+				if(is_file($fileName)) break;
+			}
+		}
+		if(!is_file($fileName))
+		{
+			$name = $this->yellow->lookup->normaliseName($this->yellow->config->get("template"));
+			$fileName = strreplaceu("(.*)", $name, $this->yellow->config->get("configDir").$this->yellow->config->get("editNewFile"));
+		}
 		$rawData = $this->yellow->toolbox->readFile($fileName);
+		$rawData = preg_replace("/@timestamp/i", time(), $rawData);
 		$rawData = preg_replace("/@datetime/i", date("Y-m-d H:i:s"), $rawData);
 		$rawData = preg_replace("/@date/i", date("Y-m-d"), $rawData);
-		$rawData = preg_replace("/@usershort/i", strtok($this->webinterface->users->getName($this->userEmail), " "), $rawData);
-		$rawData = preg_replace("/@username/i", $this->webinterface->users->getName($this->userEmail), $rawData);
-		$rawData = preg_replace("/@userlanguage/i", $this->webinterface->users->getLanguage($this->userEmail), $rawData);
+		$rawData = preg_replace("/@usershort/i", strtok($this->plugin->users->getName($this->userEmail), " "), $rawData);
+		$rawData = preg_replace("/@username/i", $this->plugin->users->getName($this->userEmail), $rawData);
+		$rawData = preg_replace("/@userlanguage/i", $this->plugin->users->getLanguage($this->userEmail), $rawData);
 		if(!empty($location))
 		{
-			$title = $this->yellow->toolbox->createTextTitle($location);
-			$rawData = $this->updateTextTitle($rawData, $title);
+			$rawData = $this->yellow->toolbox->setMetaData($rawData, "title", $this->yellow->toolbox->createTextTitle($location));
 		}
 		return $rawData;
 	}
 	
-	// Return page title
-	function getPageTitle($rawData)
+	// Return location for new/modified page
+	function getLocationNew($rawData, $pageLocation, $pageNewLocation)
 	{
-		$title = $this->yellow->page->get("title");
-		if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)\-\-\-[\r\n]+/s", $rawData, $parts))
+		$location = empty($pageNewLocation) ? "@title" : $pageNewLocation;
+		$location = preg_replace("/@timestamp/i", $this->getLocationDataNew($rawData, "published", true, "U"), $location);
+		$location = preg_replace("/@date/i", $this->getLocationDataNew($rawData, "published", true, "Y-m-d"), $location);
+		$location = preg_replace("/@year/i", $this->getLocationDataNew($rawData, "published", true, "Y"), $location);
+		$location = preg_replace("/@month/i", $this->getLocationDataNew($rawData, "published", true, "m"), $location);
+		$location = preg_replace("/@day/i", $this->getLocationDataNew($rawData, "published", true, "d"), $location);
+		$location = preg_replace("/@tag/i", $this->getLocationDataNew($rawData, "tag", true), $location);
+		$location = preg_replace("/@author/i", $this->getLocationDataNew($rawData, "author", true), $location);
+		$location = preg_replace("/@title/i", $this->getLocationDataNew($rawData, "title"), $location);
+		if(!preg_match("/^\//", $location))
 		{
-			foreach($this->yellow->toolbox->getTextLines($parts[2]) as $line)
-			{
-				preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-				if(lcfirst($matches[1])=="title" && !strempty($matches[2])) { $title = $matches[2]; break; }
-			}
+			$location = $this->yellow->lookup->getDirectoryLocation($pageLocation).$location;
 		}
-		return $title;
+		return $location;
 	}
 	
-	// Return language for user
-	function getLanguage($email)
+	// Return location data for new/modified page
+	function getLocationDataNew($rawData, $key, $filterFirst = false, $dateFormat = "")
 	{
-		$language = $this->webinterface->users->getLanguage($email);
-		if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
-		return $language;
+		$value = $this->yellow->toolbox->getMetaData($rawData, $key);
+		if($filterFirst && preg_match("/^(.*?)\,(.*)$/", $value, $matches)) $value = $matches[1];
+		if(!empty($dateFormat)) $value = date($dateFormat, strtotime($value));
+		if(strempty($value)) $value = "none";
+		$value = $this->yellow->lookup->normaliseName($value, true, false, true);
+		return trim(preg_replace("/-+/", "-", $value), "-");
 	}
 	
-	// Update text title
-	function updateTextTitle($rawData, $title)
+	// Return title for next page
+	function getTitleNext($rawData)
 	{
-		foreach($this->yellow->toolbox->getTextLines($rawData) as $line)
-		{
-			preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-			if(lcfirst($matches[1])=="title") $line = "Title: $title\n";
-			$rawDataNew .= $line;
-		}
-		return $rawDataNew;
+		preg_match("/^(.*?)(\d*)$/", $this->yellow->toolbox->getMetaData($rawData, "title"), $matches);
+		$titleText = $matches[1];
+		$titleNumber = strempty($matches[2]) ? " 2" : $matches[2]+1;
+		return $titleText.$titleNumber;
 	}
 	
-	// Normlise text with special characters
-	function normaliseText($text)
-	{
-		if($this->yellow->plugins->isExisting("emojiawesome"))
-		{
-			$text = $this->yellow->plugins->get("emojiawesome")->normaliseText($text, true, false);
-		}
-		return $text;
-	}
-
 	// Create browser cookie
 	function createCookie($scheme, $address, $base, $email)
 	{
-		$session = $this->webinterface->users->createSession($email);
+		$session = $this->plugin->users->createSession($email);
 		setcookie("login", "$email,$session", time()+60*60*24*365, "$base/", "", $scheme=="https");
 	}
 	
@@ -1001,6 +1024,18 @@ class YellowResponse
 		setcookie("login", "", time()-60*60, "$base/", "", $scheme=="https");
 	}
 	
+	// Edit content file
+	function editContentFile($page, $action)
+	{
+		if(!$page->isError())
+		{
+			foreach($this->yellow->plugins->plugins as $key=>$value)
+			{
+				if(method_exists($value["obj"], "onEditContentFile")) $value["obj"]->onEditContentFile($page, $action);
+			}
+		}
+	}
+	
 	// Send mail to user
 	function sendMail($scheme, $address, $base, $email, $action)
 	{
@@ -1009,7 +1044,7 @@ class YellowResponse
 			$url = "$scheme://$address$base/";
 		} else {
 			$expire = time()+60*60*24;
-			$id = $this->webinterface->users->createRequestId($email, $action, $expire);
+			$id = $this->plugin->users->createRequestId($email, $action, $expire);
 			$url = "$scheme://$address$base"."/action:$action/email:$email/expire:$expire/id:$id/";
 		}
 		if($action=="approve")
@@ -1019,12 +1054,12 @@ class YellowResponse
 			$email = $this->yellow->config->get("email");
 		} else {
 			$account = $email;
-			$name = $this->webinterface->users->getName($email);
+			$name = $this->plugin->users->getName($email);
 		}
-		$language = $this->webinterface->users->getLanguage($email);
+		$language = $this->plugin->users->getLanguage($email);
 		if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
 		$sitename = $this->yellow->config->get("sitename");
-		$prefix = "webinterface".ucfirst($action);
+		$prefix = "edit".ucfirst($action);
 		$message = $this->yellow->text->getText("{$prefix}Message", $language);
 		$message = preg_replace("/@useraccount/i", $account, $message);
 		$message = preg_replace("/@usershort/i", strtok($name, " "), $message);
@@ -1041,24 +1076,18 @@ class YellowResponse
 		return mail($mailTo, $mailSubject, $mailMessage, $mailHeaders);
 	}
 	
-	// Check if web interface active
+	// Check if active
 	function isActive()
 	{
 		return $this->active;
 	}
 	
-	// Check if web interface has login restrictions
-	function isLoginRestrictions()
-	{
-		return substru($this->yellow->config->get("email"), 0, 7)=="noreply";
-	}
-
 	// Check if user is logged in
 	function isUser()
 	{
 		return !empty($this->userEmail);
 	}
-
+	
 	// Check if user has restrictions
 	function isUserRestrictions()
 	{
@@ -1070,6 +1099,12 @@ class YellowResponse
 	{
 		return !empty($this->userEmail) && $this->userEmail==$this->yellow->config->get("email");
 	}
+	
+	// Check if login has restrictions
+	function isLoginRestrictions()
+	{
+		return $this->yellow->config->get("editLoginRestrictions");
+	}
 }
 
 class YellowUsers
@@ -1142,10 +1177,10 @@ class YellowUsers
 			$hash = strreplaceu(',', '-', empty($hash) ? "none" : $hash);
 			$name = strreplaceu(',', '-', empty($name) ? $this->yellow->config->get("sitename") : $name);
 			$language = strreplaceu(',', '-', empty($language) ? $this->yellow->config->get("language") : $language);
-			$status = strreplaceu(',', '-', empty($status) ? $this->yellow->config->get("webinterfaceUserStatus") : $status);
+			$status = strreplaceu(',', '-', empty($status) ? $this->yellow->config->get("editUserStatus") : $status);
 			$modified = strreplaceu(',', '-', empty($modified) ? time() : $modified);
 			$pending = strreplaceu(',', '-', empty($pending) ? "none" : $pending);
-			$home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("webinterfaceUserHome") : $home);
+			$home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("editUserHome") : $home);
 		}
 		$this->set($email, $hash, $name, $language, $status, $modified, $pending, $home);
 		$fileData = $this->yellow->toolbox->readFile($fileName);
@@ -1181,7 +1216,7 @@ class YellowUsers
 	// Check user login from email and password
 	function checkUser($email, $password)
 	{
-		$algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm");
+		$algorithm = $this->yellow->config->get("editUserHashAlgorithm");
 		return $this->isExisting($email) && $this->users[$email]["status"]=="active" &&
 			$this->yellow->toolbox->verifyHash($password, $algorithm, $this->users[$email]["hash"]);
 	}
@@ -1207,8 +1242,8 @@ class YellowUsers
 	// Create password hash
 	function createHash($password)
 	{
-		$algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm");
-		$cost = $this->yellow->config->get("webinterfaceUserHashCost");
+		$algorithm = $this->yellow->config->get("editUserHashAlgorithm");
+		$cost = $this->yellow->config->get("editUserHashCost");
 		$hash = $this->yellow->toolbox->createHash($password, $algorithm, $cost);
 		if(empty($hash)) $hash = "error-hash-algorithm-$algorithm";
 		return $hash;
@@ -1300,7 +1335,7 @@ class YellowUsers
 			$data[$key] = "$value[email] - $name $language $status";
 			if($value["home"]!="/") $data[$key] .= " restrictions";
 		}
-		usort($data, strnatcasecmp);
+		uksort($data, strnatcasecmp);
 		return $data;
 	}
 	
@@ -1506,5 +1541,5 @@ class YellowMerge
 	}
 }
 
-$yellow->plugins->register("webinterface", "YellowWebinterface", YellowWebinterface::VERSION);
+$yellow->plugins->register("edit", "YellowEdit", YellowEdit::VERSION);
 ?>

+ 79 - 79
system/plugins/language-de.txt

@@ -3,7 +3,7 @@
 Language: de
 LanguageDescription: Deutsch
 LanguageTranslator: David Fehrmann
-LanguageVersion: 0.6.16
+LanguageVersion: 0.7.1
 
 BlogBy: von
 BlogFilter: Blog:
@@ -25,6 +25,84 @@ DateFormatShort: F Y
 DateFormatMedium: d.m.Y
 DateFormatLong: d.m.Y H:i
 DateFormatTime: H:i
+EditInstallationTitle: Hallo
+EditInstallationFeature: Was willst du machen?
+EditInstallationHomePage: Deine Webseite funktioniert!\n\nDu kannst [edit - diese Seite bearbeiten] oder einen Texteditor benutzen.
+EditInstallationAboutPage: Diese Webseite ist erstellt mit [yellow]. [Weitere Informationen](https://developers.datenstrom.se/help/help-de).
+EditLoginTitle: Willkommen
+EditLoginEmail: E-Mail:
+EditLoginPassword: Kennwort:
+EditLoginRecover: Kennwort vergessen?
+EditLoginSignup: Benutzerkonto erstellen?
+EditLoginButton: Anmelden
+EditSignupTitle: Benutzerkonto erstellen
+EditSignupName: Name:
+EditSignupEmail: E-Mail:
+EditSignupPassword: Kennwort:
+EditSignupButton: Erstellen
+EditSignupStatusNone: Hier kannst du ein neues Benutzerkonto erstellen.
+EditSignupStatusIncomplete: Bitte alle Felder ausfüllen.
+EditSignupStatusInvalid: Bitte eine gültige E-Mail angeben.
+EditSignupStatusWeak: Bitte ein anderes Kennwort angeben.
+EditSignupStatusNext: Benutzerkonto wird erstellt, bitte überprüfe deine E-Mails.
+EditRecoverTitle: Kennwort vergessen
+EditRecoverEmail: E-Mail:
+EditRecoverPassword: Kennwort:
+EditRecoverStatusNone: Kein Problem, du kannst ein neues Kennwort erstellen.
+EditRecoverStatusInvalid: Bitte eine gültige E-Mail angeben.
+EditRecoverStatusPassword: Bitte ein neues Kennwort angeben.
+EditRecoverStatusWeak: Bitte ein anderes Kennwort angeben.
+EditRecoverStatusNext: Benutzerkonto wird wiederhergestellt, bitte überprüfe deine E-Mails.
+EditSettingsTitle: Einstellungen
+EditSettingsStatusInvalid: Bitte eine gültige E-Mail angeben.
+EditSettingsStatusTaken: Bitte eine andere E-Mail angeben.
+EditSettingsStatusWeak: Bitte ein anderes Kennwort angeben.
+EditSettingsStatusNext: Benutzerkonto wird geändert, bitte überprüfe deine E-Mails.
+EditConfirmSubject: Benutzerkonto bestätigen
+EditConfirmMessage: Hallo @usershort, bitte bestätige dein Benutzerkonto. Klicke auf den folgenden Link.
+EditConfirmStatusDone: Benutzerkonto wurde bestätigt und wartet auf Genehmigung. Vielen Dank!
+EditConfirmStatusExpired: Benutzerkonto kann nicht bestätigt werden. Link ist abgelaufen!
+EditApproveSubject: Benutzerkonto genehmigen
+EditApproveMessage: Hallo @usershort, bitte genehmige ein neues Benutzerkonto für @useraccount. Klicke auf den folgenden Link.
+EditApproveStatusDone: Benutzerkonto wurde genehmigt. Vielen Dank!
+EditApproveStatusExpired: Benutzerkonto kann nicht genehmigt werden. Link ist abgelaufen!
+EditRecoverSubject: Benutzerkonto wiederherstellen
+EditRecoverMessage: Hallo @usershort, bitte bestätige, dass du dein Kennwort vergessen hast. Klicke auf den folgenden Link.
+EditRecoverStatusDone: Benutzerkonto wurde wiederhergestellt. Vielen Dank!
+EditRecoverStatusExpired: Benutzerkonto kann nicht wiederhergestellt werden. Link ist abgelaufen!
+EditReconfirmSubject: Benutzerkonto ändern
+EditReconfirmMessage: Hallo @usershort, bitte bestätige eine neue E-Mail für dein Benutzerkonto. Klicke auf den folgenden Link.
+EditReconfirmStatusDone: Benutzerkonto wurde bestätigt. Vielen Dank!
+EditReconfirmStatusExpired: Benutzerkonto kann nicht bestätigt werden. Link ist abgelaufen!
+EditChangeSubject: Benutzerkonto ändern
+EditChangeMessage: Hallo @usershort, bitte bestätige, dass du dein Benutzerkonto ändern möchtest. Klicke auf den folgenden Link.
+EditChangeStatusDone: Benutzerkonto wurde geändert. Vielen Dank!
+EditChangeStatusExpired: Benutzerkonto kann nicht geändert werden. Link ist abgelaufen!
+EditWelcomeSubject: Willkommen
+EditWelcomeMessage: Hallo @usershort, dein Benutzerkonto wurde erstellt. Viel Spass beim Bearbeiten der Webseite.
+EditInformationSubject: Willkommen zurück
+EditInformationMessage: Hallo @usershort, dein Benutzerkonto wurde geändert. Du kannst dich jetzt anmelden.
+EditVersionTitle: Über diese Webseite
+EditVersionStatusNone: Yellow ist für Menschen die Webseiten machen.
+EditVersionStatusCheck: Nach Aktualisierung suchen…
+EditVersionStatusDone: Deine Webseite ist auf dem neusten Stand.
+EditVersionStatusUpdates: Aktualisierung verfügbar, bitte an den Webmaster wenden.
+EditVersionUpdateNormal: Aktualisierung verfügbar, jetzt aktualisieren.
+EditVersionUpdateForce: Aktualisierung erzwingen
+EditVersionUpdateModified: @software wurde modifiziert
+EditOkButton: Ok
+EditCancelButton: Abbruch
+EditCreateButton: Erzeugen
+EditEditButton: Ändern
+EditDeleteButton: Löschen
+EditEdit: Seite ändern
+EditCreate: +
+EditDelete: -
+EditCreateTitle: Seite erzeugen
+EditDeleteTitle: Seite löschen
+EditMarkdownHelp: Markdown
+EditUserHelp: Hilfe
+EditUserLogout: Abmelden
 PagePrevious: ← Zurück: @title
 PageNext: Weiter: @title →
 PaginationPrevious: ← Zurück
@@ -34,84 +112,6 @@ SearchResultsNone: Bitte einen Suchbegriff eingeben.
 SearchResultsEmpty: Keine Treffer für diese Suchanfrage.
 SearchSpecialChanges: Letzte Änderungen
 SearchButton: Suchen
-WebinterfaceInstallationTitle: Hallo
-WebinterfaceInstallationFeature: Was willst du machen?
-WebinterfaceInstallationHomePage: Deine Webseite funktioniert!\n\nDu kannst [edit - diese Seite bearbeiten] oder einen Texteditor benutzen.
-WebinterfaceInstallationAboutPage: Diese Webseite ist erstellt mit [yellow]. [Weitere Informationen](https://developers.datenstrom.se/help/help-de).
-WebinterfaceLoginTitle: Willkommen
-WebinterfaceLoginEmail: E-Mail:
-WebinterfaceLoginPassword: Kennwort:
-WebinterfaceLoginRecover: Kennwort vergessen?
-WebinterfaceLoginSignup: Benutzerkonto erstellen?
-WebinterfaceLoginButton: Anmelden
-WebinterfaceSignupTitle: Benutzerkonto erstellen
-WebinterfaceSignupName: Name:
-WebinterfaceSignupEmail: E-Mail:
-WebinterfaceSignupPassword: Kennwort:
-WebinterfaceSignupButton: Erstellen
-WebinterfaceSignupStatusNone: Hier kannst du ein neues Benutzerkonto erstellen.
-WebinterfaceSignupStatusIncomplete: Bitte alle Felder ausfüllen.
-WebinterfaceSignupStatusInvalid: Bitte eine gültige E-Mail angeben.
-WebinterfaceSignupStatusWeak: Bitte ein anderes Kennwort angeben.
-WebinterfaceSignupStatusNext: Benutzerkonto wird erstellt, bitte überprüfe deine E-Mails.
-WebinterfaceRecoverTitle: Kennwort vergessen
-WebinterfaceRecoverEmail: E-Mail:
-WebinterfaceRecoverPassword: Kennwort:
-WebinterfaceRecoverStatusNone: Kein Problem, du kannst ein neues Kennwort erstellen.
-WebinterfaceRecoverStatusInvalid: Bitte eine gültige E-Mail angeben.
-WebinterfaceRecoverStatusPassword: Bitte ein neues Kennwort angeben.
-WebinterfaceRecoverStatusWeak: Bitte ein anderes Kennwort angeben.
-WebinterfaceRecoverStatusNext: Benutzerkonto wird wiederhergestellt, bitte überprüfe deine E-Mails.
-WebinterfaceSettingsTitle: Einstellungen
-WebinterfaceSettingsStatusInvalid: Bitte eine gültige E-Mail angeben.
-WebinterfaceSettingsStatusTaken: Bitte eine andere E-Mail angeben.
-WebinterfaceSettingsStatusWeak: Bitte ein anderes Kennwort angeben.
-WebinterfaceSettingsStatusNext: Benutzerkonto wird geändert, bitte überprüfe deine E-Mails.
-WebinterfaceConfirmSubject: Benutzerkonto bestätigen
-WebinterfaceConfirmMessage: Hallo @usershort, bitte bestätige dein Benutzerkonto. Klicke auf den folgenden Link.
-WebinterfaceConfirmStatusDone: Benutzerkonto wurde bestätigt und wartet auf Genehmigung. Vielen Dank!
-WebinterfaceConfirmStatusExpired: Benutzerkonto kann nicht bestätigt werden. Link ist abgelaufen!
-WebinterfaceApproveSubject: Benutzerkonto genehmigen
-WebinterfaceApproveMessage: Hallo @usershort, bitte genehmige ein neues Benutzerkonto für @useraccount. Klicke auf den folgenden Link.
-WebinterfaceApproveStatusDone: Benutzerkonto wurde genehmigt. Vielen Dank!
-WebinterfaceApproveStatusExpired: Benutzerkonto kann nicht genehmigt werden. Link ist abgelaufen!
-WebinterfaceRecoverSubject: Benutzerkonto wiederherstellen
-WebinterfaceRecoverMessage: Hallo @usershort, bitte bestätige, dass du dein Kennwort vergessen hast. Klicke auf den folgenden Link.
-WebinterfaceRecoverStatusDone: Benutzerkonto wurde wiederhergestellt. Vielen Dank!
-WebinterfaceRecoverStatusExpired: Benutzerkonto kann nicht wiederhergestellt werden. Link ist abgelaufen!
-WebinterfaceReconfirmSubject: Benutzerkonto ändern
-WebinterfaceReconfirmMessage: Hallo @usershort, bitte bestätige eine neue E-Mail für dein Benutzerkonto. Klicke auf den folgenden Link.
-WebinterfaceReconfirmStatusDone: Benutzerkonto wurde bestätigt. Vielen Dank!
-WebinterfaceReconfirmStatusExpired: Benutzerkonto kann nicht bestätigt werden. Link ist abgelaufen!
-WebinterfaceChangeSubject: Benutzerkonto ändern
-WebinterfaceChangeMessage: Hallo @usershort, bitte bestätige, dass du dein Benutzerkonto ändern möchtest. Klicke auf den folgenden Link.
-WebinterfaceChangeStatusDone: Benutzerkonto wurde geändert. Vielen Dank!
-WebinterfaceChangeStatusExpired: Benutzerkonto kann nicht geändert werden. Link ist abgelaufen!
-WebinterfaceWelcomeSubject: Willkommen
-WebinterfaceWelcomeMessage: Hallo @usershort, dein Benutzerkonto wurde erstellt. Viel Spass beim Bearbeiten der Webseite.
-WebinterfaceInformationSubject: Willkommen zurück
-WebinterfaceInformationMessage: Hallo @usershort, dein Benutzerkonto wurde geändert. Du kannst dich jetzt anmelden.
-WebinterfaceVersionTitle: Über diese Webseite
-WebinterfaceVersionStatusNone: Yellow ist für Menschen die Webseiten machen.
-WebinterfaceVersionStatusCheck: Nach Aktualisierung suchen…
-WebinterfaceVersionStatusDone: Deine Webseite ist auf dem neusten Stand.
-WebinterfaceVersionStatusUpdates: Aktualisierung verfügbar, bitte an den Webmaster wenden.
-WebinterfaceVersionUpdateNormal: Aktualisierung verfügbar, jetzt aktualisieren.
-WebinterfaceVersionUpdateForce: Aktualisierung erzwingen
-WebinterfaceVersionUpdateModified: @software wurde modifiziert
-WebinterfaceOkButton: Ok
-WebinterfaceCancelButton: Abbruch
-WebinterfaceCreateButton: Erzeugen
-WebinterfaceEditButton: Ändern
-WebinterfaceDeleteButton: Löschen
-WebinterfaceEdit: Seite ändern
-WebinterfaceCreate: +
-WebinterfaceDelete: -
-WebinterfaceCreateTitle: Seite erzeugen
-WebinterfaceDeleteTitle: Seite löschen
-WebinterfaceMarkdownHelp: Markdown
-WebinterfaceUserHelp: Hilfe
-WebinterfaceUserLogout: Abmelden
 WikiFilter: Wiki:
 WikiTag: Tags:
 WikiSpecialPages: Alle Seiten

+ 79 - 79
system/plugins/language-en.txt

@@ -3,7 +3,7 @@
 Language: en
 LanguageDescription: English
 LanguageTranslator: Mark Seuffert
-LanguageVersion: 0.6.16
+LanguageVersion: 0.7.1
 
 BlogBy: by
 BlogFilter: Blog:
@@ -25,6 +25,84 @@ DateFormatShort: F Y
 DateFormatMedium: Y-m-d
 DateFormatLong: Y-m-d H:i
 DateFormatTime: H:i
+EditInstallationTitle: Hello
+EditInstallationFeature: What do you want to make?
+EditInstallationHomePage: Your website works!\n\nYou can [edit this page] or use your text editor.
+EditInstallationAboutPage: This website is made with [yellow]. [Learn more](https://developers.datenstrom.se/help/).
+EditLoginTitle: Welcome
+EditLoginEmail: Email:
+EditLoginPassword: Password:
+EditLoginRecover: Forgot your password?
+EditLoginSignup: Create user account?
+EditLoginButton: Log in
+EditSignupTitle: Create user account
+EditSignupName: Name:
+EditSignupEmail: Email:
+EditSignupPassword: Password:
+EditSignupButton: Create
+EditSignupStatusNone: Here you can create a new user account.
+EditSignupStatusIncomplete: Please fill out all fields.
+EditSignupStatusInvalid: Please enter a valid email.
+EditSignupStatusWeak: Please enter a different password.
+EditSignupStatusNext: User account will be created, please check your emails.
+EditRecoverTitle: Forgot your password
+EditRecoverEmail: Email:
+EditRecoverPassword: Password:
+EditRecoverStatusNone: No problem, you can create a new password.
+EditRecoverStatusInvalid: Please enter a valid email.
+EditRecoverStatusPassword: Please enter a new password.
+EditRecoverStatusWeak: Please enter a different password.
+EditRecoverStatusNext: User account will be recovered, please check your emails.
+EditSettingsTitle: Settings
+EditSettingsStatusInvalid: Please enter a valid email.
+EditSettingsStatusTaken: Please enter a different email.
+EditSettingsStatusWeak: Please enter a different password.
+EditSettingsStatusNext: User account will be changed, please check your emails.
+EditConfirmSubject: Confirm user account
+EditConfirmMessage: Hi @usershort, please confirm your user account. Click the following link.
+EditConfirmStatusDone: User account confirmed and waiting for approval. Thank you!
+EditConfirmStatusExpired: User account can not be confirmed. Link has expired!
+EditApproveSubject: Approve user account
+EditApproveMessage: Hi @usershort, please approve a new user account for @useraccount. Click the following link.
+EditApproveStatusDone: User account approved. Thank you!
+EditApproveStatusExpired: User account can not be approved. Link has expired!
+EditRecoverSubject: Recover user account
+EditRecoverMessage: Hi @usershort, please confirm that you forgot your password. Click the following link.
+EditRecoverStatusDone: User account recovered. Thank you!
+EditRecoverStatusExpired: User account can not be recovered. Link has expired!
+EditReconfirmSubject: Change user account
+EditReconfirmMessage: Hi @usershort, please confirm a new email for your user account. Click the following link.
+EditReconfirmStatusDone: User account confirmed. Thank you!
+EditReconfirmStatusExpired: User account can not be confirmed. Link has expired!
+EditChangeSubject: Change user account
+EditChangeMessage: Hi @usershort, please confirm that you want to change your user account. Click the following link.
+EditChangeStatusDone: User account changed. Thank you!
+EditChangeStatusExpired: User account can not be changed. Link has expired!
+EditWelcomeSubject: Welcome
+EditWelcomeMessage: Hi @usershort, your user account has been created. Have fun editing the website.
+EditInformationSubject: Welcome back
+EditInformationMessage: Hi @usershort, your user account has been changed. You can now log in.
+EditVersionTitle: About this website
+EditVersionStatusNone: Yellow is for people who make websites.
+EditVersionStatusCheck: Checking for updates…
+EditVersionStatusDone: Your website is up to date.
+EditVersionStatusUpdates: Updates available, please contact the webmaster.
+EditVersionUpdateNormal: Updates available, update now.
+EditVersionUpdateForce: Force update
+EditVersionUpdateModified: @software has been modified
+EditOkButton: Ok
+EditCancelButton: Cancel
+EditCreateButton: Create
+EditEditButton: Save
+EditDeleteButton: Delete
+EditEdit: Edit page
+EditCreate: +
+EditDelete: -
+EditCreateTitle: Create page
+EditDeleteTitle: Delete page
+EditMarkdownHelp: Markdown
+EditUserHelp: Help
+EditUserLogout: Logout
 PagePrevious: ← Previous: @title
 PageNext: Next: @title →
 PaginationPrevious: ← Previous
@@ -34,84 +112,6 @@ SearchResultsNone: Enter a search term.
 SearchResultsEmpty: No results found.
 SearchSpecialChanges: Recent changes
 SearchButton: Search
-WebinterfaceInstallationTitle: Hello
-WebinterfaceInstallationFeature: What do you want to make?
-WebinterfaceInstallationHomePage: Your website works!\n\nYou can [edit this page] or use your text editor.
-WebinterfaceInstallationAboutPage: This website is made with [yellow]. [Learn more](https://developers.datenstrom.se/help/).
-WebinterfaceLoginTitle: Welcome
-WebinterfaceLoginEmail: Email:
-WebinterfaceLoginPassword: Password:
-WebinterfaceLoginRecover: Forgot your password?
-WebinterfaceLoginSignup: Create user account?
-WebinterfaceLoginButton: Log in
-WebinterfaceSignupTitle: Create user account
-WebinterfaceSignupName: Name:
-WebinterfaceSignupEmail: Email:
-WebinterfaceSignupPassword: Password:
-WebinterfaceSignupButton: Create
-WebinterfaceSignupStatusNone: Here you can create a new user account.
-WebinterfaceSignupStatusIncomplete: Please fill out all fields.
-WebinterfaceSignupStatusInvalid: Please enter a valid email.
-WebinterfaceSignupStatusWeak: Please enter a different password.
-WebinterfaceSignupStatusNext: User account will be created, please check your emails.
-WebinterfaceRecoverTitle: Forgot your password
-WebinterfaceRecoverEmail: Email:
-WebinterfaceRecoverPassword: Password:
-WebinterfaceRecoverStatusNone: No problem, you can create a new password.
-WebinterfaceRecoverStatusInvalid: Please enter a valid email.
-WebinterfaceRecoverStatusPassword: Please enter a new password.
-WebinterfaceRecoverStatusWeak: Please enter a different password.
-WebinterfaceRecoverStatusNext: User account will be recovered, please check your emails.
-WebinterfaceSettingsTitle: Settings
-WebinterfaceSettingsStatusInvalid: Please enter a valid email.
-WebinterfaceSettingsStatusTaken: Please enter a different email.
-WebinterfaceSettingsStatusWeak: Please enter a different password.
-WebinterfaceSettingsStatusNext: User account will be changed, please check your emails.
-WebinterfaceConfirmSubject: Confirm user account
-WebinterfaceConfirmMessage: Hi @usershort, please confirm your user account. Click the following link.
-WebinterfaceConfirmStatusDone: User account confirmed and waiting for approval. Thank you!
-WebinterfaceConfirmStatusExpired: User account can not be confirmed. Link has expired!
-WebinterfaceApproveSubject: Approve user account
-WebinterfaceApproveMessage: Hi @usershort, please approve a new user account for @useraccount. Click the following link.
-WebinterfaceApproveStatusDone: User account approved. Thank you!
-WebinterfaceApproveStatusExpired: User account can not be approved. Link has expired!
-WebinterfaceRecoverSubject: Recover user account
-WebinterfaceRecoverMessage: Hi @usershort, please confirm that you forgot your password. Click the following link.
-WebinterfaceRecoverStatusDone: User account recovered. Thank you!
-WebinterfaceRecoverStatusExpired: User account can not be recovered. Link has expired!
-WebinterfaceReconfirmSubject: Change user account
-WebinterfaceReconfirmMessage: Hi @usershort, please confirm a new email for your user account. Click the following link.
-WebinterfaceReconfirmStatusDone: User account confirmed. Thank you!
-WebinterfaceReconfirmStatusExpired: User account can not be confirmed. Link has expired!
-WebinterfaceChangeSubject: Change user account
-WebinterfaceChangeMessage: Hi @usershort, please confirm that you want to change your user account. Click the following link.
-WebinterfaceChangeStatusDone: User account changed. Thank you!
-WebinterfaceChangeStatusExpired: User account can not be changed. Link has expired!
-WebinterfaceWelcomeSubject: Welcome
-WebinterfaceWelcomeMessage: Hi @usershort, your user account has been created. Have fun editing the website.
-WebinterfaceInformationSubject: Welcome back
-WebinterfaceInformationMessage: Hi @usershort, your user account has been changed. You can now log in.
-WebinterfaceVersionTitle: About this website
-WebinterfaceVersionStatusNone: Yellow is for people who make websites.
-WebinterfaceVersionStatusCheck: Checking for updates…
-WebinterfaceVersionStatusDone: Your website is up to date.
-WebinterfaceVersionStatusUpdates: Updates available, please contact the webmaster.
-WebinterfaceVersionUpdateNormal: Updates available, update now.
-WebinterfaceVersionUpdateForce: Force update
-WebinterfaceVersionUpdateModified: @software has been modified
-WebinterfaceOkButton: Ok
-WebinterfaceCancelButton: Cancel
-WebinterfaceCreateButton: Create
-WebinterfaceEditButton: Save
-WebinterfaceDeleteButton: Delete
-WebinterfaceEdit: Edit page
-WebinterfaceCreate: +
-WebinterfaceDelete: -
-WebinterfaceCreateTitle: Create page
-WebinterfaceDeleteTitle: Delete page
-WebinterfaceMarkdownHelp: Markdown
-WebinterfaceUserHelp: Help
-WebinterfaceUserLogout: Logout
 WikiFilter: Wiki:
 WikiTag: Tags:
 WikiSpecialPages: All pages

+ 79 - 79
system/plugins/language-fr.txt

@@ -3,7 +3,7 @@
 Language: fr
 LanguageDescription: Français
 LanguageTranslator: Juh Nibreh
-LanguageVersion: 0.6.16
+LanguageVersion: 0.7.1
 
 BlogBy: par
 BlogFilter: Blog:
@@ -25,6 +25,84 @@ DateFormatShort: F Y
 DateFormatMedium: d/m/Y
 DateFormatLong: d/m/Y H:i
 DateFormatTime: H:i
+EditInstallationTitle: Bonjour
+EditInstallationFeature: Que voulez-vous faire?
+EditInstallationHomePage: Votre site web fonctionne!\n\nVous pouvez [edit - modifier cette page] ou utiliser un éditeur de texte.
+EditInstallationAboutPage: Ce site web est fait avec [yellow]. [Apprenez-en plus](https://developers.datenstrom.se/help/help-fr).
+EditLoginTitle: Bienvenue
+EditLoginEmail: Email:
+EditLoginPassword: Mot de passe:
+EditLoginRecover: Mot de passe oublié?
+EditLoginSignup: Créer un compte utilisateur?
+EditLoginButton: Se connecter
+EditSignupTitle: Créer un compte utilisateur
+EditSignupName: Nom:
+EditSignupEmail: Email:
+EditSignupPassword: Mot de passe:
+EditSignupButton: Créer
+EditSignupStatusNone: Ici, vous pouvez créer un nouveau compte utilisateur.
+EditSignupStatusIncomplete: Veuillez remplir tous les champs.
+EditSignupStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
+EditSignupStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
+EditSignupStatusNext: Votre compte a été créé, vérifiez vos emails.
+EditRecoverTitle: Mot de passe oublié
+EditRecoverEmail: Email:
+EditRecoverPassword: Mot de passe:
+EditRecoverStatusNone: Pas de problème, vous pouvez créer un nouveau mot de passe.
+EditRecoverStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
+EditRecoverStatusPassword: S'il vous plaît, choisissez un nouveau mot de passe.
+EditRecoverStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
+EditRecoverStatusNext: Votre compte est à nouveau disponible, vérifiez vos emails.
+EditSettingsTitle: Paramètres
+EditSettingsStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
+EditSettingsStatusTaken: S'il vous plaît, veuillez entrer une adresse email différent.
+EditSettingsStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
+EditSettingsStatusNext: Votre compte a été changé, vérifiez vos emails.
+EditConfirmSubject: Confirmation d'un compte utilisateur
+EditConfirmMessage: Bonjour @usershort, veuillez confirmer votre compte utilisateur. Cliquez sur le lien suivant.
+EditConfirmStatusDone: Votre compte utilisateur est confirmé et en attente d'approbation. Merci!
+EditConfirmStatusExpired: Le compte ne peut pas être créé. Le lien de confirmation a expiré!
+EditApproveSubject: Approuver un nouvel utilisateur
+EditApproveMessage: Bonjour @usershort, veuillez approuver la création d'un nouveau compte utilisateur pour @useraccount. Cliquez sur le lien suivant.
+EditApproveStatusDone: Compte utilisateur approuvé. Merci!
+EditApproveStatusExpired: Le compte ne peut pas être approuvé. Le lien de confirmation a expiré!
+EditRecoverSubject: Restauration d'un compte utilisateur
+EditRecoverMessage: Bonjour @usershort, veuillez confirmer que vous avez oublié votre mot de passe. Cliquez sur le lien suivant.
+EditRecoverStatusDone: Compte utilisateur restauré. Merci!
+EditRecoverStatusExpired: Le compte ne peut pas être restauré. Le lien de confirmation a expiré!
+EditReconfirmSubject: Changement d'un compte utilisateur
+EditReconfirmMessage: Bonjour @usershort, veuillez confirmer une nouvelle adresse email pour votre compte utilisateur. Cliquez sur le lien suivant.
+EditReconfirmStatusDone: Votre compte utilisateur est confirmé. Merci!
+EditReconfirmStatusExpired: Le compte ne peut pas être créé. Le lien de confirmation a expiré!
+EditChangeSubject: Changement d'un compte utilisateur
+EditChangeMessage: Bonjour @usershort, veuillez confirmer que vous souhaitez modifier votre compte utilisateur. Cliquez sur le lien suivant.
+EditChangeStatusDone: Compte utilisateur changé. Merci!
+EditChangeStatusExpired: Le compte ne peut pas être changé. Le lien de confirmation a expiré!
+EditWelcomeSubject: Bienvenue
+EditWelcomeMessage: Bonjour @usershort, votre compte utilisateur a bien été créé. Amusez-vous bien en éditant le site web.
+EditInformationSubject: Bienvenue à nouveau
+EditInformationMessage: Bonjour @usershort, votre compte utilisateur a bien été changé. Vous pouvez maintenant vous connecter.
+EditVersionTitle: A propos de ce site
+EditVersionStatusNone: Yellow est fait pour les gens qui font des sites web.
+EditVersionStatusCheck: Vérification des mises à jour…
+EditVersionStatusDone: Votre site est à jour.
+EditVersionStatusUpdates: Mises à jour disponibles, s'il vous plaît contacter le webmestre.
+EditVersionUpdateNormal: Mises à jour disponibles, mettre à jour maintenant.
+EditVersionUpdateForce: Forcer mise à jour
+EditVersionUpdateModified: @software a été modifié
+EditOkButton: Ok
+EditCancelButton: Annuler
+EditCreateButton: Créer
+EditEditButton: Sauvegarder
+EditDeleteButton: Supprimer
+EditEdit: Éditer page
+EditCreate: +
+EditDelete: -
+EditCreateTitle: Créer page
+EditDeleteTitle: Supprimer page
+EditMarkdownHelp: Markdown
+EditUserHelp: Aide
+EditUserLogout: Déconnexion
 PagePrevious: ← Précédent: @title
 PageNext: Suivant: @title →
 PaginationPrevious: ← Précédent
@@ -34,84 +112,6 @@ SearchResultsNone: Entrez un mot dans le champ de recherche.
 SearchResultsEmpty: Pas de résultats.
 SearchSpecialChanges: Changements récents
 SearchButton: Rechercher
-WebinterfaceInstallationTitle: Bonjour
-WebinterfaceInstallationFeature: Que voulez-vous faire?
-WebinterfaceInstallationHomePage: Votre site web fonctionne!\n\nVous pouvez [edit - modifier cette page] ou utiliser un éditeur de texte.
-WebinterfaceInstallationAboutPage: Ce site web est fait avec [yellow]. [Apprenez-en plus](https://developers.datenstrom.se/help/help-fr).
-WebinterfaceLoginTitle: Bienvenue
-WebinterfaceLoginEmail: Email:
-WebinterfaceLoginPassword: Mot de passe:
-WebinterfaceLoginRecover: Mot de passe oublié?
-WebinterfaceLoginSignup: Créer un compte utilisateur?
-WebinterfaceLoginButton: Se connecter
-WebinterfaceSignupTitle: Créer un compte utilisateur
-WebinterfaceSignupName: Nom:
-WebinterfaceSignupEmail: Email:
-WebinterfaceSignupPassword: Mot de passe:
-WebinterfaceSignupButton: Créer
-WebinterfaceSignupStatusNone: Ici, vous pouvez créer un nouveau compte utilisateur.
-WebinterfaceSignupStatusIncomplete: Veuillez remplir tous les champs.
-WebinterfaceSignupStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
-WebinterfaceSignupStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
-WebinterfaceSignupStatusNext: Votre compte a été créé, vérifiez vos emails.
-WebinterfaceRecoverTitle: Mot de passe oublié
-WebinterfaceRecoverEmail: Email:
-WebinterfaceRecoverPassword: Mot de passe:
-WebinterfaceRecoverStatusNone: Pas de problème, vous pouvez créer un nouveau mot de passe.
-WebinterfaceRecoverStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
-WebinterfaceRecoverStatusPassword: S'il vous plaît, choisissez un nouveau mot de passe.
-WebinterfaceRecoverStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
-WebinterfaceRecoverStatusNext: Votre compte est à nouveau disponible, vérifiez vos emails.
-WebinterfaceSettingsTitle: Paramètres
-WebinterfaceSettingsStatusInvalid: S'il vous plaît, veuillez entrer une adresse email valide.
-WebinterfaceSettingsStatusTaken: S'il vous plaît, veuillez entrer une adresse email différent.
-WebinterfaceSettingsStatusWeak: S'il vous plaît, choisissez un mot de passe différent.
-WebinterfaceSettingsStatusNext: Votre compte a été changé, vérifiez vos emails.
-WebinterfaceConfirmSubject: Confirmation d'un compte utilisateur
-WebinterfaceConfirmMessage: Bonjour @usershort, veuillez confirmer votre compte utilisateur. Cliquez sur le lien suivant.
-WebinterfaceConfirmStatusDone: Votre compte utilisateur est confirmé et en attente d'approbation. Merci!
-WebinterfaceConfirmStatusExpired: Le compte ne peut pas être créé. Le lien de confirmation a expiré!
-WebinterfaceApproveSubject: Approuver un nouvel utilisateur
-WebinterfaceApproveMessage: Bonjour @usershort, veuillez approuver la création d'un nouveau compte utilisateur pour @useraccount. Cliquez sur le lien suivant.
-WebinterfaceApproveStatusDone: Compte utilisateur approuvé. Merci!
-WebinterfaceApproveStatusExpired: Le compte ne peut pas être approuvé. Le lien de confirmation a expiré!
-WebinterfaceRecoverSubject: Restauration d'un compte utilisateur
-WebinterfaceRecoverMessage: Bonjour @usershort, veuillez confirmer que vous avez oublié votre mot de passe. Cliquez sur le lien suivant.
-WebinterfaceRecoverStatusDone: Compte utilisateur restauré. Merci!
-WebinterfaceRecoverStatusExpired: Le compte ne peut pas être restauré. Le lien de confirmation a expiré!
-WebinterfaceReconfirmSubject: Changement d'un compte utilisateur
-WebinterfaceReconfirmMessage: Bonjour @usershort, veuillez confirmer une nouvelle adresse email pour votre compte utilisateur. Cliquez sur le lien suivant.
-WebinterfaceReconfirmStatusDone: Votre compte utilisateur est confirmé. Merci!
-WebinterfaceReconfirmStatusExpired: Le compte ne peut pas être créé. Le lien de confirmation a expiré!
-WebinterfaceChangeSubject: Changement d'un compte utilisateur
-WebinterfaceChangeMessage: Bonjour @usershort, veuillez confirmer que vous souhaitez modifier votre compte utilisateur. Cliquez sur le lien suivant.
-WebinterfaceChangeStatusDone: Compte utilisateur changé. Merci!
-WebinterfaceChangeStatusExpired: Le compte ne peut pas être changé. Le lien de confirmation a expiré!
-WebinterfaceWelcomeSubject: Bienvenue
-WebinterfaceWelcomeMessage: Bonjour @usershort, votre compte utilisateur a bien été créé. Amusez-vous bien en éditant le site web.
-WebinterfaceInformationSubject: Bienvenue à nouveau
-WebinterfaceInformationMessage: Bonjour @usershort, votre compte utilisateur a bien été changé. Vous pouvez maintenant vous connecter.
-WebinterfaceVersionTitle: A propos de ce site
-WebinterfaceVersionStatusNone: Yellow est fait pour les gens qui font des sites web.
-WebinterfaceVersionStatusCheck: Vérification des mises à jour…
-WebinterfaceVersionStatusDone: Votre site est à jour.
-WebinterfaceVersionStatusUpdates: Mises à jour disponibles, s'il vous plaît contacter le webmestre.
-WebinterfaceVersionUpdateNormal: Mises à jour disponibles, mettre à jour maintenant.
-WebinterfaceVersionUpdateForce: Forcer mise à jour
-WebinterfaceVersionUpdateModified: @software a été modifié
-WebinterfaceOkButton: Ok
-WebinterfaceCancelButton: Annuler
-WebinterfaceCreateButton: Créer
-WebinterfaceEditButton: Sauvegarder
-WebinterfaceDeleteButton: Supprimer
-WebinterfaceEdit: Éditer page
-WebinterfaceCreate: +
-WebinterfaceDelete: -
-WebinterfaceCreateTitle: Créer page
-WebinterfaceDeleteTitle: Supprimer page
-WebinterfaceMarkdownHelp: Markdown
-WebinterfaceUserHelp: Aide
-WebinterfaceUserLogout: Déconnexion
 WikiFilter: Wiki:
 WikiTag: Tags:
 WikiSpecialPages: Toutes les pages

+ 1 - 1
system/plugins/language.php

@@ -5,7 +5,7 @@
 
 class YellowLanguage
 {
-	const VERSION = "0.6.16";
+	const VERSION = "0.7.1";
 }
 
 $yellow->plugins->register("language", "YellowLanguage", YellowLanguage::VERSION);

+ 70 - 25
system/plugins/update.php

@@ -5,7 +5,7 @@
 
 class YellowUpdate
 {
-	const VERSION = "0.6.15";
+	const VERSION = "0.7.1";
 	var $yellow;					//access to API
 	var $updates;					//number of updates
 	
@@ -23,35 +23,80 @@ class YellowUpdate
 	// Handle startup
 	function onStartup($update)
 	{
-		if($this->yellow->config->isExisting("updateNotification")) //TODO: remove later, cleans old config
+		if($update) //TODO: remove later, converts old config file
 		{
-			$update = true;
 			$fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
 			$fileData = $this->yellow->toolbox->readFile($fileNameConfig);
 			foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
 			{
+				$line = preg_replace("/^Webinterface/i", "Edit", $line);
 				preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-				if(!empty($matches[1]) && is_null($this->yellow->config->configDefaults[$matches[1]]) &&
-				   $line[0]!='#' && substru($line, 0, 5)!="Login")
+				if(!empty($matches[1]) && is_null($this->yellow->config->configDefaults[$matches[1]]))
 				{
 					$fileDataNew .= "# $line";
 				} else {
 					$fileDataNew .= $line;
 				}
 			}
-			$this->yellow->toolbox->createFile($fileNameConfig, $fileDataNew);
+			if($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileNameConfig, $fileDataNew);
 		}
-		if($update)	//TODO: remove later, converts old Yellow version
+		if($update)	//TODO: remove later, converts old error page
 		{
-			$fileNameScript = "yellow.php";
-			if(filesize($fileNameScript)==591)
+			$fileName = $this->yellow->config->get("configDir")."page-error-500.txt";
+			if(is_file($fileName))
 			{
-				$fileData = $this->yellow->toolbox->readFile($fileNameScript);
-				$fileData = preg_replace("#yellow->plugins->load\(\)#", "yellow->load()", $fileData);
-				$this->yellow->toolbox->createFile($fileNameScript, $fileData);
+				$fileData = $this->yellow->toolbox->readFile($fileName);
+				$fileDataNew = preg_replace("/@pageerror/", "[yellow error]", $fileData);
+				if($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
 			}
 		}
-		if($update)	//TODO: remove later, imports old file format
+		if($update)	//TODO: remove later, converts new blog page
+		{
+			$fileName = $this->yellow->config->get("configDir")."page-new-blog.txt";
+			if(is_file($fileName))
+			{
+				$fileData = $this->yellow->toolbox->readFile($fileName);
+				$fileDataNew = $this->yellow->toolbox->setMetaData($fileData, "template", "blog");
+				if($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
+			}
+		}
+		if($update)	//TODO: remove later, converts new wiki page
+		{
+			$fileName = $this->yellow->config->get("configDir")."page-new-wiki.txt";
+			if(is_file($fileName))
+			{
+				$fileData = $this->yellow->toolbox->readFile($fileName);
+				$fileDataNew = $this->yellow->toolbox->setMetaData($fileData, "template", "wiki");
+				if($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
+			}
+		}
+		if($update)	//TODO: remove later, converts template settings
+		{
+			$valueDefault = $this->yellow->config->get("template");
+			foreach($this->yellow->pages->index(true, true) as $page)
+			{
+				preg_match("/^.*\/(.+?)$/", dirname($page->fileName), $matches);
+				$value = $this->yellow->lookup->normaliseName($matches[1], true, false, true);
+				if(!is_file($this->yellow->config->get("templateDir").$value.".html")) $value = $valueDefault;
+				if(empty($this->yellow->toolbox->getMetaData($page->rawData, "template")) && $value!=$valueDefault)
+				{
+					$rawDataNew = $this->yellow->toolbox->setMetaData($page->rawData, "template", $value);
+					if($page->rawData!=$rawDataNew) $this->yellow->toolbox->createFile($page->fileName, $rawDataNew);
+				}
+			}
+			foreach($this->yellow->pages->index(true, true)->filter("template", "blogpages") as $page)
+			{
+				$rawDataNew = $this->yellow->toolbox->setMetaData($page->rawData, "templateNew", "blog");
+				if($page->rawData!=$rawDataNew) $this->yellow->toolbox->createFile($page->fileName, $rawDataNew);
+			}
+			foreach($this->yellow->pages->index(true, true)->filter("template", "wikipages") as $page)
+			{
+				$rawDataNew = $this->yellow->toolbox->setMetaData($page->rawData, "templateNew", "wiki");
+				if($page->rawData!=$rawDataNew) $this->yellow->toolbox->createFile($page->fileName, $rawDataNew);
+			}
+			$this->yellow->pages = new YellowPages($this->yellow);
+		}
+		if($update)	//TODO: remove later, converts theme files
 		{
 			$path = $this->yellow->config->get("themeDir");
 			foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.css$/", true, false) as $entry)
@@ -460,8 +505,8 @@ class YellowUpdate
 		if($language!="en")
 		{
 			$fileData = strreplaceu("\r\n", "\n", $this->yellow->toolbox->readFile($fileName));
-			$rawDataOld = strreplaceu("\\n", "\n", $this->yellow->text->getText("webinterfaceInstallation{$name}Page", "en"));
-			$rawDataNew = strreplaceu("\\n", "\n", $this->yellow->text->getText("webinterfaceInstallation{$name}Page", $language));
+			$rawDataOld = strreplaceu("\\n", "\n", $this->yellow->text->getText("editInstallation{$name}Page", "en"));
+			$rawDataNew = strreplaceu("\\n", "\n", $this->yellow->text->getText("editInstallation{$name}Page", $language));
 			if(!$this->yellow->toolbox->createFile($fileName, strreplaceu($rawDataOld, $rawDataNew, $fileData)))
 			{
 				$statusCode = 500;
@@ -522,10 +567,10 @@ class YellowUpdate
 			if($status=="install")
 			{
 				$status = "ok";
-				if(!empty($email) && !empty($password) && $this->yellow->plugins->isExisting("webinterface"))
+				if(!empty($email) && !empty($password) && $this->yellow->plugins->isExisting("edit"))
 				{
-					$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
-					$status = $this->yellow->plugins->get("webinterface")->users->update($fileNameUser, $email, $password, $name, $language) ? "ok" : "error";
+					$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+					$status = $this->yellow->plugins->get("edit")->users->update($fileNameUser, $email, $password, $name, $language) ? "ok" : "error";
 					if($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
 				}
 			}
@@ -572,16 +617,16 @@ class YellowUpdate
 	function getRawDataInstallation()
 	{
 		$language = $this->yellow->toolbox->detectBrowserLanguage($this->yellow->text->getLanguages(), $this->yellow->config->get("language"));
-		$fileName = strreplaceu("(.*)", "installation", $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceNewFile"));
+		$fileName = strreplaceu("(.*)", "installation", $this->yellow->config->get("configDir").$this->yellow->config->get("editNewFile"));
 		$rawData = $this->yellow->toolbox->readFile($fileName);
 		if(empty($rawData))
 		{
 			$this->yellow->text->setLanguage($language);
-			$rawData = "---\nTitle:".$this->yellow->text->get("webinterfaceInstallationTitle")."\nLanguage:$language\nNavigation:navigation\n---\n";
+			$rawData = "---\nTitle:".$this->yellow->text->get("editInstallationTitle")."\nLanguage:$language\nNavigation:navigation\n---\n";
 			$rawData .= "<form class=\"installation-form\" action=\"".$this->yellow->page->getLocation(true)."\" method=\"post\">\n";
-			$rawData .= "<p><label for=\"name\">".$this->yellow->text->get("webinterfaceSignupName")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"name\" id=\"name\" value=\"\"></p>\n";
-			$rawData .= "<p><label for=\"email\">".$this->yellow->text->get("webinterfaceSignupEmail")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"email\" id=\"email\" value=\"\"></p>\n";
-			$rawData .= "<p><label for=\"password\">".$this->yellow->text->get("webinterfaceSignupPassword")."</label><br /><input class=\"form-control\" type=\"password\" maxlength=\"64\" name=\"password\" id=\"password\" value=\"\"></p>\n";
+			$rawData .= "<p><label for=\"name\">".$this->yellow->text->get("editSignupName")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"name\" id=\"name\" value=\"\"></p>\n";
+			$rawData .= "<p><label for=\"email\">".$this->yellow->text->get("editSignupEmail")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"email\" id=\"email\" value=\"\"></p>\n";
+			$rawData .= "<p><label for=\"password\">".$this->yellow->text->get("editSignupPassword")."</label><br /><input class=\"form-control\" type=\"password\" maxlength=\"64\" name=\"password\" id=\"password\" value=\"\"></p>\n";
 			if(count($this->yellow->text->getLanguages())>1)
 			{
 				$rawData .= "<p>";
@@ -594,7 +639,7 @@ class YellowUpdate
 			}
 			if(count($this->getInstallationFeatures())>1)
 			{
-				$rawData .= "<p>".$this->yellow->text->get("webinterfaceInstallationFeature")."<p>";
+				$rawData .= "<p>".$this->yellow->text->get("editInstallationFeature")."<p>";
 				foreach($this->getInstallationFeatures() as $feature)
 				{
 					$checked = $feature=="website" ? " checked=\"checked\"" : "";
@@ -602,7 +647,7 @@ class YellowUpdate
 				}
 				$rawData .= "</p>\n";
 			}
-			$rawData .= "<input class=\"btn\" type=\"submit\" value=\"".$this->yellow->text->get("webinterfaceOkButton")."\" />\n";
+			$rawData .= "<input class=\"btn\" type=\"submit\" value=\"".$this->yellow->text->get("editOkButton")."\" />\n";
 			$rawData .= "<input type=\"hidden\" name=\"status\" value=\"install\" />\n";
 			$rawData .= "</form>\n";
 		}

BIN
system/plugins/yellow-blog.zip.installation


BIN
system/plugins/yellow-wiki.zip.installation