commit 3c7c88ddf3aa96c9e00adfebde48600057ef2d1a
parent 6d06eb1f26f7f0a0de070d9105ca890236ad81fa
Author: markseu <mark2011@mayberg.se>
Date: Sat, 17 Jun 2017 16:43:19 +0200
System update (better content handling)
Diffstat:
18 files changed, 3449 insertions(+), 3360 deletions(-)
diff --git a/system/config/config.ini b/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
diff --git a/system/config/page-error-500.txt b/system/config/page-error-500.txt
@@ -1,4 +1,4 @@
---
Title: Server error
---
-Something went wrong. @pageerror
-\ No newline at end of file
+Something went wrong. [yellow error]
+\ No newline at end of file
diff --git a/system/plugins/command.php b/system/plugins/command.php
@@ -0,0 +1,465 @@
+<?php
+// 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 YellowCommand
+{
+ const VERSION = "0.7.1";
+ var $yellow; //access to API
+ var $files; //number of files
+ var $errors; //number of errors
+ var $locationsArgs; //locations with location arguments detected
+ var $locationsArgsPagination; //locations with pagination arguments detected
+
+ // Handle initialisation
+ function onLoad($yellow)
+ {
+ $this->yellow = $yellow;
+ }
+
+ // Handle command
+ function onCommand($args)
+ {
+ list($command) = $args;
+ switch($command)
+ {
+ case "": $statusCode = $this->helpCommand(); break;
+ case "build": $statusCode = $this->buildCommand($args); break;
+ case "clean": $statusCode = $this->cleanCommand($args); break;
+ case "version": $statusCode = $this->versionCommand($args); break;
+ default: $statusCode = 0;
+ }
+ return $statusCode;
+ }
+
+ // Handle command help
+ function onCommandHelp()
+ {
+ $help .= "build [DIRECTORY LOCATION]\n";
+ $help .= "clean [DIRECTORY LOCATION]\n";
+ $help .= "version\n";
+ return $help;
+ }
+
+ // Show available commands
+ function helpCommand()
+ {
+ echo "Datenstrom Yellow ".YellowCore::VERSION."\n";
+ $lineCounter = 0;
+ foreach($this->getCommandHelp() as $line) echo (++$lineCounter>1 ? " " : "Syntax: ")."yellow.php $line\n";
+ return 200;
+ }
+
+ // Build static files
+ function buildCommand($args)
+ {
+ $statusCode = 0;
+ list($command, $path, $location) = $args;
+ if(empty($location) || $location[0]=='/')
+ {
+ if($this->checkStaticConfig())
+ {
+ $statusCode = $this->buildStatic($path, $location);
+ } else {
+ $statusCode = 500;
+ $this->files = 0; $this->errors = 1;
+ $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
+ echo "ERROR building files: Please configure StaticUrl in file '$fileName'!\n";
+ }
+ echo "Yellow $command: $this->files file".($this->files!=1 ? 's' : '');
+ echo ", $this->errors error".($this->errors!=1 ? 's' : '');
+ echo ", status $statusCode\n";
+ } else {
+ $statusCode = 400;
+ echo "Yellow $command: Invalid arguments\n";
+ }
+ return $statusCode;
+ }
+
+ // Build static files and additional locations
+ function buildStatic($path, $location)
+ {
+ $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
+ $this->files = $this->errors = $statusCode = 0;
+ $this->locationsArgs = $this->locationsArgsPagination = array();
+ if(empty($location))
+ {
+ $statusCode = $this->cleanStatic($path, $location);
+ foreach($this->getContentLocations() as $location)
+ {
+ $statusCode = max($statusCode, $this->buildStaticFile($path, $location, true));
+ }
+ foreach($this->locationsArgs as $location)
+ {
+ $statusCode = max($statusCode, $this->buildStaticFile($path, $location, true));
+ }
+ foreach($this->locationsArgsPagination as $location)
+ {
+ if(substru($location, -1)!=$this->yellow->toolbox->getLocationArgsSeparator())
+ {
+ $statusCode = max($statusCode, $this->buildStaticFile($path, $location, false, true));
+ }
+ for($pageNumber=2; $pageNumber<=999; ++$pageNumber)
+ {
+ $statusCodeLocation = $this->buildStaticFile($path, $location.$pageNumber, false, true);
+ $statusCode = max($statusCode, $statusCodeLocation);
+ if($statusCodeLocation==100) break;
+ }
+ }
+ foreach($this->getMediaLocations() as $location)
+ {
+ $statusCode = max($statusCode, $this->buildStaticFile($path, $location));
+ }
+ foreach($this->getSystemLocations() as $location)
+ {
+ $statusCode = max($statusCode, $this->buildStaticFile($path, $location));
+ }
+ $statusCode = max($statusCode, $this->buildStaticFile($path, "/error/", false, false, true));
+ } else {
+ $statusCode = $this->buildStaticFile($path, $location);
+ }
+ return $statusCode;
+ }
+
+ // Build static file
+ function buildStaticFile($path, $location, $analyse = false, $probe = false, $error = false)
+ {
+ $this->yellow->pages = new YellowPages($this->yellow);
+ $this->yellow->page = new YellowPage($this->yellow);
+ $this->yellow->page->fileName = substru($location, 1);
+ if(!is_readable($this->yellow->page->fileName))
+ {
+ ob_start();
+ $staticUrl = $this->yellow->config->get("staticUrl");
+ list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
+ $statusCode = $this->requestStaticFile($scheme, $address, $base, $location);
+ if($statusCode<400 || $error)
+ {
+ $fileData = ob_get_contents();
+ $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
+ if($modified==0) $modified = $this->yellow->toolbox->getFileModified($this->yellow->page->fileName);
+ if($statusCode>=301 && $statusCode<=303)
+ {
+ $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
+ $modified = time();
+ }
+ $fileName = $this->getStaticFile($path, $location, $statusCode);
+ if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
+ !$this->yellow->toolbox->modifyFile($fileName, $modified))
+ {
+ $statusCode = 500;
+ $this->yellow->page->statusCode = $statusCode;
+ $this->yellow->page->set("pageError", "Can't write file '$fileName'!");
+ }
+ }
+ ob_end_clean();
+ } else {
+ $statusCode = 200;
+ $modified = $this->yellow->toolbox->getFileModified($this->yellow->page->fileName);
+ $fileName = $this->getStaticFile($path, $location, $statusCode);
+ if(!$this->yellow->toolbox->copyFile($this->yellow->page->fileName, $fileName, true) ||
+ !$this->yellow->toolbox->modifyFile($fileName, $modified))
+ {
+ $statusCode = 500;
+ $this->yellow->page->statusCode = $statusCode;
+ $this->yellow->page->set("pageError", "Can't write file '$fileName'!");
+ }
+ }
+ if($statusCode==200 && $analyse) $this->analyseStaticFile($scheme, $address, $base, $fileData);
+ if($statusCode==404 && $probe) $statusCode = 100;
+ if($statusCode==404 && $error) $statusCode = 200;
+ if($statusCode>=200) ++$this->files;
+ if($statusCode>=400)
+ {
+ ++$this->errors;
+ echo "ERROR building location '$location', ".$this->yellow->page->getStatusCode(true)."\n";
+ }
+ if(defined("DEBUG") && DEBUG>=1) echo "YellowCommand::buildStaticFile status:$statusCode location:$location<br/>\n";
+ return $statusCode;
+ }
+
+ // Request static file
+ function requestStaticFile($scheme, $address, $base, $location)
+ {
+ list($serverName, $serverPort) = explode(':', $address);
+ if(is_null($serverPort)) $serverPort = $scheme=="https" ? 443 : 80;
+ $_SERVER["HTTPS"] = $scheme=="https" ? "on" : "off";
+ $_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";
+ $_REQUEST = array();
+ return $this->yellow->request();
+ }
+
+ // Analyse static file, detect locations with arguments
+ function analyseStaticFile($scheme, $address, $base, $rawData)
+ {
+ $pagination = $this->yellow->config->get("contentPagination");
+ preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $rawData, $matches);
+ foreach($matches[2] as $match)
+ {
+ $location = rawurldecode($match);
+ if(preg_match("/^(.*?)#(.*)$/", $location, $tokens)) $location = $tokens[1];
+ if(preg_match("/^(\w+):\/\/([^\/]+)(.*)$/", $location, $tokens))
+ {
+ if($tokens[1]!=$scheme) continue;
+ if($tokens[2]!=$address) continue;
+ $location = $tokens[3];
+ }
+ if(substru($location, 0, strlenu($base))!=$base) continue;
+ $location = substru($location, strlenu($base));
+ if(!$this->yellow->toolbox->isLocationArgs($location)) continue;
+ if(!$this->yellow->toolbox->isLocationArgsPagination($location, $pagination))
+ {
+ $location = rtrim($location, '/').'/';
+ if(is_null($this->locationsArgs[$location]))
+ {
+ $this->locationsArgs[$location] = $location;
+ 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 "YellowCommand::analyseStaticFile detected location:$location<br/>\n";
+ }
+ }
+ }
+ }
+
+ // Clean static files
+ function cleanCommand($args)
+ {
+ $statusCode = 0;
+ list($command, $path, $location) = $args;
+ if(empty($location) || $location[0]=='/')
+ {
+ $statusCode = $this->cleanStatic($path, $location);
+ echo "Yellow $command: Static file".(empty($location) ? "s" : "")." ".($statusCode!=200 ? "not " : "")."cleaned\n";
+ } else {
+ $statusCode = 400;
+ echo "Yellow $command: Invalid arguments\n";
+ }
+ return $statusCode;
+ }
+
+ // Clean static files and directories
+ function cleanStatic($path, $location)
+ {
+ $statusCode = 200;
+ $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
+ if(empty($location))
+ {
+ $statusCode = max($statusCode, $this->commandBroadcast("clean", "all"));
+ $statusCode = max($statusCode, $this->cleanStaticDirectory($path));
+ } else {
+ $statusCode = $this->cleanStaticFile($path, $location);
+ }
+ return $statusCode;
+ }
+
+ // Clean static directory
+ function cleanStaticDirectory($path)
+ {
+ $statusCode = 200;
+ if(is_dir($path) && $this->checkStaticDirectory($path))
+ {
+ if(!$this->yellow->toolbox->deleteDirectory($path))
+ {
+ $statusCode = 500;
+ echo "ERROR cleaning files: Can't delete directory '$path'!\n";
+ }
+ }
+ return $statusCode;
+ }
+
+ // Clean static file
+ function cleanStaticFile($path, $location)
+ {
+ $statusCode = 200;
+ $fileName = $this->getStaticFile($path, $location, $statusCode);
+ if(is_file($fileName))
+ {
+ if(!$this->yellow->toolbox->deleteFile($fileName))
+ {
+ $statusCode = 500;
+ echo "ERROR cleaning files: Can't delete file '$fileName'!\n";
+ }
+ }
+ return $statusCode;
+ }
+
+ // Broadcast command to other plugins
+ function commandBroadcast($args)
+ {
+ $statusCode = 0;
+ foreach($this->yellow->plugins->plugins as $key=>$value)
+ {
+ if($key=="command") continue;
+ if(method_exists($value["obj"], "onCommand"))
+ {
+ $statusCode = $value["obj"]->onCommand(func_get_args());
+ if($statusCode!=0) break;
+ }
+ }
+ return $statusCode;
+ }
+
+ // Show software version and updates
+ function versionCommand($args)
+ {
+ $serverVersion = $this->yellow->toolbox->getServerVersion();
+ echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
+ list($command) = $args;
+ list($statusCode, $dataCurrent) = $this->getSoftwareVersion();
+ list($statusCode, $dataLatest) = $this->getSoftwareVersion(true);
+ foreach($dataCurrent as $key=>$value)
+ {
+ if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])>=0)
+ {
+ echo "$key $value\n";
+ } else {
+ echo "$key $dataLatest[$key] - Update available\n";
+ }
+ }
+ if($statusCode!=200) echo "ERROR checking updates: ".$this->yellow->page->get("pageError")."\n";
+ return $statusCode;
+ }
+
+ // Check static configuration
+ function checkStaticConfig()
+ {
+ $staticUrl = $this->yellow->config->get("staticUrl");
+ return !empty($staticUrl);
+ }
+
+ // Check static directory
+ function checkStaticDirectory($path)
+ {
+ $ok = false;
+ if(!empty($path))
+ {
+ if($path==rtrim($this->yellow->config->get("staticDir"), '/')) $ok = true;
+ if($path==rtrim($this->yellow->config->get("trashDir"), '/')) $ok = true;
+ if(is_file("$path/".$this->yellow->config->get("staticDefaultFile"))) $ok = true;
+ if(is_file("$path/yellow.php")) $ok = false;
+ }
+ return $ok;
+ }
+
+ // Return static file
+ function getStaticFile($path, $location, $statusCode)
+ {
+ if($statusCode<400)
+ {
+ $fileName = $path.$location;
+ if(!$this->yellow->lookup->isFileLocation($location)) $fileName .= $this->yellow->config->get("staticDefaultFile");
+ } else if($statusCode==404) {
+ $fileName = $path."/".$this->yellow->config->get("staticErrorFile");
+ }
+ return $fileName;
+ }
+
+ // Return static redirect
+ function getStaticRedirect($location)
+ {
+ $output = "<!DOCTYPE html><html>\n<head>\n";
+ $output .= "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
+ $output .= "<meta http-equiv=\"refresh\" content=\"0;url=".htmlspecialchars($location)."\" />\n";
+ $output .= "</head>\n</html>";
+ return $output;
+ }
+
+ // Return content locations
+ function getContentLocations()
+ {
+ $locations = array();
+ $staticUrl = $this->yellow->config->get("staticUrl");
+ list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
+ $this->yellow->page->setRequestInformation($scheme, $address, $base, "", "");
+ foreach($this->yellow->pages->index(true, true) as $page)
+ {
+ if($page->get("status")!="ignore" && $page->get("status")!="draft")
+ {
+ array_push($locations, $page->location);
+ }
+ }
+ if(!$this->yellow->pages->find("/") && $this->yellow->config->get("multiLanguageMode")) array_unshift($locations, "/");
+ return $locations;
+ }
+
+ // Return media locations
+ function getMediaLocations()
+ {
+ $locations = array();
+ $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("mediaDir"), "/.*/", false, false);
+ foreach($fileNames as $fileName)
+ {
+ array_push($locations, "/".$fileName);
+ }
+ return $locations;
+ }
+
+ // Return system locations
+ function getSystemLocations()
+ {
+ $locations = array();
+ $regex = "/\.(css|ico|js|jpg|png|svg|txt|woff|woff2)$/";
+ $pluginDirLength = strlenu($this->yellow->config->get("pluginDir"));
+ $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("pluginDir"), $regex, false, false);
+ foreach($fileNames as $fileName)
+ {
+ array_push($locations, $this->yellow->config->get("pluginLocation").substru($fileName, $pluginDirLength));
+ }
+ $themeDirLength = strlenu($this->yellow->config->get("themeDir"));
+ $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("themeDir"), $regex, false, false);
+ foreach($fileNames as $fileName)
+ {
+ array_push($locations, $this->yellow->config->get("themeLocation").substru($fileName, $themeDirLength));
+ }
+ array_push($locations, "/".$this->yellow->config->get("robotsFile"));
+ return $locations;
+ }
+
+ // Return command help
+ function getCommandHelp()
+ {
+ $data = array();
+ foreach($this->yellow->plugins->plugins as $key=>$value)
+ {
+ if(method_exists($value["obj"], "onCommandHelp"))
+ {
+ foreach(preg_split("/[\r\n]+/", $value["obj"]->onCommandHelp()) as $line)
+ {
+ list($command) = explode(' ', $line);
+ if(!empty($command) && is_null($data[$command])) $data[$command] = $line;
+ }
+ }
+ }
+ uksort($data, strnatcasecmp);
+ return $data;
+ }
+
+ // Return software version
+ function getSoftwareVersion($latest = false)
+ {
+ $data = array();
+ if($this->yellow->plugins->isExisting("update"))
+ {
+ list($statusCode, $data) = $this->yellow->plugins->get("update")->getSoftwareVersion($latest);
+ } else {
+ $statusCode = 200;
+ $data = array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData());
+ }
+ return array($statusCode, $data);
+ }
+}
+
+$yellow->plugins->register("command", "YellowCommand", YellowCommand::VERSION);
+?>
diff --git a/system/plugins/commandline.php b/system/plugins/commandline.php
@@ -1,464 +0,0 @@
-<?php
-// Commandline plugin, https://github.com/datenstrom/yellow-plugins/tree/master/commandline
-// Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-class YellowCommandline
-{
- const VERSION = "0.6.19";
- var $yellow; //access to API
- var $files; //number of files
- var $errors; //number of errors
- var $locationsArgs; //locations with location arguments detected
- var $locationsArgsPagination; //locations with pagination arguments detected
-
- // Handle initialisation
- function onLoad($yellow)
- {
- $this->yellow = $yellow;
- }
-
- // Handle command
- function onCommand($args)
- {
- list($command) = $args;
- switch($command)
- {
- case "": $statusCode = $this->helpCommand(); break;
- case "build": $statusCode = $this->buildCommand($args); break;
- case "clean": $statusCode = $this->cleanCommand($args); break;
- case "version": $statusCode = $this->versionCommand($args); break;
- default: $statusCode = 0;
- }
- return $statusCode;
- }
-
- // Handle command help
- function onCommandHelp()
- {
- $help .= "build [DIRECTORY LOCATION]\n";
- $help .= "clean [DIRECTORY LOCATION]\n";
- $help .= "version\n";
- return $help;
- }
-
- // Show available commands
- function helpCommand()
- {
- echo "Yellow ".YellowCore::VERSION."\n";
- $lineCounter = 0;
- foreach($this->getCommandHelp() as $line) echo (++$lineCounter>1 ? " " : "Syntax: ")."yellow.php $line\n";
- return 200;
- }
-
- // Build static files
- function buildCommand($args)
- {
- $statusCode = 0;
- list($command, $path, $location) = $args;
- if(empty($location) || $location[0]=='/')
- {
- if($this->checkStaticConfig())
- {
- $statusCode = $this->buildStatic($path, $location);
- } else {
- $statusCode = 500;
- $this->files = 0; $this->errors = 1;
- $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
- echo "ERROR building files: Please configure StaticUrl in file '$fileName'!\n";
- }
- echo "Yellow $command: $this->files file".($this->files!=1 ? 's' : '');
- echo ", $this->errors error".($this->errors!=1 ? 's' : '');
- echo ", status $statusCode\n";
- } else {
- $statusCode = 400;
- echo "Yellow $command: Invalid arguments\n";
- }
- return $statusCode;
- }
-
- // Build static files and additional locations
- function buildStatic($path, $location)
- {
- $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
- $this->files = $this->errors = $statusCode = 0;
- $this->locationsArgs = $this->locationsArgsPagination = array();
- if(empty($location))
- {
- $statusCode = $this->cleanStatic($path, $location);
- foreach($this->getContentLocations() as $location)
- {
- $statusCode = max($statusCode, $this->buildStaticFile($path, $location, true));
- }
- foreach($this->locationsArgs as $location)
- {
- $statusCode = max($statusCode, $this->buildStaticFile($path, $location, true));
- }
- foreach($this->locationsArgsPagination as $location)
- {
- if(substru($location, -1)!=$this->yellow->toolbox->getLocationArgsSeparator())
- {
- $statusCode = max($statusCode, $this->buildStaticFile($path, $location, false, true));
- }
- for($pageNumber=2; $pageNumber<=999; ++$pageNumber)
- {
- $statusCodeLocation = $this->buildStaticFile($path, $location.$pageNumber, false, true);
- $statusCode = max($statusCode, $statusCodeLocation);
- if($statusCodeLocation==100) break;
- }
- }
- foreach($this->getMediaLocations() as $location)
- {
- $statusCode = max($statusCode, $this->buildStaticFile($path, $location));
- }
- foreach($this->getSystemLocations() as $location)
- {
- $statusCode = max($statusCode, $this->buildStaticFile($path, $location));
- }
- $statusCode = max($statusCode, $this->buildStaticFile($path, "/error/", false, false, true));
- } else {
- $statusCode = $this->buildStaticFile($path, $location);
- }
- return $statusCode;
- }
-
- // Build static file
- function buildStaticFile($path, $location, $analyse = false, $probe = false, $error = false)
- {
- $this->yellow->pages = new YellowPages($this->yellow);
- $this->yellow->page = new YellowPage($this->yellow);
- $this->yellow->page->fileName = substru($location, 1);
- if(!is_readable($this->yellow->page->fileName))
- {
- ob_start();
- $staticUrl = $this->yellow->config->get("staticUrl");
- list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
- $statusCode = $this->requestStaticFile($scheme, $address, $base, $location);
- if($statusCode<400 || $error)
- {
- $fileData = ob_get_contents();
- $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
- if($modified==0) $modified = $this->yellow->toolbox->getFileModified($this->yellow->page->fileName);
- if($statusCode>=301 && $statusCode<=303)
- {
- $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
- $modified = time();
- }
- $fileName = $this->getStaticFile($path, $location, $statusCode);
- if(!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
- !$this->yellow->toolbox->modifyFile($fileName, $modified))
- {
- $statusCode = 500;
- $this->yellow->page->statusCode = $statusCode;
- $this->yellow->page->set("pageError", "Can't write file '$fileName'!");
- }
- }
- ob_end_clean();
- } else {
- $statusCode = 200;
- $modified = $this->yellow->toolbox->getFileModified($this->yellow->page->fileName);
- $fileName = $this->getStaticFile($path, $location, $statusCode);
- if(!$this->yellow->toolbox->copyFile($this->yellow->page->fileName, $fileName, true) ||
- !$this->yellow->toolbox->modifyFile($fileName, $modified))
- {
- $statusCode = 500;
- $this->yellow->page->statusCode = $statusCode;
- $this->yellow->page->set("pageError", "Can't write file '$fileName'!");
- }
- }
- if($statusCode==200 && $analyse) $this->analyseStaticFile($scheme, $address, $base, $fileData);
- if($statusCode==404 && $probe) $statusCode = 100;
- if($statusCode==404 && $error) $statusCode = 200;
- if($statusCode>=200) ++$this->files;
- if($statusCode>=400)
- {
- ++$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";
- return $statusCode;
- }
-
- // Request static file
- function requestStaticFile($scheme, $address, $base, $location)
- {
- list($serverName, $serverPort) = explode(':', $address);
- if(is_null($serverPort)) $serverPort = $scheme=="https" ? 443 : 80;
- $_SERVER["HTTPS"] = $scheme=="https" ? "on" : "off";
- $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
- $_SERVER["SERVER_NAME"] = $serverName;
- $_SERVER["SERVER_PORT"] = $serverPort;
- $_SERVER["REQUEST_URI"] = $base.$location;
- $_SERVER["SCRIPT_NAME"] = $base."/yellow.php";
- $_SERVER["REMOTE_ADDR"] = "127.0.0.1";
- $_REQUEST = array();
- return $this->yellow->request();
- }
-
- // Analyse static file, detect locations with arguments
- function analyseStaticFile($scheme, $address, $base, $rawData)
- {
- $pagination = $this->yellow->config->get("contentPagination");
- preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $rawData, $matches);
- foreach($matches[2] as $match)
- {
- $location = rawurldecode($match);
- if(preg_match("/^(.*?)#(.*)$/", $location, $tokens)) $location = $tokens[1];
- if(preg_match("/^(\w+):\/\/([^\/]+)(.*)$/", $location, $tokens))
- {
- if($tokens[1]!=$scheme) continue;
- if($tokens[2]!=$address) continue;
- $location = $tokens[3];
- }
- if(substru($location, 0, strlenu($base))!=$base) continue;
- $location = substru($location, strlenu($base));
- if(!$this->yellow->toolbox->isLocationArgs($location)) continue;
- if(!$this->yellow->toolbox->isLocationArgsPagination($location, $pagination))
- {
- $location = rtrim($location, '/').'/';
- if(is_null($this->locationsArgs[$location]))
- {
- $this->locationsArgs[$location] = $location;
- if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::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";
- }
- }
- }
- }
-
- // Clean static files
- function cleanCommand($args)
- {
- $statusCode = 0;
- list($command, $path, $location) = $args;
- if(empty($location) || $location[0]=='/')
- {
- $statusCode = $this->cleanStatic($path, $location);
- echo "Yellow $command: Static file".(empty($location) ? "s" : "")." ".($statusCode!=200 ? "not " : "")."cleaned\n";
- } else {
- $statusCode = 400;
- echo "Yellow $command: Invalid arguments\n";
- }
- return $statusCode;
- }
-
- // Clean static files and directories
- function cleanStatic($path, $location)
- {
- $statusCode = 200;
- $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, '/');
- if(empty($location))
- {
- $statusCode = max($statusCode, $this->commandBroadcast("clean", "all"));
- $statusCode = max($statusCode, $this->cleanStaticDirectory($path));
- } else {
- $statusCode = $this->cleanStaticFile($path, $location);
- }
- return $statusCode;
- }
-
- // Clean static directory
- function cleanStaticDirectory($path)
- {
- $statusCode = 200;
- if(is_dir($path) && $this->checkStaticDirectory($path))
- {
- if(!$this->yellow->toolbox->deleteDirectory($path))
- {
- $statusCode = 500;
- echo "ERROR cleaning files: Can't delete directory '$path'!\n";
- }
- }
- return $statusCode;
- }
-
- // Clean static file
- function cleanStaticFile($path, $location)
- {
- $statusCode = 200;
- $fileName = $this->getStaticFile($path, $location, $statusCode);
- if(is_file($fileName))
- {
- if(!$this->yellow->toolbox->deleteFile($fileName))
- {
- $statusCode = 500;
- echo "ERROR cleaning files: Can't delete file '$fileName'!\n";
- }
- }
- return $statusCode;
- }
-
- // Broadcast command to other plugins
- function commandBroadcast($args)
- {
- $statusCode = 0;
- foreach($this->yellow->plugins->plugins as $key=>$value)
- {
- if($key=="commandline") continue;
- if(method_exists($value["obj"], "onCommand"))
- {
- $statusCode = $value["obj"]->onCommand(func_get_args());
- if($statusCode!=0) break;
- }
- }
- return $statusCode;
- }
-
- // Show software version and updates
- function versionCommand($args)
- {
- $serverVersion = $this->yellow->toolbox->getServerVersion();
- echo "Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
- list($command) = $args;
- list($statusCode, $dataCurrent) = $this->getSoftwareVersion();
- list($statusCode, $dataLatest) = $this->getSoftwareVersion(true);
- foreach($dataCurrent as $key=>$value)
- {
- if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])>=0)
- {
- echo "$key $value\n";
- } else {
- echo "$key $dataLatest[$key] - Update available\n";
- }
- }
- if($statusCode!=200) echo "ERROR checking updates: ".$this->yellow->page->get("pageError")."\n";
- return $statusCode;
- }
-
- // Check static configuration
- function checkStaticConfig()
- {
- $staticUrl = $this->yellow->config->get("staticUrl");
- return !empty($staticUrl);
- }
-
- // Check static directory
- function checkStaticDirectory($path)
- {
- $ok = false;
- if(!empty($path))
- {
- if($path==rtrim($this->yellow->config->get("staticDir"), '/')) $ok = true;
- if($path==rtrim($this->yellow->config->get("trashDir"), '/')) $ok = true;
- if(is_file("$path/".$this->yellow->config->get("staticDefaultFile"))) $ok = true;
- if(is_file("$path/yellow.php")) $ok = false;
- }
- return $ok;
- }
-
- // Return static file
- function getStaticFile($path, $location, $statusCode)
- {
- if($statusCode<400)
- {
- $fileName = $path.$location;
- if(!$this->yellow->lookup->isFileLocation($location)) $fileName .= $this->yellow->config->get("staticDefaultFile");
- } else if($statusCode==404) {
- $fileName = $path."/".$this->yellow->config->get("staticErrorFile");
- }
- return $fileName;
- }
-
- // Return static redirect
- function getStaticRedirect($location)
- {
- $output = "<!DOCTYPE html><html>\n<head>\n";
- $output .= "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
- $output .= "<meta http-equiv=\"refresh\" content=\"0;url=".htmlspecialchars($location)."\" />\n";
- $output .= "</head>\n</html>";
- return $output;
- }
-
- // Return content locations
- function getContentLocations()
- {
- $locations = array();
- $staticUrl = $this->yellow->config->get("staticUrl");
- list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
- $this->yellow->page->setRequestInformation($scheme, $address, $base, "", "");
- foreach($this->yellow->pages->index(true, true) as $page)
- {
- if($page->get("status")!="ignore" && $page->get("status")!="draft")
- {
- array_push($locations, $page->location);
- }
- }
- if(!$this->yellow->pages->find("/") && $this->yellow->config->get("multiLanguageMode")) array_unshift($locations, "/");
- return $locations;
- }
-
- // Return media locations
- function getMediaLocations()
- {
- $locations = array();
- $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("mediaDir"), "/.*/", false, false);
- foreach($fileNames as $fileName)
- {
- array_push($locations, "/".$fileName);
- }
- return $locations;
- }
-
- // Return system locations
- function getSystemLocations()
- {
- $locations = array();
- $regex = "/\.(css|ico|js|jpg|png|svg|txt|woff|woff2)$/";
- $pluginDirLength = strlenu($this->yellow->config->get("pluginDir"));
- $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("pluginDir"), $regex, false, false);
- foreach($fileNames as $fileName)
- {
- array_push($locations, $this->yellow->config->get("pluginLocation").substru($fileName, $pluginDirLength));
- }
- $themeDirLength = strlenu($this->yellow->config->get("themeDir"));
- $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("themeDir"), $regex, false, false);
- foreach($fileNames as $fileName)
- {
- array_push($locations, $this->yellow->config->get("themeLocation").substru($fileName, $themeDirLength));
- }
- array_push($locations, "/".$this->yellow->config->get("robotsFile"));
- return $locations;
- }
-
- // Return command help
- function getCommandHelp()
- {
- $data = array();
- foreach($this->yellow->plugins->plugins as $key=>$value)
- {
- if(method_exists($value["obj"], "onCommandHelp"))
- {
- foreach(preg_split("/[\r\n]+/", $value["obj"]->onCommandHelp()) as $line)
- {
- list($command) = explode(' ', $line);
- if(!empty($command) && is_null($data[$command])) $data[$command] = $line;
- }
- }
- }
- uksort($data, strnatcasecmp);
- return $data;
- }
-
- // Return software version
- function getSoftwareVersion($latest = false)
- {
- $data = array();
- if($this->yellow->plugins->isExisting("update"))
- {
- list($statusCode, $data) = $this->yellow->plugins->get("update")->getSoftwareVersion($latest);
- } else {
- $statusCode = 200;
- $data = array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData());
- }
- return array($statusCode, $data);
- }
-}
-
-$yellow->plugins->register("commandline", "YellowCommandline", YellowCommandline::VERSION);
-?>
-\ No newline at end of file
diff --git a/system/plugins/core.php b/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)
{
diff --git a/system/plugins/edit.css b/system/plugins/edit.css
@@ -0,0 +1,129 @@
+/* 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. */
+
+.yellow-bar { position:relative; overflow:hidden; height:2em; margin-bottom:10px; }
+.yellow-bar-left { display:block; float:left; }
+.yellow-bar-right { display:block; float:right; }
+.yellow-bar-right a { margin-left:1em; }
+.yellow-bar-right #yellow-pane-create-link { padding:0 0.5em; }
+.yellow-bar-right #yellow-pane-delete-link { padding:0 0.5em; }
+.yellow-body-modal-open { overflow:hidden; }
+
+.yellow-pane {
+ position:absolute; display:none; z-index:100;
+ margin:10px 0; padding:10px;
+ background-color:#fff; color:#000;
+ border:1px solid #bbb;
+ border-radius:4px; box-shadow:2px 4px 10px rgba(0, 0, 0, 0.2);
+}
+.yellow-pane h1 { color:#000; }
+.yellow-pane p { margin:0.5em; }
+.yellow-pane ul { list-style:none; margin:0 0.5em; padding:0; }
+.yellow-pane div { overflow:hidden; }
+.yellow-close { display:block; float:right; padding:0 0.5em; font-size:1.1em; color:#bbb; text-decoration:none; }
+.yellow-close:hover { color:#000; text-decoration:none; }
+.yellow-arrow { position:absolute; top:0; left:0; }
+.yellow-arrow:after, .yellow-arrow:before {
+ position:absolute;
+ bottom:100%;
+ height:0; width:0;
+ border:solid transparent;
+ content:" ";
+}
+.yellow-arrow:after {
+ border-color:rgba(255, 255, 255, 0);
+ border-bottom-color:#fff;
+ border-width:10px;
+ margin-left:-10px;
+}
+.yellow-arrow:before {
+ border-color:rgba(187, 187, 187, 0);
+ border-bottom-color:#bbb;
+ border-width:11px;
+ margin-left:-11px;
+}
+
+.yellow-form-control {
+ margin:0; padding:2px 4px;
+ display:inline-block;
+ background-color:#fff; color:#000;
+ background-image:linear-gradient(to bottom, #fff, #fff);
+ border:1px solid #bbb;
+ border-radius:4px;
+ font-size:0.9em; font-family:inherit; font-weight:normal; line-height:normal;
+}
+.yellow-btn {
+ margin:0; padding:4px 22px;
+ display:inline-block; min-width:8em;
+ background-color:#eaeaea; color:#333333;
+ background-image:linear-gradient(to bottom, #f8f8f8, #e1e1e1);
+ border:1px solid #bbb;
+ border-color:#c1c1c1 #c1c1c1 #aaaaaa;
+ border-radius:4px;
+ outline-offset:-2px;
+ font-size:0.9em; font-family:inherit; font-weight:normal; line-height:1;
+ text-align:center; text-decoration:none;
+}
+.yellow-btn:hover, .yellow-btn:focus, .yellow-btn:active {
+ color:#333333;
+ background-image:none;
+ text-decoration:none;
+}
+.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); }
+.yellow-btn-delete {
+ background-color:#c33c35; color:#ffffff;
+ background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);
+ border-color:#b13121 #b13121 #802020;
+}
+.yellow-btn-delete:hover, .yellow-btn-delete:focus, .yellow-btn-delete:active { color:#ffffff; }
+
+#yellow-pane-login { text-align:center; white-space:nowrap; }
+#yellow-pane-login h1 { margin:0 1em; font-size:2em; }
+#yellow-pane-login .yellow-form-control { width:15em; box-sizing:border-box; }
+#yellow-pane-login .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
+#yellow-pane-login-fields { width:15em; text-align:left; margin:0 auto; }
+#yellow-pane-login-buttons { margin:0.5em 0; }
+#yellow-pane-login-buttons p { margin:0; }
+
+#yellow-pane-signup { text-align:center; white-space:nowrap; }
+#yellow-pane-signup h1 { margin:0 1em; font-size:2em; }
+#yellow-pane-signup .yellow-form-control { width:15em; box-sizing:border-box; }
+#yellow-pane-signup .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
+#yellow-pane-signup-status { margin:0.5em 0; display:inline-block; }
+#yellow-pane-signup-fields { width:15em; text-align:left; margin:0 auto; }
+#yellow-pane-signup-buttons { margin-top:-0.5em; }
+
+#yellow-pane-recover { text-align:center; white-space:nowrap; }
+#yellow-pane-recover h1 { margin:0 1em; font-size:2em; }
+#yellow-pane-recover .yellow-form-control { width:15em; box-sizing:border-box; }
+#yellow-pane-recover .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
+#yellow-pane-recover-status { margin:0.5em 0; display:inline-block; }
+#yellow-pane-recover-fields-first, #yellow-pane-recover-fields-second { width:15em; text-align:left; margin:0 auto; }
+#yellow-pane-recover-buttons { margin-top:-0.5em; }
+
+#yellow-pane-settings { text-align:center; white-space:nowrap; }
+#yellow-pane-settings h1 { margin:0 1em; font-size:2em; }
+#yellow-pane-settings .yellow-form-control { width:15em; box-sizing:border-box; }
+#yellow-pane-settings .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
+#yellow-pane-settings-status { margin:0.5em 0; display:inline-block; }
+#yellow-pane-settings-fields { width:15em; text-align:left; margin:0 auto; }
+#yellow-pane-settings-buttons { margin-top:-0.5em; }
+
+#yellow-pane-version { text-align:center; white-space:nowrap; }
+#yellow-pane-version h1 { margin:0 1em; font-size:2em; }
+#yellow-pane-version .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
+#yellow-pane-version-status { margin:0.5em 0; display:inline-block; }
+#yellow-pane-version-fields { text-align:center; margin:0.5em 0; }
+#yellow-pane-version-buttons { margin-top:-0.5em; }
+
+#yellow-pane-edit { }
+#yellow-pane-edit h1 { margin:0 0 10px 0; font-size:2em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
+#yellow-pane-edit-page { padding:5px; outline:none; resize:none; }
+#yellow-pane-edit-buttons { margin-top:5px; }
+#yellow-pane-edit-buttons input { margin-right:10px; }
+#yellow-pane-edit-help { float:right; }
+
+#yellow-pane-user { cursor:pointer; }
+#yellow-pane-user a { text-decoration:none; }
+#yellow-pane-user a:hover { text-decoration:underline; }
diff --git a/system/plugins/edit.js b/system/plugins/edit.js
@@ -0,0 +1,811 @@
+// 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.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.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
+
+ // Handle action
+ action: function(action, status, args)
+ {
+ status = status ? status : "none";
+ args = args ? args : "none";
+ switch(action)
+ {
+ case "login": this.showPane("yellow-pane-login", action, status); break;
+ case "logout": this.sendPane("yellow-pane-logout", action); break;
+ case "signup": this.showPane("yellow-pane-signup", action, status); break;
+ case "confirm": this.showPane("yellow-pane-signup", action, status); break;
+ case "approve": this.showPane("yellow-pane-signup", action, status); break;
+ case "recover": this.showPane("yellow-pane-recover", action, status); break;
+ case "settings": this.showPane("yellow-pane-settings", action, status); break;
+ case "reconfirm": this.showPane("yellow-pane-settings", action, status); break;
+ case "change": this.showPane("yellow-pane-settings", action, status); break;
+ case "version": this.showPane("yellow-pane-version", action, status); break;
+ case "update": this.sendPane("yellow-pane-update", action, status, args); break;
+ case "create": this.showPane("yellow-pane-edit", action, status, true); break;
+ 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;
+ }
+ },
+
+ // Load interface
+ load: function()
+ {
+ var body = document.getElementsByTagName("body")[0];
+ if(body && body.firstChild && !document.getElementById("yellow-bar"))
+ {
+ this.createBar("yellow-bar");
+ this.createPane("yellow-pane-edit", "none", "none");
+ this.action(yellow.page.action, yellow.page.status);
+ clearInterval(this.intervalId);
+ }
+ },
+
+ // Create bar
+ createBar: function(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);
+ if(barId=="yellow-bar")
+ {
+ yellow.toolbox.addEvent(document, "click", yellow.onClick);
+ yellow.toolbox.addEvent(document, "keydown", yellow.onKeydown);
+ yellow.toolbox.addEvent(window, "resize", yellow.onResize);
+ }
+ if(yellow.config.userName)
+ {
+ elementBar.innerHTML =
+ "<div class=\"yellow-bar-left\">"+
+ "<a href=\"#\" onclick=\"yellow.action('edit'); return false;\" id=\"yellow-pane-edit-link\">"+this.getText("Edit")+"</a>"+
+ "</div>"+
+ "<div class=\"yellow-bar-right\">"+
+ "<a href=\"#\" onclick=\"yellow.action('create'); return false;\" id=\"yellow-pane-create-link\">"+this.getText("Create")+"</a>"+
+ "<a href=\"#\" onclick=\"yellow.action('delete'); return false;\" id=\"yellow-pane-delete-link\">"+this.getText("Delete")+"</a>"+
+ "<a href=\"#\" onclick=\"yellow.action('user'); return false;\" id=\"yellow-pane-user-link\">"+yellow.toolbox.encodeHtml(yellow.config.userName)+"</a>"+
+ "</div>";
+ }
+ yellow.toolbox.insertBefore(elementBar, document.getElementsByTagName("body")[0].firstChild);
+ return elementBar;
+ },
+
+ // Create pane
+ createPane: function(paneId, paneAction, paneStatus)
+ {
+ if(yellow.config.debug) console.log("yellow.edit.createPane id:"+paneId);
+ var elementPane = document.createElement("div");
+ elementPane.className = "yellow-pane";
+ elementPane.setAttribute("id", paneId);
+ elementPane.style.display = "none";
+ if(paneId=="yellow-pane-edit")
+ {
+ yellow.toolbox.addEvent(elementPane, "keyup", yellow.onUpdate);
+ yellow.toolbox.addEvent(elementPane, "change", yellow.onUpdate);
+ }
+ if(paneId=="yellow-pane-edit" || paneId=="yellow-pane-user")
+ {
+ var elementArrow = document.createElement("span");
+ elementArrow.className = "yellow-arrow";
+ elementArrow.setAttribute("id", paneId+"-arrow");
+ elementPane.appendChild(elementArrow);
+ }
+ var elementDiv = document.createElement("div");
+ elementDiv.setAttribute("id", paneId+"-content");
+ switch(paneId)
+ {
+ case "yellow-pane-login":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<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.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;\" 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;
+ case "yellow-pane-signup":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<h1>"+this.getText("SignupTitle")+"</h1>"+
+ "<div id=\"yellow-pane-signup-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
+ "<div id=\"yellow-pane-signup-fields\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"signup\" />"+
+ "<p><label for=\"yellow-pane-signup-name\">"+this.getText("SignupName")+"</label><br /><input class=\"yellow-form-control\" name=\"name\" id=\"yellow-pane-signup-name\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("name"))+"\" /></p>"+
+ "<p><label for=\"yellow-pane-signup-email\">"+this.getText("SignupEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-signup-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
+ "<p><label for=\"yellow-pane-signup-password\">"+this.getText("SignupPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-signup-password\" maxlength=\"64\" value=\"\" /></p>"+
+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SignupButton")+"\" /></p>"+
+ "</div>"+
+ "<div id=\"yellow-pane-signup-buttons\">"+
+ "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "</form>";
+ break;
+ case "yellow-pane-recover":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<h1>"+this.getText("RecoverTitle")+"</h1>"+
+ "<div id=\"yellow-pane-recover-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
+ "<div id=\"yellow-pane-recover-fields-first\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"recover\" />"+
+ "<p><label for=\"yellow-pane-recover-email\">"+this.getText("RecoverEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-recover-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "<div id=\"yellow-pane-recover-fields-second\">"+
+ "<p><label for=\"yellow-pane-recover-password\">"+this.getText("RecoverPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-recover-password\" maxlength=\"64\" value=\"\" /></p>"+
+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "<div id=\"yellow-pane-recover-buttons\">"+
+ "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "</form>";
+ break;
+ case "yellow-pane-settings":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<h1 id=\"yellow-pane-settings-title\">"+this.getText("SettingsTitle")+"</h1>"+
+ "<div id=\"yellow-pane-settings-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
+ "<div id=\"yellow-pane-settings-fields\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"settings\" />"+
+ "<p><label for=\"yellow-pane-settings-name\">"+this.getText("SignupName")+"</label><br /><input class=\"yellow-form-control\" name=\"name\" id=\"yellow-pane-settings-name\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("name"))+"\" /></p>"+
+ "<p><label for=\"yellow-pane-settings-email\">"+this.getText("SignupEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-settings-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
+ "<p><label for=\"yellow-pane-settings-password\">"+this.getText("SignupPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-settings-password\" maxlength=\"64\" value=\"\" /></p>"+this.getLanguages(paneId)+
+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "<div id=\"yellow-pane-settings-buttons\">"+
+ "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "</form>";
+ break;
+ case "yellow-pane-version":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<h1 id=\"yellow-pane-version-title\">"+yellow.toolbox.encodeHtml(yellow.config.serverVersion)+"</h1>"+
+ "<div id=\"yellow-pane-version-status\" class=\""+paneStatus+"\">"+this.getText("VersionStatus", "", paneStatus)+"</div>"+
+ "<div id=\"yellow-pane-version-fields\">"+yellow.page.rawDataOutput+"</div>"+
+ "<div id=\"yellow-pane-version-buttons\">"+
+ "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
+ "</div>"+
+ "</form>";
+ break;
+ case "yellow-pane-edit":
+ elementDiv.innerHTML =
+ "<form method=\"post\">"+
+ "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
+ "<h1 id=\"yellow-pane-edit-title\">"+this.getText("Edit")+"</h1>"+
+ "<textarea id=\"yellow-pane-edit-page\" class=\"yellow-form-control\" name=\"rawdataedit\"></textarea>"+
+ "<div id=\"yellow-pane-edit-buttons\">"+
+ "<input id=\"yellow-pane-edit-send\" class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('send'); return false;\" value=\""+this.getText("EditButton")+"\" />"+
+ "<a href=\""+this.getText("MarkdownHelpUrl", "yellow")+"\" target=\"_blank\" id=\"yellow-pane-edit-help\">"+this.getText("MarkdownHelp")+"</a>" +
+ "</div>"+
+ "</form>";
+ break;
+ case "yellow-pane-user":
+ elementDiv.innerHTML =
+ "<p>"+yellow.toolbox.encodeHtml(yellow.config.userEmail)+"</p>"+
+ "<p><a href=\"#\" onclick=\"yellow.action('settings'); return false;\">"+this.getText("SettingsTitle")+"</a></p>" +
+ "<p><a href=\"#\" onclick=\"yellow.action('help'); return false;\">"+this.getText("UserHelp")+"</a></p>" +
+ "<p><a href=\"#\" onclick=\"yellow.action('logout'); return false;\">"+this.getText("UserLogout")+"</a></p>";
+ break;
+ }
+ elementPane.appendChild(elementDiv);
+ yellow.toolbox.insertAfter(elementPane, document.getElementsByTagName("body")[0].firstChild);
+ return elementPane;
+ },
+
+ // Update pane
+ updatePane: function(paneId, paneAction, paneStatus, init)
+ {
+ 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.editLoginRestrictions)
+ {
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-signup"), false);
+ }
+ break;
+ case "yellow-pane-signup":
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-signup-fields"), showFields);
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-signup-buttons"), !showFields);
+ break;
+ case "yellow-pane-recover":
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-first"), showFields);
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-second"), showFields);
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-buttons"), !showFields);
+ if(showFields)
+ {
+ if(this.getRequest("id"))
+ {
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-first"), false);
+ } else {
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-second"), false);
+ }
+ }
+ break;
+ case "yellow-pane-settings":
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-settings-fields"), showFields);
+ yellow.toolbox.setVisible(document.getElementById("yellow-pane-settings-buttons"), !showFields);
+ if(paneStatus=="none")
+ {
+ document.getElementById("yellow-pane-settings-status").innerHTML = "<a href=\"#\" onclick=\"yellow.action('version'); return false;\">"+this.getText("VersionTitle")+"</a>";
+ document.getElementById("yellow-pane-settings-name").value = yellow.config.userName;
+ document.getElementById("yellow-pane-settings-email").value = yellow.config.userEmail;
+ document.getElementById("yellow-pane-settings-"+yellow.config.userLanguage).checked = true;
+ }
+ break;
+ case "yellow-pane-version":
+ if(paneStatus=="none" && yellow.config.userUpdate)
+ {
+ document.getElementById("yellow-pane-version-status").innerHTML = this.getText("VersionStatusCheck");
+ document.getElementById("yellow-pane-version-fields").innerHTML = "";
+ setTimeout("yellow.action('send');", 500);
+ }
+ if(paneStatus=="updates" && yellow.config.userWebmaster)
+ {
+ document.getElementById("yellow-pane-version-status").innerHTML = "<a href=\"#\" onclick=\"yellow.action('update'); return false;\">"+this.getText("VersionUpdateNormal")+"</a>";
+ }
+ break;
+ case "yellow-pane-edit":
+ if(init)
+ {
+ 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);
+ document.getElementById("yellow-pane-edit-page").value = string;
+ yellow.toolbox.setCursorPosition(document.getElementById("yellow-pane-edit-page"), 0);
+ }
+ paneAction = this.getPaneAction(paneId, paneAction);
+ var key, className, readOnly;
+ switch(paneAction)
+ {
+ case "create": key = "CreateButton"; className = "yellow-btn yellow-btn-create"; readOnly = false; break;
+ case "edit": key = "EditButton"; className = "yellow-btn yellow-btn-edit"; readOnly = false; break;
+ case "delete": key = "DeleteButton"; className = "yellow-btn yellow-btn-delete"; readOnly = false; break;
+ case "": key = "CancelButton"; className = "yellow-btn yellow-btn-cancel"; readOnly = true; break;
+ }
+ document.getElementById("yellow-pane-edit-send").value = this.getText(key);
+ document.getElementById("yellow-pane-edit-send").className = className;
+ document.getElementById("yellow-pane-edit-page").readOnly = readOnly;
+ break;
+ }
+ },
+
+ // Resize pane
+ resizePane: function(paneId, paneAction, paneStatus)
+ {
+ var elementBar = document.getElementById("yellow-bar");
+ var paneLeft = yellow.toolbox.getOuterLeft(elementBar);
+ var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar);
+ var paneWidth = yellow.toolbox.getOuterWidth(elementBar);
+ var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar);
+ switch(paneId)
+ {
+ case "yellow-pane-login":
+ case "yellow-pane-signup":
+ case "yellow-pane-recover":
+ case "yellow-pane-settings":
+ case "yellow-pane-version":
+ yellow.toolbox.setOuterLeft(document.getElementById(paneId), paneLeft);
+ yellow.toolbox.setOuterTop(document.getElementById(paneId), paneTop);
+ yellow.toolbox.setOuterWidth(document.getElementById(paneId), paneWidth);
+ break;
+ case "yellow-pane-edit":
+ yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit"), paneLeft);
+ yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-edit"), paneTop);
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit"), paneHeight);
+ yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit"), paneWidth);
+ yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-page"), yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit")));
+ var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-pane-edit"));
+ var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-content"));
+ var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-page"));
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-page"), height1 - height2 + height3);
+ var elementLink = document.getElementById("yellow-pane-"+paneAction+"-link");
+ var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2;
+ position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-edit")) + 1;
+ yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit-arrow"), position);
+ break;
+ case "yellow-pane-user":
+ yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user"), paneLeft + paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-user")));
+ yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-user"), paneTop);
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-user"), paneHeight, true);
+ var elementLink = document.getElementById("yellow-pane-user-link");
+ var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2;
+ position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-user"));
+ yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user-arrow"), position);
+ break;
+ }
+ },
+
+ // Show or hide pane
+ showPane: function(paneId, paneAction, paneStatus, modal)
+ {
+ if(this.paneId!=paneId || this.paneAction!=paneAction)
+ {
+ this.hidePane(this.paneId);
+ var element = document.getElementById(paneId);
+ if(!element) element = this.createPane(paneId, paneAction, paneStatus);
+ if(!yellow.toolbox.isVisible(element))
+ {
+ if(yellow.config.debug) console.log("yellow.edit.showPane id:"+paneId);
+ yellow.toolbox.setVisible(element, true);
+ if(modal)
+ {
+ yellow.toolbox.addClass(document.body, "yellow-body-modal-open");
+ yellow.toolbox.addValue("meta[name=viewport]", "content", ", maximum-scale=1, user-scalable=0");
+ }
+ this.paneId = paneId;
+ this.paneAction = paneAction;
+ this.paneStatus = paneStatus;
+ this.resizePane(paneId, paneAction, paneStatus);
+ this.updatePane(paneId, paneAction, paneStatus, this.paneActionOld!=this.paneAction);
+ }
+ } else {
+ this.hidePane(this.paneId);
+ }
+ },
+
+ // Hide pane
+ hidePane: function(paneId)
+ {
+ var element = document.getElementById(paneId);
+ if(yellow.toolbox.isVisible(element))
+ {
+ 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;
+ }
+ },
+
+ // Hide all panes
+ hidePanes: function()
+ {
+ for(var element=document.getElementById("yellow-bar"); element; element=element.nextSibling)
+ {
+ if(element.className && element.className.indexOf("yellow-pane")>=0)
+ {
+ this.hidePane(element.getAttribute("id"));
+ }
+ }
+ },
+
+ // Hide all panes on mouse click outside
+ hidePanesOnClick: function(element)
+ {
+ for(;element; element=element.parentNode)
+ {
+ if(element.className)
+ {
+ if(element.className.indexOf("yellow-pane")>=0 || element.className.indexOf("yellow-bar-")>=0) return;
+ }
+ }
+ this.hidePanes();
+ },
+
+ // Hide all panes on ESC key
+ hidePanesOnKeydown: function(keycode)
+ {
+ if(keycode==27) this.hidePanes();
+ },
+
+ // Send pane
+ sendPane: function(paneId, paneAction, paneStatus, paneArgs)
+ {
+ if(yellow.config.debug) console.log("yellow.edit.sendPane id:"+paneId);
+ if(paneId=="yellow-pane-edit")
+ {
+ paneAction = this.getPaneAction(paneId, paneAction);
+ if(paneAction)
+ {
+ var args = {};
+ args.action = paneAction;
+ args.rawdatasource = yellow.page.rawDataSource;
+ args.rawdataedit = document.getElementById("yellow-pane-edit-page").value;
+ yellow.toolbox.submitForm(args, true);
+ } else {
+ this.hidePane(paneId);
+ }
+ } else {
+ var args = {"action":paneAction};
+ if(paneArgs)
+ {
+ var tokens = paneArgs.split('/');
+ for(var i=0; i<tokens.length; i++)
+ {
+ var pair = tokens[i].split(/[:=]/);
+ if(!pair[0] || !pair[1]) continue;
+ args[pair[0]] = pair[1];
+ }
+ }
+ yellow.toolbox.submitForm(args);
+ }
+ },
+
+ // Return pane action
+ getPaneAction: function(paneId, paneAction)
+ {
+ if(paneId=="yellow-pane-edit")
+ {
+ var string = document.getElementById("yellow-pane-edit-page").value;
+ var paneActionOld = paneAction;
+ switch(paneAction)
+ {
+ case "create": paneAction = "create"; break;
+ case "edit": paneAction = string ? "edit" : "delete"; break;
+ case "delete": paneAction = "delete"; break;
+ }
+ if(yellow.page.statusCode==424 && paneActionOld!="delete") paneAction = "create";
+ if(yellow.config.userRestrictions) paneAction = "";
+ }
+ return paneAction;
+ },
+
+ // Return language selection
+ getLanguages: function(paneId)
+ {
+ var languages = "";
+ if(yellow.config.serverLanguages && yellow.toolbox.getLength(yellow.config.serverLanguages)>1)
+ {
+ languages += "<p>";
+ 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.toolbox.encodeHtml(yellow.config.serverLanguages[language])+"</label><br />";
+ }
+ languages += "</p>";
+ }
+ return languages;
+ },
+
+ // Return request string
+ getRequest: function(key, prefix)
+ {
+ if(!prefix) prefix = "request";
+ key = prefix + key.charAt(0).toUpperCase() + key.slice(1);
+ return (key in yellow.page) ? yellow.page[key] : "";
+ },
+
+ // Return text string
+ getText: function(key, prefix, postfix)
+ {
+ 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+"]";
+ }
+};
+
+yellow.toolbox =
+{
+ // Insert element before reference element
+ insertBefore: function(element, elementReference)
+ {
+ elementReference.parentNode.insertBefore(element, elementReference);
+ },
+
+ // Insert element after reference element
+ insertAfter: function(element, elementReference)
+ {
+ elementReference.parentNode.insertBefore(element, elementReference.nextSibling);
+ },
+
+ // Add element class
+ addClass: function(element, name)
+ {
+ var string = element.className + " " + name;
+ element.className = string.replace(/^\s+|\s+$/, "");
+ },
+
+ // Remove element class
+ removeClass: function(element, name)
+ {
+ var string = (" " + element.className + " ").replace(" " + name + " ", " ");
+ element.className = string.replace(/^\s+|\s+$/, "");
+ },
+
+ // Add attribute information
+ addValue: function(selector, name, value)
+ {
+ var element = document.querySelector(selector);
+ element.setAttribute(name, element.getAttribute(name) + value);
+ },
+
+ // Remove attribute information
+ removeValue: function(selector, name, value)
+ {
+ var element = document.querySelector(selector);
+ element.setAttribute(name, element.getAttribute(name).replace(value, ""));
+ },
+
+ // Add event handler
+ addEvent: function(element, type, handler)
+ {
+ if(element.addEventListener) element.addEventListener(type, handler, false);
+ else element.attachEvent("on"+type, handler);
+ },
+
+ // Remove event handler
+ removeEvent: function(element, type, handler)
+ {
+ if(element.removeEventListener) element.removeEventListener(type, handler, false);
+ else element.detachEvent("on"+type, handler);
+ },
+
+ // Return element of event
+ getEventElement: function(e)
+ {
+ e = e ? e : window.event;
+ return e.target ? e.target : e.srcElement;
+ },
+
+ // Return keycode of event
+ getEventKeycode: function(e)
+ {
+ e = e ? e : window.event;
+ return e.keyCode;
+ },
+
+ // Return element length
+ getLength: function(element)
+ {
+ return Object.keys ? Object.keys(element).length : 0;
+ },
+
+ // Return element width in pixel
+ getWidth: function(element)
+ {
+ return element.offsetWidth - this.getBoxSize(element).width;
+ },
+
+ // Return element height in pixel
+ getHeight: function(element)
+ {
+ return element.offsetHeight - this.getBoxSize(element).height;
+ },
+
+ // Set element width in pixel, including padding and border
+ setOuterWidth: function(element, width, setMax)
+ {
+ width -= this.getBoxSize(element).width;
+ if(setMax)
+ {
+ element.style.maxWidth = Math.max(0, width) + "px";
+ } else {
+ element.style.width = Math.max(0, width) + "px";
+ }
+ },
+
+ // Set element height in pixel, including padding and border
+ setOuterHeight: function(element, height, setMax)
+ {
+ height -= this.getBoxSize(element).height;
+ if(setMax)
+ {
+ element.style.maxHeight = Math.max(0, height) + "px";
+ } else {
+ element.style.height = Math.max(0, height) + "px";
+ }
+ },
+
+ // Return element width in pixel, including padding and border
+ getOuterWidth: function(element, includeMargin)
+ {
+ var width = element.offsetWidth;
+ if(includeMargin) width += this.getMarginSize(element).width;
+ return width;
+ },
+
+ // Return element height in pixel, including padding and border
+ getOuterHeight: function(element, includeMargin)
+ {
+ var height = element.offsetHeight;
+ if(includeMargin) height += this.getMarginSize(element).height;
+ return height;
+ },
+
+ // Set element left position in pixel
+ setOuterLeft: function(element, left)
+ {
+ element.style.left = Math.max(0, left) + "px";
+ },
+
+ // Set element top position in pixel
+ setOuterTop: function(element, top)
+ {
+ element.style.top = Math.max(0, top) + "px";
+ },
+
+ // Return element left position in pixel
+ getOuterLeft: function(element)
+ {
+ var left = element.getBoundingClientRect().left;
+ return left + (window.pageXOffset || document.documentElement.scrollLeft);
+ },
+
+ // Return element top position in pixel
+ getOuterTop: function(element)
+ {
+ var top = element.getBoundingClientRect().top;
+ return top + (window.pageYOffset || document.documentElement.scrollTop);
+ },
+
+ // Return window width in pixel
+ getWindowWidth: function()
+ {
+ return window.innerWidth || document.documentElement.clientWidth;
+ },
+
+ // Return window height in pixel
+ getWindowHeight: function()
+ {
+ return window.innerHeight || document.documentElement.clientHeight;
+ },
+
+ // Return element CSS property
+ getStyle: function(element, property)
+ {
+ var string = "";
+ if(window.getComputedStyle)
+ {
+ string = window.getComputedStyle(element, null).getPropertyValue(property);
+ } else {
+ property = property.replace(/\-(\w)/g, function(match, m) { return m.toUpperCase(); });
+ string = element.currentStyle[property];
+ }
+ return string;
+ },
+
+ // Return element CSS padding and border
+ getBoxSize: function(element)
+ {
+ var paddingLeft = parseFloat(this.getStyle(element, "padding-left")) || 0;
+ var paddingRight = parseFloat(this.getStyle(element, "padding-right")) || 0;
+ var borderLeft = parseFloat(this.getStyle(element, "border-left-width")) || 0;
+ var borderRight = parseFloat(this.getStyle(element, "border-right-width")) || 0;
+ var width = paddingLeft + paddingRight + borderLeft + borderRight;
+ var paddingTop = parseFloat(this.getStyle(element, "padding-top")) || 0;
+ var paddingBottom = parseFloat(this.getStyle(element, "padding-bottom")) || 0;
+ var borderTop = parseFloat(this.getStyle(element, "border-top-width")) || 0;
+ var borderBottom = parseFloat(this.getStyle(element, "border-bottom-width")) || 0;
+ var height = paddingTop + paddingBottom + borderTop + borderBottom;
+ return { "width":width, "height":height };
+ },
+
+ // Return element CSS margin
+ getMarginSize: function(element)
+ {
+ var marginLeft = parseFloat(this.getStyle(element, "margin-left")) || 0;
+ var marginRight = parseFloat(this.getStyle(element, "margin-right")) || 0;
+ var width = marginLeft + marginRight;
+ var marginTop = parseFloat(this.getStyle(element, "margin-top")) || 0;
+ var marginBottom = parseFloat(this.getStyle(element, "margin-bottom")) || 0;
+ var height = marginTop + marginBottom;
+ return { "width":width, "height":height };
+ },
+
+ // Set input cursor position
+ setCursorPosition: function(element, pos)
+ {
+ if(element.setSelectionRange)
+ {
+ element.focus();
+ element.setSelectionRange(pos, pos);
+ } else if(element.createTextRange) {
+ var range = element.createTextRange();
+ range.move("character", pos);
+ range.select();
+ }
+ },
+
+ // Get input cursor position
+ getCursorPosition: function(element)
+ {
+ var pos = 0;
+ if(element.setSelectionRange)
+ {
+ pos = element.selectionStart;
+ } else if(document.selection) {
+ var range = document.selection.createRange();
+ var rangeDuplicate = range.duplicate();
+ rangeDuplicate.moveToElementText(element);
+ rangeDuplicate.setEndPoint("EndToEnd", range);
+ pos = rangeDuplicate.text.length - range.text.length;
+ }
+ return pos;
+ },
+
+ // Set element visibility
+ setVisible: function(element, show)
+ {
+ element.style.display = show ? "block" : "none";
+ },
+
+ // Check if element exists and is visible
+ isVisible: function(element)
+ {
+ return element && element.style.display!="none";
+ },
+
+ // Encode newline characters
+ encodeNewline: function(string)
+ {
+ return string
+ .replace(/[%]/g, "%25")
+ .replace(/[\r]/g, "%0d")
+ .replace(/[\n]/g, "%0a");
+ },
+
+ // Encode HTML special characters
+ encodeHtml: function(string)
+ {
+ return string
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/"/g, """);
+ },
+
+ // Submit form with post method
+ submitForm: function(args, encodeNewline)
+ {
+ var elementForm = document.createElement("form");
+ elementForm.setAttribute("method", "post");
+ for(var key in args)
+ {
+ if(!args.hasOwnProperty(key)) continue;
+ var value = encodeNewline ? this.encodeNewline(args[key]) : args[key];
+ var elementInput = document.createElement("input");
+ elementInput.setAttribute("type", "hidden");
+ elementInput.setAttribute("name", key);
+ elementInput.setAttribute("value", value);
+ elementForm.appendChild(elementInput);
+ }
+ document.body.appendChild(elementForm);
+ elementForm.submit();
+ }
+};
+
+yellow.edit.intervalId = setInterval("yellow.onLoad()", 1);
diff --git a/system/plugins/edit.php b/system/plugins/edit.php
@@ -0,0 +1,1545 @@
+<?php
+// 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 YellowEdit
+{
+ const VERSION = "0.7.1";
+ var $yellow; //access to API
+ var $response; //web response
+ var $users; //user accounts
+ var $merge; //text merge
+
+ // Handle initialisation
+ function onLoad($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->response = new YellowResponse($yellow);
+ $this->users = new YellowUsers($yellow);
+ $this->merge = new YellowMerge($yellow);
+ $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
+ function onStartup($update)
+ {
+ if($update) $this->cleanCommand(array("clean", "all"));
+ }
+
+ // Handle request
+ function onRequest($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($this->checkRequest($location))
+ {
+ $scheme = $this->yellow->config->get("serverScheme");
+ $address = $this->yellow->config->get("serverAddress");
+ $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);
+ }
+ return $statusCode;
+ }
+
+ // Handle page meta data parsing
+ function onParseMeta($page)
+ {
+ if($page==$this->yellow->page && $this->response->isActive())
+ {
+ if($this->response->isUser())
+ {
+ if(empty($this->response->rawDataSource)) $this->response->rawDataSource = $page->rawData;
+ if(empty($this->response->rawDataEdit)) $this->response->rawDataEdit = $page->rawData;
+ if($page->statusCode==424) $this->response->rawDataEdit = $this->response->getRawDataNew($page->location);
+ }
+ if(empty($this->response->language)) $this->response->language = $page->get("language");
+ if(empty($this->response->action)) $this->response->action = $this->response->isUser() ? "none" : "login";
+ if(empty($this->response->status)) $this->response->status = "none";
+ if($this->response->status=="error") $this->response->action = "error";
+ }
+ }
+
+ // Handle page content parsing of custom block
+ function onParseContentBlock($page, $name, $text, $shortcut)
+ {
+ $output = null;
+ if($name=="edit" && $shortcut)
+ {
+ $editText = "$name $text";
+ if(substru($text, 0, 2)=="- ") $editText = trim(substru($text, 2));
+ $output = "<a href=\"".$page->get("pageEdit")."\">".htmlspecialchars($editText)."</a>";
+ }
+ return $output;
+ }
+
+ // Handle page extra HTML data
+ function onExtra($name)
+ {
+ $output = null;
+ 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}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";
+ $output .= "yellow.config = ".json_encode($this->response->getConfigData()).";\n";
+ $output .= "yellow.text = ".json_encode($this->response->getTextData()).";\n";
+ $output .= "// ]]>\n";
+ $output .= "</script>\n";
+ }
+ return $output;
+ }
+
+ // Handle command
+ function onCommand($args)
+ {
+ list($command) = $args;
+ switch($command)
+ {
+ case "clean": $statusCode = $this->cleanCommand($args); break;
+ case "user": $statusCode = $this->userCommand($args); break;
+ default: $statusCode = 0;
+ }
+ return $statusCode;
+ }
+
+ // Handle command help
+ function onCommandHelp()
+ {
+ return "user [EMAIL PASSWORD NAME LANGUAGE]\n";
+ }
+
+ // Clean user accounts
+ function cleanCommand($args)
+ {
+ $statusCode = 0;
+ list($command, $path) = $args;
+ if($path=="all")
+ {
+ $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";
+ }
+ return $statusCode;
+ }
+
+ // Update user account
+ function userCommand($args)
+ {
+ $statusCode = 0;
+ list($command, $email, $password, $name, $language) = $args;
+ if(!empty($email) && !empty($password))
+ {
+ $userExisting = $this->users->isExisting($email);
+ $status = $this->getUserAccount($email, $password, $command);
+ switch($status)
+ {
+ case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break;
+ case "weak": echo "ERROR updating configuration: Please enter a different password!\n"; break;
+ }
+ if($status=="ok")
+ {
+ $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("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";
+ }
+ $statusCode = $status=="ok" ? 200 : 500;
+ echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "");
+ echo ($userExisting ? "updated" : "created")."\n";
+ } else {
+ $statusCode = 200;
+ foreach($this->users->getData() as $line) echo "$line\n";
+ if(!$this->users->getNumber()) echo "Yellow $command: No user accounts\n";
+ }
+ return $statusCode;
+ }
+
+ // Process request
+ function processRequest($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($this->checkUser($scheme, $address, $base, $location, $fileName))
+ {
+ switch($_REQUEST["action"])
+ {
+ case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
+ case "login": $statusCode = $this->processRequestLogin($scheme, $address, $base, $location, $fileName); break;
+ case "logout": $statusCode = $this->processRequestLogout($scheme, $address, $base, $location, $fileName); break;
+ case "signup": $statusCode = $this->processRequestSignup($scheme, $address, $base, $location, $fileName); break;
+ case "confirm": $statusCode = $this->processRequestConfirm($scheme, $address, $base, $location, $fileName); break;
+ case "approve": $statusCode = $this->processRequestApprove($scheme, $address, $base, $location, $fileName); break;
+ case "recover": $statusCode = $this->processRequestRecover($scheme, $address, $base, $location, $fileName); break;
+ case "settings": $statusCode = $this->processRequestSettings($scheme, $address, $base, $location, $fileName); break;
+ case "reconfirm": $statusCode = $this->processRequestReconfirm($scheme, $address, $base, $location, $fileName); break;
+ case "change": $statusCode = $this->processRequestChange($scheme, $address, $base, $location, $fileName); break;
+ case "version": $statusCode = $this->processRequestVersion($scheme, $address, $base, $location, $fileName); break;
+ case "update": $statusCode = $this->processRequestUpdate($scheme, $address, $base, $location, $fileName); break;
+ case "create": $statusCode = $this->processRequestCreate($scheme, $address, $base, $location, $fileName); break;
+ case "edit": $statusCode = $this->processRequestEdit($scheme, $address, $base, $location, $fileName); break;
+ case "delete": $statusCode = $this->processRequestDelete($scheme, $address, $base, $location, $fileName); break;
+ }
+ } else {
+ $this->yellow->lookup->requestHandler = "core";
+ switch($_REQUEST["action"])
+ {
+ case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
+ case "signup": $statusCode = $this->processRequestSignup($scheme, $address, $base, $location, $fileName); break;
+ case "confirm": $statusCode = $this->processRequestConfirm($scheme, $address, $base, $location, $fileName); break;
+ case "approve": $statusCode = $this->processRequestApprove($scheme, $address, $base, $location, $fileName); break;
+ case "recover": $statusCode = $this->processRequestRecover($scheme, $address, $base, $location, $fileName); break;
+ 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, <a href=\"javascript:yellow.action('login');\">please log in</a>!");
+ }
+ return $statusCode;
+ }
+
+ // Process request to show file
+ function processRequestShow($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if(is_readable($fileName))
+ {
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ } else {
+ if($this->yellow->lookup->isRedirectLocation($location))
+ {
+ $statusCode = 301;
+ $location = $this->yellow->lookup->isFileLocation($location) ? "$location/" : "/".$this->yellow->getRequestLanguage()."/";
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+ $this->yellow->sendStatus($statusCode, $location);
+ } else {
+ $statusCode = $this->response->isUserRestrictions() ? 404 : 424;
+ $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ $this->yellow->page->error($statusCode);
+ }
+ }
+ return $statusCode;
+ }
+
+ // Process request for user login
+ function processRequestLogin($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ $home = $this->users->getHome($this->response->userEmail);
+ if(substru($location, 0, strlenu($home))==$home)
+ {
+ $statusCode = 303;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+ $this->yellow->sendStatus($statusCode, $location);
+ } else {
+ $statusCode = 302;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $home);
+ $this->yellow->sendStatus($statusCode, $location);
+ }
+ return $statusCode;
+ }
+
+ // Process request for user logout
+ function processRequestLogout($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 302;
+ $this->response->userEmail = "";
+ $this->response->destroyCookie($scheme, $address, $base);
+ $location = $this->yellow->lookup->normaliseUrl(
+ $this->yellow->config->get("serverScheme"),
+ $this->yellow->config->get("serverAddress"),
+ $this->yellow->config->get("serverBase"), $location);
+ $this->yellow->sendStatus($statusCode, $location);
+ return $statusCode;
+ }
+
+ // Process request for user signup
+ function processRequestSignup($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "signup";
+ $this->response->status = "ok";
+ $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
+ $email = trim($_REQUEST["email"]);
+ $password = trim($_REQUEST["password"]);
+ if(empty($name) || empty($email) || empty($password)) $this->response->status = "incomplete";
+ if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
+ if($this->response->status=="ok" && $this->response->isLoginRestrictions()) $this->response->status = "next";
+ 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("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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "confirm") ? "next" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to confirm user signup
+ function processRequestConfirm($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "confirm";
+ $this->response->status = "ok";
+ $email = $_REQUEST["email"];
+ $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("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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "approve") ? "done" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to approve user signup
+ function processRequestApprove($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "approve";
+ $this->response->status = "ok";
+ $email = $_REQUEST["email"];
+ $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("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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "welcome") ? "done" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to recover password
+ function processRequestRecover($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "recover";
+ $this->response->status = "ok";
+ $email = trim($_REQUEST["email"]);
+ $password = trim($_REQUEST["password"]);
+ if(empty($_REQUEST["id"]))
+ {
+ if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $this->response->status = "invalid";
+ if($this->response->status=="ok" && !$this->users->isExisting($email)) $this->response->status = "next";
+ if($this->response->status=="ok")
+ {
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "recover") ? "next" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ } else {
+ $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
+ if($this->response->status=="ok")
+ {
+ if(empty($password)) $this->response->status = "password";
+ 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("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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->userEmail = "";
+ $this->response->destroyCookie($scheme, $address, $base);
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ }
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to change settings
+ function processRequestSettings($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "settings";
+ $this->response->status = "ok";
+ $email = trim($_REQUEST["email"]);
+ $emailSource = $this->response->userEmail;
+ $password = trim($_REQUEST["password"]);
+ $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
+ $language = trim($_REQUEST["language"]);
+ if($email!=$emailSource || !empty($password))
+ {
+ if(empty($email)) $this->response->status = "invalid";
+ if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
+ if($this->response->status=="ok" && $email!=$emailSource && $this->users->isTaken($email)) $this->response->status = "taken";
+ if($this->response->status=="ok" && $email!=$emailSource)
+ {
+ $pending = $emailSource;
+ $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("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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $action = $email!=$emailSource ? "reconfirm" : "change";
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, $action) ? "next" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ } else {
+ if($this->response->status=="ok")
+ {
+ $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'!");
+ }
+ }
+ if($this->response->status=="done")
+ {
+ $statusCode = 303;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+ $this->yellow->sendStatus($statusCode, $location);
+ } else {
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ }
+ return $statusCode;
+ }
+
+ // Process request to reconfirm email
+ function processRequestReconfirm($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "reconfirm";
+ $this->response->status = "ok";
+ $email = $emailSource = $_REQUEST["email"];
+ $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
+ if($this->response->status=="ok")
+ {
+ $emailSource = $this->users->getPending($email);
+ if($this->users->getStatus($emailSource)!="active") $this->response->status = "done";
+ }
+ if($this->response->status=="ok")
+ {
+ $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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $emailSource, "change") ? "done" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to change settings
+ function processRequestChange($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "change";
+ $this->response->status = "ok";
+ $email = $emailSource = trim($_REQUEST["email"]);
+ $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
+ if($this->response->status=="ok")
+ {
+ list($email, $hash) = explode(':', $this->users->getPending($email), 2);
+ if(!$this->users->isExisting($email) || empty($hash)) $this->response->status = "done";
+ }
+ if($this->response->status=="ok" && $email!=$emailSource)
+ {
+ $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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->users->users[$email]["hash"] = $hash;
+ $this->users->users[$email]["pending"] = "none";
+ $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'!");
+ }
+ if($this->response->status=="ok")
+ {
+ $this->response->userEmail = "";
+ $this->response->destroyCookie($scheme, $address, $base);
+ $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
+ if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to show software version
+ function processRequestVersion($scheme, $address, $base, $location, $fileName)
+ {
+ $this->response->action = "version";
+ $this->response->status = "ok";
+ if($this->yellow->plugins->isExisting("update"))
+ {
+ list($statusCodeCurrent, $dataCurrent) = $this->yellow->plugins->get("update")->getSoftwareVersion();
+ list($statusCodeLatest, $dataLatest) = $this->yellow->plugins->get("update")->getSoftwareVersion(true);
+ list($statusCodeModified, $dataModified) = $this->yellow->plugins->get("update")->getSoftwareModified();
+ $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeModified);
+ if($this->response->isUserWebmaster())
+ {
+ foreach($dataCurrent as $key=>$value)
+ {
+ if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0)
+ {
+ ++$updates;
+ if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "<br />\n";
+ $this->response->rawDataOutput .= htmlspecialchars("$key $dataLatest[$key]");
+ }
+ }
+ if($updates==0)
+ {
+ foreach($dataCurrent as $key=>$value)
+ {
+ if(!is_null($dataModified[$key]) && !is_null($dataLatest[$key]))
+ {
+ $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;
+ }
+ }
+ }
+ } else {
+ foreach($dataCurrent as $key=>$value)
+ {
+ if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0) ++$updates;
+ }
+ }
+ $this->response->status = $updates ? "updates" : "done";
+ if($statusCode!=200) $this->response->status = "error";
+ }
+ $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ return $statusCode;
+ }
+
+ // Process request to update website
+ function processRequestUpdate($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($this->yellow->plugins->isExisting("update") && $this->response->isUserWebmaster())
+ {
+ $option = trim($_REQUEST["option"]);
+ $feature = trim($_REQUEST["feature"]);
+ $statusCode = $this->yellow->command("update", $option, $feature);
+ if($statusCode==200)
+ {
+ $statusCode = 303;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
+ $this->yellow->sendStatus($statusCode, $location);
+ }
+ }
+ return $statusCode;
+ }
+
+ // Process request to create page
+ function processRequestCreate($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if(!$this->response->isUserRestrictions() && !empty($_POST["rawdataedit"]))
+ {
+ $this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
+ $rawData = rawurldecode($_POST["rawdataedit"]);
+ $page = $this->response->getPageNew($scheme, $address, $base, $location, $fileName, $rawData);
+ if(!$page->isError())
+ {
+ if($this->yellow->toolbox->createFile($page->fileName, $page->rawData, true))
+ {
+ $statusCode = 303;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->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 write file '$page->fileName'!");
+ }
+ } else {
+ $statusCode = 500;
+ $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ $this->yellow->page->error($statusCode, $page->get("pageError"));
+ }
+ }
+ return $statusCode;
+ }
+
+ // Process request to edit page
+ function processRequestEdit($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if(!$this->response->isUserRestrictions() && !empty($_POST["rawdataedit"]))
+ {
+ $this->response->rawDataSource = rawurldecode($_POST["rawdatasource"]);
+ $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, true) &&
+ $this->yellow->toolbox->createFile($page->fileName, $page->rawData))
+ {
+ $statusCode = 303;
+ $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->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 write file '$page->fileName'!");
+ }
+ } else {
+ $statusCode = 500;
+ $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ $this->yellow->page->error($statusCode, $page->get("pageError"));
+ }
+ }
+ return $statusCode;
+ }
+
+ // Process request to delete page
+ function processRequestDelete($scheme, $address, $base, $location, $fileName)
+ {
+ $statusCode = 0;
+ if(!$this->response->isUserRestrictions() && is_file($fileName))
+ {
+ $this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
+ $page = $this->response->getPageDelete($scheme, $address, $base, $location, $fileName, $this->response->rawDataSource);
+ if(!$page->isError())
+ {
+ if($this->yellow->lookup->isFileLocation($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 {
+ 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 {
+ $statusCode = 500;
+ $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
+ $this->yellow->page->error($statusCode, $page->get("pageError"));
+ }
+ }
+ return $statusCode;
+ }
+
+ // Check request
+ function checkRequest($location)
+ {
+ $locationLength = strlenu($this->yellow->config->get("editLocation"));
+ $this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("editLocation");
+ return $this->response->isActive();
+ }
+
+ // Check user
+ function checkUser($scheme, $address, $base, $location, $fileName)
+ {
+ if($_POST["action"]=="login")
+ {
+ $email = $_POST["email"];
+ $password = $_POST["password"];
+ if($this->users->checkUser($email, $password))
+ {
+ $this->response->createCookie($scheme, $address, $base, $email);
+ $this->response->userEmail = $email;
+ $this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
+ $this->response->language = $this->getUserLanguage($email);
+ } else {
+ $this->response->action = "fail";
+ }
+ } else if(isset($_COOKIE["login"])) {
+ list($email, $session) = explode(',', $_COOKIE["login"], 2);
+ if($this->users->checkCookie($email, $session))
+ {
+ $this->response->userEmail = $email;
+ $this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
+ $this->response->language = $this->getUserLanguage($email);
+ } else {
+ $this->response->action = "fail";
+ }
+ }
+ return $this->response->isUser();
+ }
+
+ // Return user account changes
+ function getUserAccount($email, $password, $action)
+ {
+ $status = null;
+ foreach($this->yellow->plugins->plugins as $key=>$value)
+ {
+ if(method_exists($value["obj"], "onEditUserAccount"))
+ {
+ $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("editUserPasswordMinLength")) $status = "weak";
+ if(!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) $status = "invalid";
+ }
+ return $status;
+ }
+
+ // Return user restrictions
+ function getUserRestrictions($email, $location, $fileName)
+ {
+ $userRestrictions = null;
+ foreach($this->yellow->plugins->plugins as $key=>$value)
+ {
+ if(method_exists($value["obj"], "onEditUserRestrictions"))
+ {
+ $userRestrictions = $value["obj"]->onEditUserRestrictions($email, $location, $fileName, $this->users);
+ if(!is_null($userRestrictions)) break;
+ }
+ }
+ if(is_null($userRestrictions))
+ {
+ $userRestrictions = substru($location, 0, strlenu($this->users->getHome($email)))!=$this->users->getHome($email);
+ $userRestrictions |= empty($fileName) || strlenu(dirname($fileName))>128 || strlenu(basename($fileName))>128;
+ }
+ 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 $plugin; //access to plugin
+ var $userEmail; //user email
+ var $userRestrictions; //user can change page? (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
+ var $language; //response language
+ var $action; //response action
+ var $status; //response status
+
+ function __construct($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->plugin = $yellow->plugins->get("edit");
+ }
+
+ // Return new page
+ function getPageNew($scheme, $address, $base, $location, $fileName, $rawData)
+ {
+ $page = new YellowPage($this->yellow);
+ $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
+ $page->parseData($rawData, false, 0);
+ $this->editContentFile($page, "create");
+ if($this->yellow->lookup->isFileLocation($location) || $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))
+ {
+ $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($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
+ {
+ $page->error(500, "Page '".$page->get("title")."' is restricted!");
+ }
+ return $page;
+ }
+
+ // Return modified page
+ 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->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);
+ if(substrb($pageSource->rawData, 0, $pageSource->metaDataOffsetBytes) !=
+ substrb($page->rawData, 0, $page->metaDataOffsetBytes))
+ {
+ $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) || empty($page->fileName))
+ {
+ $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->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
+ {
+ $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;
+ }
+
+ // Return page data including login information
+ function getPageData()
+ {
+ $data = array();
+ if($this->isUser())
+ {
+ $data["title"] = $this->yellow->toolbox->getMetaData($this->rawDataEdit, "title");
+ $data["rawDataSource"] = $this->rawDataSource;
+ $data["rawDataEdit"] = $this->rawDataEdit;
+ $data["rawDataNew"] = $this->getRawDataNew();
+ $data["rawDataOutput"] = strval($this->rawDataOutput);
+ $data["scheme"] = $this->yellow->page->scheme;
+ $data["address"] = $this->yellow->page->address;
+ $data["base"] = $this->yellow->page->base;
+ $data["location"] = $this->yellow->page->location;
+ $data["parserSafeMode"] = $this->yellow->page->parserSafeMode;
+ }
+ if($this->action!="none") $data = array_merge($data, $this->getRequestData());
+ $data["action"] = $this->action;
+ $data["status"] = $this->status;
+ $data["statusCode"] = $this->yellow->page->statusCode;
+ return $data;
+ }
+
+ // Return configuration data including user information
+ function getConfigData()
+ {
+ $data = $this->yellow->config->getData("", "Location");
+ if($this->isUser())
+ {
+ $data["userEmail"] = $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["userUpdate"] = intval($this->yellow->plugins->isExisting("update"));
+ $data["serverLanguages"] = array();
+ foreach($this->yellow->text->getLanguages() as $language)
+ {
+ $data["serverLanguages"][$language] = $this->yellow->text->getTextHtml("languageDescription", $language);
+ }
+ $data["serverScheme"] = $this->yellow->config->get("serverScheme");
+ $data["serverAddress"] = $this->yellow->config->get("serverAddress");
+ $data["serverBase"] = $this->yellow->config->get("serverBase");
+ $data["serverVersion"] = "Datenstrom Yellow ".YellowCore::VERSION;
+ } else {
+ $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;
+ }
+
+ // Return request strings
+ function getRequestData()
+ {
+ $data = array();
+ foreach($_REQUEST as $key=>$value)
+ {
+ if($key=="login" || $key=="password") continue;
+ $data["request".ucfirst($key)] = trim($value);
+ }
+ return $data;
+ }
+
+ // Return text strings
+ function getTextData()
+ {
+ $textLanguage = $this->yellow->text->getData("language", $this->language);
+ $textEdit = $this->yellow->text->getData("edit", $this->language);
+ $textYellow = $this->yellow->text->getData("yellow", $this->language);
+ return array_merge($textLanguage, $textEdit, $textYellow);
+ }
+
+ // Return raw data for new page
+ function getRawDataNew($location = "")
+ {
+ 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->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))
+ {
+ $rawData = $this->yellow->toolbox->setMetaData($rawData, "title", $this->yellow->toolbox->createTextTitle($location));
+ }
+ return $rawData;
+ }
+
+ // Return location for new/modified page
+ function getLocationNew($rawData, $pageLocation, $pageNewLocation)
+ {
+ $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))
+ {
+ $location = $this->yellow->lookup->getDirectoryLocation($pageLocation).$location;
+ }
+ return $location;
+ }
+
+ // Return location data for new/modified page
+ function getLocationDataNew($rawData, $key, $filterFirst = false, $dateFormat = "")
+ {
+ $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), "-");
+ }
+
+ // Return title for next page
+ function getTitleNext($rawData)
+ {
+ preg_match("/^(.*?)(\d*)$/", $this->yellow->toolbox->getMetaData($rawData, "title"), $matches);
+ $titleText = $matches[1];
+ $titleNumber = strempty($matches[2]) ? " 2" : $matches[2]+1;
+ return $titleText.$titleNumber;
+ }
+
+ // Create browser cookie
+ function createCookie($scheme, $address, $base, $email)
+ {
+ $session = $this->plugin->users->createSession($email);
+ setcookie("login", "$email,$session", time()+60*60*24*365, "$base/", "", $scheme=="https");
+ }
+
+ // Destroy browser cookie
+ function destroyCookie($scheme, $address, $base)
+ {
+ 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)
+ {
+ if($action=="welcome" || $action=="information")
+ {
+ $url = "$scheme://$address$base/";
+ } else {
+ $expire = time()+60*60*24;
+ $id = $this->plugin->users->createRequestId($email, $action, $expire);
+ $url = "$scheme://$address$base"."/action:$action/email:$email/expire:$expire/id:$id/";
+ }
+ if($action=="approve")
+ {
+ $account = $email;
+ $name = $this->yellow->config->get("author");
+ $email = $this->yellow->config->get("email");
+ } else {
+ $account = $email;
+ $name = $this->plugin->users->getName($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 = "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);
+ $message = preg_replace("/@username/i", $name, $message);
+ $message = preg_replace("/@userlanguage/i", $language, $message);
+ $mailTo = mb_encode_mimeheader("$name")." <$email>";
+ $mailSubject = mb_encode_mimeheader($this->yellow->text->getText("{$prefix}Subject", $language));
+ $mailHeaders = mb_encode_mimeheader("From: $sitename")." <noreply>\r\n";
+ $mailHeaders .= mb_encode_mimeheader("X-Request-Url: $scheme://$address$base")."\r\n";
+ $mailHeaders .= mb_encode_mimeheader("X-Remote-Addr: $_SERVER[REMOTE_ADDR]")."\r\n";
+ $mailHeaders .= "Mime-Version: 1.0\r\n";
+ $mailHeaders .= "Content-Type: text/plain; charset=utf-8\r\n";
+ $mailMessage = "$message\r\n\r\n$url\r\n-- \r\n$sitename";
+ return mail($mailTo, $mailSubject, $mailMessage, $mailHeaders);
+ }
+
+ // Check if active
+ function isActive()
+ {
+ return $this->active;
+ }
+
+ // Check if user is logged in
+ function isUser()
+ {
+ return !empty($this->userEmail);
+ }
+
+ // Check if user has restrictions
+ function isUserRestrictions()
+ {
+ return empty($this->userEmail) || $this->userRestrictions;
+ }
+
+ // Check if user is webmaster
+ function isUserWebmaster()
+ {
+ 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
+{
+ var $yellow; //access to API
+ var $users; //registered users
+
+ function __construct($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->users = array();
+ }
+
+ // Load users from file
+ function load($fileName)
+ {
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowUsers::load file:$fileName<br/>\n";
+ $fileData = $this->yellow->toolbox->readFile($fileName);
+ foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
+ {
+ if(preg_match("/^\#/", $line)) continue;
+ preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+ if(!empty($matches[1]) && !empty($matches[2]))
+ {
+ list($hash, $name, $language, $status, $modified, $pending, $home) = explode(',', $matches[2]);
+ $this->set($matches[1], $hash, $name, $language, $status, $modified, $pending, $home);
+ if(defined("DEBUG") && DEBUG>=3) echo "YellowUsers::load email:$matches[1]<br/>\n";
+ }
+ }
+ }
+
+ // Clean users in file
+ function clean($fileName)
+ {
+ $fileData = $this->yellow->toolbox->readFile($fileName);
+ foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
+ {
+ preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+ if(!empty($matches[1]) && !empty($matches[2]))
+ {
+ list($hash, $name, $language, $status, $modified, $pending, $home) = explode(',', $matches[2]);
+ if($status=="active" || $status=="inactive")
+ {
+ $pending = "none";
+ $fileDataNew .= "$matches[1]: $hash,$name,$language,$status,$modified,$pending,$home\n";
+ }
+ } else {
+ $fileDataNew .= $line;
+ }
+ }
+ return $this->yellow->toolbox->createFile($fileName, $fileDataNew);
+ }
+
+ // Update users in file
+ function update($fileName, $email, $password = "", $name = "", $language = "", $status = "", $modified = "", $pending = "", $home = "")
+ {
+ if(!empty($password)) $hash = $this->createHash($password);
+ if($this->isExisting($email))
+ {
+ $email = strreplaceu(',', '-', $email);
+ $hash = strreplaceu(',', '-', empty($hash) ? $this->users[$email]["hash"] : $hash);
+ $name = strreplaceu(',', '-', empty($name) ? $this->users[$email]["name"] : $name);
+ $language = strreplaceu(',', '-', empty($language) ? $this->users[$email]["language"] : $language);
+ $status = strreplaceu(',', '-', empty($status) ? $this->users[$email]["status"] : $status);
+ $modified = strreplaceu(',', '-', empty($modified) ? time() : $modified);
+ $pending = strreplaceu(',', '-', empty($pending) ? $this->users[$email]["pending"] : $pending);
+ $home = strreplaceu(',', '-', empty($home) ? $this->users[$email]["home"] : $home);
+ } else {
+ $email = strreplaceu(',', '-', empty($email) ? "none" : $email);
+ $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("editUserStatus") : $status);
+ $modified = strreplaceu(',', '-', empty($modified) ? time() : $modified);
+ $pending = strreplaceu(',', '-', empty($pending) ? "none" : $pending);
+ $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);
+ foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
+ {
+ preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+ if(!empty($matches[1]) && $matches[1]==$email)
+ {
+ $fileDataNew .= "$email: $hash,$name,$language,$status,$modified,$pending,$home\n";
+ $found = true;
+ } else {
+ $fileDataNew .= $line;
+ }
+ }
+ if(!$found) $fileDataNew .= "$email: $hash,$name,$language,$status,$modified,$pending,$home\n";
+ return $this->yellow->toolbox->createFile($fileName, $fileDataNew);
+ }
+
+ // Set user data
+ function set($email, $hash, $name, $language, $status, $modified, $pending, $home)
+ {
+ $this->users[$email] = array();
+ $this->users[$email]["email"] = $email;
+ $this->users[$email]["hash"] = $hash;
+ $this->users[$email]["name"] = $name;
+ $this->users[$email]["language"] = $language;
+ $this->users[$email]["status"] = $status;
+ $this->users[$email]["modified"] = $modified;
+ $this->users[$email]["pending"] = $pending;
+ $this->users[$email]["home"] = $home;
+ }
+
+ // Check user login from email and password
+ function checkUser($email, $password)
+ {
+ $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"]);
+ }
+
+ // Check user login from email and session
+ function checkCookie($email, $session)
+ {
+ return $this->isExisting($email) && $this->users[$email]["status"]=="active" &&
+ $this->yellow->toolbox->verifyHash($this->users[$email]["hash"], "sha256", $session);
+ }
+
+ // Create session
+ function createSession($email)
+ {
+ if($this->isExisting($email))
+ {
+ $session = $this->yellow->toolbox->createHash($this->users[$email]["hash"], "sha256");
+ if(empty($session)) $session = "error-hash-algorithm-sha256";
+ }
+ return $session;
+ }
+
+ // Create password hash
+ function createHash($password)
+ {
+ $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;
+ }
+
+ // Create request ID for action
+ function createRequestId($email, $action, $expire)
+ {
+ return $this->yellow->toolbox->createHash($this->users[$email]["hash"].$action.$expire, "sha256");
+ }
+
+ // Return response status for action
+ function getResponseStatus($email, $action, $expire, $id)
+ {
+ $status = "done";
+ switch($action)
+ {
+ case "confirm": $statusExpected = "unconfirmed"; break;
+ case "reconfirm": $statusExpected = "unconfirmed"; break;
+ case "approve": $statusExpected = "unapproved"; break;
+ default: $statusExpected = "active"; break;
+ }
+ if($this->isExisting($email) && $this->users[$email]["status"]==$statusExpected &&
+ $this->yellow->toolbox->verifyHash($this->users[$email]["hash"].$action.$expire, "sha256", $id))
+ {
+ $status = "ok";
+ }
+ if($expire<=time()) $status = "expired";
+ return $status;
+ }
+
+ // Return user hash
+ function getHash($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["hash"] : "";
+ }
+
+ // Return user name
+ function getName($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["name"] : "";
+ }
+
+ // Return user language
+ function getLanguage($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["language"] : "";
+ }
+
+ // Return user status
+ function getStatus($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["status"] : "";
+ }
+
+ // Return user modified
+ function getModified($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["modified"] : "";
+ }
+
+ // Return user pending
+ function getPending($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["pending"] : "";
+ }
+
+ // Return user home
+ function getHome($email = "")
+ {
+ return $this->isExisting($email) ? $this->users[$email]["home"] : "";
+ }
+
+ // Return number of users
+ function getNumber()
+ {
+ return count($this->users);
+ }
+
+ // Return user data
+ function getData()
+ {
+ $data = array();
+ foreach($this->users as $key=>$value)
+ {
+ $name = $value["name"]; if(preg_match("/\s/", $name)) $name = "\"$name\"";
+ $language = $value["language"]; if(preg_match("/\s/", $language)) $language = "\"$language\"";
+ $status = $value["status"]; if(preg_match("/\s/", $status)) $status = "\"$status\"";
+ $data[$key] = "$value[email] - $name $language $status";
+ if($value["home"]!="/") $data[$key] .= " restrictions";
+ }
+ uksort($data, strnatcasecmp);
+ return $data;
+ }
+
+ // Check if user is taken
+ function isTaken($email)
+ {
+ $taken = false;
+ if($this->isExisting($email))
+ {
+ $status = $this->users[$email]["status"];
+ $reserved = $this->users[$email]["modified"] + 60*60*24;
+ if($status=="active" || $status=="inactive" || $reserved>time()) $taken = true;
+ }
+ return $taken;
+ }
+
+ // Check if user exists
+ function isExisting($email)
+ {
+ return !is_null($this->users[$email]);
+ }
+}
+
+class YellowMerge
+{
+ var $yellow; //access to API
+ const ADD = '+'; //merge types
+ const MODIFY = '*';
+ const REMOVE = '-';
+ const SAME = ' ';
+
+ function __construct($yellow)
+ {
+ $this->yellow = $yellow;
+ }
+
+ // Merge text, null if not possible
+ function merge($textSource, $textMine, $textYours, $showDiff = false)
+ {
+ if($textMine!=$textYours)
+ {
+ $diffMine = $this->buildDiff($textSource, $textMine);
+ $diffYours = $this->buildDiff($textSource, $textYours);
+ $diff = $this->mergeDiff($diffMine, $diffYours);
+ $output = $this->getOutput($diff, $showDiff);
+ } else {
+ $output = $textMine;
+ }
+ return $output;
+ }
+
+ // Build differences to common source
+ function buildDiff($textSource, $textOther)
+ {
+ $diff = array();
+ $lastRemove = -1;
+ $textStart = 0;
+ $textSource = $this->yellow->toolbox->getTextLines($textSource);
+ $textOther = $this->yellow->toolbox->getTextLines($textOther);
+ $sourceEnd = $sourceSize = count($textSource);
+ $otherEnd = $otherSize = count($textOther);
+ while($textStart<$sourceEnd && $textStart<$otherEnd && $textSource[$textStart]==$textOther[$textStart]) ++$textStart;
+ while($textStart<$sourceEnd && $textStart<$otherEnd && $textSource[$sourceEnd-1]==$textOther[$otherEnd-1])
+ {
+ --$sourceEnd; --$otherEnd;
+ }
+ for($pos=0; $pos<$textStart; ++$pos) array_push($diff, array(YellowMerge::SAME, $textSource[$pos], false));
+ $lcs = $this->buildDiffLCS($textSource, $textOther, $textStart, $sourceEnd-$textStart, $otherEnd-$textStart);
+ for($x=0,$y=0,$xEnd=$otherEnd-$textStart,$yEnd=$sourceEnd-$textStart; $x<$xEnd || $y<$yEnd;)
+ {
+ $max = $lcs[$y][$x];
+ if($y<$yEnd && $lcs[$y+1][$x]==$max)
+ {
+ array_push($diff, array(YellowMerge::REMOVE, $textSource[$textStart+$y], false));
+ if($lastRemove==-1) $lastRemove = count($diff)-1;
+ ++$y;
+ continue;
+ }
+ if($x<$xEnd && $lcs[$y][$x+1]==$max)
+ {
+ if($lastRemove==-1 || $diff[$lastRemove][0]!=YellowMerge::REMOVE)
+ {
+ array_push($diff, array(YellowMerge::ADD, $textOther[$textStart+$x], false));
+ $lastRemove = -1;
+ } else {
+ $diff[$lastRemove] = array(YellowMerge::MODIFY, $textOther[$textStart+$x], false);
+ ++$lastRemove; if(count($diff)==$lastRemove) $lastRemove = -1;
+ }
+ ++$x;
+ continue;
+ }
+ array_push($diff, array(YellowMerge::SAME, $textSource[$textStart+$y], false));
+ $lastRemove = -1;
+ ++$x;
+ ++$y;
+ }
+ for($pos=$sourceEnd;$pos<$sourceSize; ++$pos) array_push($diff, array(YellowMerge::SAME, $textSource[$pos], false));
+ return $diff;
+ }
+
+ // Build longest common subsequence
+ function buildDiffLCS($textSource, $textOther, $textStart, $yEnd, $xEnd)
+ {
+ $lcs = array_fill(0, $yEnd+1, array_fill(0, $xEnd+1, 0));
+ for($y=$yEnd-1; $y>=0; --$y)
+ {
+ for($x=$xEnd-1; $x>=0; --$x)
+ {
+ if($textSource[$textStart+$y]==$textOther[$textStart+$x])
+ {
+ $lcs[$y][$x] = $lcs[$y+1][$x+1]+1;
+ } else {
+ $lcs[$y][$x] = max($lcs[$y][$x+1], $lcs[$y+1][$x]);
+ }
+ }
+ }
+ return $lcs;
+ }
+
+ // Merge differences
+ function mergeDiff($diffMine, $diffYours)
+ {
+ $diff = array();
+ $posMine = $posYours = 0;
+ while($posMine<count($diffMine) && $posYours<count($diffYours))
+ {
+ $typeMine = $diffMine[$posMine][0];
+ $typeYours = $diffYours[$posYours][0];
+ if($typeMine==YellowMerge::SAME)
+ {
+ array_push($diff, $diffYours[$posYours]);
+ } else if($typeYours==YellowMerge::SAME) {
+ array_push($diff, $diffMine[$posMine]);
+ } else if($typeMine==YellowMerge::ADD && $typeYours==YellowMerge::ADD) {
+ $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], false);
+ } else if($typeMine==YellowMerge::MODIFY && $typeYours==YellowMerge::MODIFY) {
+ $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], false);
+ } else if($typeMine==YellowMerge::REMOVE && $typeYours==YellowMerge::REMOVE) {
+ array_push($diff, $diffMine[$posMine]);
+ } else if($typeMine==YellowMerge::ADD) {
+ array_push($diff, $diffMine[$posMine]);
+ } else if($typeYours==YellowMerge::ADD) {
+ array_push($diff, $diffYours[$posYours]);
+ } else {
+ $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], true);
+ }
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
+ if($typeMine==YellowMerge::ADD || $typeYours==YellowMerge::ADD)
+ {
+ if($typeMine==YellowMerge::ADD) ++$posMine;
+ if($typeYours==YellowMerge::ADD) ++$posYours;
+ } else {
+ ++$posMine;
+ ++$posYours;
+ }
+ }
+ for(;$posMine<count($diffMine); ++$posMine)
+ {
+ array_push($diff, $diffMine[$posMine]);
+ $typeMine = $diffMine[$posMine][0]; $typeYours = ' ';
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
+ }
+ for(;$posYours<count($diffYours); ++$posYours)
+ {
+ array_push($diff, $diffYours[$posYours]);
+ $typeYours = $diffYours[$posYours][0]; $typeMine = ' ';
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
+ }
+ return $diff;
+ }
+
+ // Merge potential conflict
+ function mergeConflict(&$diff, $diffMine, $diffYours, $conflict)
+ {
+ if(!$conflict && $diffMine[1]==$diffYours[1])
+ {
+ array_push($diff, $diffMine);
+ } else {
+ array_push($diff, array($diffMine[0], $diffMine[1], true));
+ array_push($diff, array($diffYours[0], $diffYours[1], true));
+ }
+ }
+
+ // Return merged text, null if not possible
+ function getOutput($diff, $showDiff = false)
+ {
+ $output = "";
+ if(!$showDiff)
+ {
+ for($i=0; $i<count($diff); ++$i)
+ {
+ if($diff[$i][0]!=YellowMerge::REMOVE) $output .= $diff[$i][1];
+ $conflict |= $diff[$i][2];
+ }
+ } else {
+ for($i=0; $i<count($diff); ++$i)
+ {
+ $output .= $diff[$i][2] ? "! " : $diff[$i][0].' ';
+ $output .= $diff[$i][1];
+ }
+ }
+ return !$conflict ? $output : null;
+ }
+}
+
+$yellow->plugins->register("edit", "YellowEdit", YellowEdit::VERSION);
+?>
diff --git a/system/plugins/language-de.txt b/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
diff --git a/system/plugins/language-en.txt b/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
diff --git a/system/plugins/language-fr.txt b/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
diff --git a/system/plugins/language.php b/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);
diff --git a/system/plugins/update.php b/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";
}
diff --git a/system/plugins/webinterface.css b/system/plugins/webinterface.css
@@ -1,129 +0,0 @@
-/* Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface */
-/* Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se */
-/* This file may be used and distributed under the terms of the public license. */
-
-.yellow-bar { position:relative; overflow:hidden; height:2em; margin-bottom:10px; }
-.yellow-bar-left { display:block; float:left; }
-.yellow-bar-right { display:block; float:right; }
-.yellow-bar-right a { margin-left:1em; }
-.yellow-bar-right #yellow-pane-create-link { padding:0 0.5em; }
-.yellow-bar-right #yellow-pane-delete-link { padding:0 0.5em; }
-.yellow-body-modal-open { overflow:hidden; }
-
-.yellow-pane {
- position:absolute; display:none; z-index:100;
- margin:10px 0; padding:10px;
- background-color:#fff; color:#000;
- border:1px solid #bbb;
- border-radius:4px; box-shadow:2px 4px 10px rgba(0, 0, 0, 0.2);
-}
-.yellow-pane h1 { color:#000; }
-.yellow-pane p { margin:0.5em; }
-.yellow-pane ul { list-style:none; margin:0 0.5em; padding:0; }
-.yellow-pane div { overflow:hidden; }
-.yellow-close { display:block; float:right; padding:0 0.5em; font-size:1.1em; color:#bbb; text-decoration:none; }
-.yellow-close:hover { color:#000; text-decoration:none; }
-.yellow-arrow { position:absolute; top:0; left:0; }
-.yellow-arrow:after, .yellow-arrow:before {
- position:absolute;
- bottom:100%;
- height:0; width:0;
- border:solid transparent;
- content:" ";
-}
-.yellow-arrow:after {
- border-color:rgba(255, 255, 255, 0);
- border-bottom-color:#fff;
- border-width:10px;
- margin-left:-10px;
-}
-.yellow-arrow:before {
- border-color:rgba(187, 187, 187, 0);
- border-bottom-color:#bbb;
- border-width:11px;
- margin-left:-11px;
-}
-
-.yellow-form-control {
- margin:0; padding:2px 4px;
- display:inline-block;
- background-color:#fff; color:#000;
- background-image:linear-gradient(to bottom, #fff, #fff);
- border:1px solid #bbb;
- border-radius:4px;
- font-size:0.9em; font-family:inherit; font-weight:normal; line-height:normal;
-}
-.yellow-btn {
- margin:0; padding:4px 22px;
- display:inline-block; min-width:8em;
- background-color:#eaeaea; color:#333333;
- background-image:linear-gradient(to bottom, #f8f8f8, #e1e1e1);
- border:1px solid #bbb;
- border-color:#c1c1c1 #c1c1c1 #aaaaaa;
- border-radius:4px;
- outline-offset:-2px;
- font-size:0.9em; font-family:inherit; font-weight:normal; line-height:1;
- text-align:center; text-decoration:none;
-}
-.yellow-btn:hover, .yellow-btn:focus, .yellow-btn:active {
- color:#333333;
- background-image:none;
- text-decoration:none;
-}
-.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); }
-.yellow-btn-delete {
- background-color:#c33c35; color:#ffffff;
- background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);
- border-color:#b13121 #b13121 #802020;
-}
-.yellow-btn-delete:hover, .yellow-btn-delete:focus, .yellow-btn-delete:active { color:#ffffff; }
-
-#yellow-pane-login { text-align:center; white-space:nowrap; }
-#yellow-pane-login h1 { margin:0 1em; font-size:2em; }
-#yellow-pane-login .yellow-form-control { width:15em; box-sizing:border-box; }
-#yellow-pane-login .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
-#yellow-pane-login-fields { width:15em; text-align:left; margin:0 auto; }
-#yellow-pane-login-buttons { margin:0.5em 0; }
-#yellow-pane-login-buttons p { margin:0; }
-
-#yellow-pane-signup { text-align:center; white-space:nowrap; }
-#yellow-pane-signup h1 { margin:0 1em; font-size:2em; }
-#yellow-pane-signup .yellow-form-control { width:15em; box-sizing:border-box; }
-#yellow-pane-signup .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
-#yellow-pane-signup-status { margin:0.5em 0; display:inline-block; }
-#yellow-pane-signup-fields { width:15em; text-align:left; margin:0 auto; }
-#yellow-pane-signup-buttons { margin-top:-0.5em; }
-
-#yellow-pane-recover { text-align:center; white-space:nowrap; }
-#yellow-pane-recover h1 { margin:0 1em; font-size:2em; }
-#yellow-pane-recover .yellow-form-control { width:15em; box-sizing:border-box; }
-#yellow-pane-recover .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
-#yellow-pane-recover-status { margin:0.5em 0; display:inline-block; }
-#yellow-pane-recover-fields-first, #yellow-pane-recover-fields-second { width:15em; text-align:left; margin:0 auto; }
-#yellow-pane-recover-buttons { margin-top:-0.5em; }
-
-#yellow-pane-settings { text-align:center; white-space:nowrap; }
-#yellow-pane-settings h1 { margin:0 1em; font-size:2em; }
-#yellow-pane-settings .yellow-form-control { width:15em; box-sizing:border-box; }
-#yellow-pane-settings .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
-#yellow-pane-settings-status { margin:0.5em 0; display:inline-block; }
-#yellow-pane-settings-fields { width:15em; text-align:left; margin:0 auto; }
-#yellow-pane-settings-buttons { margin-top:-0.5em; }
-
-#yellow-pane-version { text-align:center; white-space:nowrap; }
-#yellow-pane-version h1 { margin:0 1em; font-size:2em; }
-#yellow-pane-version .yellow-btn { width:15em; margin:1em 1em 0.5em 0; }
-#yellow-pane-version-status { margin:0.5em 0; display:inline-block; }
-#yellow-pane-version-fields { text-align:center; margin:0.5em 0; }
-#yellow-pane-version-buttons { margin-top:-0.5em; }
-
-#yellow-pane-edit { }
-#yellow-pane-edit h1 { margin:0 0 10px 0; font-size:2em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
-#yellow-pane-edit-page { padding:5px; outline:none; resize:none; }
-#yellow-pane-edit-buttons { margin-top:5px; }
-#yellow-pane-edit-buttons input { margin-right:10px; }
-#yellow-pane-edit-help { float:right; }
-
-#yellow-pane-user { cursor:pointer; }
-#yellow-pane-user a { text-decoration:none; }
-#yellow-pane-user a:hover { text-decoration:underline; }
diff --git a/system/plugins/webinterface.js b/system/plugins/webinterface.js
@@ -1,808 +0,0 @@
-// Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface
-// 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); }
-};
-
-yellow.webinterface =
-{
- paneId: 0, //visible pane ID
- paneAction: 0, //current pane action
- paneStatus: 0, //current pane status
- intervalId: 0, //timer interval ID
-
- // Handle action
- action: function(action, status, args)
- {
- status = status ? status : "none";
- args = args ? args : "none";
- switch(action)
- {
- case "login": this.showPane("yellow-pane-login", action, status); break;
- case "logout": this.sendPane("yellow-pane-logout", action); break;
- case "signup": this.showPane("yellow-pane-signup", action, status); break;
- case "confirm": this.showPane("yellow-pane-signup", action, status); break;
- case "approve": this.showPane("yellow-pane-signup", action, status); break;
- case "recover": this.showPane("yellow-pane-recover", action, status); break;
- case "settings": this.showPane("yellow-pane-settings", action, status); break;
- case "reconfirm": this.showPane("yellow-pane-settings", action, status); break;
- case "change": this.showPane("yellow-pane-settings", action, status); break;
- case "version": this.showPane("yellow-pane-version", action, status); break;
- case "update": this.sendPane("yellow-pane-update", action, status, args); break;
- case "create": this.showPane("yellow-pane-edit", action, status, true); break;
- 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 "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()
- {
- var body = document.getElementsByTagName("body")[0];
- if(body && body.firstChild && !document.getElementById("yellow-bar"))
- {
- this.createBar("yellow-bar");
- this.createPane("yellow-pane-edit", "none", "none");
- this.action(yellow.page.action, yellow.page.status);
- clearInterval(this.intervalId);
- }
- },
-
- // Create bar
- createBar: function(barId)
- {
- if(yellow.config.debug) console.log("yellow.webinterface.createBar id:"+barId);
- var elementBar = document.createElement("div");
- elementBar.className = "yellow-bar";
- elementBar.setAttribute("id", barId);
- if(barId=="yellow-bar")
- {
- yellow.toolbox.addEvent(document, "click", yellow.onClick);
- yellow.toolbox.addEvent(document, "keydown", yellow.onKeydown);
- yellow.toolbox.addEvent(window, "resize", yellow.onResize);
- }
- if(yellow.config.userName)
- {
- elementBar.innerHTML =
- "<div class=\"yellow-bar-left\">"+
- "<a href=\"#\" onclick=\"yellow.action('edit'); return false;\" id=\"yellow-pane-edit-link\">"+this.getText("Edit")+"</a>"+
- "</div>"+
- "<div class=\"yellow-bar-right\">"+
- "<a href=\"#\" onclick=\"yellow.action('create'); return false;\" id=\"yellow-pane-create-link\">"+this.getText("Create")+"</a>"+
- "<a href=\"#\" onclick=\"yellow.action('delete'); return false;\" id=\"yellow-pane-delete-link\">"+this.getText("Delete")+"</a>"+
- "<a href=\"#\" onclick=\"yellow.action('user'); return false;\" id=\"yellow-pane-user-link\">"+yellow.toolbox.encodeHtml(yellow.config.userName)+"</a>"+
- "</div>";
- }
- yellow.toolbox.insertBefore(elementBar, document.getElementsByTagName("body")[0].firstChild);
- return elementBar;
- },
-
- // Create pane
- createPane: function(paneId, paneAction, paneStatus)
- {
- if(yellow.config.debug) console.log("yellow.webinterface.createPane id:"+paneId);
- var elementPane = document.createElement("div");
- elementPane.className = "yellow-pane";
- elementPane.setAttribute("id", paneId);
- elementPane.style.display = "none";
- if(paneId=="yellow-pane-edit")
- {
- yellow.toolbox.addEvent(elementPane, "keyup", yellow.onUpdate);
- yellow.toolbox.addEvent(elementPane, "change", yellow.onUpdate);
- }
- if(paneId=="yellow-pane-edit" || paneId=="yellow-pane-user")
- {
- var elementArrow = document.createElement("span");
- elementArrow.className = "yellow-arrow";
- elementArrow.setAttribute("id", paneId+"-arrow");
- elementPane.appendChild(elementArrow);
- }
- var elementDiv = document.createElement("div");
- elementDiv.setAttribute("id", paneId+"-content");
- switch(paneId)
- {
- case "yellow-pane-login":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<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><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>"+
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-signup":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<h1>"+this.getText("SignupTitle")+"</h1>"+
- "<div id=\"yellow-pane-signup-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
- "<div id=\"yellow-pane-signup-fields\">"+
- "<input type=\"hidden\" name=\"action\" value=\"signup\" />"+
- "<p><label for=\"yellow-pane-signup-name\">"+this.getText("SignupName")+"</label><br /><input class=\"yellow-form-control\" name=\"name\" id=\"yellow-pane-signup-name\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("name"))+"\" /></p>"+
- "<p><label for=\"yellow-pane-signup-email\">"+this.getText("SignupEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-signup-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
- "<p><label for=\"yellow-pane-signup-password\">"+this.getText("SignupPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-signup-password\" maxlength=\"64\" value=\"\" /></p>"+
- "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SignupButton")+"\" /></p>"+
- "</div>"+
- "<div id=\"yellow-pane-signup-buttons\">"+
- "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-recover":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<h1>"+this.getText("RecoverTitle")+"</h1>"+
- "<div id=\"yellow-pane-recover-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
- "<div id=\"yellow-pane-recover-fields-first\">"+
- "<input type=\"hidden\" name=\"action\" value=\"recover\" />"+
- "<p><label for=\"yellow-pane-recover-email\">"+this.getText("RecoverEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-recover-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
- "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "<div id=\"yellow-pane-recover-fields-second\">"+
- "<p><label for=\"yellow-pane-recover-password\">"+this.getText("RecoverPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-recover-password\" maxlength=\"64\" value=\"\" /></p>"+
- "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "<div id=\"yellow-pane-recover-buttons\">"+
- "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-settings":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<h1 id=\"yellow-pane-settings-title\">"+this.getText("SettingsTitle")+"</h1>"+
- "<div id=\"yellow-pane-settings-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
- "<div id=\"yellow-pane-settings-fields\">"+
- "<input type=\"hidden\" name=\"action\" value=\"settings\" />"+
- "<p><label for=\"yellow-pane-settings-name\">"+this.getText("SignupName")+"</label><br /><input class=\"yellow-form-control\" name=\"name\" id=\"yellow-pane-settings-name\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("name"))+"\" /></p>"+
- "<p><label for=\"yellow-pane-settings-email\">"+this.getText("SignupEmail")+"</label><br /><input class=\"yellow-form-control\" name=\"email\" id=\"yellow-pane-settings-email\" maxlength=\"64\" value=\""+yellow.toolbox.encodeHtml(this.getRequest("email"))+"\" /></p>"+
- "<p><label for=\"yellow-pane-settings-password\">"+this.getText("SignupPassword")+"</label><br /><input class=\"yellow-form-control\" type=\"password\" name=\"password\" id=\"yellow-pane-settings-password\" maxlength=\"64\" value=\"\" /></p>"+this.getLanguages(paneId)+
- "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "<div id=\"yellow-pane-settings-buttons\">"+
- "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-version":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<h1 id=\"yellow-pane-version-title\">"+yellow.toolbox.encodeHtml(yellow.config.serverVersion)+"</h1>"+
- "<div id=\"yellow-pane-version-status\" class=\""+paneStatus+"\">"+this.getText("VersionStatus", "", paneStatus)+"</div>"+
- "<div id=\"yellow-pane-version-fields\">"+yellow.page.rawDataOutput+"</div>"+
- "<div id=\"yellow-pane-version-buttons\">"+
- "<p><input class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('close'); return false;\" value=\""+this.getText("OkButton")+"\" /></p>"+
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-edit":
- elementDiv.innerHTML =
- "<form method=\"post\">"+
- "<a href=\"#\" onclick=\"yellow.action('close'); return false;\" class=\"yellow-close\">x</a>"+
- "<h1 id=\"yellow-pane-edit-title\">"+this.getText("Edit")+"</h1>"+
- "<textarea id=\"yellow-pane-edit-page\" class=\"yellow-form-control\" name=\"rawdataedit\"></textarea>"+
- "<div id=\"yellow-pane-edit-buttons\">"+
- "<input id=\"yellow-pane-edit-send\" class=\"yellow-btn\" type=\"button\" onclick=\"yellow.action('send'); return false;\" value=\""+this.getText("EditButton")+"\" />"+
- "<a href=\""+this.getText("MarkdownHelpUrl", "yellow")+"\" target=\"_blank\" id=\"yellow-pane-edit-help\">"+this.getText("MarkdownHelp")+"</a>" +
- "</div>"+
- "</form>";
- break;
- case "yellow-pane-user":
- elementDiv.innerHTML =
- "<p>"+yellow.toolbox.encodeHtml(yellow.config.userEmail)+"</p>"+
- "<p><a href=\"#\" onclick=\"yellow.action('settings'); return false;\">"+this.getText("SettingsTitle")+"</a></p>" +
- "<p><a href=\"#\" onclick=\"yellow.action('help'); return false;\">"+this.getText("UserHelp")+"</a></p>" +
- "<p><a href=\"#\" onclick=\"yellow.action('logout'); return false;\">"+this.getText("UserLogout")+"</a></p>";
- break;
- }
- elementPane.appendChild(elementDiv);
- yellow.toolbox.insertAfter(elementPane, document.getElementsByTagName("body")[0].firstChild);
- return elementPane;
- },
-
- // Update pane
- updatePane: function(paneId, paneAction, paneStatus, init)
- {
- if(yellow.config.debug) console.log("yellow.webinterface.updatePane id:"+paneId);
- var showFields = paneStatus!="next" && paneStatus!="done" && paneStatus!="expired";
- switch(paneId)
- {
- case "yellow-pane-login":
- if(yellow.config.loginRestrictions)
- {
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-buttons"), false);
- }
- break;
- case "yellow-pane-signup":
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-signup-fields"), showFields);
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-signup-buttons"), !showFields);
- break;
- case "yellow-pane-recover":
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-first"), showFields);
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-second"), showFields);
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-buttons"), !showFields);
- if(showFields)
- {
- if(this.getRequest("id"))
- {
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-first"), false);
- } else {
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-recover-fields-second"), false);
- }
- }
- break;
- case "yellow-pane-settings":
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-settings-fields"), showFields);
- yellow.toolbox.setVisible(document.getElementById("yellow-pane-settings-buttons"), !showFields);
- if(paneStatus=="none")
- {
- document.getElementById("yellow-pane-settings-status").innerHTML = "<a href=\"#\" onclick=\"yellow.action('version'); return false;\">"+this.getText("VersionTitle")+"</a>";
- document.getElementById("yellow-pane-settings-name").value = yellow.config.userName;
- document.getElementById("yellow-pane-settings-email").value = yellow.config.userEmail;
- document.getElementById("yellow-pane-settings-"+yellow.config.userLanguage).checked = true;
- }
- break;
- case "yellow-pane-version":
- if(paneStatus=="none" && yellow.config.pluginUpdate)
- {
- document.getElementById("yellow-pane-version-status").innerHTML = this.getText("VersionStatusCheck");
- document.getElementById("yellow-pane-version-fields").innerHTML = "";
- setTimeout("yellow.action('send');", 500);
- }
- if(paneStatus=="updates" && yellow.config.userWebmaster)
- {
- document.getElementById("yellow-pane-version-status").innerHTML = "<a href=\"#\" onclick=\"yellow.action('update'); return false;\">"+this.getText("VersionUpdateNormal")+"</a>";
- }
- break;
- case "yellow-pane-edit":
- if(init)
- {
- var title = yellow.page.title;
- var string = yellow.page.rawDataEdit;
- switch(paneAction)
- {
- case "create": title = this.getText("CreateTitle"); string = yellow.page.rawDataNew; break;
- case "delete": title = this.getText("DeleteTitle"); break;
- }
- document.getElementById("yellow-pane-edit-title").innerHTML = yellow.toolbox.encodeHtml(title);
- document.getElementById("yellow-pane-edit-page").value = string;
- yellow.toolbox.setCursorPosition(document.getElementById("yellow-pane-edit-page"), 0);
- }
- paneAction = this.getPaneAction(paneId, paneAction);
- var key, className, readOnly;
- switch(paneAction)
- {
- case "create": key = "CreateButton"; className = "yellow-btn yellow-btn-create"; readOnly = false; break;
- case "edit": key = "EditButton"; className = "yellow-btn yellow-btn-edit"; readOnly = false; break;
- case "delete": key = "DeleteButton"; className = "yellow-btn yellow-btn-delete"; readOnly = false; break;
- case "": key = "CancelButton"; className = "yellow-btn yellow-btn-cancel"; readOnly = true; break;
- }
- document.getElementById("yellow-pane-edit-send").value = this.getText(key);
- document.getElementById("yellow-pane-edit-send").className = className;
- document.getElementById("yellow-pane-edit-page").readOnly = readOnly;
- break;
- }
- },
-
- // Resize pane
- resizePane: function(paneId, paneAction, paneStatus)
- {
- var elementBar = document.getElementById("yellow-bar");
- var paneLeft = yellow.toolbox.getOuterLeft(elementBar);
- var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar);
- var paneWidth = yellow.toolbox.getOuterWidth(elementBar);
- var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar);
- switch(paneId)
- {
- case "yellow-pane-login":
- case "yellow-pane-signup":
- case "yellow-pane-recover":
- case "yellow-pane-settings":
- case "yellow-pane-version":
- yellow.toolbox.setOuterLeft(document.getElementById(paneId), paneLeft);
- yellow.toolbox.setOuterTop(document.getElementById(paneId), paneTop);
- yellow.toolbox.setOuterWidth(document.getElementById(paneId), paneWidth);
- break;
- case "yellow-pane-edit":
- yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit"), paneLeft);
- yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-edit"), paneTop);
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit"), paneHeight);
- yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit"), paneWidth);
- yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-page"), yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit")));
- var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-pane-edit"));
- var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-content"));
- var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-page"));
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-page"), height1 - height2 + height3);
- var elementLink = document.getElementById("yellow-pane-"+paneAction+"-link");
- var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2;
- position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-edit")) + 1;
- yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-edit-arrow"), position);
- break;
- case "yellow-pane-user":
- yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user"), paneLeft + paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-user")));
- yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-user"), paneTop);
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-user"), paneHeight, true);
- var elementLink = document.getElementById("yellow-pane-user-link");
- var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2;
- position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-user"));
- yellow.toolbox.setOuterLeft(document.getElementById("yellow-pane-user-arrow"), position);
- break;
- }
- },
-
- // Show or hide pane
- showPane: function(paneId, paneAction, paneStatus, modal)
- {
- if(this.paneId!=paneId || this.paneAction!=paneAction)
- {
- this.hidePane(this.paneId);
- var element = document.getElementById(paneId);
- if(!element) element = this.createPane(paneId, paneAction, paneStatus);
- if(!yellow.toolbox.isVisible(element))
- {
- if(yellow.config.debug) console.log("yellow.webinterface.showPane id:"+paneId);
- yellow.toolbox.setVisible(element, true);
- if(modal)
- {
- yellow.toolbox.addClass(document.body, "yellow-body-modal-open");
- yellow.toolbox.addValue("meta[name=viewport]", "content", ", maximum-scale=1, user-scalable=0");
- }
- this.paneId = paneId;
- this.paneAction = paneAction;
- this.paneStatus = paneStatus;
- this.resizePane(paneId, paneAction, paneStatus);
- this.updatePane(paneId, paneAction, paneStatus, true);
- }
- } else {
- this.hidePane(this.paneId);
- }
- },
-
- // Hide pane
- hidePane: function(paneId)
- {
- var element = document.getElementById(paneId);
- if(yellow.toolbox.isVisible(element))
- {
- if(yellow.config.debug) console.log("yellow.webinterface.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.paneAction = 0;
- this.paneStatus = 0;
- }
- },
-
- // Hide all panes
- hidePanes: function()
- {
- for(var element=document.getElementById("yellow-bar"); element; element=element.nextSibling)
- {
- if(element.className && element.className.indexOf("yellow-pane")>=0)
- {
- this.hidePane(element.getAttribute("id"));
- }
- }
- },
-
- // Hide all panes on mouse click outside
- hidePanesOnClick: function(element)
- {
- for(;element; element=element.parentNode)
- {
- if(element.className)
- {
- if(element.className.indexOf("yellow-pane")>=0 || element.className.indexOf("yellow-bar-")>=0) return;
- }
- }
- this.hidePanes();
- },
-
- // Hide all panes on ESC key
- hidePanesOnKeydown: function(keycode)
- {
- if(keycode==27) this.hidePanes();
- },
-
- // Send pane
- sendPane: function(paneId, paneAction, paneStatus, paneArgs)
- {
- if(yellow.config.debug) console.log("yellow.webinterface.sendPane id:"+paneId);
- if(paneId=="yellow-pane-edit")
- {
- paneAction = this.getPaneAction(paneId, paneAction);
- if(paneAction)
- {
- var args = {};
- args.action = paneAction;
- args.rawdatasource = yellow.page.rawDataSource;
- args.rawdataedit = document.getElementById("yellow-pane-edit-page").value;
- yellow.toolbox.submitForm(args, true);
- } else {
- this.hidePane(paneId);
- }
- } else {
- var args = {"action":paneAction};
- if(paneArgs)
- {
- var tokens = paneArgs.split('/');
- for(var i=0; i<tokens.length; i++)
- {
- var pair = tokens[i].split(/[:=]/);
- if(!pair[0] || !pair[1]) continue;
- args[pair[0]] = pair[1];
- }
- }
- yellow.toolbox.submitForm(args);
- }
- },
-
- // Return pane action
- getPaneAction: function(paneId, paneAction)
- {
- if(paneId=="yellow-pane-edit")
- {
- var string = document.getElementById("yellow-pane-edit-page").value;
- var paneActionOld = paneAction;
- switch(paneAction)
- {
- case "create": paneAction = "create"; break;
- case "edit": paneAction = string ? "edit" : "delete"; break;
- case "delete": paneAction = "delete"; break;
- }
- if(yellow.page.statusCode==424 && paneActionOld!="delete") paneAction = "create";
- if(yellow.config.userRestrictions) paneAction = "";
- }
- return paneAction;
- },
-
- // Return language selection
- getLanguages: function(paneId)
- {
- var languages = "";
- if(yellow.config.serverLanguages && yellow.toolbox.getLength(yellow.config.serverLanguages)>1)
- {
- languages += "<p>";
- 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 += "</p>";
- }
- return languages;
- },
-
- // Return request string
- getRequest: function(key, prefix)
- {
- if(!prefix) prefix = "request";
- key = prefix + key.charAt(0).toUpperCase() + key.slice(1);
- return (key in yellow.page) ? yellow.page[key] : "";
- },
-
- // Return text string
- getText: function(key, prefix, postfix)
- {
- if(!prefix) prefix = "webinterface";
- 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+"]";
- }
-};
-
-yellow.toolbox =
-{
- // Insert element before reference element
- insertBefore: function(element, elementReference)
- {
- elementReference.parentNode.insertBefore(element, elementReference);
- },
-
- // Insert element after reference element
- insertAfter: function(element, elementReference)
- {
- elementReference.parentNode.insertBefore(element, elementReference.nextSibling);
- },
-
- // Add element class
- addClass: function(element, name)
- {
- var string = element.className + " " + name;
- element.className = string.replace(/^\s+|\s+$/, "");
- },
-
- // Remove element class
- removeClass: function(element, name)
- {
- var string = (" " + element.className + " ").replace(" " + name + " ", " ");
- element.className = string.replace(/^\s+|\s+$/, "");
- },
-
- // Add attribute information
- addValue: function(selector, name, value)
- {
- var element = document.querySelector(selector);
- element.setAttribute(name, element.getAttribute(name) + value);
- },
-
- // Remove attribute information
- removeValue: function(selector, name, value)
- {
- var element = document.querySelector(selector);
- element.setAttribute(name, element.getAttribute(name).replace(value, ""));
- },
-
- // Add event handler
- addEvent: function(element, type, handler)
- {
- if(element.addEventListener) element.addEventListener(type, handler, false);
- else element.attachEvent("on"+type, handler);
- },
-
- // Remove event handler
- removeEvent: function(element, type, handler)
- {
- if(element.removeEventListener) element.removeEventListener(type, handler, false);
- else element.detachEvent("on"+type, handler);
- },
-
- // Return element of event
- getEventElement: function(e)
- {
- e = e ? e : window.event;
- return e.target ? e.target : e.srcElement;
- },
-
- // Return keycode of event
- getEventKeycode: function(e)
- {
- e = e ? e : window.event;
- return e.keyCode;
- },
-
- // Return element length
- getLength: function(element)
- {
- return Object.keys ? Object.keys(element).length : 0;
- },
-
- // Return element width in pixel
- getWidth: function(element)
- {
- return element.offsetWidth - this.getBoxSize(element).width;
- },
-
- // Return element height in pixel
- getHeight: function(element)
- {
- return element.offsetHeight - this.getBoxSize(element).height;
- },
-
- // Set element width in pixel, including padding and border
- setOuterWidth: function(element, width, setMax)
- {
- width -= this.getBoxSize(element).width;
- if(setMax)
- {
- element.style.maxWidth = Math.max(0, width) + "px";
- } else {
- element.style.width = Math.max(0, width) + "px";
- }
- },
-
- // Set element height in pixel, including padding and border
- setOuterHeight: function(element, height, setMax)
- {
- height -= this.getBoxSize(element).height;
- if(setMax)
- {
- element.style.maxHeight = Math.max(0, height) + "px";
- } else {
- element.style.height = Math.max(0, height) + "px";
- }
- },
-
- // Return element width in pixel, including padding and border
- getOuterWidth: function(element, includeMargin)
- {
- var width = element.offsetWidth;
- if(includeMargin) width += this.getMarginSize(element).width;
- return width;
- },
-
- // Return element height in pixel, including padding and border
- getOuterHeight: function(element, includeMargin)
- {
- var height = element.offsetHeight;
- if(includeMargin) height += this.getMarginSize(element).height;
- return height;
- },
-
- // Set element left position in pixel
- setOuterLeft: function(element, left)
- {
- element.style.left = Math.max(0, left) + "px";
- },
-
- // Set element top position in pixel
- setOuterTop: function(element, top)
- {
- element.style.top = Math.max(0, top) + "px";
- },
-
- // Return element left position in pixel
- getOuterLeft: function(element)
- {
- var left = element.getBoundingClientRect().left;
- return left + (window.pageXOffset || document.documentElement.scrollLeft);
- },
-
- // Return element top position in pixel
- getOuterTop: function(element)
- {
- var top = element.getBoundingClientRect().top;
- return top + (window.pageYOffset || document.documentElement.scrollTop);
- },
-
- // Return window width in pixel
- getWindowWidth: function()
- {
- return window.innerWidth || document.documentElement.clientWidth;
- },
-
- // Return window height in pixel
- getWindowHeight: function()
- {
- return window.innerHeight || document.documentElement.clientHeight;
- },
-
- // Return element CSS property
- getStyle: function(element, property)
- {
- var string = "";
- if(window.getComputedStyle)
- {
- string = window.getComputedStyle(element, null).getPropertyValue(property);
- } else {
- property = property.replace(/\-(\w)/g, function(match, m) { return m.toUpperCase(); });
- string = element.currentStyle[property];
- }
- return string;
- },
-
- // Return element CSS padding and border
- getBoxSize: function(element)
- {
- var paddingLeft = parseFloat(this.getStyle(element, "padding-left")) || 0;
- var paddingRight = parseFloat(this.getStyle(element, "padding-right")) || 0;
- var borderLeft = parseFloat(this.getStyle(element, "border-left-width")) || 0;
- var borderRight = parseFloat(this.getStyle(element, "border-right-width")) || 0;
- var width = paddingLeft + paddingRight + borderLeft + borderRight;
- var paddingTop = parseFloat(this.getStyle(element, "padding-top")) || 0;
- var paddingBottom = parseFloat(this.getStyle(element, "padding-bottom")) || 0;
- var borderTop = parseFloat(this.getStyle(element, "border-top-width")) || 0;
- var borderBottom = parseFloat(this.getStyle(element, "border-bottom-width")) || 0;
- var height = paddingTop + paddingBottom + borderTop + borderBottom;
- return { "width":width, "height":height };
- },
-
- // Return element CSS margin
- getMarginSize: function(element)
- {
- var marginLeft = parseFloat(this.getStyle(element, "margin-left")) || 0;
- var marginRight = parseFloat(this.getStyle(element, "margin-right")) || 0;
- var width = marginLeft + marginRight;
- var marginTop = parseFloat(this.getStyle(element, "margin-top")) || 0;
- var marginBottom = parseFloat(this.getStyle(element, "margin-bottom")) || 0;
- var height = marginTop + marginBottom;
- return { "width":width, "height":height };
- },
-
- // Set input cursor position
- setCursorPosition: function(element, pos)
- {
- if(element.setSelectionRange)
- {
- element.focus();
- element.setSelectionRange(pos, pos);
- } else if(element.createTextRange) {
- var range = element.createTextRange();
- range.move("character", pos);
- range.select();
- }
- },
-
- // Get input cursor position
- getCursorPosition: function(element)
- {
- var pos = 0;
- if(element.setSelectionRange)
- {
- pos = element.selectionStart;
- } else if(document.selection) {
- var range = document.selection.createRange();
- var rangeDuplicate = range.duplicate();
- rangeDuplicate.moveToElementText(element);
- rangeDuplicate.setEndPoint("EndToEnd", range);
- pos = rangeDuplicate.text.length - range.text.length;
- }
- return pos;
- },
-
- // Set element visibility
- setVisible: function(element, show)
- {
- element.style.display = show ? "block" : "none";
- },
-
- // Check if element exists and is visible
- isVisible: function(element)
- {
- return element && element.style.display!="none";
- },
-
- // Encode newline characters
- encodeNewline: function(string)
- {
- return string
- .replace(/[%]/g, "%25")
- .replace(/[\r]/g, "%0d")
- .replace(/[\n]/g, "%0a");
- },
-
- // Encode HTML special characters
- encodeHtml: function(string)
- {
- return string
- .replace(/&/g, "&")
- .replace(/</g, "<")
- .replace(/>/g, ">")
- .replace(/"/g, """);
- },
-
- // Submit form with post method
- submitForm: function(args, encodeNewline)
- {
- var elementForm = document.createElement("form");
- elementForm.setAttribute("method", "post");
- for(var key in args)
- {
- if(!args.hasOwnProperty(key)) continue;
- var value = encodeNewline ? this.encodeNewline(args[key]) : args[key];
- var elementInput = document.createElement("input");
- elementInput.setAttribute("type", "hidden");
- elementInput.setAttribute("name", key);
- elementInput.setAttribute("value", value);
- elementForm.appendChild(elementInput);
- }
- document.body.appendChild(elementForm);
- elementForm.submit();
- }
-};
-
-yellow.webinterface.intervalId = setInterval("yellow.onLoad()", 1);
diff --git a/system/plugins/webinterface.php b/system/plugins/webinterface.php
@@ -1,1510 +0,0 @@
-<?php
-// Webinterface plugin, https://github.com/datenstrom/yellow-plugins/tree/master/webinterface
-// Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-class YellowWebinterface
-{
- const VERSION = "0.6.21";
- var $yellow; //access to API
- var $response; //web interface response
- var $users; //web interface users
- var $merge; //web interface merge
-
- // Handle initialisation
- function onLoad($yellow)
- {
- $this->yellow = $yellow;
- $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"));
- }
-
- // Handle startup
- function onStartup($update)
- {
- if($update) $this->cleanCommand(array("clean", "all"));
- }
-
- // Handle request
- function onRequest($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if($this->checkRequest($location))
- {
- $scheme = $this->yellow->config->get("serverScheme");
- $address = $this->yellow->config->get("serverAddress");
- $base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("webinterfaceLocation"), '/');
- 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);
- }
- return $statusCode;
- }
-
- // Handle page meta data parsing
- function onParseMeta($page)
- {
- if($page==$this->yellow->page && $this->response->isActive())
- {
- if($this->response->isUser())
- {
- if(empty($this->response->rawDataSource)) $this->response->rawDataSource = $page->rawData;
- if(empty($this->response->rawDataEdit)) $this->response->rawDataEdit = $page->rawData;
- if($page->statusCode==424) $this->response->rawDataEdit = $this->response->getRawDataNew($page->location);
- }
- if(empty($this->response->language)) $this->response->language = $page->get("language");
- if(empty($this->response->action)) $this->response->action = $this->response->isUser() ? "none" : "login";
- if(empty($this->response->status)) $this->response->status = "none";
- if($this->response->status=="error") $this->response->action = "error";
- }
- }
-
- // Handle page content parsing of custom block
- function onParseContentBlock($page, $name, $text, $shortcut)
- {
- $output = null;
- if($name=="edit" && $shortcut)
- {
- $editText = "$name $text";
- if(substru($text, 0, 2)=="- ") $editText = trim(substru($text, 2));
- $output = "<a href=\"".$page->get("pageEdit")."\">".htmlspecialchars($editText)."</a>";
- }
- return $output;
- }
-
- // Handle page extra HTML data
- function onExtra($name)
- {
- $output = null;
- 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 .= "<script type=\"text/javascript\">\n";
- $output .= "// <![CDATA[\n";
- $output .= "yellow.page = ".json_encode($this->response->getPageData()).";\n";
- $output .= "yellow.config = ".json_encode($this->response->getConfigData()).";\n";
- $output .= "yellow.text = ".json_encode($this->response->getTextData()).";\n";
- $output .= "// ]]>\n";
- $output .= "</script>\n";
- }
- return $output;
- }
-
- // Handle command
- function onCommand($args)
- {
- list($command) = $args;
- switch($command)
- {
- case "clean": $statusCode = $this->cleanCommand($args); break;
- case "user": $statusCode = $this->userCommand($args); break;
- default: $statusCode = 0;
- }
- return $statusCode;
- }
-
- // Handle command help
- function onCommandHelp()
- {
- return "user [EMAIL PASSWORD NAME LANGUAGE]\n";
- }
-
- // Clean user accounts
- function cleanCommand($args)
- {
- $statusCode = 0;
- list($command, $path) = $args;
- if($path=="all")
- {
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- if(!$this->users->clean($fileNameUser)) $statusCode = 500;
- if($statusCode==500) echo "ERROR cleaning configuration: Can't write file '$fileNameUser'!\n";
- }
- return $statusCode;
- }
-
- // Update user account
- function userCommand($args)
- {
- $statusCode = 0;
- list($command, $email, $password, $name, $language) = $args;
- if(!empty($email) && !empty($password))
- {
- $userExisting = $this->users->isExisting($email);
- $status = $this->getUserAccount($email, $password, $command);
- switch($status)
- {
- case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break;
- case "weak": echo "ERROR updating configuration: Please enter a different password!\n"; break;
- }
- if($status=="ok")
- {
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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");
- $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";
- }
- $statusCode = $status=="ok" ? 200 : 500;
- echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "");
- echo ($userExisting ? "updated" : "created")."\n";
- } else {
- $statusCode = 200;
- foreach($this->users->getData() as $line) echo "$line\n";
- if(!$this->users->getNumber()) echo "Yellow $command: No user accounts\n";
- }
- return $statusCode;
- }
-
- // Process request
- function processRequest($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if($this->checkUser($scheme, $address, $base, $location, $fileName))
- {
- switch($_REQUEST["action"])
- {
- case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
- case "login": $statusCode = $this->processRequestLogin($scheme, $address, $base, $location, $fileName); break;
- case "logout": $statusCode = $this->processRequestLogout($scheme, $address, $base, $location, $fileName); break;
- case "signup": $statusCode = $this->processRequestSignup($scheme, $address, $base, $location, $fileName); break;
- case "confirm": $statusCode = $this->processRequestConfirm($scheme, $address, $base, $location, $fileName); break;
- case "approve": $statusCode = $this->processRequestApprove($scheme, $address, $base, $location, $fileName); break;
- case "recover": $statusCode = $this->processRequestRecover($scheme, $address, $base, $location, $fileName); break;
- case "settings": $statusCode = $this->processRequestSettings($scheme, $address, $base, $location, $fileName); break;
- case "reconfirm": $statusCode = $this->processRequestReconfirm($scheme, $address, $base, $location, $fileName); break;
- case "change": $statusCode = $this->processRequestChange($scheme, $address, $base, $location, $fileName); break;
- case "version": $statusCode = $this->processRequestVersion($scheme, $address, $base, $location, $fileName); break;
- case "update": $statusCode = $this->processRequestUpdate($scheme, $address, $base, $location, $fileName); break;
- case "create": $statusCode = $this->processRequestCreate($scheme, $address, $base, $location, $fileName); break;
- case "edit": $statusCode = $this->processRequestEdit($scheme, $address, $base, $location, $fileName); break;
- case "delete": $statusCode = $this->processRequestDelete($scheme, $address, $base, $location, $fileName); break;
- }
- } else {
- $this->yellow->lookup->requestHandler = "core";
- switch($_REQUEST["action"])
- {
- case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
- case "signup": $statusCode = $this->processRequestSignup($scheme, $address, $base, $location, $fileName); break;
- case "confirm": $statusCode = $this->processRequestConfirm($scheme, $address, $base, $location, $fileName); break;
- case "approve": $statusCode = $this->processRequestApprove($scheme, $address, $base, $location, $fileName); break;
- case "recover": $statusCode = $this->processRequestRecover($scheme, $address, $base, $location, $fileName); break;
- 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');)!");
- }
- return $statusCode;
- }
-
- // Process request to show file
- function processRequestShow($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if(is_readable($fileName))
- {
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- } else {
- if($this->yellow->lookup->isRedirectLocation($location))
- {
- $statusCode = 301;
- $location = $this->yellow->lookup->isFileLocation($location) ? "$location/" : "/".$this->yellow->getRequestLanguage()."/";
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
- $this->yellow->sendStatus($statusCode, $location);
- } else {
- $statusCode = $this->response->isUserRestrictions() ? 404 : 424;
- $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- $this->yellow->page->error($statusCode);
- }
- }
- return $statusCode;
- }
-
- // Process request for user login
- function processRequestLogin($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- $home = $this->users->getHome($this->response->userEmail);
- if(substru($location, 0, strlenu($home))==$home)
- {
- $statusCode = 303;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
- $this->yellow->sendStatus($statusCode, $location);
- } else {
- $statusCode = 302;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $home);
- $this->yellow->sendStatus($statusCode, $location);
- }
- return $statusCode;
- }
-
- // Process request for user logout
- function processRequestLogout($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 302;
- $this->response->userEmail = "";
- $this->response->destroyCookie($scheme, $address, $base);
- $location = $this->yellow->lookup->normaliseUrl(
- $this->yellow->config->get("serverScheme"),
- $this->yellow->config->get("serverAddress"),
- $this->yellow->config->get("serverBase"), $location);
- $this->yellow->sendStatus($statusCode, $location);
- return $statusCode;
- }
-
- // Process request for user signup
- function processRequestSignup($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "signup";
- $this->response->status = "ok";
- $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
- $email = trim($_REQUEST["email"]);
- $password = trim($_REQUEST["password"]);
- if(empty($name) || empty($email) || empty($password)) $this->response->status = "incomplete";
- if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
- if($this->response->status=="ok" && $this->response->isLoginRestrictions()) $this->response->status = "next";
- 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");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "confirm") ? "next" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to confirm user signup
- function processRequestConfirm($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "confirm";
- $this->response->status = "ok";
- $email = $_REQUEST["email"];
- $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");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "approve") ? "done" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to approve user signup
- function processRequestApprove($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "approve";
- $this->response->status = "ok";
- $email = $_REQUEST["email"];
- $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");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "welcome") ? "done" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to recover password
- function processRequestRecover($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "recover";
- $this->response->status = "ok";
- $email = trim($_REQUEST["email"]);
- $password = trim($_REQUEST["password"]);
- 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")
- {
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "recover") ? "next" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- } else {
- $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
- if($this->response->status=="ok")
- {
- if(empty($password)) $this->response->status = "password";
- 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");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->userEmail = "";
- $this->response->destroyCookie($scheme, $address, $base);
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- }
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to change settings
- function processRequestSettings($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "settings";
- $this->response->status = "ok";
- $email = trim($_REQUEST["email"]);
- $emailSource = $this->response->userEmail;
- $password = trim($_REQUEST["password"]);
- $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
- $language = trim($_REQUEST["language"]);
- if($email!=$emailSource || !empty($password))
- {
- if(empty($email)) $this->response->status = "invalid";
- if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
- if($this->response->status=="ok" && $email!=$emailSource && $this->users->isTaken($email)) $this->response->status = "taken";
- if($this->response->status=="ok" && $email!=$emailSource)
- {
- $pending = $emailSource;
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $action = $email!=$emailSource ? "reconfirm" : "change";
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, $action) ? "next" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- } else {
- if($this->response->status=="ok")
- {
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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'!");
- }
- }
- if($this->response->status=="done")
- {
- $statusCode = 303;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
- $this->yellow->sendStatus($statusCode, $location);
- } else {
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- }
- return $statusCode;
- }
-
- // Process request to reconfirm email
- function processRequestReconfirm($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "reconfirm";
- $this->response->status = "ok";
- $email = $emailSource = $_REQUEST["email"];
- $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
- if($this->response->status=="ok")
- {
- $emailSource = $this->users->getPending($email);
- if($this->users->getStatus($emailSource)!="active") $this->response->status = "done";
- }
- if($this->response->status=="ok")
- {
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $emailSource, "change") ? "done" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to change settings
- function processRequestChange($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "change";
- $this->response->status = "ok";
- $email = $emailSource = trim($_REQUEST["email"]);
- $this->response->status = $this->users->getResponseStatus($email, $_REQUEST["action"], $_REQUEST["expire"], $_REQUEST["id"]);
- if($this->response->status=="ok")
- {
- list($email, $hash) = explode(':', $this->users->getPending($email), 2);
- if(!$this->users->isExisting($email) || empty($hash)) $this->response->status = "done";
- }
- if($this->response->status=="ok" && $email!=$emailSource)
- {
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->users->users[$email]["hash"] = $hash;
- $this->users->users[$email]["pending"] = "none";
- $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile");
- $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'!");
- }
- if($this->response->status=="ok")
- {
- $this->response->userEmail = "";
- $this->response->destroyCookie($scheme, $address, $base);
- $this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
- if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to show software version
- function processRequestVersion($scheme, $address, $base, $location, $fileName)
- {
- $this->response->action = "version";
- $this->response->status = "ok";
- if($this->yellow->plugins->isExisting("update"))
- {
- list($statusCodeCurrent, $dataCurrent) = $this->yellow->plugins->get("update")->getSoftwareVersion();
- list($statusCodeLatest, $dataLatest) = $this->yellow->plugins->get("update")->getSoftwareVersion(true);
- list($statusCodeModified, $dataModified) = $this->yellow->plugins->get("update")->getSoftwareModified();
- $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeModified);
- if($this->response->isUserWebmaster())
- {
- foreach($dataCurrent as $key=>$value)
- {
- if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0)
- {
- ++$updates;
- if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "<br />\n";
- $this->response->rawDataOutput .= htmlspecialchars("$key $dataLatest[$key]");
- }
- }
- if($updates==0)
- {
- foreach($dataCurrent as $key=>$value)
- {
- 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 = preg_replace("/@software/i", htmlspecialchars("$key $dataLatest[$key]"), $rawData);
- if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "<br />\n";
- $this->response->rawDataOutput .= $rawData;
- }
- }
- }
- } else {
- foreach($dataCurrent as $key=>$value)
- {
- if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0) ++$updates;
- }
- }
- $this->response->status = $updates ? "updates" : "done";
- if($statusCode!=200) $this->response->status = "error";
- }
- $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- return $statusCode;
- }
-
- // Process request to update website
- function processRequestUpdate($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if($this->yellow->plugins->isExisting("update") && $this->response->isUserWebmaster())
- {
- $option = trim($_REQUEST["option"]);
- $feature = trim($_REQUEST["feature"]);
- $statusCode = $this->yellow->command("update", $option, $feature);
- if($statusCode==200)
- {
- $statusCode = 303;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
- $this->yellow->sendStatus($statusCode, $location);
- }
- }
- return $statusCode;
- }
-
- // Process request to create page
- function processRequestCreate($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if(!$this->response->isUserRestrictions() && !empty($_POST["rawdataedit"]))
- {
- $this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
- $rawData = $this->response->normaliseText(rawurldecode($_POST["rawdataedit"]));
- $page = $this->response->getPageNew($scheme, $address, $base, $location, $fileName, $rawData);
- if(!$page->isError())
- {
- if($this->yellow->toolbox->createFile($page->fileName, $page->rawData, true))
- {
- $statusCode = 303;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->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 write file '$page->fileName'!");
- }
- } else {
- $statusCode = 500;
- $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- $this->yellow->page->error($statusCode, $page->get("pageError"));
- }
- }
- return $statusCode;
- }
-
- // Process request to edit page
- function processRequestEdit($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- 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->rawDataSource, $this->response->rawDataEdit, $this->yellow->toolbox->readFile($fileName));
- if(!$page->isError())
- {
- if($this->yellow->toolbox->renameFile($fileName, $page->fileName) &&
- $this->yellow->toolbox->createFile($page->fileName, $page->rawData))
- {
- $statusCode = 303;
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->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 write file '$page->fileName'!");
- }
- } else {
- $statusCode = 500;
- $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
- $this->yellow->page->error($statusCode, $page->get("pageError"));
- }
- }
- return $statusCode;
- }
-
- // Process request to delete page
- function processRequestDelete($scheme, $address, $base, $location, $fileName)
- {
- $statusCode = 0;
- if(!$this->response->isUserRestrictions() && is_file($fileName))
- {
- $this->response->rawDataSource = $this->response->rawDataEdit = rawurldecode($_POST["rawdatasource"]);
- if($this->yellow->lookup->isFileLocation($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 {
- 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'!");
- }
- }
- }
- return $statusCode;
- }
-
- // Check web interface request
- function checkRequest($location)
- {
- $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation"));
- $this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("webinterfaceLocation");
- return $this->response->isActive();
- }
-
- // Check web interface user
- function checkUser($scheme, $address, $base, $location, $fileName)
- {
- if($_POST["action"]=="login")
- {
- $email = $_POST["email"];
- $password = $_POST["password"];
- if($this->users->checkUser($email, $password))
- {
- $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);
- } else {
- $this->response->action = "fail";
- }
- } else if(isset($_COOKIE["login"])) {
- list($email, $session) = explode(',', $_COOKIE["login"], 2);
- if($this->users->checkCookie($email, $session))
- {
- $this->response->userEmail = $email;
- $this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
- $this->response->language = $this->response->getLanguage($email);
- } else {
- $this->response->action = "fail";
- }
- }
- return $this->response->isUser();
- }
-
- // Return user account changes
- function getUserAccount($email, $password, $action)
- {
- $status = null;
- foreach($this->yellow->plugins->plugins as $key=>$value)
- {
- if(method_exists($value["obj"], "onUserAccount"))
- {
- $status = $value["obj"]->onUserAccount($email, $password, $action, $status, $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($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) $status = "invalid";
- }
- return $status;
- }
-
- // Return user restrictions to change page
- function getUserRestrictions($email, $location, $fileName)
- {
- $userRestrictions = null;
- foreach($this->yellow->plugins->plugins as $key=>$value)
- {
- if(method_exists($value["obj"], "onUserRestrictions"))
- {
- $userRestrictions = $value["obj"]->onUserRestrictions($email, $location, $fileName, $this->users);
- if(!is_null($userRestrictions)) break;
- }
- }
- if(is_null($userRestrictions))
- {
- $userRestrictions = substru($location, 0, strlenu($this->users->getHome($email)))!=$this->users->getHome($email);
- $userRestrictions |= empty($fileName) || strlenu(dirname($fileName))>128 || strlenu(basename($fileName))>128;
- }
- return $userRestrictions;
- }
-}
-
-class YellowResponse
-{
- var $yellow; //access to API
- var $webinterface; //access to web interface
- var $userEmail; //user email
- var $userRestrictions; //user can change page? (boolean)
- var $active; //web interface 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
- var $language; //response language
- var $action; //response action
- var $status; //response status
-
- function __construct($yellow)
- {
- $this->yellow = $yellow;
- $this->webinterface = $yellow->plugins->get("webinterface");
- }
-
- // Return new page
- function getPageNew($scheme, $address, $base, $location, $fileName, $rawData)
- {
- $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))
- {
- $page->fileName = $this->yellow->lookup->findFileFromTitle(
- $page->get($this->yellow->config->get("webinterfaceMetaFilePrefix")), $page->get("title"), $fileName,
- $this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension"));
- $page->location = $this->yellow->lookup->findLocationFromFile($page->fileName);
- if($this->yellow->pages->find($page->location))
- {
- preg_match("/^(.*?)(\d*)$/", $page->get("title"), $matches);
- $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!");
- }
- }
- 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))
- {
- $page->error(500, "Page '".$page->get("title")."' is not allowed!");
- }
- return $page;
- }
-
- // Return modified page
- function getPageUpdate($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);
- 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"))
- {
- $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)
- {
- if(!$this->yellow->lookup->isFileLocation($page->location))
- {
- $page->error(500, "Page '".$page->get("title")."' is not allowed!");
- } 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))
- {
- $page->error(500, "Page '".$page->get("title")."' is not allowed!");
- }
- return $page;
- }
-
- // Return page data including login information
- function getPageData()
- {
- $data = array();
- if($this->isUser())
- {
- $data["title"] = $this->getPageTitle($this->rawDataEdit);
- $data["rawDataSource"] = $this->rawDataSource;
- $data["rawDataEdit"] = $this->rawDataEdit;
- $data["rawDataNew"] = $this->getRawDataNew();
- $data["rawDataOutput"] = strval($this->rawDataOutput);
- $data["scheme"] = $this->yellow->page->scheme;
- $data["address"] = $this->yellow->page->address;
- $data["base"] = $this->yellow->page->base;
- $data["location"] = $this->yellow->page->location;
- $data["parserSafeMode"] = $this->yellow->page->parserSafeMode;
- }
- if($this->action!="none") $data = array_merge($data, $this->getRequestData());
- $data["action"] = $this->action;
- $data["status"] = $this->status;
- $data["statusCode"] = $this->yellow->page->statusCode;
- return $data;
- }
-
- // Return configuration data including user information
- function getConfigData()
- {
- $data = $this->yellow->config->getData("", "Location");
- 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["userRestrictions"] = intval($this->isUserRestrictions());
- $data["userWebmaster"] = intval($this->isUserWebmaster());
- $data["pluginUpdate"] = intval($this->yellow->plugins->isExisting("update"));
- $data["serverLanguages"] = array();
- foreach($this->yellow->text->getLanguages() as $language)
- {
- $data["serverLanguages"][$language] = $this->yellow->text->getTextHtml("languageDescription", $language);
- }
- $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;
- } else {
- $data["loginEmail"] = $this->yellow->config->get("loginEmail");
- $data["loginPassword"] = $this->yellow->config->get("loginPassword");
- $data["loginRestrictions"] = intval($this->isLoginRestrictions());
- }
- if(defined("DEBUG") && DEBUG>=1) $data["debug"] = DEBUG;
- return $data;
- }
-
- // Return request strings
- function getRequestData()
- {
- $data = array();
- foreach($_REQUEST as $key=>$value)
- {
- if($key=="login" || $key=="password") continue;
- $data["request".ucfirst($key)] = trim($value);
- }
- return $data;
- }
-
- // Return text strings
- function getTextData()
- {
- $textLanguage = $this->yellow->text->getData("language", $this->language);
- $textWebinterface = $this->yellow->text->getData("webinterface", $this->language);
- $textYellow = $this->yellow->text->getData("yellow", $this->language);
- return array_merge($textLanguage, $textWebinterface, $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"));
- $rawData = $this->yellow->toolbox->readFile($fileName);
- $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);
- if(!empty($location))
- {
- $title = $this->yellow->toolbox->createTextTitle($location);
- $rawData = $this->updateTextTitle($rawData, $title);
- }
- return $rawData;
- }
-
- // Return page title
- function getPageTitle($rawData)
- {
- $title = $this->yellow->page->get("title");
- if(preg_match("/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+(.+?)\-\-\-[\r\n]+/s", $rawData, $parts))
- {
- 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; }
- }
- }
- return $title;
- }
-
- // Return language for user
- function getLanguage($email)
- {
- $language = $this->webinterface->users->getLanguage($email);
- if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
- return $language;
- }
-
- // Update text title
- function updateTextTitle($rawData, $title)
- {
- 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;
- }
-
- // 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);
- setcookie("login", "$email,$session", time()+60*60*24*365, "$base/", "", $scheme=="https");
- }
-
- // Destroy browser cookie
- function destroyCookie($scheme, $address, $base)
- {
- setcookie("login", "", time()-60*60, "$base/", "", $scheme=="https");
- }
-
- // Send mail to user
- function sendMail($scheme, $address, $base, $email, $action)
- {
- if($action=="welcome" || $action=="information")
- {
- $url = "$scheme://$address$base/";
- } else {
- $expire = time()+60*60*24;
- $id = $this->webinterface->users->createRequestId($email, $action, $expire);
- $url = "$scheme://$address$base"."/action:$action/email:$email/expire:$expire/id:$id/";
- }
- if($action=="approve")
- {
- $account = $email;
- $name = $this->yellow->config->get("author");
- $email = $this->yellow->config->get("email");
- } else {
- $account = $email;
- $name = $this->webinterface->users->getName($email);
- }
- $language = $this->webinterface->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);
- $message = $this->yellow->text->getText("{$prefix}Message", $language);
- $message = preg_replace("/@useraccount/i", $account, $message);
- $message = preg_replace("/@usershort/i", strtok($name, " "), $message);
- $message = preg_replace("/@username/i", $name, $message);
- $message = preg_replace("/@userlanguage/i", $language, $message);
- $mailTo = mb_encode_mimeheader("$name")." <$email>";
- $mailSubject = mb_encode_mimeheader($this->yellow->text->getText("{$prefix}Subject", $language));
- $mailHeaders = mb_encode_mimeheader("From: $sitename")." <noreply>\r\n";
- $mailHeaders .= mb_encode_mimeheader("X-Request-Url: $scheme://$address$base")."\r\n";
- $mailHeaders .= mb_encode_mimeheader("X-Remote-Addr: $_SERVER[REMOTE_ADDR]")."\r\n";
- $mailHeaders .= "Mime-Version: 1.0\r\n";
- $mailHeaders .= "Content-Type: text/plain; charset=utf-8\r\n";
- $mailMessage = "$message\r\n\r\n$url\r\n-- \r\n$sitename";
- return mail($mailTo, $mailSubject, $mailMessage, $mailHeaders);
- }
-
- // Check if web interface 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()
- {
- return empty($this->userEmail) || $this->userRestrictions;
- }
-
- // Check if user is webmaster
- function isUserWebmaster()
- {
- return !empty($this->userEmail) && $this->userEmail==$this->yellow->config->get("email");
- }
-}
-
-class YellowUsers
-{
- var $yellow; //access to API
- var $users; //registered users
-
- function __construct($yellow)
- {
- $this->yellow = $yellow;
- $this->users = array();
- }
-
- // Load users from file
- function load($fileName)
- {
- if(defined("DEBUG") && DEBUG>=2) echo "YellowUsers::load file:$fileName<br/>\n";
- $fileData = $this->yellow->toolbox->readFile($fileName);
- foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
- {
- if(preg_match("/^\#/", $line)) continue;
- preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
- if(!empty($matches[1]) && !empty($matches[2]))
- {
- list($hash, $name, $language, $status, $modified, $pending, $home) = explode(',', $matches[2]);
- $this->set($matches[1], $hash, $name, $language, $status, $modified, $pending, $home);
- if(defined("DEBUG") && DEBUG>=3) echo "YellowUsers::load email:$matches[1]<br/>\n";
- }
- }
- }
-
- // Clean users in file
- function clean($fileName)
- {
- $fileData = $this->yellow->toolbox->readFile($fileName);
- foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
- {
- preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
- if(!empty($matches[1]) && !empty($matches[2]))
- {
- list($hash, $name, $language, $status, $modified, $pending, $home) = explode(',', $matches[2]);
- if($status=="active" || $status=="inactive")
- {
- $pending = "none";
- $fileDataNew .= "$matches[1]: $hash,$name,$language,$status,$modified,$pending,$home\n";
- }
- } else {
- $fileDataNew .= $line;
- }
- }
- return $this->yellow->toolbox->createFile($fileName, $fileDataNew);
- }
-
- // Update users in file
- function update($fileName, $email, $password = "", $name = "", $language = "", $status = "", $modified = "", $pending = "", $home = "")
- {
- if(!empty($password)) $hash = $this->createHash($password);
- if($this->isExisting($email))
- {
- $email = strreplaceu(',', '-', $email);
- $hash = strreplaceu(',', '-', empty($hash) ? $this->users[$email]["hash"] : $hash);
- $name = strreplaceu(',', '-', empty($name) ? $this->users[$email]["name"] : $name);
- $language = strreplaceu(',', '-', empty($language) ? $this->users[$email]["language"] : $language);
- $status = strreplaceu(',', '-', empty($status) ? $this->users[$email]["status"] : $status);
- $modified = strreplaceu(',', '-', empty($modified) ? time() : $modified);
- $pending = strreplaceu(',', '-', empty($pending) ? $this->users[$email]["pending"] : $pending);
- $home = strreplaceu(',', '-', empty($home) ? $this->users[$email]["home"] : $home);
- } else {
- $email = strreplaceu(',', '-', empty($email) ? "none" : $email);
- $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);
- $modified = strreplaceu(',', '-', empty($modified) ? time() : $modified);
- $pending = strreplaceu(',', '-', empty($pending) ? "none" : $pending);
- $home = strreplaceu(',', '-', empty($home) ? $this->yellow->config->get("webinterfaceUserHome") : $home);
- }
- $this->set($email, $hash, $name, $language, $status, $modified, $pending, $home);
- $fileData = $this->yellow->toolbox->readFile($fileName);
- foreach($this->yellow->toolbox->getTextLines($fileData) as $line)
- {
- preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
- if(!empty($matches[1]) && $matches[1]==$email)
- {
- $fileDataNew .= "$email: $hash,$name,$language,$status,$modified,$pending,$home\n";
- $found = true;
- } else {
- $fileDataNew .= $line;
- }
- }
- if(!$found) $fileDataNew .= "$email: $hash,$name,$language,$status,$modified,$pending,$home\n";
- return $this->yellow->toolbox->createFile($fileName, $fileDataNew);
- }
-
- // Set user data
- function set($email, $hash, $name, $language, $status, $modified, $pending, $home)
- {
- $this->users[$email] = array();
- $this->users[$email]["email"] = $email;
- $this->users[$email]["hash"] = $hash;
- $this->users[$email]["name"] = $name;
- $this->users[$email]["language"] = $language;
- $this->users[$email]["status"] = $status;
- $this->users[$email]["modified"] = $modified;
- $this->users[$email]["pending"] = $pending;
- $this->users[$email]["home"] = $home;
- }
-
- // Check user login from email and password
- function checkUser($email, $password)
- {
- $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm");
- return $this->isExisting($email) && $this->users[$email]["status"]=="active" &&
- $this->yellow->toolbox->verifyHash($password, $algorithm, $this->users[$email]["hash"]);
- }
-
- // Check user login from email and session
- function checkCookie($email, $session)
- {
- return $this->isExisting($email) && $this->users[$email]["status"]=="active" &&
- $this->yellow->toolbox->verifyHash($this->users[$email]["hash"], "sha256", $session);
- }
-
- // Create session
- function createSession($email)
- {
- if($this->isExisting($email))
- {
- $session = $this->yellow->toolbox->createHash($this->users[$email]["hash"], "sha256");
- if(empty($session)) $session = "error-hash-algorithm-sha256";
- }
- return $session;
- }
-
- // Create password hash
- function createHash($password)
- {
- $algorithm = $this->yellow->config->get("webinterfaceUserHashAlgorithm");
- $cost = $this->yellow->config->get("webinterfaceUserHashCost");
- $hash = $this->yellow->toolbox->createHash($password, $algorithm, $cost);
- if(empty($hash)) $hash = "error-hash-algorithm-$algorithm";
- return $hash;
- }
-
- // Create request ID for action
- function createRequestId($email, $action, $expire)
- {
- return $this->yellow->toolbox->createHash($this->users[$email]["hash"].$action.$expire, "sha256");
- }
-
- // Return response status for action
- function getResponseStatus($email, $action, $expire, $id)
- {
- $status = "done";
- switch($action)
- {
- case "confirm": $statusExpected = "unconfirmed"; break;
- case "reconfirm": $statusExpected = "unconfirmed"; break;
- case "approve": $statusExpected = "unapproved"; break;
- default: $statusExpected = "active"; break;
- }
- if($this->isExisting($email) && $this->users[$email]["status"]==$statusExpected &&
- $this->yellow->toolbox->verifyHash($this->users[$email]["hash"].$action.$expire, "sha256", $id))
- {
- $status = "ok";
- }
- if($expire<=time()) $status = "expired";
- return $status;
- }
-
- // Return user hash
- function getHash($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["hash"] : "";
- }
-
- // Return user name
- function getName($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["name"] : "";
- }
-
- // Return user language
- function getLanguage($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["language"] : "";
- }
-
- // Return user status
- function getStatus($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["status"] : "";
- }
-
- // Return user modified
- function getModified($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["modified"] : "";
- }
-
- // Return user pending
- function getPending($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["pending"] : "";
- }
-
- // Return user home
- function getHome($email = "")
- {
- return $this->isExisting($email) ? $this->users[$email]["home"] : "";
- }
-
- // Return number of users
- function getNumber()
- {
- return count($this->users);
- }
-
- // Return user data
- function getData()
- {
- $data = array();
- foreach($this->users as $key=>$value)
- {
- $name = $value["name"]; if(preg_match("/\s/", $name)) $name = "\"$name\"";
- $language = $value["language"]; if(preg_match("/\s/", $language)) $language = "\"$language\"";
- $status = $value["status"]; if(preg_match("/\s/", $status)) $status = "\"$status\"";
- $data[$key] = "$value[email] - $name $language $status";
- if($value["home"]!="/") $data[$key] .= " restrictions";
- }
- usort($data, strnatcasecmp);
- return $data;
- }
-
- // Check if user is taken
- function isTaken($email)
- {
- $taken = false;
- if($this->isExisting($email))
- {
- $status = $this->users[$email]["status"];
- $reserved = $this->users[$email]["modified"] + 60*60*24;
- if($status=="active" || $status=="inactive" || $reserved>time()) $taken = true;
- }
- return $taken;
- }
-
- // Check if user exists
- function isExisting($email)
- {
- return !is_null($this->users[$email]);
- }
-}
-
-class YellowMerge
-{
- var $yellow; //access to API
- const ADD = '+'; //merge types
- const MODIFY = '*';
- const REMOVE = '-';
- const SAME = ' ';
-
- function __construct($yellow)
- {
- $this->yellow = $yellow;
- }
-
- // Merge text, null if not possible
- function merge($textSource, $textMine, $textYours, $showDiff = false)
- {
- if($textMine!=$textYours)
- {
- $diffMine = $this->buildDiff($textSource, $textMine);
- $diffYours = $this->buildDiff($textSource, $textYours);
- $diff = $this->mergeDiff($diffMine, $diffYours);
- $output = $this->getOutput($diff, $showDiff);
- } else {
- $output = $textMine;
- }
- return $output;
- }
-
- // Build differences to common source
- function buildDiff($textSource, $textOther)
- {
- $diff = array();
- $lastRemove = -1;
- $textStart = 0;
- $textSource = $this->yellow->toolbox->getTextLines($textSource);
- $textOther = $this->yellow->toolbox->getTextLines($textOther);
- $sourceEnd = $sourceSize = count($textSource);
- $otherEnd = $otherSize = count($textOther);
- while($textStart<$sourceEnd && $textStart<$otherEnd && $textSource[$textStart]==$textOther[$textStart]) ++$textStart;
- while($textStart<$sourceEnd && $textStart<$otherEnd && $textSource[$sourceEnd-1]==$textOther[$otherEnd-1])
- {
- --$sourceEnd; --$otherEnd;
- }
- for($pos=0; $pos<$textStart; ++$pos) array_push($diff, array(YellowMerge::SAME, $textSource[$pos], false));
- $lcs = $this->buildDiffLCS($textSource, $textOther, $textStart, $sourceEnd-$textStart, $otherEnd-$textStart);
- for($x=0,$y=0,$xEnd=$otherEnd-$textStart,$yEnd=$sourceEnd-$textStart; $x<$xEnd || $y<$yEnd;)
- {
- $max = $lcs[$y][$x];
- if($y<$yEnd && $lcs[$y+1][$x]==$max)
- {
- array_push($diff, array(YellowMerge::REMOVE, $textSource[$textStart+$y], false));
- if($lastRemove==-1) $lastRemove = count($diff)-1;
- ++$y;
- continue;
- }
- if($x<$xEnd && $lcs[$y][$x+1]==$max)
- {
- if($lastRemove==-1 || $diff[$lastRemove][0]!=YellowMerge::REMOVE)
- {
- array_push($diff, array(YellowMerge::ADD, $textOther[$textStart+$x], false));
- $lastRemove = -1;
- } else {
- $diff[$lastRemove] = array(YellowMerge::MODIFY, $textOther[$textStart+$x], false);
- ++$lastRemove; if(count($diff)==$lastRemove) $lastRemove = -1;
- }
- ++$x;
- continue;
- }
- array_push($diff, array(YellowMerge::SAME, $textSource[$textStart+$y], false));
- $lastRemove = -1;
- ++$x;
- ++$y;
- }
- for($pos=$sourceEnd;$pos<$sourceSize; ++$pos) array_push($diff, array(YellowMerge::SAME, $textSource[$pos], false));
- return $diff;
- }
-
- // Build longest common subsequence
- function buildDiffLCS($textSource, $textOther, $textStart, $yEnd, $xEnd)
- {
- $lcs = array_fill(0, $yEnd+1, array_fill(0, $xEnd+1, 0));
- for($y=$yEnd-1; $y>=0; --$y)
- {
- for($x=$xEnd-1; $x>=0; --$x)
- {
- if($textSource[$textStart+$y]==$textOther[$textStart+$x])
- {
- $lcs[$y][$x] = $lcs[$y+1][$x+1]+1;
- } else {
- $lcs[$y][$x] = max($lcs[$y][$x+1], $lcs[$y+1][$x]);
- }
- }
- }
- return $lcs;
- }
-
- // Merge differences
- function mergeDiff($diffMine, $diffYours)
- {
- $diff = array();
- $posMine = $posYours = 0;
- while($posMine<count($diffMine) && $posYours<count($diffYours))
- {
- $typeMine = $diffMine[$posMine][0];
- $typeYours = $diffYours[$posYours][0];
- if($typeMine==YellowMerge::SAME)
- {
- array_push($diff, $diffYours[$posYours]);
- } else if($typeYours==YellowMerge::SAME) {
- array_push($diff, $diffMine[$posMine]);
- } else if($typeMine==YellowMerge::ADD && $typeYours==YellowMerge::ADD) {
- $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], false);
- } else if($typeMine==YellowMerge::MODIFY && $typeYours==YellowMerge::MODIFY) {
- $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], false);
- } else if($typeMine==YellowMerge::REMOVE && $typeYours==YellowMerge::REMOVE) {
- array_push($diff, $diffMine[$posMine]);
- } else if($typeMine==YellowMerge::ADD) {
- array_push($diff, $diffMine[$posMine]);
- } else if($typeYours==YellowMerge::ADD) {
- array_push($diff, $diffYours[$posYours]);
- } else {
- $this->mergeConflict($diff, $diffMine[$posMine], $diffYours[$posYours], true);
- }
- if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
- if($typeMine==YellowMerge::ADD || $typeYours==YellowMerge::ADD)
- {
- if($typeMine==YellowMerge::ADD) ++$posMine;
- if($typeYours==YellowMerge::ADD) ++$posYours;
- } else {
- ++$posMine;
- ++$posYours;
- }
- }
- for(;$posMine<count($diffMine); ++$posMine)
- {
- array_push($diff, $diffMine[$posMine]);
- $typeMine = $diffMine[$posMine][0]; $typeYours = ' ';
- if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
- }
- for(;$posYours<count($diffYours); ++$posYours)
- {
- array_push($diff, $diffYours[$posYours]);
- $typeYours = $diffYours[$posYours][0]; $typeMine = ' ';
- if(defined("DEBUG") && DEBUG>=2) echo "YellowMerge::mergeDiff $typeMine $typeYours pos:$posMine\t$posYours<br/>\n";
- }
- return $diff;
- }
-
- // Merge potential conflict
- function mergeConflict(&$diff, $diffMine, $diffYours, $conflict)
- {
- if(!$conflict && $diffMine[1]==$diffYours[1])
- {
- array_push($diff, $diffMine);
- } else {
- array_push($diff, array($diffMine[0], $diffMine[1], true));
- array_push($diff, array($diffYours[0], $diffYours[1], true));
- }
- }
-
- // Return merged text, null if not possible
- function getOutput($diff, $showDiff = false)
- {
- $output = "";
- if(!$showDiff)
- {
- for($i=0; $i<count($diff); ++$i)
- {
- if($diff[$i][0]!=YellowMerge::REMOVE) $output .= $diff[$i][1];
- $conflict |= $diff[$i][2];
- }
- } else {
- for($i=0; $i<count($diff); ++$i)
- {
- $output .= $diff[$i][2] ? "! " : $diff[$i][0].' ';
- $output .= $diff[$i][1];
- }
- }
- return !$conflict ? $output : null;
- }
-}
-
-$yellow->plugins->register("webinterface", "YellowWebinterface", YellowWebinterface::VERSION);
-?>
diff --git a/system/plugins/yellow-blog.zip.installation b/system/plugins/yellow-blog.zip.installation
Binary files differ.
diff --git a/system/plugins/yellow-wiki.zip.installation b/system/plugins/yellow-wiki.zip.installation
Binary files differ.