mikuli.cz

:)
git clone https://git.sr.ht/~ashymad/mikuli.cz
Log | Files | Refs

commit c124aad12cd9005d567b2c9c6d3ecfce342d1e46
parent b8d7052a277aeb0d1a9f8b07090baa2c02c256b5
Author: markseu <mark2011@mayberg.se>
Date:   Sun,  1 Dec 2013 12:59:07 +0100

Code cleanup

Diffstat:
M.htaccess | 2+-
MREADME.md | 18++++++++----------
Rmedia/images/default_icon.png -> media/images/icon.png | 0
Msystem/config/config.ini | 6+++---
Rsystem/config/text_english.ini -> system/config/textenglish.ini | 0
Asystem/core/core-commandline.php | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsystem/core/core_fontawesome.woff -> system/core/core-fontawesome.woff | 0
Asystem/core/core-markdownextra.php | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asystem/core/core-webinterface.css | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asystem/core/core-webinterface.js | 423+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asystem/core/core-webinterface.php | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsystem/core/core_webinterface.png -> system/core/core-webinterface.png | 0
Msystem/core/core.php | 68++++++++++++++++++++++++++++++++++----------------------------------
Dsystem/core/core_commandline.php | 268-------------------------------------------------------------------------------
Dsystem/core/core_markdown.php | 113-------------------------------------------------------------------------------
Dsystem/core/core_webinterface.css | 66------------------------------------------------------------------
Dsystem/core/core_webinterface.js | 423-------------------------------------------------------------------------------
Dsystem/core/core_webinterface.php | 328-------------------------------------------------------------------------------
Msystem/plugins/example.php | 4++--
Msystem/snippets/header.php | 2+-
Myellow.php | 3++-
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