Parcourir la source

Updated system, new API

markseu il y a 6 ans
Parent
commit
c17da68c1a
42 fichiers modifiés avec 1148 ajouts et 1189 suppressions
  1. 0 2
      system/config/text.ini
  2. 17 16
      system/extensions/bundle.php
  3. 96 95
      system/extensions/command.php
  4. 307 384
      system/extensions/core.php
  5. 2 2
      system/extensions/edit.css
  6. 48 48
      system/extensions/edit.js
  7. 160 160
      system/extensions/edit.php
  8. 0 0
      system/extensions/edit.woff
  9. 9 0
      system/extensions/flatsite.php
  10. 24 23
      system/extensions/image.php
  11. BIN
      system/extensions/install-blog.zip
  12. BIN
      system/extensions/install-languages.zip
  13. BIN
      system/extensions/install-wiki.zip
  14. 96 96
      system/extensions/install.php
  15. 6 5
      system/extensions/markdown.php
  16. 291 251
      system/extensions/update.php
  17. 9 0
      system/layouts/default.html
  18. 8 0
      system/layouts/error.html
  19. 10 0
      system/layouts/footer.html
  20. 27 0
      system/layouts/header.html
  21. 2 2
      system/layouts/navigation-sidebar.html
  22. 4 4
      system/layouts/navigation-tree.html
  23. 2 2
      system/layouts/navigation.html
  24. 3 3
      system/layouts/pagination.html
  25. 6 6
      system/layouts/sidebar.html
  26. BIN
      system/plugins/install-blog.zip
  27. BIN
      system/plugins/install-language.zip
  28. BIN
      system/plugins/install-wiki.zip
  29. BIN
      system/resources/flatsite-icon.png
  30. 5 5
      system/resources/flatsite.css
  31. 0 0
      system/resources/opensans-bold.woff
  32. 0 0
      system/resources/opensans-light.woff
  33. 0 0
      system/resources/opensans-regular.woff
  34. 14 22
      system/settings/system.ini
  35. 2 0
      system/settings/text.ini
  36. 0 0
      system/settings/user.ini
  37. 0 8
      system/themes/assets/flatsite.php
  38. BIN
      system/themes/assets/icon.png
  39. 0 11
      system/themes/snippets/footer.php
  40. 0 27
      system/themes/snippets/header.php
  41. 0 9
      system/themes/templates/default.html
  42. 0 8
      system/themes/templates/error.html

+ 0 - 2
system/config/text.ini

@@ -1,2 +0,0 @@
-# Datenstrom Yellow text
-

+ 17 - 16
system/plugins/bundle.php → system/extensions/bundle.php

@@ -1,16 +1,17 @@
 <?php
