commit c124aad12cd9005d567b2c9c6d3ecfce342d1e46
parent b8d7052a277aeb0d1a9f8b07090baa2c02c256b5
Author: markseu <mark2011@mayberg.se>
Date: Sun, 1 Dec 2013 12:59:07 +0100
Code cleanup
Diffstat:
21 files changed, 1249 insertions(+), 1250 deletions(-)
diff --git a/.htaccess b/.htaccess
@@ -7,7 +7,7 @@ RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(content|system)/ error404 [L]
RewriteCond %{REQUEST_URI} \.(css|js|png|woff)$
-RewriteRule ^media/plugins/(core_.+) system/core/$1 [L]
+RewriteRule ^media/plugins/(core-.+) system/core/$1 [L]
RewriteCond %{REQUEST_URI} \.(css|js|png|woff)$
RewriteRule ^media/plugins/(.+) system/plugins/$1 [L]
diff --git a/README.md b/README.md
@@ -16,17 +16,15 @@ How to make a website?
----------------------
You already have everything you need, start by editing the default pages.
For more information see [Yellow documentation](https://github.com/markseu/yellowcms-extensions/blob/master/documentation/README.md).
-
-License and acknowledgments
----------------------------
-* Yellow and Yellow extensions are licensed under [GPLv2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
-* [PHP Markdown](https://github.com/michelf/php-markdown) by Michel Fortin is licensed under [BSD license](http://opensource.org/licenses/BSD-3-Clause)
-* [Font Awesome](https://github.com/FortAwesome/Font-Awesome) by Dave Gandy is licensed under [OFLv1.1](http://opensource.org/licenses/OFL-1.1)
-
-Yellow is open source. You can use it for free.
-
+
+License and acknowledgments
+---------------------------
+* Yellow and extensions are licensed under [GPLv2](http://opensource.org/licenses/GPL-2.0)
+* [PHP Markdown Extra](https://github.com/michelf/php-markdown) by Michel Fortin is licensed under [BSD license](http://opensource.org/licenses/BSD-3-Clause)
+* [Font Awesome](https://github.com/FortAwesome/Font-Awesome) by Dave Gandy is licensed under [OFLv1.1](http://opensource.org/licenses/OFL-1.1)
+
Need help? Have a question?
----------------------------
+---------------------------
Looking for something, then get in touch with other users.
Visit [Yellow on Reddit](http://www.reddit.com/r/yellowcms/),
follow [Yellow on Twitter](https://twitter.com/yellowcms).
\ No newline at end of file
diff --git a/media/images/default_icon.png b/media/images/icon.png
Binary files differ.
diff --git a/system/config/config.ini b/system/config/config.ini
@@ -6,7 +6,7 @@ author = Yellow
language = en
template = default
style = default
-parser = markdown
+parser = markdownextra
// serverName = your.domain.name
// serverBase = /yellow
@@ -28,4 +28,4 @@ contentDefaultFile = page.txt
contentExtension = .txt
configExtension = .ini
errorPageFile = error(.*).txt
-textStringFile = text_(.*).ini
-\ No newline at end of file
+textStringFile = text(.*).ini
+\ No newline at end of file
diff --git a/system/config/text_english.ini b/system/config/textenglish.ini
diff --git a/system/core/core-commandline.php b/system/core/core-commandline.php
@@ -0,0 +1,267 @@
+<?php
+// Copyright (c) 2013 Datenstrom, http://datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Command line core plugin
+class YellowCommandline
+{
+ const Version = "0.2.1";
+ var $yellow; //access to API
+
+ // Initialise plugin
+ function onLoad($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->yellow->config->setDefault("commandBuildDefaultFile", "index.html");
+ $this->yellow->config->setDefault("commandBuildCustomMediaExtension", ".txt");
+ $this->yellow->config->setDefault("commandBuildCustomErrorFile", "error404.html");
+ }
+
+ // Handle command
+ function onCommand($args)
+ {
+ list($name, $command) = $args;
+ switch($command)
+ {
+ case "build": $statusCode = $this->build($args); break;
+ case "version": $statusCode = $this->version(); break;
+ default: $statusCode = $this->help();
+ }
+ return $statusCode;
+ }
+
+ // Show available commands
+ function help()
+ {
+ echo "Yellow command line ".YellowCommandline::Version."\n";
+ echo "Syntax: yellow.php build DIRECTORY [LOCATION]\n";
+ echo " yellow.php version\n";
+ return 0;
+ }
+
+ // Show software version
+ function version()
+ {
+ echo "Yellow ".Yellow::Version."\n";
+ foreach($this->yellow->plugins->plugins as $key=>$value) echo "$value[class] $value[version]\n";
+ return 0;
+ }
+
+ // Build website
+ function build($args)
+ {
+ $statusCode = 0;
+ list($name, $command, $path, $location) = $args;
+ if(!empty($path) && $path!="/")
+ {
+ if($this->yellow->config->isExisting("serverName") && $this->yellow->config->isExisting("serverBase"))
+ {
+ $serverName = $this->yellow->config->get("serverName");
+ $serverBase = $this->yellow->config->get("serverBase");
+ list($statusCode, $content, $media, $system, $error) = $this->buildStatic($serverName, $serverBase, $location, $path);
+ } else {
+ list($statusCode, $content, $media, $system, $error) = array(500, 0, 0, 0, 1);
+ $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
+ echo "ERROR bulding website: Please configure serverName and serverBase in file '$fileName'!\n";
+ }
+ echo "Yellow build: $content content, $media media, $system system";
+ echo ", $error error".($error!=1 ? 's' : '');
+ echo ", status $statusCode\n";
+ } else {
+ echo "Yellow build: Invalid arguments\n";
+ }
+ return $statusCode;
+ }
+
+ // Build static files
+ function buildStatic($serverName, $serverBase, $location, $path)
+ {
+ $this->yellow->toolbox->timerStart($time);
+ $statusCodeMax = $error = 0;
+ if(empty($location))
+ {
+ $pages = $this->yellow->pages->index(true);
+ $fileNamesMedia = $this->yellow->toolbox->getDirectoryEntriesrecursive(
+ $this->yellow->config->get("mediaDir"), "/.*/", false, false);
+ $fileNamesMedia = array_merge($fileNamesMedia, $this->yellow->toolbox->getDirectoryEntries(
+ ".", "/.*\\".$this->yellow->config->get("commandBuildCustomMediaExtension")."/", false, false));
+ $fileNamesSystem = array($this->yellow->config->get("commandBuildCustomErrorFile"));
+ } else {
+ $pages = new YellowPageCollection($this->yellow, $location);
+ $pages->append(new YellowPage($this->yellow, $location));
+ $fileNamesMedia = array();
+ $fileNamesSystem = array();
+ }
+ foreach($pages as $page)
+ {
+ $statusCode = $this->buildStaticLocation($serverName, $serverBase, $page->location, $path);
+ $statusCodeMax = max($statusCodeMax, $statusCode);
+ if($statusCode >= 400)
+ {
+ ++$error;
+ echo "ERROR building location '".$page->location."', ".$this->yellow->page->getStatusCode(true)."\n";
+ }
+ if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic status:$statusCode location:".$page->location."\n";
+ }
+ foreach($fileNamesMedia as $fileName)
+ {
+ $statusCode = $this->copyStaticFile($fileName, "$path/$fileName") ? 200 : 500;
+ $statusCodeMax = max($statusCodeMax, $statusCode);
+ if($statusCode >= 400)
+ {
+ ++$error;
+ echo "ERROR building media file '$path/$fileName', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
+ }
+ if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic status:$statusCode file:$fileName\n";
+ }
+ foreach($fileNamesSystem as $fileName)
+ {
+ $statusCode = $this->buildStaticError($serverName, $serverBase, "$path/$fileName", 404) ? 200 : 500;
+ $statusCodeMax = max($statusCodeMax, $statusCode);
+ if($statusCode >= 400)
+ {
+ ++$error;
+ echo "ERROR building system file '$path/$fileName', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
+ }
+ if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic status:$statusCode file:$fileName\n";
+ }
+ $this->yellow->toolbox->timerStop($time);
+ if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStatic time:$time ms\n";
+ return array($statusCodeMax, count($pages), count($fileNamesMedia), count($fileNamesSystem), $error);
+ }
+
+ // Build static location as file
+ function buildStaticLocation($serverName, $serverBase, $location, $path)
+ {
+ ob_start();
+ $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
+ $_SERVER["SERVER_NAME"] = $serverName;
+ $_SERVER["REQUEST_URI"] = $serverBase.$location;
+ $_SERVER["SCRIPT_NAME"] = $serverBase."yellow.php";
+ $statusCode = $this->yellow->request();
+ if($statusCode != 404)
+ {
+ $fileOk = true;
+ $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
+ list($contentType, $contentEncoding) = explode(';', $this->yellow->page->getHeader("Content-Type"), 2);
+ $staticLocation = $this->getStaticLocation($location, $contentType);
+ if($location == $staticLocation)
+ {
+ $fileName = $this->getStaticFileName($location, $path);
+ $fileData = ob_get_contents();
+ if($statusCode>=301 && $statusCode<=303) $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
+ $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
+ } else {
+ if(!$this->yellow->toolbox->isFileLocation($location))
+ {
+ $fileName = $this->getStaticFileName($location, $path);
+ $fileData = $this->getStaticRedirect("http://$serverName$serverBase$staticLocation");
+ $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
+ if($fileOk)
+ {
+ $fileName = $this->getStaticFileName($staticLocation, $path);
+ $fileData = ob_get_contents();
+ $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
+ }
+ } else {
+ $statusCode = 409;
+ $this->yellow->page->error($statusCode, "Type '$contentType' does not match file name!");
+ }
+ }
+ if(!$fileOk)
+ {
+ $statusCode = 500;
+ $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
+ }
+ }
+ ob_end_clean();
+ return $statusCode;
+ }
+
+ // Build static error as file
+ function buildStaticError($serverName, $serverBase, $fileName, $statusCodeRequest)
+ {
+ ob_start();
+ $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
+ $_SERVER["SERVER_NAME"] = $serverName;
+ $_SERVER["REQUEST_URI"] = $serverBase."/";
+ $_SERVER["SCRIPT_NAME"] = $serverBase."yellow.php";
+ $statusCode = $this->yellow->request($statusCodeRequest);
+ if($statusCode == $statusCodeRequest)
+ {
+ $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
+ if(!$this->makeStaticFile($fileName, ob_get_contents(), $modified))
+ {
+ $statusCode = 500;
+ $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
+ }
+ }
+ ob_end_clean();
+ return $statusCode == $statusCodeRequest;
+ }
+
+ // Create static file
+ function makeStaticFile($fileName, $fileData, $modified)
+ {
+ return $this->yellow->toolbox->makeFile($fileName, $fileData, true) &&
+ $this->yellow->toolbox->modifyFile($fileName, $modified);
+ }
+
+ // Copy static file
+ function copyStaticFile($fileNameSource, $fileNameDest)
+ {
+ return $this->yellow->toolbox->copyFile($fileNameSource, $fileNameDest, true) &&
+ $this->yellow->toolbox->modifyFile($fileNameDest, filemtime($fileNameSource));
+ }
+
+ // Return static location corresponding to content type
+ function getStaticLocation($location, $contentType)
+ {
+ if(!empty($contentType))
+ {
+ $extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
+ if($contentType == "text/html")
+ {
+ if($this->yellow->toolbox->isFileLocation($location))
+ {
+ if(!empty($extension) && $extension!=".html") $location .= ".html";
+ }
+ } else {
+ if($this->yellow->toolbox->isFileLocation($location))
+ {
+ if(empty($extension)) $location .= ".unknown";
+ } else {
+ if(preg_match("/^(\w+)\/(\w+)/", $contentType, $matches)) $extension = ".$matches[2]";
+ $location .= "index$extension";
+ }
+ }
+ }
+ return $location;
+ }
+
+ // Return static file name from location
+ function getStaticFileName($location, $path)
+ {
+ $fileName = $path.$location;
+ if(!$this->yellow->toolbox->isFileLocation($location))
+ {
+ $fileName .= $this->yellow->config->get("commandBuildDefaultFile");
+ }
+ return $fileName;
+ }
+
+ // Return static redirect data
+ function getStaticRedirect($url)
+ {
+ $data = "<!DOCTYPE html><html>\n";
+ $data .= "<head>\n";
+ $data .= "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
+ $data .= "<meta http-equiv=\"refresh\" content=\"0;url=$url\" />\n";
+ $data .= "</head>\n";
+ $data .= "</html>\n";
+ return $data;
+ }
+}
+
+$yellow->registerPlugin("commandline", "YellowCommandline", YellowCommandline::Version);
+?>
+\ No newline at end of file
diff --git a/system/core/core_fontawesome.woff b/system/core/core-fontawesome.woff
Binary files differ.
diff --git a/system/core/core-markdownextra.php b/system/core/core-markdownextra.php
@@ -0,0 +1,112 @@
+<?php
+// Copyright (c) 2013 Datenstrom, http://datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Markdown extra parser core plugin
+class YellowMarkdownExtra
+{
+ const Version = "0.2.1";
+ var $yellow; //access to API
+ var $textHtml; //generated text (HTML format)
+
+ // Initialise plugin
+ function onLoad($yellow)
+ {
+ $this->yellow = $yellow;
+ }
+
+ // Parse text
+ function parse($text)
+ {
+ $markdown = new YellowMarkdownExtraParser($this->yellow);
+ return $this->textHtml = $markdown->transform($text);
+ }
+}
+
+require_once("markdown.php");
+
+class YellowMarkdownExtraParser extends MarkdownExtra_Parser
+{
+ var $yellow; //access to API
+
+ function __construct($yellow)
+ {
+ $this->yellow = $yellow;
+ parent::__construct();
+ }
+
+ // Transform text
+ function transform($text)
+ {
+ $text = preg_replace("/@pageRead/i", $this->yellow->page->get("pageRead"), $text);
+ $text = preg_replace("/@pageEdit/i", $this->yellow->page->get("pageEdit"), $text);
+ $text = preg_replace("/@pageError/i", $this->yellow->page->get("pageError"), $text);
+ return parent::transform($text);
+ }
+
+ // Handle links
+ function doAutoLinks($text)
+ {
+ $text = preg_replace_callback("/<(\w+:[^\'\">\s]+)>/", array(&$this, "_doAutoLinks_url_callback"), $text);
+ $text = preg_replace_callback("/<(\w+@[\w\-\.]+)>/", array(&$this, "_doAutoLinks_email_callback"), $text);
+ $text = preg_replace_callback("/\[(\w+)\s+(.*?)\]/", array(&$this, "_doAutoLinks_shortcut_callback"), $text);
+ return $text;
+ }
+
+ // Handle shortcuts
+ function _doAutoLinks_shortcut_callback($matches)
+ {
+ $text = preg_replace("/\s+/s", " ", $matches[2]);
+ $output = $this->yellow->page->parseType($matches[1], $text, true);
+ if(is_null($output)) $output = $matches[0];
+ return $this->hashBlock($output);
+ }
+
+ // Handle fenced code blocks
+ function _doFencedCodeBlocks_callback($matches)
+ {
+ $text = $matches[4];
+ $output = $this->yellow->page->parseType($matches[2], $text, false);
+ if(is_null($output))
+ {
+ $attr = $this->doExtraAttributes("pre", $dummy =& $matches[3]);
+ $output = "<pre$attr><code>".htmlspecialchars($text, ENT_NOQUOTES)."</code></pre>";
+ }
+ return "\n\n".$this->hashBlock($output)."\n\n";
+ }
+
+ // Handle inline links
+ function _doAnchors_inline_callback($matches)
+ {
+ $url = $matches[3]=="" ? $matches[4] : $matches[3];
+ $text = $matches[2];
+ $title = $matches[7];
+ $attr = $this->doExtraAttributes("a", $dummy =& $matches[8]);
+ $output = "<a href=\"".$this->encodeAttribute($url)."\"";
+ if(!empty($title)) $output .= " title=\"".$this->encodeAttribute($title)."\"";
+ $output .= $attr;
+ $output .= ">".$this->runSpanGamut($text)."</a>";
+ return $this->hashPart($output);
+ }
+
+ // Handle inline images
+ function _doImages_inline_callback($matches)
+ {
+ $path = $matches[3]=="" ? $matches[4] : $matches[3];
+ $src = $this->yellow->config->get("serverBase").$this->yellow->config->get("imageLocation").$path;
+ list($width, $height) = $this->yellow->toolbox->detectImageDimensions($this->yellow->config->get("imageDir").$path);
+ $alt = $matches[2];
+ $title = $matches[7];
+ $attr = $this->doExtraAttributes("img", $dummy =& $matches[8]);
+ $output = "<img src=\"".$this->encodeAttribute($src)."\"";
+ if($width && $height) $output .= " width=\"$width\" height=\"$height\"";
+ if(!empty($alt)) $output .= " alt=\"".$this->encodeAttribute($alt)."\"";
+ if(!empty($title)) $output .= " title=\"".$this->encodeAttribute($title)."\"";
+ $output .= $attr;
+ $output .= $this->empty_element_suffix;
+ return $this->hashPart($output);
+ }
+}
+
+$yellow->registerPlugin("markdownextra", "YellowMarkdownExtra", YellowMarkdownExtra::Version);
+?>
+\ No newline at end of file
diff --git a/system/core/core-webinterface.css b/system/core/core-webinterface.css
@@ -0,0 +1,65 @@
+/* Yellow web interface 0.1.3 */
+
+.yellow-bar { position:relative; overflow:hidden; line-height:2.0em; }
+.yellow-barleft { display:block; float:left; }
+.yellow-barleft a { margin-right:1em; }
+.yellow-barright { display:block; float:right; }
+
+.yellow-pane {
+ position:absolute; display:none; z-index:10;
+ margin:0; padding:5px;
+ background-color:#fff; color:#000;
+ border:1px solid #bbb;
+ border-radius:4px;
+}
+.yellow-pane a { color:#000; text-decoration:none; }
+.yellow-pane a:hover { color:#f00; text-decoration:none; }
+.yellow-pane p { margin:0.5em; }
+.yellow-pane ul { list-style:none; margin:0 0.5em; padding:0; }
+.yellow-pane div { overflow:hidden; }
+.yellow-panebubble { }
+
+.yellow-btn {
+ margin:0; padding:4px 22px;
+ background-color:#eaeaea; color:#333333;
+ background-image:linear-gradient(to bottom, #ffffff, #e1e1e1);
+ background-repeat:repeat-x;
+ border:1px solid #bbb;
+ border-color:#d1d1d1 #d1d1d1 #aaaaaa;
+ border-radius:4px;
+ outline-offset:-2px;
+ font-size:0.9em;
+}
+.yellow-btn:hover, .yellow-btn:focus, .yellow-btn:active { background-image:none; }
+.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); }
+.yellow-btn-warn {
+ background-color:#c33c35; color:#ffffff;
+ background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);
+ border-color:#b13121 #b13121 #802020;
+ text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+.yellow-btn-warn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.3); }
+
+#yellow-panelogin { }
+#yellow-panelogin h1 { margin:0.5em 0.5em; }
+#yellow-panelogin p { margin:0.5em; text-align:right; }
+#yellow-paneedit { }
+#yellow-paneedit #yellow-edittext { margin:0; padding:5px; border:1px solid #bbb; resize:none; font-size:0.9em }
+#yellow-paneedit #yellow-editinfo { margin:0; padding:5px; border:1px solid #bbb; display:none; }
+#yellow-paneedit #yellow-editbuttons { margin:5px 0; }
+#yellow-paneshow { min-width:20em; overflow:auto; }
+#yellow-paneuser { }
+
+/* Font icons from Fontawesome */
+
+@font-face { font-family:'FontAwesome'; font-style:normal; font-weight:normal; src:url('core-fontawesome.woff'); }
+[class*="yellow-icon-"] {
+ font-family:FontAwesome;
+ font-style:normal;
+ font-weight:normal;
+ -webkit-font-smoothing:antialiased;
+}
+.yellow-icon-search:before { content:"\f002"; }
+.yellow-icon-trash-o:before { content:"\f014"; }
+.yellow-icon-caret-down:before { content:"\f0d7"; }
+.yellow-icon-caret-up:before { content:"\f0d8"; }
+\ No newline at end of file
diff --git a/system/core/core-webinterface.js b/system/core/core-webinterface.js
@@ -0,0 +1,422 @@
+// Copyright (c) 2013 Datenstrom, http://datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Yellow main API
+var yellow =
+{
+ version: "0.2.1",
+ onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); },
+ onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); },
+ onResize: function() { yellow.webinterface.resizePanes(); },
+ onShow: function(id) { yellow.webinterface.showPane(id); },
+ webinterface:{}, page:{}, pages:{}, toolbox:{}, config:{}, text:{}
+}
+
+// Yellow web interface
+yellow.webinterface =
+{
+ created: false, //interface created? (boolean)
+ intervalId: 0, //interface timer interval ID
+
+ // Initialise web interface
+ init: function()
+ {
+ this.intervalId = setInterval("yellow.webinterface.create()", 1);
+ yellow.toolbox.addEvent(window, "resize", yellow.onResize);
+ yellow.toolbox.addEvent(document, "click", yellow.onClick);
+ yellow.toolbox.addEvent(document, "keydown", yellow.onKeydown);
+ },
+
+ // Create web interface
+ create: function()
+ {
+ var body = document.getElementsByTagName("body")[0];
+ if(body && body.firstChild && !this.created)
+ {
+ this.created = true;
+ if(yellow.debug) console.log("yellow.webinterface.create email:"+yellow.config.userEmail+" "+yellow.config.userName);
+ if(yellow.config.userEmail)
+ {
+ yellow.toolbox.insertBefore(this.createBar("yellow-bar"), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellow-paneedit"), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellow-paneshow"), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellow-paneuser"), body.firstChild);
+ yellow.toolbox.setText(document.getElementById("yellow-username"), yellow.config.userName);
+ yellow.toolbox.setText(document.getElementById("yellow-edittext"), yellow.page.rawData);
+ } else {
+ yellow.toolbox.insertBefore(this.createBar("yellow-bar", true), body.firstChild);
+ yellow.toolbox.insertAfter(this.createPane("yellow-panelogin", true), body.firstChild);
+ this.showPane("yellow-panelogin");
+ }
+ clearInterval(this.intervalId);
+ }
+ },
+
+ // Create bar
+ createBar: function(id, simple)
+ {
+ if(yellow.debug) console.log("yellow.webinterface.createBar id:"+id);
+ var elementBar = document.createElement("div");
+ elementBar.className = "yellow-bar yellow";
+ elementBar.setAttribute("id", id);
+ if(!simple)
+ {
+ var location = yellow.config.serverBase+yellow.config.pluginLocation;
+ elementBar.innerHTML =
+ "<div class=\"yellow-barleft\">"+
+ "<a href=\"http://datenstrom.se/yellow/\" target=\"_blank\"><img src=\""+location+"core-webinterface.png\" width=\"16\" height=\"16\"> Yellow</a>"+
+ "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneedit'); return false;\">"+this.getText("Edit")+"</a>"+
+ "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneshow'); return false;\">"+this.getText("Show")+"</a>"+
+ "</div>"+
+ "<div class=\"yellow-barright\">"+
+ "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneuser'); return false;\" id=\"yellow-username\">"+this.getText("User")+"</a>"+
+ "</div>";
+ }
+ return elementBar;
+ },
+
+ // Create pane
+ createPane: function(id, simple)
+ {
+ if(yellow.debug) console.log("yellow.webinterface.createPane id:"+id);
+ var elementPane = document.createElement("div");
+ elementPane.className = simple ? "yellow-pane" : "yellow-pane yellow-panebubble";
+ elementPane.setAttribute("id", id);
+ elementPane.style.display = "none";
+ var elementDiv = document.createElement("div");
+ elementDiv.setAttribute("id", id+"content");
+ if(id == "yellow-panelogin")
+ {
+ elementDiv.innerHTML =
+ "<h1>"+this.getText("LoginText")+"</h1>"+
+ "<form method=\"post\" name=\"formlogin\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"login\"/>"+
+ "<p><label for=\"email\">"+this.getText("LoginEmail")+"</label> <input name=\"email\" id=\"email\" maxlength=\"64\" /></p>"+
+ "<p><label for=\"password\">"+this.getText("LoginPassword")+"</label> <input type=\"password\" name=\"password\" id=\"password\" maxlength=\"64\" /></p>"+
+ "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\"/></p>"+
+ "</form>";
+ } else if(id == "yellow-paneedit") {
+ elementDiv.innerHTML =
+ "<p>Editing page...</p>"+
+ "<form method=\"post\" name=\"formeditor\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"edit\"/>"+
+ "<textarea id=\"yellow-edittext\" name=\"rawdata\"></textarea>"+
+ "<div id=\"yellow-editinfo\"/></div>"+
+ "<div id=\"yellow-editbuttons\">"+
+ "<input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SaveButton")+"\"/>"+
+ "</div>"+
+ "</form>";
+ } else if(id == "yellow-paneshow") {
+ elementDiv.innerHTML = "<p>Showing files...</p>";
+ var elementUl = document.createElement("ul");
+ for(var n in yellow.pages)
+ {
+ var elementLi = document.createElement("li");
+ var elementA = document.createElement("a");
+ elementA.setAttribute("href", yellow.pages[n]["location"]);
+ yellow.toolbox.setText(elementA, yellow.pages[n]["title"]);
+ elementLi.appendChild(elementA);
+ elementUl.appendChild(elementLi);
+ }
+ elementDiv.appendChild(elementUl);
+ } else if(id == "yellow-paneuser") {
+ elementDiv.innerHTML =
+ "<p>"+yellow.config.userEmail+"</p>"+
+ "<form method=\"post\" name=\"formlogout\">"+
+ "<input type=\"hidden\" name=\"action\" value=\"logout\"/>"+
+ "<p><a href=\"javascript:document.formlogout.submit();\">"+this.getText("UserLogout")+"</a></p> "+
+ "</form>";
+ }
+
+ elementPane.appendChild(elementDiv);
+ return elementPane;
+ },
+
+ // Show or hide pane
+ showPane: function(id)
+ {
+ if(!yellow.toolbox.isVisible(document.getElementById(id)))
+ {
+ this.hidePanes();
+ if(yellow.debug) console.log("yellow.webinterface.showPane id:"+id);
+ document.getElementById(id).style.display = "block";
+ this.resizePanes();
+ } else {
+ this.hidePane(id);
+ }
+ },
+
+ // Hide pane
+ hidePane: function(id)
+ {
+ if(yellow.toolbox.isVisible(document.getElementById(id)))
+ {
+ if(yellow.debug) console.log("yellow.webinterface.hidePane id:"+id);
+ document.getElementById(id).style.display = "none";
+ }
+ },
+
+ // Hide all panes
+ hidePanes: function()
+ {
+ for(var element=document.getElementById("yellow-bar"); element; element=element.nextSibling)
+ {
+ if(element.className && element.className.indexOf("yellow-pane")>=0)
+ {
+ this.hidePane(element.getAttribute("id"));
+ }
+ }
+ },
+
+ // Hide all panes on mouse click outside
+ hidePanesOnClick: function(element)
+ {
+ while(element = element.parentNode)
+ {
+ if(element.className)
+ {
+ if(element.className.indexOf("yellow-pane")>=0 || element.className.indexOf("yellow-bar")>=0) return;
+ }
+ }
+ this.hidePanes();
+ },
+
+ // Hide all panes on ESC key
+ hidePanesOnKeydown: function(keycode)
+ {
+ if(keycode == 27) this.hidePanes();
+ },
+
+ // Resize panes, recalculate width and height where needed
+ resizePanes: function()
+ {
+ if(document.getElementById("yellow-bar"))
+ {
+ var elementBar = document.getElementById("yellow-bar");
+ var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar);
+ var paneWidth = yellow.toolbox.getOuterWidth(elementBar, true);
+ var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar);
+ if(yellow.toolbox.isVisible(document.getElementById("yellow-panelogin")))
+ {
+ yellow.toolbox.setOuterWidth(document.getElementById("yellow-panelogin"), paneWidth);
+ }
+ if(yellow.toolbox.isVisible(document.getElementById("yellow-paneedit")))
+ {
+ yellow.toolbox.setOuterTop(document.getElementById("yellow-paneedit"), paneTop);
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneedit"), paneHeight);
+ yellow.toolbox.setOuterWidth(document.getElementById("yellow-paneedit"), paneWidth);
+ yellow.toolbox.setOuterWidth(document.getElementById("yellow-edittext"), yellow.toolbox.getWidth(document.getElementById("yellow-paneedit")));
+ var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-paneedit"));
+ var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-paneeditcontent"));
+ var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-edittext"));
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-edittext"), height1 - height2 + height3);
+ }
+ if(yellow.toolbox.isVisible(document.getElementById("yellow-paneshow")))
+ {
+ yellow.toolbox.setOuterTop(document.getElementById("yellow-paneshow"), paneTop);
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneshow"), paneHeight, true);
+ }
+ if(yellow.toolbox.isVisible(document.getElementById("yellow-paneuser")))
+ {
+ yellow.toolbox.setOuterTop(document.getElementById("yellow-paneuser"), paneTop);
+ yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneuser"), paneHeight, true);
+ yellow.toolbox.setOuterLeft(document.getElementById("yellow-paneuser"), paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-paneuser")), true);
+ }
+ if(yellow.debug) console.log("yellow.webinterface.resizePanes bar:"+elementBar.offsetWidth+"/"+elementBar.offsetHeight);
+ }
+ },
+
+ // Return text string
+ getText: function(key)
+ {
+ return ("webinterface"+key in yellow.text) ? yellow.text["webinterface"+key] : "[webinterface"+key+"]";
+ }
+}
+
+// Yellow toolbox with helpers
+yellow.toolbox =
+{
+ // Set element text
+ setText: function(element, text)
+ {
+ while(element.firstChild !== null) element.removeChild(element.firstChild);
+ element.appendChild(document.createTextNode(text));
+ },
+
+ // Insert element before element
+ insertBefore: function(newElement, referenceElement)
+ {
+ referenceElement.parentNode.insertBefore(newElement, referenceElement);
+ },
+
+ // Insert element after element
+ insertAfter: function(newElement, referenceElement)
+ {
+ referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
+ },
+
+ // Add event handler
+ addEvent: function(element, type, handler)
+ {
+ if(element.addEventListener) element.addEventListener(type, handler, false);
+ else element.attachEvent('on'+type, handler);
+ },
+
+ // Return element of event
+ getEventElement: function(e)
+ {
+ e = e ? e : window.event;
+ return e.target ? e.target : e.srcElement;
+ },
+
+ // Return keycode of event
+ getEventKeycode: function(e)
+ {
+ e = e ? e : window.event;
+ return e.keyCode
+ },
+
+ // Set element width/height in pixel, including padding and border
+ setOuterWidth: function(element, width, maxWidth)
+ {
+ width -= this.getBoxSize(element).width;
+ if(maxWidth)
+ {
+ element.style.maxWidth = Math.max(0, width) + "px";
+ } else {
+ element.style.width = Math.max(0, width) + "px";
+ }
+ },
+
+ setOuterHeight: function(element, height, maxHeight)
+ {
+ height -=this.getBoxSize(element).height;
+ if(maxHeight)
+ {
+ element.style.maxHeight = Math.max(0, height) + "px";
+ } else {
+ element.style.height = Math.max(0, height) + "px";
+ }
+ },
+
+ // Return element width/height in pixel, including padding and border
+ getOuterWidth: function(element, includeMargin)
+ {
+ width = element.offsetWidth;
+ if(includeMargin) width += this.getMarginSize(element).width;
+ return width;
+ },
+
+ getOuterHeight: function(element, includeMargin)
+ {
+ height = element.offsetHeight;
+ if(includeMargin) height += this.getMarginSize(element).height;
+ return height;
+ },
+
+ // Return element width/height in pixel
+ getWidth: function(element)
+ {
+ return element.offsetWidth - this.getBoxSize(element).width;
+ },
+
+ getHeight: function(element)
+ {
+ return element.offsetHeight - this.getBoxSize(element).height;
+ },
+
+ // Set element top/left position in pixel
+ setOuterTop: function(element, top, marginTop)
+ {
+ if(marginTop)
+ {
+ element.style.marginTop = Math.max(0, top) + "px";
+ } else {
+ element.style.top = Math.max(0, top) + "px";
+ }
+ },
+
+ setOuterLeft: function(element, left, marginLeft)
+ {
+ if(marginLeft)
+ {
+ element.style.marginLeft = Math.max(0, left) + "px";
+ } else {
+ element.style.left = Math.max(0, left) + "px";
+ }
+ },
+
+ // Return element top/left position in pixel
+ getOuterTop: function(element)
+ {
+ var top = element.getBoundingClientRect().top;
+ return top + (window.pageYOffset || document.documentElement.scrollTop);
+ },
+
+ getOuterLeft: function(element)
+ {
+ var left = element.getBoundingClientRect().left;
+ return left + (window.pageXOffset || document.documentElement.scrollLeft);
+ },
+
+ // Return window width/height in pixel
+ getWindowWidth: function()
+ {
+ return window.innerWidth || document.documentElement.clientWidth;
+ },
+
+ getWindowHeight: function()
+ {
+ return window.innerHeight || document.documentElement.clientHeight;
+ },
+
+ // Return element CSS property
+ getStyle: function(element, property)
+ {
+ var string = "";
+ if(window.getComputedStyle)
+ {
+ string = window.getComputedStyle(element, null).getPropertyValue(property);
+ } else {
+ property = property.replace(/\-(\w)/g, function(match, m) { return m.toUpperCase(); });
+ string = element.currentStyle[property];
+ }
+ return string;
+ },
+
+ // Return element CSS padding and border
+ getBoxSize: function(element)
+ {
+ var paddingLeft = parseFloat(this.getStyle(element, "padding-left")) || 0;
+ var paddingRight = parseFloat(this.getStyle(element, "padding-right")) || 0;
+ var borderLeft = parseFloat(this.getStyle(element, "border-left-width")) || 0;
+ var borderRight = parseFloat(this.getStyle(element, "border-right-width")) || 0;
+ var width = paddingLeft + paddingRight + borderLeft + borderRight;
+ var paddingTop = parseFloat(this.getStyle(element, "padding-top")) || 0;
+ var paddingBottom = parseFloat(this.getStyle(element, "padding-bottom")) || 0;
+ var borderTop = parseFloat(this.getStyle(element, "border-top-width")) || 0;
+ var borderBottom = parseFloat(this.getStyle(element, "border-bottom-width")) || 0;
+ var height = paddingTop + paddingBottom + borderTop + borderBottom;
+ return { "width":width, "height":height };
+ },
+
+ // Return element CSS margin
+ getMarginSize: function(element)
+ {
+ var marginLeft = parseFloat(this.getStyle(element, "margin-left")) || 0;
+ var marginRight = parseFloat(this.getStyle(element, "margin-right")) || 0;
+ var width = marginLeft + marginRight;
+ var marginTop = parseFloat(this.getStyle(element, "margin-top")) || 0;
+ var marginBottom = parseFloat(this.getStyle(element, "margin-bottom")) || 0;
+ var height = marginTop + marginBottom;
+ return { "width":width, "height":height };
+ },
+
+ // Check if element exists and is visible
+ isVisible: function(element)
+ {
+ return element && element.style.display != "none";
+ }
+}
+
+yellow.webinterface.init();
+\ No newline at end of file
diff --git a/system/core/core-webinterface.php b/system/core/core-webinterface.php
@@ -0,0 +1,327 @@
+<?php
+// Copyright (c) 2013 Datenstrom, http://datenstrom.se
+// This file may be used and distributed under the terms of the public license.
+
+// Web interface core plugin
+class YellowWebinterface
+{
+ const Version = "0.2.1";
+ var $yellow; //access to API
+ var $users; //web interface users
+ var $activeLocation; //web interface location? (boolean)
+ var $activeUserFail; //web interface login failed? (boolean)
+ var $activeUserEmail; //web interface user currently logged in
+ var $rawDataOriginal; //raw data of page in case of errors
+
+ // Initialise plugin
+ function onLoad($yellow)
+ {
+ $this->yellow = $yellow;
+ $this->yellow->config->setDefault("webinterfaceLocation", "/edit/");
+ $this->yellow->config->setDefault("webinterfaceUserFile", "user.ini");
+ $this->users = new YellowWebinterfaceUsers();
+ $this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"));
+ }
+
+ // Handle web interface location
+ function onRequest($serverName, $serverBase, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($this->checkWebinterfaceLocation($location))
+ {
+ $serverBase .= rtrim($this->yellow->config->get("webinterfaceLocation"), '/');
+ $location = $this->yellow->getRelativeLocation($serverBase);
+ $fileName = $this->yellow->getContentFileName($location);
+ if($this->checkUser()) $statusCode = $this->processRequestAction($serverName, $serverBase, $location, $fileName);
+ if($statusCode == 0) $statusCode = $this->yellow->processRequest($serverName, $serverBase, $location, $fileName,
+ false, $this->activeUserFail ? 401 : 0);
+ } else {
+ if($this->yellow->config->get("webinterfaceLocation") == "$location/")
+ {
+ $statusCode = 301;
+ $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, "$location/");
+ $this->yellow->sendStatus($statusCode, $locationHeader);
+ }
+ }
+ return $statusCode;
+ }
+
+ // Handle page content parsing
+ function onParseContent($page, $text)
+ {
+ $output = NULL;
+ if($this->isWebinterfaceLocation() && $this->isUser())
+ {
+ $serverBase = $this->yellow->config->get("serverBase");
+ $webinterfaceLocation = trim($this->yellow->config->get("webinterfaceLocation"), '/');
+ $output = preg_replace("#<a(.*?)href=\"$serverBase/(?!$webinterfaceLocation)(.*?)\"(.*?)>#",
+ "<a$1href=\"$serverBase/$webinterfaceLocation/$2\"$3>", $text);
+ if($page == $this->yellow->page)
+ {
+ switch($page->statusCode)
+ {
+ case 200: $this->rawDataOriginal = $page->rawData; break;
+ case 424: $language = $this->isUser() ? $this->users->getLanguage($this->activeUserEmail) : $page->get("language");
+ $page->rawData = "---\r\n";
+ $page->rawData .= "Title: ".$this->yellow->text->getLanguageText($language, "webinterface424Title")."\r\n";
+ $page->rawData .= "Author: ".$this->users->getName($this->activeUserEmail)."\r\n";
+ $page->rawData .= "---\r\n";
+ $page->rawData .= $this->yellow->text->getLanguageText($language, "webinterface424Text");
+ break;
+ case 500: $page->rawData = $this->rawDataOriginal; break;
+ }
+ }
+ }
+ return $output;
+ }
+
+ // Handle extra HTML header lines
+ function onHeaderExtra()
+ {
+ $header = "";
+ if($this->isWebinterfaceLocation())
+ {
+ $location = $this->yellow->config->getHtml("serverBase").$this->yellow->config->getHtml("pluginLocation");
+ $language = $this->isUser() ? $this->users->getLanguage($this->activeUserEmail) : $this->yellow->page->get("language");
+ $header .= "<link rel=\"styleSheet\" type=\"text/css\" media=\"all\" href=\"{$location}core-webinterface.css\" />\n";
+ $header .= "<script type=\"text/javascript\" src=\"{$location}core-webinterface.js\"></script>\n";
+ $header .= "<script type=\"text/javascript\">\n";
+ $header .= "// <![CDATA[\n";
+ if($this->isUser())
+ {
+ $header .= "yellow.page.rawData = ".json_encode($this->yellow->page->rawData).";\n";
+ $header .= "yellow.pages = ".json_encode($this->getPagesData()).";\n";
+ $header .= "yellow.config = ".json_encode($this->getConfigData($this->activeUserEmail)).";\n";
+ }
+ $header .= "yellow.text = ".json_encode($this->yellow->text->getData($language, "webinterface")).";\n";
+ if(defined("DEBUG")) $header .= "yellow.debug = ".json_encode(DEBUG).";\n";
+ $header .= "// ]]>\n";
+ $header .= "</script>\n";
+ }
+ return $header;
+ }
+
+ // Process request for an action
+ function processRequestAction($serverName, $serverBase, $location, $fileName)
+ {
+ $statusCode = 0;
+ if($_POST["action"] == "edit")
+ {
+ if(!empty($_POST["rawdata"]) && $this->checkUserPermissions($location, $fileName))
+ {
+ $this->rawDataOriginal = $_POST["rawdata"];
+ if($this->yellow->toolbox->makeFile($fileName, $_POST["rawdata"]))
+ {
+ $statusCode = 303;
+ $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, $location);
+ $this->yellow->sendStatus($statusCode, $locationHeader);
+ } else {
+ $statusCode = 500;
+ $this->yellow->processRequest($serverName, $serverBase, $location, $fileName, false, $statusCode);
+ $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
+ }
+ }
+ } else if($_POST["action"]== "login") {
+ $statusCode = 303;
+ $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, $location);
+ $this->yellow->sendStatus($statusCode, $locationHeader);
+ } else if($_POST["action"]== "logout") {
+ $this->users->destroyCookie("login");
+ $this->activeUserEmail = "";
+ $statusCode = 302;
+ $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $this->yellow->config->get("serverBase"), $location);
+ $this->yellow->sendStatus($statusCode, $locationHeader);
+ } else {
+ if(!is_readable($fileName))
+ {
+ if($this->yellow->toolbox->isFileLocation($location) && is_dir($this->yellow->getContentDirectory("$location/")))
+ {
+ $statusCode = 301;
+ $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, "$location/");
+ $this->yellow->sendStatus($statusCode, $locationHeader);
+ } else {
+ $statusCode = $this->checkUserPermissions($location, $fileName) ? 424 : 404;
+ $this->yellow->processRequest($serverName, $serverBase, $location, $fileName, false, $statusCode);
+ }
+ }
+ }
+ return $statusCode;
+ }
+
+ // Check web interface location
+ function checkWebinterfaceLocation($location)
+ {
+ $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation"));
+ $this->activeLocation = substru($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation");
+ return $this->isWebinterfaceLocation();
+ }
+
+ // Check user login
+ function checkUser()
+ {
+ if($_POST["action"] == "login")
+ {
+ $email = $corPOST["email"];
+ $password = $_POST["password"];
+ if($this->users->checkUser($email, $password))
+ {
+ $this->users->createCookie("login", $email);
+ $this->activeUserEmail = $email;
+ } else {
+ $this->activeUserFail = true;
+ }
+ } else if(isset($_COOKIE["login"])) {
+ $cookie = $_COOKIE["login"];
+ if($this->users->checkCookie($cookie))
+ {
+ $this->activeUserEmail = $this->users->getCookieEmail($cookie);
+ } else {
+ $this->activeUserFail = true;
+ }
+ }
+ return $this->isUser();
+ }
+
+ // Check users permissions for creating new page
+ function checkUserPermissions($location, $fileName)
+ {
+ $path = dirname($fileName);
+ return is_dir($path) && strlenu(basename($fileName))<128;
+ }
+
+ // Check if web interface location
+ function isWebinterfaceLocation()
+ {
+ return $this->activeLocation;
+ }
+
+ // Check if user is logged in
+ function isUser()
+ {
+ return !empty($this->activeUserEmail);
+ }
+
+ // Return page tree with content information, two levels
+ function getPagesData()
+ {
+ $data = array();
+ foreach($this->yellow->pages->index(true, 2) as $page)
+ {
+ $data[$page->fileName] = array();
+ $data[$page->fileName]["location"] = $page->getLocation();
+ $data[$page->fileName]["modified"] = $page->getModified();
+ $data[$page->fileName]["title"] = $page->getHtml("title");
+ }
+ return $data;
+ }
+
+ // Return configuration data including user information
+ function getConfigData($email)
+ {
+ $data = array("userEmail" => $email,
+ "userName" => $this->users->getName($email),
+ "userLanguage" => $this->users->getLanguage($email),
+ "serverName" => $this->yellow->config->get("serverName"),
+ "serverBase" => $this->yellow->config->get("serverBase"));
+ return array_merge($data, $this->yellow->config->getData("Location"));
+ }
+}
+
+// Yellow web interface users
+class YellowWebinterfaceUsers
+{
+ var $users; //registered users
+
+ function __construct()
+ {
+ $this->users = array();
+ }
+
+ // Load users from file
+ function load($fileName)
+ {
+ $fileData = @file($fileName);
+ if($fileData)
+ {
+ foreach($fileData as $line)
+ {
+ if(preg_match("/^\//", $line)) continue;
+ preg_match("/^(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches);
+ if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]))
+ {
+ $this->setUser($matches[1], $matches[2], $matches[3], $matches[4]);
+ if(defined("DEBUG") && DEBUG>=3) echo "YellowWebinterfaceUsers::load email:$matches[1] $matches[3]<br/>\n";
+ }
+ }
+ }
+ }
+
+ // Set user data
+ function setUser($email, $password, $name, $language)
+ {
+ $this->users[$email] = array();
+ $this->users[$email]["email"] = $email;
+ $this->users[$email]["password"] = $password;
+ $this->users[$email]["name"] = $name;
+ $this->users[$email]["language"] = $language;
+ $this->users[$email]["session"] = hash("sha256", $email.$password.$password.$email);
+ }
+
+ // Check user login
+ function checkUser($email, $password)
+ {
+ return $this->isExisting($email) && hash("sha256", $email.$password)==$this->users[$email]["password"];
+ }
+
+ // Create browser cookie
+ function createCookie($cookieName, $email)
+ {
+ if($this->isExisting($email))
+ {
+ $salt = hash("sha256", uniqid(mt_rand(), true));
+ $text = $email.";".$salt.";".hash("sha256", $salt.$this->users[$email]["session"]);
+ setcookie($cookieName, $text, time()+60*60*24*30*365*10, "/");
+ }
+ }
+
+ // Destroy browser cookie
+ function destroyCookie($cookieName)
+ {
+ setcookie($cookieName, "", time()-3600, "/");
+ }
+
+ // Check user login from browser cookie
+ function checkCookie($cookie)
+ {
+ list($email, $salt, $session) = explode(';', $cookie);
+ return $this->isExisting($email) && hash("sha256", $salt.$this->users[$email]["session"])==$session;
+ }
+
+ // Return user email from browser cookie
+ function getCookieEmail($cookie)
+ {
+ list($email, $salt, $session) = explode(';', $cookie);
+ return $email;
+ }
+
+ // Return user name
+ function getName($email)
+ {
+ return $this->isExisting($email) ? $this->users[$email]["name"] : "";
+ }
+
+ // Return user language
+ function getLanguage($email)
+ {
+ return $this->isExisting($email) ? $this->users[$email]["language"] : "";
+ }
+
+ // Check if user exists
+ function isExisting($email)
+ {
+ return !is_null($this->users[$email]);
+ }
+}
+
+$yellow->registerPlugin("webinterface", "YellowWebinterface", YellowWebinterface::Version);
+?>
+\ No newline at end of file
diff --git a/system/core/core_webinterface.png b/system/core/core-webinterface.png
Binary files differ.
diff --git a/system/core/core.php b/system/core/core.php
@@ -5,7 +5,7 @@
// Yellow main class
class Yellow
{
- const Version = "0.1.22";
+ const Version = "0.2.1";
var $page; //current page data
var $pages; //current page tree from file system
var $config; //configuration
@@ -15,17 +15,17 @@ class Yellow
function __construct()
{
- $this->pages = new Yellow_Pages($this);
- $this->config = new Yellow_Config($this);
- $this->text = new Yellow_Text($this);
- $this->toolbox = new Yellow_Toolbox();
- $this->plugins = new Yellow_Plugins();
+ $this->pages = new YellowPages($this);
+ $this->config = new YellowConfig($this);
+ $this->text = new YellowText($this);
+ $this->toolbox = new YellowToolbox();
+ $this->plugins = new YellowPlugins();
$this->config->setDefault("sitename", "Yellow");
$this->config->setDefault("author", "Yellow");
$this->config->setDefault("language", "en");
$this->config->setDefault("template", "default");
$this->config->setDefault("style", "default");
- $this->config->setDefault("parser", "markdown");
+ $this->config->setDefault("parser", "markdownextra");
$this->config->setDefault("serverName", $this->toolbox->getServerName());
$this->config->setDefault("serverBase", $this->toolbox->getServerBase());
$this->config->setDefault("styleLocation", "/media/styles/");
@@ -46,7 +46,7 @@ class Yellow
$this->config->setDefault("configExtension", ".ini");
$this->config->setDefault("configFile", "config.ini");
$this->config->setDefault("errorPageFile", "error(.*).txt");
- $this->config->setDefault("textStringFile", "text_(.*).ini");
+ $this->config->setDefault("textStringFile", "text(.*).ini");
$this->config->load($this->config->get("configDir").$this->config->get("configFile"));
$this->text->load($this->config->get("configDir").$this->config->get("textStringFile"));
}
@@ -61,7 +61,7 @@ class Yellow
$serverBase = $this->config->get("serverBase");
$location = $this->getRelativeLocation($serverBase);
$fileName = $this->getContentFileName($location);
- $this->page = new Yellow_Page($this, $location);
+ $this->page = new YellowPage($this, $location);
foreach($this->plugins->plugins as $key=>$value)
{
if(method_exists($value["obj"], "onRequest"))
@@ -152,7 +152,7 @@ class Yellow
fclose($fileHandle);
}
$this->pages->serverBase = $serverBase;
- $this->page = new Yellow_Page($this, $location);
+ $this->page = new YellowPage($this, $location);
$this->page->parseData($fileName, $fileData, $cacheable, $statusCode, $pageError);
$this->page->parseContent();
$this->page->setHeader("Content-Type", "text/html; charset=UTF-8");
@@ -337,7 +337,7 @@ class Yellow
}
// Yellow page data
-class Yellow_Page
+class YellowPage
{
var $yellow; //access to API
var $location; //page location
@@ -433,7 +433,7 @@ class Yellow_Page
fclose($fileHandle);
$this->parseMeta();
}
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Page::parseUpdate location:".$this->location."<br/>\n";
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowPage::parseUpdate location:".$this->location."<br/>\n";
}
}
@@ -467,7 +467,7 @@ class Yellow_Page
{
$this->set("keywords", $this->yellow->toolbox->createTextKeywords($this->get("title"), 10));
}
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Page::parseContent location:".$this->location."<br/>\n";
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowPage::parseContent location:".$this->location."<br/>\n";
}
}
@@ -643,7 +643,7 @@ class Yellow_Page
}
// Yellow page collection as array
-class Yellow_PageCollection extends ArrayObject
+class YellowPageCollection extends ArrayObject
{
var $yellow; //access to API
var $paginationPage; //current page number in pagination
@@ -810,7 +810,7 @@ class Yellow_PageCollection extends ArrayObject
}
// Yellow page tree from file system
-class Yellow_Pages
+class YellowPages
{
var $yellow; //access to API
var $pages; //scanned pages
@@ -827,7 +827,7 @@ class Yellow_Pages
// Return empty page collection
function create()
{
- return new Yellow_PageCollection($this->yellow);
+ return new YellowPageCollection($this->yellow);
}
// Return pages from file system
@@ -861,7 +861,7 @@ class Yellow_Pages
if($absoluteLocation) $location = substru($location, strlenu($this->serverBase));
$parentLocation = $this->getParentLocation($location);
$this->scanChildren($parentLocation);
- $pages = new Yellow_PageCollection($this->yellow);
+ $pages = new YellowPageCollection($this->yellow);
foreach($this->pages[$parentLocation] as $page) if($page->location == $location) { $pages->append($page); break; }
return $pages;
}
@@ -870,7 +870,7 @@ class Yellow_Pages
function findChildren($location, $showHidden = false)
{
$this->scanChildren($location);
- $pages = new Yellow_PageCollection($this->yellow);
+ $pages = new YellowPageCollection($this->yellow);
foreach($this->pages[$location] as $page) if($page->isVisible() || $showHidden) $pages->append($page);
return $pages;
}
@@ -880,7 +880,7 @@ class Yellow_Pages
{
--$levelMax;
$this->scanChildren($location);
- $pages = new Yellow_PageCollection($this->yellow);
+ $pages = new YellowPageCollection($this->yellow);
foreach($this->pages[$location] as $page)
{
if($page->isVisible() || $showHidden)
@@ -900,7 +900,7 @@ class Yellow_Pages
{
if(is_null($this->pages[$location]))
{
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Pages::scanChildren location:$location<br/>\n";
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowPages::scanChildren location:$location<br/>\n";
$this->pages[$location] = array();
$path = $this->yellow->config->get("contentDir");
if(!empty($location))
@@ -940,7 +940,7 @@ class Yellow_Pages
$fileData = "";
$statusCode = 0;
}
- $page = new Yellow_Page($this->yellow, $this->yellow->toolbox->findLocationFromFile($fileName,
+ $page = new YellowPage($this->yellow, $this->yellow->toolbox->findLocationFromFile($fileName,
$this->yellow->config->get("contentDir"), $this->yellow->config->get("contentHomeDir"),
$this->yellow->config->get("contentDefaultFile"), $this->yellow->config->get("contentExtension")));
$page->parseData($fileName, $fileData, false, $statusCode);
@@ -970,7 +970,7 @@ class Yellow_Pages
}
// Yellow configuration
-class Yellow_Config
+class YellowConfig
{
var $yellow; //access to API
var $modified; //configuration modification time
@@ -991,7 +991,7 @@ class Yellow_Config
$fileData = @file($fileName);
if($fileData)
{
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Config::load file:$fileName<br/>\n";
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowConfig::load file:$fileName<br/>\n";
$this->modified = filemtime($fileName);
foreach($fileData as $line)
{
@@ -1000,7 +1000,7 @@ class Yellow_Config
if(!empty($matches[1]) && !strempty($matches[2]))
{
$this->set($matches[1], $matches[2]);
- if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Config::load key:$matches[1] $matches[2]<br/>\n";
+ if(defined("DEBUG") && DEBUG>=3) echo "YellowConfig::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
@@ -1060,7 +1060,7 @@ class Yellow_Config
}
// Yellow text strings
-class Yellow_Text
+class YellowText
{
var $yellow; //access to API
var $modified; //text modification time
@@ -1084,7 +1084,7 @@ class Yellow_Text
$fileData = @file("$path/$entry");
if($fileData)
{
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Text::load file:$path/$entry<br/>\n";
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowText::load file:$path/$entry<br/>\n";
$this->modified = max($this->modified, filemtime("$path/$entry"));
$language = "";
foreach($fileData as $line)
@@ -1099,7 +1099,7 @@ class Yellow_Text
if(!empty($language) && !empty($matches[1]) && !strempty($matches[2]))
{
$this->setLanguageText($language, $matches[1], $matches[2]);
- if(defined("DEBUG") && DEBUG>=3) echo "Yellow_Text::load key:$matches[1] $matches[2]<br/>\n";
+ if(defined("DEBUG") && DEBUG>=3) echo "YellowText::load key:$matches[1] $matches[2]<br/>\n";
}
}
}
@@ -1177,7 +1177,7 @@ class Yellow_Text
}
// Yellow toolbox with helpers
-class Yellow_Toolbox
+class YellowToolbox
{
// Return server name from current HTTP request
function getServerName()
@@ -1669,7 +1669,7 @@ class Yellow_Toolbox
}
// Yellow plugins
-class Yellow_Plugins
+class YellowPlugins
{
var $plugins; //registered plugins
@@ -1682,9 +1682,9 @@ class Yellow_Plugins
function load()
{
global $yellow;
- require_once("core_markdown.php");
- require_once("core_commandline.php");
- require_once("core_webinterface.php");
+ require_once("core-commandline.php");
+ require_once("core-markdownextra.php");
+ require_once("core-webinterface.php");
foreach($yellow->toolbox->getDirectoryEntries($yellow->config->get("pluginDir"), "/.*\.php/", true, false) as $entry)
{
$fileNamePlugin = $yellow->config->get("pluginDir")."/$entry";
@@ -1693,8 +1693,8 @@ class Yellow_Plugins
foreach($this->plugins as $key=>$value)
{
$this->plugins[$key]["obj"] = new $value["class"];
- if(defined("DEBUG") && DEBUG>=2) echo "Yellow_Plugins::load class:$value[class] $value[version]<br/>\n";
- if(method_exists($this->plugins[$key]["obj"], "initPlugin")) $this->plugins[$key]["obj"]->initPlugin($yellow);
+ if(defined("DEBUG") && DEBUG>=2) echo "YellowPlugins::load class:$value[class] $value[version]<br/>\n";
+ if(method_exists($this->plugins[$key]["obj"], "onLoad")) $this->plugins[$key]["obj"]->onLoad($yellow);
}
}
diff --git a/system/core/core_commandline.php b/system/core/core_commandline.php
@@ -1,267 +0,0 @@
-<?php
-// Copyright (c) 2013 Datenstrom, http://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-// Command line core plugin
-class Yellow_Commandline
-{
- const Version = "0.1.5";
- var $yellow; //access to API
-
- // Initialise plugin
- function initPlugin($yellow)
- {
- $this->yellow = $yellow;
- $this->yellow->config->setDefault("commandBuildDefaultFile", "index.html");
- $this->yellow->config->setDefault("commandBuildCustomMediaExtension", ".txt");
- $this->yellow->config->setDefault("commandBuildCustomErrorFile", "error404.html");
- }
-
- // Handle command
- function onCommand($args)
- {
- list($name, $command) = $args;
- switch($command)
- {
- case "build": $statusCode = $this->build($args); break;
- case "version": $statusCode = $this->version(); break;
- default: $statusCode = $this->help();
- }
- return $statusCode;
- }
-
- // Show available commands
- function help()
- {
- echo "Yellow command line ".Yellow_Commandline::Version."\n";
- echo "Syntax: yellow.php build DIRECTORY [LOCATION]\n";
- echo " yellow.php version\n";
- return 0;
- }
-
- // Show software version
- function version()
- {
- echo "Yellow ".Yellow::Version."\n";
- foreach($this->yellow->plugins->plugins as $key=>$value) echo "$value[class] $value[version]\n";
- return 0;
- }
-
- // Build website
- function build($args)
- {
- $statusCode = 0;
- list($name, $command, $path, $location) = $args;
- if(!empty($path) && $path!="/")
- {
- if($this->yellow->config->isExisting("serverName") && $this->yellow->config->isExisting("serverBase"))
- {
- $serverName = $this->yellow->config->get("serverName");
- $serverBase = $this->yellow->config->get("serverBase");
- list($statusCode, $content, $media, $system, $error) = $this->buildStatic($serverName, $serverBase, $location, $path);
- } else {
- list($statusCode, $content, $media, $system, $error) = array(500, 0, 0, 0, 1);
- $fileName = $this->yellow->config->get("configDir").$this->yellow->config->get("configFile");
- echo "ERROR bulding website: Please configure serverName and serverBase in file '$fileName'!\n";
- }
- echo "Yellow build: $content content, $media media, $system system";
- echo ", $error error".($error!=1 ? 's' : '');
- echo ", status $statusCode\n";
- } else {
- echo "Yellow build: Invalid arguments\n";
- }
- return $statusCode;
- }
-
- // Build static files
- function buildStatic($serverName, $serverBase, $location, $path)
- {
- $this->yellow->toolbox->timerStart($time);
- $statusCodeMax = $error = 0;
- if(empty($location))
- {
- $pages = $this->yellow->pages->index(true);
- $fileNamesMedia = $this->yellow->toolbox->getDirectoryEntriesrecursive(
- $this->yellow->config->get("mediaDir"), "/.*/", false, false);
- $fileNamesMedia = array_merge($fileNamesMedia, $this->yellow->toolbox->getDirectoryEntries(
- ".", "/.*\\".$this->yellow->config->get("commandBuildCustomMediaExtension")."/", false, false));
- $fileNamesSystem = array($this->yellow->config->get("commandBuildCustomErrorFile"));
- } else {
- $pages = new Yellow_PageCollection($this->yellow, $location);
- $pages->append(new Yellow_Page($this->yellow, $location));
- $fileNamesMedia = array();
- $fileNamesSystem = array();
- }
- foreach($pages as $page)
- {
- $statusCode = $this->buildStaticLocation($serverName, $serverBase, $page->location, $path);
- $statusCodeMax = max($statusCodeMax, $statusCode);
- if($statusCode >= 400)
- {
- ++$error;
- echo "ERROR building location '".$page->location."', ".$this->yellow->page->getStatusCode(true)."\n";
- }
- if(defined("DEBUG") && DEBUG>=1) echo "Yellow_Commandline::buildStatic status:$statusCode location:".$page->location."\n";
- }
- foreach($fileNamesMedia as $fileName)
- {
- $statusCode = $this->copyStaticFile($fileName, "$path/$fileName") ? 200 : 500;
- $statusCodeMax = max($statusCodeMax, $statusCode);
- if($statusCode >= 400)
- {
- ++$error;
- echo "ERROR building media file '$path/$fileName', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
- }
- if(defined("DEBUG") && DEBUG>=1) echo "Yellow_Commandline::buildStatic status:$statusCode file:$fileName\n";
- }
- foreach($fileNamesSystem as $fileName)
- {
- $statusCode = $this->buildStaticError($serverName, $serverBase, "$path/$fileName", 404) ? 200 : 500;
- $statusCodeMax = max($statusCodeMax, $statusCode);
- if($statusCode >= 400)
- {
- ++$error;
- echo "ERROR building system file '$path/$fileName', ".$this->yellow->toolbox->getHttpStatusFormatted($statusCode)."\n";
- }
- if(defined("DEBUG") && DEBUG>=1) echo "Yellow_Commandline::buildStatic status:$statusCode file:$fileName\n";
- }
- $this->yellow->toolbox->timerStop($time);
- if(defined("DEBUG") && DEBUG>=1) echo "Yellow_Commandline::buildStatic time:$time ms\n";
- return array($statusCodeMax, count($pages), count($fileNamesMedia), count($fileNamesSystem), $error);
- }
-
- // Build static location as file
- function buildStaticLocation($serverName, $serverBase, $location, $path)
- {
- ob_start();
- $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
- $_SERVER["SERVER_NAME"] = $serverName;
- $_SERVER["REQUEST_URI"] = $serverBase.$location;
- $_SERVER["SCRIPT_NAME"] = $serverBase."yellow.php";
- $statusCode = $this->yellow->request();
- if($statusCode != 404)
- {
- $fileOk = true;
- $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
- list($contentType, $contentEncoding) = explode(';', $this->yellow->page->getHeader("Content-Type"), 2);
- $staticLocation = $this->getStaticLocation($location, $contentType);
- if($location == $staticLocation)
- {
- $fileName = $this->getStaticFileName($location, $path);
- $fileData = ob_get_contents();
- if($statusCode>=301 && $statusCode<=303) $fileData = $this->getStaticRedirect($this->yellow->page->getHeader("Location"));
- $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
- } else {
- if(!$this->yellow->toolbox->isFileLocation($location))
- {
- $fileName = $this->getStaticFileName($location, $path);
- $fileData = $this->getStaticRedirect("http://$serverName$serverBase$staticLocation");
- $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
- if($fileOk)
- {
- $fileName = $this->getStaticFileName($staticLocation, $path);
- $fileData = ob_get_contents();
- $fileOk = $this->makeStaticFile($fileName, $fileData, $modified);
- }
- } else {
- $statusCode = 409;
- $this->yellow->page->error($statusCode, "Type '$contentType' does not match file name!");
- }
- }
- if(!$fileOk)
- {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- ob_end_clean();
- return $statusCode;
- }
-
- // Build static error as file
- function buildStaticError($serverName, $serverBase, $fileName, $statusCodeRequest)
- {
- ob_start();
- $_SERVER["SERVER_PROTOCOL"] = "HTTP/1.1";
- $_SERVER["SERVER_NAME"] = $serverName;
- $_SERVER["REQUEST_URI"] = $serverBase."/";
- $_SERVER["SCRIPT_NAME"] = $serverBase."yellow.php";
- $statusCode = $this->yellow->request($statusCodeRequest);
- if($statusCode == $statusCodeRequest)
- {
- $modified = strtotime($this->yellow->page->getHeader("Last-Modified"));
- if(!$this->makeStaticFile($fileName, ob_get_contents(), $modified))
- {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- ob_end_clean();
- return $statusCode == $statusCodeRequest;
- }
-
- // Create static file
- function makeStaticFile($fileName, $fileData, $modified)
- {
- return $this->yellow->toolbox->makeFile($fileName, $fileData, true) &&
- $this->yellow->toolbox->modifyFile($fileName, $modified);
- }
-
- // Copy static file
- function copyStaticFile($fileNameSource, $fileNameDest)
- {
- return $this->yellow->toolbox->copyFile($fileNameSource, $fileNameDest, true) &&
- $this->yellow->toolbox->modifyFile($fileNameDest, filemtime($fileNameSource));
- }
-
- // Return static location corresponding to content type
- function getStaticLocation($location, $contentType)
- {
- if(!empty($contentType))
- {
- $extension = ($pos = strrposu($location, '.')) ? substru($location, $pos) : "";
- if($contentType == "text/html")
- {
- if($this->yellow->toolbox->isFileLocation($location))
- {
- if(!empty($extension) && $extension!=".html") $location .= ".html";
- }
- } else {
- if($this->yellow->toolbox->isFileLocation($location))
- {
- if(empty($extension)) $location .= ".unknown";
- } else {
- if(preg_match("/^(\w+)\/(\w+)/", $contentType, $matches)) $extension = ".$matches[2]";
- $location .= "index$extension";
- }
- }
- }
- return $location;
- }
-
- // Return static file name from location
- function getStaticFileName($location, $path)
- {
- $fileName = $path.$location;
- if(!$this->yellow->toolbox->isFileLocation($location))
- {
- $fileName .= $this->yellow->config->get("commandBuildDefaultFile");
- }
- return $fileName;
- }
-
- // Return static redirect data
- function getStaticRedirect($url)
- {
- $data = "<!DOCTYPE html><html>\n";
- $data .= "<head>\n";
- $data .= "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
- $data .= "<meta http-equiv=\"refresh\" content=\"0;url=$url\" />\n";
- $data .= "</head>\n";
- $data .= "</html>\n";
- return $data;
- }
-}
-
-$yellow->registerPlugin("commandline", "Yellow_Commandline", Yellow_Commandline::Version);
-?>
-\ No newline at end of file
diff --git a/system/core/core_markdown.php b/system/core/core_markdown.php
@@ -1,112 +0,0 @@
-<?php
-// Copyright (c) 2013 Datenstrom, http://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-// Markdown parser core plugin
-class Yellow_Markdown
-{
- const Version = "0.1.7";
- var $yellow; //access to API
- var $textHtml; //generated text (HTML format)
-
- // Initialise plugin
- function initPlugin($yellow)
- {
- $this->yellow = $yellow;
- }
-
- // Parse text
- function parse($text)
- {
- $markdown = new Yellow_MarkdownExtraParser($this->yellow);
- return $this->textHtml = $markdown->transform($text);
- }
-}
-
-require_once("markdown.php");
-
-class Yellow_MarkdownExtraParser extends MarkdownExtra_Parser
-{
- var $yellow; //access to API
-
- function __construct($yellow)
- {
- $this->yellow = $yellow;
- parent::__construct();
- }
-
- // Transform text
- function transform($text)
- {
- $text = preg_replace("/@pageRead/i", $this->yellow->page->get("pageRead"), $text);
- $text = preg_replace("/@pageEdit/i", $this->yellow->page->get("pageEdit"), $text);
- $text = preg_replace("/@pageError/i", $this->yellow->page->get("pageError"), $text);
- return parent::transform($text);
- }
-
- // Handle links
- function doAutoLinks($text)
- {
- $text = preg_replace_callback("/<(\w+:[^\'\">\s]+)>/", array(&$this, "_doAutoLinks_url_callback"), $text);
- $text = preg_replace_callback("/<(\w+@[\w\-\.]+)>/", array(&$this, "_doAutoLinks_email_callback"), $text);
- $text = preg_replace_callback("/\[(\w+)\s+(.*?)\]/", array(&$this, "_doAutoLinks_shortcut_callback"), $text);
- return $text;
- }
-
- // Handle shortcuts
- function _doAutoLinks_shortcut_callback($matches)
- {
- $text = preg_replace("/\s+/s", " ", $matches[2]);
- $output = $this->yellow->page->parseType($matches[1], $text, true);
- if(is_null($output)) $output = $matches[0];
- return $this->hashBlock($output);
- }
-
- // Handle fenced code blocks
- function _doFencedCodeBlocks_callback($matches)
- {
- $text = $matches[4];
- $output = $this->yellow->page->parseType($matches[2], $text, false);
- if(is_null($output))
- {
- $attr = $this->doExtraAttributes("pre", $dummy =& $matches[3]);
- $output = "<pre$attr><code>".htmlspecialchars($text, ENT_NOQUOTES)."</code></pre>";
- }
- return "\n\n".$this->hashBlock($output)."\n\n";
- }
-
- // Handle inline links
- function _doAnchors_inline_callback($matches)
- {
- $url = $matches[3]=="" ? $matches[4] : $matches[3];
- $text = $matches[2];
- $title = $matches[7];
- $attr = $this->doExtraAttributes("a", $dummy =& $matches[8]);
- $output = "<a href=\"".$this->encodeAttribute($url)."\"";
- if(!empty($title)) $output .= " title=\"".$this->encodeAttribute($title)."\"";
- $output .= $attr;
- $output .= ">".$this->runSpanGamut($text)."</a>";
- return $this->hashPart($output);
- }
-
- // Handle inline images
- function _doImages_inline_callback($matches)
- {
- $path = $matches[3]=="" ? $matches[4] : $matches[3];
- $src = $this->yellow->config->get("serverBase").$this->yellow->config->get("imageLocation").$path;
- list($width, $height) = $this->yellow->toolbox->detectImageDimensions($this->yellow->config->get("imageDir").$path);
- $alt = $matches[2];
- $title = $matches[7];
- $attr = $this->doExtraAttributes("img", $dummy =& $matches[8]);
- $output = "<img src=\"".$this->encodeAttribute($src)."\"";
- if($width && $height) $output .= " width=\"$width\" height=\"$height\"";
- if(!empty($alt)) $output .= " alt=\"".$this->encodeAttribute($alt)."\"";
- if(!empty($title)) $output .= " title=\"".$this->encodeAttribute($title)."\"";
- $output .= $attr;
- $output .= $this->empty_element_suffix;
- return $this->hashPart($output);
- }
-}
-
-$yellow->registerPlugin("markdown", "Yellow_Markdown", Yellow_Markdown::Version);
-?>
-\ No newline at end of file
diff --git a/system/core/core_webinterface.css b/system/core/core_webinterface.css
@@ -1,65 +0,0 @@
-/* Yellow web interface 0.1.2 */
-
-.yellow-bar { position:relative; overflow:hidden; line-height:2.0em; }
-.yellow-barleft { display:block; float:left; }
-.yellow-barleft a { margin-right:1em; }
-.yellow-barright { display:block; float:right; }
-
-.yellow-pane {
- position:absolute; display:none; z-index:10;
- margin:0; padding:5px;
- background-color:#fff; color:#000;
- border:1px solid #bbb;
- border-radius:4px;
-}
-.yellow-pane a { color:#000; text-decoration:none; }
-.yellow-pane a:hover { color:#f00; text-decoration:none; }
-.yellow-pane p { margin:0.5em; }
-.yellow-pane ul { list-style:none; margin:0 0.5em; padding:0; }
-.yellow-pane div { overflow:hidden; }
-.yellow-panebubble { }
-
-.yellow-btn {
- margin:0; padding:4px 22px;
- background-color:#eaeaea; color:#333333;
- background-image:linear-gradient(to bottom, #ffffff, #e1e1e1);
- background-repeat:repeat-x;
- border:1px solid #bbb;
- border-color:#d1d1d1 #d1d1d1 #aaaaaa;
- border-radius:4px;
- outline-offset:-2px;
- font-size:0.9em;
-}
-.yellow-btn:hover, .yellow-btn:focus, .yellow-btn:active { background-image:none; }
-.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); }
-.yellow-btn-warn {
- background-color:#c33c35; color:#ffffff;
- background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);
- border-color:#b13121 #b13121 #802020;
- text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);
-}
-.yellow-btn-warn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.3); }
-
-#yellow-panelogin { }
-#yellow-panelogin h1 { margin:0.5em 0.5em; }
-#yellow-panelogin p { margin:0.5em; text-align:right; }
-#yellow-paneedit { }
-#yellow-paneedit #yellow-edittext { margin:0; padding:5px; border:1px solid #bbb; resize:none; font-size:0.9em }
-#yellow-paneedit #yellow-editinfo { margin:0; padding:5px; border:1px solid #bbb; display:none; }
-#yellow-paneedit #yellow-editbuttons { margin:5px 0; }
-#yellow-paneshow { min-width:20em; overflow:auto; }
-#yellow-paneuser { }
-
-/* Font icons from Fontawesome */
-
-@font-face { font-family:'FontAwesome'; font-style:normal; font-weight:normal; src:url('core_fontawesome.woff'); }
-[class*="yellow-icon-"] {
- font-family:FontAwesome;
- font-style:normal;
- font-weight:normal;
- -webkit-font-smoothing:antialiased;
-}
-.yellow-icon-search:before { content:"\f002"; }
-.yellow-icon-trash-o:before { content:"\f014"; }
-.yellow-icon-caret-down:before { content:"\f0d7"; }
-.yellow-icon-caret-up:before { content:"\f0d8"; }
-\ No newline at end of file
diff --git a/system/core/core_webinterface.js b/system/core/core_webinterface.js
@@ -1,422 +0,0 @@
-// Copyright (c) 2013 Datenstrom, http://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-// Yellow main API
-var yellow =
-{
- version: "0.1.2",
- onClick: function(e) { yellow.webinterface.hidePanesOnClick(yellow.toolbox.getEventElement(e)); },
- onKeydown: function(e) { yellow.webinterface.hidePanesOnKeydown(yellow.toolbox.getEventKeycode(e)); },
- onResize: function() { yellow.webinterface.resizePanes(); },
- onShow: function(id) { yellow.webinterface.showPane(id); },
- webinterface:{}, page:{}, pages:{}, toolbox:{}, config:{}, text:{}
-}
-
-// Yellow web interface
-yellow.webinterface =
-{
- created: false, //interface created? (boolean)
- intervalId: 0, //interface timer interval ID
-
- // Initialise web interface
- init: function()
- {
- this.intervalId = setInterval("yellow.webinterface.create()", 1);
- yellow.toolbox.addEvent(window, "resize", yellow.onResize);
- yellow.toolbox.addEvent(document, "click", yellow.onClick);
- yellow.toolbox.addEvent(document, "keydown", yellow.onKeydown);
- },
-
- // Create web interface
- create: function()
- {
- var body = document.getElementsByTagName("body")[0];
- if(body && body.firstChild && !this.created)
- {
- this.created = true;
- if(yellow.debug) console.log("yellow.webinterface.create email:"+yellow.config.userEmail+" "+yellow.config.userName);
- if(yellow.config.userEmail)
- {
- yellow.toolbox.insertBefore(this.createBar("yellow-bar"), body.firstChild);
- yellow.toolbox.insertAfter(this.createPane("yellow-paneedit"), body.firstChild);
- yellow.toolbox.insertAfter(this.createPane("yellow-paneshow"), body.firstChild);
- yellow.toolbox.insertAfter(this.createPane("yellow-paneuser"), body.firstChild);
- yellow.toolbox.setText(document.getElementById("yellow-username"), yellow.config.userName);
- yellow.toolbox.setText(document.getElementById("yellow-edittext"), yellow.page.rawData);
- } else {
- yellow.toolbox.insertBefore(this.createBar("yellow-bar", true), body.firstChild);
- yellow.toolbox.insertAfter(this.createPane("yellow-panelogin", true), body.firstChild);
- this.showPane("yellow-panelogin");
- }
- clearInterval(this.intervalId);
- }
- },
-
- // Create bar
- createBar: function(id, simple)
- {
- if(yellow.debug) console.log("yellow.webinterface.createBar id:"+id);
- var elementBar = document.createElement("div");
- elementBar.className = "yellow-bar yellow";
- elementBar.setAttribute("id", id);
- if(!simple)
- {
- var location = yellow.config.serverBase+yellow.config.pluginLocation;
- elementBar.innerHTML =
- "<div class=\"yellow-barleft\">"+
- "<a href=\"http://datenstrom.se/yellow/\" target=\"_blank\"><img src=\""+location+"core_webinterface.png\" width=\"16\" height=\"16\"> Yellow</a>"+
- "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneedit'); return false;\">"+this.getText("Edit")+"</a>"+
- "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneshow'); return false;\">"+this.getText("Show")+"</a>"+
- "</div>"+
- "<div class=\"yellow-barright\">"+
- "<a href=\"#\" onclick=\"yellow.onShow('yellow-paneuser'); return false;\" id=\"yellow-username\">"+this.getText("User")+"</a>"+
- "</div>";
- }
- return elementBar;
- },
-
- // Create pane
- createPane: function(id, simple)
- {
- if(yellow.debug) console.log("yellow.webinterface.createPane id:"+id);
- var elementPane = document.createElement("div");
- elementPane.className = simple ? "yellow-pane" : "yellow-pane yellow-panebubble";
- elementPane.setAttribute("id", id);
- elementPane.style.display = "none";
- var elementDiv = document.createElement("div");
- elementDiv.setAttribute("id", id+"content");
- if(id == "yellow-panelogin")
- {
- elementDiv.innerHTML =
- "<h1>"+this.getText("LoginText")+"</h1>"+
- "<form method=\"post\" name=\"formlogin\">"+
- "<input type=\"hidden\" name=\"action\" value=\"login\"/>"+
- "<p><label for=\"email\">"+this.getText("LoginEmail")+"</label> <input name=\"email\" id=\"email\" maxlength=\"64\" /></p>"+
- "<p><label for=\"password\">"+this.getText("LoginPassword")+"</label> <input type=\"password\" name=\"password\" id=\"password\" maxlength=\"64\" /></p>"+
- "<p><input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("LoginButton")+"\"/></p>"+
- "</form>";
- } else if(id == "yellow-paneedit") {
- elementDiv.innerHTML =
- "<p>Editing page...</p>"+
- "<form method=\"post\" name=\"formeditor\">"+
- "<input type=\"hidden\" name=\"action\" value=\"edit\"/>"+
- "<textarea id=\"yellow-edittext\" name=\"rawdata\"></textarea>"+
- "<div id=\"yellow-editinfo\"/></div>"+
- "<div id=\"yellow-editbuttons\">"+
- "<input class=\"yellow-btn\" type=\"submit\" value=\""+this.getText("SaveButton")+"\"/>"+
- "</div>"+
- "</form>";
- } else if(id == "yellow-paneshow") {
- elementDiv.innerHTML = "<p>Showing files...</p>";
- var elementUl = document.createElement("ul");
- for(var n in yellow.pages)
- {
- var elementLi = document.createElement("li");
- var elementA = document.createElement("a");
- elementA.setAttribute("href", yellow.pages[n]["location"]);
- yellow.toolbox.setText(elementA, yellow.pages[n]["title"]);
- elementLi.appendChild(elementA);
- elementUl.appendChild(elementLi);
- }
- elementDiv.appendChild(elementUl);
- } else if(id == "yellow-paneuser") {
- elementDiv.innerHTML =
- "<p>"+yellow.config.userEmail+"</p>"+
- "<form method=\"post\" name=\"formlogout\">"+
- "<input type=\"hidden\" name=\"action\" value=\"logout\"/>"+
- "<p><a href=\"javascript:document.formlogout.submit();\">"+this.getText("UserLogout")+"</a></p> "+
- "</form>";
- }
-
- elementPane.appendChild(elementDiv);
- return elementPane;
- },
-
- // Show or hide pane
- showPane: function(id)
- {
- if(!yellow.toolbox.isVisible(document.getElementById(id)))
- {
- this.hidePanes();
- if(yellow.debug) console.log("yellow.webinterface.showPane id:"+id);
- document.getElementById(id).style.display = "block";
- this.resizePanes();
- } else {
- this.hidePane(id);
- }
- },
-
- // Hide pane
- hidePane: function(id)
- {
- if(yellow.toolbox.isVisible(document.getElementById(id)))
- {
- if(yellow.debug) console.log("yellow.webinterface.hidePane id:"+id);
- document.getElementById(id).style.display = "none";
- }
- },
-
- // Hide all panes
- hidePanes: function()
- {
- for(var element=document.getElementById("yellow-bar"); element; element=element.nextSibling)
- {
- if(element.className && element.className.indexOf("yellow-pane")>=0)
- {
- this.hidePane(element.getAttribute("id"));
- }
- }
- },
-
- // Hide all panes on mouse click outside
- hidePanesOnClick: function(element)
- {
- while(element = element.parentNode)
- {
- if(element.className)
- {
- if(element.className.indexOf("yellow-pane")>=0 || element.className.indexOf("yellow-bar")>=0) return;
- }
- }
- this.hidePanes();
- },
-
- // Hide all panes on ESC key
- hidePanesOnKeydown: function(keycode)
- {
- if(keycode == 27) this.hidePanes();
- },
-
- // Resize panes, recalculate width and height where needed
- resizePanes: function()
- {
- if(document.getElementById("yellow-bar"))
- {
- var elementBar = document.getElementById("yellow-bar");
- var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar);
- var paneWidth = yellow.toolbox.getOuterWidth(elementBar, true);
- var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar);
- if(yellow.toolbox.isVisible(document.getElementById("yellow-panelogin")))
- {
- yellow.toolbox.setOuterWidth(document.getElementById("yellow-panelogin"), paneWidth);
- }
- if(yellow.toolbox.isVisible(document.getElementById("yellow-paneedit")))
- {
- yellow.toolbox.setOuterTop(document.getElementById("yellow-paneedit"), paneTop);
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneedit"), paneHeight);
- yellow.toolbox.setOuterWidth(document.getElementById("yellow-paneedit"), paneWidth);
- yellow.toolbox.setOuterWidth(document.getElementById("yellow-edittext"), yellow.toolbox.getWidth(document.getElementById("yellow-paneedit")));
- var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-paneedit"));
- var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-paneeditcontent"));
- var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-edittext"));
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-edittext"), height1 - height2 + height3);
- }
- if(yellow.toolbox.isVisible(document.getElementById("yellow-paneshow")))
- {
- yellow.toolbox.setOuterTop(document.getElementById("yellow-paneshow"), paneTop);
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneshow"), paneHeight, true);
- }
- if(yellow.toolbox.isVisible(document.getElementById("yellow-paneuser")))
- {
- yellow.toolbox.setOuterTop(document.getElementById("yellow-paneuser"), paneTop);
- yellow.toolbox.setOuterHeight(document.getElementById("yellow-paneuser"), paneHeight, true);
- yellow.toolbox.setOuterLeft(document.getElementById("yellow-paneuser"), paneWidth - yellow.toolbox.getOuterWidth(document.getElementById("yellow-paneuser")), true);
- }
- if(yellow.debug) console.log("yellow.webinterface.resizePanes bar:"+elementBar.offsetWidth+"/"+elementBar.offsetHeight);
- }
- },
-
- // Return text string
- getText: function(key)
- {
- return ("webinterface"+key in yellow.text) ? yellow.text["webinterface"+key] : "[webinterface"+key+"]";
- }
-}
-
-// Yellow toolbox with helpers
-yellow.toolbox =
-{
- // Set element text
- setText: function(element, text)
- {
- while(element.firstChild !== null) element.removeChild(element.firstChild);
- element.appendChild(document.createTextNode(text));
- },
-
- // Insert element before element
- insertBefore: function(newElement, referenceElement)
- {
- referenceElement.parentNode.insertBefore(newElement, referenceElement);
- },
-
- // Insert element after element
- insertAfter: function(newElement, referenceElement)
- {
- referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
- },
-
- // Add event handler
- addEvent: function(element, type, handler)
- {
- if(element.addEventListener) element.addEventListener(type, handler, false);
- else element.attachEvent('on'+type, handler);
- },
-
- // Return element of event
- getEventElement: function(e)
- {
- e = e ? e : window.event;
- return e.target ? e.target : e.srcElement;
- },
-
- // Return keycode of event
- getEventKeycode: function(e)
- {
- e = e ? e : window.event;
- return e.keyCode
- },
-
- // Set element width/height in pixel, including padding and border
- setOuterWidth: function(element, width, maxWidth)
- {
- width -= this.getBoxSize(element).width;
- if(maxWidth)
- {
- element.style.maxWidth = Math.max(0, width) + "px";
- } else {
- element.style.width = Math.max(0, width) + "px";
- }
- },
-
- setOuterHeight: function(element, height, maxHeight)
- {
- height -=this.getBoxSize(element).height;
- if(maxHeight)
- {
- element.style.maxHeight = Math.max(0, height) + "px";
- } else {
- element.style.height = Math.max(0, height) + "px";
- }
- },
-
- // Return element width/height in pixel, including padding and border
- getOuterWidth: function(element, includeMargin)
- {
- width = element.offsetWidth;
- if(includeMargin) width += this.getMarginSize(element).width;
- return width;
- },
-
- getOuterHeight: function(element, includeMargin)
- {
- height = element.offsetHeight;
- if(includeMargin) height += this.getMarginSize(element).height;
- return height;
- },
-
- // Return element width/height in pixel
- getWidth: function(element)
- {
- return element.offsetWidth - this.getBoxSize(element).width;
- },
-
- getHeight: function(element)
- {
- return element.offsetHeight - this.getBoxSize(element).height;
- },
-
- // Set element top/left position in pixel
- setOuterTop: function(element, top, marginTop)
- {
- if(marginTop)
- {
- element.style.marginTop = Math.max(0, top) + "px";
- } else {
- element.style.top = Math.max(0, top) + "px";
- }
- },
-
- setOuterLeft: function(element, left, marginLeft)
- {
- if(marginLeft)
- {
- element.style.marginLeft = Math.max(0, left) + "px";
- } else {
- element.style.left = Math.max(0, left) + "px";
- }
- },
-
- // Return element top/left position in pixel
- getOuterTop: function(element)
- {
- var top = element.getBoundingClientRect().top;
- return top + (window.pageYOffset || document.documentElement.scrollTop);
- },
-
- getOuterLeft: function(element)
- {
- var left = element.getBoundingClientRect().left;
- return left + (window.pageXOffset || document.documentElement.scrollLeft);
- },
-
- // Return window width/height in pixel
- getWindowWidth: function()
- {
- return window.innerWidth || document.documentElement.clientWidth;
- },
-
- getWindowHeight: function()
- {
- return window.innerHeight || document.documentElement.clientHeight;
- },
-
- // Return element CSS property
- getStyle: function(element, property)
- {
- var string = "";
- if(window.getComputedStyle)
- {
- string = window.getComputedStyle(element, null).getPropertyValue(property);
- } else {
- property = property.replace(/\-(\w)/g, function(match, m) { return m.toUpperCase(); });
- string = element.currentStyle[property];
- }
- return string;
- },
-
- // Return element CSS padding and border
- getBoxSize: function(element)
- {
- var paddingLeft = parseFloat(this.getStyle(element, "padding-left")) || 0;
- var paddingRight = parseFloat(this.getStyle(element, "padding-right")) || 0;
- var borderLeft = parseFloat(this.getStyle(element, "border-left-width")) || 0;
- var borderRight = parseFloat(this.getStyle(element, "border-right-width")) || 0;
- var width = paddingLeft + paddingRight + borderLeft + borderRight;
- var paddingTop = parseFloat(this.getStyle(element, "padding-top")) || 0;
- var paddingBottom = parseFloat(this.getStyle(element, "padding-bottom")) || 0;
- var borderTop = parseFloat(this.getStyle(element, "border-top-width")) || 0;
- var borderBottom = parseFloat(this.getStyle(element, "border-bottom-width")) || 0;
- var height = paddingTop + paddingBottom + borderTop + borderBottom;
- return { "width":width, "height":height };
- },
-
- // Return element CSS margin
- getMarginSize: function(element)
- {
- var marginLeft = parseFloat(this.getStyle(element, "margin-left")) || 0;
- var marginRight = parseFloat(this.getStyle(element, "margin-right")) || 0;
- var width = marginLeft + marginRight;
- var marginTop = parseFloat(this.getStyle(element, "margin-top")) || 0;
- var marginBottom = parseFloat(this.getStyle(element, "margin-bottom")) || 0;
- var height = marginTop + marginBottom;
- return { "width":width, "height":height };
- },
-
- // Check if element exists and is visible
- isVisible: function(element)
- {
- return element && element.style.display != "none";
- }
-}
-
-yellow.webinterface.init();
-\ No newline at end of file
diff --git a/system/core/core_webinterface.php b/system/core/core_webinterface.php
@@ -1,327 +0,0 @@
-<?php
-// Copyright (c) 2013 Datenstrom, http://datenstrom.se
-// This file may be used and distributed under the terms of the public license.
-
-// Web interface core plugin
-class Yellow_Webinterface
-{
- const Version = "0.1.10";
- var $yellow; //access to API
- var $users; //web interface users
- var $activeLocation; //web interface location? (boolean)
- var $activeUserFail; //web interface login failed? (boolean)
- var $activeUserEmail; //web interface user currently logged in
- var $rawDataOriginal; //raw data of page in case of errors
-
- // Initialise plugin
- function initPlugin($yellow)
- {
- $this->yellow = $yellow;
- $this->yellow->config->setDefault("webinterfaceLocation", "/edit/");
- $this->yellow->config->setDefault("webinterfaceUserFile", "user.ini");
- $this->users = new Yellow_WebinterfaceUsers();
- $this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("webinterfaceUserFile"));
- }
-
- // Handle web interface location
- function onRequest($serverName, $serverBase, $location, $fileName)
- {
- $statusCode = 0;
- if($this->checkWebinterfaceLocation($location))
- {
- $serverBase .= rtrim($this->yellow->config->get("webinterfaceLocation"), '/');
- $location = $this->yellow->getRelativeLocation($serverBase);
- $fileName = $this->yellow->getContentFileName($location);
- if($this->checkUser()) $statusCode = $this->processRequestAction($serverName, $serverBase, $location, $fileName);
- if($statusCode == 0) $statusCode = $this->yellow->processRequest($serverName, $serverBase, $location, $fileName,
- false, $this->activeUserFail ? 401 : 0);
- } else {
- if($this->yellow->config->get("webinterfaceLocation") == "$location/")
- {
- $statusCode = 301;
- $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, "$location/");
- $this->yellow->sendStatus($statusCode, $locationHeader);
- }
- }
- return $statusCode;
- }
-
- // Handle page content parsing
- function onParseContent($page, $text)
- {
- $output = NULL;
- if($this->isWebinterfaceLocation() && $this->isUser())
- {
- $serverBase = $this->yellow->config->get("serverBase");
- $webinterfaceLocation = trim($this->yellow->config->get("webinterfaceLocation"), '/');
- $output = preg_replace("#<a(.*?)href=\"$serverBase/(?!$webinterfaceLocation)(.*?)\"(.*?)>#",
- "<a$1href=\"$serverBase/$webinterfaceLocation/$2\"$3>", $text);
- if($page == $this->yellow->page)
- {
- switch($page->statusCode)
- {
- case 200: $this->rawDataOriginal = $page->rawData; break;
- case 424: $language = $this->isUser() ? $this->users->getLanguage($this->activeUserEmail) : $page->get("language");
- $page->rawData = "---\r\n";
- $page->rawData .= "Title: ".$this->yellow->text->getLanguageText($language, "webinterface424Title")."\r\n";
- $page->rawData .= "Author: ".$this->users->getName($this->activeUserEmail)."\r\n";
- $page->rawData .= "---\r\n";
- $page->rawData .= $this->yellow->text->getLanguageText($language, "webinterface424Text");
- break;
- case 500: $page->rawData = $this->rawDataOriginal; break;
- }
- }
- }
- return $output;
- }
-
- // Handle extra HTML header lines
- function onHeaderExtra()
- {
- $header = "";
- if($this->isWebinterfaceLocation())
- {
- $location = $this->yellow->config->getHtml("serverBase").$this->yellow->config->getHtml("pluginLocation");
- $language = $this->isUser() ? $this->users->getLanguage($this->activeUserEmail) : $this->yellow->page->get("language");
- $header .= "<link rel=\"styleSheet\" type=\"text/css\" media=\"all\" href=\"{$location}core_webinterface.css\" />\n";
- $header .= "<script type=\"text/javascript\" src=\"{$location}core_webinterface.js\"></script>\n";
- $header .= "<script type=\"text/javascript\">\n";
- $header .= "// <![CDATA[\n";
- if($this->isUser())
- {
- $header .= "yellow.page.rawData = ".json_encode($this->yellow->page->rawData).";\n";
- $header .= "yellow.pages = ".json_encode($this->getPagesData()).";\n";
- $header .= "yellow.config = ".json_encode($this->getConfigData($this->activeUserEmail)).";\n";
- }
- $header .= "yellow.text = ".json_encode($this->yellow->text->getData($language, "webinterface")).";\n";
- if(defined("DEBUG")) $header .= "yellow.debug = ".json_encode(DEBUG).";\n";
- $header .= "// ]]>\n";
- $header .= "</script>\n";
- }
- return $header;
- }
-
- // Process request for an action
- function processRequestAction($serverName, $serverBase, $location, $fileName)
- {
- $statusCode = 0;
- if($_POST["action"] == "edit")
- {
- if(!empty($_POST["rawdata"]) && $this->checkUserPermissions($location, $fileName))
- {
- $this->rawDataOriginal = $_POST["rawdata"];
- if($this->yellow->toolbox->makeFile($fileName, $_POST["rawdata"]))
- {
- $statusCode = 303;
- $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, $location);
- $this->yellow->sendStatus($statusCode, $locationHeader);
- } else {
- $statusCode = 500;
- $this->yellow->processRequest($serverName, $serverBase, $location, $fileName, false, $statusCode);
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- } else if($_POST["action"]== "login") {
- $statusCode = 303;
- $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, $location);
- $this->yellow->sendStatus($statusCode, $locationHeader);
- } else if($_POST["action"]== "logout") {
- $this->users->destroyCookie("login");
- $this->activeUserEmail = "";
- $statusCode = 302;
- $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $this->yellow->config->get("serverBase"), $location);
- $this->yellow->sendStatus($statusCode, $locationHeader);
- } else {
- if(!is_readable($fileName))
- {
- if($this->yellow->toolbox->isFileLocation($location) && is_dir($this->yellow->getContentDirectory("$location/")))
- {
- $statusCode = 301;
- $locationHeader = $this->yellow->toolbox->getHttpLocationHeader($serverName, $serverBase, "$location/");
- $this->yellow->sendStatus($statusCode, $locationHeader);
- } else {
- $statusCode = $this->checkUserPermissions($location, $fileName) ? 424 : 404;
- $this->yellow->processRequest($serverName, $serverBase, $location, $fileName, false, $statusCode);
- }
- }
- }
- return $statusCode;
- }
-
- // Check web interface location
- function checkWebinterfaceLocation($location)
- {
- $locationLength = strlenu($this->yellow->config->get("webinterfaceLocation"));
- $this->activeLocation = substru($location, 0, $locationLength) == $this->yellow->config->get("webinterfaceLocation");
- return $this->isWebinterfaceLocation();
- }
-
- // Check user login
- function checkUser()
- {
- if($_POST["action"] == "login")
- {
- $email = $_POST["email"];
- $password = $_POST["password"];
- if($this->users->checkUser($email, $password))
- {
- $this->users->createCookie("login", $email);
- $this->activeUserEmail = $email;
- } else {
- $this->activeUserFail = true;
- }
- } else if(isset($_COOKIE["login"])) {
- $cookie = $_COOKIE["login"];
- if($this->users->checkCookie($cookie))
- {
- $this->activeUserEmail = $this->users->getCookieEmail($cookie);
- } else {
- $this->activeUserFail = true;
- }
- }
- return $this->isUser();
- }
-
- // Check users permissions for creating new page
- function checkUserPermissions($location, $fileName)
- {
- $path = dirname($fileName);
- return is_dir($path) && strlenu(basename($fileName))<128;
- }
-
- // Check if web interface location
- function isWebinterfaceLocation()
- {
- return $this->activeLocation;
- }
-
- // Check if user is logged in
- function isUser()
- {
- return !empty($this->activeUserEmail);
- }
-
- // Return page tree with content information, two levels
- function getPagesData()
- {
- $data = array();
- foreach($this->yellow->pages->index(true, 2) as $page)
- {
- $data[$page->fileName] = array();
- $data[$page->fileName]["location"] = $page->getLocation();
- $data[$page->fileName]["modified"] = $page->getModified();
- $data[$page->fileName]["title"] = $page->getHtml("title");
- }
- return $data;
- }
-
- // Return configuration data including user information
- function getConfigData($email)
- {
- $data = array("userEmail" => $email,
- "userName" => $this->users->getName($email),
- "userLanguage" => $this->users->getLanguage($email),
- "serverName" => $this->yellow->config->get("serverName"),
- "serverBase" => $this->yellow->config->get("serverBase"));
- return array_merge($data, $this->yellow->config->getData("Location"));
- }
-}
-
-// Yellow web interface users
-class Yellow_WebinterfaceUsers
-{
- var $users; //registered users
-
- function __construct()
- {
- $this->users = array();
- }
-
- // Load users from file
- function load($fileName)
- {
- $fileData = @file($fileName);
- if($fileData)
- {
- foreach($fileData as $line)
- {
- if(preg_match("/^\//", $line)) continue;
- preg_match("/^(.*?),\s*(.*?),\s*(.*?),\s*(.*?)\s*$/", $line, $matches);
- if(!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3]) && !empty($matches[4]))
- {
- $this->setUser($matches[1], $matches[2], $matches[3], $matches[4]);
- if(defined("DEBUG") && DEBUG>=3) echo "Yellow_WebinterfaceUsers::load email:$matches[1] $matches[3]<br/>\n";
- }
- }
- }
- }
-
- // Set user data
- function setUser($email, $password, $name, $language)
- {
- $this->users[$email] = array();
- $this->users[$email]["email"] = $email;
- $this->users[$email]["password"] = $password;
- $this->users[$email]["name"] = $name;
- $this->users[$email]["language"] = $language;
- $this->users[$email]["session"] = hash("sha256", $email.$password.$password.$email);
- }
-
- // Check user login
- function checkUser($email, $password)
- {
- return $this->isExisting($email) && hash("sha256", $email.$password)==$this->users[$email]["password"];
- }
-
- // Create browser cookie
- function createCookie($cookieName, $email)
- {
- if($this->isExisting($email))
- {
- $salt = hash("sha256", uniqid(mt_rand(), true));
- $text = $email.";".$salt.";".hash("sha256", $salt.$this->users[$email]["session"]);
- setcookie($cookieName, $text, time()+60*60*24*30*365*10, "/");
- }
- }
-
- // Destroy browser cookie
- function destroyCookie($cookieName)
- {
- setcookie($cookieName, "", time()-3600, "/");
- }
-
- // Check user login from browser cookie
- function checkCookie($cookie)
- {
- list($email, $salt, $session) = explode(';', $cookie);
- return $this->isExisting($email) && hash("sha256", $salt.$this->users[$email]["session"])==$session;
- }
-
- // Return user email from browser cookie
- function getCookieEmail($cookie)
- {
- list($email, $salt, $session) = explode(';', $cookie);
- return $email;
- }
-
- // Return user name
- function getName($email)
- {
- return $this->isExisting($email) ? $this->users[$email]["name"] : "";
- }
-
- // Return user language
- function getLanguage($email)
- {
- return $this->isExisting($email) ? $this->users[$email]["language"] : "";
- }
-
- // Check if user exists
- function isExisting($email)
- {
- return !is_null($this->users[$email]);
- }
-}
-
-$yellow->registerPlugin("webinterface", "Yellow_Webinterface", Yellow_Webinterface::Version);
-?>
-\ No newline at end of file
diff --git a/system/plugins/example.php b/system/plugins/example.php
@@ -3,12 +3,12 @@
// This file may be used and distributed under the terms of the public license.
// Example plugin
-class Yellow_Example
+class YellowExample
{
//You can download plugins and extensions from Github.
//See https://github.com/markseu/yellowcms-extensions
const Version = "0.0.0";
}
-$yellow->registerPlugin("example", "Yellow_Example", Yellow_Example::Version);
+$yellow->registerPlugin("example", "YellowExample", YellowExample::Version);
?>
\ No newline at end of file
diff --git a/system/snippets/header.php b/system/snippets/header.php
@@ -6,7 +6,7 @@
<meta name="author" content="<?php echo $yellow->page->getHtml("author") ?>" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo $yellow->page->getHtml("titleHeader") ?></title>
-<link rel="shortcut icon" href="<?php echo $yellow->config->get("serverBase").$yellow->config->get("imageLocation")."default_icon.png" ?>" />
+<link rel="shortcut icon" href="<?php echo $yellow->config->get("serverBase").$yellow->config->get("imageLocation")."icon.png" ?>" />
<link rel="stylesheet" type="text/css" media="all" href="<?php echo $yellow->config->get("serverBase").$yellow->config->get("styleLocation").$yellow->page->get("style").".css" ?>" />
<?php echo $yellow->getHeaderExtra() ?>
</head>
diff --git a/yellow.php b/yellow.php
@@ -11,6 +11,7 @@ if(PHP_SAPI != "cli")
} else {
$yellow = new Yellow();
$yellow->plugins->load();
- $yellow->plugin("commandline", $argv[1], $argv[2], $argv[3], $argv[4], $argv[5]);
+ $statusCode = $yellow->plugin("commandline", $argv[1], $argv[2], $argv[3], $argv[4], $argv[5]);
+ exit($statusCode<=200 ? 0 : 1);
}
?>
\ No newline at end of file