commit 5c5feb0bea7a3e983a35f43dc658f22b967dec36
parent d15f38582f400caf6dab16480676c9a1b0f4f7e2
Author: Ashymad <szymon.mikulicz@posteo.net>
Date: Mon, 2 Mar 2026 23:03:57 +0100
Update yellow
Diffstat:
15 files changed, 365 insertions(+), 934 deletions(-)
diff --git a/license.md b/license.md
@@ -1,294 +0,0 @@
-# GNU GENERAL PUBLIC LICENSE
-
-Version 2, June 1991
-Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Everyone is permitted to copy and distribute verbatim copies
-of this license document, but changing it is not allowed.
-
-## Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
-## Terms and conditions
-
- **0.** This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- **1.** You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- **2.** You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- **3.** You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- **4.** You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- **5.** You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- **6.** Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- **7.** If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- **8.** If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- **9.** The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- **10.** If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-END OF TERMS AND CONDITIONS
-
-## How to apply this license to this software
-
-At the start of each source file you see a link to a website, that contains
-this license and contact information. For example:
-
- Datenstrom Yellow, https://github.com/datenstrom/yellow
-
-If your software is based on modified source code, you have to keep the
-original link in each source file. For example:
-
- Gnomovision Orange, https://github.com/gnomovision/orange
- Based on Datenstrom Yellow, https://github.com/datenstrom/yellow
-
-All source files are copyrighted by the respective author(s)
-and licensed under GPL version 2, unless stated otherwise.
diff --git a/media/thumbnails/photo-100x40.jpg b/media/thumbnails/photo-100x40.jpg
Binary files differ.
diff --git a/system/extensions/update-available.ini b/system/extensions/update-available.ini
@@ -612,17 +612,6 @@ Published: 2024-04-05 17:22:52
Status: available
system/workers/readingtime.php: readingtime.php, create, update
-Extension: Readingtime
-Version: 0.8.22
-Description: Show estimated reading time for page content.
-DownloadUrl: https://github.com/schulle4u/yellow-readingtime/archive/refs/heads/main.zip
-DocumentationUrl: https://github.com/schulle4u/yellow-readingtime
-DocumentationLanguage: en, de
-Published: 2023-05-23 13:25:56
-Developer: Steffen Schultz
-Tag: feature, page, blog, readingtime
-system/extensions/readingtime.php: readingtime.php, create, update
-
Extension: Russian
Version: 0.9.5
Description: Russian language.
diff --git a/system/extensions/update-installed.ini b/system/extensions/update-installed.ini
@@ -1,21 +1,22 @@
# Datenstrom Yellow update settings for installed extensions
Extension: Blog
-Version: 0.8.30
+Version: 0.9.4
Description: Blog for your website.
+Developer: Anna Svensson
+Tag: feature
DownloadUrl: https://github.com/annaesvensson/yellow-blog/archive/refs/heads/main.zip
DocumentationUrl: https://github.com/annaesvensson/yellow-blog
DocumentationLanguage: en, de, sv
-Published: 2023-11-01 17:49:02
-Developer: Anna Svensson
-Tag: feature
-system/extensions/blog.php: blog.php, create, update
+Published: 2024-05-09 16:44:32
+Status: available
+system/workers/blog.php: blog.php, create, update
system/layouts/blog.html: blog.html, create, update, careful
system/layouts/blog-start.html: blog-start.html, create, update, careful
content/shared/page-new-blog.md: page-new-blog.md, create, optional
-content/2-blog/page.md: page.md, create, optional
-content/2-blog/2020-04-07-blog-example-page.md: 2020-04-07-blog-example-page.md, create, optional
-content/2-blog/2020-12-06-made-for-people.md: 2020-12-06-made-for-people.md, create, optional
+content/3-blog/page.md: page.md, create, optional
+content/3-blog/2020-04-07-blog-example-page.md: 2020-04-07-blog-example-page.md, create, optional
+content/3-blog/2020-12-06-made-for-people.md: 2020-12-06-made-for-people.md, create, optional
Extension: Core
Version: 0.9.22
@@ -98,31 +99,6 @@ system/workers/image.php: image.php, create, update
media/images/photo.jpg: photo.jpg, create, optional
media/thumbnails/photo-100x40.jpg: photo-100x40.jpg, create, optional
-Extension: Install
-Version: 0.9.10
-Description: Install a brand new website.
-Developer: Anna Svensson
-DownloadUrl: https://github.com/annaesvensson/yellow-install/archive/refs/heads/main.zip
-DocumentationUrl: https://github.com/annaesvensson/yellow-install
-DocumentationLanguage: en, de, sv
-Published: 2026-02-19 22:47:16
-Status: unassembled
-system/workers/install.php: install.php, create
-system/workers/install-language.bin: install-language.bin, compress @source/yellow-language/, create
-system/workers/install-wiki.bin: install-wiki.bin, compress @source/yellow-wiki/, create
-system/workers/install-blog.bin: install-blog.bin, compress @source/yellow-blog/, create
-system/extensions/yellow-system.ini: yellow-system.ini, create
-system/extensions/yellow-user.ini: yellow-user.ini, create
-system/extensions/yellow-language.ini: yellow-language.ini, create
-content/1-home/page.md: 1-home-page.md, create
-content/9-about/page.md: 9-about-page.md, create
-content/shared/page-error-404.md: page-error-404.md, create
-media/downloads/yellow-english.pdf: yellow-english.pdf, create
-media/downloads/yellow-deutsch.pdf: yellow-deutsch.pdf, create
-media/downloads/yellow-svenska.pdf: yellow-svenska.pdf, create
-./yellow.php: yellow.php, create
-./robots.txt: robots.txt, create
-
Extension: Markdown
Version: 0.9.8
Description: Text formatting for humans.
@@ -135,6 +111,18 @@ Published: 2026-02-24 18:30:33
Status: available
system/workers/markdown.php: markdown.php, create, update
+Extension: Previousnext
+Version: 0.9.1
+Description: Show links to previous/next page.
+Developer: Anna Svensson
+Tag: feature
+DownloadUrl: https://github.com/annaesvensson/yellow-previousnext/archive/refs/heads/main.zip
+DocumentationUrl: https://github.com/annaesvensson/yellow-previousnext
+DocumentationLanguage: en, de, sv
+Published: 2024-04-05 00:26:47
+Status: available
+system/workers/previousnext.php: previousnext.php, create, update
+
Extension: Serve
Version: 0.9.1
Description: Built-in web server.
diff --git a/system/extensions/yellow-language.ini b/system/extensions/yellow-language.ini
@@ -4,10 +4,6 @@ Language: en
LanguageLocale: en_GB
LanguageDescription: English
LanguageTranslator: Mark Seuffert
-BlogDescription: Blog for your website.
-BlogBy: by
-BlogTag: Tags:
-BlogMore: Read moreā¦
CoreDescription: Core functionality of your website.
CoreNavigation: Main
CorePagination: Page
diff --git a/system/extensions/yellow-system.ini b/system/extensions/yellow-system.ini
@@ -16,24 +16,24 @@ CoreContentErrorFile: page-error-(.*).md
CoreLanguageFile: yellow-language.ini
CoreUserFile: yellow-user.ini
CoreWebsiteFile: yellow-website.log
+CoreAssetLocation: /assets/
CoreMediaLocation: /media/
CoreDownloadLocation: /media/downloads/
CoreImageLocation: /media/images/
CoreThumbnailLocation: /media/thumbnails/
-CoreExtensionLocation: /media/extensions/
-CoreThemeLocation: /media/themes/
CoreMultiLanguageMode: 0
CoreDebugMode: 0
-UpdateCurrentRelease: 0.8.23
-UpdateLatestUrl: auto
-UpdateLatestFile: update-latest.ini
-UpdateCurrentFile: update-current.ini
+UpdateCurrentRelease: 0.9
+UpdateAvailableUrl: auto
+UpdateAvailableFile: update-available.ini
+UpdateInstalledFile: update-installed.ini
UpdateExtensionFile: extension.ini
UpdateEventPending: none
-UpdateEventDaily: 1703376051
+UpdateEventDaily: 1772496051
UpdateTrashTimeout: 7776660
BlogStartLocation: /write/
-BlogNewLocation: @title
+BlogNewLocation: @date-@title
+BlogFilePrefix: 1
BlogShortcutEntries: 0
BlogPaginationLimit: 5
EditSiteEmail: noreply
@@ -52,11 +52,21 @@ EditUserHome: /
EditLoginRestriction: 0
EditLoginSessionTimeout: 2592000
EditBruteForceProtection: 25
-GenerateStaticUrl: auto
+GenerateStaticUrl: https://mikuli.cz
GenerateStaticDirectory: public/
GenerateStaticDefaultFile: index.html
GenerateStaticErrorFile: 404.html
ImageUploadWidthMax: 1280
ImageUploadHeightMax: 1280
+ImageUploadJpegQuality: 80
+ImageThumbnailJpegQuality: 80
+ImageJpegExtension: auto
+PreviousnextPagePrevious: 1
+PreviousnextPageNext: 1
+CoreExtensionLocation: /media/extensions/
+CoreThemeLocation: /media/themes/
+UpdateLatestUrl: auto
+UpdateLatestFile: update-latest.ini
+UpdateCurrentFile: update-current.ini
ImageUploadJpgQuality: 80
ImageThumbnailJpgQuality: 80
diff --git a/system/extensions/yellow-website.log b/system/extensions/yellow-website.log
@@ -12,3 +12,7 @@
2023-12-22 17:46:30 info Install extension 'Swedish 0.8.43'
2023-12-22 17:46:45 info Add user 'asd'
2023-12-23 08:35:04 info Install extension 'Blog 0.8.30'
+2026-03-02 21:35:59 info Uninstall extension 'Install 0.9.10'
+2026-03-02 21:35:59 info Update Datenstrom Yellow 0.9, PHP 8.3.30, Built-in 8.3.30, Linux
+2026-03-02 21:53:49 info Install extension 'Blog 0.9.4'
+2026-03-02 22:02:06 info Install extension 'Previousnext 0.9.1'
diff --git a/system/layouts/blog-start.html b/system/layouts/blog-start.html
@@ -8,7 +8,7 @@
<?php foreach ($pages as $page): ?>
<?php $page->set("entryClass", "entry") ?>
<?php if ($page->isExisting("tag")): ?>
-<?php foreach (preg_split("/\s*,\s*/", $page->get("tag")) as $tag) { $page->set("entryClass", $page->get("entryClass")." tag-".$this->yellow->lookup->normaliseArguments($tag, false)); } ?>
+<?php foreach (preg_split("/\s*,\s*/", $page->get("tag")) as $tag) { $page->set("entryClass", $page->get("entryClass")." tag-".$this->yellow->lookup->normaliseClass($tag)); } ?>
<?php endif ?>
<div class="<?php echo $page->getHtml("entryClass") ?>">
<div class="entry-title"><h1><a href="<?php echo $page->getLocation(true) ?>"><?php echo $page->getHtml("title") ?></a></h1></div>
diff --git a/system/layouts/blog.html b/system/layouts/blog.html
@@ -3,7 +3,7 @@
<div class="main" role="main">
<?php $this->yellow->page->set("entryClass", "entry") ?>
<?php if ($this->yellow->page->isExisting("tag")): ?>
-<?php foreach (preg_split("/\s*,\s*/", $this->yellow->page->get("tag")) as $tag) { $this->yellow->page->set("entryClass", $this->yellow->page->get("entryClass")." tag-".$this->yellow->lookup->normaliseArguments($tag, false)); } ?>
+<?php foreach (preg_split("/\s*,\s*/", $this->yellow->page->get("tag")) as $tag) { $this->yellow->page->set("entryClass", $this->yellow->page->get("entryClass")." tag-".$this->yellow->lookup->normaliseClass($tag)); } ?>
<?php endif ?>
<div class="<?php echo $this->yellow->page->getHtml("entryClass") ?>">
<div class="entry-title"><h1><?php echo $this->yellow->page->getHtml("titleContent") ?></h1></div>
diff --git a/system/workers/blog.php b/system/workers/blog.php
@@ -0,0 +1,252 @@
+<?php
+// Blog extension, https://github.com/annaesvensson/yellow-blog
+
+class YellowBlog {
+ const VERSION = "0.9.4";
+ public $yellow; // access to API
+
+ // Handle initialisation
+ public function onLoad($yellow) {
+ $this->yellow = $yellow;
+ $this->yellow->system->setDefault("blogStartLocation", "auto");
+ $this->yellow->system->setDefault("blogNewLocation", "@title");
+ $this->yellow->system->setDefault("blogFilePrefix", "1");
+ $this->yellow->system->setDefault("blogShortcutEntries", "0");
+ $this->yellow->system->setDefault("blogPaginationLimit", "5");
+ }
+
+ // Handle page meta data
+ public function onParseMetaData($page) {
+ if ($page->get("layout")=="blog") {
+ $page->set("editNewLocation", $this->yellow->system->get("blogNewLocation"));
+ if ($this->yellow->system->get("blogFilePrefix")) $page->set("editNewPrefix", $page->get("published"));
+ }
+ }
+
+ // Handle page content element
+ public function onParseContentElement($page, $name, $text, $attributes, $type) {
+ $output = null;
+ if (substru($name, 0, 4)=="blog" && ($type=="block" || $type=="inline")) {
+ switch($name) {
+ case "blogauthors": $output = $this->getShortcutBlogauthors($page, $name, $text); break;
+ case "blogtags": $output = $this->getShortcutBlogtags($page, $name, $text); break;
+ case "blogyears": $output = $this->getShortcutBlogyears($page, $name, $text); break;
+ case "blogmonths": $output = $this->getShortcutBlogmonths($page, $name, $text); break;
+ case "blogpages": $output = $this->getShortcutBlogpages($page, $name, $text); break;
+ }
+ }
+ return $output;
+ }
+
+ // Return blogauthors shortcut
+ public function getShortcutBlogauthors($page, $name, $text) {
+ $output = null;
+ list($startLocation, $shortcutEntries) = $this->yellow->toolbox->getTextArguments($text);
+ if (is_string_empty($startLocation)) $startLocation = $this->yellow->system->get("blogStartLocation");
+ if (is_string_empty($shortcutEntries)) $shortcutEntries = $this->yellow->system->get("blogShortcutEntries");
+ $blogStart = $this->getBlogStart($page, $startLocation);
+ if (!is_null($blogStart)) {
+ $pages = $this->getBlogPages($blogStart);
+ $page->setLastModified($pages->getModified());
+ $authors = $pages->group("author", false, "count");
+ if ($shortcutEntries!=0) $authors = array_slice($authors, 0, $shortcutEntries, true);
+ uksort($authors, "strnatcasecmp");
+ $output = "<div class=\"".htmlspecialchars($name)."\">\n";
+ $output .= "<ul>\n";
+ foreach ($authors as $author=>$collection) {
+ $output .= "<li><a href=\"".$blogStart->getLocation(true).$this->yellow->lookup->normaliseArguments("author:$author")."\">";
+ $output .= htmlspecialchars($author)."</a></li>\n";
+ }
+ $output .= "</ul>\n";
+ $output .= "</div>\n";
+ } else {
+ $page->error(500, "Blogauthors '$startLocation' does not exist!");
+ }
+ return $output;
+ }
+
+ // Return blogtags shortcut
+ public function getShortcutBlogtags($page, $name, $text) {
+ $output = null;
+ list($startLocation, $shortcutEntries) = $this->yellow->toolbox->getTextArguments($text);
+ if (is_string_empty($startLocation)) $startLocation = $this->yellow->system->get("blogStartLocation");
+ if (is_string_empty($shortcutEntries)) $shortcutEntries = $this->yellow->system->get("blogShortcutEntries");
+ $blogStart = $this->getBlogStart($page, $startLocation);
+ if (!is_null($blogStart)) {
+ $pages = $this->getBlogPages($blogStart);
+ $page->setLastModified($pages->getModified());
+ $tags = $pages->group("tag", false, "count");
+ if ($shortcutEntries!=0) $tags = array_slice($tags, 0, $shortcutEntries, true);
+ uksort($tags, "strnatcasecmp");
+ $output = "<div class=\"".htmlspecialchars($name)."\">\n";
+ $output .= "<ul>\n";
+ foreach ($tags as $tag=>$collection) {
+ $output .= "<li><a href=\"".$blogStart->getLocation(true).$this->yellow->lookup->normaliseArguments("tag:$tag")."\">";
+ $output .= htmlspecialchars($tag)."</a></li>\n";
+ }
+ $output .= "</ul>\n";
+ $output .= "</div>\n";
+ } else {
+ $page->error(500, "Blogtags '$startLocation' does not exist!");
+ }
+ return $output;
+ }
+
+ // Return blogyears shortcut
+ public function getShortcutBlogyears($page, $name, $text) {
+ $output = null;
+ list($startLocation, $shortcutEntries) = $this->yellow->toolbox->getTextArguments($text);
+ if (is_string_empty($startLocation)) $startLocation = $this->yellow->system->get("blogStartLocation");
+ if (is_string_empty($shortcutEntries)) $shortcutEntries = $this->yellow->system->get("blogShortcutEntries");
+ $blogStart = $this->getBlogStart($page, $startLocation);
+ if (!is_null($blogStart)) {
+ $pages = $this->getBlogPages($blogStart);
+ $page->setLastModified($pages->getModified());
+ $years = $pages->group("published", false, "Y");
+ if ($shortcutEntries!=0) $years = array_slice($years, 0, $shortcutEntries, true);
+ $output = "<div class=\"".htmlspecialchars($name)."\">\n";
+ $output .= "<ul>\n";
+ foreach ($years as $year=>$collection) {
+ $output .= "<li><a href=\"".$blogStart->getLocation(true).$this->yellow->lookup->normaliseArguments("published:$year")."\">";
+ $output .= htmlspecialchars($this->yellow->language->getDateStandard($year))."</a></li>\n";
+ }
+ $output .= "</ul>\n";
+ $output .= "</div>\n";
+ } else {
+ $page->error(500, "Blogyears '$startLocation' does not exist!");
+ }
+ return $output;
+ }
+
+ // Return blogmonths shortcut
+ public function getShortcutBlogmonths($page, $name, $text) {
+ $output = null;
+ list($startLocation, $shortcutEntries) = $this->yellow->toolbox->getTextArguments($text);
+ if (is_string_empty($startLocation)) $startLocation = $this->yellow->system->get("blogStartLocation");
+ if (is_string_empty($shortcutEntries)) $shortcutEntries = $this->yellow->system->get("blogShortcutEntries");
+ $blogStart = $this->getBlogStart($page, $startLocation);
+ if (!is_null($blogStart)) {
+ $pages = $this->getBlogPages($blogStart);
+ $page->setLastModified($pages->getModified());
+ $months = $pages->group("published", false, "Y-m");
+ if ($shortcutEntries!=0) $months = array_slice($months, 0, $shortcutEntries, true);
+ $output = "<div class=\"".htmlspecialchars($name)."\">\n";
+ $output .= "<ul>\n";
+ foreach ($months as $month=>$collection) {
+ $output .= "<li><a href=\"".$blogStart->getLocation(true).$this->yellow->lookup->normaliseArguments("published:$month")."\">";
+ $output .= htmlspecialchars($this->yellow->language->getDateStandard($month))."</a></li>\n";
+ }
+ $output .= "</ul>\n";
+ $output .= "</div>\n";
+ } else {
+ $page->error(500, "Blogmonths '$startLocation' does not exist!");
+ }
+ return $output;
+ }
+
+ // Return blogpages shortcut
+ public function getShortcutBlogpages($page, $name, $text) {
+ $output = null;
+ list($startLocation, $shortcutEntries, $filterTag) = $this->yellow->toolbox->getTextArguments($text);
+ if (is_string_empty($startLocation)) $startLocation = $this->yellow->system->get("blogStartLocation");
+ if (is_string_empty($shortcutEntries)) $shortcutEntries = $this->yellow->system->get("blogShortcutEntries");
+ $blogStart = $this->getBlogStart($page, $startLocation);
+ if (!is_null($blogStart)) {
+ $pages = $this->getBlogPages($blogStart)->remove($page);
+ $page->setLastModified($pages->getModified());
+ if (!is_string_empty($filterTag)) $pages->filter("tag", $filterTag);
+ $pages->sort("published", false);
+ if ($shortcutEntries!=0) $pages->limit($shortcutEntries);
+ $output = "<div class=\"".htmlspecialchars($name)."\">\n";
+ $output .= "<ul>\n";
+ foreach ($pages as $pageBlog) {
+ $output .= "<li><a".($pageBlog->isExisting("tag") ? " class=\"".$this->getClass($pageBlog)."\"" : "");
+ $output .=" href=\"".$pageBlog->getLocation(true)."\">".$pageBlog->getHtml("title")."</a></li>\n";
+ }
+ $output .= "</ul>\n";
+ $output .= "</div>\n";
+ } else {
+ $page->error(500, "Blogpages '$startLocation' does not exist!");
+ }
+ return $output;
+ }
+
+ // Handle page layout
+ public function onParsePageLayout($page, $name) {
+ if ($name=="blog-start") {
+ $pages = $this->getBlogPages($page);
+ $pagesFilter = array();
+ if ($page->isRequest("tag")) {
+ $pages->filter("tag", $page->getRequest("tag"));
+ array_push($pagesFilter, $pages->getFilter());
+ }
+ if ($page->isRequest("author")) {
+ $pages->filter("author", $page->getRequest("author"));
+ array_push($pagesFilter, $pages->getFilter());
+ }
+ if ($page->isRequest("published")) {
+ $pages->filter("published", $page->getRequest("published"), false);
+ array_push($pagesFilter, $this->yellow->language->getDateStandard($pages->getFilter()));
+ }
+ $pages->sort("published", false);
+ if (!is_array_empty($pagesFilter)) {
+ $text = implode(" ", $pagesFilter);
+ $page->set("titleHeader", $text." - ".$page->get("sitename"));
+ $page->set("titleContent", $page->get("title").": ".$text);
+ $page->set("title", $page->get("title").": ".$text);
+ $page->set("blogWithFilter", true);
+ }
+ $page->setPages("blog", $pages);
+ $page->setLastModified($pages->getModified());
+ $page->setHeader("Cache-Control", "max-age=60");
+ }
+ if ($name=="blog") {
+ $blogStartLocation = $this->yellow->system->get("blogStartLocation");
+ if ($blogStartLocation=="auto") {
+ $blogStart = $page->getParent();
+ } else {
+ $blogStart = $this->yellow->content->find($blogStartLocation);
+ }
+ $page->setPage("blogStart", $blogStart);
+ }
+ }
+
+ // Return blog start page, null if not found
+ public function getBlogStart($page, $blogStartLocation) {
+ if ($blogStartLocation=="auto") {
+ $blogStart = null;
+ foreach ($this->yellow->content->top(true, false) as $pageTop) {
+ if ($pageTop->get("layout")=="blog-start") {
+ $blogStart = $pageTop;
+ break;
+ }
+ }
+ if ($page->get("layout")=="blog-start") $blogStart = $page;
+ } else {
+ $blogStart = $this->yellow->content->find($blogStartLocation);
+ }
+ return $blogStart;
+ }
+
+ // Return blog pages for page
+ public function getBlogPages($page) {
+ if ($this->yellow->system->get("blogStartLocation")=="auto") {
+ $pages = $page->getChildren();
+ } else {
+ $pages = $this->yellow->content->index();
+ }
+ $pages->filter("layout", "blog");
+ return $pages;
+ }
+
+ // Return class for page
+ public function getClass($page) {
+ $class = "";
+ if ($page->isExisting("tag")) {
+ foreach (preg_split("/\s*,\s*/", $page->get("tag")) as $tag) {
+ $class .= " tag-".$this->yellow->lookup->normaliseClass($tag);
+ }
+ }
+ return trim($class);
+ }
+}
diff --git a/system/workers/install-blog.bin b/system/workers/install-blog.bin
Binary files differ.
diff --git a/system/workers/install-language.bin b/system/workers/install-language.bin
Binary files differ.
diff --git a/system/workers/install-wiki.bin b/system/workers/install-wiki.bin
Binary files differ.
diff --git a/system/workers/install.php b/system/workers/install.php
@@ -1,581 +0,0 @@
-<?php
-// Install extension, https://github.com/annaesvensson/yellow-install
-
-class YellowInstall {
- const VERSION = "0.9.10";
- const PRIORITY = "1";
- public $yellow; // access to API
-
- // Handle initialisation
- public function onLoad($yellow) {
- $this->yellow = $yellow;
- }
-
- // Handle request
- public function onRequest($scheme, $address, $base, $location, $fileName) {
- return $this->processRequestInstall($scheme, $address, $base, $location, $fileName);
- }
-
- // Handle command
- public function onCommand($command, $text) {
- return $this->processCommandInstall($command, $text);
- }
-
- // Process request to install website
- public function processRequestInstall($scheme, $address, $base, $location, $fileName) {
- $statusCode = 0;
- if ($this->yellow->lookup->isContentFile($fileName) || is_string_empty($fileName)) {
- if ($this->yellow->system->get("updateCurrentRelease")=="none") {
- $this->checkServerRequirements();
- $author = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $this->yellow->page->getRequest("author")));
- $email = trim($this->yellow->page->getRequest("email"));
- $password = trim($this->yellow->page->getRequest("password"));
- $language = trim($this->yellow->page->getRequest("language"));
- $extension = trim($this->yellow->page->getRequest("extension"));
- $status = trim($this->yellow->page->getRequest("status"));
- $statusCode = $this->updateLog();
- $statusCode = max($statusCode, $this->updateLanguages("small"));
- $errorMessage = $this->yellow->page->errorMessage;
- $this->yellow->content->pages["root/"] = array();
- $this->yellow->page = new YellowPage($this->yellow);
- $this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName, false);
- $this->yellow->page->parseMeta($this->getRawDataInstall(), $statusCode, $errorMessage);
- $this->yellow->page->parseContent();
- $this->yellow->page->parsePage();
- if ($status=="install") $status = $this->updateExtensions("small", $extension)==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateUser($email, $password, $author, $language)==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateAuthentication($scheme, $address, $base, $email)==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "installHome", "/")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "installAbout", "/about/")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "installDefault", "/shared/page-new-default")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "installWiki", "/shared/page-new-wiki")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "installBlog", "/shared/page-new-blog")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateContent($language, "coreError404", "/shared/page-error-404")==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->updateSettings()==200 ? "ok" : "error";
- if ($status=="ok") $status = $this->removeInstall()==200 ? "done" : "error";
- } else {
- $status = $this->removeInstall(true)==200 ? "done" : "error";
- }
- if ($status=="done") {
- $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, "/");
- $statusCode = $this->yellow->sendStatus(303, $location);
- } else {
- $statusCode = $this->yellow->sendData($this->yellow->page->statusCode, $this->yellow->page->headerData, $this->yellow->page->outputData);
- }
- }
- return $statusCode;
- }
-
- // Process command to install website
- public function processCommandInstall($command, $text) {
- $statusCode = 0;
- if ($this->yellow->system->get("updateCurrentRelease")=="none") {
- $this->checkCommandRequirements();
- list($installation, $option) = $this->yellow->toolbox->getTextArguments($text);
- if (is_string_empty($command)) {
- $statusCode = 200;
- echo "Datenstrom Yellow is for people who make small websites. https://datenstrom.se/yellow/\n";
- echo "Syntax: php yellow.php\n";
- echo " php yellow.php about [extension]\n";
- echo " php yellow.php serve [url]\n";
- echo " php yellow.php skip installation [option]\n";
- } elseif ($command=="about" || $command=="serve") {
- $statusCode = 0;
- } elseif ($command=="skip" && $installation=="installation") {
- $statusCode = $this->updateLog();
- if ($statusCode==200) $statusCode = $this->updateLanguages($option);
- if ($statusCode==200) $statusCode = $this->updateExtensions($option, "");
- if ($statusCode==200) $statusCode = $this->updateSettings(true);
- if ($statusCode==200) $statusCode = $this->removeInstall();
- if ($statusCode>=400) {
- echo "ERROR installing files: ".$this->yellow->page->errorMessage."\n";
- echo "The installation has not been completed. Please run command again.\n";
- } else {
- $extensionsCount = $this->getExtensionsCount();
- echo "Yellow $command: $extensionsCount extension".($extensionsCount!=1 ? "s" : "").", 0 errors\n";
- }
- } else {
- $statusCode = 500;
- echo "The installation has not been completed. Please type 'php yellow.php serve' or 'php yellow.php skip installation`.\n";
- }
- } else {
- $statusCode = $this->removeInstall(true);
- if ($statusCode==200) $statusCode = 0;
- if ($statusCode>=400) {
- echo "ERROR installing files: ".$this->yellow->page->errorMessage."\n";
- echo "Detected ZIP files, 0 extensions installed. Please run command again.\n";
- }
- }
- return $statusCode;
- }
-
- // Update log file
- public function updateLog() {
- $statusCode = 200;
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreWebsiteFile");
- if (!is_file($fileName)) {
- list($name, $version, $os) = $this->yellow->toolbox->detectServerInformation();
- $product = "Datenstrom Yellow ".YellowCore::RELEASE;
- $this->yellow->toolbox->log("info", "Install $product, PHP ".PHP_VERSION.", $name $version, $os");
- foreach ($this->yellow->extension->data as $key=>$value) {
- if ($key=="install") continue;
- $this->yellow->toolbox->log("info", "Install extension '".ucfirst($key)." $value[version]'");
- }
- if (!is_file($fileName)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- return $statusCode;
- }
-
- // Update languages
- public function updateLanguages($option) {
- $statusCode = 200;
- $path = $this->yellow->system->get("coreWorkerDirectory")."install-language.bin";
- $zip = new ZipArchive();
- if ($zip->open($path)===true) {
- $pathBase = "";
- if (preg_match("#^(.*\/).*?$#", $zip->getNameIndex(0), $matches)) $pathBase = $matches[1];
- $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateExtensionFile"));
- foreach ($this->getLanguageExtensionsRequired($fileData, $option) as $extension) {
- $fileDataPhp = $zip->getFromName($pathBase."translations/$extension/$extension.php");
- $fileDataIni = $zip->getFromName($pathBase."translations/$extension/extension.ini");
- $statusCode = max($statusCode, $this->updateLanguageArchive($fileDataPhp, $fileDataIni, $pathBase, "install"));
- }
- $this->yellow->extension->load($this->yellow->system->get("coreWorkerDirectory"));
- $this->yellow->language->load($this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreLanguageFile"));
- $zip->close();
- } else {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't open file '$path'!");
- }
- return $statusCode;
- }
-
- // Update language archive
- public function updateLanguageArchive($fileDataPhp, $fileDataIni, $pathBase, $action) {
- $statusCode = 200;
- if ($this->yellow->extension->isExisting("update")) {
- $settings = $this->yellow->toolbox->getTextSettings($fileDataIni, "");
- $extension = lcfirst($settings->get("extension"));
- $version = $settings->get("version");
- $modified = strtotime($settings->get("published"));
- $fileNamePhp = $this->yellow->system->get("coreWorkerDirectory").$extension.".php";
- if (!is_string_empty($extension) && !is_string_empty($version) && !is_file($fileNamePhp)) {
- $statusCode = max($statusCode, $this->yellow->extension->get("update")->updateExtensionSettings($extension, $action, $fileDataIni));
- $statusCode = max($statusCode, $this->yellow->extension->get("update")->updateExtensionFile(
- $fileNamePhp, $fileDataPhp, $modified, 0, 0, "create", $extension));
- $this->yellow->toolbox->log($statusCode==200 ? "info" : "error", ucfirst($action)." extension '".ucfirst($extension)." $version'");
- }
- }
- return $statusCode;
- }
-
- // Update extensions
- public function updateExtensions($option, $extension) {
- $statusCode = 200;
- if ($this->yellow->extension->isExisting("update")) {
- if (!is_string_empty($option)) {
- if ($option=="medium" || $option=="large") {
- $path = $this->yellow->system->get("coreExtensionDirectory");
- $fileData = $this->yellow->toolbox->readFile($path.$this->yellow->system->get("updateAvailableFile"));
- $settings = $this->yellow->toolbox->getTextSettings($fileData, "extension");
- $extensions = $this->getAvailableExtensionsRequired($settings, $option);
- $statusCode = $this->downloadExtensionsAvailable($settings, $extensions);
- $path = $this->yellow->system->get("coreWorkerDirectory");
- foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^install-.*\.bin$/", true, false) as $entry) {
- if (basename($entry)=="install-language.bin") continue;
- if (preg_match("/^install-(.*?)\.bin/", basename($entry), $matches) && !in_array($matches[1], $extensions)) continue;
- $statusCode = max($statusCode, $this->yellow->extension->get("update")->updateExtensionArchive($entry, "install"));
- }
- }
- if (!($option=="small" || $option=="medium" || $option=="large")) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Option '$option' not supported!");
- }
- }
- if (!is_string_empty($extension)) {
- $path = $this->yellow->system->get("coreWorkerDirectory")."install-".$extension.".bin";
- if (is_file($path)) {
- $statusCode = $this->yellow->extension->get("update")->updateExtensionArchive($path, "install");
- }
- }
- }
- return $statusCode;
- }
-
- // Update user
- public function updateUser($email, $password, $name, $language) {
- $statusCode = 200;
- if ($this->yellow->extension->isExisting("edit") && !is_string_empty($email) && !is_string_empty($password)) {
- if (is_string_empty($name)) $name = $this->yellow->system->get("sitename");
- $fileNameUser = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreUserFile");
- $settings = array(
- "name" => $name,
- "description" => $this->yellow->language->getText("editUserDescription", $language),
- "language" => $language,
- "access" => "create, edit, delete, restore, upload, configure, update",
- "home" => "/",
- "hash" => $this->yellow->extension->get("edit")->response->createHash($password),
- "stamp" => $this->yellow->extension->get("edit")->response->createStamp(),
- "pending" => "none",
- "failed" => "0",
- "modified" => date("Y-m-d H:i:s", time()),
- "status" => "active");
- if (!$this->yellow->user->save($fileNameUser, $email, $settings)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileNameUser'!");
- }
- $this->yellow->toolbox->log($statusCode==200 ? "info" : "error", "Add user '".strtok($name, " ")."'");
- }
- return $statusCode;
- }
-
- // Update authentication
- public function updateAuthentication($scheme, $address, $base, $email) {
- if ($this->yellow->extension->isExisting("edit") && $this->yellow->user->isExisting($email)) {
- $base = rtrim($base.$this->yellow->system->get("editLocation"), "/");
- $this->yellow->extension->get("edit")->response->createCookies($scheme, $address, $base, $email);
- }
- return 200;
- }
-
- // Update content
- public function updateContent($language, $name, $location) {
- $statusCode = 200;
- $fileName = $this->yellow->lookup->findFileFromContentLocation($location);
- $fileData = str_replace("\r\n", "\n", $this->yellow->toolbox->readFile($fileName));
- if (!is_string_empty($fileData) && $language!="en") {
- $titleOld = "Title: ".$this->yellow->language->getText("{$name}Title", "en")."\n";
- $titleNew = "Title: ".$this->yellow->language->getText("{$name}Title", $language)."\n";
- $fileData = str_replace($titleOld, $titleNew, $fileData);
- $textOld = str_replace("\\n", "\n", $this->yellow->language->getText("{$name}Text", "en"));
- $textNew = str_replace("\\n", "\n", $this->yellow->language->getText("{$name}Text", $language));
- $fileData = str_replace($textOld, $textNew, $fileData);
- if (!$this->yellow->toolbox->writeFile($fileName, $fileData)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- return $statusCode;
- }
-
- // Update settings
- public function updateSettings($skipInstallation = false) {
- $statusCode = 200;
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreSystemFile");
- if (!$this->yellow->system->save($fileName, $this->getSystemSettings($skipInstallation))) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- $language = $this->yellow->system->get("language");
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreLanguageFile");
- $fileData = $this->yellow->toolbox->readFile($fileName);
- if (strposu($fileData, "Language:")===false) {
- if (!is_string_empty($fileData)) $fileData .= "\n";
- $fileData .= "Language: $language\n";
- $fileData .= "media/images/photo.jpg: ".$this->yellow->language->getText("installExampleImage", $language)."\n";
- if (!$this->yellow->toolbox->writeFile($fileName, $fileData)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- }
- return $statusCode;
- }
-
- // Remove files used by installation
- public function removeInstall($log = false) {
- $statusCode = 200;
- if (function_exists("opcache_reset")) opcache_reset();
- $this->yellow->toolbox->deleteFile("license.md");
- $fileName = $this->yellow->system->get("coreWorkerDirectory")."install.php";
- if (!$this->yellow->toolbox->deleteFile($fileName)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't delete file '$fileName'!");
- }
- $path = $this->yellow->system->get("coreWorkerDirectory");
- foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^install-.*\.bin$/", true, false) as $entry) {
- if (!$this->yellow->toolbox->deleteFile($entry)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't delete file '$entry'!");
- }
- }
- if ($statusCode==200) unset($this->yellow->extension->data["install"]);
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("updateInstalledFile");
- $fileData = $this->yellow->toolbox->readFile($fileName);
- $fileDataNew = $this->yellow->toolbox->unsetTextSettings($fileData, "extension", "install");
- if ($statusCode==200 && !$this->yellow->toolbox->writeFile($fileName, $fileDataNew)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- if ($log) $this->yellow->toolbox->log($statusCode==200 ? "info" : "error", "Uninstall extension 'Install ".YellowInstall::VERSION."'");
- return $statusCode;
- }
-
- // Check web server requirements
- public function checkServerRequirements() {
- if ($this->yellow->system->get("coreDebugMode")>=1) {
- list($name, $version, $os) = $this->yellow->toolbox->detectServerInformation();
- echo "YellowInstall::checkServerRequirements for $name $version, $os<br />\n";
- }
- if (!$this->checkServerComplete()) $this->yellow->exitFatalError("Datenstrom Yellow requires complete upload!");
- if (!$this->checkServerWrite()) $this->yellow->exitFatalError("Datenstrom Yellow requires write access!");
- if (!$this->checkServerHtaccess()) $this->yellow->exitFatalError("Datenstrom Yellow requires htaccess file!");
- if (!$this->checkServerRewrite()) $this->yellow->exitFatalError("Datenstrom Yellow requires rewrite support!");
- }
-
- // Check command line requirements
- public function checkCommandRequirements() {
- if ($this->yellow->system->get("coreDebugMode")>=1) {
- list($name, $version, $os) = $this->yellow->toolbox->detectServerInformation();
- echo "YellowInstall::checkCommandRequirements for $name $version, $os<br />\n";
- }
- if (!$this->checkServerComplete()) $this->yellow->exitFatalError("Datenstrom Yellow requires complete upload!");
- if (!$this->checkServerWrite()) $this->yellow->exitFatalError("Datenstrom Yellow requires write access!");
- }
-
- // Check web server complete upload
- public function checkServerComplete() {
- $complete = true;
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("updateInstalledFile");
- $fileData = $this->yellow->toolbox->readFile($fileName);
- $settings = $this->yellow->toolbox->getTextSettings($fileData, "extension");
- $fileNames = array($fileName);
- foreach ($settings as $extension=>$block) {
- foreach ($block as $key=>$value) {
- if (strposu($key, "/")) {
- list($entry, $flags) = $this->yellow->toolbox->getTextList($value, ",", 2);
- if (!preg_match("/create/i", $flags)) continue;
- if (preg_match("/delete/i", $flags)) continue;
- if (preg_match("/additional/i", $flags)) continue;
- array_push($fileNames, $key);
- }
- }
- }
- foreach ($fileNames as $fileName) {
- if (!is_file($fileName) || filesize($fileName)==0) {
- $complete = false;
- if ($this->yellow->system->get("coreDebugMode")>=1) {
- echo "YellowInstall::checkServerComplete detected missing file:$fileName<br />\n";
- }
- }
- }
- return $complete;
- }
-
- // Check web server write access
- public function checkServerWrite() {
- $fileName = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("coreSystemFile");
- return $this->yellow->system->save($fileName, array());
- }
-
- // Check web server htaccess file
- public function checkServerHtaccess() {
- list($name) = $this->yellow->toolbox->detectServerInformation();
- return strtoloweru($name)!="apache" || is_file(".htaccess");
- }
-
- // Check web server rewrite support
- public function checkServerRewrite() {
- $rewrite = true;
- if (!$this->isServerBuiltin()) {
- $curlHandle = curl_init();
- list($scheme, $address, $base) = $this->yellow->lookup->getRequestInformation();
- $location = $this->yellow->system->get("coreAssetLocation").$this->yellow->lookup->normaliseName($this->yellow->system->get("theme")).".css";
- $url = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
- curl_setopt($curlHandle, CURLOPT_URL, $url);
- curl_setopt($curlHandle, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; YellowInstall/".YellowInstall::VERSION).")";
- curl_setopt($curlHandle, CURLOPT_NOBODY, 1);
- curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 30);
- curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, false);
- curl_exec($curlHandle);
- $statusCode = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
- if (PHP_VERSION_ID<80000) curl_close($curlHandle);
- if ($statusCode!=200) {
- $rewrite = false;
- if ($this->yellow->system->get("coreDebugMode")>=1 && !$rewrite) {
- echo "YellowInstall::checkServerRewrite detected failed url:$url<br />\n";
- }
- }
- }
- return $rewrite;
- }
-
- // Download available extension files
- public function downloadExtensionsAvailable($settings, $extensions) {
- $statusCode = 200;
- if ($this->yellow->extension->isExisting("update")) {
- $path = $this->yellow->system->get("coreWorkerDirectory");
- $extensionsNow = 0;
- $extensionsTotal = count($extensions);
- $curlHandle = curl_init();
- foreach ($extensions as $extension) {
- echo "\rDownloading available extensions ".$this->getProgressPercent(++$extensionsNow, $extensionsTotal, 5, 95)."%... ";
- $fileName = $path."install-".$this->yellow->lookup->normaliseName($extension, true, false, true).".bin";
- if (is_file($fileName)) continue;
- $url = $settings[$extension]->get("downloadUrl");
- curl_setopt($curlHandle, CURLOPT_URL, $this->yellow->extension->get("update")->getExtensionDownloadUrl($url));
- curl_setopt($curlHandle, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; YellowInstall/".YellowInstall::VERSION).")";
- curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, 30);
- $fileData = curl_exec($curlHandle);
- $statusCode = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
- $redirectUrl = ($statusCode>=300 && $statusCode<=399) ? curl_getinfo($curlHandle, CURLINFO_REDIRECT_URL) : "";
- if ($statusCode==0) {
- $statusCode = 450;
- $this->yellow->page->error($statusCode, "Can't connect to the update server!");
- }
- if ($statusCode!=450 && $statusCode!=200) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't download file '$url'!");
- }
- if ($statusCode==200 && !$this->yellow->toolbox->writeFile($fileName, $fileData)) {
- $statusCode = 500;
- $this->yellow->page->error($statusCode, "Can't write file '$fileName'!");
- }
- if ($this->yellow->system->get("coreDebugMode")>=2 && !is_string_empty($redirectUrl)) {
- echo "YellowInstall::downloadExtensionsAvailable redirected to url:$redirectUrl<br />\n";
- }
- if ($this->yellow->system->get("coreDebugMode")>=2) {
- echo "YellowInstall::downloadExtensionsAvailable status:$statusCode url:$url<br />\n";
- }
- if ($statusCode!=200) break;
- }
- if (PHP_VERSION_ID<80000) curl_close($curlHandle);
- echo "\rDownloading available extensions 100%... done\n";
- }
- return $statusCode;
- }
-
- // Return available extensions required
- public function getAvailableExtensionsRequired($settings, $option) {
- $extensions = array();
- if ($option=="medium") {
- $text = "help highlight search toc";
- $extensions = array_unique(array_filter($this->yellow->toolbox->getTextArguments($text), "strlen"));
- } elseif ($option=="large") {
- foreach ($settings as $key=>$value) {
- if (preg_match("/language/i", $value->get("tag"))) continue;
- array_push($extensions, strtoloweru($key));
- }
- }
- return $extensions;
- }
-
- // Return language extensions required
- public function getLanguageExtensionsRequired($fileData, $option) {
- $extensions = array();
- $languages = array();
- foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
- if (preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches)) {
- if (!is_string_empty($matches[1]) && !is_string_empty($matches[2]) && strposu($matches[1], "/")) {
- $extension = basename($matches[1]);
- $extension = $this->yellow->lookup->normaliseName($extension, true, true);
- list($entry, $flags) = $this->yellow->toolbox->getTextList($matches[2], ",", 2);
- $arguments = preg_split("/\s*,\s*/", trim($flags));
- $language = array_pop($arguments);
- if (preg_match("/^(.*)\.php$/", basename($entry))) {
- $languages[$language] = $extension;
- }
- }
- }
- }
- if ($option=="large") {
- foreach ($languages as $language=>$extension) {
- array_push($extensions, $extension);
- }
- } else {
- foreach ($this->getSystemLanguages("en, de, sv") as $language) {
- if (isset($languages[$language])) array_push($extensions, $languages[$language]);
- }
- $extensions = array_slice($extensions, 0, 3);
- }
- return $extensions;
- }
-
- // Return extensions installed
- public function getExtensionsCount() {
- $fileNameCurrent = $this->yellow->system->get("coreExtensionDirectory").$this->yellow->system->get("updateInstalledFile");
- $fileData = $this->yellow->toolbox->readFile($fileNameCurrent);
- $settings = $this->yellow->toolbox->getTextSettings($fileData, "extension");
- return count($settings);
- }
-
- // Return system languages
- public function getSystemLanguages($languagesDefault) {
- $languages = array();
- foreach (preg_split("/\s*,\s*/", $this->yellow->toolbox->getServer("HTTP_ACCEPT_LANGUAGE")) as $string) {
- list($language, $dummy) = $this->yellow->toolbox->getTextList($string, ";", 2);
- if (!is_string_empty($language)) array_push($languages, $language);
- }
- foreach (preg_split("/\s*,\s*/", $languagesDefault) as $language) {
- if (!is_string_empty($language)) array_push($languages, $language);
- }
- return array_unique($languages);
- }
-
- // Return system settings
- public function getSystemSettings($skipInstallation) {
- $settings = array();
- foreach ($_REQUEST as $key=>$value) {
- if (!$this->yellow->system->isExisting($key)) continue;
- if ($key=="password" || $key=="status") continue;
- $settings[$key] = trim($value);
- }
- if ($this->yellow->system->get("sitename")=="Datenstrom Yellow") $settings["sitename"] = $this->yellow->toolbox->detectServerSitename();
- if ($this->yellow->system->get("generateStaticUrl")=="auto" && getenv("URL")!==false) $settings["generateStaticUrl"] = getenv("URL");
- if ($this->yellow->system->get("generateStaticUrl")=="auto" && $skipInstallation) $settings["generateStaticUrl"] = "http://localhost:8000/";
- if ($this->yellow->system->get("coreTimezone")=="UTC") $settings["coreTimezone"] = $this->yellow->toolbox->detectServerTimezone();
- if ($this->yellow->system->get("updateEventPending")=="none") {
- $settings["updateEventPending"] = "website/install";
- } else {
- $themeStandard = ",".$this->yellow->system->get("theme")."/install";
- $settings["updateEventPending"] = $this->yellow->system->get("updateEventPending").$themeStandard;
- }
- $settings["updateCurrentRelease"] = YellowCore::RELEASE;
- return $settings;
- }
-
- // Return raw data for install page
- public function getRawDataInstall() {
- $languages = $this->yellow->toolbox->enumerate("language");
- $language = $this->yellow->toolbox->detectBrowserLanguage($languages, $this->yellow->system->get("language"));
- $this->yellow->language->set($language);
- $rawData = "---\nTitle:".$this->yellow->language->getText("installTitle")."\nLanguage:$language\nNavigation:navigation\nHeader:none\nFooter:none\nSidebar:none\n---\n";
- $rawData .= "<form class=\"install-form\" action=\"".$this->yellow->page->getLocation(true)."\" method=\"post\">\n";
- $rawData .= "<p><label for=\"author\">".$this->yellow->language->getText("editSignupName")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"author\" id=\"author\" value=\"\" /></p>\n";
- $rawData .= "<p><label for=\"email\">".$this->yellow->language->getText("editSignupEmail")."</label><br /><input class=\"form-control\" type=\"text\" maxlength=\"64\" name=\"email\" id=\"email\" value=\"\" /></p>\n";
- $rawData .= "<p><label for=\"password\">".$this->yellow->language->getText("editSignupPassword")."</label><br /><input class=\"form-control\" type=\"password\" maxlength=\"64\" name=\"password\" id=\"password\" value=\"\" /></p>\n";
- $rawData .= "<p>".$this->yellow->language->getText("installLanguage")."</p>\n<p>";
- foreach ($languages as $language) {
- $checked = $language==$this->yellow->language->language ? " checked=\"checked\"" : "";
- $rawData .= "<label for=\"{$language}-language\"><input type=\"radio\" name=\"language\" id=\"{$language}-language\" value=\"$language\"$checked> ".$this->yellow->language->getTextHtml("languageDescription", $language)."</label><br />";
- }
- $rawData .= "</p>\n";
- $rawData .= "<p>".$this->yellow->language->getText("installExtension")."</p>\n<p>";
- foreach (array("website", "wiki", "blog") as $extension) {
- $checked = $extension=="website" ? " checked=\"checked\"" : "";
- $rawData .= "<label for=\"{$extension}-extension\"><input type=\"radio\" name=\"extension\" id=\"{$extension}-extension\" value=\"$extension\"$checked> ".$this->yellow->language->getTextHtml("installExtension".ucfirst($extension))."</label><br />";
- }
- $rawData .= "</p>\n";
- $rawData .= "<input class=\"btn\" type=\"submit\" value=\"".$this->yellow->language->getText("installButton")."\" />\n";
- $rawData .= "<input type=\"hidden\" name=\"status\" value=\"install\" />\n";
- $rawData .= "</form>\n";
- return $rawData;
- }
-
- // Return progress in percent
- public function getProgressPercent($now, $total, $increments, $max) {
- $max = intval($max/$increments) * $increments;
- $percent = intval(($max/$total) * $now);
- if ($increments>1) $percent = intval($percent/$increments) * $increments;
- return min($max, $percent);
- }
-
- // Check if running built-in web server
- public function isServerBuiltin() {
- list($name) = $this->yellow->toolbox->detectServerInformation();
- return strtoloweru($name)=="built-in";
- }
-}
diff --git a/system/workers/previousnext.php b/system/workers/previousnext.php
@@ -0,0 +1,67 @@
+<?php
+// Previousnext extension, https://github.com/annaesvensson/yellow-previousnext
+
+class YellowPreviousnext {
+ const VERSION = "0.9.1";
+ public $yellow; // access to API
+
+ // Handle initialisation
+ public function onLoad($yellow) {
+ $this->yellow = $yellow;
+ $this->yellow->system->setDefault("previousnextPagePrevious", "1");
+ $this->yellow->system->setDefault("previousnextPageNext", "1");
+ }
+
+ // Handle page content element
+ public function onParseContentElement($page, $name, $text, $attributes, $type) {
+ $output = null;
+ if ($name=="previousnext" && ($type=="block" || $type=="inline")) {
+ $pages = $this->getRelatedPages($page);
+ $page->setLastModified($pages->getModified());
+ $pagePrevious = $pageNext = null;
+ if ($this->yellow->system->get("previousnextPagePrevious")) $pagePrevious = $pages->getPagePrevious($page);
+ if ($this->yellow->system->get("previousnextPageNext")) $pageNext = $pages->getPageNext($page);
+ if ($pagePrevious!=null || $pageNext!=null) {
+ $output = "<div class=\"previousnext\" role=\"navigation\" aria-label=\"".$this->yellow->language->getTextHtml("previousnextNavigation")."\">\n";
+ $output .= "<p>";
+ if ($pagePrevious!=null) {
+ $text = preg_replace("/@title/i", $pagePrevious->get("title"), $this->yellow->language->getText("previousnextPagePrevious"));
+ $output .= "<a class=\"previous\" href=\"".$pagePrevious->getLocation(true)."\">".htmlspecialchars($text)."</a>";
+ }
+ if ($pageNext!=null) {
+ if ($pagePrevious) $output .= " ";
+ $text = preg_replace("/@title/i", $pageNext->get("title"), $this->yellow->language->getText("previousnextPageNext"));
+ $output .= "<a class=\"next\" href=\"".$pageNext->getLocation(true)."\">".htmlspecialchars($text)."</a>";
+ }
+ $output .= "</p>\n";
+ $output .="</div>\n";
+ }
+ }
+ return $output;
+ }
+
+ // Handle page extra data
+ public function onParsePageExtra($page, $name) {
+ $output = null;
+ if ($name=="previousnext" || $name=="link") {
+ $output = $this->onParseContentElement($page, "previousnext", "", "", "block");
+ }
+ return $output;
+ }
+
+ // Return related pages
+ public function getRelatedPages($page) {
+ switch ($page->get("layout")) {
+ case "blog": if ($this->yellow->system->get("blogStartLocation")=="auto") {
+ $pages = $page->getSiblings();
+ } else {
+ $pages = $this->yellow->content->index();
+ }
+ $pages->filter("layout", "blog")->sort("published", true);
+ break;
+ case "blog-start": $pages = $this->yellow->content->clean(); break;
+ default: $pages = $page->getSiblings();
+ }
+ return $pages;
+ }
+}