-// Bundle plugin, https://github.com/datenstrom/yellow-plugins/tree/master/bundle
+// Bundle extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/bundle
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowBundle {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     public $yellow;         //access to API
 
     // Handle initialisation
     public function onLoad($yellow) {
         $this->yellow = $yellow;
-        $this->yellow->config->setDefault("bundleAndMinify", "1");
+        $this->yellow->system->setDefault("bundleAndMinify", "1");
     }
     
     // Handle page output data
@@ -37,7 +38,7 @@ class YellowBundle {
         $statusCode = 0;
         list($command, $path) = $args;
         if ($path=="all") {
-            $path = $this->yellow->config->get("assetDir");
+            $path = $this->yellow->system->get("resourceDir");
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/bundle-.*/", false, false) as $entry) {
                 if (!$this->yellow->toolbox->deleteFile($entry)) $statusCode = 500;
             }
@@ -56,7 +57,7 @@ class YellowBundle {
                 if (preg_match("/\"stylesheet\"/i", $line)) {
                     if (is_null($dataCss[$matches[2]])) $dataCss[$matches[2]] = $line;
                 } else {
-                    if (is_null($dataLink[$matches[2]])) $dataLink[$matches[2]] = $line;
+                    array_push($dataLink, $line);
                 }
             } elseif (preg_match("/^<script (.*?)src=\"([^\"]+)\"(.*?)><\/script>$/i", $line, $matches)) {
                 if (preg_match("/\"defer\"/i", $line)) {
@@ -68,7 +69,7 @@ class YellowBundle {
                 array_push($dataOther, $line);
             }
         }
-        if ($this->yellow->config->get("bundleAndMinify")) {
+        if ($this->yellow->system->get("bundleAndMinify")) {
             $dataCss = $this->processBundle($dataCss, "css");
             $dataScript = $this->processBundle($dataScript, "js");
         }
@@ -79,9 +80,9 @@ class YellowBundle {
     // Process bundle, create file on demand
     public function processBundle($data, $type) {
         $fileNames = array();
-        $scheme = $this->yellow->config->get("serverScheme");
-        $address = $this->yellow->config->get("serverAddress");
-        $base = $this->yellow->config->get("serverBase");
+        $scheme = $this->yellow->system->get("serverScheme");
+        $address = $this->yellow->system->get("serverAddress");
+        $base = $this->yellow->system->get("serverBase");
         foreach ($data as $key=>$value) {
             if (preg_match("/^\w+:/", $key)) continue;
             if (preg_match("/data-bundle=\"none\"/i", $value)) continue;
@@ -97,8 +98,8 @@ class YellowBundle {
         if (!empty($fileNames)) {
             $this->yellow->toolbox->timerStart($time);
             $id = substru(md5(implode($fileNames).$base), 0, 10);
-            $fileNameBundle = $this->yellow->config->get("assetDir")."bundle-$id.min.$type";;
-            $locationBundle = $base.$this->yellow->config->get("assetLocation")."bundle-$id.min.$type";
+            $fileNameBundle = $this->yellow->system->get("resourceDir")."bundle-$id.min.$type";;
+            $locationBundle = $base.$this->yellow->system->get("resourceLocation")."bundle-$id.min.$type";
             if ($type=="css") {
                 $data[$locationBundle] = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"".htmlspecialchars($locationBundle)."\" />\n";
             } else {
@@ -134,11 +135,11 @@ class YellowBundle {
     // Process bundle, convert URLs
     public function processBundleConvert($scheme, $address, $base, $fileData, $fileName, $type) {
         if ($type=="css") {
-            $pluginDirLength = strlenu($this->yellow->config->get("pluginDir"));
-            if (substru($fileName, 0, $pluginDirLength) == $this->yellow->config->get("pluginDir")) {
-                $base .= $this->yellow->config->get("pluginLocation");
+            $extensionDirLength = strlenu($this->yellow->system->get("extensionDir"));
+            if (substru($fileName, 0, $extensionDirLength) == $this->yellow->system->get("extensionDir")) {
+                $base .= $this->yellow->system->get("extensionLocation");
             } else {
-                $base .= $this->yellow->config->get("assetLocation");
+                $base .= $this->yellow->system->get("resourceLocation");
             }
             $thisCompatible = $this;
             $callback = function ($matches) use ($thisCompatible, $scheme, $address, $base) {
@@ -1903,7 +1904,7 @@ class Converter implements ConverterInterface {
 }
 
 // Minify extensions
-// Copyright (c) 2013-2018 Datenstrom
+// Copyright (c) 2013-2019 Datenstrom
 
 class MinifyCss extends CSS { }
 

+ 96 - 95
system/plugins/command.php → system/extensions/command.php

@@ -1,10 +1,11 @@
 <?php
-// Command plugin, https://github.com/datenstrom/yellow-plugins/tree/master/command
+// Command extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/command
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowCommand {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     public $yellow;                     //access to API
     public $files;                      //number of files
     public $links;                      //number of links
@@ -22,11 +23,11 @@ class YellowCommand {
         list($command) = $args;
         switch ($command) {
             case "":        $statusCode = $this->processCommandHelp(); break;
+            case "about":   $statusCode = $this->processCommandAbout($args); break;
             case "build":   $statusCode = $this->processCommandBuild($args); break;
             case "check":   $statusCode = $this->processCommandCheck($args); break;
             case "clean":   $statusCode = $this->processCommandClean($args); break;
             case "serve":   $statusCode = $this->processCommandServe($args); break;
-            case "version": $statusCode = $this->processCommandVersion($args); break;
             default:        $statusCode = 0;
         }
         return $statusCode;
@@ -34,11 +35,11 @@ class YellowCommand {
     
     // Handle command help
     public function onCommandHelp() {
+        $help .= "about\n";
         $help .= "build [directory location]\n";
         $help .= "check [directory location]\n";
         $help .= "clean [directory location]\n";
         $help .= "serve [url]\n";
-        $help .= "version\n";
         return $help;
     }
     
@@ -52,18 +53,35 @@ class YellowCommand {
         return 200;
     }
     
+    // Process command to show website version and updates
+    public function processCommandAbout($args) {
+        $serverVersion = $this->yellow->toolbox->getServerVersion();
+        echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
+        list($statusCode, $dataCurrent) = $this->getExtensionsVersion();
+        list($statusCode, $dataLatest) = $this->getExtensionsVersion(true);
+        foreach ($dataCurrent as $key=>$value) {
+            if (strnatcasecmp($dataCurrent[$key], $dataLatest[$key])>=0) {
+                echo ucfirst($key)." $value\n";
+            } else {
+                echo ucfirst($key)." $value - Update available\n";
+            }
+        }
+        if ($statusCode!=200) echo "ERROR checking updates: ".$this->yellow->page->get("pageError")."\n";
+        return $statusCode;
+    }
+    
     // Process command to build static website
     public function processCommandBuild($args) {
         $statusCode = 0;
         list($command, $path, $location) = $args;
         if (empty($location) || $location[0]=="/") {
-            if ($this->checkStaticConfig()) {
+            if ($this->checkStaticSettings()) {
                 $statusCode = $this->buildStaticFiles($path, $location);
             } else {
                 $statusCode = 500;
                 $this->files = 0;
                 $this->errors = 1;
-                $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
                 echo "ERROR building files: Please configure StaticUrl in file '$fileName'!\n";
             }
             echo "Yellow $command: $this->files file".($this->files!=1 ? "s" : "");
@@ -77,11 +95,11 @@ class YellowCommand {
     
     // Build static files
     public function buildStaticFiles($path, $locationFilter) {
-        $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, "/");
+        $path = rtrim(empty($path) ? $this->yellow->system->get("staticDir") : $path, "/");
         $this->files = $this->errors = 0;
         $this->locationsArgs = $this->locationsArgsPagination = array();
         $statusCode = empty($locationFilter) ? $this->cleanStaticFiles($path, $locationFilter) : 200;
-        $staticUrl = $this->yellow->config->get("staticUrl");
+        $staticUrl = $this->yellow->system->get("staticUrl");
         list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
         foreach ($this->getContentLocations() as $location) {
             if (!preg_match("#^$base$locationFilter#", "$base$location")) continue;
@@ -119,12 +137,12 @@ class YellowCommand {
     
     // Build static file
     public function buildStaticFile($path, $location, $analyse = false, $probe = false, $error = false) {
-        $this->yellow->pages = new YellowPages($this->yellow);
+        $this->yellow->content = new YellowContent($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");
+            $staticUrl = $this->yellow->system->get("staticUrl");
             list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
             $statusCode = $this->requestStaticFile($scheme, $address, $base, $location);
             if ($statusCode<400 || $error) {
@@ -199,7 +217,7 @@ class YellowCommand {
     
     // Analyse locations with arguments
     public function analyseLocations($scheme, $address, $base, $rawData) {
-        $pagination = $this->yellow->config->get("contentPagination");
+        $pagination = $this->yellow->system->get("contentPagination");
         preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $rawData, $matches);
         foreach ($matches[2] as $match) {
             $location = rawurldecode($match);
@@ -233,12 +251,12 @@ class YellowCommand {
         $statusCode = 0;
         list($command, $path, $location) = $args;
         if (empty($location) || $location[0]=="/") {
-            if ($this->checkStaticConfig()) {
+            if ($this->checkStaticSettings()) {
                 $statusCode = $this->checkStaticFiles($path, $location);
             } else {
                 $statusCode = 500;
                 $this->files = $this->links = 0;
-                $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
                 echo "ERROR checking files: Please configure StaticUrl in file '$fileName'!\n";
             }
             echo "Yellow $command: $this->files file".($this->files!=1 ? "s" : "");
@@ -252,9 +270,9 @@ class YellowCommand {
     
     // Check static files for broken links
     public function checkStaticFiles($path, $locationFilter) {
-        $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, "/");
+        $path = rtrim(empty($path) ? $this->yellow->system->get("staticDir") : $path, "/");
         $this->files = $this->links = 0;
-        $regex = "/^[^.]+$|".$this->yellow->config->get("staticDefaultFile")."$/";
+        $regex = "/^[^.]+$|".$this->yellow->system->get("staticDefaultFile")."$/";
         $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($path, $regex, false, false);
         list($statusCodeFiles, $links) = $this->analyseLinks($path, $locationFilter, $fileNames);
         list($statusCodeLinks, $broken, $redirect) = $this->analyseStatus($path, $links);
@@ -270,7 +288,7 @@ class YellowCommand {
         $statusCode = 200;
         $links = array();
         if (!empty($fileNames)) {
-            $staticUrl = $this->yellow->config->get("staticUrl");
+            $staticUrl = $this->yellow->system->get("staticUrl");
             list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
             foreach ($fileNames as $fileName) {
                 if (is_readable($fileName)) {
@@ -294,6 +312,7 @@ class YellowCommand {
                         }
                     }
                     ++$this->files;
+                    if (defined("DEBUG") && DEBUG>=1) echo "YellowCommand::analyseLinks location:$locationSource<br/>\n";
                 } else {
                     $statusCode = 500;
                     echo "ERROR reading files: Can't read file '$fileName'!\n";
@@ -311,7 +330,7 @@ class YellowCommand {
     public function analyseStatus($path, $links) {
         $statusCode = 200;
         $broken = $redirect = $data = array();
-        $staticUrl = $this->yellow->config->get("staticUrl");
+        $staticUrl = $this->yellow->system->get("staticUrl");
         $staticUrlLength = strlenu(rtrim($staticUrl, "/"));
         list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($staticUrl);
         $staticLocations = $this->getContentLocations(true);
@@ -378,7 +397,7 @@ class YellowCommand {
     // Clean static files and directories
     public function cleanStaticFiles($path, $location) {
         $statusCode = 200;
-        $path = rtrim(empty($path) ? $this->yellow->config->get("staticDir") : $path, "/");
+        $path = rtrim(empty($path) ? $this->yellow->system->get("staticDir") : $path, "/");
         if (empty($location)) {
             $statusCode = max($statusCode, $this->broadcastCommand("clean", "all"));
             $statusCode = max($statusCode, $this->cleanStaticDirectory($path));
@@ -417,10 +436,10 @@ class YellowCommand {
         return $statusCode;
     }
     
-    // Broadcast command to other plugins
+    // Broadcast command to other extensions
     public function broadcastCommand($args) {
         $statusCode = 0;
-        foreach ($this->yellow->plugins->plugins as $key=>$value) {
+        foreach ($this->yellow->extensions->extensions as $key=>$value) {
             if ($key=="command") continue;
             if (method_exists($value["obj"], "onCommand")) {
                 $statusCode = $value["obj"]->onCommand(func_get_args());
@@ -448,48 +467,62 @@ class YellowCommand {
         return $statusCode;
     }
     
-    // Process command to show software version and updates
-    public function processCommandVersion($args) {
-        $serverVersion = $this->yellow->toolbox->getServerVersion();
-        echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion\n";
-        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 $value - Update available\n";
-            }
-        }
-        if ($statusCode!=200) echo "ERROR checking updates: ".$this->yellow->page->get("pageError")."\n";
-        return $statusCode;
-    }
-    
-    // Check static configuration
-    public function checkStaticConfig() {
-        $staticUrl = $this->yellow->config->get("staticUrl");
-        return !empty($staticUrl);
+    // Check static settings
+    public function checkStaticSettings() {
+        return !empty($this->yellow->system->get("staticUrl"));
     }
     
     // Check static directory
     public 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 ($path==rtrim($this->yellow->system->get("staticDir"), "/")) $ok = true;
+            if ($path==rtrim($this->yellow->system->get("trashDir"), "/")) $ok = true;
+            if (is_file("$path/".$this->yellow->system->get("staticDefaultFile"))) $ok = true;
             if (is_file("$path/yellow.php")) $ok = false;
         }
         return $ok;
     }
     
+    // Return command help
+    public function getCommandHelp() {
+        $data = array();
+        foreach ($this->yellow->extensions->extensions 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 extensions version
+    public function getExtensionsVersion($latest = false) {
+        $data = array();
+        if ($this->yellow->extensions->isExisting("update")) {
+            list($statusCode, $data) = $this->yellow->extensions->get("update")->getExtensionsVersion($latest);
+        } else {
+            $statusCode = 200;
+            $data = $this->yellow->extensions->getData();
+        }
+        return array($statusCode, $data);
+    }
+    
+    // Return human readable status
+    public function getStatusFormatted($statusCode) {
+        return $this->yellow->toolbox->getHttpStatusFormatted($statusCode, true);
+    }
+    
     // Return static file
     public function getStaticFile($path, $location, $statusCode) {
         if ($statusCode<400) {
             $fileName = $path.$location;
-            if (!$this->yellow->lookup->isFileLocation($location)) $fileName .= $this->yellow->config->get("staticDefaultFile");
+            if (!$this->yellow->lookup->isFileLocation($location)) $fileName .= $this->yellow->system->get("staticDefaultFile");
         } elseif ($statusCode==404) {
-            $fileName = $path."/".$this->yellow->config->get("staticErrorFile");
+            $fileName = $path."/".$this->yellow->system->get("staticErrorFile");
         }
         return $fileName;
     }
@@ -497,8 +530,8 @@ class YellowCommand {
     // Return static location
     public function getStaticLocation($path, $fileName) {
         $location = substru($fileName, strlenu($path));
-        if (basename($location)==$this->yellow->config->get("staticDefaultFile")) {
-            $defaultFileLength = strlenu($this->yellow->config->get("staticDefaultFile"));
+        if (basename($location)==$this->yellow->system->get("staticDefaultFile")) {
+            $defaultFileLength = strlenu($this->yellow->system->get("staticDefaultFile"));
             $location = substru($location, 0, -$defaultFileLength);
         }
         return $location;
@@ -513,30 +546,25 @@ class YellowCommand {
         return $output;
     }
 
-    // Return human readable status
-    public function getStatusFormatted($statusCode) {
-        return $this->yellow->toolbox->getHttpStatusFormatted($statusCode, true);
-    }
-    
     // Return content locations
     public function getContentLocations($includeAll = false) {
         $locations = array();
-        $staticUrl = $this->yellow->config->get("staticUrl");
+        $staticUrl = $this->yellow->system->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) {
+        foreach ($this->yellow->content->index(true, true) as $page) {
             if (($page->get("status")!="ignore" && $page->get("status")!="draft") || $includeAll) {
                 array_push($locations, $page->location);
             }
         }
-        if (!$this->yellow->pages->find("/") && $this->yellow->config->get("multiLanguageMode")) array_unshift($locations, "/");
+        if (!$this->yellow->content->find("/") && $this->yellow->system->get("multiLanguageMode")) array_unshift($locations, "/");
         return $locations;
     }
     
     // Return media locations
     public function getMediaLocations() {
         $locations = array();
-        $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("mediaDir"), "/.*/", false, false);
+        $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->system->get("mediaDir"), "/.*/", false, false);
         foreach ($fileNames as $fileName) {
             array_push($locations, "/".$fileName);
         }
@@ -547,15 +575,15 @@ class YellowCommand {
     public function getSystemLocations() {
         $locations = array();
         $regex = "/\.(css|gif|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);
+        $extensionDirLength = strlenu($this->yellow->system->get("extensionDir"));
+        $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->system->get("extensionDir"), $regex, false, false);
         foreach ($fileNames as $fileName) {
-            array_push($locations, $this->yellow->config->get("pluginLocation").substru($fileName, $pluginDirLength));
+            array_push($locations, $this->yellow->system->get("extensionLocation").substru($fileName, $extensionDirLength));
         }
-        $themeDirLength = strlenu($this->yellow->config->get("themeDir"));
-        $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->config->get("themeDir"), $regex, false, false);
+        $resourceDirLength = strlenu($this->yellow->system->get("resourceDir"));
+        $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive($this->yellow->system->get("resourceDir"), $regex, false, false);
         foreach ($fileNames as $fileName) {
-            array_push($locations, $this->yellow->config->get("themeLocation").substru($fileName, $themeDirLength));
+            array_push($locations, $this->yellow->system->get("resourceLocation").substru($fileName, $resourceDirLength));
         }
         return $locations;
     }
@@ -563,11 +591,11 @@ class YellowCommand {
     // Return extra locations
     public function getExtraLocations() {
         $locations = array();
-        $pathIgnore = "(".$this->yellow->config->get("staticDir")."|".
-            $this->yellow->config->get("cacheDir")."|".
-            $this->yellow->config->get("contentDir")."|".
-            $this->yellow->config->get("mediaDir")."|".
-            $this->yellow->config->get("systemDir").")";
+        $pathIgnore = "(".$this->yellow->system->get("staticDir")."|".
+            $this->yellow->system->get("cacheDir")."|".
+            $this->yellow->system->get("contentDir")."|".
+            $this->yellow->system->get("mediaDir")."|".
+            $this->yellow->system->get("systemDir").")";
         $fileNames = $this->yellow->toolbox->getDirectoryEntriesRecursive(".", "/.*/", false, false);
         foreach ($fileNames as $fileName) {
             $fileName = substru($fileName, 2);
@@ -577,33 +605,6 @@ class YellowCommand {
         return $locations;
     }
     
-    // Return command help
-    public 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
-    public 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);
-    }
-    
     // Return link status
     public function getLinkStatus($url, $referer) {
         $curlHandle = curl_init();

Fichier diff supprimé car celui-ci est trop grand
+ 307 - 384
system/extensions/core.php


+ 2 - 2
system/plugins/edit.css → system/extensions/edit.css

@@ -1,5 +1,5 @@
-/* Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit */
-/* Copyright (c) 2013-2018 Datenstrom, https://datenstrom.se */
+/* Edit extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/edit */
+/* Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se */
 /* This file may be used and distributed under the terms of the public license. */
 
 .yellow-bar {

+ 48 - 48
system/plugins/edit.js → system/extensions/edit.js

@@ -1,5 +1,5 @@
-// Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit
-// Copyright (c) 2013-2018 Datenstrom, https://datenstrom.se
+// Edit extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/edit
+// Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 var yellow = {
@@ -106,7 +106,7 @@ yellow.edit = {
     
     // Create bar
     createBar: function(barId) {
-        if (yellow.config.debug) console.log("yellow.edit.createBar id:"+barId);
+        if (yellow.system.debug) console.log("yellow.edit.createBar id:"+barId);
         var elementBar = document.createElement("div");
         elementBar.className = "yellow-bar";
         elementBar.setAttribute("id", barId);
@@ -117,7 +117,7 @@ yellow.edit = {
         }
         var elementDiv = document.createElement("div");
         elementDiv.setAttribute("id", barId+"-content");
-        if (yellow.config.userName) {
+        if (yellow.system.userName) {
             elementDiv.innerHTML =
                 "<div class=\"yellow-bar-left\">"+
                 "<a href=\"#\" id=\"yellow-pane-edit-link\" data-action=\"edit\">"+this.getText("Edit")+"</a>"+
@@ -125,7 +125,7 @@ yellow.edit = {
                 "<div class=\"yellow-bar-right\">"+
                 "<a href=\"#\" id=\"yellow-pane-create-link\" data-action=\"create\">"+this.getText("Create")+"</a>"+
                 "<a href=\"#\" id=\"yellow-pane-delete-link\" data-action=\"delete\">"+this.getText("Delete")+"</a>"+
-                "<a href=\"#\" id=\"yellow-pane-user-link\" data-action=\"user\">"+yellow.toolbox.encodeHtml(yellow.config.userName)+"</a>"+
+                "<a href=\"#\" id=\"yellow-pane-user-link\" data-action=\"user\">"+yellow.toolbox.encodeHtml(yellow.system.userName)+"</a>"+
                 "</div>"+
                 "<div class=\"yellow-bar-banner\"></div>";
         }
@@ -136,7 +136,7 @@ yellow.edit = {
     
     // Create pane
     createPane: function(paneId, paneAction, paneStatus) {
-        if (yellow.config.debug) console.log("yellow.edit.createPane id:"+paneId);
+        if (yellow.system.debug) console.log("yellow.edit.createPane id:"+paneId);
         var elementPane = document.createElement("div");
         elementPane.className = "yellow-pane";
         elementPane.setAttribute("id", paneId);
@@ -164,8 +164,8 @@ yellow.edit = {
                 "<div class=\"yellow-title\"><h1>"+this.getText("LoginTitle")+"</h1></div>"+
                 "<div class=\"yellow-fields\" 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><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.system.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.system.editLoginPassword)+"\" /></p>"+
                 "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\" /></p>"+
                 "</div>"+
                 "<div class=\"yellow-actions\" id=\"yellow-pane-login-actions\">"+
@@ -225,11 +225,11 @@ yellow.edit = {
                 break;
             case "yellow-pane-settings":
                 var rawDataLanguages = "";
-                if (yellow.config.serverLanguages && Object.keys(yellow.config.serverLanguages).length>1) {
+                if (yellow.system.serverLanguages && Object.keys(yellow.system.serverLanguages).length>1) {
                     rawDataLanguages += "<p>";
-                    for (var language in yellow.config.serverLanguages) {
+                    for (var language in yellow.system.serverLanguages) {
                         var checked = language==this.getRequest("language") ? " checked=\"checked\"" : "";
-                        rawDataLanguages += "<label for=\"yellow-pane-settings-"+language+"\"><input type=\"radio\" name=\"language\" id=\"yellow-pane-settings-"+language+"\" value=\""+language+"\""+checked+"> "+yellow.toolbox.encodeHtml(yellow.config.serverLanguages[language])+"</label><br />";
+                        rawDataLanguages += "<label for=\"yellow-pane-settings-"+language+"\"><input type=\"radio\" name=\"language\" id=\"yellow-pane-settings-"+language+"\" value=\""+language+"\""+checked+"> "+yellow.toolbox.encodeHtml(yellow.system.serverLanguages[language])+"</label><br />";
                     }
                     rawDataLanguages += "</p>";
                 }
@@ -256,7 +256,7 @@ yellow.edit = {
                 elementDiv.innerHTML =
                 "<form method=\"post\">"+
                 "<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
-                "<div class=\"yellow-title\"><h1 id=\"yellow-pane-version-title\">"+yellow.toolbox.encodeHtml(yellow.config.serverVersion)+"</h1></div>"+
+                "<div class=\"yellow-title\"><h1 id=\"yellow-pane-version-title\">"+yellow.toolbox.encodeHtml(yellow.system.serverVersion)+"</h1></div>"+
                 "<div class=\"yellow-status\"><p id=\"yellow-pane-version-status\" class=\""+paneStatus+"\">"+this.getText("VersionStatus", "", paneStatus)+"</p></div>"+
                 "<div class=\"yellow-output\" id=\"yellow-pane-version-output\">"+yellow.page.rawDataOutput+"</div>"+
                 "<div class=\"yellow-buttons\" id=\"yellow-pane-version-buttons\">"+
@@ -283,8 +283,8 @@ yellow.edit = {
                 break;
             case "yellow-pane-edit":
                 var rawDataButtons = "";
-                if (yellow.config.editToolbarButtons && yellow.config.editToolbarButtons!="none") {
-                    var tokens = yellow.config.editToolbarButtons.split(",");
+                if (yellow.system.editToolbarButtons && yellow.system.editToolbarButtons!="none") {
+                    var tokens = yellow.system.editToolbarButtons.split(",");
                     for (var i=0; i<tokens.length; i++) {
                         var token = tokens[i].trim();
                         if (token!="separator") {
@@ -293,7 +293,7 @@ yellow.edit = {
                             rawDataButtons += "<li><a href=\"#\" class=\"yellow-toolbar-btn-separator\"></a></li>";
                         }
                     }
-                    if (yellow.config.debug) console.log("yellow.edit.createPane buttons:"+yellow.config.editToolbarButtons);
+                    if (yellow.system.debug) console.log("yellow.edit.createPane buttons:"+yellow.system.editToolbarButtons);
                 }
                 elementDiv.innerHTML =
                 "<form method=\"post\">"+
@@ -313,7 +313,7 @@ yellow.edit = {
             case "yellow-pane-user":
                 elementDiv.innerHTML =
                 "<ul class=\"yellow-dropdown\">"+
-                "<li><span>"+yellow.toolbox.encodeHtml(yellow.config.userEmail)+"</span></li>"+
+                "<li><span>"+yellow.toolbox.encodeHtml(yellow.system.userEmail)+"</span></li>"+
                 "<li><a href=\"#\" data-action=\"settings\">"+this.getText("SettingsTitle")+"</a></li>" +
                 "<li><a href=\"#\" data-action=\"help\">"+this.getText("UserHelp")+"</a></li>" +
                 "<li><a href=\"#\" data-action=\"logout\">"+this.getText("UserLogout")+"</a></li>"+
@@ -327,11 +327,11 @@ yellow.edit = {
 
     // Update pane
     updatePane: function(paneId, paneAction, paneStatus, init) {
-        if (yellow.config.debug) console.log("yellow.edit.updatePane id:"+paneId);
+        if (yellow.system.debug) console.log("yellow.edit.updatePane id:"+paneId);
         var showFields = paneStatus!="next" && paneStatus!="done";
         switch (paneId) {
             case "yellow-pane-login":
-                if (yellow.config.editLoginRestrictions) {
+                if (yellow.system.editLoginRestrictions) {
                     yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-signup"), false);
                 }
                 break;
@@ -352,18 +352,18 @@ yellow.edit = {
                 yellow.toolbox.setVisible(document.getElementById("yellow-pane-settings-buttons"), !showFields);
                 if (paneStatus=="none") {
                     document.getElementById("yellow-pane-settings-status").innerHTML = "<a href=\"#\" data-action=\"version\">"+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;
+                    document.getElementById("yellow-pane-settings-name").value = yellow.system.userName;
+                    document.getElementById("yellow-pane-settings-email").value = yellow.system.userEmail;
+                    document.getElementById("yellow-pane-settings-"+yellow.system.userLanguage).checked = true;
                 }
                 break;
             case "yellow-pane-version":
-                if (paneStatus=="none" && this.isPlugin("update")) {
+                if (paneStatus=="none" && this.isExtension("update")) {
                     document.getElementById("yellow-pane-version-status").innerHTML = this.getText("VersionStatusCheck");
                     document.getElementById("yellow-pane-version-output").innerHTML = "";
                     setTimeout("yellow.action('send');", 500);
                 }
-                if (paneStatus=="updates" && this.isPlugin("update")) {
+                if (paneStatus=="updates" && this.isExtension("update")) {
                     document.getElementById("yellow-pane-version-status").innerHTML = "<a href=\"#\" data-action=\"update\">"+this.getText("VersionStatusUpdates")+"</a>";
                 }
                 break;
@@ -385,16 +385,16 @@ yellow.edit = {
                     var matches = document.getElementById("yellow-pane-edit-text").value.match(/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+/);
                     var position = document.getElementById("yellow-pane-edit-text").value.indexOf("\n", matches ? matches[0].length : 0);
                     document.getElementById("yellow-pane-edit-text").setSelectionRange(position, position);
-                    if (yellow.config.editToolbarButtons!="none") {
+                    if (yellow.system.editToolbarButtons!="none") {
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-toolbar-title"), false);
                         this.updateToolbar(0, "yellow-toolbar-checked");
                     }
-                    if (yellow.config.userRestrictions) {
+                    if (yellow.system.userRestrictions) {
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-send"), false);
                         document.getElementById("yellow-pane-edit-text").readOnly = true;
                     }
                 }
-                if (!yellow.config.userRestrictions) {
+                if (!yellow.system.userRestrictions) {
                     var key, className;
                     switch (this.getAction(paneId, paneAction)) {
                         case "create":    key = "CreateButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-create"; break;
@@ -476,7 +476,7 @@ yellow.edit = {
             if (!document.getElementById(paneId)) this.createPane(paneId, paneAction, paneStatus);
             var element = document.getElementById(paneId);
             if (!yellow.toolbox.isVisible(element)) {
-                if (yellow.config.debug) console.log("yellow.edit.showPane id:"+paneId);
+                if (yellow.system.debug) console.log("yellow.edit.showPane id:"+paneId);
                 yellow.toolbox.setVisible(element, true);
                 if (modal) {
                     yellow.toolbox.addClass(document.body, "yellow-body-modal-open");
@@ -510,7 +510,7 @@ yellow.edit = {
 
     // Send pane
     sendPane: function(paneId, paneAction, paneStatus, paneArgs) {
-        if (yellow.config.debug) console.log("yellow.edit.sendPane id:"+paneId);
+        if (yellow.system.debug) console.log("yellow.edit.sendPane id:"+paneId);
         var args = { "action":paneAction, "csrftoken":this.getCookie("csrftoken") };
         if (paneId=="yellow-pane-edit") {
             args.action = this.getAction(paneId, paneAction);
@@ -539,7 +539,7 @@ yellow.edit = {
     processShortcut: function(e) {
         var shortcut = yellow.toolbox.getEventShortcut(e);
         if (shortcut) {
-            var tokens = yellow.config.editKeyboardShortcuts.split(",");
+            var tokens = yellow.system.editKeyboardShortcuts.split(",");
             for (var i=0; i<tokens.length; i++) {
                 var pair = tokens[i].trim().split(" ");
                 if (shortcut==pair[0] || shortcut.replace("meta+", "ctrl+")==pair[0]) {
@@ -553,10 +553,10 @@ yellow.edit = {
     
     // Process toolbar
     processToolbar: function(status, args) {
-        if (yellow.config.debug) console.log("yellow.edit.processToolbar status:"+status);
+        if (yellow.system.debug) console.log("yellow.edit.processToolbar status:"+status);
         var elementText = document.getElementById("yellow-pane-edit-text");
         var elementPreview = document.getElementById("yellow-pane-edit-preview");
-        if (!yellow.config.userRestrictions && this.paneAction!="delete" && !yellow.toolbox.isVisible(elementPreview)) {
+        if (!yellow.system.userRestrictions && this.paneAction!="delete" && !yellow.toolbox.isVisible(elementPreview)) {
             switch (status) {
                 case "h1":              yellow.editor.setMarkdown(elementText, "# ", "insert-multiline-block", true); break;
                 case "h2":              yellow.editor.setMarkdown(elementText, "## ", "insert-multiline-block", true); break;
@@ -581,7 +581,7 @@ yellow.edit = {
             }
         }
         if (status=="preview") this.showPreview(elementText, elementPreview);
-        if (status=="save" && !yellow.config.userRestrictions && this.paneAction!="delete") this.action("send");
+        if (status=="save" && !yellow.system.userRestrictions && this.paneAction!="delete") this.action("send");
         if (status=="help") window.open(this.getText("HelpUrl", "yellow"), "_blank");
         if (status=="markdown") window.open(this.getText("MarkdownUrl", "yellow"), "_blank");
         if (status=="format" || status=="heading" || status=="list" || status=="emojiawesome" || status=="fontawesome") {
@@ -606,7 +606,7 @@ yellow.edit = {
     
     // Create popup
     createPopup: function(popupId) {
-        if (yellow.config.debug) console.log("yellow.edit.createPopup id:"+popupId);
+        if (yellow.system.debug) console.log("yellow.edit.createPopup id:"+popupId);
         var elementPopup = document.createElement("div");
         elementPopup.className = "yellow-popup";
         elementPopup.setAttribute("id", popupId);
@@ -642,8 +642,8 @@ yellow.edit = {
                 break;
             case "yellow-popup-emojiawesome":
                 var rawDataEmojis = "";
-                if (yellow.config.emojiawesomeToolbarButtons && yellow.config.emojiawesomeToolbarButtons!="none") {
-                    var tokens = yellow.config.emojiawesomeToolbarButtons.split(" ");
+                if (yellow.system.emojiawesomeToolbarButtons && yellow.system.emojiawesomeToolbarButtons!="none") {
+                    var tokens = yellow.system.emojiawesomeToolbarButtons.split(" ");
                     for (var i=0; i<tokens.length; i++) {
                         var token = tokens[i].replace(/[\:]/g,"");
                         var className = token.replace("+1", "plus1").replace("-1", "minus1").replace(/_/g, "-");
@@ -654,8 +654,8 @@ yellow.edit = {
                 break;
             case "yellow-popup-fontawesome":
                 var rawDataIcons = "";
-                if (yellow.config.fontawesomeToolbarButtons && yellow.config.fontawesomeToolbarButtons!="none") {
-                    var tokens = yellow.config.fontawesomeToolbarButtons.split(" ");
+                if (yellow.system.fontawesomeToolbarButtons && yellow.system.fontawesomeToolbarButtons!="none") {
+                    var tokens = yellow.system.fontawesomeToolbarButtons.split(" ");
                     for (var i=0; i<tokens.length; i++) {
                         var token = tokens[i].replace(/[\:]/g,"");
                         rawDataIcons += "<li><a href=\"#\" id=\"yellow-popup-list-"+yellow.toolbox.encodeHtml(token)+"\" data-action=\"toolbar\" data-status=\"text\" data-args=\":"+yellow.toolbox.encodeHtml(token)+":\"><i class=\"fa "+yellow.toolbox.encodeHtml(token)+"\"></i></a></li>";
@@ -675,7 +675,7 @@ yellow.edit = {
             this.hidePopup(this.popupId);
             if (!document.getElementById(popupId)) this.createPopup(popupId);
             var element = document.getElementById(popupId);
-            if (yellow.config.debug) console.log("yellow.edit.showPopup id:"+popupId);
+            if (yellow.system.debug) console.log("yellow.edit.showPopup id:"+popupId);
             yellow.toolbox.setVisible(element, true);
             this.popupId = popupId;
             this.updateToolbar(status, "yellow-toolbar-selected");
@@ -737,7 +737,7 @@ yellow.edit = {
         var element = document.createElement("input");
         element.setAttribute("id", "yellow-file-dialog");
         element.setAttribute("type", "file");
-        element.setAttribute("accept", yellow.config.editUploadExtensions);
+        element.setAttribute("accept", yellow.system.editUploadExtensions);
         element.setAttribute("multiple", "multiple");
         yellow.toolbox.addEvent(element, "change", yellow.onDrop);
         element.click();
@@ -746,8 +746,8 @@ yellow.edit = {
     // Upload file
     uploadFile: function(elementText, file) {
         var extension = (file.name.lastIndexOf(".")!=-1 ? file.name.substring(file.name.lastIndexOf("."), file.name.length) : "").toLowerCase();
-        var extensions = yellow.config.editUploadExtensions.split(/\s*,\s*/);
-        if (file.size<=yellow.config.serverFileSizeMax && extensions.indexOf(extension)!=-1) {
+        var extensions = yellow.system.editUploadExtensions.split(/\s*,\s*/);
+        if (file.size<=yellow.system.serverFileSizeMax && extensions.indexOf(extension)!=-1) {
             var text = this.getText("UploadProgress")+"\u200b";
             yellow.editor.setMarkdown(elementText, text, "insert");
             var thisObject = this;
@@ -768,8 +768,8 @@ yellow.edit = {
         if (result) {
             var textOld = this.getText("UploadProgress")+"\u200b";
             var textNew;
-            if (result.location.substring(0, yellow.config.imageLocation.length)==yellow.config.imageLocation) {
-                textNew = "[image "+result.location.substring(yellow.config.imageLocation.length)+"]";
+            if (result.location.substring(0, yellow.system.imageLocation.length)==yellow.system.imageLocation) {
+                textNew = "[image "+result.location.substring(yellow.system.imageLocation.length)+"]";
             } else {
                 textNew = "[link]("+result.location+")";
             }
@@ -830,9 +830,9 @@ yellow.edit = {
         return yellow.toolbox.getCookie(name);
     },
 
-    // Check if plugin exists
-    isPlugin: function(name) {
-        return name in yellow.config.serverPlugins;
+    // Check if extension exists
+    isExtension: function(name) {
+        return name in yellow.system.serverExtensions;
     }
 };
 
@@ -899,7 +899,7 @@ yellow.editor = {
             element.value = textSelectionBefore + textSelectionNew + textSelectionAfter;
             element.setSelectionRange(selectionStartNew, selectionEndNew);
         }
-        if (yellow.config.debug) console.log("yellow.editor.setMarkdown type:"+information.type);
+        if (yellow.system.debug) console.log("yellow.editor.setMarkdown type:"+information.type);
     },
     
     // Return Markdown formatting information
@@ -1027,7 +1027,7 @@ yellow.editor = {
             element.value = textSelectionBefore + textSelectionNew + textSelectionAfter;
             element.setSelectionRange(selectionStartNew, selectionEndNew);
             element.scrollTop = 0;
-            if (yellow.config.debug) console.log("yellow.editor.setMetaData key:"+key);
+            if (yellow.system.debug) console.log("yellow.editor.setMetaData key:"+key);
         }
     },
     

+ 160 - 160
system/plugins/edit.php → system/extensions/edit.php

@@ -1,10 +1,11 @@
 <?php
-// Edit plugin, https://github.com/datenstrom/yellow-plugins/tree/master/edit
+// Edit extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/edit
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowEdit {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     public $yellow;         //access to API
     public $response;       //web response
     public $users;          //user accounts
@@ -16,34 +17,33 @@ class YellowEdit {
         $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("editUploadNewLocation", "/media/@group/@filename");
-        $this->yellow->config->setDefault("editUploadExtensions", ".gif, .jpg, .pdf, .png, .svg, .tgz, .zip");
-        $this->yellow->config->setDefault("editKeyboardShortcuts", "ctrl+b bold, ctrl+i italic, ctrl+e code, ctrl+k link, ctrl+s save, ctrl+shift+p preview");
-        $this->yellow->config->setDefault("editToolbarButtons", "auto");
-        $this->yellow->config->setDefault("editEndOfLine", "auto");
-        $this->yellow->config->setDefault("editUserFile", "user.ini");
-        $this->yellow->config->setDefault("editUserPasswordMinLength", "8");
-        $this->yellow->config->setDefault("editUserHashAlgorithm", "bcrypt");
-        $this->yellow->config->setDefault("editUserHashCost", "10");
-        $this->yellow->config->setDefault("editUserHome", "/");
-        $this->yellow->config->setDefault("editLoginRestrictions", "0");
-        $this->yellow->config->setDefault("editLoginSessionTimeout", "2592000");
-        $this->yellow->config->setDefault("editBruteForceProtection", "25");
-        $this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile"));
+        $this->yellow->system->setDefault("editLocation", "/edit/");
+        $this->yellow->system->setDefault("editUploadNewLocation", "/media/@group/@filename");
+        $this->yellow->system->setDefault("editUploadExtensions", ".gif, .jpg, .pdf, .png, .svg, .tgz, .zip");
+        $this->yellow->system->setDefault("editKeyboardShortcuts", "ctrl+b bold, ctrl+i italic, ctrl+e code, ctrl+k link, ctrl+s save, ctrl+shift+p preview");
+        $this->yellow->system->setDefault("editToolbarButtons", "auto");
+        $this->yellow->system->setDefault("editEndOfLine", "auto");
+        $this->yellow->system->setDefault("editUserFile", "user.ini");
+        $this->yellow->system->setDefault("editUserPasswordMinLength", "8");
+        $this->yellow->system->setDefault("editUserHashAlgorithm", "bcrypt");
+        $this->yellow->system->setDefault("editUserHashCost", "10");
+        $this->yellow->system->setDefault("editUserHome", "/");
+        $this->yellow->system->setDefault("editNewFile", "page-new-(.*).md");
+        $this->yellow->system->setDefault("editLoginRestrictions", "0");
+        $this->yellow->system->setDefault("editLoginSessionTimeout", "2592000");
+        $this->yellow->system->setDefault("editBruteForceProtection", "25");
+        $this->users->load($this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile"));
     }
 
     // Handle startup
     public function onStartup($update) {
         if ($update) {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $fileData = $this->yellow->toolbox->readFile($fileNameUser);
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2]) && $matches[1][0]!="#") {
                     list($hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home) = explode(",", $matches[2]);
-                    if ($errors=="none") { $home=$pending; $pending=$errors; $errors=$modified; $modified=$stamp; $stamp=""; } //TODO: remove later
-                    if (strlenb($stamp)!=20) $stamp=$this->users->createStamp(); //TODO: remove later, converts old file format
                     if ($status!="active" && $status!="inactive") {
                         unset($this->users->users[$matches[1]]);
                         continue;
@@ -63,9 +63,9 @@ class YellowEdit {
     public 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"), "/");
+            $scheme = $this->yellow->system->get("serverScheme");
+            $address = $this->yellow->system->get("serverAddress");
+            $base = rtrim($this->yellow->system->get("serverBase").$this->yellow->system->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);
@@ -104,13 +104,13 @@ class YellowEdit {
     public function onParsePageExtra($page, $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\" data-bundle=\"none\" href=\"{$pluginLocation}edit.css\" />\n";
-            $output .= "<script type=\"text/javascript\" data-bundle=\"none\" src=\"{$pluginLocation}edit.js\"></script>\n";
+            $extensionLocation = $this->yellow->system->get("serverBase").$this->yellow->system->get("extensionLocation");
+            $output = "<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" data-bundle=\"none\" href=\"{$extensionLocation}edit.css\" />\n";
+            $output .= "<script type=\"text/javascript\" data-bundle=\"none\" src=\"{$extensionLocation}edit.js\"></script>\n";
             $output .= "<script type=\"text/javascript\">\n";
             $output .= "// <![CDATA[\n";
             $output .= "yellow.page = ".json_encode($this->response->getPageData($page)).";\n";
-            $output .= "yellow.config = ".json_encode($this->response->getConfigData()).";\n";
+            $output .= "yellow.system = ".json_encode($this->response->getSystemData()).";\n";
             $output .= "yellow.text = ".json_encode($this->response->getTextData()).";\n";
             $output .= "// ]]>\n";
             $output .= "</script>\n";
@@ -164,20 +164,20 @@ class YellowEdit {
         if ($status=="ok") $status = $this->getUserAccount($email, $password, "add");
         if ($status=="ok" && $this->users->isTaken($email)) $status = "taken";
         switch ($status) {
-            case "incomplete":  echo "ERROR updating configuration: Please enter email and password!\n"; break;
-            case "invalid":     echo "ERROR updating configuration: Please enter a valid email!\n"; break;
-            case "taken":       echo "ERROR updating configuration: Please enter a different email!\n"; break;
-            case "weak":        echo "ERROR updating configuration: Please enter a different password!\n"; break;
+            case "incomplete":  echo "ERROR updating settings: Please enter email and password!\n"; break;
+            case "invalid":     echo "ERROR updating settings: Please enter a valid email!\n"; break;
+            case "taken":       echo "ERROR updating settings: Please enter a different email!\n"; break;
+            case "weak":        echo "ERROR updating settings: Please enter a different password!\n"; break;
         }
         if ($status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $status = $this->users->save($fileNameUser, $email, $password, $name, "", "active") ? "ok" : "error";
-            if ($status=="error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n";
+            if ($status=="error") echo "ERROR updating settings: Can't write file '$fileNameUser'!\n";
         }
         if ($status=="ok") {
-            $algorithm = $this->yellow->config->get("editUserHashAlgorithm");
+            $algorithm = $this->yellow->system->get("editUserHashAlgorithm");
             $status = substru($this->users->getHash($email), 0, 10)!="error-hash" ? "ok" : "error";
-            if ($status=="error") echo "ERROR updating configuration: Hash algorithm '$algorithm' not supported!\n";
+            if ($status=="error") echo "ERROR updating settings: Hash algorithm '$algorithm' not supported!\n";
         }
         $statusCode = $status=="ok" ? 200 : 500;
         echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "")."added\n";
@@ -192,14 +192,14 @@ class YellowEdit {
         if ($status=="ok") $status = $this->getUserAccount($email, $password, "change");
         if ($status=="ok" && !$this->users->isExisting($email)) $status = "unknown";
         switch ($status) {
-            case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break;
-            case "unknown": echo "ERROR updating configuration: Can't find email '$email'!\n"; break;
-            case "weak":    echo "ERROR updating configuration: Please enter a different password!\n"; break;
+            case "invalid": echo "ERROR updating settings: Please enter a valid email!\n"; break;
+            case "unknown": echo "ERROR updating settings: Can't find email '$email'!\n"; break;
+            case "weak":    echo "ERROR updating settings: Please enter a different password!\n"; break;
         }
         if ($status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $status = $this->users->save($fileNameUser, $email, $password, $name) ? "ok" : "error";
-            if ($status=="error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n";
+            if ($status=="error") echo "ERROR updating settings: Can't write file '$fileNameUser'!\n";
         }
         $statusCode = $status=="ok" ? 200 : 500;
         echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "")."changed\n";
@@ -214,13 +214,13 @@ class YellowEdit {
         if ($status=="ok") $status = $this->getUserAccount($email, "", "remove");
         if ($status=="ok" && !$this->users->isExisting($email)) $status = "unknown";
         switch ($status) {
-            case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break;
-            case "unknown": echo "ERROR updating configuration: Can't find email '$email'!\n"; break;
+            case "invalid": echo "ERROR updating settings: Please enter a valid email!\n"; break;
+            case "unknown": echo "ERROR updating settings: Can't find email '$email'!\n"; break;
         }
         if ($status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $status = $this->users->remove($fileNameUser, $email) ? "ok" : "error";
-            if ($status=="error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n";
+            if ($status=="error") echo "ERROR updating settings: Can't write file '$fileNameUser'!\n";
         }
         $statusCode = $status=="ok" ? 200 : 500;
         echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "")."removed\n";
@@ -285,7 +285,7 @@ class YellowEdit {
 
     // Process request for user login
     public function processRequestLogin($scheme, $address, $base, $location, $fileName) {
-        $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+        $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
         if ($this->users->save($fileNameUser, $this->response->userEmail)) {
             $home = $this->users->getHome($this->response->userEmail);
             if (substru($location, 0, strlenu($home))==$home) {
@@ -307,9 +307,9 @@ class YellowEdit {
         $this->response->userEmail = "";
         $this->response->destroyCookies($scheme, $address, $base);
         $location = $this->yellow->lookup->normaliseUrl(
-            $this->yellow->config->get("serverScheme"),
-            $this->yellow->config->get("serverAddress"),
-            $this->yellow->config->get("serverBase"),
+            $this->yellow->system->get("serverScheme"),
+            $this->yellow->system->get("serverAddress"),
+            $this->yellow->system->get("serverBase"),
             $location);
         $statusCode = $this->yellow->sendStatus(302, $location);
         return $statusCode;
@@ -328,12 +328,12 @@ class YellowEdit {
         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");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($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") {
-            $algorithm = $this->yellow->config->get("editUserHashAlgorithm");
+            $algorithm = $this->yellow->system->get("editUserHashAlgorithm");
             $this->response->status = substru($this->users->getHash($email), 0, 10)!="error-hash" ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Hash algorithm '$algorithm' not supported!");
         }
@@ -352,7 +352,7 @@ class YellowEdit {
         $email = $_REQUEST["email"];
         $this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
         if ($this->response->status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($fileNameUser, $email, "", "", "", "unapproved") ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -371,7 +371,7 @@ class YellowEdit {
         $email = $_REQUEST["email"];
         $this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
         if ($this->response->status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($fileNameUser, $email, "", "", "", "active") ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -409,7 +409,7 @@ class YellowEdit {
             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");
+                $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
                 $this->response->status = $this->users->save($fileNameUser, $email, $password) ? "ok" : "error";
                 if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
             }
@@ -429,7 +429,7 @@ class YellowEdit {
         $email = $_REQUEST["email"];
         $this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
         if ($this->response->status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($fileNameUser, $email, "", "", "", "active") ? "done" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -453,13 +453,13 @@ class YellowEdit {
             if ($this->response->status=="ok" && $email!=$emailSource) {
                 $pending = $emailSource;
                 $home = $this->users->getHome($emailSource);
-                $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+                $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
                 $this->response->status = $this->users->save($fileNameUser, $email, "no", $name, $language, "unverified", "", "", "", $pending, $home) ? "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");
+                $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
                 $this->response->status = $this->users->save($fileNameUser, $emailSource, "", $name, $language, "", "", "", "", $pending) ? "ok" : "error";
                 if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
             }
@@ -470,7 +470,7 @@ class YellowEdit {
             }
         } else {
             if ($this->response->status=="ok") {
-                $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+                $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
                 $this->response->status = $this->users->save($fileNameUser, $email, "", $name, $language) ? "done" : "error";
                 if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
             }
@@ -495,7 +495,7 @@ class YellowEdit {
             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");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($fileNameUser, $email, "", "", "", "unchanged") ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -520,12 +520,12 @@ class YellowEdit {
         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");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($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" && $email!=$emailSource) {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->remove($fileNameUser, $emailSource) ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -537,28 +537,28 @@ class YellowEdit {
         return $statusCode;
     }
     
-    // Process request to show software version
+    // Process request to show version
     public 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();
+        if ($this->yellow->extensions->isExisting("update")) {
+            list($statusCodeCurrent, $dataCurrent) = $this->yellow->extensions->get("update")->getExtensionsVersion();
+            list($statusCodeLatest, $dataLatest) = $this->yellow->extensions->get("update")->getExtensionsVersion(true);
+            list($statusCodeModified, $dataModified) = $this->yellow->extensions->get("update")->getExtensionsModified();
             $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeModified);
             if ($this->response->isUserWebmaster()) {
                 foreach ($dataCurrent as $key=>$value) {
                     if (strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0) {
                         ++$updates;
-                        $rawData = htmlspecialchars("$key $dataLatest[$key]")."<br />\n";
+                        $rawData = htmlspecialchars(ucfirst($key)." $dataLatest[$key]")."<br />\n";
                         $this->response->rawDataOutput .= $rawData;
                     }
                 }
                 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=\"#\" data-action=\"update\" data-status=\"update\" data-args=\"".$this->yellow->toolbox->normaliseArgs("feature:$key/option:force")."\">".$this->yellow->text->getTextHtml("editVersionUpdateForce", $this->response->language)."</a><br />\n";
-                            $rawData = preg_replace("/@software/i", htmlspecialchars("$key $dataLatest[$key]"), $rawData);
+                            $rawData = $this->yellow->text->getTextHtml("editVersionUpdateModified", $this->response->language)." - <a href=\"#\" data-action=\"update\" data-status=\"update\" data-args=\"".$this->yellow->toolbox->normaliseArgs("extension:$key/option:force")."\">".$this->yellow->text->getTextHtml("editVersionUpdateForce", $this->response->language)."</a><br />\n";
+                            $rawData = preg_replace("/@extension/i", htmlspecialchars(ucfirst($key)." $dataLatest[$key]"), $rawData);
                             $this->response->rawDataOutput .= $rawData;
                         }
                     }
@@ -579,10 +579,10 @@ class YellowEdit {
     // Process request to update website
     public function processRequestUpdate($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
-        if ($this->yellow->plugins->isExisting("update") && $this->response->isUserWebmaster()) {
-            $feature = trim($_REQUEST["feature"]);
+        if ($this->yellow->extensions->isExisting("update") && $this->response->isUserWebmaster()) {
+            $extension = trim($_REQUEST["extension"]);
             $option = trim($_REQUEST["option"]);
-            $statusCode = $this->yellow->command("update", $feature, $option);
+            $statusCode = $this->yellow->command("update", $extension, $option);
             if ($statusCode==200) {
                 $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
                 $statusCode = $this->yellow->sendStatus(303, $location);
@@ -615,7 +615,7 @@ class YellowEdit {
         $email = $_REQUEST["email"];
         $this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
         if ($this->response->status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->save($fileNameUser, $email, "", "", "", "removed") ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -624,7 +624,7 @@ class YellowEdit {
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
         }
         if ($this->response->status=="ok") {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $this->response->status = $this->users->remove($fileNameUser, $email) ? "ok" : "error";
             if ($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
@@ -712,7 +712,7 @@ class YellowEdit {
                 $rawDataFile, $this->response->rawDataEndOfLine);
             if (!$page->isError()) {
                 if ($this->yellow->lookup->isFileLocation($location)) {
-                    if ($this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir"))) {
+                    if ($this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
                         $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
                         $statusCode = $this->yellow->sendStatus(303, $location);
                     } else {
@@ -720,7 +720,7 @@ class YellowEdit {
                         $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
                     }
                 } else {
-                    if ($this->yellow->toolbox->deleteDirectory(dirname($fileName), $this->yellow->config->get("trashDir"))) {
+                    if ($this->yellow->toolbox->deleteDirectory(dirname($fileName), $this->yellow->system->get("trashDir"))) {
                         $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
                         $statusCode = $this->yellow->sendStatus(303, $location);
                     } else {
@@ -755,7 +755,7 @@ class YellowEdit {
         $fileNameShort = preg_replace("/[^\pL\d\-\.]/u", "-", basename($_FILES["file"]["name"]));
         $fileSizeMax = $this->yellow->toolbox->getNumberBytes(ini_get("upload_max_filesize"));
         $extension = strtoloweru(($pos = strrposu($fileNameShort, ".")) ? substru($fileNameShort, $pos) : "");
-        $extensions = preg_split("/\s*,\s*/", $this->yellow->config->get("editUploadExtensions"));
+        $extensions = preg_split("/\s*,\s*/", $this->yellow->system->get("editUploadExtensions"));
         if (!$this->response->isUserRestrictions() && is_uploaded_file($fileNameTemp) &&
            filesize($fileNameTemp)<=$fileSizeMax && in_array($extension, $extensions)) {
             $file = $this->response->getFileUpload($scheme, $address, $base, $location, $fileNameTemp, $fileNameShort);
@@ -773,8 +773,8 @@ class YellowEdit {
     
     // Check request
     public function checkRequest($location) {
-        $locationLength = strlenu($this->yellow->config->get("editLocation"));
-        $this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("editLocation");
+        $locationLength = strlenu($this->yellow->system->get("editLocation"));
+        $this->response->active = substru($location, 0, $locationLength)==$this->yellow->system->get("editLocation");
         return $this->response->isActive();
     }
     
@@ -834,10 +834,10 @@ class YellowEdit {
                 $email = $this->response->userFailedEmail;
                 $modified = $this->users->getModified($email);
                 $errors = $this->users->getErrors($email)+1;
-                $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
+                $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
                 $status = $this->users->save($fileNameUser, $email, "", "", "", "", "", $modified, $errors) ? "ok" : "error";
                 if ($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
-                if ($errors==$this->yellow->config->get("editBruteForceProtection")) {
+                if ($errors==$this->yellow->system->get("editBruteForceProtection")) {
                     $statusBeforeProtection = $this->users->getStatus($email);
                     $statusAfterProtection = ($statusBeforeProtection=="active" || $statusBeforeProtection=="inactive") ? "inactive" : "failed";
                     if ($status=="ok") {
@@ -878,7 +878,7 @@ class YellowEdit {
     // Return user account changes
     public function getUserAccount($email, $password, $action) {
         $status = null;
-        foreach ($this->yellow->plugins->plugins as $key=>$value) {
+        foreach ($this->yellow->extensions->extensions as $key=>$value) {
             if (method_exists($value["obj"], "onEditUserAccount")) {
                 $status = $value["obj"]->onEditUserAccount($email, $password, $action, $this->users);
                 if (!is_null($status)) break;
@@ -886,7 +886,7 @@ class YellowEdit {
         }
         if (is_null($status)) {
             $status = "ok";
-            if (!empty($password) && strlenu($password)<$this->yellow->config->get("editUserPasswordMinLength")) $status = "weak";
+            if (!empty($password) && strlenu($password)<$this->yellow->system->get("editUserPasswordMinLength")) $status = "weak";
             if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) $status = "invalid";
         }
         return $status;
@@ -895,7 +895,7 @@ class YellowEdit {
     // Return user restrictions
     public function getUserRestrictions($email, $location, $fileName) {
         $userRestrictions = null;
-        foreach ($this->yellow->plugins->plugins as $key=>$value) {
+        foreach ($this->yellow->extensions->extensions as $key=>$value) {
             if (method_exists($value["obj"], "onEditUserRestrictions")) {
                 $userRestrictions = $value["obj"]->onEditUserRestrictions($email, $location, $fileName, $this->users);
                 if (!is_null($userRestrictions)) break;
@@ -911,7 +911,7 @@ class YellowEdit {
     // Return user language
     public function getUserLanguage($email) {
         $language = $this->users->getLanguage($email);
-        if (!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
+        if (!$this->yellow->text->isLanguage($language)) $language = $this->yellow->system->get("language");
         return $language;
     }
     
@@ -925,7 +925,7 @@ class YellowEdit {
     
 class YellowResponse {
     public $yellow;             //access to API
-    public $plugin;             //access to plugin
+    public $extension;          //access to extension
     public $active;             //location is active? (boolean)
     public $userEmail;          //user email
     public $userRestrictions;   //user can change page? (boolean)
@@ -942,7 +942,7 @@ class YellowResponse {
     
     public function __construct($yellow) {
         $this->yellow = $yellow;
-        $this->plugin = $yellow->plugins->get("edit");
+        $this->extension = $yellow->extensions->get("edit");
     }
     
     // Return new page
@@ -951,23 +951,23 @@ class YellowResponse {
         $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
         $this->editContentFile($page, "create");
-        if ($this->yellow->pages->find($page->location)) {
+        if ($this->yellow->content->find($page->location)) {
             $page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"));
             $page->fileName = $this->getPageNewFile($page->location, $page->fileName, $page->get("published"));
-            while ($this->yellow->pages->find($page->location) || empty($page->fileName)) {
+            while ($this->yellow->content->find($page->location) || empty($page->fileName)) {
                 $rawData = $this->yellow->toolbox->setMetaData($page->rawData, "title", $this->getTitleNext($page->rawData));
                 $page->rawData = $this->normaliseLines($rawData, $endOfLine);
                 $page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"));
                 $page->fileName = $this->getPageNewFile($page->location, $page->fileName, $page->get("published"));
                 if (++$pageCounter>999) break;
             }
-            if ($this->yellow->pages->find($page->location) || empty($page->fileName)) {
+            if ($this->yellow->content->find($page->location) || empty($page->fileName)) {
                 $page->error(500, "Page '".$page->get("title")."' is not possible!");
             }
         } else {
             $page->fileName = $this->getPageNewFile($page->location);
         }
-        if ($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
+        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         return $page;
@@ -977,7 +977,7 @@ class YellowResponse {
     public function getPageEdit($scheme, $address, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile, $endOfLine) {
         $page = new YellowPage($this->yellow);
         $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
-        $rawData = $this->plugin->merge->merge(
+        $rawData = $this->extension->merge->merge(
             $this->normaliseLines($rawDataSource, $endOfLine),
             $this->normaliseLines($rawDataEdit, $endOfLine),
             $this->normaliseLines($rawDataFile, $endOfLine));
@@ -986,16 +986,16 @@ class YellowResponse {
         $pageSource->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $pageSource->parseData($this->normaliseLines($rawDataSource, $endOfLine), false, 0);
         $this->editContentFile($page, "edit");
-        if ($this->isMetaModified($pageSource, $page) && $page->location!=$this->yellow->pages->getHomeLocation($page->location)) {
+        if ($this->isMetaModified($pageSource, $page) && $page->location!=$this->yellow->content->getHomeLocation($page->location)) {
             $page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"), true);
             $page->fileName = $this->getPageNewFile($page->location, $page->fileName, $page->get("published"));
-            if ($page->location!=$pageSource->location && ($this->yellow->pages->find($page->location) || empty($page->fileName))) {
+            if ($page->location!=$pageSource->location && ($this->yellow->content->find($page->location) || empty($page->fileName))) {
                 $page->error(500, "Page '".$page->get("title")."' is not possible!");
             }
         }
         if (empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
-        if ($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName) ||
-            $this->plugin->getUserRestrictions($this->userEmail, $pageSource->location, $pageSource->fileName)) {
+        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName) ||
+            $this->extension->getUserRestrictions($this->userEmail, $pageSource->location, $pageSource->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         return $page;
@@ -1007,7 +1007,7 @@ class YellowResponse {
         $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
         $this->editContentFile($page, "delete");
-        if ($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
+        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         return $page;
@@ -1020,9 +1020,9 @@ class YellowResponse {
         $page->parseData($this->normaliseLines($rawData, $endOfLine), false, 200);
         $this->yellow->text->setLanguage($page->get("language"));
         $page->set("pageClass", "page-preview");
-        $page->set("pageClass", $page->get("pageClass")." template-".$page->get("template"));
+        $page->set("pageClass", $page->get("pageClass")." layout-".$page->get("layout"));
         $output = "<div class=\"".$page->getHtml("pageClass")."\"><div class=\"content\">";
-        if ($this->yellow->config->get("editToolbarButtons")!="none") $output .= "<h1>".$page->getHtml("titleContent")."</h1>\n";
+        if ($this->yellow->system->get("editToolbarButtons")!="none") $output .= "<h1>".$page->getHtml("titleContent")."</h1>\n";
         $output .= $page->getContent();
         $output .= "</div></div>";
         $page->setOutput($output);
@@ -1071,32 +1071,32 @@ class YellowResponse {
         return $data;
     }
     
-    // Return configuration data including user information
-    public function getConfigData() {
-        $data = $this->yellow->config->getData("", "Location");
+    // Return system data including user information
+    public function getSystemData() {
+        $data = $this->yellow->system->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["userName"] = $this->extension->users->getName($this->userEmail);
+            $data["userLanguage"] = $this->extension->users->getLanguage($this->userEmail);
+            $data["userStatus"] = $this->extension->users->getStatus($this->userEmail);
+            $data["userHome"] = $this->extension->users->getHome($this->userEmail);
             $data["userRestrictions"] = intval($this->isUserRestrictions());
             $data["userWebmaster"] = intval($this->isUserWebmaster());
-            $data["serverScheme"] = $this->yellow->config->get("serverScheme");
-            $data["serverAddress"] = $this->yellow->config->get("serverAddress");
-            $data["serverBase"] = $this->yellow->config->get("serverBase");
+            $data["serverScheme"] = $this->yellow->system->get("serverScheme");
+            $data["serverAddress"] = $this->yellow->system->get("serverAddress");
+            $data["serverBase"] = $this->yellow->system->get("serverBase");
             $data["serverFileSizeMax"] = $this->yellow->toolbox->getNumberBytes(ini_get("upload_max_filesize"));
             $data["serverVersion"] = "Datenstrom Yellow ".YellowCore::VERSION;
-            $data["serverPlugins"] = array();
-            foreach ($this->yellow->plugins->plugins as $key=>$value) {
-                $data["serverPlugins"][$key] = $value["plugin"];
+            $data["serverExtensions"] = array();
+            foreach ($this->yellow->extensions->extensions as $key=>$value) {
+                $data["serverExtensions"][$key] = $value["type"];
             }
             $data["serverLanguages"] = array();
             foreach ($this->yellow->text->getLanguages() as $language) {
                 $data["serverLanguages"][$language] = $this->yellow->text->getTextHtml("languageDescription", $language);
             }
-            $data["editUploadExtensions"] = $this->yellow->config->get("editUploadExtensions");
-            $data["editKeyboardShortcuts"] = $this->yellow->config->get("editKeyboardShortcuts");
+            $data["editUploadExtensions"] = $this->yellow->system->get("editUploadExtensions");
+            $data["editKeyboardShortcuts"] = $this->yellow->system->get("editKeyboardShortcuts");
             $data["editToolbarButtons"] = $this->getToolbarButtons("edit");
             $data["emojiawesomeToolbarButtons"] =  $this->getToolbarButtons("emojiawesome");
             $data["fontawesomeToolbarButtons"] =  $this->getToolbarButtons("fontawesome");
@@ -1130,24 +1130,24 @@ class YellowResponse {
     // Return toolbar buttons
     public function getToolbarButtons($name) {
         if ($name=="edit") {
-            $toolbarButtons = $this->yellow->config->get("editToolbarButtons");
+            $toolbarButtons = $this->yellow->system->get("editToolbarButtons");
             if ($toolbarButtons=="auto") {
                 $toolbarButtons = "";
-                if ($this->yellow->plugins->isExisting("markdown")) $toolbarButtons = "preview, format, bold, italic, code, list, link, file";
-                if ($this->yellow->plugins->isExisting("emojiawesome")) $toolbarButtons .= ", emojiawesome";
-                if ($this->yellow->plugins->isExisting("fontawesome")) $toolbarButtons .= ", fontawesome";
-                if ($this->yellow->plugins->isExisting("draft")) $toolbarButtons .= ", draft";
-                if ($this->yellow->plugins->isExisting("markdown")) $toolbarButtons .= ", markdown";
+                if ($this->yellow->extensions->isExisting("markdown")) $toolbarButtons = "preview, format, bold, italic, code, list, link, file";
+                if ($this->yellow->extensions->isExisting("emojiawesome")) $toolbarButtons .= ", emojiawesome";
+                if ($this->yellow->extensions->isExisting("fontawesome")) $toolbarButtons .= ", fontawesome";
+                if ($this->yellow->extensions->isExisting("draft")) $toolbarButtons .= ", draft";
+                if ($this->yellow->extensions->isExisting("markdown")) $toolbarButtons .= ", markdown";
             }
         } else {
-            $toolbarButtons = $this->yellow->config->get("{$name}ToolbarButtons");
+            $toolbarButtons = $this->yellow->system->get("{$name}ToolbarButtons");
         }
         return $toolbarButtons;
     }
     
     // Return end of line format
     public function getEndOfLine($rawData = "") {
-        $endOfLine = $this->yellow->config->get("editEndOfLine");
+        $endOfLine = $this->yellow->system->get("editEndOfLine");
         if ($endOfLine=="auto") {
             $rawData = empty($rawData) ? PHP_EOL : substru($rawData, 0, 4096);
             $endOfLine = strposu($rawData, "\r")===false ? "lf" : "crlf";
@@ -1157,19 +1157,19 @@ class YellowResponse {
     
     // Return raw data for new page
     public function getRawDataNew($page, $customTitle = false) {
-        foreach ($this->yellow->pages->path($page->location)->reverse() as $ancestor) {
-            if ($ancestor->isExisting("templateNew")) {
-                $name = $this->yellow->lookup->normaliseName($ancestor->get("templateNew"));
-                $location = $this->yellow->pages->getHomeLocation($page->location).$this->yellow->config->get("contentSharedDir");
-                $fileName = $this->yellow->lookup->findFileFromLocation($location, true).$this->yellow->config->get("newFile");
+        foreach ($this->yellow->content->path($page->location)->reverse() as $ancestor) {
+            if ($ancestor->isExisting("layoutNew")) {
+                $name = $this->yellow->lookup->normaliseName($ancestor->get("layoutNew"));
+                $location = $this->yellow->content->getHomeLocation($page->location).$this->yellow->system->get("contentSharedDir");
+                $fileName = $this->yellow->lookup->findFileFromLocation($location, true).$this->yellow->system->get("editNewFile");
                 $fileName = strreplaceu("(.*)", $name, $fileName);
                 if (is_file($fileName)) break;
             }
         }
         if (!is_file($fileName)) {
-            $name = $this->yellow->lookup->normaliseName($this->yellow->config->get("template"));
-            $location = $this->yellow->pages->getHomeLocation($page->location).$this->yellow->config->get("contentSharedDir");
-            $fileName = $this->yellow->lookup->findFileFromLocation($location, true).$this->yellow->config->get("newFile");
+            $name = $this->yellow->lookup->normaliseName($this->yellow->system->get("layout"));
+            $location = $this->yellow->content->getHomeLocation($page->location).$this->yellow->system->get("contentSharedDir");
+            $fileName = $this->yellow->lookup->findFileFromLocation($location, true).$this->yellow->system->get("editNewFile");
             $fileName = strreplaceu("(.*)", $name, $fileName);
         }
         if (is_file($fileName)) {
@@ -1177,9 +1177,9 @@ class YellowResponse {
             $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);
+            $rawData = preg_replace("/@usershort/i", strtok($this->extension->users->getName($this->userEmail), " "), $rawData);
+            $rawData = preg_replace("/@username/i", $this->extension->users->getName($this->userEmail), $rawData);
+            $rawData = preg_replace("/@userlanguage/i", $this->extension->users->getLanguage($this->userEmail), $rawData);
         } else {
             $rawData = "---\nTitle: Page\n---\n";
         }
@@ -1263,13 +1263,13 @@ class YellowResponse {
                 $path = $matches[1];
                 $text = $this->yellow->lookup->normaliseName($matches[2], true, true);
                 if (preg_match("/^[\d\-\_\.]*$/", $text)) $prefix = "";
-                $fileName = $path."/".$prefix.$text.$this->yellow->config->get("contentExtension");
+                $fileName = $path."/".$prefix.$text.$this->yellow->system->get("contentExtension");
             } else {
                 preg_match("#^(.*)\/(.+?)$#", dirname($fileName), $matches);
                 $path = $matches[1];
                 $text = $this->yellow->lookup->normaliseName($matches[2], true, false);
                 if (preg_match("/^[\d\-\_\.]*$/", $text)) $prefix = "";
-                $fileName = $path."/".$prefix.$text."/".$this->yellow->config->get("contentDefaultFile");
+                $fileName = $path."/".$prefix.$text."/".$this->yellow->system->get("contentDefaultFile");
             }
         }
         return $fileName;
@@ -1291,31 +1291,31 @@ class YellowResponse {
     
     // Return location for new file
     public function getFileNewLocation($fileNameShort, $pageLocation, $fileNewLocation) {
-        $location = empty($fileNewLocation) ? $this->yellow->config->get("editUploadNewLocation") : $fileNewLocation;
+        $location = empty($fileNewLocation) ? $this->yellow->system->get("editUploadNewLocation") : $fileNewLocation;
         $location = preg_replace("/@timestamp/i", time(), $location);
         $location = preg_replace("/@type/i", $this->yellow->toolbox->getFileType($fileNameShort), $location);
         $location = preg_replace("/@group/i", $this->getFileNewGroup($fileNameShort), $location);
         $location = preg_replace("/@folder/i", $this->getFileNewFolder($pageLocation), $location);
         $location = preg_replace("/@filename/i", strtoloweru($fileNameShort), $location);
         if (!preg_match("/^\//", $location)) {
-            $location = $this->yellow->config->get("mediaLocation").$location;
+            $location = $this->yellow->system->get("mediaLocation").$location;
         }
         return $location;
     }
     
     // Return group for new file
     public function getFileNewGroup($fileNameShort) {
-        $path = $this->yellow->config->get("mediaDir");
+        $path = $this->yellow->system->get("mediaDir");
         $fileType = $this->yellow->toolbox->getFileType($fileNameShort);
-        $fileName = $this->yellow->config->get(preg_match("/(gif|jpg|png|svg)$/", $fileType) ? "imageDir" : "downloadDir").$fileNameShort;
+        $fileName = $this->yellow->system->get(preg_match("/(gif|jpg|png|svg)$/", $fileType) ? "imageDir" : "downloadDir").$fileNameShort;
         preg_match("#^$path(.+?)\/#", $fileName, $matches);
         return strtoloweru($matches[1]);
     }
 
     // Return folder for new file
     public function getFileNewFolder($pageLocation) {
-        $parentTopLocation = $this->yellow->pages->getParentTopLocation($pageLocation);
-        if ($parentTopLocation==$this->yellow->pages->getHomeLocation($pageLocation)) $parentTopLocation .= "home";
+        $parentTopLocation = $this->yellow->content->getParentTopLocation($pageLocation);
+        if ($parentTopLocation==$this->yellow->content->getHomeLocation($pageLocation)) $parentTopLocation .= "home";
         return strtoloweru(trim($parentTopLocation, "/"));
     }
     
@@ -1348,9 +1348,9 @@ class YellowResponse {
     
     // Create browser cookies
     public function createCookies($scheme, $address, $base, $email) {
-        $expire = time() + $this->yellow->config->get("editLoginSessionTimeout");
-        $authToken = $this->plugin->users->createAuthToken($email, $expire);
-        $csrfToken = $this->plugin->users->createCsrfToken();
+        $expire = time() + $this->yellow->system->get("editLoginSessionTimeout");
+        $authToken = $this->extension->users->createAuthToken($email, $expire);
+        $csrfToken = $this->extension->users->createCsrfToken();
         setcookie("authtoken", $authToken, $expire, "$base/", "", $scheme=="https", true);
         setcookie("csrftoken", $csrfToken, $expire, "$base/", "", $scheme=="https", false);
     }
@@ -1367,20 +1367,20 @@ class YellowResponse {
             $url = "$scheme://$address$base/";
         } else {
             $expire = time() + 60*60*24;
-            $actionToken = $this->plugin->users->createActionToken($email, $action, $expire);
+            $actionToken = $this->extension->users->createActionToken($email, $action, $expire);
             $url = "$scheme://$address$base"."/action:$action/email:$email/expire:$expire/actiontoken:$actionToken/";
         }
         if ($action=="approve") {
             $account = $email;
-            $name = $this->yellow->config->get("author");
-            $email = $this->yellow->config->get("email");
+            $name = $this->yellow->system->get("author");
+            $email = $this->yellow->system->get("email");
         } else {
             $account = $email;
-            $name = $this->plugin->users->getName($email);
+            $name = $this->extension->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");
+        $language = $this->extension->users->getLanguage($email);
+        if (!$this->yellow->text->isLanguage($language)) $language = $this->yellow->system->get("language");
+        $sitename = $this->yellow->system->get("sitename");
         $prefix = "edit".ucfirst($action);
         $message = $this->yellow->text->getText("{$prefix}Message", $language);
         $message = strreplaceu("\\n", "\n", $message);
@@ -1401,7 +1401,7 @@ class YellowResponse {
     // Change content file
     public function editContentFile($page, $action) {
         if (!$page->isError()) {
-            foreach ($this->yellow->plugins->plugins as $key=>$value) {
+            foreach ($this->yellow->extensions->extensions as $key=>$value) {
                 if (method_exists($value["obj"], "onEditContentFile")) $value["obj"]->onEditContentFile($page, $action);
             }
         }
@@ -1410,7 +1410,7 @@ class YellowResponse {
     // Change media file
     public function editMediaFile($file, $action) {
         if (!$file->isError()) {
-            foreach ($this->yellow->plugins->plugins as $key=>$value) {
+            foreach ($this->yellow->extensions->extensions as $key=>$value) {
                 if (method_exists($value["obj"], "onEditMediaFile")) $value["obj"]->onEditMediaFile($file, $action);
             }
         }
@@ -1434,7 +1434,7 @@ class YellowResponse {
     
     // Check if user is webmaster
     public function isUserWebmaster() {
-        return !empty($this->userEmail) && $this->userEmail==$this->yellow->config->get("email");
+        return !empty($this->userEmail) && $this->userEmail==$this->yellow->system->get("email");
     }
     
     // Check if user has restrictions
@@ -1444,7 +1444,7 @@ class YellowResponse {
     
     // Check if login has restrictions
     public function isLoginRestrictions() {
-        return $this->yellow->config->get("editLoginRestrictions");
+        return $this->yellow->system->get("editLoginRestrictions");
     }
 }
 
@@ -1489,14 +1489,14 @@ class YellowUsers {
         } 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);
+            $name = strreplaceu(",", "-", empty($name) ? $this->yellow->system->get("sitename") : $name);
+            $language = strreplaceu(",", "-", empty($language) ? $this->yellow->system->get("language") : $language);
             $status = strreplaceu(",", "-", empty($status) ? "active" : $status);
             $stamp = strreplaceu(",", "-", empty($stamp) ? $this->createStamp() : $stamp);
             $modified = strreplaceu(",", "-", empty($modified) ? time() : $modified);
             $errors = strreplaceu(",", "-", empty($errors) ? "0" : $errors);
             $pending = strreplaceu(",", "-", empty($pending) ? "none" : $pending);
-            $home = strreplaceu(",", "-", empty($home) ? $this->yellow->config->get("editUserHome") : $home);
+            $home = strreplaceu(",", "-", empty($home) ? $this->yellow->system->get("editUserHome") : $home);
         }
         $this->set($email, $hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home);
         $fileData = $this->yellow->toolbox->readFile($fileName);
@@ -1541,7 +1541,7 @@ class YellowUsers {
     
     // Check user authentication from email and password
     public function checkAuthLogin($email, $password) {
-        $algorithm = $this->yellow->config->get("editUserHashAlgorithm");
+        $algorithm = $this->yellow->system->get("editUserHashAlgorithm");
         return $this->isExisting($email) && $this->users[$email]["status"]=="active" &&
             $this->yellow->toolbox->verifyHash($password, $algorithm, $this->users[$email]["hash"]);
     }
@@ -1584,8 +1584,8 @@ class YellowUsers {
     
     // Create password hash
     public function createHash($password) {
-        $algorithm = $this->yellow->config->get("editUserHashAlgorithm");
-        $cost = $this->yellow->config->get("editUserHashCost");
+        $algorithm = $this->yellow->system->get("editUserHashAlgorithm");
+        $cost = $this->yellow->system->get("editUserHashCost");
         $hash = $this->yellow->toolbox->createHash($password, $algorithm, $cost);
         if (empty($hash)) $hash = "error-hash-algorithm-$algorithm";
         return $hash;

+ 0 - 0
system/plugins/edit.woff → system/extensions/edit.woff


+ 9 - 0
system/extensions/flatsite.php

@@ -0,0 +1,9 @@
+<?php
+// Flatsite extension, https://github.com/datenstrom/yellow-extensions/tree/master/themes/flatsite
+// Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+class YellowFlatsite {
+    const VERSION = "0.8.2";
+    const TYPE = "theme";
+}

+ 24 - 23
system/plugins/image.php → system/extensions/image.php

@@ -1,23 +1,24 @@
 <?php
-// Image plugin, https://github.com/datenstrom/yellow-plugins/tree/master/image
+// Image extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/image
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowImage {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     public $yellow;             //access to API
     public $graphicsLibrary;    //graphics library support? (boolean)
 
     // Handle initialisation
     public function onLoad($yellow) {
         $this->yellow = $yellow;
-        $this->yellow->config->setDefault("imageAlt", "Image");
-        $this->yellow->config->setDefault("imageUploadWidthMax", "1280");
-        $this->yellow->config->setDefault("imageUploadHeightMax", "1280");
-        $this->yellow->config->setDefault("imageUploadJpgQuality", "80");
-        $this->yellow->config->setDefault("imageThumbnailLocation", "/media/thumbnails/");
-        $this->yellow->config->setDefault("imageThumbnailDir", "media/thumbnails/");
-        $this->yellow->config->setDefault("imageThumbnailJpgQuality", "80");
+        $this->yellow->system->setDefault("imageAlt", "Image");
+        $this->yellow->system->setDefault("imageUploadWidthMax", "1280");
+        $this->yellow->system->setDefault("imageUploadHeightMax", "1280");
+        $this->yellow->system->setDefault("imageUploadJpgQuality", "80");
+        $this->yellow->system->setDefault("imageThumbnailLocation", "/media/thumbnails/");
+        $this->yellow->system->setDefault("imageThumbnailDir", "media/thumbnails/");
+        $this->yellow->system->setDefault("imageThumbnailJpgQuality", "80");
         $this->graphicsLibrary = $this->isGraphicsLibrary();
     }
 
@@ -26,17 +27,17 @@ class YellowImage {
         $output = null;
         if ($name=="image" && $type=="inline") {
             if (!$this->graphicsLibrary) {
-                $this->yellow->page->error(500, "Plugin 'image' requires GD library with gif/jpg/png support!");
+                $this->yellow->page->error(500, "Image extension requires GD library with gif/jpg/png support!");
                 return $output;
             }
             list($name, $alt, $style, $width, $height) = $this->yellow->toolbox->getTextArgs($text);
             if (!preg_match("/^\w+:/", $name)) {
-                if (empty($alt)) $alt = $this->yellow->config->get("imageAlt");
+                if (empty($alt)) $alt = $this->yellow->system->get("imageAlt");
                 if (empty($width)) $width = "100%";
                 if (empty($height)) $height = $width;
-                list($src, $width, $height) = $this->getImageInformation($this->yellow->config->get("imageDir").$name, $width, $height);
+                list($src, $width, $height) = $this->getImageInformation($this->yellow->system->get("imageDir").$name, $width, $height);
             } else {
-                if (empty($alt)) $alt = $this->yellow->config->get("imageAlt");
+                if (empty($alt)) $alt = $this->yellow->system->get("imageAlt");
                 $src = $this->yellow->lookup->normaliseUrl("", "", "", $name);
                 $width = $height = 0;
             }
@@ -55,17 +56,17 @@ class YellowImage {
             $fileName = $file->fileName;
             $fileType = $this->yellow->toolbox->getFileType($file->get("fileNameShort"));
             list($widthInput, $heightInput, $type) = $this->yellow->toolbox->detectImageInformation($fileName, $fileType);
-            $widthMax = $this->yellow->config->get("imageUploadWidthMax");
-            $heightMax = $this->yellow->config->get("imageUploadHeightMax");
+            $widthMax = $this->yellow->system->get("imageUploadWidthMax");
+            $heightMax = $this->yellow->system->get("imageUploadHeightMax");
             if (($widthInput>$widthMax || $heightInput>$heightMax) && ($type=="gif" || $type=="jpg" || $type=="png")) {
                 list($widthOutput, $heightOutput) = $this->getImageDimensionsFit($widthInput, $heightInput, $widthMax, $heightMax);
                 $image = $this->loadImage($fileName, $type);
                 $image = $this->resizeImage($image, $widthInput, $heightInput, $widthOutput, $heightOutput);
-                if (!$this->saveImage($image, $fileName, $type, $this->yellow->config->get("imageUploadJpgQuality"))) {
+                if (!$this->saveImage($image, $fileName, $type, $this->yellow->system->get("imageUploadJpgQuality"))) {
                     $file->error(500, "Can't write file '$fileName'!");
                 }
             }
-            if ($this->yellow->config->get("safeMode") && $fileType=="svg") {
+            if ($this->yellow->system->get("safeMode") && $fileType=="svg") {
                 $output = $this->sanitiseXmlData($this->yellow->toolbox->readFile($fileName));
                 if (empty($output) || !$this->yellow->toolbox->createFile($fileName, $output)) {
                      $file->error(500, "Can't write file '$fileName'!");
@@ -89,7 +90,7 @@ class YellowImage {
         $statusCode = 0;
         list($command, $path) = $args;
         if ($path=="all") {
-            $path = $this->yellow->config->get("imageThumbnailDir");
+            $path = $this->yellow->system->get("imageThumbnailDir");
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/.*/", false, false) as $entry) {
                 if (!$this->yellow->toolbox->deleteFile($entry)) $statusCode = 500;
             }
@@ -100,29 +101,29 @@ class YellowImage {
 
     // Return image info, create thumbnail on demand
     public function getImageInformation($fileName, $widthOutput, $heightOutput) {
-        $fileNameShort = substru($fileName, strlenu($this->yellow->config->get("imageDir")));
+        $fileNameShort = substru($fileName, strlenu($this->yellow->system->get("imageDir")));
         list($widthInput, $heightInput, $type) = $this->yellow->toolbox->detectImageInformation($fileName);
         $widthOutput = $this->convertValueAndUnit($widthOutput, $widthInput);
         $heightOutput = $this->convertValueAndUnit($heightOutput, $heightInput);
         if (($widthInput==$widthOutput && $heightInput==$heightOutput) || $type=="svg") {
-            $src = $this->yellow->config->get("serverBase").$this->yellow->config->get("imageLocation").$fileNameShort;
+            $src = $this->yellow->system->get("serverBase").$this->yellow->system->get("imageLocation").$fileNameShort;
             $width = $widthOutput;
             $height = $heightOutput;
         } else {
             $fileNameThumb = ltrim(str_replace(array("/", "\\", "."), "-", dirname($fileNameShort)."/".pathinfo($fileName, PATHINFO_FILENAME)), "-");
             $fileNameThumb .= "-".$widthOutput."x".$heightOutput;
             $fileNameThumb .= ".".pathinfo($fileName, PATHINFO_EXTENSION);
-            $fileNameOutput = $this->yellow->config->get("imageThumbnailDir").$fileNameThumb;
+            $fileNameOutput = $this->yellow->system->get("imageThumbnailDir").$fileNameThumb;
             if ($this->isFileNotUpdated($fileName, $fileNameOutput)) {
                 $image = $this->loadImage($fileName, $type);
                 $image = $this->resizeImage($image, $widthInput, $heightInput, $widthOutput, $heightOutput);
                 if (is_file($fileNameOutput)) $this->yellow->toolbox->deleteFile($fileNameOutput);
-                if (!$this->saveImage($image, $fileNameOutput, $type, $this->yellow->config->get("imageThumbnailJpgQuality")) ||
+                if (!$this->saveImage($image, $fileNameOutput, $type, $this->yellow->system->get("imageThumbnailJpgQuality")) ||
                     !$this->yellow->toolbox->modifyFile($fileNameOutput, $this->yellow->toolbox->getFileModified($fileName))) {
                     $this->yellow->page->error(500, "Can't write file '$fileNameOutput'!");
                 }
             }
-            $src = $this->yellow->config->get("serverBase").$this->yellow->config->get("imageThumbnailLocation").$fileNameThumb;
+            $src = $this->yellow->system->get("serverBase").$this->yellow->system->get("imageThumbnailLocation").$fileNameThumb;
             list($width, $height) = $this->yellow->toolbox->detectImageInformation($fileNameOutput);
         }
         return array($src, $width, $height);

BIN
system/extensions/install-blog.zip


BIN
system/extensions/install-languages.zip


BIN
system/extensions/install-wiki.zip


+ 96 - 96
system/plugins/install.php → system/extensions/install.php

@@ -1,10 +1,11 @@
 <?php
-// Install plugin, https://github.com/datenstrom/yellow
+// Install extension, https://github.com/datenstrom/yellow
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowInstall {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     const PRIORITY = "1";
     public $yellow;                 //access to API
     
@@ -30,11 +31,11 @@ class YellowInstall {
         return $this->processCommandInstall();
     }
     
-    // Process command to set up website
+    // Process command to install website
     public function processCommandInstall() {
-        $statusCode = $this->updateLanguage();
-        if ($statusCode==200) $statusCode = $this->updateConfig($this->getConfigData());
-        if ($statusCode==200) $statusCode = $this->removeInstall();
+        $statusCode = $this->updateLanguages();
+        if ($statusCode==200) $statusCode = $this->updateSettings($this->getSystemData());
+        if ($statusCode==200) $statusCode = $this->removeFiles();
         if ($statusCode==200) {
             $statusCode = 0;
         } else {
@@ -44,28 +45,28 @@ class YellowInstall {
         return $statusCode;
     }
     
-    // Process request to set up website
+    // Process request to install website
     public function processRequestInstall($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
         $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
         $email = trim($_REQUEST["email"]);
         $password = trim($_REQUEST["password"]);
         $language = trim($_REQUEST["language"]);
-        $feature = trim($_REQUEST["feature"]);
+        $extension = trim($_REQUEST["extension"]);
         $status = trim($_REQUEST["status"]);
-        $this->yellow->pages->pages["root/"] = array();
+        $this->yellow->content->pages["root/"] = array();
         $this->yellow->page = new YellowPage($this->yellow);
-        $statusCode = $this->updateLanguage();
+        $statusCode = $this->updateLanguages();
         $this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $this->yellow->page->parseData($this->getRawDataInstall(), false, $statusCode, $this->yellow->page->get("pageError"));
         $this->yellow->page->safeMode = false;
         if ($status=="install") $status = $this->updateUser($email, $password, $name, $language)==200 ? "ok" : "error";
-        if ($status=="ok") $status = $this->updateFeature($feature)==200 ? "ok" : "error";
+        if ($status=="ok") $status = $this->updateExtension($extension)==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "Home", "/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "About", "/about/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "Footer", "/shared/footer")==200 ? "ok" : "error";
-        if ($status=="ok") $status = $this->updateConfig($this->getConfigData()) ? "ok" : "error";
-        if ($status=="ok") $status = $this->removeInstall() ? "done" : "error";
+        if ($status=="ok") $status = $this->updateSettings($this->getSystemData()) ? "ok" : "error";
+        if ($status=="ok") $status = $this->removeFiles() ? "done" : "error";
         if ($status=="done") {
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
@@ -75,48 +76,51 @@ class YellowInstall {
         return $statusCode;
     }
     
-    // Update language
-    public function updateLanguage() {
+    // Update languages
+    public function updateLanguages() {
         $statusCode = 200;
-        $path = $this->yellow->config->get("pluginDir")."install-language.zip";
-        if (is_file($path) && $this->yellow->plugins->isExisting("update")) {
+        $path = $this->yellow->system->get("extensionDir")."install-languages.zip";
+        if (is_file($path) && $this->yellow->extensions->isExisting("update")) {
             $zip = new ZipArchive();
             if ($zip->open($path)===true) {
-                if (defined("DEBUG") && DEBUG>=2) echo "YellowInstall::updateLanguage file:$path<br/>\n";
-                $languages = $this->getLanguageData("en, de, fr");
+                if (defined("DEBUG") && DEBUG>=2) echo "YellowInstall::updateLanguages file:$path<br/>\n";
+                $languages = $this->detectBrowserLanguages("en, de, fr");
+                $languagesFound = array();
+                foreach ($languages as $language) $languagesFound[$language] = "";
                 if (preg_match("#^(.*\/).*?$#", $zip->getNameIndex(0), $matches)) $pathBase = $matches[1];
-                $fileData = $zip->getFromName($pathBase.$this->yellow->config->get("updateInformationFile"));
+                $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateInformationFile"));
                 foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                     preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                         list($dummy, $entry) = explode("/", $matches[1], 2);
-                        if (preg_match("/^language-(.*)\.txt$/", $entry, $tokens) && !is_null($languages[$tokens[1]])) {
-                            $languages[$tokens[1]] = $entry;
+                        $language = array_pop(explode(",", $matches[2]));
+                        if (preg_match("/^(.*)\.php$/", basename($entry), $tokens) && in_array($language, $languages)) {
+                            $languagesFound[$language] = $tokens[1];
                         }
                     }
                 }
-                $languages = array_slice(array_filter($languages, "strlen"), 0, 3);
+                $languagesFound = array_slice(array_filter($languagesFound, "strlen"), 0, 3);
                 foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                     preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                    if (lcfirst($matches[1])=="plugin" || lcfirst($matches[1])=="theme") $software = $matches[2];
+                    if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
                     if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                         list($dummy, $entry) = explode("/", $matches[1], 2);
                         list($fileName) = explode(",", $matches[2], 2);
-                        $fileData = $zip->getFromName($pathBase.$entry);
-                        if (preg_match("/^language.php$/", $entry)) {
-                            $statusCode = $this->yellow->plugins->get("update")->updateSoftwareFile($fileName, $fileData,
-                                $modified, 0, 0, "create,update", false, $software);
+                        $fileData = $zip->getFromName($pathBase.basename($entry));
+                        if (preg_match("/^(.*).php$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
+                            $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
+                                $modified, 0, 0, "create,update", false, $extension);
                         }
-                        if (preg_match("/^language-(.*)\.txt$/", $entry, $tokens) && !is_null($languages[$tokens[1]])) {
-                            $statusCode = $this->yellow->plugins->get("update")->updateSoftwareFile($fileName, $fileData,
-                                $modified, 0, 0, "create,update", false, $software);
+                        if (preg_match("/^(.*)-language\.txt$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
+                            $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
+                                $modified, 0, 0, "create,update", false, $extension);
                         }
                     }
                 }
                 $zip->close();
                 if ($statusCode==200) {
-                    $this->yellow->text->load($this->yellow->config->get("pluginDir").$this->yellow->config->get("languageFile"), "");
+                    $this->yellow->text->load($this->yellow->system->get("extensionDir").$this->yellow->system->get("languageFile"), "");
                 }
             } else {
                 $statusCode = 500;
@@ -129,23 +133,23 @@ class YellowInstall {
     // Update user
     public function updateUser($email, $password, $name, $language) {
         $statusCode = 200;
-        if (!empty($email) && !empty($password) && $this->yellow->plugins->isExisting("edit")) {
-            $fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
-            $status = $this->yellow->plugins->get("edit")->users->save($fileNameUser, $email, $password, $name, $language) ? "ok" : "error";
+        if (!empty($email) && !empty($password) && $this->yellow->extensions->isExisting("edit")) {
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
+            $status = $this->yellow->extensions->get("edit")->users->save($fileNameUser, $email, $password, $name, $language) ? "ok" : "error";
             if ($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
         }
         return $statusCode;
     }
     
-    // Update feature
-    public function updateFeature($feature) {
+    // Update extension
+    public function updateExtension($extension) {
         $statusCode = 200;
-        $path = $this->yellow->config->get("pluginDir");
-        if (!empty($feature) && $this->yellow->plugins->isExisting("update")) {
+        $path = $this->yellow->system->get("extensionDir");
+        if (!empty($extension) && $this->yellow->extensions->isExisting("update")) {
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
                 if (preg_match("/^install-(.*?)\./", basename($entry), $matches)) {
-                    if (strtoloweru($matches[1])==strtoloweru($feature)) {
-                        $statusCode = $this->yellow->plugins->get("update")->updateSoftwareArchive($entry);
+                    if (strtoloweru($matches[1])==strtoloweru($extension)) {
+                        $statusCode = $this->yellow->extensions->get("update")->updateExtensionArchive($entry);
                         break;
                     }
                 }
@@ -174,22 +178,22 @@ class YellowInstall {
         return $statusCode;
     }
     
-    // Update config
-    public function updateConfig($config) {
+    // Update settings
+    public function updateSettings($settings) {
         $statusCode = 200;
-        $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-        if (!$this->yellow->config->save($fileNameConfig, $config)) {
+        $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+        if (!$this->yellow->system->save($fileName, $settings)) {
             $statusCode = 500;
-            $this->yellow->page->error($statusCode, "Can't write file '$fileNameConfig'!");
+            $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
         }
         return $statusCode;
     }
     
-    // Remove install
-    public function removeInstall() {
+    // Remove files used by installation
+    public function removeFiles() {
         $statusCode = 200;
         if (function_exists("opcache_reset")) opcache_reset();
-        $path = $this->yellow->config->get("pluginDir");
+        $path = $this->yellow->system->get("extensionDir");
         foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
             if (preg_match("/^install-(.*?)\./", basename($entry), $matches)) {
                 if (!$this->yellow->toolbox->deleteFile($entry)) {
@@ -198,19 +202,19 @@ class YellowInstall {
                 }
             }
         }
-        $path = $this->yellow->config->get("pluginDir")."install.php";
+        $path = $this->yellow->system->get("extensionDir")."install.php";
         if ($statusCode==200 && !$this->yellow->toolbox->deleteFile($path)) {
             $statusCode = 500;
             $this->yellow->page->error($statusCode, "Can't delete file '$path'!");
         }
-        if ($statusCode==200) unset($this->yellow->plugins->plugins["install"]);
+        if ($statusCode==200) unset($this->yellow->extensions->extensions["install"]);
         return $statusCode;
     }
     
     // Check web server rewrite
     public function checkServerRewrite($scheme, $address, $base, $location, $fileName) {
         $curlHandle = curl_init();
-        $location = $this->yellow->config->get("assetLocation").$this->yellow->config->get("theme").".css";
+        $location = $this->yellow->system->get("resourceLocation").$this->yellow->lookup->normaliseName($this->yellow->system->get("theme")).".css";
         $url = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
         curl_setopt($curlHandle, CURLOPT_URL, $url);
         curl_setopt($curlHandle, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; YellowCore/".YellowCore::VERSION).")";
@@ -224,30 +228,30 @@ class YellowInstall {
     
     // Check web server read/write access
     public function checkServerAccess() {
-        $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-        return $this->yellow->config->save($fileNameConfig, array());
+        $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+        return $this->yellow->system->save($fileName, array());
     }
 
-    // Return language data, detect browser languages
-    public function getLanguageData($languagesDefault) {
-        $data = array();
+    // Detect web browser languages
+    public function detectBrowserLanguages($languagesDefault) {
+        $languages = array();
         if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
             foreach (preg_split("/\s*,\s*/", $_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $string) {
                 list($language) = explode(";", $string);
-                if (!empty($language)) $data[$language] = "";
+                if (!empty($language)) array_push($languages, $language);
             }
         }
         foreach (preg_split("/\s*,\s*/", $languagesDefault) as $language) {
-            if (!empty($language)) $data[$language] = "";
+            if (!empty($language)) array_push($languages, $language);
         }
-        return $data;
+        return array_unique($languages);
     }
     
-    // Return configuration data, detect server URL
-    public function getConfigData() {
+    // Return system data, detect server URL
+    public function getSystemData() {
         $data = array();
         foreach ($_REQUEST as $key=>$value) {
-            if (!$this->yellow->config->isExisting($key)) continue;
+            if (!$this->yellow->system->isExisting($key)) continue;
             $data[$key] = trim($value);
         }
         $data["timezone"] = $this->yellow->toolbox->getTimezone();
@@ -258,46 +262,42 @@ class YellowInstall {
 
     // Return raw data for install page
     public function getRawDataInstall() {
-        $language = $this->yellow->toolbox->detectBrowserLanguage($this->yellow->text->getLanguages(), $this->yellow->config->get("language"));
-        $fileName = strreplaceu("(.*)", "install", $this->yellow->config->get("configDir").$this->yellow->config->get("newFile"));
-        $rawData = $this->yellow->toolbox->readFile($fileName);
-        if (empty($rawData)) {
-            $this->yellow->text->setLanguage($language);
-            $rawData = "---\nTitle:".$this->yellow->text->get("installTitle")."\nLanguage:$language\nNavigation:navigation\n---\n";
-            $rawData .= "<form class=\"install-form\" action=\"".$this->yellow->page->getLocation(true)."\" method=\"post\">\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>";
-                foreach ($this->yellow->text->getLanguages() as $language) {
-                    $checked = $language==$this->yellow->text->language ? " checked=\"checked\"" : "";
-                    $rawData .= "<label for=\"$language\"><input type=\"radio\" name=\"language\" id=\"$language\" value=\"$language\"$checked> ".$this->yellow->text->getTextHtml("languageDescription", $language)."</label><br />";
-                }
-                $rawData .= "</p>\n";
+        $language = $this->yellow->toolbox->detectBrowserLanguage($this->yellow->text->getLanguages(), $this->yellow->system->get("language"));
+        $this->yellow->text->setLanguage($language);
+        $rawData = "---\nTitle:".$this->yellow->text->get("installTitle")."\nLanguage:$language\nNavigation:navigation\n---\n";
+        $rawData .= "<form class=\"install-form\" action=\"".$this->yellow->page->getLocation(true)."\" method=\"post\">\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>";
+            foreach ($this->yellow->text->getLanguages() as $language) {
+                $checked = $language==$this->yellow->text->language ? " checked=\"checked\"" : "";
+                $rawData .= "<label for=\"$language\"><input type=\"radio\" name=\"language\" id=\"$language\" value=\"$language\"$checked> ".$this->yellow->text->getTextHtml("languageDescription", $language)."</label><br />";
             }
-            if (count($this->getFeaturesInstall())>1) {
-                $rawData .= "<p>".$this->yellow->text->get("installFeature")."<p>";
-                foreach ($this->getFeaturesInstall() as $feature) {
-                    $checked = $feature=="website" ? " checked=\"checked\"" : "";
-                    $rawData .= "<label for=\"$feature\"><input type=\"radio\" name=\"feature\" id=\"$feature\" value=\"$feature\"$checked> ".ucfirst($feature)."</label><br />";
-                }
-                $rawData .= "</p>\n";
+            $rawData .= "</p>\n";
+        }
+        if (count($this->getExtensionsInstall())>1) {
+            $rawData .= "<p>".$this->yellow->text->get("installExtension")."<p>";
+            foreach ($this->getExtensionsInstall() as $extension) {
+                $checked = $extension=="website" ? " checked=\"checked\"" : "";
+                $rawData .= "<label for=\"$extension\"><input type=\"radio\" name=\"extension\" id=\"$extension\" value=\"$extension\"$checked> ".ucfirst($extension)."</label><br />";
             }
-            $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";
+            $rawData .= "</p>\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";
         return $rawData;
     }
     
-    // Return features for install page
-    public function getFeaturesInstall() {
-        $features = array("website");
-        $path = $this->yellow->config->get("pluginDir");
+    // Return extensions for install page
+    public function getExtensionsInstall() {
+        $extensions = array("website");
+        $path = $this->yellow->system->get("extensionDir");
         foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false, false) as $entry) {
-            if (preg_match("/^install-(.*?)\./", $entry, $matches) && $matches[1]!="language") array_push($features, $matches[1]);
+            if (preg_match("/^install-(.*?)\./", $entry, $matches) && $matches[1]!="languages") array_push($extensions, $matches[1]);
         }
-        return $features;
+        return $extensions;
     }
 }

+ 6 - 5
system/plugins/markdown.php → system/extensions/markdown.php

@@ -1,10 +1,11 @@
 <?php
-// Markdown plugin, https://github.com/datenstrom/yellow-plugins/tree/master/markdown
+// Markdown extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/markdown
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowMarkdown {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     public $yellow;         //access to API
     
     // Handle initialisation
@@ -3732,7 +3733,7 @@ class MarkdownExtraParser extends MarkdownParser {
 	}
 }
 
-// Markdown extra parser extensions
+// Yellow Markdown extra extension
 // Copyright (c) 2013-2019 Datenstrom
 
 class YellowMarkdownExtraParser extends MarkdownExtraParser {
@@ -3840,8 +3841,8 @@ class YellowMarkdownExtraParser extends MarkdownExtraParser {
         $width = $height = 0;
         $src = $matches[3]=="" ? $matches[4] : $matches[3];
         if (!preg_match("/^\w+:/", $src)) {
-            list($width, $height) = $this->yellow->toolbox->detectImageInformation($this->yellow->config->get("imageDir").$src);
-            $src = $this->yellow->config->get("serverBase").$this->yellow->config->get("imageLocation").$src;
+            list($width, $height) = $this->yellow->toolbox->detectImageInformation($this->yellow->system->get("imageDir").$src);
+            $src = $this->yellow->system->get("serverBase").$this->yellow->system->get("imageLocation").$src;
         }
         $alt = $matches[2];
         $title = $matches[7]=="" ? $matches[2] : $matches[7];

+ 291 - 251
system/plugins/update.php → system/extensions/update.php

@@ -1,10 +1,11 @@
 <?php
-// Update plugin, https://github.com/datenstrom/yellow-plugins/tree/master/update
+// Update extension, https://github.com/datenstrom/yellow-extensions/tree/master/features/update
 // Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
 // This file may be used and distributed under the terms of the public license.
 
 class YellowUpdate {
-    const VERSION = "0.8.1";
+    const VERSION = "0.8.2";
+    const TYPE = "feature";
     const PRIORITY = "2";
     public $yellow;                 //access to API
     public $updates;                //number of updates
@@ -12,81 +13,135 @@ class YellowUpdate {
     // Handle initialisation
     public function onLoad($yellow) {
         $this->yellow = $yellow;
-        $this->yellow->config->setDefault("updatePluginsUrl", "https://github.com/datenstrom/yellow-plugins");
-        $this->yellow->config->setDefault("updateThemesUrl", "https://github.com/datenstrom/yellow-themes");
-        $this->yellow->config->setDefault("updateInformationFile", "update.ini");
-        $this->yellow->config->setDefault("updateVersionFile", "version.ini");
-        $this->yellow->config->setDefault("updateResourceFile", "resource.ini");
+        $this->yellow->system->setDefault("updateExtensionUrl", "https://github.com/datenstrom/yellow-extensions");
+        $this->yellow->system->setDefault("updateInformationFile", "update.ini");
+        $this->yellow->system->setDefault("updateVersionFile", "version.ini");
+        $this->yellow->system->setDefault("updateWaffleFile", "waffle.ini");
     }
     
     // Handle startup
     public function onStartup($update) {
-        if ($update) { //TODO: remove later, converts old config
-            $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-            if ($this->yellow->config->isExisting("parserSafeMode")) {
-                $this->yellow->config->save($fileNameConfig, array("safeMode" => $this->yellow->config->get("parserSafeMode")));
+        if ($update) {  //TODO: remove later, converts old API in layouts
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            if ($this->yellow->system->isExisting("templateDir")) {
+                $path = $this->yellow->system->get("layoutDir");
+                foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.html$/", true, false) as $entry) {
+                    $fileData = $fileDataNew = $this->yellow->toolbox->readFile($entry);
+                    $fileDataNew = str_replace("\$yellow->", "\$this->yellow->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->config->", "yellow->system->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->pages->", "yellow->content->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->files->", "yellow->media->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->plugins->", "yellow->extensions->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->themes->", "yellow->extensions->", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->snippet(", "yellow->layout(", $fileDataNew);
+                    $fileDataNew = str_replace("yellow->getSnippetArgs(", "yellow->getLayoutArgs(", $fileDataNew);
+                    $fileDataNew = str_replace("\"template\"", "\"layout\"", $fileDataNew);
+                    $fileDataNew = str_replace("\"page template-\"", "\"page layout-\"", $fileDataNew);
+                    if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
+                        $fileDataError .= "ERROR writing file '$entry'!\n";
+                    }
+                }
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
-            if ($this->yellow->config->get("staticDir")=="cache/") {
-                $this->yellow->config->save($fileNameConfig, array("staticDir" => "public/"));
+        }
+        if ($update) {  //TODO: remove later, converts old website icon
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            if ($this->yellow->system->isExisting("siteicon")) {
+                $theme = $this->yellow->system->get("theme");
+                $fileName = $this->yellow->system->get("resourceDir")."icon.png";
+                $fileNameNew = $this->yellow->system->get("resourceDir").$this->yellow->lookup->normaliseName($theme)."-icon.png";
+                if (is_file($fileName) && !$this->yellow->toolbox->renameFile($fileName, $fileNameNew)) {
+                    $fileDataError .= "ERROR renaming file '$fileName'!\n";
+                }
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
         }
-        if ($update) {  //TODO: remove later, converts old robots file
-            $fileNameRobots = $this->yellow->config->get("configDir")."robots.txt";
-            $fileNameError = $this->yellow->config->get("configDir")."system-error.log";
-            if (is_file($fileNameRobots)) {
-                if (!$this->yellow->toolbox->renameFile($fileNameRobots, "./robots.txt")) {
-                    $fileDataError .= "ERROR moving file '$fileNameRobots'!\n";
+        if ($update) {  //TODO: remove later, converts old language files
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            if ($this->yellow->system->isExisting("languageFile")) {
+                $path = $this->yellow->system->get("extensionDir");
+                foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
+                    preg_match("/^language-(.*)\.txt$/", basename($entry), $matches);
+                    $languageName = $this->getLanguageName($matches[1]);
+                    if (!empty($languageName)) {
+                        $entryNew = $path.$languageName."-language.txt";
+                        if (!$this->yellow->toolbox->renameFile($entry, $entryNew)) {
+                            $fileDataError .= "ERROR renaming file '$entry'!\n";
+                        }
+                        $fileNameNew = $path.$languageName.".php";
+                        $fileDataNew = "<?php\n\nclass Yellow".ucfirst($languageName)." {\nconst VERSION = \"0.8.2\";\nconst TYPE = \"language\";\n}\n";
+                        if (!$this->yellow->toolbox->createFile($fileNameNew, $fileDataNew)) {
+                            $fileDataError .= "ERROR writing file '$fileNameNew'!\n";
+                        }
+                    }
                 }
-                if (!empty($fileDataError)) {
-                    $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
+                $fileName = $this->yellow->system->get("extensionDir")."language.php";
+                if (is_file($fileName) && !$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
+                    $fileDataError .= "ERROR deleting file '$fileName'!\n";
                 }
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
         }
-        if ($update) {  //TODO: remove later, converts old Markdown extension
-            $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-            $fileNameError = $this->yellow->config->get("configDir")."system-error.log";
-            if ($this->yellow->config->get("contentDefaultFile")=="page.txt") {
-                $config = array("contentDefaultFile" => "page.md", "contentExtension" => ".md",
-                    "errorFile" => "page-error-(.*).md", "newFile" => "page-new-(.*).md");
-                $this->yellow->config->save($fileNameConfig, $config);
-                $path = $this->yellow->config->get("contentDir");
+        if ($update) {  //TODO: remove later, converts old Markdown files
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            if ($this->yellow->system->get("contentDefaultFile")=="page.txt") {
+                $settings = array("contentDefaultFile" => "page.md", "contentExtension" => ".md", "editNewFile" => "page-new-(.*).md");
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+                if (!$this->yellow->system->save($fileName, $settings)) {
+                    $fileDataError .= "ERROR writing file '$fileName'!\n";
+                }
+                $path = $this->yellow->system->get("contentDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.txt$/", true, false) as $entry) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
                         $fileDataError .= "ERROR renaming file '$entry'!\n";
                     }
                 }
-                $path = $this->yellow->config->get("configDir");
+                $path = $this->yellow->system->get("settingDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
                         $fileDataError .= "ERROR renaming file '$entry!'\n";
                     }
                 }
-                if (!empty($fileDataError)) {
-                    $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
+                $_GET["clean-url"] = "system-updated";
+            }
+        }
+        if ($update) {  //TODO: remove later, converts old template setting
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            if ($this->yellow->system->isExisting("template")) {
+                $path = $this->yellow->system->get("contentDir");
+                foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.md$/", true, false) as $entry) {
+                    $fileData = $fileDataNew = $this->yellow->toolbox->readFile($entry);
+                    $fileDataNew = preg_replace("/Template:/i", "Layout:", $fileDataNew);
+                    $fileDataNew = preg_replace("/TemplateNew:/i", "LayoutNew:", $fileDataNew);
+                    if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
+                        $fileDataError .= "ERROR writing file '$entry'!\n";
+                    }
                 }
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
                 $_GET["clean-url"] = "system-updated";
             }
         }
         if ($update) {  //TODO: remove later, updates shared pages
-            $fileNameError = $this->yellow->config->get("configDir")."system-error.log";
-            $pathConfig = $this->yellow->config->get("configDir");
-            $pathShared = $this->yellow->config->get("contentDir").$this->yellow->config->get("contentSharedDir");
-            if (count($this->yellow->toolbox->getDirectoryEntries($pathConfig, "/.*/", false, false))>3) {
+            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+            $pathSetting = $this->yellow->system->get("settingDir");
+            $pathShared = $this->yellow->system->get("contentDir").$this->yellow->system->get("contentSharedDir");
+            if (count($this->yellow->toolbox->getDirectoryEntries($pathSetting, "/.*/", false, false))>3) {
                 $regex = "/^page-error-(.*)\.md$/";
-                foreach ($this->yellow->toolbox->getDirectoryEntries($pathConfig, $regex, true, false) as $entry) {
-                    if (!$this->yellow->toolbox->deleteFile($entry, $this->yellow->config->get("trashDir"))) {
+                foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
+                    if (!$this->yellow->toolbox->deleteFile($entry, $this->yellow->system->get("trashDir"))) {
                         $fileDataError .= "ERROR deleting file '$entry'!\n";
                     }
                 }
                 $regex = "/^page-new-(.*)\.md$/";
-                foreach ($this->yellow->toolbox->getDirectoryEntries($pathConfig, $regex, true, false) as $entry) {
-                    if (!$this->yellow->toolbox->renameFile($entry, str_replace($pathConfig, $pathShared, $entry), true)) {
+                foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
+                    if (!$this->yellow->toolbox->renameFile($entry, str_replace($pathSetting, $pathShared, $entry), true)) {
                         $fileDataError .= "ERROR moving file '$entry'!\n";
                     }
                 }
                 $fileNameHeader = $pathShared."header.md";
-                if (!is_file($fileNameHeader) && $this->yellow->config->isExisting("tagline")) {
-                    $fileDataHeader = "---\nTitle: Header\nStatus: hidden\n---\n".$this->yellow->config->get("tagline");
+                if (!is_file($fileNameHeader) && $this->yellow->system->isExisting("tagline")) {
+                    $fileDataHeader = "---\nTitle: Header\nStatus: hidden\n---\n".$this->yellow->system->get("tagline");
                     if (!$this->yellow->toolbox->createFile($fileNameHeader, $fileDataHeader, true)) {
                         $fileDataError .= "ERROR writing file '$fileNameHeader'!\n";
                     }
@@ -94,43 +149,42 @@ class YellowUpdate {
                 $fileNameFooter = $pathShared."footer.md";
                 if (!is_file($fileNameFooter)) {
                     $fileDataFooter = "---\nTitle: Footer\nStatus: hidden\n---\n";
-                    $fileDataFooter .= $this->yellow->text->getText("InstallFooterText", $this->yellow->config->get("language"));
+                    $fileDataFooter .= $this->yellow->text->getText("InstallFooterText", $this->yellow->system->get("language"));
                     if (!$this->yellow->toolbox->createFile($fileNameFooter, $fileDataFooter, true)) {
                         $fileDataError .= "ERROR writing file '$fileNameFooter'!\n";
                     }
                 }
-                $this->updateSoftwareMultiLanguage("shared-pages");
-                if (!empty($fileDataError)) {
-                    $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
-                }
+                $this->updateContentMultiLanguage("shared-pages");
+                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
         }
         if ($update) {
-            $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-            $fileData = $this->yellow->toolbox->readFile($fileNameConfig);
-            $configDefaults = new YellowDataCollection();
-            $configDefaults->exchangeArray($this->yellow->config->configDefaults->getArrayCopy());
+            $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+            $fileData = $this->yellow->toolbox->readFile($fileName);
+            $fileDataNew = "";
+            $settingsDefaults = new YellowDataCollection();
+            $settingsDefaults->exchangeArray($this->yellow->system->settingsDefaults->getArrayCopy());
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                if (!empty($matches[1]) && !is_null($configDefaults[$matches[1]])) unset($configDefaults[$matches[1]]);
-                if (!empty($matches[1]) && $matches[1][0]!="#" && is_null($this->yellow->config->configDefaults[$matches[1]])) {
+                if (!empty($matches[1]) && !is_null($settingsDefaults[$matches[1]])) unset($settingsDefaults[$matches[1]]);
+                if (!empty($matches[1]) && $matches[1][0]!="#" && is_null($this->yellow->system->settingsDefaults[$matches[1]])) {
                     $fileDataNew .= "# $line";
                 } else {
                     $fileDataNew .= $line;
                 }
             }
-            unset($configDefaults["configFile"]);
-            foreach ($configDefaults as $key=>$value) {
+            unset($settingsDefaults["systemFile"]);
+            foreach ($settingsDefaults as $key=>$value) {
                 $fileDataNew .= ucfirst($key).": $value\n";
             }
-            if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileNameConfig, $fileDataNew);
+            if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
         }
     }
     
     // Handle request
     public function onRequest($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
-        if ($this->yellow->lookup->isContentFile($fileName) && $this->isSoftwarePending()) {
+        if ($this->yellow->lookup->isContentFile($fileName) && $this->isExtensionPending()) {
             $statusCode = $this->processRequestPending($scheme, $address, $base, $location, $fileName);
         }
         return $statusCode;
@@ -139,7 +193,7 @@ class YellowUpdate {
     // Handle command
     public function onCommand($args) {
         $statusCode = 0;
-        if ($this->isSoftwarePending()) $statusCode = $this->processCommandPending();
+        if ($this->isExtensionPending()) $statusCode = $this->processCommandPending();
         if ($statusCode==0) {
             list($command) = $args;
             switch ($command) {
@@ -155,9 +209,9 @@ class YellowUpdate {
     
     // Handle command help
     public function onCommandHelp() {
-        $help .= "install [feature]\n";
-        $help .= "uninstall [feature]\n";
-        $help .= "update [feature]\n";
+        $help .= "install [extension]\n";
+        $help .= "uninstall [extension]\n";
+        $help .= "update [extension]\n";
         return $help;
     }
     
@@ -166,8 +220,8 @@ class YellowUpdate {
         $statusCode = 0;
         list($command, $path) = $args;
         if ($path=="all") {
-            $path = $this->yellow->config->get("pluginDir");
-            $regex = "/^.*\\".$this->yellow->config->get("downloadExtension")."$/";
+            $path = $this->yellow->system->get("extensionDir");
+            $regex = "/^.*\\".$this->yellow->system->get("downloadExtension")."$/";
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, $regex, false, false) as $entry) {
                 if (!$this->yellow->toolbox->deleteFile($entry)) $statusCode = 500;
             }
@@ -176,47 +230,47 @@ class YellowUpdate {
         return $statusCode;
     }
     
-    // Process command to install website features
+    // Process command to install extensions
     public function processCommandInstall($args) {
-        list($command, $features) = $this->getCommandFeatures($args);
-        if (!empty($features)) {
+        list($command, $extensions) = $this->getExtensionInformation($args);
+        if (!empty($extensions)) {
             $this->updates = 0;
-            list($statusCode, $data) = $this->getInstallInformation($features);
-            if ($statusCode==200) $statusCode = $this->downloadSoftware($data);
-            if ($statusCode==200) $statusCode = $this->updateSoftware();
+            list($statusCode, $data) = $this->getInstallInformation($extensions);
+            if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
+            if ($statusCode==200) $statusCode = $this->updateExtensions();
             if ($statusCode>=400) echo "ERROR installing files: ".$this->yellow->page->get("pageError")."\n";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
-            echo ", $this->updates feature".($this->updates!=1 ? "s" : "")." installed\n";
+            echo ", $this->updates extension".($this->updates!=1 ? "s" : "")." installed\n";
         } else {
-            $statusCode = $this->showSoftware();
+            $statusCode = $this->showExtensions();
         }
         return $statusCode;
     }
     
-    // Process command to uninstall website features
+    // Process command to uninstall extensions
     public function processCommandUninstall($args) {
-        list($command, $features) = $this->getCommandFeatures($args);
-        if (!empty($features)) {
+        list($command, $extensions) = $this->getExtensionInformation($args);
+        if (!empty($extensions)) {
             $this->updates = 0;
-            list($statusCode, $data) = $this->getUninstallInformation($features, "YellowCore, YellowUpdate");
-            if ($statusCode==200) $statusCode = $this->removeSoftware($data);
+            list($statusCode, $data) = $this->getUninstallInformation($extensions, "core, command, update");
+            if ($statusCode==200) $statusCode = $this->removeExtensions($data);
             if ($statusCode>=400) echo "ERROR uninstalling files: ".$this->yellow->page->get("pageError")."\n";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
-            echo ", $this->updates feature".($this->updates!=1 ? "s" : "")." uninstalled\n";
+            echo ", $this->updates extension".($this->updates!=1 ? "s" : "")." uninstalled\n";
         } else {
-            $statusCode = $this->showSoftware();
+            $statusCode = $this->showExtensions();
         }
         return $statusCode;
     }
     
     // Process command to update website
     public function processCommandUpdate($args) {
-        list($command, $features, $force) = $this->getCommandFeatures($args);
-        list($statusCode, $data) = $this->getUpdateInformation($features, $force);
+        list($command, $extensions, $force) = $this->getExtensionInformation($args);
+        list($statusCode, $data) = $this->getUpdateInformation($extensions, $force);
         if ($statusCode!=200 || !empty($data)) {
             $this->updates = 0;
-            if ($statusCode==200) $statusCode = $this->downloadSoftware($data);
-            if ($statusCode==200) $statusCode = $this->updateSoftware($force);
+            if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
+            if ($statusCode==200) $statusCode = $this->updateExtensions($force);
             if ($statusCode>=400) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
             echo ", $this->updates update".($this->updates!=1 ? "s" : "")." installed\n";
@@ -226,34 +280,47 @@ class YellowUpdate {
         return $statusCode;
     }
     
-    // Process command to update website with pending software
+    // Process command to update website with pending extension
     public function processCommandPending() {
-        $statusCode = $this->updateSoftware();
+        $statusCode = $this->updateExtensions();
         if ($statusCode!=200) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
         echo "Your website has ".($statusCode!=200 ? "not " : "")."been updated: Please run command again\n";
         return $statusCode;
     }
     
-    // Process request to update website with pending software
+    // Process request to update website with pending extension
     public function processRequestPending($scheme, $address, $base, $location, $fileName) {
-        $statusCode = $this->updateSoftware();
+        $statusCode = $this->updateExtensions();
         if ($statusCode==200) {
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
         }
         return $statusCode;
     }
+    
+    // Return extension information
+    public function getExtensionInformation($args) {
+        $command = array_shift($args);
+        $extensions = array_unique(array_filter($args, "strlen"));
+        foreach ($extensions as $key=>$value) {
+            if ($value=="force") {
+                $force = true;
+                unset($extensions[$key]);
+            }
+        }
+        return array($command, $extensions, $force);
+    }
 
     // Return install information
-    public function getInstallInformation($features) {
+    public function getInstallInformation($extensions) {
         $data = array();
-        list($statusCodeCurrent, $dataCurrent) = $this->getSoftwareVersion();
-        list($statusCodeLatest, $dataLatest) = $this->getSoftwareVersion(true, true);
+        list($statusCodeCurrent, $dataCurrent) = $this->getExtensionsVersion();
+        list($statusCodeLatest, $dataLatest) = $this->getExtensionsVersion(true, true);
         $statusCode = max($statusCodeCurrent, $statusCodeLatest);
-        foreach ($features as $feature) {
+        foreach ($extensions as $extension) {
             $found = false;
             foreach ($dataLatest as $key=>$value) {
-                if (strtoloweru($key)==strtoloweru($feature)) {
+                if (strtoloweru($key)==strtoloweru($extension)) {
                     $data[$key] = $dataLatest[$key];
                     $found = true;
                     break;
@@ -261,34 +328,34 @@ class YellowUpdate {
             }
             if (!$found) {
                 $statusCode = 500;
-                $this->yellow->page->error($statusCode, "Can't find feature '$feature'!");
+                $this->yellow->page->error($statusCode, "Can't find extension '$extension'!");
             }
         }
         return array($statusCode, $data);
     }
 
     // Return uninstall information
-    public function getUninstallInformation($features, $featuresProtected) {
+    public function getUninstallInformation($extensions, $extensionsProtected) {
         $data = array();
-        list($statusCodeCurrent, $dataCurrent) = $this->getSoftwareVersion();
-        list($statusCodeLatest, $dataLatest) = $this->getSoftwareVersion(true, true);
-        list($statusCodeFiles, $dataFiles) = $this->getSoftwareFiles();
-        $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeFiles);
-        foreach ($features as $feature) {
+        list($statusCodeCurrent, $dataCurrent) = $this->getExtensionsVersion();
+        list($statusCodeLatest, $dataLatest) = $this->getExtensionsVersion(true, true);
+        list($statusCodeRelevant, $dataRelevant) = $this->getExtensionsRelevant();
+        $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeRelevant);
+        foreach ($extensions as $extension) {
             $found = false;
             foreach ($dataCurrent as $key=>$value) {
-                if (strtoloweru($key)==strtoloweru($feature) && !is_null($dataLatest[$key]) && !is_null($dataFiles[$key])) {
-                    $data[$key] = $dataFiles[$key];
+                if (strtoloweru($key)==strtoloweru($extension) && !is_null($dataLatest[$key]) && !is_null($dataRelevant[$key])) {
+                    $data[$key] = $dataRelevant[$key];
                     $found = true;
                     break;
                 }
             }
             if (!$found) {
                 $statusCode = 500;
-                $this->yellow->page->error($statusCode, "Can't find feature '$feature'!");
+                $this->yellow->page->error($statusCode, "Can't find extension '$extension'!");
             }
         }
-        $protected = preg_split("/\s*,\s*/", $featuresProtected);
+        $protected = preg_split("/\s*,\s*/", $extensionsProtected);
         foreach ($data as $key=>$value) {
             if (in_array($key, $protected)) unset($data[$key]);
         }
@@ -296,24 +363,24 @@ class YellowUpdate {
     }
 
     // Return update information
-    public function getUpdateInformation($features, $force) {
+    public function getUpdateInformation($extensions, $force) {
         $data = array();
-        list($statusCodeCurrent, $dataCurrent) = $this->getSoftwareVersion();
-        list($statusCodeLatest, $dataLatest) = $this->getSoftwareVersion(true, true);
-        list($statusCodeModified, $dataModified) = $this->getSoftwareModified();
+        list($statusCodeCurrent, $dataCurrent) = $this->getExtensionsVersion();
+        list($statusCodeLatest, $dataLatest) = $this->getExtensionsVersion(true, true);
+        list($statusCodeModified, $dataModified) = $this->getExtensionsModified();
         $statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeModified);
-        if (empty($features)) {
+        if (empty($extensions)) {
             foreach ($dataCurrent as $key=>$value) {
                 list($version) = explode(",", $dataLatest[$key]);
                 if (strnatcasecmp($dataCurrent[$key], $version)<0) $data[$key] = $dataLatest[$key];
                 if (!is_null($dataModified[$key]) && !empty($version) && $force) $data[$key] = $dataLatest[$key];
             }
         } else {
-            foreach ($features as $feature) {
+            foreach ($extensions as $extension) {
                 $found = false;
                 foreach ($dataCurrent as $key=>$value) {
                     list($version) = explode(",", $dataLatest[$key]);
-                    if (strtoloweru($key)==strtoloweru($feature) && !empty($version)) {
+                    if (strtoloweru($key)==strtoloweru($extension) && !empty($version)) {
                         $data[$key] = $dataLatest[$key];
                         $dataModified = array_intersect_key($dataModified, $data);
                         $found = true;
@@ -322,7 +389,7 @@ class YellowUpdate {
                 }
                 if (!$found) {
                     $statusCode = 500;
-                    $this->yellow->page->error($statusCode, "Can't find feature '$feature'!");
+                    $this->yellow->page->error($statusCode, "Can't find extension '$extension'!");
                 }
             }
         }
@@ -330,35 +397,35 @@ class YellowUpdate {
             foreach (array_merge($dataModified, $data) as $key=>$value) {
                 list($version) = explode(",", $value);
                 if (is_null($dataModified[$key]) || $force) {
-                    echo "$key $version\n";
+                    echo ucfirst($key)." $version\n";
                 } else {
-                    echo "$key $version has been modified - Force update\n";
+                    echo ucfirst($key)." $version has been modified - Force update\n";
                 }
             }
         }
         return array($statusCode, $data);
     }
     
-    // Show software
-    public function showSoftware() {
-        list($statusCode, $dataLatest) = $this->getSoftwareVersion(true, true);
+    // Show extensions
+    public function showExtensions() {
+        list($statusCode, $dataLatest) = $this->getExtensionsVersion(true, true);
         foreach ($dataLatest as $key=>$value) {
             list($version, $url, $description) = explode(",", $value, 3);
-            echo "$key: $description\n";
+            echo ucfirst($key).": $description\n";
         }
-        if ($statusCode!=200) echo "ERROR checking features: ".$this->yellow->page->get("pageError")."\n";
+        if ($statusCode!=200) echo "ERROR checking extensions: ".$this->yellow->page->get("pageError")."\n";
         return $statusCode;
     }
     
-    // Download software
-    public function downloadSoftware($data) {
+    // Download extensions
+    public function downloadExtensions($data) {
         $statusCode = 200;
-        $path = $this->yellow->config->get("pluginDir");
-        $fileExtension = $this->yellow->config->get("downloadExtension");
+        $path = $this->yellow->system->get("extensionDir");
+        $fileExtension = $this->yellow->system->get("downloadExtension");
         foreach ($data as $key=>$value) {
             $fileName = $path.$this->yellow->lookup->normaliseName($key, true, false, true).".zip";
             list($version, $url) = explode(",", $value);
-            list($statusCode, $fileData) = $this->getSoftwareFile($url);
+            list($statusCode, $fileData) = $this->getExtensionFile($url);
             if (empty($fileData) || !$this->yellow->toolbox->createFile($fileName.$fileExtension, $fileData)) {
                 $statusCode = 500;
                 $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
@@ -377,21 +444,13 @@ class YellowUpdate {
         return $statusCode;
     }
 
-    // Update software
-    public function updateSoftware($force = false) {
+    // Update extensions
+    public function updateExtensions($force = false) {
         $statusCode = 200;
         if (function_exists("opcache_reset")) opcache_reset();
-        $path = $this->yellow->config->get("pluginDir");
-        foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
-            $statusCode = max($statusCode, $this->updateSoftwareArchive($entry, $force));
-            if (!$this->yellow->toolbox->deleteFile($entry)) {
-                $statusCode = 500;
-                $this->yellow->page->error($statusCode, "Can't delete file '$entry'!");
-            }
-        }
-        $path = $this->yellow->config->get("themeDir");
+        $path = $this->yellow->system->get("extensionDir");
         foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
-            $statusCode = max($statusCode, $this->updateSoftwareArchive($entry, $force));
+            $statusCode = max($statusCode, $this->updateExtensionArchive($entry, $force));
             if (!$this->yellow->toolbox->deleteFile($entry)) {
                 $statusCode = 500;
                 $this->yellow->page->error($statusCode, "Can't delete file '$entry'!");
@@ -400,20 +459,18 @@ class YellowUpdate {
         return $statusCode;
     }
 
-    // Update software from archive
-    public function updateSoftwareArchive($path, $force = false) {
+    // Update extension from archive
+    public function updateExtensionArchive($path, $force = false) {
         $statusCode = 200;
         $zip = new ZipArchive();
         if ($zip->open($path)===true) {
-            if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::updateSoftwareArchive file:$path<br/>\n";
+            if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::updateExtensionArchive file:$path<br/>\n";
             if (preg_match("#^(.*\/).*?$#", $zip->getNameIndex(0), $matches)) $pathBase = $matches[1];
-            $fileData = $zip->getFromName($pathBase.$this->yellow->config->get("updateInformationFile"));
+            $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateInformationFile"));
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($dummy, $entry) = explode("/", $matches[1], 2);
                     list($fileName) = explode(",", $matches[2], 2);
-                    if ($dummy[0]!="Y") $fileName = $matches[1];    //TODO: remove later, converts old file format
                     if (is_file($fileName)) {
                         $lastPublished = filemtime($fileName);
                         break;
@@ -422,24 +479,22 @@ class YellowUpdate {
             }
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                if (lcfirst($matches[1])=="plugin" || lcfirst($matches[1])=="theme") $software = $matches[2];
+                if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
+                if (lcfirst($matches[1])=="plugin") $extension = lcfirst(substru($matches[2], 6)); //TODO: remove later, for backwards compatibility
+                if (lcfirst($matches[1])=="theme") $extension = lcfirst(substru($matches[2], 11)); //TODO: remove later, for backwards compatibility
                 if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                 if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                     list($dummy, $entry) = explode("/", $matches[1], 2);
                     list($fileName, $flags) = explode(",", $matches[2], 2);
-                    if ($dummy[0]!="Y") { //TODO: remove later, converts old file format
-                        list($entry, $flags) = explode(",", $matches[2], 2);
-                        $fileName = $matches[1];
-                    }
-                    $fileData = $zip->getFromName($pathBase.$entry);
+                    $fileData = $zip->getFromName($pathBase.basename($entry));
                     $lastModified = $this->yellow->toolbox->getFileModified($fileName);
-                    $statusCode = $this->updateSoftwareFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $software);
+                    $statusCode = $this->updateExtensionFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $extension);
                     if ($statusCode!=200) break;
                 }
             }
             $zip->close();
-            if ($statusCode==200) $statusCode = $this->updateSoftwareMultiLanguage($software);
-            if ($statusCode==200) $statusCode = $this->updateSoftwareNotification($software);
+            if ($statusCode==200) $statusCode = $this->updateContentMultiLanguage($extension);
+            if ($statusCode==200) $statusCode = $this->updateStartupNotification($extension);
             ++$this->updates;
         } else {
             $statusCode = 500;
@@ -448,17 +503,17 @@ class YellowUpdate {
         return $statusCode;
     }
     
-    // Update software file
-    public function updateSoftwareFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $software) {
+    // Update extension from file
+    public function updateExtensionFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $extension) {
         $statusCode = 200;
         $fileName = $this->yellow->toolbox->normaliseTokens($fileName);
-        if ($this->yellow->lookup->isValidFile($fileName) && !empty($software)) {
+        if ($this->yellow->lookup->isValidFile($fileName) && !empty($extension)) {
             $create = $update = $delete = false;
             if (preg_match("/create/i", $flags) && !is_file($fileName) && !empty($fileData)) $create = true;
             if (preg_match("/update/i", $flags) && is_file($fileName) && !empty($fileData)) $update = true;
             if (preg_match("/delete/i", $flags) && is_file($fileName)) $delete = true;
             if (preg_match("/careful/i", $flags) && is_file($fileName) && $lastModified!=$lastPublished && !$force) $update = false;
-            if (preg_match("/optional/i", $flags) && $this->isSoftwareExisting($software)) $create = $update = $delete = false;
+            if (preg_match("/optional/i", $flags) && $this->yellow->extensions->isExisting($extension)) $create = $update = $delete = false;
             if ($create) {
                 if (!$this->yellow->toolbox->createFile($fileName, $fileData, true) ||
                     !$this->yellow->toolbox->modifyFile($fileName, $modified)) {
@@ -467,7 +522,7 @@ class YellowUpdate {
                 }
             }
             if ($update) {
-                if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir")) ||
+                if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir")) ||
                     !$this->yellow->toolbox->createFile($fileName, $fileData) ||
                     !$this->yellow->toolbox->modifyFile($fileName, $modified)) {
                     $statusCode = 500;
@@ -475,7 +530,7 @@ class YellowUpdate {
                 }
             }
             if ($delete) {
-                if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir"))) {
+                if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
                     $statusCode = 500;
                     $this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
                 }
@@ -483,19 +538,19 @@ class YellowUpdate {
             if (defined("DEBUG") && DEBUG>=2) {
                 $debug = "action:".($create ? "create" : "").($update ? "update" : "").($delete ? "delete" : "");
                 if (!$create && !$update && !$delete) $debug = "action:none";
-                echo "YellowUpdate::updateSoftwareFile file:$fileName $debug<br/>\n";
+                echo "YellowUpdate::updateExtensionFile file:$fileName $debug<br/>\n";
             }
         }
         return $statusCode;
     }
 
-    // Update software for multiple languages
-    public function updateSoftwareMultiLanguage($software) {
+    // Update content for multi language mode
+    public function updateContentMultiLanguage($extension) {
         $statusCode = 200;
-        if ($this->yellow->config->get("multiLanguageMode") && !$this->isSoftwareExisting($software)) {
+        if ($this->yellow->system->get("multiLanguageMode") && !$this->yellow->extensions->isExisting($extension)) {
             $pathsSource = $pathsTarget = array();
-            $pathBase = $this->yellow->config->get("contentDir");
-            $fileExtension = $this->yellow->config->get("contentExtension");
+            $pathBase = $this->yellow->system->get("contentDir");
+            $fileExtension = $this->yellow->system->get("contentExtension");
             $fileRegex = "/^.*\\".$fileExtension."$/";
             foreach ($this->yellow->toolbox->getDirectoryEntries($pathBase, "/.*/", true, true) as $entry) {
                 if (count($this->yellow->toolbox->getDirectoryEntries($entry, $fileRegex, false, false))) {
@@ -518,7 +573,7 @@ class YellowUpdate {
                                     $this->yellow->page->error(500, "Can't write file '$fileNameTarget'!");
                                 }
                             }
-                            if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::updateSoftwareNew file:$fileNameTarget<br/>\n";
+                            if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::updateContentMultiLanguage file:$fileNameTarget<br/>\n";
                         }
                     }
                     if (!$this->yellow->toolbox->deleteDirectory($pathSource)) {
@@ -531,144 +586,125 @@ class YellowUpdate {
         return $statusCode;
     }
     
-    // Update software notification for next startup
-    public function updateSoftwareNotification($software) {
+    // Update notification for next startup
+    public function updateStartupNotification($extension) {
         $statusCode = 200;
-        $startupUpdate = $this->yellow->config->get("startupUpdate");
-        if ($startupUpdate=="none") $startupUpdate = "YellowUpdate";
-        if ($software!="YellowUpdate") $startupUpdate .= ",$software";
-        $fileNameConfig = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
-        if (!$this->yellow->config->save($fileNameConfig, array("startupUpdate" => $startupUpdate))) {
+        $startupUpdate = $this->yellow->system->get("startupUpdate");
+        if ($startupUpdate=="none") $startupUpdate = "update";
+        if ($extension!="update") $startupUpdate .= ",$extension";
+        $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+        if (!$this->yellow->system->save($fileName, array("startupUpdate" => $startupUpdate))) {
             $statusCode = 500;
-            $this->yellow->page->error(500, "Can't write file '$fileNameConfig'!");
+            $this->yellow->page->error(500, "Can't write file '$fileName'!");
         }
         return $statusCode;
     }
     
-    // Remove software
-    public function removeSoftware($data) {
+    // Remove extensions
+    public function removeExtensions($data) {
         $statusCode = 200;
         if (function_exists("opcache_reset")) opcache_reset();
         foreach ($data as $key=>$value) {
             foreach (preg_split("/\s*,\s*/", $value) as $fileName) {
-                $statusCode = max($statusCode, $this->removeSoftwareFile($fileName, $key));
+                $statusCode = max($statusCode, $this->removeExtensionsFile($fileName, $key));
             }
             ++$this->updates;
         }
-        if ($statusCode==200) $statusCode = $this->updateSoftwareNotification("YellowUpdate");
+        if ($statusCode==200) $statusCode = $this->updateStartupNotification("update");
         return $statusCode;
     }
     
-    // Remove software file
-    public function removeSoftwareFile($fileName, $software) {
+    // Remove extensions file
+    public function removeExtensionsFile($fileName, $extension) {
         $statusCode = 200;
         $fileName = $this->yellow->toolbox->normaliseTokens($fileName);
-        if ($this->yellow->lookup->isValidFile($fileName) && !empty($software)) {
-            if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir"))) {
+        if ($this->yellow->lookup->isValidFile($fileName) && !empty($extension)) {
+            if (!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
                 $statusCode = 500;
                 $this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
             }
             if (defined("DEBUG") && DEBUG>=2) {
-                echo "YellowUpdate::removeSoftwareFile file:$fileName action:delete<br/>\n";
+                echo "YellowUpdate::removeExtensionsFile file:$fileName action:delete<br/>\n";
             }
         }
         return $statusCode;
     }
     
-    // Return features from commandline arguments
-    public function getCommandFeatures($args) {
-        $command = array_shift($args);
-        $features = array_unique(array_filter($args, "strlen"));
-        foreach ($features as $key=>$value) {
-            if ($value=="force") {
-                $force = true;
-                unset($features[$key]);
-            }
-        }
-        return array($command, $features, $force);
-    }
-
-    // Return software version
-    public function getSoftwareVersion($latest = false, $rawFormat = false) {
+    // Return extensions version
+    public function getExtensionsVersion($latest = false, $rawFormat = false) {
         $data = array();
         if ($latest) {
-            $urlPlugins = $this->yellow->config->get("updatePluginsUrl")."/raw/master/".$this->yellow->config->get("updateVersionFile");
-            $urlThemes = $this->yellow->config->get("updateThemesUrl")."/raw/master/".$this->yellow->config->get("updateVersionFile");
-            list($statusCodePlugins, $fileDataPlugins) = $this->getSoftwareFile($urlPlugins);
-            list($statusCodeThemes, $fileDataThemes) = $this->getSoftwareFile($urlThemes);
-            $statusCode = max($statusCodePlugins, $statusCodeThemes);
+            $url = $this->yellow->system->get("updateExtensionUrl")."/raw/master/".$this->yellow->system->get("updateVersionFile");
+            list($statusCode, $fileData) = $this->getExtensionFile($url);
             if ($statusCode==200) {
-                foreach ($this->yellow->toolbox->getTextLines($fileDataPlugins."\n".$fileDataThemes) as $line) {
+                foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                     preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                     if (!empty($matches[1]) && !empty($matches[2])) {
+                        $extension = lcfirst($matches[1]);
                         list($version) = explode(",", $matches[2]);
-                        $data[$matches[1]] = $rawFormat ? $matches[2] : $version;
+                        $data[$extension] = $rawFormat ? $matches[2] : $version;
                     }
                 }
             }
         } else {
             $statusCode = 200;
-            $data = array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData());
+            $data = $this->yellow->extensions->getData();
         }
         return array($statusCode, $data);
     }
  
-    // Return software modification
-    public function getSoftwareModified() {
+    // Return extensions relevant files
+    public function getExtensionsRelevant() {
         $data = array();
-        $dataCurrent = array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData());
-        $urlPlugins = $this->yellow->config->get("updatePluginsUrl")."/raw/master/".$this->yellow->config->get("updateResourceFile");
-        $urlThemes = $this->yellow->config->get("updateThemesUrl")."/raw/master/".$this->yellow->config->get("updateResourceFile");
-        list($statusCodePlugins, $fileDataPlugins) = $this->getSoftwareFile($urlPlugins);
-        list($statusCodeThemes, $fileDataThemes) = $this->getSoftwareFile($urlThemes);
-        $statusCode = max($statusCodePlugins, $statusCodeThemes);
+        $url = $this->yellow->system->get("updateExtensionUrl")."/raw/master/".$this->yellow->system->get("updateWaffleFile");
+        list($statusCode, $fileData) = $this->getExtensionFile($url);
         if ($statusCode==200) {
-            foreach ($this->yellow->toolbox->getTextLines($fileDataPlugins."\n".$fileDataThemes) as $line) {
+            foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($softwareNew) = explode("/", $matches[1]);
-                    list($fileName, $flags) = explode(",", $matches[2], 2);
-                    if ($software!=$softwareNew) {
-                        $software = $softwareNew;
-                        $lastPublished = $this->yellow->toolbox->getFileModified($fileName);
-                    }
-                    if (!is_null($dataCurrent[$software])) {
-                        $lastModified = $this->yellow->toolbox->getFileModified($fileName);
-                        if (preg_match("/update/i", $flags) && preg_match("/careful/i", $flags) && $lastModified!=$lastPublished) {
-                            $data[$software] = $dataCurrent[$software];
-                            if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::getSoftwareModified detected file:$fileName<br/>\n";
-                        }
-                    }
+                    list($extension) = explode("/", lcfirst($matches[1]));
+                    list($fileName) = explode(",", $matches[2], 2);
+                    if (!is_null($data[$extension])) $data[$extension] .= ",";
+                    $data[$extension] .= $fileName;
                 }
             }
         }
         return array($statusCode, $data);
     }
     
-    // Return software files
-    public function getSoftwareFiles() {
+    // Return extensions modified files
+    public function getExtensionsModified() {
         $data = array();
-        $urlPlugins = $this->yellow->config->get("updatePluginsUrl")."/raw/master/".$this->yellow->config->get("updateResourceFile");
-        $urlThemes = $this->yellow->config->get("updateThemesUrl")."/raw/master/".$this->yellow->config->get("updateResourceFile");
-        list($statusCodePlugins, $fileDataPlugins) = $this->getSoftwareFile($urlPlugins);
-        list($statusCodeThemes, $fileDataThemes) = $this->getSoftwareFile($urlThemes);
-        $statusCode = max($statusCodePlugins, $statusCodeThemes);
+        $dataCurrent = $this->yellow->extensions->getData();
+        $url = $this->yellow->system->get("updateExtensionUrl")."/raw/master/".$this->yellow->system->get("updateWaffleFile");
+        list($statusCode, $fileData) = $this->getExtensionFile($url);
         if ($statusCode==200) {
-            foreach ($this->yellow->toolbox->getTextLines($fileDataPlugins."\n".$fileDataThemes) as $line) {
+            foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($software) = explode("/", $matches[1]);
-                    list($fileName) = explode(",", $matches[2], 2);
-                    if (!is_null($data[$software])) $data[$software] .= ",";
-                    $data[$software] .= $fileName;
+                    list($extensionNew) = explode("/", lcfirst($matches[1]));
+                    list($fileName, $flags) = explode(",", $matches[2], 2);
+                    if ($extension!=$extensionNew) {
+                        $extension = $extensionNew;
+                        $lastPublished = $this->yellow->toolbox->getFileModified($fileName);
+                    }
+                    if (!is_null($dataCurrent[$extension])) {
+                        $lastModified = $this->yellow->toolbox->getFileModified($fileName);
+                        if (preg_match("/update/i", $flags) && preg_match("/careful/i", $flags) && $lastModified!=$lastPublished) {
+                            $data[$extension] = $dataCurrent[$extension];
+                            if (defined("DEBUG") && DEBUG>=2) {
+                                echo "YellowUpdate::getExtensionsModified detected file:$fileName extension:$extension<br/>\n";
+                            }
+                        }
+                    }
                 }
             }
         }
         return array($statusCode, $data);
     }
-
-    // Return software file
-    public function getSoftwareFile($url) {
+    
+    // Return extension file
+    public function getExtensionFile($url) {
         $urlRequest = $url;
         if (preg_match("#^https://github.com/(.+)/raw/(.+)$#", $url, $matches)) $urlRequest = "https://raw.githubusercontent.com/".$matches[1]."/".$matches[2];
         $curlHandle = curl_init();
@@ -689,22 +725,26 @@ class YellowUpdate {
             $statusCode = 500;
             $this->yellow->page->error($statusCode, "Can't download file '$url'!");
         }
-        if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::getSoftwareFile status:$statusCode url:$url<br/>\n";
+        if (defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::getExtensionFile status:$statusCode url:$url<br/>\n";
         return array($statusCode, $fileData);
     }
     
-    // Check if software pending
-    public function isSoftwarePending() {
-        $path = $this->yellow->config->get("pluginDir");
-        $foundPlugins = count($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", false, false))>0;
-        $path = $this->yellow->config->get("themeDir");
-        $foundThemes = count($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", false, false))>0;
-        return $foundPlugins || $foundThemes;
+    // Return human readable language name, TODO: remove later, for backwards compatibility
+    public function getLanguageName($language) {
+        $languageName = "";
+        $languageNames = array("bn" => "bengali", "cs" => "czech", "da" => "danish", "de" => "german",
+            "en" => "english", "es" => "spanish", "fr" => "french", "hu" => "hungarian", "id" => "indonesian",
+            "it" => "italian", "ja" => "japanese", "ko" => "korean", "nl" => "dutch", "pl" => "polish",
+            "pt" => "portuguese", "ru" => "russian", "sk" => "slovenian", "sv" => "swedish", "zh-CN" => "chinese");
+        if (array_key_exists($language, $languageNames)) {
+            $languageName = $languageNames[$language];
+        }
+        return $languageName;
     }
 
-    // Check if software exists
-    public function isSoftwareExisting($software) {
-        $data = array_merge($this->yellow->plugins->getData(), $this->yellow->themes->getData());
-        return !is_null($data[$software]);
+    // Check if extension pending
+    public function isExtensionPending() {
+        $path = $this->yellow->system->get("extensionDir");
+        return count($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", false, false))>0;
     }
 }

+ 9 - 0
system/layouts/default.html

@@ -0,0 +1,9 @@
+<?php $this->yellow->layout("header") ?>
+<div class="content">
+<?php $this->yellow->layout("sidebar") ?>
+<div class="main" role="main">
+<h1><?php echo $this->yellow->page->getHtml("titleContent") ?></h1>
+<?php echo $this->yellow->page->getContent() ?>
+</div>
+</div>
+<?php $this->yellow->layout("footer") ?>

+ 8 - 0
system/layouts/error.html

@@ -0,0 +1,8 @@
+<?php $this->yellow->layout("header") ?>
+<div class="content">
+<div class="main" role="main">
+<h1><?php echo $this->yellow->page->getHtml("titleContent") ?></h1>
+<?php echo $this->yellow->page->getContent() ?>
+</div>
+</div>
+<?php $this->yellow->layout("footer") ?>

+ 10 - 0
system/layouts/footer.html

@@ -0,0 +1,10 @@
+<div class="footer" role="contentinfo">
+<div class="siteinfo">
+<?php if ($this->yellow->page->isPage("footer")) echo $this->yellow->page->getPage("footer")->getContent() ?>
+<div class="siteinfo-banner"></div>
+</div>
+</div>
+</div>
+<?php echo $this->yellow->page->getExtra("footer") ?>
+</body>
+</html>

+ 27 - 0
system/layouts/header.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html><html lang="<?php echo $this->yellow->page->getHtml("language") ?>">
+<head>
+<title><?php echo $this->yellow->page->getHtml("titleHeader") ?></title>
+<meta charset="utf-8" />
+<meta name="description" content="<?php echo $this->yellow->page->getHtml("description") ?>" />
+<meta name="keywords" content="<?php echo $this->yellow->page->getHtml("keywords") ?>" />
+<meta name="author" content="<?php echo $this->yellow->page->getHtml("author") ?>" />
+<meta name="generator" content="Datenstrom Yellow" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<?php echo $this->yellow->page->getExtra("header") ?>
+</head>
+<body>
+<?php if ($page = $this->yellow->content->shared($this->yellow->page->location, false, $this->yellow->page->get("header"))) $this->yellow->page->setPage("header", $page) ?>
+<?php if ($page = $this->yellow->content->shared($this->yellow->page->location, false, $this->yellow->page->get("footer"))) $this->yellow->page->setPage("footer", $page) ?>
+<?php if ($page = $this->yellow->content->shared($this->yellow->page->location, false, $this->yellow->page->get("sidebar"))) $this->yellow->page->setPage("sidebar", $page) ?>
+<?php if ($this->yellow->page->get("navigation")=="navigation-sidebar") $this->yellow->page->setPage("navigation-sidebar", $this->yellow->page->getParentTop(true)) ?>
+<?php $this->yellow->page->set("pageClass", "page layout-".$this->yellow->page->get("layout")) ?>
+<?php if (!$this->yellow->page->isError() && ($this->yellow->page->isPage("sidebar") || $this->yellow->page->isPage("navigation-sidebar"))) $this->yellow->page->set("pageClass", $this->yellow->page->get("pageClass")." with-sidebar") ?>
+<div class="<?php echo $this->yellow->page->getHtml("pageClass") ?>">
+<div class="header" role="banner">
+<div class="sitename">
+<h1><a href="<?php echo $this->yellow->page->getBase(true)."/" ?>"><i class="sitename-logo"></i><?php echo $this->yellow->page->getHtml("sitename") ?></a></h1>
+<?php if ($this->yellow->page->isPage("header")) echo $this->yellow->page->getPage("header")->getContent() ?>
+</div>
+<div class="sitename-banner"></div>
+<?php $this->yellow->layout($this->yellow->page->get("navigation")) ?>
+</div>

+ 2 - 2
system/themes/snippets/navigation-sidebar.php → system/layouts/navigation-sidebar.html

@@ -1,5 +1,5 @@
-<?php $pages = $yellow->pages->top() ?>
-<?php $yellow->page->setLastModified($pages->getModified()) ?>
+<?php $pages = $this->yellow->content->top() ?>
+<?php $this->yellow->page->setLastModified($pages->getModified()) ?>
 <div class="navigation" role="navigation">
 <ul>
 <?php foreach ($pages as $page): ?>

+ 4 - 4
system/themes/snippets/navigation-tree.php → system/layouts/navigation-tree.html

@@ -1,13 +1,13 @@
-<?php list($name, $pages, $level) = $yellow->getSnippetArgs() ?>
-<?php if (!$pages) $pages = $yellow->pages->top() ?>
-<?php $yellow->page->setLastModified($pages->getModified()) ?>
+<?php list($name, $pages, $level) = $this->yellow->getLayoutArgs() ?>
+<?php if (!$pages) $pages = $this->yellow->content->top() ?>
+<?php $this->yellow->page->setLastModified($pages->getModified()) ?>
 <?php if (!$level): ?>
 <div class="navigation-tree" role="navigation">
 <?php endif ?>
 <ul>
 <?php foreach ($pages as $page): ?>
 <?php $children = $page->getChildren() ?>
-<li><a<?php echo $page->isActive() ? " class=\"active\" aria-current=\"page\"" : "" ?> href="<?php echo $page->getLocation(true) ?>"><?php echo $page->getHtml("titleNavigation") ?></a><?php if ($children->count()) { echo "\n"; $yellow->snippet($name, $children, $level+1); } ?></li>
+<li><a<?php echo $page->isActive() ? " class=\"active\" aria-current=\"page\"" : "" ?> href="<?php echo $page->getLocation(true) ?>"><?php echo $page->getHtml("titleNavigation") ?></a><?php if ($children->count()) { echo "\n"; $this->yellow->layout($name, $children, $level+1); } ?></li>
 <?php endforeach ?>
 </ul>
 <?php if (!$level): ?>

+ 2 - 2
system/themes/snippets/navigation.php → system/layouts/navigation.html

@@ -1,5 +1,5 @@
-<?php $pages = $yellow->pages->top() ?>
-<?php $yellow->page->setLastModified($pages->getModified()) ?>
+<?php $pages = $this->yellow->content->top() ?>
+<?php $this->yellow->page->setLastModified($pages->getModified()) ?>
 <div class="navigation" role="navigation">
 <ul>
 <?php foreach ($pages as $page): ?>

+ 3 - 3
system/themes/snippets/pagination.php → system/layouts/pagination.html

@@ -1,11 +1,11 @@
-<?php list($name, $pages) = $yellow->getSnippetArgs() ?>
+<?php list($name, $pages) = $this->yellow->getLayoutArgs() ?>
 <?php if ($pages->isPagination()): ?>
 <div class="pagination" role="navigation">
 <?php if ($pages->getPaginationPrevious()): ?>
-<a class="previous" href="<?php echo $pages->getPaginationPrevious() ?>"><?php echo $yellow->text->getHtml("paginationPrevious") ?></a>
+<a class="previous" href="<?php echo $pages->getPaginationPrevious() ?>"><?php echo $this->yellow->text->getHtml("paginationPrevious") ?></a>
 <?php endif ?>
 <?php if ($pages->getPaginationNext()): ?>
-<a class="next" href="<?php echo $pages->getPaginationNext() ?>"><?php echo $yellow->text->getHtml("paginationNext") ?></a>
+<a class="next" href="<?php echo $pages->getPaginationNext() ?>"><?php echo $this->yellow->text->getHtml("paginationNext") ?></a>
 <?php endif ?>
 </div>
 <?php endif ?>

+ 6 - 6
system/themes/snippets/sidebar.php → system/layouts/sidebar.html

@@ -1,15 +1,15 @@
-<?php if ($yellow->page->isPage("sidebar")): ?>
+<?php if ($this->yellow->page->isPage("sidebar")): ?>
 <div class="sidebar" role="complementary">
-<?php $page = $yellow->page->getPage("sidebar") ?>
-<?php $page->setPage("main", $yellow->page) ?>
+<?php $page = $this->yellow->page->getPage("sidebar") ?>
+<?php $page->setPage("main", $this->yellow->page) ?>
 <?php echo $page->getContent() ?>
 </div>
-<?php elseif ($yellow->page->isPage("navigation-sidebar")): ?>
+<?php elseif ($this->yellow->page->isPage("navigation-sidebar")): ?>
 <div class="sidebar" role="complementary">
 <div class="navigation-sidebar">
-<?php $page = $yellow->page->getPage("navigation-sidebar") ?>
+<?php $page = $this->yellow->page->getPage("navigation-sidebar") ?>
 <?php $pages = $page->getChildren(!$page->isVisible()) ?>
-<?php $yellow->page->setLastModified($pages->getModified()) ?>
+<?php $this->yellow->page->setLastModified($pages->getModified()) ?>
 <p><?php echo $page->getHtml("titleNavigation") ?></p>
 <ul>
 <?php foreach ($pages as $page): ?>

BIN
system/plugins/install-blog.zip


BIN
system/plugins/install-language.zip


BIN
system/plugins/install-wiki.zip


BIN
system/resources/flatsite-icon.png


+ 5 - 5
system/themes/assets/flatsite.css → system/resources/flatsite.css

@@ -1,4 +1,4 @@
-/* Flatsite theme, https://github.com/datenstrom/yellow-themes/tree/master/flatsite */
+/* Flatsite extension, https://github.com/datenstrom/yellow-extensions/tree/master/themes/flatsite */
 /* Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se */
 /* This file may be used and distributed under the terms of the public license. */
 
@@ -438,19 +438,19 @@ a:hover {
 
 /* Misc */
 
-.template-default .content img.screenshot {
+.layout-default .content img.screenshot {
     margin: 0 -0.5em;
 }
-.template-language .content div.language {
+.layout-language .content div.language {
     font-size: 1.2em;
     text-align: left;
     width: 9em;
     margin: 0 auto;
 }
-.template-language .content div.language p {
+.layout-language .content div.language p {
     margin: 1.5em 0em;
 }
-.template-language .content div.language img {
+.layout-language .content div.language img {
     vertical-align: middle;
     margin-top: -5px;
     margin-right: 1.5em;

+ 0 - 0
system/themes/assets/opensans-bold.woff → system/resources/opensans-bold.woff


+ 0 - 0
system/themes/assets/opensans-light.woff → system/resources/opensans-light.woff


+ 0 - 0
system/themes/assets/opensans-regular.woff → system/resources/opensans-regular.woff


+ 14 - 22
system/config/config.ini → system/settings/system.ini

@@ -1,11 +1,10 @@
-# Datenstrom Yellow configuration
+# Datenstrom Yellow system settings
 
 Sitename: Datenstrom Yellow
 Author: Datenstrom
 Email: webmaster
 Language: en
 Timezone: UTC
-Theme: flatsite
 
 StaticUrl:
 StaticDefaultFile: index.html
@@ -15,19 +14,16 @@ CacheDir: cache/
 MediaLocation: /media/
 DownloadLocation: /media/downloads/
 ImageLocation: /media/images/
-PluginLocation: /media/plugins/
-ThemeLocation: /media/themes/
-AssetLocation: /media/themes/assets/
+ExtensionLocation: /media/extensions/
+ResourceLocation: /media/resources/
 MediaDir: media/
 DownloadDir: media/downloads/
 ImageDir: media/images/
 SystemDir: system/
-ConfigDir: system/config/
-PluginDir: system/plugins/
-ThemeDir: system/themes/
-AssetDir: system/themes/assets/
-SnippetDir: system/themes/snippets/
-TemplateDir: system/themes/templates/
+ExtensionDir: system/extensions/
+LayoutDir: system/layouts/
+ResourceDir: system/resources/
+SettingDir: system/settings/
 TrashDir: system/trash/
 ContentDir: content/
 ContentRootDir: default/
@@ -36,20 +32,17 @@ ContentSharedDir: shared/
 ContentPagination: page
 ContentDefaultFile: page.md
 ContentExtension: .md
-ConfigExtension: .ini
 DownloadExtension: .download
 TextFile: text.ini
-NewFile: page-new-(.*).md
-LanguageFile: language-(.*).txt
 ServerUrl:
-StartupUpdate: none
-Template: default
+Layout: default
+Theme: flatsite
+Parser: markdown
 Navigation: navigation
 Header: header
 Footer: footer
 Sidebar: sidebar
-Siteicon: icon
-Parser: markdown
+StartupUpdate: none
 MultiLanguageMode: 0
 SafeMode: 0
 BundleAndMinify: 1
@@ -64,6 +57,7 @@ EditUserPasswordMinLength: 8
 EditUserHashAlgorithm: bcrypt
 EditUserHashCost: 10
 EditUserHome: /
+EditNewFile: page-new-(.*).md
 EditLoginRestrictions: 0
 EditLoginSessionTimeout: 2592000
 EditBruteForceProtection: 25
@@ -74,9 +68,7 @@ ImageUploadJpgQuality: 80
 ImageThumbnailLocation: /media/thumbnails/
 ImageThumbnailDir: media/thumbnails/
 ImageThumbnailJpgQuality: 80
-UpdatePluginsUrl: https://github.com/datenstrom/yellow-plugins
-UpdateThemesUrl: https://github.com/datenstrom/yellow-themes
+UpdateExtensionUrl: https://github.com/datenstrom/yellow-extensions
 UpdateInformationFile: update.ini
 UpdateVersionFile: version.ini
-UpdateResourceFile: resource.ini
-
+UpdateWaffleFile: waffle.ini

+ 2 - 0
system/settings/text.ini

@@ -0,0 +1,2 @@
+# Datenstrom Yellow text settings
+

+ 0 - 0
system/config/user.ini → system/settings/user.ini


+ 0 - 8
system/themes/assets/flatsite.php

@@ -1,8 +0,0 @@
-<?php
-// Flatsite theme, https://github.com/datenstrom/yellow-themes/tree/master/flatsite
-// Copyright (c) 2013-2019 Datenstrom, https://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-class YellowThemeFlatsite {
-    const VERSION = "0.8.1";
-}

BIN
system/themes/assets/icon.png


+ 0 - 11
system/themes/snippets/footer.php

@@ -1,11 +0,0 @@
-<div class="footer" role="contentinfo">
-<div class="siteinfo">
-<?php if ($yellow->page->isPage("footer")) echo $yellow->page->getPage("footer")->getContent() ?>
-</div>
-<div class="siteinfo-banner"></div>
-</div>
-</div>
-</div>
-<?php echo $yellow->page->getExtra("footer") ?>
-</body>
-</html>

+ 0 - 27
system/themes/snippets/header.php

@@ -1,27 +0,0 @@
-<!DOCTYPE html><html lang="<?php echo $yellow->page->getHtml("language") ?>">
-<head>
-<title><?php echo $yellow->page->getHtml("titleHeader") ?></title>
-<meta charset="utf-8" />
-<meta name="description" content="<?php echo $yellow->page->getHtml("description") ?>" />
-<meta name="keywords" content="<?php echo $yellow->page->getHtml("keywords") ?>" />
-<meta name="author" content="<?php echo $yellow->page->getHtml("author") ?>" />
-<meta name="generator" content="Datenstrom Yellow" />
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<?php echo $yellow->page->getExtra("header") ?>
-</head>
-<body>
-<?php if ($page = $yellow->pages->shared($yellow->page->location, false, $yellow->page->get("header"))) $yellow->page->setPage("header", $page) ?>
-<?php if ($page = $yellow->pages->shared($yellow->page->location, false, $yellow->page->get("footer"))) $yellow->page->setPage("footer", $page) ?>
-<?php if ($page = $yellow->pages->shared($yellow->page->location, false, $yellow->page->get("sidebar"))) $yellow->page->setPage("sidebar", $page) ?>
-<?php if ($yellow->page->get("navigation")=="navigation-sidebar") $yellow->page->setPage("navigation-sidebar", $yellow->page->getParentTop(true)) ?>
-<?php $yellow->page->set("pageClass", "page template-".$yellow->page->get("template")) ?>
-<?php if (!$yellow->page->isError() && ($yellow->page->isPage("sidebar") || $yellow->page->isPage("navigation-sidebar"))) $yellow->page->set("pageClass", $yellow->page->get("pageClass")." with-sidebar") ?>
-<div class="<?php echo $yellow->page->getHtml("pageClass") ?>">
-<div class="header" role="banner">
-<div class="sitename">
-<h1><a href="<?php echo $yellow->page->getBase(true)."/" ?>"><i class="sitename-logo"></i><?php echo $yellow->page->getHtml("sitename") ?></a></h1>
-<?php if ($yellow->page->isPage("header")) echo $yellow->page->getPage("header")->getContent() ?>
-</div>
-<div class="sitename-banner"></div>
-<?php $yellow->snippet($yellow->page->get("navigation")) ?>
-</div>

+ 0 - 9
system/themes/templates/default.html

@@ -1,9 +0,0 @@
-<?php $yellow->snippet("header") ?>
-<div class="content">
-<?php $yellow->snippet("sidebar") ?>
-<div class="main" role="main">
-<h1><?php echo $yellow->page->getHtml("titleContent") ?></h1>
-<?php echo $yellow->page->getContent() ?>
-</div>
-</div>
-<?php $yellow->snippet("footer") ?>

+ 0 - 8
system/themes/templates/error.html

@@ -1,8 +0,0 @@
-<?php $yellow->snippet("header") ?>
-<div class="content">
-<div class="main" role="main">
-<h1><?php echo $yellow->page->getHtml("titleContent") ?></h1>
-<?php echo $yellow->page->getContent() ?>
-</div>
-</div>
-<?php $yellow->snippet("footer") ?>

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff