-
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2023 Diego Najar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - نظام إدارة المحتوى البسيط والسريع والمرن.
|
||||
|
||||
مع Bludit، يمكنك بناء موقعك الإلكتروني أو مدونتك في ثوانٍ معدودة. إنه مجاني تمامًا، مفتوح المصدر، وسهل الاستخدام. يخزن Bludit المحتوى بتنسيق JSON، مما يلغي الحاجة إلى تثبيت أو تهيئة قاعدة بيانات. كل ما تحتاجه هو خادم ويب يدعم PHP.
|
||||
|
||||
كـ Flat-File CMS، يقدم Bludit مرونة وسرعة لا مثيل لهما. بالإضافة إلى ذلك، مع دعم كود Markdown وHTML، أصبح إنشاء وإدارة المحتوى أسهل من أي وقت مضى.
|
||||
|
||||
## الموارد
|
||||
|
||||
- [الإضافات](https://plugins.bludit.com)
|
||||
- [القوالب](https://themes.bludit.com)
|
||||
- [الوثائق](https://docs.bludit.com)
|
||||
- الأخبار والإعلانات على [تويتر](https://twitter.com/bludit)، [فيسبوك](https://www.facebook.com/bluditcms)، و[ريديت](https://www.reddit.com/r/bludit/)
|
||||
- الحديث والدردشة على [ديسكورد](https://discord.gg/CFaXEdZWds)
|
||||
- المساعدة والدعم على [المنتدى](https://forum.bludit.org)
|
||||
- تقارير الأخطاء على [مشكلات غيت هب](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## المتطلبات
|
||||
|
||||
- خادم ويب يدعم PHP.
|
||||
- إصدار PHP 8.0 أو أعلى.
|
||||
- وحدة PHP [mbstring](http://php.net/manual/en/book.mbstring.php) لدعم UTF-8 الكامل.
|
||||
- وحدة PHP [gd](http://php.net/manual/en/book.image.php) لمعالجة الصور.
|
||||
- وحدة PHP [dom](http://php.net/manual/en/book.dom.php) للتعامل مع DOM.
|
||||
- وحدة PHP [json](http://php.net/manual/en/book.json.php) للتعامل مع JSON.
|
||||
|
||||
## التثبيت
|
||||
|
||||
1. قم بتنزيل الإصدار الأحدث من الصفحة الرسمية: [Bludit.com](https://www.bludit.com)
|
||||
2. استخرج ملف الـ zip إلى دليل، مثل `bludit`.
|
||||
3. ارفع دليل `bludit` إلى خادم الويب أو الاستضافة الخاص بك.
|
||||
4. قم بزيارة نطاقك (مثل https://example.com/bludit/).
|
||||
5. اتبع مثبت Bludit لإعداد موقعك.
|
||||
|
||||
## تثبيت سريع للاختبار
|
||||
|
||||
يمكنك استخدام خادم الويب المدمج في PHP (`php -S localhost:8000`) أو Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
ثم افتح http://localhost:8000
|
||||
|
||||
## ترقية Bludit
|
||||
|
||||
قبل ترقية Bludit، **قم دائمًا بعمل نسخة احتياطية من موقعك**. هذا يشمل:
|
||||
- مجلد `bl-content/` بأكمله (يحتوي على صفحاتك، القاعدة، الوسائط، الإعدادات)
|
||||
- أي تخصيصات قمت بها على المواضيع أو الإضافات
|
||||
|
||||
### خطوات الترقية
|
||||
|
||||
1. **قم بتنزيل أحدث نسخة**: احصل على أحدث إصدار من Bludit من [الموقع الرسمي](https://www.bludit.com) أو [GitHub](https://github.com/bludit/bludit/releases)
|
||||
|
||||
2. **قم بعمل نسخة احتياطية**: انسخ المجلدات التالية إلى مكان آمن:
|
||||
- `bl-content/` (الأهم - يحتوي على جميع بياناتك)
|
||||
- أي مواضيع أو إضافات مخصصة قمت بتعديلها
|
||||
|
||||
3. **حذف المجلدات القديمة**: احذف هذه المجلدات من تثبيت Bludit الحالي:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
|
||||
4. **تحميل الملفات الجديدة**: من حزمة Bludit الجديدة، قم بتحميل:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
- `index.php`
|
||||
- `install.php`
|
||||
- `.htaccess` (إذا كان موجودًا)
|
||||
|
||||
5. **الاحتفاظ بمحتواك**: **لا تستبدل** مجلد `bl-content/` - فهو يحتوي على جميع بياناتك
|
||||
|
||||
6. **تحديث Bludit**: افتح موقعك في متصفح. سيكتشف Bludit الإصدار الجديد ويقوم بتشغيل عملية الترقية تلقائيًا
|
||||
|
||||
7. **التحقق من موقعك**: بعد الترقية:
|
||||
- تسجيل الدخول إلى لوحة الإدارة
|
||||
- التحقق من ظهور محتواك بشكل صحيح
|
||||
- اختبار المواضيع والإضافات
|
||||
- مراجعة إعداداتك
|
||||
|
||||
8. **مسح ذاكرة التخزين المؤقت**: إذا واجهت مشاكل:
|
||||
- مسح ذاكرة التخزين المؤقت للمتصفح
|
||||
- إذا كنت تستخددم إضافة للتخزين المؤقت، امسح ذاكرتها المؤقتة
|
||||
- تحقق من سجلات الخادم للأخطاء
|
||||
|
||||
> **ملاحظة**: يحفظ Bludit جميع بياناتك كملفات JSON في `bl-content/databases/`. طالما حافظت على هذا المجلد سليمًا، فإن بياناتك آمنة.
|
||||
|
||||
## دعم Bludit
|
||||
|
||||
Bludit مفتوح المصدر ومجاني الاستخدام، لكن إذا وجدت المشروع مفيدًا وترغب في دعم تطويره، يمكنك المساهمة على [باتيريون](https://www.patreon.com/join/bludit). كرمز لتقديرنا، سيحصل الداعمون على Bludit PRO.
|
||||
|
||||
إذا كنت تفضل، يمكنك أيضًا تقديم تبرع لمرة واحدة لشراء قهوة أو بيرة لنا. كل مساهمة تساعدنا على مواصلة تحسين Bludit وتقديم أفضل تجربة ممكنة لمستخدمينا.
|
||||
|
||||
- [باي بال](https://www.paypal.me/bludit/10)
|
||||
- BTC (بيتكوين): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (إيثريوم): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## الترخيص
|
||||
|
||||
Bludit هو برمجية مفتوحة المصدر مرخصة بموجب [ترخيص MIT](https://tldrlegal.com/license/mit-license).
|
||||
@@ -0,0 +1,85 @@
|
||||
# [Bludit](https://www.bludit.com/de/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - das einfache, schnelle und flexible CMS.
|
||||
|
||||
Mit Bludit können Sie Ihre eigene Website oder Ihren Blog in Sekunden erstellen. Es ist völlig kostenlos, open-source und einfach zu bedienen. Bludit speichert Inhalte im JSON-Format, sodass keine Datenbankinstallation oder -konfiguration erforderlich ist. Alles, was Sie brauchen, ist ein Webserver mit PHP-Unterstützung.
|
||||
|
||||
Als Flat-File-CMS bietet Bludit unvergleichliche Flexibilität und Geschwindigkeit. Zudem macht die Unterstützung für Markdown- und HTML-Code das Erstellen und Verwalten von Inhalten einfacher denn je.
|
||||
|
||||
## Ressourcen
|
||||
|
||||
- [Plugins](https://plugins.bludit.com)
|
||||
- [Themes](https://themes.bludit.com)
|
||||
- [Dokumentation](https://docs.bludit.com)
|
||||
- Neuigkeiten und Ankündigungen auf [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms) und [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Gespräche und Chat auf [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Hilfe und Support auf [Forum](https://forum.bludit.org)
|
||||
- Fehlermeldungen auf [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Anforderungen
|
||||
|
||||
- Webserver mit PHP-Unterstützung.
|
||||
- PHP Version 8.0 oder höher.
|
||||
- PHP-Modul [mbstring](http://php.net/manual/en/book.mbstring.php) für vollständige UTF-8-Unterstützung.
|
||||
- PHP-Modul [gd](http://php.net/manual/en/book.image.php) für Bildverarbeitung.
|
||||
- PHP-Modul [dom](http://php.net/manual/en/book.dom.php) für DOM-Manipulation.
|
||||
- PHP-Modul [json](http://php.net/manual/en/book.json.php) für JSON-Manipulation.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Laden Sie die neueste Version von der offiziellen Seite herunter: [Bludit.com](https://www.bludit.com/de/)
|
||||
2. Entpacken Sie die Zip-Datei in ein Verzeichnis, wie `bludit`.
|
||||
3. Laden Sie das Verzeichnis `bludit` auf Ihren Webserver oder Ihr Hosting hoch.
|
||||
4. Besuchen Sie Ihre Domain (z. B. https://example.com/bludit/).
|
||||
5. Folgen Sie dem Bludit-Installer, um Ihre Website einzurichten.
|
||||
|
||||
## Schnelle Installation zum Testen
|
||||
|
||||
Sie können den integrierten PHP-Webserver (`php -S localhost:8000`) oder Docker verwenden:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Dann öffnen Sie http://localhost:8000
|
||||
|
||||
## Bludit aktualisieren
|
||||
|
||||
Die folgenden Schritte gelten für die Aktualisierung auf jede Version von Bludit derselben Hauptversion. Die Hauptversion ist die erste Ziffer in der Versionsnummer, zum Beispiel Bludit v3.x.
|
||||
|
||||
1. **Erstellen Sie ein vollständiges Backup**, keine Diskussion hier, vollständiges Backup der Dateien und Verzeichnisse. Das bedeutet, ALLE Dateien in einen neuen Ordner zu kopieren.
|
||||
2. **Merken Sie sich, welche Version von Bludit Sie verwenden** für ein mögliches Rollback.
|
||||
3. **Laden Sie die neueste Version** von der [offiziellen Seite](https://www.bludit.com) herunter.
|
||||
4. **Entpacken Sie die Zip-Datei**.
|
||||
5. **Ersetzen Sie vorhandene Dateien** durch die neuen Dateien.
|
||||
6. **Löschen Sie Ihren Browser-Cache**, und lesen Sie bitte den Hinweis unten.
|
||||
7. **Melden Sie sich im Administrationsbereich an** und überprüfen Sie Ihre Einstellungen.
|
||||
8. Fertig.
|
||||
|
||||
> **Hinweis:** Wenn Ihre Website hinter einem Server-Cache-System steht (z.B. bietet Cloudflare standardmäßig eines an), müssen Sie die Dateien dort ebenfalls löschen. Es ist auch eine gute Idee, Ihren Browser-Cache zu löschen. Bludit versucht, die Dateien mit den neuen zu laden, aber einige Komponenten wie TinyMCE werden möglicherweise nicht neu geladen und können Probleme in der Benutzeroberfläche verursachen oder JavaScript-Fehler werfen.
|
||||
|
||||
## Bludit unterstützen
|
||||
|
||||
Bludit ist open-source und kostenlos zu verwenden, aber wenn Sie das Projekt nützlich finden und seine Entwicklung unterstützen möchten, können Sie auf [Patreon](https://www.patreon.com/join/bludit) beitragen. Als Zeichen unserer Wertschätzung erhalten Unterstützer Bludit PRO.
|
||||
|
||||
Falls gewünscht, können Sie auch eine einmalige Spende machen, um uns einen Kaffee oder ein Bier zu spenden. Jeder Beitrag hilft uns, Bludit weiter zu verbessern und die beste Erfahrung für unsere Nutzer zu bieten.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Lizenz
|
||||
|
||||
Bludit ist open-source-Software unter der [MIT-Lizenz](https://tldrlegal.com/license/mit-license).
|
||||
@@ -0,0 +1,85 @@
|
||||
# [Bludit](https://www.bludit.com/es/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - CMS simple, rápido y flexible.
|
||||
|
||||
Con Bludit, puedes crear tu propio sitio web o blog en solo segundos. Es completamente gratuito, de código abierto y fácil de usar. Bludit almacena el contenido en formato JSON, eliminando la necesidad de instalar o configurar una base de datos. Todo lo que necesitas es un servidor web con soporte PHP.
|
||||
|
||||
Como CMS de archivos planos, Bludit ofrece una flexibilidad y velocidad inigualables. Además, con soporte para código Markdown y HTML, crear y gestionar contenido nunca ha sido tan fácil.
|
||||
|
||||
## Recursos
|
||||
|
||||
- [Plugins](https://plugins.bludit.com)
|
||||
- [Temas](https://themes.bludit.com)
|
||||
- [Documentación](https://docs.bludit.com)
|
||||
- Noticias y anuncios en [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms) y [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Charla y chat en [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Ayuda y soporte en [Foro](https://forum.bludit.org)
|
||||
- Reportes de errores en [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Servidor web con soporte PHP.
|
||||
- PHP versión 8.0 o superior.
|
||||
- Módulo PHP [mbstring](http://php.net/manual/en/book.mbstring.php) para soporte completo de UTF-8.
|
||||
- Módulo PHP [gd](http://php.net/manual/en/book.image.php) para procesamiento de imágenes.
|
||||
- Módulo PHP [dom](http://php.net/manual/en/book.dom.php) para manipulación de DOM.
|
||||
- Módulo PHP [json](http://php.net/manual/en/book.json.php) para manipulación de JSON.
|
||||
|
||||
## Instalación
|
||||
|
||||
1. Descarga la última versión desde la página oficial: [Bludit.com](https://www.bludit.com/es/)
|
||||
2. Extrae el archivo zip en un directorio, como `bludit`.
|
||||
3. Sube el directorio `bludit` a tu servidor web o hosting.
|
||||
4. Visita tu dominio (por ejemplo, https://example.com/bludit/).
|
||||
5. Sigue el instalador de Bludit para configurar tu sitio.
|
||||
|
||||
## Instalación rápida para pruebas
|
||||
|
||||
Puedes usar el servidor web incorporado de PHP (`php -S localhost:8000`) o Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Luego abre http://localhost:8000
|
||||
|
||||
## Actualizar Bludit
|
||||
|
||||
Los siguientes pasos son válidos para actualizar a cualquier versión de Bludit de la misma versión mayor. La versión mayor es el primer dígito en el número de versión, por ejemplo, Bludit v3.x.
|
||||
|
||||
1. **Haz una copia de seguridad completa**, sin discusión aquí, copia de seguridad completa de los archivos y directorios. Eso significa copiar TODOS los archivos en una nueva carpeta.
|
||||
2. **Recuerda qué versión de Bludit estás usando** para una posible reversión.
|
||||
3. **Descarga la última versión** desde la [página oficial](https://www.bludit.com).
|
||||
4. **Extrae el archivo zip**.
|
||||
5. **Reemplaza los archivos existentes** con los nuevos archivos.
|
||||
6. **Limpia la caché de tu navegador**, y por favor lee la nota a continuación.
|
||||
7. **Inicia sesión en el área de administración** y verifica tu configuración.
|
||||
8. Listo.
|
||||
|
||||
> **Nota:** Si tu sitio web está detrás de algún tipo de sistema de caché de servidor (por ejemplo, Cloudflare proporciona uno por defecto) necesitas purgar los archivos allí también. También es una buena idea limpiar la caché de tu navegador. Bludit intenta recargar los archivos con los nuevos, pero algunos componentes como TinyMCE pueden no recargarse y provocar problemas en la interfaz de usuario o generar errores de JavaScript.
|
||||
|
||||
## Apoya a Bludit
|
||||
|
||||
Bludit es de código abierto y gratuito para usar, pero si encuentras el proyecto útil y quieres apoyar su desarrollo, puedes contribuir en [Patreon](https://www.patreon.com/join/bludit). Como muestra de nuestra apreciación, los supporters recibirán Bludit PRO.
|
||||
|
||||
Si prefieres, también puedes hacer una donación única para comprarnos un café o una cerveza. Cada contribución nos ayuda a continuar mejorando Bludit y proporcionar la mejor experiencia posible a nuestros usuarios.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Licencia
|
||||
|
||||
Bludit es software de código abierto licenciado bajo la [licencia MIT](https://tldrlegal.com/license/mit-license).
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - le CMS simple, rapide et flexible.
|
||||
|
||||
Avec Bludit, vous pouvez créer votre propre site web ou blog en quelques secondes. Il est complètement gratuit, open-source et facile à utiliser. Bludit stocke le contenu au format JSON, éliminant le besoin d'installer ou de configurer une base de données. Tout ce dont vous avez besoin est un serveur web avec support PHP.
|
||||
|
||||
En tant que CMS flat-file, Bludit offre une flexibilité et une vitesse inégalées. De plus, avec le support pour le code Markdown et HTML, créer et gérer du contenu n'a jamais été aussi simple.
|
||||
|
||||
## Ressources
|
||||
|
||||
- [Plugins](https://plugins.bludit.com)
|
||||
- [Thèmes](https://themes.bludit.com)
|
||||
- [Documentation](https://docs.bludit.com)
|
||||
- Actualités et annonces sur [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms) et [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Discussion et chat sur [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Aide et support sur [Forum](https://forum.bludit.org)
|
||||
- Rapports de bugs sur [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Exigences
|
||||
|
||||
- Serveur web avec support PHP.
|
||||
- PHP version 8.0 ou supérieure.
|
||||
- Module PHP [mbstring](http://php.net/manual/en/book.mbstring.php) pour un support UTF-8 complet.
|
||||
- Module PHP [gd](http://php.net/manual/en/book.image.php) pour le traitement d'images.
|
||||
- Module PHP [dom](http://php.net/manual/en/book.dom.php) pour la manipulation DOM.
|
||||
- Module PHP [json](http://php.net/manual/en/book.json.php) pour la manipulation JSON.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Téléchargez la dernière version depuis la page officielle : [Bludit.com](https://www.bludit.com)
|
||||
2. Extrayez le fichier zip dans un répertoire, tel que `bludit`.
|
||||
3. Téléchargez le répertoire `bludit` sur votre serveur web ou hébergement.
|
||||
4. Visitez votre domaine (par exemple, https://example.com/bludit/).
|
||||
5. Suivez l'installateur Bludit pour configurer votre site.
|
||||
|
||||
## Installation rapide pour tests
|
||||
|
||||
Vous pouvez utiliser le serveur web intégré de PHP (`php -S localhost:8000`) ou Docker :
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Ensuite, ouvrez http://localhost:8000
|
||||
|
||||
## Mettre à jour Bludit
|
||||
|
||||
Avant de mettre à jour Bludit, **faites toujours une sauvegarde de votre site**. Cela inclut :
|
||||
- L'intégralité du dossier `bl-content/` (contient vos pages, bases de données, médias, paramètres)
|
||||
- Toute personnalisation apportée aux thèmes ou plugins
|
||||
|
||||
### Étapes de mise à jour
|
||||
|
||||
1. **Téléchargez la dernière version** : Obtenez la dernière version de Bludit depuis le [site officiel](https://www.bludit.com) ou [GitHub](https://github.com/bludit/bludit/releases)
|
||||
|
||||
2. **Créez une sauvegarde** : Copiez les dossiers suivants dans un endroit sûr :
|
||||
- `bl-content/` (le plus important - contient toutes vos données)
|
||||
- Tout thème ou plugin personnalisé que vous avez modifié
|
||||
|
||||
3. **Supprimez les anciens dossiers** : De votre installation Bludit actuelle, supprimez ces dossiers :
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
|
||||
4. **Téléversez les nouveaux fichiers** : Depuis le nouveau package Bludit, téléversez :
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
- `index.php`
|
||||
- `install.php`
|
||||
- `.htaccess` (si présent)
|
||||
|
||||
5. **Conservez votre contenu** : **NE remplacez PAS** le dossier `bl-content/` - il contient toutes vos données
|
||||
|
||||
6. **Mettez à jour Bludit** : Ouvrez votre site dans un navigateur. Bludit détectera la nouvelle version et exécutera automatiquement le processus de mise à jour
|
||||
|
||||
7. **Vérifiez votre site** : Après la mise à jour :
|
||||
- Connectez-vous au panneau d'administration
|
||||
- Vérifiez que votre contenu s'affiche correctement
|
||||
- Testez les thèmes et plugins
|
||||
- Vérifiez vos paramètres
|
||||
|
||||
8. **Videz le cache** : Si vous rencontrez des problèmes :
|
||||
- Videz le cache de votre navigateur
|
||||
- Si vous utilisez un plugin de mise en cache, videz son cache
|
||||
- Vérifiez les journaux du serveur pour les erreurs
|
||||
|
||||
> **Note** : Bludit stocke toutes vos données sous forme de fichiers JSON dans `bl-content/databases/`. Tant que vous conservez ce dossier intact, vos données sont en sécurité.
|
||||
|
||||
## Soutenir Bludit
|
||||
|
||||
Bludit est open-source et gratuit à utiliser, mais si vous trouvez le projet utile et souhaitez soutenir son développement, vous pouvez contribuer sur [Patreon](https://www.patreon.com/join/bludit). En signe de notre appréciation, les supporters recevront Bludit PRO.
|
||||
|
||||
Si vous préférez, vous pouvez également faire un don unique pour nous offrir un café ou une bière. Chaque contribution nous aide à continuer d'améliorer Bludit et à fournir la meilleure expérience possible à nos utilisateurs.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Licence
|
||||
|
||||
Bludit est un logiciel open-source sous [licence MIT](https://tldrlegal.com/license/mit-license).
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - सरल, तेज और लचीला CMS.
|
||||
|
||||
Bludit के साथ, आप कुछ सेकंड में अपनी खुद की वेबसाइट या ब्लॉग बना सकते हैं। यह पूरी तरह से मुफ्त, ओपन-सोर्स और उपयोग में आसान है। Bludit सामग्री को JSON प्रारूप में संग्रहीत करता है, जो डेटाबेस इंस्टॉलेशन या कॉन्फ़िगरेशन की आवश्यकता को समाप्त कर देता है। आपको केवल PHP सपोर्ट वाले वेब सर्वर की आवश्यकता है।
|
||||
|
||||
एक Flat-File CMS के रूप में, Bludit अद्वितीय लचीलापन और गति प्रदान करता है। इसके अलावा, Markdown और HTML कोड के समर्थन के साथ, सामग्री बनाना और प्रबंधित करना कभी इतना आसान नहीं रहा।
|
||||
|
||||
## संसाधन
|
||||
|
||||
- [प्लगइन्स](https://plugins.bludit.com)
|
||||
- [थीम्स](https://themes.bludit.com)
|
||||
- [दस्तावेज़ीकरण](https://docs.bludit.com)
|
||||
- समाचार और घोषणाएं [ट्विटर](https://twitter.com/bludit), [फेसबुक](https://www.facebook.com/bluditcms) और [रेडिट](https://www.reddit.com/r/bludit/) पर
|
||||
- बातचीत और चैट [डिस्कॉर्ड](https://discord.gg/CFaXEdZWds) पर
|
||||
- मदद और समर्थन [फोरम](https://forum.bludit.org) पर
|
||||
- बग रिपोर्ट [गिटहब इश्यूज](https://github.com/bludit/bludit/issues) पर
|
||||
|
||||
## आवश्यकताएँ
|
||||
|
||||
- PHP सपोर्ट वाला वेबसर्वर।
|
||||
- PHP v8.0 या उच्च संस्करण।
|
||||
- पूर्ण UTF-8 समर्थन के लिए PHP [mbstring](http://php.net/manual/en/book.mbstring.php) मॉड्यूल।
|
||||
- छवि प्रसंस्करण के लिए PHP [gd](http://php.net/manual/en/book.image.php) मॉड्यूल।
|
||||
- DOM मैनिपुलेशन के लिए PHP [dom](http://php.net/manual/en/book.dom.php) मॉड्यूल।
|
||||
- JSON मैनिपुलेशन के लिए PHP [json](http://php.net/manual/en/book.json.php) मॉड्यूल।
|
||||
|
||||
## इंस्टॉलेशन
|
||||
|
||||
1. आधिकारिक पेज से नवीनतम संस्करण डाउनलोड करें: [Bludit.com](https://www.bludit.com)
|
||||
2. ज़िप फ़ाइल को एक डायरेक्टरी में निकालें, जैसे `bludit`।
|
||||
3. `bludit` डायरेक्टरी को अपने वेब सर्वर या होस्टिंग पर अपलोड करें।
|
||||
4. अपना डोमेन विज़िट करें (उदा., https://example.com/bludit/)।
|
||||
5. अपनी वेबसाइट सेट अप करने के लिए Bludit इंस्टॉलर का पालन करें।
|
||||
|
||||
## परीक्षण के लिए त्वरित इंस्टॉलेशन
|
||||
|
||||
आप PHP बिल्ट-इन वेब सर्वर (`php -S localhost:8000`) या Docker का उपयोग कर सकते हैं:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
फिर http://localhost:8000 खोलें
|
||||
|
||||
## Bludit का अपग्रेड करें
|
||||
|
||||
Bludit को अपग्रेड करने से पहले, **हमेशा अपनी साइट का बैकअप लें**। इसमें शामिल हैं:
|
||||
- संपूर्ण `bl-content/` फ़ोल्डर (इसमें आपके पेज, डेटाबेस, मीडिया, सेटिंग्स हैं)
|
||||
- थीम या प्लगइन्स में किए गए कोई भी कस्टमाइज़ेशन
|
||||
|
||||
### अपग्रेड चरण
|
||||
|
||||
1. **नवीनतम संस्करण डाउनलोड करें**: [आधिकारिक वेबसाइट](https://www.bludit.com) या [GitHub](https://github.com/bludit/bludit/releases) से Bludit का नवीनतम संस्करण प्राप्त करें
|
||||
|
||||
2. **बैकअप बनाएं**: निम्नलिखित फ़ोल्डरों को सुरक्षित स्थान पर कॉपी करें:
|
||||
- `bl-content/` (सबसे महत्वपूर्ण - इसमें आपका सभी डेटा है)
|
||||
- कोई भी कस्टम थीम या प्लगइन्स जिन्हें आपने संशोधित किया है
|
||||
|
||||
3. **पुराने फ़ोल्डर हटाएं**: अपने वर्तमान Bludit इंस्टॉलेशन से ये फ़ोल्डर हटाएं:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
|
||||
4. **नई फाइलें अपलोड करें**: नए Bludit पैकेज से, अपलोड करें:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
- `index.php`
|
||||
- `install.php`
|
||||
- `.htaccess` (यदि मौजूद हो)
|
||||
|
||||
5. **अपनी सामग्री रखें**: `bl-content/` फ़ोल्डर को **प्रतिस्थापित न करें** - इसमें आपका सभी डेटा है
|
||||
|
||||
6. **Bludit अपडेट करें**: अपनी साइट को ब्राउज़र में खोलें। Bludit नए संस्करण का पता लगाएगा और स्वचालित रूप से अपग्रेड प्रक्रिया चलाएगा
|
||||
|
||||
7. **अपनी साइट सत्यापित करें**: अपग्रेड के बाद:
|
||||
- व्यवस्थापक पैनल में लॉग इन करें
|
||||
- सत्यापित करें कि आपकी सामग्री सही ढंग से दिखाई देती है
|
||||
- थीम और प्लगइन्स का परीक्षण करें
|
||||
- अपनी सेटिंग्स की समीक्षा करें
|
||||
|
||||
8. **कैश साफ़ करें**: यदि आपको समस्याएं आती हैं:
|
||||
- अपने ब्राउज़र का कैश साफ़ करें
|
||||
- यदि कैशिंग प्लगइन का उपयोग कर रहे हैं, तो इसका कैश साफ़ करें
|
||||
- त्रुटियों के लिए सर्वर लॉग जांचें
|
||||
|
||||
> **नोट**: Bludit आपके सभी डेटा को `bl-content/databases/` में JSON फाइलों के रूप में संग्रहीत करता है। जब तक आप इस फ़ोल्डर को बरकरार रखते हैं, आपका डेटा सुरक्षित है।
|
||||
|
||||
## Bludit का समर्थन करें
|
||||
|
||||
Bludit ओपन-सोर्स और उपयोग करने के लिए मुफ्त है, लेकिन यदि आपको प्रोजेक्ट उपयोगी लगता है और इसके विकास का समर्थन करना चाहते हैं, तो आप [पैट्रियन](https://www.patreon.com/join/bludit) पर योगदान दे सकते हैं। हमारी सराहना के प्रतीक के रूप में, समर्थक Bludit PRO प्राप्त करेंगे।
|
||||
|
||||
यदि आप चाहें, तो आप हमें कॉफी या बीयर खरीदने के लिए एक बार का दान भी कर सकते हैं। हर योगदान हमें Bludit को बेहतर बनाने और हमारे उपयोगकर्ताओं के लिए सर्वोत्तम संभव अनुभव प्रदान करने में मदद करता है।
|
||||
|
||||
- [पेपाल](https://www.paypal.me/bludit/10)
|
||||
- BTC (बिटकॉइन): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (ईथीरियम): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
|
||||
## लाइसेंस
|
||||
|
||||
Bludit MIT लाइसेंस के तहत लाइसेंस प्राप्त ओपन सोर्स सॉफ्टवेयर है।
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - il CMS semplice, veloce e flessibile.
|
||||
|
||||
Con Bludit, puoi creare il tuo sito web o blog in pochi secondi. È completamente gratuito, open-source e facile da usare. Bludit memorizza i contenuti in formato JSON, eliminando la necessità di installare o configurare un database. Tutto ciò di cui hai bisogno è un server web con supporto PHP.
|
||||
|
||||
Come CMS flat-file, Bludit offre una flessibilità e velocità senza pari. Inoltre, con il supporto per codice Markdown e HTML, creare e gestire contenuti non è mai stato così facile.
|
||||
|
||||
## Risorse
|
||||
|
||||
- [Plugin](https://plugins.bludit.com)
|
||||
- [Temi](https://themes.bludit.com)
|
||||
- [Documentazione](https://docs.bludit.com)
|
||||
- Notizie e annunci su [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms) e [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Conversazioni e chat su [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Aiuto e supporto su [Forum](https://forum.bludit.org)
|
||||
- Segnalazioni di bug su [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Requisiti
|
||||
|
||||
- Server web con supporto PHP.
|
||||
- PHP versione 8.0 o superiore.
|
||||
- Modulo PHP [mbstring](http://php.net/manual/en/book.mbstring.php) per supporto completo UTF-8.
|
||||
- Modulo PHP [gd](http://php.net/manual/en/book.image.php) per elaborazione immagini.
|
||||
- Modulo PHP [dom](http://php.net/manual/en/book.dom.php) per manipolazione DOM.
|
||||
- Modulo PHP [json](http://php.net/manual/en/book.json.php) per manipolazione JSON.
|
||||
|
||||
## Installazione
|
||||
|
||||
1. Scarica l'ultima versione dalla pagina ufficiale: [Bludit.com](https://www.bludit.com)
|
||||
2. Estrai il file zip in una directory, come `bludit`.
|
||||
3. Carica la directory `bludit` sul tuo server web o hosting.
|
||||
4. Visita il tuo dominio (ad esempio, https://example.com/bludit/).
|
||||
5. Segui l'installatore Bludit per configurare il tuo sito.
|
||||
|
||||
## Installazione rapida per test
|
||||
|
||||
Puoi usare il server web integrato di PHP (`php -S localhost:8000`) oppure Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Poi apri http://localhost:8000
|
||||
|
||||
## Aggiornare Bludit
|
||||
|
||||
Prima di aggiornare Bludit, **fai sempre un backup del tuo sito**. Questo include:
|
||||
- L'intera cartella `bl-content/` (contiene le tue pagine, database, media, impostazioni)
|
||||
- Qualsiasi personalizzazione fatta a temi o plugin
|
||||
|
||||
### Passaggi per l'Aggiornamento
|
||||
|
||||
1. **Scarica l'ultima versione**: Ottieni l'ultima versione di Bludit dal [sito ufficiale](https://www.bludit.com) o da [GitHub](https://github.com/bludit/bludit/releases)
|
||||
|
||||
2. **Crea un backup**: Copia le seguenti cartelle in un luogo sicuro:
|
||||
- `bl-content/` (più importante - contiene tutti i tuoi dati)
|
||||
- Qualsiasi tema o plugin personalizzato che hai modificato
|
||||
|
||||
3. **Elimina le vecchie cartelle**: Dalla tua installazione Bludit corrente, elimina queste cartelle:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
|
||||
4. **Carica i nuovi file**: Dal nuovo pacchetto Bludit, carica:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
- `index.php`
|
||||
- `install.php`
|
||||
- `.htaccess` (se presente)
|
||||
|
||||
5. **Mantieni il tuo contenuto**: **NON sostituire** la cartella `bl-content/` - contiene tutti i tuoi dati
|
||||
|
||||
6. **Aggiorna Bludit**: Apri il tuo sito in un browser. Bludit rileverà la nuova versione ed eseguirà automaticamente il processo di aggiornamento
|
||||
|
||||
7. **Verifica il tuo sito**: Dopo l'aggiornamento:
|
||||
- Accedi al pannello di amministrazione
|
||||
- Verifica che il tuo contenuto appaia correttamente
|
||||
- Testa temi e plugin
|
||||
- Controlla le tue impostazioni
|
||||
|
||||
8. **Cancella la cache**: Se riscontri problemi:
|
||||
- Cancella la cache del browser
|
||||
- Se usi un plugin di caching, cancella la sua cache
|
||||
- Controlla i log del server per errori
|
||||
|
||||
> **Nota**: Bludit memorizza tutti i tuoi dati come file JSON in `bl-content/databases/`. Finché mantieni questa cartella intatta, i tuoi dati sono al sicuro.
|
||||
|
||||
## Supporta Bludit
|
||||
|
||||
Bludit è open-source e gratuito da usare, ma se trovi il progetto utile e vuoi supportarne lo sviluppo, puoi contribuire su [Patreon](https://www.patreon.com/join/bludit). Come segno della nostra apprezzamento, i sostenitori riceveranno Bludit PRO.
|
||||
|
||||
Se preferisci, puoi anche fare una donazione una tantum per offrirci un caffè o una birra. Ogni contributo ci aiuta a continuare a migliorare Bludit e fornire la migliore esperienza possibile ai nostri utenti.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Licenza
|
||||
|
||||
Bludit è software open-source con licenza [MIT](https://tldrlegal.com/license/mit-license).
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - シンプルで高速で柔軟なCMS。
|
||||
|
||||
Bluditを使えば、数秒で自分のウェブサイトやブログを作成できます。完全に無料でオープンソースで使いやすいです。BluditはコンテンツをJSON形式で保存するため、データベースのインストールや設定は必要ありません。必要なのはPHPをサポートするウェブサーバーだけです。
|
||||
|
||||
フラットファイルCMSとして、Bluditは比類のない柔軟性と速度を提供します。さらに、MarkdownとHTMLコードのサポートにより、コンテンツの作成と管理がこれまで以上に簡単になりました。
|
||||
|
||||
## リソース
|
||||
|
||||
- [プラグイン](https://plugins.bludit.com)
|
||||
- [テーマ](https://themes.bludit.com)
|
||||
- [ドキュメント](https://docs.bludit.com)
|
||||
- ニュースと発表は[Twitter](https://twitter.com/bludit)、[Facebook](https://www.facebook.com/bluditcms)、[Reddit](https://www.reddit.com/r/bludit/)で
|
||||
- トークとチャットは[Discord](https://discord.gg/CFaXEdZWds)で
|
||||
- ヘルプとサポートは[フォーラム](https://forum.bludit.org)で
|
||||
- バグレポートは[Github Issues](https://github.com/bludit/bludit/issues)で
|
||||
|
||||
## 要件
|
||||
|
||||
- PHPをサポートするウェブサーバー。
|
||||
- PHPバージョン8.0以上。
|
||||
- UTF-8の完全サポートのためのPHP [mbstring](http://php.net/manual/en/book.mbstring.php)モジュール。
|
||||
- 画像処理のためのPHP [gd](http://php.net/manual/en/book.image.php)モジュール。
|
||||
- DOM操作のためのPHP [dom](http://php.net/manual/en/book.dom.php)モジュール。
|
||||
- JSON操作のためのPHP [json](http://php.net/manual/en/book.json.php)モジュール。
|
||||
|
||||
## インストール
|
||||
|
||||
1. 公式ページから最新バージョンをダウンロード:[Bludit.com](https://www.bludit.com)
|
||||
2. zipファイルをディレクトリに展開、例えば`bludit`。
|
||||
3. `bludit`ディレクトリをウェブサーバーまたはホスティングにアップロード。
|
||||
4. ドメインにアクセス(例: https://example.com/bludit/)。
|
||||
5. Bluditインストーラーに従ってサイトを設定。
|
||||
|
||||
## テストのためのクイックインストール
|
||||
|
||||
PHPの組み込みウェブサーバー(`php -S localhost:8000`)またはDockerを使用できます:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
その後 http://localhost:8000 を開いてください
|
||||
|
||||
## Bluditのアップグレード
|
||||
|
||||
Bluditをアップグレードする前に、**必ずサイトをバックアップしてください**。これには以下が含まれます:
|
||||
- `bl-content/` フォルダ全体(ページ、データベース、メディア、設定を含みます)
|
||||
- テーマやプラグインへのカスタマイズ
|
||||
|
||||
### アップグレード手順
|
||||
|
||||
1. **最新バージョンをダウンロード**: [公式ウェブサイト](https://www.bludit.com)または[GitHub](https://github.com/bludit/bludit/releases)からBluditの最新バージョンを入手
|
||||
|
||||
2. **バックアップを作成**: 以下のフォルダを安全な場所にコピー:
|
||||
- `bl-content/`(最も重要 - すべてのデータが含まれています)
|
||||
- 変更したカスタムテーマやプラグイン
|
||||
|
||||
3. **古いフォルダを削除**: 現在のBluditインストールから以下のフォルダを削除:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
|
||||
4. **新しいファイルをアップロード**: 新しいBluditパッケージから以下をアップロード:
|
||||
- `bl-kernel/`
|
||||
- `bl-languages/`
|
||||
- `bl-plugins/`
|
||||
- `bl-themes/`
|
||||
- `index.php`
|
||||
- `install.php`
|
||||
- `.htaccess`(存在する場合)
|
||||
|
||||
5. **コンテンツを保持**: `bl-content/` フォルダは**置き換えないでください** - すべてのデータが含まれています
|
||||
|
||||
6. **Bluditを更新**: ブラウザでサイトを開きます。Bluditは新しいバージョンを検出し、自動的にアップグレードプロセスを実行します
|
||||
|
||||
7. **サイトを検証**: アップグレード後:
|
||||
- 管理パネルにログイン
|
||||
- コンテンツが正しく表示されることを確認
|
||||
- テーマとプラグインをテスト
|
||||
- 設定を確認
|
||||
|
||||
8. **キャッシュをクリア**: 問題が発生した場合:
|
||||
- ブラウザのキャッシュをクリア
|
||||
- キャッシングプラグインを使用している場合は、そのキャッシュをクリア
|
||||
- エラーがないかサーバーログを確認
|
||||
|
||||
> **注意**: Bluditはすべてのデータを`bl-content/databases/`にJSONファイルとして保存します。このフォルダを無傷に保つ限り、データは安全です。
|
||||
|
||||
## Bluditをサポート
|
||||
|
||||
Bluditはオープンソースで無料ですが、プロジェクトが有用だと感じて開発をサポートしたい場合は、[Patreon](https://www.patreon.com/join/bludit)で貢献できます。私たちの感謝の印として、サポーターはBludit PROを受け取ります。
|
||||
|
||||
好みに応じて、コーヒーやビールを買うための1回限りの寄付も可能です。すべての貢献がBluditの改善とユーザーへの最高の体験提供に役立ちます。
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## ライセンス
|
||||
|
||||
Bluditは[MITライセンス](https://tldrlegal.com/license/mit-license)下のオープンソースソフトウェアです。
|
||||
@@ -0,0 +1,92 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit the Simple, Fast, and Flexible CMS.
|
||||
|
||||
With Bludit, you can build your own website or blog in just seconds. It’s completely free, open-source, and easy to use. Bludit stores content in JSON format, eliminating the need for database installation or configuration. All you need is a web server with PHP support.
|
||||
|
||||
As a Flat-File CMS, Bludit offers unparalleled flexibility and speed. Plus, with support for both Markdown and HTML code, creating and managing content has never been easier.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Plugins](https://plugins.bludit.com)
|
||||
- [Themes](https://themes.bludit.com)
|
||||
- [Documentation](https://docs.bludit.com)
|
||||
- News and announcement on [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms), and [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Talk & Chat on [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Help and Support on [Forum](https://forum.bludit.org)
|
||||
- Bugs reports on [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Webserver with PHP support.
|
||||
- PHP v8.0 or higher version.
|
||||
- PHP [mbstring](http://php.net/manual/en/book.mbstring.php) module for full UTF-8 support.
|
||||
- PHP [gd](http://php.net/manual/en/book.image.php) module for image processing.
|
||||
- PHP [dom](http://php.net/manual/en/book.dom.php) module for DOM manipulation.
|
||||
- PHP [json](http://php.net/manual/en/book.json.php) module for JSON manipulation.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download the latest version from the official page: [Bludit.com](https://www.bludit.com)
|
||||
2. Extract the zip file into a directory, such as `bludit`.
|
||||
3. Upload the `bludit` directory to your web server or hosting.
|
||||
4. Visit your domain (e.g., https://example.com/bludit/).
|
||||
5. Follow the Bludit Installer to set up your website.
|
||||
|
||||
> **Note — running behind Cloudflare, nginx, Apache or another reverse proxy:** Bludit reads the client IP from `REMOTE_ADDR` only. Proxy headers like `X-Forwarded-For` or `CF-Connecting-IP` are **not** trusted at the PHP layer because any client can forge them. If your site sits behind a reverse proxy, configure the webserver to rewrite `REMOTE_ADDR` to the real client IP before PHP sees it — otherwise the login brute-force blocklist will block the proxy itself (locking out every visitor after enough failed logins) and visitor statistics will count all traffic as a single visitor.
|
||||
>
|
||||
> - **Apache** — enable [`mod_remoteip`](https://httpd.apache.org/docs/current/mod/mod_remoteip.html) and list your upstream's IP ranges with `RemoteIPTrustedProxy`. For Cloudflare, use the header `CF-Connecting-IP` and the IP ranges published at [cloudflare.com/ips-v4](https://www.cloudflare.com/ips-v4) and [cloudflare.com/ips-v6](https://www.cloudflare.com/ips-v6).
|
||||
> - **nginx** — use the built-in [`ngx_http_realip_module`](https://nginx.org/en/docs/http/ngx_http_realip_module.html) with `set_real_ip_from` + `real_ip_header`.
|
||||
>
|
||||
> No configuration is needed for direct / localhost / intranet deployments.
|
||||
|
||||
## Quick installation for testing
|
||||
|
||||
You can use PHP Built-in web server (`php -S localhost:8000`) or Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Then open http://localhost:8000
|
||||
|
||||
## Upgrading Bludit
|
||||
|
||||
The following steps are valid for upgrading to any version of Bludit from the same major version. The major version is the first digit in the version number, for example, Bludit v3.x.
|
||||
|
||||
1. **Make a full backup**, no discussion here, entire backup of the files and directories. That means copy ALL files into a new folder.
|
||||
2. **Remember which version of Bludit you are using** for a possible roll-back.
|
||||
3. **Download the latest version** from the [official page](https://www.bludit.com).
|
||||
4. **Extract the zip file**.
|
||||
5. **Replace existing files** with the new files.
|
||||
6. **Clean your browser cache**, and please read the note below.
|
||||
7. **Log into the admin area** and check your settings.
|
||||
8. Done.
|
||||
|
||||
> **Note:** If your website is behind some kind of server cache system (for example, Cloudflare provides one by default) you need to purge the files there, too. It's also a good idea to clear your browser cache. Bludit tries to reload the files with the new ones, but some components like TinyMCE may not reload, and provoke some issues in the UI or throw out JavaScript errors.
|
||||
|
||||
## Support Bludit
|
||||
|
||||
Bludit is open-source and free to use, but if you find the project useful and would like to support its development, you can contribute on [Patreon](https://www.patreon.com/join/bludit). As a token of our appreciation, supporters will receive Bludit PRO.
|
||||
|
||||
If you prefer, you can also make a one-time donation to buy us a coffee or beer. Every contribution helps us continue to improve Bludit and provide the best possible experience for our users.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## License
|
||||
|
||||
Bludit is open source software licensed under the [MIT license](https://tldrlegal.com/license/mit-license).
|
||||
@@ -0,0 +1,85 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - o CMS simples, rápido e flexível.
|
||||
|
||||
Com o Bludit, você pode criar seu próprio site ou blog em segundos. É completamente gratuito, de código aberto e fácil de usar. O Bludit armazena o conteúdo em formato JSON, eliminando a necessidade de instalação ou configuração de banco de dados. Tudo o que você precisa é de um servidor web com suporte a PHP.
|
||||
|
||||
Como um CMS de arquivos planos, o Bludit oferece flexibilidade e velocidade incomparáveis. Além disso, com suporte a código Markdown e HTML, criar e gerenciar conteúdo nunca foi tão fácil.
|
||||
|
||||
## Recursos
|
||||
|
||||
- [Plugins](https://plugins.bludit.com)
|
||||
- [Temas](https://themes.bludit.com)
|
||||
- [Documentação](https://docs.bludit.com)
|
||||
- Notícias e anúncios no [Twitter](https://twitter.com/bludit), [Facebook](https://www.facebook.com/bluditcms) e [Reddit](https://www.reddit.com/r/bludit/)
|
||||
- Conversa e chat no [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Ajuda e suporte no [Fórum](https://forum.bludit.org)
|
||||
- Relatórios de bugs no [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Servidor web com suporte a PHP.
|
||||
- PHP v8.0 ou versão superior.
|
||||
- Módulo PHP [mbstring](http://php.net/manual/en/book.mbstring.php) para suporte completo a UTF-8.
|
||||
- Módulo PHP [gd](http://php.net/manual/en/book.image.php) para processamento de imagens.
|
||||
- Módulo PHP [dom](http://php.net/manual/en/book.dom.php) para manipulação de DOM.
|
||||
- Módulo PHP [json](http://php.net/manual/en/book.json.php) para manipulação de JSON.
|
||||
|
||||
## Instalação
|
||||
|
||||
1. Baixe a versão mais recente da página oficial: [Bludit.com](https://www.bludit.com)
|
||||
2. Extraia o arquivo zip em um diretório, como `bludit`.
|
||||
3. Carregue o diretório `bludit` para o seu servidor web ou hospedagem.
|
||||
4. Visite o seu domínio (ex.: https://example.com/bludit/).
|
||||
5. Siga o instalador do Bludit para configurar o seu site.
|
||||
|
||||
## Instalação rápida para testes
|
||||
|
||||
Você pode usar o servidor web integrado do PHP (`php -S localhost:8000`) ou Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Em seguida, abra http://localhost:8000
|
||||
|
||||
## Atualizar o Bludit
|
||||
|
||||
As etapas a seguir são válidas para atualizar para qualquer versão do Bludit da mesma versão principal. A versão principal é o primeiro dígito no número da versão, por exemplo, Bludit v3.x.
|
||||
|
||||
1. **Faça um backup completo**, sem discussão aqui, backup completo dos arquivos e diretórios. Isso significa copiar TODOS os arquivos para uma nova pasta.
|
||||
2. **Lembre-se de qual versão do Bludit você está usando** para um possível rollback.
|
||||
3. **Baixe a versão mais recente** da [página oficial](https://www.bludit.com).
|
||||
4. **Extraia o arquivo zip**.
|
||||
5. **Substitua os arquivos existentes** pelos novos arquivos.
|
||||
6. **Limpe o cache do seu navegador**, e por favor leia a nota abaixo.
|
||||
7. **Faça login na área de administração** e verifique suas configurações.
|
||||
8. Concluído.
|
||||
|
||||
> **Nota:** Se o seu site estiver atrás de algum tipo de sistema de cache de servidor (por exemplo, Cloudflare fornece um por padrão), você precisa limpar os arquivos lá também. Também é uma boa ideia limpar o cache do seu navegador. O Bludit tenta recarregar os arquivos com os novos, mas alguns componentes como TinyMCE podem não recarregar e provocar problemas na interface do usuário ou gerar erros de JavaScript.
|
||||
|
||||
## Apoie o Bludit
|
||||
|
||||
O Bludit é de código aberto e gratuito para uso, mas se você achar o projeto útil e quiser apoiar seu desenvolvimento, pode contribuir no [Patreon](https://www.patreon.com/join/bludit). Como sinal de nossa apreciação, os apoiadores receberão o Bludit PRO.
|
||||
|
||||
Se preferir, você também pode fazer uma doação única para nos comprar um café ou uma cerveja. Cada contribuição nos ajuda a continuar melhorando o Bludit e fornecer a melhor experiência possível aos nossos usuários.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Licença
|
||||
|
||||
O Bludit é software de código aberto licenciado sob a [licença MIT](https://tldrlegal.com/license/mit-license).
|
||||
@@ -0,0 +1,83 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - простой, быстрый и гибкий CMS.
|
||||
|
||||
С Bludit вы можете создать собственный веб-сайт или блог всего за несколько секунд. Это полностью бесплатный, с открытым исходным кодом и простой в использовании CMS. Bludit хранит контент в формате JSON, что устраняет необходимость установки или настройки базы данных. Все, что вам нужно — это веб-сервер с поддержкой PHP.
|
||||
|
||||
Как Flat-File CMS, Bludit предлагает непревзойденную гибкость и скорость. Кроме того, с поддержкой как Markdown, так и HTML кода, создание и управление контентом стало еще проще.
|
||||
|
||||
## Ресурсы
|
||||
|
||||
- [Плагины](https://plugins.bludit.com)
|
||||
- [Темы](https://themes.bludit.com)
|
||||
- [Документация](https://docs.bludit.com)
|
||||
- Новости и объявления в [Твиттере](https://twitter.com/bludit), [Фейсбуке](https://www.facebook.com/bluditcms) и [Реддите](https://www.reddit.com/r/bludit/)
|
||||
- Общение и чат в [Discord](https://discord.gg/CFaXEdZWds)
|
||||
- Помощь и поддержка на [форуме](https://forum.bludit.org)
|
||||
- Сообщения об ошибках на [Github Issues](https://github.com/bludit/bludit/issues)
|
||||
|
||||
## Требования
|
||||
|
||||
- Веб-сервер с поддержкой PHP.
|
||||
- PHP версии 8.0 или выше.
|
||||
- PHP-модуль [mbstring](http://php.net/manual/en/book.mbstring.php) для полной поддержки UTF-8.
|
||||
- PHP-модуль [gd](http://php.net/manual/en/book.image.php) для обработки изображений.
|
||||
- PHP-модуль [dom](http://php.net/manual/en/book.dom.php) для работы с DOM.
|
||||
- PHP-модуль [json](http://php.net/manual/en/book.json.php) для работы с JSON.
|
||||
|
||||
## Установка
|
||||
|
||||
1. Скачайте последнюю версию с официальной страницы: [Bludit.com](https://www.bludit.com)
|
||||
2. Распакуйте zip-файл в каталог, например `bludit`.
|
||||
3. Загрузите каталог `bludit` на ваш веб-сервер или хостинг.
|
||||
4. Перейдите на ваш домен (например, https://example.com/bludit/).
|
||||
5. Следуйте установщику Bludit для настройки вашего сайта.
|
||||
|
||||
## Быстрая установка для тестирования
|
||||
|
||||
Вы можете использовать встроенный веб-сервер PHP (`php -S localhost:8000`) или Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
Затем откройте http://localhost:8000
|
||||
## Обновление Bludit
|
||||
|
||||
Следующие шаги действительны для обновления до любой версии Bludit той же основной версии. Основная версия - это первая цифра в номере версии, например, Bludit v3.x.
|
||||
|
||||
1. **Сделайте полную резервную копию**, никаких обсуждений, полная резервная копия файлов и каталогов. Это означает копирование ВСЕХ файлов в новую папку.
|
||||
2. **Запомните, какую версию Bludit вы используете** для возможного отката.
|
||||
3. **Загрузите последнюю версию** с [официальной страницы](https://www.bludit.com).
|
||||
4. **Извлеките zip-файл**.
|
||||
5. **Замените существующие файлы** новыми файлами.
|
||||
6. **Очистите кеш браузера**, и пожалуйста, прочитайте примечание ниже.
|
||||
7. **Войдите в административную область** и проверьте свои настройки.
|
||||
8. Готово.
|
||||
|
||||
> **Примечание:** Если ваш веб-сайт находится за какой-либо системой кеширования сервера (например, Cloudflare предоставляет ее по умолчанию), вам также необходимо очистить файлы там. Также рекомендуется очистить кеш браузера. Bludit пытается перезагрузить файлы с новыми, но некоторые компоненты, такие как TinyMCE, могут не перезагрузиться и вызвать проблемы в пользовательском интерфейсе или вызвать ошибки JavaScript.
|
||||
## Поддержать Bludit
|
||||
|
||||
Bludit - это проект с открытым исходным кодом и бесплатный для использования, но если вы считаете его полезным и хотите поддержать развитие, вы можете сделать пожертвование на [Patreon](https://www.patreon.com/join/bludit). В знак нашей благодарности, поддерживающие получат Bludit PRO.
|
||||
|
||||
Если хотите, вы также можете сделать одноразовое пожертвование, чтобы угостить нас кофе или пивом. Каждое пожертвование помогает нам продолжать улучшать Bludit и предоставлять лучший опыт нашим пользователям.
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## Лицензия
|
||||
|
||||
Bludit - это программное обеспечение с открытым исходным кодом, лицензированное по [MIT лицензии](https://tldrlegal.com/license/mit-license).
|
||||
@@ -0,0 +1,83 @@
|
||||
# [Bludit](https://www.bludit.com/)
|
||||
|
||||
[](README.md)
|
||||
[](README.es.md)
|
||||
[](README.ar.md)
|
||||
[](README.zh.md)
|
||||
[](README.fr.md)
|
||||
[](README.de.md)
|
||||
[](README.hi.md)
|
||||
[](README.ja.md)
|
||||
[](README.pt.md)
|
||||
[](README.ru.md)
|
||||
|
||||
Bludit - 简单、快速、灵活的CMS。
|
||||
|
||||
使用Bludit,您可以在几秒钟内构建自己的网站或博客。它完全免费、开源且易于使用。Bludit将内容存储在JSON格式中,消除了安装或配置数据库的需要。您只需要一个支持PHP的Web服务器。
|
||||
|
||||
作为Flat-File CMS,Bludit提供了无与伦比的灵活性和速度。而且,支持Markdown和HTML代码,创建和管理内容从未如此简单。
|
||||
|
||||
## 资源
|
||||
|
||||
- [插件](https://plugins.bludit.com)
|
||||
- [主题](https://themes.bludit.com)
|
||||
- [文档](https://docs.bludit.com)
|
||||
- 新闻和公告在[Twitter](https://twitter.com/bludit)、[Facebook](https://www.facebook.com/bluditcms)和[Reddit](https://www.reddit.com/r/bludit/)上
|
||||
- 对话和聊天在[Discord](https://discord.gg/CFaXEdZWds)上
|
||||
- 帮助和支持在[论坛](https://forum.bludit.org)上
|
||||
- 错误报告在[Github Issues](https://github.com/bludit/bludit/issues)上
|
||||
|
||||
## 要求
|
||||
|
||||
- 支持PHP的Web服务器。
|
||||
- PHP版本8.0或更高。
|
||||
- PHP [mbstring](http://php.net/manual/en/book.mbstring.php)模块用于完整的UTF-8支持。
|
||||
- PHP [gd](http://php.net/manual/en/book.image.php)模块用于图像处理。
|
||||
- PHP [dom](http://php.net/manual/en/book.dom.php)模块用于DOM操作。
|
||||
- PHP [json](http://php.net/manual/en/book.json.php)模块用于JSON操作。
|
||||
|
||||
## 安装
|
||||
|
||||
1. 从官方页面下载最新版本:[Bludit.com](https://www.bludit.com)
|
||||
2. 将zip文件解压到目录中,例如`bludit`。
|
||||
3. 将`bludit`目录上传到您的Web服务器或托管。
|
||||
4. 访问您的域名(例如,https://example.com/bludit/)。
|
||||
5. 按照Bludit安装程序设置您的网站。
|
||||
|
||||
## 测试的快速安装
|
||||
|
||||
您可以使用PHP内置Web服务器(`php -S localhost:8000`)或 Docker:
|
||||
|
||||
```bash
|
||||
docker pull bludit/docker:latest
|
||||
docker run -d --name bludit -p 8000:80 bludit/docker:latest
|
||||
```
|
||||
|
||||
然后打开 http://localhost:8000
|
||||
## 升级 Bludit
|
||||
|
||||
以下步骤适用于从相同主版本升级到 Bludit 的任何版本。主版本是版本号中的第一位数字,例如 Bludit v3.x。
|
||||
|
||||
1. **进行完整备份**,这里不讨论,完整备份文件和目录。这意味着将所有文件复制到一个新文件夹。
|
||||
2. **记住您正在使用的 Bludit 版本**,以便可能的回滚。
|
||||
3. **从[官方页面](https://www.bludit.com)下载最新版本**。
|
||||
4. **解压 zip 文件**。
|
||||
5. **用新文件替换现有文件**。
|
||||
6. **清除浏览器缓存**,请阅读下面的注释。
|
||||
7. **登录管理区域**并检查您的设置。
|
||||
8. 完成。
|
||||
|
||||
> **注意:** 如果您的网站位于某种服务器缓存系统后面(例如,Cloudflare 默认提供一个),您也需要在那里清除文件。清除浏览器缓存也是一个好主意。Bludit 尝试用新文件重新加载文件,但某些组件(如 TinyMCE)可能无法重新加载,并在 UI 中引发一些问题或抛出 JavaScript 错误。
|
||||
## 支持Bludit
|
||||
|
||||
Bludit是开源且免费使用的,但如果您发现该项目有用并希望支持其开发,您可以在[Patreon](https://www.patreon.com/join/bludit)上贡献。作为我们感激的象征,支持者将收到Bludit PRO。
|
||||
|
||||
如果您愿意,您也可以进行一次性捐赠,为我们买杯咖啡或啤酒。每笔贡献都帮助我们继续改进Bludit并为用户提供最佳体验。
|
||||
|
||||
- [PayPal](https://www.paypal.me/bludit/10)
|
||||
- BTC (Bitcoin): [bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph](https://www.blockchain.com/explorer/addresses/btc/bc1qtets5pdj73uyysjpegfh2gar4pfywra4rglcph)
|
||||
- ETH (Ethereum): [0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7](https://www.blockchain.com/explorer/addresses/eth/0x0d7D58D848aA5f175D75Ce4bC746bAC107f331b7)
|
||||
|
||||
## 许可证
|
||||
|
||||
Bludit是根据[MIT许可证](https://tldrlegal.com/license/mit-license)许可的开源软件。
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you believe you have found a security vulnerability in Bludit, please **do
|
||||
not** open a public GitHub issue, post in discussions, or disclose it on social
|
||||
media before it has been addressed.
|
||||
|
||||
Instead, report it privately through GitHub's Private Vulnerability Reporting:
|
||||
|
||||
**https://github.com/bludit/bludit/security/advisories/new**
|
||||
|
||||
This opens a private advisory visible only to the Bludit maintainers.
|
||||
|
||||
When reporting, please include:
|
||||
|
||||
- A clear description of the vulnerability and its impact.
|
||||
- Steps to reproduce, including a proof of concept if possible.
|
||||
- The Bludit version, PHP version, and webserver where you reproduced it.
|
||||
- Any suggested mitigation or patch.
|
||||
|
||||
## What to Expect
|
||||
|
||||
- We aim to acknowledge new reports within **5 business days**.
|
||||
- We will keep you informed as we investigate and work on a fix.
|
||||
- Once a fix is released, we will publish a GitHub Security Advisory crediting
|
||||
the reporter (unless you prefer to remain anonymous) and, where appropriate,
|
||||
request a CVE.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Security fixes are provided for the **latest stable release** of Bludit on the
|
||||
`master` branch. Older versions are not supported — please upgrade before
|
||||
reporting issues against them.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- The Bludit core (`bl-kernel/`, `bl-plugins/` shipped with core, `bl-themes/`
|
||||
shipped with core).
|
||||
- The official admin interface.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- Third-party plugins and themes not maintained in this repository.
|
||||
- Issues that require an already-compromised admin account or server.
|
||||
- Denial of service, rate-limiting, and brute-force concerns — these should be
|
||||
handled at the infrastructure layer (reverse proxy / WAF / Cloudflare).
|
||||
- Self-XSS, missing security headers without a demonstrated impact, and other
|
||||
best-practice findings without a concrete exploit.
|
||||
|
||||
Thank you for helping keep Bludit and its users safe.
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
class dbJSON {
|
||||
|
||||
public $db;
|
||||
public $dbBackup;
|
||||
public $file;
|
||||
public $firstLine;
|
||||
|
||||
// $file, the JSON file.
|
||||
// $firstLine, TRUE if you want to remove the first line, FALSE otherwise
|
||||
function __construct($file, $firstLine=true)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->db = array();
|
||||
$this->dbBackup = array();
|
||||
$this->firstLine = $firstLine;
|
||||
|
||||
if (file_exists($file)) {
|
||||
// Read JSON file
|
||||
$lines = file($file);
|
||||
|
||||
// Remove the first line, the first line is for security reasons
|
||||
if ($firstLine) {
|
||||
unset($lines[0]);
|
||||
}
|
||||
|
||||
// Regenerate the JSON file
|
||||
$implode = implode('', $lines);
|
||||
|
||||
// Unserialize, JSON to Array
|
||||
$array = $this->unserialize($implode);
|
||||
if (empty($array)) {
|
||||
$this->db = array();
|
||||
$this->dbBackup = array();
|
||||
} else {
|
||||
$this->db = $array;
|
||||
$this->dbBackup = $array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function restoreDB()
|
||||
{
|
||||
$this->db = $this->dbBackup;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the number of rows in the database
|
||||
public function count()
|
||||
{
|
||||
return count($this->db);
|
||||
}
|
||||
|
||||
// Returns the value from the field
|
||||
public function getField($field)
|
||||
{
|
||||
if (isset($this->db[$field])) {
|
||||
return $this->db[$field];
|
||||
}
|
||||
if (isset($this->dbFields[$field])) {
|
||||
return $this->dbFields[$field];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Save the JSON file
|
||||
public function save()
|
||||
{
|
||||
$data = '';
|
||||
if ($this->firstLine) {
|
||||
$data = "<?php defined('BLUDIT') or die('Bludit CMS.'); ?>".PHP_EOL;
|
||||
}
|
||||
|
||||
// Serialize database
|
||||
$data .= $this->serialize($this->db);
|
||||
|
||||
// Backup the new database.
|
||||
$this->dbBackup = $this->db;
|
||||
|
||||
// LOCK_EX flag to prevent anyone else writing to the file at the same time.
|
||||
if (file_put_contents($this->file, $data, LOCK_EX)) {
|
||||
return true;
|
||||
} else {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to save the database file.', LOG_TYPE_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a JSON encoded string on success or FALSE on failure
|
||||
private function serialize($data)
|
||||
{
|
||||
if (DEBUG_MODE) {
|
||||
return json_encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
// Returns the value encoded in json in appropriate PHP type
|
||||
private function unserialize($data)
|
||||
{
|
||||
// NULL is returned if the json cannot be decoded
|
||||
$decode = json_decode($data, true);
|
||||
if ($decode===NULL) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error trying to read the JSON file: '.$this->file, LOG_TYPE_ERROR);
|
||||
return false;
|
||||
}
|
||||
return $decode;
|
||||
}
|
||||
|
||||
public function getDB()
|
||||
{
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
// Truncate all the rows
|
||||
public function truncate()
|
||||
{
|
||||
$this->db = array();
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
/*
|
||||
Database structure
|
||||
|
||||
{
|
||||
"videos": {
|
||||
"name": "Videos",
|
||||
"template: "",
|
||||
"description: "",
|
||||
"list": [ "my-page", "second-page" ]
|
||||
},
|
||||
"pets": {
|
||||
"name": "Pets",
|
||||
"template: "",
|
||||
"description: "",
|
||||
"list": [ "cats-and-dogs" ]
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
class dbList extends dbJSON
|
||||
{
|
||||
public $db = array();
|
||||
|
||||
function __construct($file)
|
||||
{
|
||||
parent::__construct($file);
|
||||
}
|
||||
|
||||
public function keys()
|
||||
{
|
||||
return array_keys($this->db);
|
||||
}
|
||||
|
||||
// Returns the list of keys filter by pageNumber
|
||||
// $pageNumber start in 1
|
||||
public function getList($key, $pageNumber, $numberOfItems)
|
||||
{
|
||||
if (!isset($this->db[$key])) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error key does not exist '.$key);
|
||||
return false;
|
||||
}
|
||||
|
||||
// List of keys
|
||||
$list = $this->db[$key]['list'];
|
||||
|
||||
// Returns all the items from the list
|
||||
if ($numberOfItems==-1) {
|
||||
return $list;
|
||||
}
|
||||
|
||||
// The first page number is 1, so the real is 0
|
||||
$realPageNumber = $pageNumber - 1;
|
||||
$chunks = array_chunk($list, $numberOfItems);
|
||||
if (isset($chunks[$realPageNumber])) {
|
||||
return $chunks[$realPageNumber];
|
||||
}
|
||||
|
||||
// Out of index,returns FALSE
|
||||
return false;
|
||||
}
|
||||
|
||||
public function generateKey($name)
|
||||
{
|
||||
global $L;
|
||||
|
||||
$key = Text::cleanUrl($name);
|
||||
if (Text::isEmpty($key)) {
|
||||
$key = $L->g('empty');
|
||||
}
|
||||
while (isset($this->db[$key])) {
|
||||
$key++;
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
// Add a new item to the dblist
|
||||
// $args => 'name', 'template', 'description', 'list'
|
||||
public function add($args)
|
||||
{
|
||||
$key = $this->generateKey($args['name']);
|
||||
|
||||
$this->db[$key]['name'] = Sanitize::removeTags($args['name']);
|
||||
$this->db[$key]['template'] = isset($args['template'])?Sanitize::removeTags($args['template']):'';
|
||||
$this->db[$key]['description'] = isset($args['description'])?Sanitize::removeTags($args['description']):'';
|
||||
$this->db[$key]['list'] = isset($args['list'])?$args['list']:array();
|
||||
|
||||
$this->sortAlphanumeric();
|
||||
$this->save();
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function remove($key)
|
||||
{
|
||||
if (!isset($this->db[$key])) {
|
||||
Log::set(__METHOD__.LOG_SEP.'The key does not exist, key: '.$key);
|
||||
return false;
|
||||
}
|
||||
|
||||
unset($this->db[$key]);
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
// Edit an item to the dblist
|
||||
// $args => 'name', 'oldkey', 'newKey', 'template', 'description'
|
||||
public function edit($args)
|
||||
{
|
||||
if ( isset($this->db[$args['newKey']]) && ($args['newKey']!==$args['oldKey']) ) {
|
||||
Log::set(__METHOD__.LOG_SEP.'The new key already exists. Key: '.$args['newKey'], LOG_TYPE_WARN);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->db[$args['newKey']]['name'] = Sanitize::removeTags($args['name']);
|
||||
$this->db[$args['newKey']]['template'] = isset($args['template'])?Sanitize::removeTags($args['template']):'';
|
||||
$this->db[$args['newKey']]['description'] = isset($args['description'])?Sanitize::removeTags($args['description']):'';
|
||||
$this->db[$args['newKey']]['list'] = $this->db[$args['oldKey']]['list'];
|
||||
|
||||
// Remove the old category
|
||||
if ($args['oldKey'] !== $args['newKey']) {
|
||||
unset( $this->db[$args['oldKey']] );
|
||||
}
|
||||
|
||||
$this->sortAlphanumeric();
|
||||
$this->save();
|
||||
return $args['newKey'];
|
||||
}
|
||||
|
||||
// Sort the categories by "Natural order"
|
||||
public function sortAlphanumeric()
|
||||
{
|
||||
// Sort key alphanumeric strings, a01, a10, b10, c02
|
||||
return ksort($this->db);
|
||||
}
|
||||
|
||||
// Returns the name associated to the key, FALSE if the key doesn't exist
|
||||
public function getName($key)
|
||||
{
|
||||
if (isset($this->db[$key])) {
|
||||
return $this->db[$key]['name'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns an array with key=>name of the list
|
||||
public function getKeyNameArray()
|
||||
{
|
||||
$tmp = array();
|
||||
foreach($this->db as $key=>$fields) {
|
||||
$tmp[$key] = $fields['name'];
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// Returns the number of items in the list
|
||||
public function countItems($key)
|
||||
{
|
||||
if (isset($this->db[$key])) {
|
||||
return count($this->db[$key]['list']);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function exists($key)
|
||||
{
|
||||
return isset( $this->db[$key] );
|
||||
}
|
||||
|
||||
public function existsName($name)
|
||||
{
|
||||
foreach ($this->db as $key=>$fields) {
|
||||
if ($name==$fields['name']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns an array with a portion of the database filtered by key
|
||||
// Returns array( 'key'=>'', 'name'=>'', 'template'=>'', 'description'=>'', list'=>array() )
|
||||
public function getMap($key)
|
||||
{
|
||||
if (isset($this->db[$key])) {
|
||||
$tmp = $this->db[$key];
|
||||
$tmp['key'] = $key;
|
||||
return $tmp;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
class Plugin
|
||||
{
|
||||
|
||||
// (string) directory name, just the name
|
||||
// Ex: sitemap
|
||||
public $directoryName;
|
||||
|
||||
// (string) Absolute database filename and path
|
||||
// Ex: /www/bludit/bl-content/plugins/sitemap/db.php
|
||||
public $filenameDb;
|
||||
|
||||
// (string) Absolute metadata filename and path
|
||||
// Ex: /www/bludit/bl-plugins/sitemap/metadata.json
|
||||
public $filenameMetadata;
|
||||
|
||||
// (array) Plugin metadata
|
||||
// Ex: array('author'=>'',...., 'notes'=>'')
|
||||
public $metadata;
|
||||
|
||||
// (string) Class name
|
||||
// Ex: pluginSitemap
|
||||
public $className;
|
||||
|
||||
// (array) Database unserialized
|
||||
public $db;
|
||||
|
||||
// (array) Database fields, only for initialize
|
||||
public $dbFields;
|
||||
|
||||
// (boolean) Enable or disable default Save and Cancel button on plugin settings
|
||||
public $formButtons;
|
||||
|
||||
// (array) List of custom hooks
|
||||
public $customHooks;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->dbFields = array();
|
||||
$this->customHooks = array();
|
||||
|
||||
$reflector = new ReflectionClass(get_class($this));
|
||||
|
||||
// Directory name
|
||||
$this->directoryName = basename(dirname($reflector->getFileName()));
|
||||
|
||||
// Class Name
|
||||
$this->className = $reflector->getName();
|
||||
|
||||
$this->formButtons = true;
|
||||
|
||||
// Call the method init() from the children
|
||||
$this->init();
|
||||
|
||||
// Init empty database with default values
|
||||
$this->db = $this->dbFields;
|
||||
|
||||
$this->filenameDb = PATH_PLUGINS_DATABASES . $this->directoryName . DS . 'db.php';
|
||||
|
||||
// --- Metadata ---
|
||||
$this->filenameMetadata = PATH_PLUGINS . $this->directoryName() . DS . 'metadata.json';
|
||||
$metadataString = file_get_contents($this->filenameMetadata);
|
||||
$this->metadata = json_decode($metadataString, true);
|
||||
|
||||
// If the plugin is installed then get the database
|
||||
if ($this->installed()) {
|
||||
$Tmp = new dbJSON($this->filenameDb);
|
||||
$this->db = $Tmp->db;
|
||||
$this->prepare();
|
||||
}
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$tmp = new dbJSON($this->filenameDb);
|
||||
$tmp->db = $this->db;
|
||||
return $tmp->save();
|
||||
}
|
||||
|
||||
public function includeCSS($filename)
|
||||
{
|
||||
return '<link rel="stylesheet" type="text/css" href="' . $this->domainPath() . 'css/' . $filename . '?version=' . BLUDIT_VERSION . '">' . PHP_EOL;
|
||||
}
|
||||
|
||||
public function includeJS($filename)
|
||||
{
|
||||
return '<script charset="utf-8" src="' . $this->domainPath() . 'js/' . $filename . '?version=' . BLUDIT_VERSION . '"></script>' . PHP_EOL;
|
||||
}
|
||||
|
||||
// Returns absolute URL and path of the plugin directory
|
||||
// This function helps to include CSS or Javascript files with absolute URL
|
||||
public function domainPath()
|
||||
{
|
||||
return DOMAIN_PLUGINS . $this->directoryName . '/';
|
||||
}
|
||||
|
||||
// Returns relative path of the plugin directory
|
||||
// This function helps to include CSS or Javascript files with relative URL
|
||||
public function htmlPath()
|
||||
{
|
||||
return HTML_PATH_PLUGINS . $this->directoryName . '/';
|
||||
}
|
||||
|
||||
// Returns absolute path of the plugin directory
|
||||
// This function helps to include PHP libraries or some file at server level
|
||||
public function phpPath()
|
||||
{
|
||||
return PATH_PLUGINS . $this->directoryName . DS;
|
||||
}
|
||||
|
||||
public function phpPathDB()
|
||||
{
|
||||
return PATH_PLUGINS_DATABASES . $this->directoryName . DS;
|
||||
}
|
||||
|
||||
// Returns the value of the key from the metadata of the plugin, FALSE if the key doesn't exist
|
||||
public function getMetadata($key)
|
||||
{
|
||||
if (isset($this->metadata[$key])) {
|
||||
return $this->metadata[$key];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set a key / value on the metadata of the plugin
|
||||
public function setMetadata($key, $value)
|
||||
{
|
||||
$this->metadata[$key] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the value of the field from the database
|
||||
// (string) $field
|
||||
// (boolean) $html, TRUE returns the value sanitized, FALSE unsanitized
|
||||
public function getValue($field, $html = true)
|
||||
{
|
||||
if (isset($this->db[$field])) {
|
||||
if ($html) {
|
||||
return $this->db[$field];
|
||||
} else {
|
||||
return Sanitize::htmlDecode($this->db[$field]);
|
||||
}
|
||||
}
|
||||
return $this->dbFields[$field];
|
||||
}
|
||||
|
||||
public function label()
|
||||
{
|
||||
return $this->getMetadata('label');
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->getMetadata('name');
|
||||
}
|
||||
|
||||
public function description()
|
||||
{
|
||||
return $this->getMetadata('description');
|
||||
}
|
||||
|
||||
public function author()
|
||||
{
|
||||
return $this->getMetadata('author');
|
||||
}
|
||||
|
||||
public function email()
|
||||
{
|
||||
return $this->getMetadata('email');
|
||||
}
|
||||
|
||||
public function website()
|
||||
{
|
||||
return $this->getMetadata('website');
|
||||
}
|
||||
|
||||
public function position()
|
||||
{
|
||||
return $this->getValue('position');
|
||||
}
|
||||
|
||||
public function version()
|
||||
{
|
||||
return $this->getMetadata('version');
|
||||
}
|
||||
|
||||
public function releaseDate()
|
||||
{
|
||||
return $this->getMetadata('releaseDate');
|
||||
}
|
||||
|
||||
public function className()
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
public function formButtons()
|
||||
{
|
||||
return $this->formButtons;
|
||||
}
|
||||
|
||||
public function isCompatible()
|
||||
{
|
||||
$bluditRoot = explode('.', BLUDIT_VERSION);
|
||||
$compatible = explode(',', $this->getMetadata('compatible'));
|
||||
foreach ($compatible as $version) {
|
||||
$root = explode('.', $version);
|
||||
if ($root[0] == $bluditRoot[0] && $root[1] == $bluditRoot[1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function directoryName()
|
||||
{
|
||||
return $this->directoryName;
|
||||
}
|
||||
|
||||
// Return TRUE if the installation success, otherwise FALSE.
|
||||
public function install($position = 1)
|
||||
{
|
||||
if ($this->installed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create workspace
|
||||
$workspace = $this->workspace();
|
||||
mkdir($workspace, DIR_PERMISSIONS, true);
|
||||
|
||||
// Create plugin directory for the database
|
||||
mkdir(PATH_PLUGINS_DATABASES . $this->directoryName, DIR_PERMISSIONS, true);
|
||||
|
||||
$this->dbFields['position'] = $position;
|
||||
// Sanitize default values to store in the file
|
||||
foreach ($this->dbFields as $key => $value) {
|
||||
$value = Sanitize::html($value);
|
||||
settype($value, gettype($this->dbFields[$key]));
|
||||
$this->db[$key] = $value;
|
||||
}
|
||||
|
||||
// Create the database
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
{
|
||||
// Delete database
|
||||
$path = PATH_PLUGINS_DATABASES . $this->directoryName;
|
||||
Filesystem::deleteRecursive($path);
|
||||
|
||||
// Delete workspace
|
||||
$workspace = $this->workspace();
|
||||
Filesystem::deleteRecursive($workspace);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns TRUE if the plugin is installed
|
||||
// This function just check if the database of the plugin is created
|
||||
public function installed()
|
||||
{
|
||||
return file_exists($this->filenameDb);
|
||||
}
|
||||
|
||||
public function workspace()
|
||||
{
|
||||
return PATH_WORKSPACES . $this->directoryName . DS;
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
// This method is used on children classes
|
||||
// The user can define his own field of the database
|
||||
}
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
// This method is used on children classes
|
||||
// The user can prepare the plugin, when it is installed
|
||||
}
|
||||
|
||||
public function post()
|
||||
{
|
||||
$args = $_POST;
|
||||
foreach ($this->dbFields as $field => $value) {
|
||||
if (isset($args[$field])) {
|
||||
$finalValue = Sanitize::html($args[$field]);
|
||||
if ($finalValue === 'false') {
|
||||
$finalValue = false;
|
||||
} elseif ($finalValue === 'true') {
|
||||
$finalValue = true;
|
||||
}
|
||||
settype($finalValue, gettype($value));
|
||||
$this->db[$field] = $finalValue;
|
||||
}
|
||||
}
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function type()
|
||||
{
|
||||
return $this->getMetadata('type');
|
||||
}
|
||||
|
||||
public function setField($field, $value)
|
||||
{
|
||||
$this->db[$field] = Sanitize::html($value);
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function setPosition($position)
|
||||
{
|
||||
return $this->setField('position', $position);
|
||||
}
|
||||
|
||||
// Returns the parameters after the URI, FALSE if the URI doesn't match with the webhook
|
||||
// Example: https://www.mybludit.com/api/foo/bar
|
||||
public function webhook($URI = false, $returnsAfterURI = false, $fixed = true)
|
||||
{
|
||||
global $url;
|
||||
|
||||
if (empty($URI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check URI start with the webhook
|
||||
$startString = HTML_PATH_ROOT . $URI;
|
||||
$URI = $url->uri();
|
||||
$length = mb_strlen($startString, CHARSET);
|
||||
if (mb_substr($URI, 0, $length) != $startString) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$afterURI = mb_substr($URI, $length);
|
||||
if (!empty($afterURI)) {
|
||||
if ($fixed) {
|
||||
return false;
|
||||
}
|
||||
if ($afterURI[0] != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($returnsAfterURI) {
|
||||
return $afterURI;
|
||||
}
|
||||
|
||||
Log::set(__METHOD__ . LOG_SEP . 'Webhook requested.');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] = $L->g('About') . ' - ' . $layout['title'];
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
activatePlugin('pluginAPI');
|
||||
$apiURL = DOMAIN_BASE.'api/';
|
||||
$pluginAPI = getPlugin('pluginAPI');
|
||||
$apiToken = $pluginAPI->getToken();
|
||||
$username = $login->username();
|
||||
$admin = new User($username);
|
||||
$authToken = $admin->tokenAuth();
|
||||
$output = array(
|
||||
'apiURL'=>$apiURL,
|
||||
'username'=>$username,
|
||||
'apiToken'=>$apiToken,
|
||||
'authToken'=>$authToken
|
||||
);
|
||||
exit(json_encode($output));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Categories');
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
$plugin = false;
|
||||
$pluginClassName = $layout['parameters'];
|
||||
|
||||
// Check if the plugin exists
|
||||
if (isset($plugins['all'][$pluginClassName])) {
|
||||
$plugin = $plugins['all'][$pluginClassName];
|
||||
} else {
|
||||
Redirect::page('plugins');
|
||||
}
|
||||
|
||||
// Check if the plugin has the method form()
|
||||
if (!method_exists($plugin, 'form')) {
|
||||
Redirect::page('plugins');
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Add to syslog
|
||||
$syslog->add(array(
|
||||
'dictionaryKey'=>'plugin-configured',
|
||||
'notes'=>$plugin->name()
|
||||
));
|
||||
|
||||
// Call the method post of the plugin
|
||||
$plugin->post();
|
||||
Alert::set( $L->g('The changes have been saved') );
|
||||
Redirect::page('configure-plugin/'.$plugin->className());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] = $L->g('Plugin').' - '.$plugin->name().' - '.$layout['title'];
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin', 'editor', 'author'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// Returns the content belongs to the current user if the user has the role Editor
|
||||
function filterContentOwner($list) {
|
||||
global $login;
|
||||
global $pages;
|
||||
$tmp = array();
|
||||
foreach ($list as $pageKey) {
|
||||
if ($pages->db[$pageKey]['username']==$login->username()) {
|
||||
array_push($tmp, $pageKey);
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
$published = $pages->getList($url->pageNumber(), ITEMS_PER_PAGE_ADMIN);
|
||||
$drafts = $pages->getDraftDB(true);
|
||||
$scheduled = $pages->getScheduledDB(true);
|
||||
$static = $pages->getStaticDB(true);
|
||||
$sticky = $pages->getStickyDB(true);
|
||||
$autosave = $pages->getAutosaveDB(true);
|
||||
|
||||
// If the user is an Author filter the content he/she can edit
|
||||
if (checkRole(array('author'), false)) {
|
||||
$published = filterContentOwner($published);
|
||||
$drafts = filterContentOwner($drafts);
|
||||
$scheduled = filterContentOwner($scheduled);
|
||||
$static = filterContentOwner($static);
|
||||
$sticky = filterContentOwner($sticky);
|
||||
}
|
||||
|
||||
// Check if out of range the pageNumber
|
||||
if (empty($published) && $url->pageNumber()>1) {
|
||||
Redirect::page('content');
|
||||
}
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Manage content');
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
function updateBludit() {
|
||||
global $site;
|
||||
global $syslog;
|
||||
|
||||
// New installation
|
||||
if ($site->currentBuild()==0) {
|
||||
$site->set(array('currentBuild'=>BLUDIT_BUILD));
|
||||
}
|
||||
|
||||
// Check if Bludit need to be updated
|
||||
if ( ($site->currentBuild() < BLUDIT_BUILD) || isset($_GET['update']) ) {
|
||||
Log::set('UPDATE SYSTEM - Starting.');
|
||||
|
||||
// Updates only for version less than Bludit v3.0 rc-3
|
||||
if ($site->currentBuild()<='20180910') {
|
||||
@mkdir(PATH_WORKSPACES, DIR_PERMISSIONS, true);
|
||||
$plugins = array('pluginVisitsStats', 'pluginRSS', 'pluginSitemap', 'pluginTimeMachineX', 'pluginBackup');
|
||||
foreach ($plugins as $plugin) {
|
||||
if (pluginActivated($plugin)) {
|
||||
Log::set('UPDATE SYSTEM - Re-enable plugin: '.$plugin);
|
||||
deactivatePlugin($plugin);
|
||||
activatePlugin($plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates only for version less than Bludit v3.1
|
||||
if ($site->currentBuild()<='20180921') {
|
||||
@mkdir(PATH_UPLOADS_PAGES, DIR_PERMISSIONS, true);
|
||||
$site->set(array('imageRelativeToAbsolute'=>true, 'imageRestrict'=>false));
|
||||
}
|
||||
|
||||
// Set the current build number
|
||||
$site->set(array('currentBuild'=>BLUDIT_BUILD));
|
||||
Log::set('UPDATE SYSTEM - Finished.');
|
||||
|
||||
// Add to syslog
|
||||
$syslog->add(array(
|
||||
'dictionaryKey'=>'system-updated',
|
||||
'notes'=>'Bludit v'.BLUDIT_VERSION
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Try update Bludit
|
||||
updateBludit();
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Dashboard');
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// This function is used on the VIEW to show the tables
|
||||
function printTable($title, $array) {
|
||||
echo '<h2 class="mb-2 mt-4">'.$title.'</h2>';
|
||||
echo '<table class="table table-striped mt-3">
|
||||
<tbody>
|
||||
';
|
||||
|
||||
foreach ($array as $key=>$value) {
|
||||
if($value===false) { $value = 'false'; }
|
||||
elseif($value===true) { $value = 'true'; }
|
||||
echo '<tr>';
|
||||
echo '<td>'.$key.'</td>';
|
||||
if (is_array($value)) {
|
||||
echo '<td>'.json_encode($value).'</td>';
|
||||
} else {
|
||||
echo '<td>'.Sanitize::html($value).'</td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
$layout['title'] .= ' - '.$L->g('Developers');
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if ($_POST['action']=='delete') {
|
||||
deleteCategory($_POST);
|
||||
} elseif ($_POST['action']=='edit') {
|
||||
editCategory($_POST);
|
||||
}
|
||||
|
||||
Redirect::page('categories');
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
$categoryKey = $layout['parameters'];
|
||||
|
||||
if (!$categories->exists($categoryKey)) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to get the category: '.$categoryKey);
|
||||
Redirect::page('categories');
|
||||
}
|
||||
|
||||
$categoryMap = $categories->getMap($categoryKey);
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Edit Category').' [ '.$categoryMap['name'] . ' ] ';
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
if (checkRole(array('author'), false)) {
|
||||
try {
|
||||
$pageKey = isset($_POST['key']) ? $_POST['key'] : $layout['parameters'];
|
||||
$page = new Page($pageKey);
|
||||
} catch (Exception $e) {
|
||||
Alert::set($L->g('You do not have sufficient permissions'));
|
||||
Redirect::page('dashboard');
|
||||
}
|
||||
|
||||
if ($page->username()!==$login->username()) {
|
||||
// Add to syslog
|
||||
$syslog->add(array(
|
||||
'dictionaryKey'=>'access-denied',
|
||||
'notes'=>$login->username()
|
||||
));
|
||||
|
||||
Alert::set($L->g('You do not have sufficient permissions'));
|
||||
Redirect::page('dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if ($_POST['type']==='delete') {
|
||||
// Get the page type before deleting to redirect to the correct tab
|
||||
if (empty($_POST['tab'])) {
|
||||
try {
|
||||
$pageToDelete = new Page($_POST['key']);
|
||||
$pageType = $pageToDelete->type();
|
||||
if ($pageType === 'autosave') {
|
||||
$_POST['tab'] = 'autosave';
|
||||
} elseif ($pageType === 'draft') {
|
||||
$_POST['tab'] = 'draft';
|
||||
} elseif ($pageType === 'scheduled') {
|
||||
$_POST['tab'] = 'scheduled';
|
||||
} elseif ($pageType === 'static') {
|
||||
$_POST['tab'] = 'static';
|
||||
} else {
|
||||
$_POST['tab'] = 'pages';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$_POST['tab'] = 'pages';
|
||||
}
|
||||
}
|
||||
|
||||
if (deletePage($_POST['key'])) {
|
||||
Alert::set( $L->g('The changes have been saved') );
|
||||
}
|
||||
} else {
|
||||
$key = editPage($_POST);
|
||||
if ($key!==false) {
|
||||
Alert::set( $L->g('The changes have been saved') );
|
||||
Redirect::page('edit-content/'.$key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_POST['tab'])) {
|
||||
$tab = preg_replace('/[^a-zA-Z0-9_-]/', '', $_POST['tab']);
|
||||
Redirect::page('content#'.$tab);
|
||||
}
|
||||
Redirect::page('content');
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
try {
|
||||
$pageKey = $layout['parameters'];
|
||||
$page = new Page($pageKey);
|
||||
} catch (Exception $e) {
|
||||
Log::set(__METHOD__.LOG_SEP.'Error occurred when trying to get the page: '.$pageKey, LOG_TYPE_ERROR);
|
||||
Redirect::page('content');
|
||||
}
|
||||
|
||||
// Images prefix directory
|
||||
define('PAGE_IMAGES_KEY', $page->uuid());
|
||||
|
||||
// Images and thubmnails directories
|
||||
if (IMAGE_RESTRICT) {
|
||||
define('PAGE_IMAGES_DIRECTORY', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : HTML_PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/'));
|
||||
define('PAGE_IMAGES_URL', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : DOMAIN_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/'));
|
||||
define('PAGE_THUMBNAILS_DIRECTORY', PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS.'thumbnails'.DS);
|
||||
define('PAGE_THUMBNAILS_HTML', HTML_PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/thumbnails/');
|
||||
define('PAGE_THUMBNAILS_URL', DOMAIN_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/thumbnails/');
|
||||
} else {
|
||||
define('PAGE_IMAGES_DIRECTORY', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : HTML_PATH_UPLOADS));
|
||||
define('PAGE_IMAGES_URL', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : DOMAIN_UPLOADS));
|
||||
define('PAGE_THUMBNAILS_DIRECTORY', PATH_UPLOADS_THUMBNAILS);
|
||||
define('PAGE_THUMBNAILS_HTML', HTML_PATH_UPLOADS_THUMBNAILS);
|
||||
define('PAGE_THUMBNAILS_URL', DOMAIN_UPLOADS_THUMBNAILS);
|
||||
}
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Edit content').' - '.$page->title();
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Prevent non-administrators to change other users
|
||||
if ($login->role()!=='admin') {
|
||||
$_POST['username'] = $login->username();
|
||||
unset($_POST['role']);
|
||||
}
|
||||
|
||||
if (isset($_POST['deleteUserAndDeleteContent']) && ($login->role()==='admin')) {
|
||||
$_POST['deleteContent'] = true;
|
||||
deleteUser($_POST);
|
||||
} elseif (isset($_POST['deleteUserAndKeepContent']) && ($login->role()==='admin')) {
|
||||
$_POST['deleteContent'] = false;
|
||||
deleteUser($_POST);
|
||||
} elseif (isset($_POST['disableUser']) && ($login->role()==='admin')) {
|
||||
disableUser(array('username'=>$_POST['username']));
|
||||
} else {
|
||||
editUser($_POST);
|
||||
}
|
||||
|
||||
Alert::set($L->g('The changes have been saved'));
|
||||
|
||||
if ($login->role()==='admin') {
|
||||
Redirect::page('users');
|
||||
}
|
||||
Redirect::page('edit-user/'.$login->username());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
$username = $layout['parameters'];
|
||||
|
||||
// Prevent non-administrators to change other users
|
||||
if ($login->role()!=='admin') {
|
||||
$username = $login->username();
|
||||
}
|
||||
|
||||
try {
|
||||
$user = new User($username);
|
||||
} catch (Exception $e) {
|
||||
Redirect::page('users');
|
||||
}
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] = $L->g('Edit user').' - '.$layout['title'];
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
$pluginClassName = $layout['parameters'];
|
||||
if (!activatePlugin($pluginClassName)) {
|
||||
Log::set('Fail when try to activate the plugin.', LOG_TYPE_ERROR);
|
||||
}
|
||||
|
||||
if (isset($plugins['all'][$pluginClassName])) {
|
||||
$plugin = $plugins['all'][$pluginClassName];
|
||||
} else {
|
||||
Redirect::page('plugins');
|
||||
}
|
||||
|
||||
if (method_exists($plugin, 'form')) {
|
||||
Redirect::page('configure-plugin/'.$pluginClassName);
|
||||
}
|
||||
|
||||
Redirect::page('plugins#'.$pluginClassName);
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
$themeDirectory = $layout['parameters'];
|
||||
|
||||
// Activate theme
|
||||
activateTheme($themeDirectory);
|
||||
|
||||
// Redirect
|
||||
Redirect::page('themes');
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
function checkLogin($args)
|
||||
{
|
||||
global $security;
|
||||
global $login;
|
||||
global $L;
|
||||
|
||||
if ($security->isBlocked()) {
|
||||
Alert::set($L->g('IP address has been blocked').'<br>'.$L->g('Try again in a few minutes'), ALERT_STATUS_FAIL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($login->verifyUser($_POST['username'], $_POST['password'])) {
|
||||
if (isset($_POST['remember'])) {
|
||||
$login->setRememberMe($_POST['username']);
|
||||
}
|
||||
// Renew the token. This token will be the same inside the session for multiple forms.
|
||||
$security->generateTokenCSRF();
|
||||
|
||||
if (isset($_GET['enableAPI'])) {
|
||||
Redirect::page('api');
|
||||
}
|
||||
Redirect::page('dashboard');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bruteforce protection, add IP to the blacklist
|
||||
$security->addToBlacklist();
|
||||
|
||||
// Create alert
|
||||
Alert::set($L->g('Username or password incorrect'), ALERT_STATUS_FAIL);
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkRememberMe()
|
||||
{
|
||||
global $security;
|
||||
global $login;
|
||||
|
||||
if ($security->isBlocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($login->verifyUserByRemember()) {
|
||||
$security->generateTokenCSRF();
|
||||
Redirect::page('dashboard');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD']!=='POST') {
|
||||
checkRememberMe();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD']=='POST') {
|
||||
checkLogin($_POST);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
if ($login->logout()) {
|
||||
Redirect::admin();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (createCategory($_POST)) {
|
||||
Redirect::page('categories');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('New category');
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin', 'editor', 'author'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
createPage($_POST);
|
||||
Redirect::page('content');
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// UUID of the page is need it for autosave and media manager
|
||||
$uuid = $pages->generateUUID();
|
||||
|
||||
// Images prefix directory
|
||||
define('PAGE_IMAGES_KEY', $uuid);
|
||||
|
||||
// Images and thubmnails directories
|
||||
if (IMAGE_RESTRICT) {
|
||||
define('PAGE_IMAGES_DIRECTORY', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : HTML_PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/'));
|
||||
define('PAGE_IMAGES_URL', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : DOMAIN_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/'));
|
||||
define('PAGE_THUMBNAILS_DIRECTORY', PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS.'thumbnails'.DS);
|
||||
define('PAGE_THUMBNAILS_HTML', HTML_PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/thumbnails/');
|
||||
define('PAGE_THUMBNAILS_URL', DOMAIN_UPLOADS_PAGES.PAGE_IMAGES_KEY.'/thumbnails/');
|
||||
} else {
|
||||
define('PAGE_IMAGES_DIRECTORY', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : HTML_PATH_UPLOADS));
|
||||
define('PAGE_IMAGES_URL', (IMAGE_RELATIVE_TO_ABSOLUTE? '' : DOMAIN_UPLOADS));
|
||||
define('PAGE_THUMBNAILS_DIRECTORY', PATH_UPLOADS_THUMBNAILS);
|
||||
define('PAGE_THUMBNAILS_HTML', HTML_PATH_UPLOADS_THUMBNAILS);
|
||||
define('PAGE_THUMBNAILS_URL', DOMAIN_UPLOADS_THUMBNAILS);
|
||||
}
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] = $L->g('New content').' - '.$layout['title'];
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (createUser($_POST)) {
|
||||
Redirect::page('users');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Add a new user');
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
changePluginsPosition(explode(',',$_POST['plugin-list']));
|
||||
Redirect::page('plugins-position');
|
||||
}
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Plugins');
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Plugins');
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
editSettings($_POST);
|
||||
Redirect::page('settings');
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Advanced Settings');
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
$themes = buildThemes();
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Themes');
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
$pluginClassName = $layout['parameters'];
|
||||
deactivatePlugin($pluginClassName);
|
||||
Redirect::page('plugins');
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Prevent non-administrators to change other users
|
||||
$username = $_POST['username'];
|
||||
if ($login->role()!=='admin') {
|
||||
$username = $login->username();
|
||||
}
|
||||
|
||||
if (changeUserPassword(array(
|
||||
'username'=>$username,
|
||||
'newPassword'=>$_POST['newPassword'],
|
||||
'confirmPassword'=>$_POST['confirmPassword']
|
||||
))) {
|
||||
if ($login->role()==='admin') {
|
||||
Redirect::page('users');
|
||||
}
|
||||
Redirect::page('edit-user/'.$login->username());
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Prevent non-administrators to change other users
|
||||
if ($login->role()!=='admin') {
|
||||
$layout['parameters'] = $login->username();
|
||||
}
|
||||
|
||||
try {
|
||||
$username = $layout['parameters'];
|
||||
$user = new User($username);
|
||||
} catch (Exception $e) {
|
||||
Redirect::page('users');
|
||||
}
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] = $L->g('Change password').' - '.$layout['title'];
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Check role
|
||||
// ============================================================================
|
||||
|
||||
checkRole(array('admin'));
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
|
||||
{
|
||||
$site->set($_POST);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
|
||||
// Title of the page
|
||||
$layout['title'] .= ' - '.$L->g('Users');
|
||||
@@ -0,0 +1,195 @@
|
||||
a {
|
||||
color: var(--primary-blue, #1e88e5);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--primary-blue-dark, #1565c0);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bg-success {
|
||||
background-color: #8BC34A!important;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary-blue, #1e88e5)!important;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #D40000!important;
|
||||
}
|
||||
a.text-danger:focus,
|
||||
a.text-danger:hover {
|
||||
color: #790000!important;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
font-weight: var(--font-weight-medium, 550);
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
padding: 12px 24px;
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--primary-blue, #0078D4);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--primary-blue-dark, #005A9E);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--color-secondary, #64748B);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--color-secondary-dark, #475569);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-light {
|
||||
background-color: var(--bg-light, #f8f9fa);
|
||||
border: 2px solid var(--border-color, #e2e8f0);
|
||||
font-weight: var(--font-weight-medium, 550);
|
||||
}
|
||||
|
||||
.btn-light:hover {
|
||||
background-color: var(--bg-sidebar, #F1F5F9);
|
||||
border-color: var(--border-light, #cbd5e1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: var(--color-danger, #DC2626);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: var(--color-danger-dark, #B91C1C);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: var(--color-success, #16A34A);
|
||||
border: none;
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: var(--color-success-dark, #15803D);
|
||||
border: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 8px 16px;
|
||||
font-size: var(--font-size-sm, 0.925rem);
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: 16px 32px;
|
||||
font-size: var(--font-size-lg, 1.08rem);
|
||||
}
|
||||
|
||||
.btn-light.focus, .btn-light:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn.focus, .btn:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Form */
|
||||
.form-control {
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
font-weight: var(--font-weight-normal, 450);
|
||||
padding: 12px 16px;
|
||||
border: 2px solid var(--border-color, #e2e8f0);
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
color: var(--text-primary, #0F172A);
|
||||
margin-bottom: 8px;
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: var(--radius-md, 8px);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--border-color, #e2e8f0);
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
font-size: var(--font-size-lg, 1.08rem);
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.table-striped tbody tr:nth-of-type(odd) {
|
||||
background-color: var(--bg-warm, #faf8f5);
|
||||
}
|
||||
|
||||
.table-striped tbody tr:hover {
|
||||
background-color: var(--bg-warm-card, #f7f5f2);
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
font-size: var(--font-size-xs, 0.8rem);
|
||||
text-transform: uppercase!important;
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
color: var(--text-secondary, #475569);
|
||||
letter-spacing: 0.8px;
|
||||
border-bottom: 2px solid var(--border-color, #e2e8f0);
|
||||
}
|
||||
|
||||
.table td {
|
||||
font-size: var(--font-size-base, 0.945rem);
|
||||
font-weight: var(--font-weight-normal, 450);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: var(--text-primary, #0F172A);
|
||||
font-weight: var(--font-weight-bold, 750);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
h1 { font-size: var(--font-size-3xl, 2.25rem); }
|
||||
h2 { font-size: var(--font-size-2xl, 1.75rem); }
|
||||
h3 { font-size: var(--font-size-xl, 1.4rem); }
|
||||
h4 { font-size: var(--font-size-lg, 1.08rem); }
|
||||
h5 { font-size: var(--font-size-base, 0.945rem); }
|
||||
h6 { font-size: var(--font-size-sm, 0.925rem); }
|
||||
|
||||
/* Badge */
|
||||
.badge {
|
||||
font-size: var(--font-size-xs, 0.8rem);
|
||||
font-weight: var(--font-weight-semibold, 650);
|
||||
padding: 6px 12px;
|
||||
border-radius: var(--radius-sm, 4px);
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background: var(--primary-blue, #0078D4);
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
:root {
|
||||
/* Dynamic font sizing */
|
||||
--font-size-xs: 0.72rem;
|
||||
--font-size-sm: 0.833rem;
|
||||
--font-size-base: 0.945rem;
|
||||
--font-size-lg: 1.08rem;
|
||||
--font-size-xl: 1.26rem;
|
||||
--font-size-2xl: 1.575rem;
|
||||
--font-size-3xl: 2.025rem;
|
||||
|
||||
/* Font weights */
|
||||
--font-weight-normal: 450;
|
||||
--font-weight-medium: 550;
|
||||
--font-weight-semibold: 650;
|
||||
--font-weight-bold: 750;
|
||||
|
||||
/* Royal Azure Solid Blue colors */
|
||||
--primary-blue: #0078D4;
|
||||
--primary-blue-dark: #005A9E;
|
||||
--primary-blue-darker: #004578;
|
||||
--primary-gradient: #0078D4;
|
||||
|
||||
/* UI colors */
|
||||
--bg-main: #F8FAFC;
|
||||
--bg-sidebar: #F1F5F9;
|
||||
--text-primary: #1E293B;
|
||||
--text-secondary: #475569;
|
||||
--text-muted: #94A3B8;
|
||||
--border-color: #E2E8F0;
|
||||
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
|
||||
/* Warm neutral accents */
|
||||
--bg-warm: #faf8f5;
|
||||
--bg-warm-card: #f7f5f2;
|
||||
--border-warm: #e8e6e3;
|
||||
|
||||
/* Radius scale */
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
|
||||
/* Semantic colors */
|
||||
--color-info: #0078D4;
|
||||
--color-danger: #DC2626;
|
||||
--color-danger-dark: #B91C1C;
|
||||
--color-success: #16A34A;
|
||||
--color-success-dark: #15803D;
|
||||
--color-secondary: #64748B;
|
||||
--color-secondary-dark: #475569;
|
||||
--bg-card: #FFFFFF;
|
||||
--bg-light: #f8f9fa;
|
||||
--border-light: #cbd5e1;
|
||||
--primary-blue-hover-bg: rgba(0, 120, 212, 0.06);
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
font-size: var(--font-size-base);
|
||||
background: var(--bg-main);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg-main);
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
font-weight: var(--font-weight-normal);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* Prevent events in iframes */
|
||||
/* iframe{
|
||||
pointer-events: none;
|
||||
} */
|
||||
|
||||
/*
|
||||
ICONS
|
||||
*/
|
||||
.fa {
|
||||
margin-right: .5rem !important;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
SIDEBAR
|
||||
*/
|
||||
|
||||
div.sidebar {
|
||||
background: var(--bg-sidebar);
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-left: 1px solid var(--border-color);
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
color: var(--text-primary);
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-normal);
|
||||
transition: color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a:hover {
|
||||
color: var(--primary-blue);
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
div.sidebar .nav-item a.active,
|
||||
div.sidebar .nav-item a:focus {
|
||||
color: var(--primary-blue);
|
||||
}
|
||||
|
||||
div.sidebar .nav-item h4 {
|
||||
font-size: var(--font-size-xs);
|
||||
text-transform: uppercase;
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin-top: 15px;
|
||||
padding-left: 5px;
|
||||
color: var(--text-secondary);
|
||||
letter-spacing: 0.8px;
|
||||
}
|
||||
|
||||
/*
|
||||
QUICK SEARCH - SPOTLIGHT STYLE
|
||||
*/
|
||||
|
||||
/* Trigger Button */
|
||||
.quick-search-trigger {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.quick-search-trigger:hover {
|
||||
border-color: var(--primary-blue);
|
||||
}
|
||||
|
||||
.quick-search-trigger .quick-search-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--primary-gradient);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-trigger .quick-search-icon .fa {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.quick-search-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
#hello-text {
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.quick-search-hint {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.quick-search-shortcut {
|
||||
padding: 6px 12px;
|
||||
background: var(--bg-main);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Modal Overlay */
|
||||
.quick-search-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding-top: 15vh;
|
||||
}
|
||||
|
||||
.quick-search-modal.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.quick-search-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
/* Modal Content */
|
||||
.quick-search-content {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 680px;
|
||||
max-height: 80vh;
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-md);
|
||||
animation: slideDown 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px) scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.quick-search-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-header .fa-search {
|
||||
color: var(--text-secondary);
|
||||
font-size: 22px;
|
||||
margin: 0 !important;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-search-input {
|
||||
flex: 1;
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
padding: 0 !important;
|
||||
font-size: var(--font-size-xl) !important;
|
||||
font-weight: var(--font-weight-normal) !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
.quick-search-input::placeholder {
|
||||
color: var(--text-muted) !important;
|
||||
font-size: var(--font-size-xl) !important;
|
||||
}
|
||||
|
||||
.quick-search-results {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-height: 150px;
|
||||
max-height: calc(80vh - 120px);
|
||||
}
|
||||
|
||||
.search-no-results {
|
||||
padding: 32px 24px;
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
.search-suggestion {
|
||||
display: block;
|
||||
padding: 12px 16px;
|
||||
transition: background 0.15s ease;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.search-suggestion:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-suggestion:hover {
|
||||
background: var(--primary-blue-hover-bg);
|
||||
}
|
||||
|
||||
.search-suggestion .fa {
|
||||
color: var(--primary-blue);
|
||||
margin-right: 14px !important;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.search-suggestion-item {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 6px;
|
||||
font-size: var(--font-size-lg);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.search-suggestion-options {
|
||||
font-size: var(--font-size-sm);
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.search-suggestion-options a {
|
||||
color: var(--primary-blue);
|
||||
margin-right: 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.search-suggestion-options a:hover {
|
||||
color: var(--primary-blue-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
BOOTSTRAP Hacks
|
||||
*/
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
max-width: 1600px;
|
||||
}
|
||||
}
|
||||
|
||||
/* for small devices */
|
||||
@media (max-width: 575.98px) {
|
||||
|
||||
#jsmediaManagerButton,
|
||||
#jscategoryButton,
|
||||
#jsdescriptionButton {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.btn-light {
|
||||
color: #212529;
|
||||
background-color: #f3f3f3;
|
||||
border-color: #ced4d9;
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
background-color: #F3F3F3;
|
||||
border-color: #DDD;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-form:hover {
|
||||
background-color: rgb(228, 228, 228);
|
||||
border-color: #DDD;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
code {
|
||||
padding: 3px 5px 2px;
|
||||
margin: 0 1px;
|
||||
background: #eaeaea;
|
||||
background: rgba(0, 0, 0, .07);
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.list-group-sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background-color: rgb(247, 247, 247);
|
||||
}
|
||||
|
||||
.modal-dialog .btn-link {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/*
|
||||
LOGIN
|
||||
*/
|
||||
|
||||
body.login {
|
||||
background: rgb(255, 255, 255);
|
||||
background: linear-gradient(0deg, rgba(255, 255, 255, 1) 0%, rgba(250, 250, 250, 1) 53%);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD
|
||||
*/
|
||||
|
||||
#dashboard ul.list-group.list-group-striped {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
background: var(--bg-card);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li {
|
||||
border: none;
|
||||
overflow-wrap: anywhere;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-normal);
|
||||
padding: 10px 18px;
|
||||
color: var(--text-primary);
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:first-child {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
padding: 14px 18px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:first-child h4 {
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-bold);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.6px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:nth-of-type(even):not(:first-child) {
|
||||
background: var(--bg-light);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li:hover:not(:first-child) {
|
||||
background: var(--primary-blue-hover-bg);
|
||||
}
|
||||
|
||||
#dashboard ul.list-group.list-group-striped li .notification-date {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-xs);
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#dashboard div.quick-links-icons {
|
||||
font-size: 2.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#dashboard a.quick-links {
|
||||
color: var(--text-secondary);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
#dashboard a.quick-links:hover {
|
||||
text-decoration: none;
|
||||
color: var(--primary-blue);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD METRIC CARDS
|
||||
*/
|
||||
|
||||
.card.metric-card {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
height: 100%;
|
||||
background: var(--bg-card);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card.metric-card .card-body > .d-flex {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.metric-card .card-body {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.metric-card .card-title {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.6px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.2;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.metric-card-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD ANALYTICS SECTION
|
||||
*/
|
||||
|
||||
.analytics-section {
|
||||
padding: 22px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--bg-card);
|
||||
}
|
||||
|
||||
#dashboard .analytics-section ul.list-group.list-group-striped {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#dashboard .analytics-section ul.list-group.list-group-striped li:first-child {
|
||||
padding: 0 0 12px 0;
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/*
|
||||
ALERT
|
||||
*/
|
||||
|
||||
#alert {
|
||||
display: none;
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
border-radius: var(--radius-md);
|
||||
border: 0;
|
||||
z-index: 1000;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
margin: 0;
|
||||
font-size: var(--font-size-base);
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: var(--primary-gradient);
|
||||
border-left: none !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background: var(--color-danger);
|
||||
border-left: none !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
PLUGINS
|
||||
*/
|
||||
|
||||
.plugin-form label {
|
||||
display: block;
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
.plugin-form input[type="text"],
|
||||
.plugin-form textarea,
|
||||
.plugin-form select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
font-size: var(--font-size-base);
|
||||
line-height: 1.5;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-card);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
transition: border-color .15s ease-in-out;
|
||||
}
|
||||
|
||||
.plugin-form textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.plugin-form span.tip {
|
||||
display: block;
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
margin-top: .25rem;
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Manage > Content
|
||||
*/
|
||||
|
||||
td.child {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
/* Truncate the URL column with ellipsis when it doesn't fit. */
|
||||
td.contentURL a {
|
||||
display: inline-block;
|
||||
max-width: 30em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Kebab actions dropdown */
|
||||
.actionsDropdownToggle {
|
||||
line-height: 1;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.actionsDropdownToggle:focus,
|
||||
.actionsDropdownToggle:hover {
|
||||
text-decoration: none;
|
||||
color: var(--text-primary, #1E293B);
|
||||
}
|
||||
|
||||
.actionsDropdownToggle:focus-visible {
|
||||
outline: 2px solid var(--primary-blue);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.actionsDropdown .dropdown-item i.fa {
|
||||
width: 1.25em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
Manage > New Content
|
||||
*/
|
||||
|
||||
#jseditor {
|
||||
background: #fff;
|
||||
padding: 10px 5% !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
border: 1px solid #ced4da;
|
||||
}
|
||||
|
||||
#jseditorSidebar {
|
||||
display: none;
|
||||
height: calc(100% - 45px);
|
||||
width: 50%;
|
||||
max-width: 350px;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
top: 45px;
|
||||
right: 15px;
|
||||
background-color: #fff;
|
||||
overflow-x: hidden;
|
||||
transition: 0.5s;
|
||||
border-left: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
#jseditorSidebar {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#jseditorToolbarRight button {
|
||||
font-size: 0px !important;
|
||||
}
|
||||
|
||||
#jseditorToolbarRight button span {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.contentTools .btn {
|
||||
font-size: 0px !important;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.contentTools .btn span {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
#jseditorSidebar nav {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
#jseditorSidebar nav a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#jseditorSidebar .nav-tabs .nav-link {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#jseditorSidebar .nav-link.active {
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 3px solid #ccc;
|
||||
}
|
||||
|
||||
#jsshadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(72, 72, 72, 0.7);
|
||||
z-index: 10;
|
||||
display: none;
|
||||
}
|
||||
|
||||
img.profilePicture {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Switch button */
|
||||
.switch-button {
|
||||
font-size: 0.9em;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-icon-publish {
|
||||
color: #1cb11c;
|
||||
}
|
||||
|
||||
/* Subtle focus style for form elements */
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus,
|
||||
.form-control:focus,
|
||||
.custom-select:focus,
|
||||
.btn:focus {
|
||||
border-color: #b0bec5 !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<script charset="utf-8">
|
||||
function showAlert(text) {
|
||||
console.log("[INFO] Function showAlert() called.");
|
||||
$("#alert").html(text);
|
||||
$("#alert").slideDown().delay(<?php echo ALERT_DISAPPEAR_IN*1000 ?>).slideUp();
|
||||
}
|
||||
|
||||
<?php if (Alert::defined()): ?>
|
||||
setTimeout(function(){ showAlert("<?php echo Alert::get() ?>") }, 500);
|
||||
<?php endif; ?>
|
||||
|
||||
$(window).click(function() {
|
||||
$("#alert").hide();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="alert" class="alert <?php echo (Alert::status()==ALERT_STATUS_FAIL)?'alert-danger':'alert-success' ?>"></div>
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
// Preload the first chunk of files to avoid an AJAX round-trip the first time
|
||||
// the Media Manager is opened. Scans originals and resolves each thumbnail,
|
||||
// mirroring the shape returned by ajax/list-images.
|
||||
if (IMAGE_RESTRICT) {
|
||||
$mediaImagesPath = PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS;
|
||||
$mediaThumbnailsPath = PATH_UPLOADS_PAGES.PAGE_IMAGES_KEY.DS.'thumbnails'.DS;
|
||||
} else {
|
||||
$mediaImagesPath = PATH_UPLOADS;
|
||||
$mediaThumbnailsPath = PATH_UPLOADS_THUMBNAILS;
|
||||
}
|
||||
$listOfFilesByPage = mediaManagerListImages($mediaImagesPath, $mediaThumbnailsPath, MEDIA_MANAGER_NUMBER_OF_FILES);
|
||||
$preLoadFiles = !empty($listOfFilesByPage[0]) ? $listOfFilesByPage[0] : array();
|
||||
|
||||
// Amount of pages for the paginator
|
||||
$numberOfPages = count($listOfFilesByPage);
|
||||
?>
|
||||
|
||||
<div id="jsmediaManagerModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col p-3">
|
||||
|
||||
<!--
|
||||
UPLOAD INPUT
|
||||
-->
|
||||
<h3 class="mt-2 mb-3"><i class="fa fa-image"></i> <?php $L->p('Images'); ?></h3>
|
||||
|
||||
<div id="jsalertMedia" class="alert alert-warning d-none" role="alert"></div>
|
||||
|
||||
<!-- Form and Input file -->
|
||||
<form name="bluditFormUpload" id="jsbluditFormUpload" enctype="multipart/form-data">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="jsimages" name="images[]" multiple>
|
||||
<label class="custom-file-label" for="jsimages"><?php $L->p('Choose images to upload'); ?></label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<div class="progress mt-3">
|
||||
<div id="jsbluditProgressBar" class="progress-bar bg-primary" role="progressbar" style="width:0%"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
IMAGES LIST
|
||||
-->
|
||||
<!-- Table for list files -->
|
||||
<table id="jsbluditMediaTable" class="table mt-3">
|
||||
<tr>
|
||||
<td><?php $L->p('There are no images'); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Paginator -->
|
||||
<nav id="jsbluditMediaTablePagination"></nav>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
<?php
|
||||
echo 'var preLoadFiles = '.json_encode($preLoadFiles).';';
|
||||
?>
|
||||
|
||||
function openMediaManager() {
|
||||
$('#jsmediaManagerModal').modal('show');
|
||||
}
|
||||
|
||||
function closeMediaManager() {
|
||||
$('#jsmediaManagerModal').modal('hide');
|
||||
}
|
||||
|
||||
// Remove all files from the table
|
||||
function cleanTable() {
|
||||
$('#jsbluditMediaTable').empty();
|
||||
}
|
||||
|
||||
function showMediaAlert(message) {
|
||||
$("#jsalertMedia").html(message).removeClass('d-none');
|
||||
}
|
||||
|
||||
function hideMediaAlert() {
|
||||
$("#jsalertMedia").addClass('d-none');
|
||||
}
|
||||
|
||||
// Show the files in the table
|
||||
function displayFiles(files, numberOfPages = <?= $numberOfPages ?>) {
|
||||
if (!Array.isArray(files)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean table
|
||||
cleanTable();
|
||||
|
||||
// Regenerate the table
|
||||
if (files.length > 0) {
|
||||
$.each(files, function(key, item) {
|
||||
var filename = item.filename;
|
||||
var image = "<?php echo PAGE_IMAGES_URL; ?>"+filename;
|
||||
// item.thumbnail is empty when no thumbnail file exists (thumbnails
|
||||
// disabled, generation failed, format unsupported by GD). Fall back
|
||||
// to the original image so the preview never 404s.
|
||||
var thumbnail = item.thumbnail ? "<?php echo PAGE_THUMBNAILS_URL; ?>"+item.thumbnail : image;
|
||||
|
||||
tableRow = '<tr id="js'+filename+'">'+
|
||||
'<td style="width:80px"><img class="img-thumbnail" alt="200x200" src="'+thumbnail+'" style="width: 50px; height: 50px;"><\/td>'+
|
||||
'<td class="information">'+
|
||||
'<div class="text-secondary pb-2">'+filename+'<\/div>'+
|
||||
'<div>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertMedia(\''+image+'\'); closeMediaManager();"><i class="fa fa-plus-circle"></i><?php $L->p('Insert') ?><\/a>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertMedia(\''+thumbnail+'\'); closeMediaManager();"><i class="fa fa-image"></i><?php $L->p('Insert thumbnail') ?><\/a>'+
|
||||
'<a href="#" class="mr-3 text-primary" onClick="editorInsertLinkedMedia(\''+thumbnail+'\',\''+image+'\'); closeMediaManager();"><i class="fa fa-link"></i><?php $L->p('Insert linked thumbnail') ?><\/a>'+
|
||||
'<a href="#" class="text-primary" onClick="setCoverImage(\''+filename+'\'); closeMediaManager();"><i class="fa fa-desktop"></i><?php $L->p('Set as cover image') ?><\/a>'+
|
||||
'<a href="#" class="float-right text-danger" onClick="deleteMedia(\''+filename+'\')"><i class="fa fa-trash-o"></i><?php $L->p('Delete') ?><\/a>'+
|
||||
'<\/div>'+
|
||||
'<\/td>'+
|
||||
'<\/tr>';
|
||||
$('#jsbluditMediaTable').append(tableRow);
|
||||
});
|
||||
|
||||
mediaPagination = '<ul class="pagination justify-content-center flex-wrap">';
|
||||
for (var i = 1; i <= numberOfPages; i++) {
|
||||
mediaPagination += '<li class="page-item"><button type="button" class="btn btn-link page-link" onClick="getFiles('+i+')">'+i+'</button></li>';
|
||||
}
|
||||
mediaPagination += '</ul>';
|
||||
$('#jsbluditMediaTablePagination').html(mediaPagination);
|
||||
|
||||
}
|
||||
|
||||
if (files.length == 0) {
|
||||
$('#jsbluditMediaTable').html("<p><?php (IMAGE_RESTRICT ? $L->p('There are no images for the page') : $L->p('There are no images')) ?></p>");
|
||||
$('#jsbluditMediaTablePagination').html('');
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of files via AJAX, filter by the page number
|
||||
function getFiles(pageNumber) {
|
||||
$.post(HTML_PATH_ADMIN_ROOT+"ajax/list-images",
|
||||
{ tokenCSRF: tokenCSRF,
|
||||
pageNumber: pageNumber,
|
||||
uuid: "<?php echo PAGE_IMAGES_KEY ?>",
|
||||
path: "thumbnails" // the paths are defined in ajax/list-images
|
||||
},
|
||||
function(data) { // success function
|
||||
if (data.status==0) {
|
||||
displayFiles(data.files, data.numberOfPages);
|
||||
} else {
|
||||
console.log(data.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the file and the thumbnail if exist
|
||||
function deleteMedia(filename) {
|
||||
$.post(HTML_PATH_ADMIN_ROOT+"ajax/delete-image",
|
||||
{ tokenCSRF: tokenCSRF,
|
||||
filename: filename,
|
||||
uuid: "<?php echo PAGE_IMAGES_KEY; ?>"
|
||||
},
|
||||
function(data) { // success function
|
||||
if (data.status==0) {
|
||||
getFiles(1);
|
||||
} else {
|
||||
console.log(data.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function setCoverImage(filename) {
|
||||
var image = "<?php echo PAGE_IMAGES_URL; ?>"+filename;
|
||||
$("#jscoverImage").val(filename);
|
||||
$("#jscoverImagePreview").attr("src", image);
|
||||
}
|
||||
|
||||
function uploadImages() {
|
||||
// Remove current alerts
|
||||
hideMediaAlert();
|
||||
|
||||
var images = $("#jsimages")[0].files;
|
||||
for (var i=0; i < images.length; i++) {
|
||||
// Check file type/extension
|
||||
const validImageTypes = ['image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp'];
|
||||
if (!validImageTypes.includes(images[i].type)) {
|
||||
showMediaAlert("<?php echo $L->g('File type is not supported. Allowed types:').' '.implode(', ',$GLOBALS['ALLOWED_IMG_EXTENSION']) ?>");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file size and compare with PHP upload_max_filesize
|
||||
if (images[i].size > UPLOAD_MAX_FILESIZE) {
|
||||
showMediaAlert("<?php echo $L->g('Maximum load file size allowed:').' '.ini_get('upload_max_filesize') ?>");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Clean progress bar
|
||||
$("#jsbluditProgressBar").removeClass().addClass("progress-bar bg-primary");
|
||||
$("#jsbluditProgressBar").width("0");
|
||||
|
||||
// Data to send via AJAX
|
||||
var formData = new FormData($("#jsbluditFormUpload")[0]);
|
||||
formData.append("uuid", "<?php echo PAGE_IMAGES_KEY ?>");
|
||||
formData.append("tokenCSRF", tokenCSRF);
|
||||
|
||||
$.ajax({
|
||||
url: HTML_PATH_ADMIN_ROOT+"ajax/upload-images",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
xhr: function() {
|
||||
var xhr = $.ajaxSettings.xhr();
|
||||
if (xhr.upload) {
|
||||
xhr.upload.addEventListener("progress", function(e) {
|
||||
if (e.lengthComputable) {
|
||||
var percentComplete = (e.loaded / e.total)*100;
|
||||
$("#jsbluditProgressBar").width(percentComplete+"%");
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
return xhr;
|
||||
}
|
||||
}).done(function(data) {
|
||||
if (data.status==0) {
|
||||
$("#jsbluditProgressBar").removeClass("bg-primary").addClass("bg-success");
|
||||
// Get the files for the first page, including uploaded files
|
||||
getFiles(1);
|
||||
} else {
|
||||
$("#jsbluditProgressBar").removeClass("bg-primary").addClass("bg-danger");
|
||||
showMediaAlert(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Display the files preloaded for the first time
|
||||
displayFiles(preLoadFiles);
|
||||
|
||||
// Select image event
|
||||
$("#jsimages").on("change", function(e) {
|
||||
uploadImages();
|
||||
});
|
||||
|
||||
// Drag and drop image
|
||||
$(window).on("dragover dragenter", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
// Drag and drop image
|
||||
$(window).on("drop", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$("#jsimages").prop("files", e.originalEvent.dataTransfer.files);
|
||||
uploadImages();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,77 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-uppercase d-block d-lg-none">
|
||||
<div class="container">
|
||||
<span class="navbar-brand">
|
||||
<?php echo (defined('BLUDIT_PRO'))?'BLUDIT PRO':'BLUDIT' ?></span>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'dashboard' ?>">
|
||||
<?php $L->p('Dashboard') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ROOT ?>">
|
||||
<?php $L->p('Website') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'new-content' ?>">
|
||||
<?php $L->p('New content') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>">
|
||||
<?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
<?php if (!checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'edit-user/'.$login->username() ?>">
|
||||
<?php $L->p('Profile') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'categories' ?>">
|
||||
<?php $L->p('Categories') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'users' ?>">
|
||||
<?php $L->p('Users') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'settings' ?>">
|
||||
<?php $L->p('Settings') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>">
|
||||
<?php $L->p('Plugins') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'themes' ?>">
|
||||
<?php $L->p('Themes') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'about' ?>">
|
||||
<?php $L->p('About') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
<?php
|
||||
if (!empty($plugins['adminSidebar'])) {
|
||||
foreach ($plugins['adminSidebar'] as $pluginSidebar) {
|
||||
echo '<li class="nav-item">';
|
||||
echo $pluginSidebar->adminSidebar();
|
||||
echo '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'logout' ?>">
|
||||
<?php $L->p('Logout') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,83 @@
|
||||
<!-- Use .flex-column to set a vertical direction -->
|
||||
<ul class="nav flex-column pt-4">
|
||||
|
||||
<li class="nav-item mb-4" style="display: flex; align-items: center;">
|
||||
<div style="display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: var(--primary-gradient); border-radius: 8px; box-shadow: var(--shadow-sm); flex-shrink: 0;">
|
||||
<img src="<?php echo HTML_PATH_CORE_IMG ?>logo.svg" width="18" height="18" alt="bludit-logo" style="filter: brightness(0) invert(1);">
|
||||
</div>
|
||||
<span style="margin-left: 10px; font-weight: 600; font-size: 1rem; color: var(--text-primary); line-height: 1;"><?php echo (defined('BLUDIT_PRO'))?'BLUDIT PRO':'BLUDIT' ?></span>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'dashboard' ?>"><span class="fa fa-dashboard"></span><?php $L->p('Dashboard') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" target="_blank" href="<?php echo HTML_PATH_ROOT ?>"><span class="fa fa-home"></span><?php $L->p('Website') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'new-content' ?>"><span class="fa fa-plus-circle text-primary"></span><?php $L->p('New content') ?></a>
|
||||
</li>
|
||||
|
||||
<?php if (!checkRole(array('admin'),false)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>"><span class="fa fa-archive"></span><?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'edit-user/'.$login->username() ?>"><span class="fa fa-user"></span><?php $L->p('Profile') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (checkRole(array('admin'),false)): ?>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h4><?php $L->p('Manage') ?></h4>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>"><span class="fa fa-folder"></span><?php $L->p('Content') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'categories' ?>"><span class="fa fa-bookmark"></span><?php $L->p('Categories') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'users' ?>"><span class="fa fa-users"></span><?php $L->p('Users') ?></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h4><?php $L->p('Settings') ?></h4>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'settings' ?>"><span class="fa fa-gear"></span><?php $L->p('General') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>"><span class="fa fa-puzzle-piece"></span><?php $L->p('Plugins') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'themes' ?>"><span class="fa fa-desktop"></span><?php $L->p('Themes') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'about' ?>"><span class="fa fa-info"></span><?php $L->p('About') ?></a>
|
||||
</li>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (checkRole(array('admin', 'editor'),false)): ?>
|
||||
|
||||
<?php
|
||||
if (!empty($plugins['adminSidebar'])) {
|
||||
echo '<li class="nav-item"><hr></li>';
|
||||
foreach ($plugins['adminSidebar'] as $pluginSidebar) {
|
||||
echo '<li class="nav-item">';
|
||||
echo $pluginSidebar->adminSidebar();
|
||||
echo '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="nav-item mt-5">
|
||||
<a class="nav-link" href="<?php echo HTML_PATH_ADMIN_ROOT.'logout' ?>"><span class="fa fa-arrow-circle-right"></span><?php $L->p('Logout') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo $layout['title'] ?></title>
|
||||
<meta charset="<?php echo CHARSET ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
<meta name="generator" content="Bludit">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="<?php echo HTML_PATH_CORE_IMG.'favicon.png?version='.BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- CSS -->
|
||||
<?php
|
||||
echo Theme::cssBootstrap();
|
||||
echo Theme::cssLineAwesome();
|
||||
echo Theme::css(array(
|
||||
'bludit.css',
|
||||
'bludit.bootstrap.css'
|
||||
), DOMAIN_ADMIN_THEME_CSS);
|
||||
echo Theme::css(array(
|
||||
'jquery.datetimepicker.min.css',
|
||||
'select2.min.css',
|
||||
'select2-bootstrap4.min.css'
|
||||
), DOMAIN_CORE_CSS);
|
||||
?>
|
||||
|
||||
<!-- Javascript -->
|
||||
<?php
|
||||
echo Theme::jquery();
|
||||
echo Theme::jsBootstrap();
|
||||
echo Theme::jsSortable();
|
||||
echo Theme::js(array(
|
||||
'jquery.datetimepicker.full.min.js',
|
||||
'select2.full.min.js',
|
||||
'functions.js'
|
||||
), DOMAIN_CORE_JS, null);
|
||||
?>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminHead') ?>
|
||||
|
||||
</head>
|
||||
<body class="h-100">
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminBodyBegin') ?>
|
||||
|
||||
<!-- Javascript dynamic generated by PHP -->
|
||||
<?php
|
||||
echo '<script charset="utf-8">'.PHP_EOL;
|
||||
include(PATH_CORE_JS.'variables.php');
|
||||
echo '</script>'.PHP_EOL;
|
||||
|
||||
echo '<script charset="utf-8">'.PHP_EOL;
|
||||
include(PATH_CORE_JS.'bludit-ajax.php');
|
||||
echo '</script>'.PHP_EOL;
|
||||
?>
|
||||
|
||||
<!-- Overlay background -->
|
||||
<div id="jsshadow"></div>
|
||||
|
||||
<!-- Alert -->
|
||||
<?php include('html/alert.php'); ?>
|
||||
|
||||
<!-- Navbar, only for small devices -->
|
||||
<?php include('html/navbar.php'); ?>
|
||||
|
||||
<div class="container min-vh-100">
|
||||
<!-- 25%/75% split on large devices, small, medium devices hide -->
|
||||
<div class="row min-vh-100 align-items-stretch">
|
||||
|
||||
<!-- LEFT SIDEBAR - Display only on large devices -->
|
||||
<div class="sidebar col-lg-2 d-none d-lg-block">
|
||||
<?php include('html/sidebar.php'); ?>
|
||||
</div>
|
||||
|
||||
<!-- RIGHT MAIN -->
|
||||
<div class="col-lg-10 pt-3 pb-1">
|
||||
<?php
|
||||
if (Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'].'.php')) {
|
||||
include(PATH_ADMIN_VIEWS.$layout['view'].'.php');
|
||||
} elseif ($layout['plugin'] && method_exists($layout['plugin'], 'adminView')) {
|
||||
echo $layout['plugin']->adminView();
|
||||
} else {
|
||||
echo '<h1 class="text-center">'.$L->g('Page not found').'</h1>';
|
||||
echo '<h2 class="text-center">'.$L->g('Choose a page from the sidebar.').'</h2>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('adminBodyEnd') ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
class Bootstrap
|
||||
{
|
||||
|
||||
public static function modal($args)
|
||||
{
|
||||
|
||||
$buttonSecondary = $args['buttonSecondary'];
|
||||
$buttonSecondaryClass = $args['buttonSecondaryClass'];
|
||||
|
||||
$buttonPrimary = $args['buttonPrimary'];
|
||||
$buttonPrimaryClass = $args['buttonPrimaryClass'];
|
||||
|
||||
$modalText = $args['modalText'];
|
||||
$modalTitle = $args['modalTitle'];
|
||||
$modalId = $args['modalId'];
|
||||
|
||||
|
||||
return <<<EOF
|
||||
<div id="$modalId" class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<h3>$modalTitle</h3>
|
||||
<p>$modalText</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn $buttonSecondaryClass" data-dismiss="modal">$buttonSecondary</button>
|
||||
<button type="button" class="btn $buttonPrimaryClass">$buttonPrimary</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function link($args)
|
||||
{
|
||||
$options = 'href="' . $args['href'] . '"';
|
||||
if (isset($args['class'])) {
|
||||
$options .= ' class="' . $args['class'] . '"';
|
||||
}
|
||||
if (isset($args['target'])) {
|
||||
$options .= ' target="' . $args['target'] . '"';
|
||||
}
|
||||
|
||||
if (isset($args['icon'])) {
|
||||
return '<a ' . $options . '><span class="fa fa-' . $args['icon'] . '"></span>' . $args['title'] . '</a>';
|
||||
}
|
||||
|
||||
return '<a ' . $options . '>' . $args['title'] . '</a>';
|
||||
}
|
||||
|
||||
public static function pageTitle($args)
|
||||
{
|
||||
$icon = $args['icon'];
|
||||
$title = $args['title'];
|
||||
return <<<EOF
|
||||
<h2 class="mt-0 mb-3">
|
||||
<span class="fa fa-$icon" style="font-size: 0.9em;"></span><span>$title</span>
|
||||
</h2>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formOpen($args)
|
||||
{
|
||||
$class = empty($args['class']) ? '' : 'class="' . $args['class'] . '"';
|
||||
$id = empty($args['id']) ? '' : 'id="' . $args['id'] . '"';
|
||||
$enctype = empty($args['enctype']) ? '' : 'enctype="' . $args['enctype'] . '"';
|
||||
$action = empty($args['action']) ? 'action=""' : 'action="' . $args['action'] . '"';
|
||||
$method = empty($args['method']) ? 'method="post"' : 'method="' . $args['method'] . '"';
|
||||
$style = empty($args['style']) ? '' : 'style="' . $args['style'] . '"';
|
||||
|
||||
return <<<EOF
|
||||
<form $class $enctype $id $method $action $style autocomplete="off">
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formClose()
|
||||
{
|
||||
return <<<EOF
|
||||
</form>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Prevent the form submit when press enter key.
|
||||
$("form").keypress(function(e) {
|
||||
if ((e.which == 13) && (e.target.type !== "textarea")) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formTitle($args)
|
||||
{
|
||||
$title = $args['title'];
|
||||
return <<<EOF
|
||||
<h6 class="mt-4 mb-2 pb-2 border-bottom text-uppercase">$title</h6>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formInputTextBlock($args)
|
||||
{
|
||||
$name = $args['name'];
|
||||
$disabled = empty($args['disabled']) ? '' : 'disabled';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$tip = '';
|
||||
if (!empty($args['tip'])) {
|
||||
$tip = '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
|
||||
$class = 'form-group m-0';
|
||||
if (isset($args['class'])) {
|
||||
$class = $args['class'];
|
||||
}
|
||||
|
||||
$labelClass = 'mt-4 mb-2 pb-2 border-bottom text-uppercase w-100';
|
||||
if (isset($args['labelClass'])) {
|
||||
$labelClass = $args['labelClass'];
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (!empty($args['label'])) {
|
||||
$label = '<label class="' . $labelClass . '" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class">
|
||||
$label
|
||||
<input type="text" dir="auto" value="$value" class="form-control" id="$id" name="$name" placeholder="$placeholder" $disabled>
|
||||
$tip
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formInputFile($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-file';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="' . $class . '">';
|
||||
$html .= '<input type="file" class="custom-file-input" id="' . $id . '">';
|
||||
$html .= '<label class="custom-file-label" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formTextarea($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group row">';
|
||||
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<div class="col-sm-10">';
|
||||
$html .= '<textarea class="' . $class . '" id="' . $id . '" name="' . $args['name'] . '" rows="' . $args['rows'] . '" placeholder="' . $args['placeholder'] . '">' . $args['value'] . '</textarea>';
|
||||
if (isset($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formTextareaBlock($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group m-0">';
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<textarea class="' . $class . '" id="' . $id . '" name="' . $args['name'] . '" rows="' . $args['rows'] . '" placeholder="' . $args['placeholder'] . '">' . $args['value'] . '</textarea>';
|
||||
if (!empty($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formInputText($args)
|
||||
{
|
||||
$name = $args['name'];
|
||||
$disabled = empty($args['disabled']) ? '' : 'disabled';
|
||||
$readonly = empty($args['readonly']) ? '' : 'readonly';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$tip = '';
|
||||
if (isset($args['tip'])) {
|
||||
$tip = '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (isset($args['label'])) {
|
||||
$label = '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$class = 'form-control';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
return <<<EOF
|
||||
<div class="form-group row">
|
||||
$label
|
||||
<div class="col-sm-10">
|
||||
<input class="$class" id="$id" name="$name" value="$value" placeholder="$placeholder" type="$type" dir="auto" $disabled $readonly>
|
||||
$tip
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formCheckbox($args)
|
||||
{
|
||||
$labelForCheckbox = isset($args['labelForCheckbox']) ? $args['labelForCheckbox'] : '';
|
||||
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
|
||||
$tip = isset($args['tip']) ? '<small class="form-text text-muted">' . $args['tip'] . '</small>' : '';
|
||||
$value = isset($args['value']) ? $args['value'] : '';
|
||||
$name = $args['name'];
|
||||
$id = 'js' . $name;
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
$disabled = isset($args['disabled']) ? 'disabled' : '';
|
||||
|
||||
$class = 'form-group m-0';
|
||||
if (isset($args['class'])) {
|
||||
$class = $args['class'];
|
||||
}
|
||||
|
||||
$labelClass = 'mt-4 mb-2 pb-2 border-bottom text-uppercase w-100';
|
||||
if (isset($args['labelClass'])) {
|
||||
$labelClass = $args['labelClass'];
|
||||
}
|
||||
|
||||
$type = 'text';
|
||||
if (isset($args['type'])) {
|
||||
$type = $args['type'];
|
||||
}
|
||||
|
||||
$label = '';
|
||||
if (!empty($args['label'])) {
|
||||
$label = '<label class="' . $labelClass . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$checked = $args['checked'] ? 'checked' : '';
|
||||
$value = $checked ? '1' : '0';
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class">
|
||||
$label
|
||||
<div class="form-check">
|
||||
<input type="hidden" name="$name" value="$value"><input id="$id" type="checkbox" class="form-check-input" onclick="this.previousSibling.value=1-this.previousSibling.value" $checked>
|
||||
<label class="form-check-label" for="$id">$labelForCheckbox</label>
|
||||
$tip
|
||||
</div>
|
||||
</div>
|
||||
EOF;
|
||||
}
|
||||
|
||||
public static function formSelect($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-select';
|
||||
if (isset($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group row">';
|
||||
|
||||
if (isset($args['label'])) {
|
||||
$html .= '<label for="' . $id . '" class="col-sm-2 col-form-label">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<div class="col-sm-10">';
|
||||
$html .= '<select id="' . $id . '" name="' . $args['name'] . '" class="' . $class . '">';
|
||||
foreach ($args['options'] as $key => $value) {
|
||||
$html .= '<option ' . (($key == $args['selected']) ? 'selected' : '') . ' value="' . $key . '">' . $value . '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
if (isset($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formSelectBlock($args)
|
||||
{
|
||||
$id = 'js' . $args['name'];
|
||||
if (isset($args['id'])) {
|
||||
$id = $args['id'];
|
||||
}
|
||||
|
||||
$class = 'custom-select';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$html = '<div class="form-group m-0">';
|
||||
|
||||
if (!empty($args['label'])) {
|
||||
$html .= '<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100" for="' . $id . '">' . $args['label'] . '</label>';
|
||||
}
|
||||
|
||||
$html .= '<select id="' . $id . '" name="' . $args['name'] . '" class="' . $class . '">';
|
||||
if (!empty($args['emptyOption'])) {
|
||||
$html .= '<option value="">' . $args['emptyOption'] . '</option>';
|
||||
}
|
||||
foreach ($args['options'] as $key => $value) {
|
||||
$html .= '<option ' . (($key == $args['selected']) ? 'selected' : '') . ' value="' . $key . '">' . $value . '</option>';
|
||||
}
|
||||
$html .= '</select>';
|
||||
if (!empty($args['tip'])) {
|
||||
$html .= '<small class="form-text text-muted">' . $args['tip'] . '</small>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function formInputHidden($args)
|
||||
{
|
||||
return '<input type="hidden" id="js' . $args['name'] . '" name="' . $args['name'] . '" value="' . $args['value'] . '">';
|
||||
}
|
||||
|
||||
public static function alert($args)
|
||||
{
|
||||
$class = 'alert';
|
||||
if (!empty($args['class'])) {
|
||||
$class = $class . ' ' . $args['class'];
|
||||
}
|
||||
|
||||
$text = $args['text'];
|
||||
|
||||
return <<<EOF
|
||||
<div class="$class" role="alert">$text</div>
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title><?php echo (defined('BLUDIT_PRO') ? $site->title() : 'BLUDIT') ?> - Login</title>
|
||||
<meta charset="<?php echo CHARSET ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="<?php echo HTML_PATH_CORE_IMG . 'favicon.png?version=' . BLUDIT_VERSION ?>">
|
||||
|
||||
<!-- CSS -->
|
||||
<?php
|
||||
echo Theme::cssBootstrap();
|
||||
echo Theme::css(array(
|
||||
'bludit.css',
|
||||
'bludit.bootstrap.css'
|
||||
), DOMAIN_ADMIN_THEME_CSS);
|
||||
?>
|
||||
|
||||
<style>
|
||||
body.login {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 50%, #0d47a1 100%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||
padding: 40px;
|
||||
animation: fadeInUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login-logo .logo-icon {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%);
|
||||
border-radius: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 8px 20px rgba(21, 101, 192, 0.4);
|
||||
}
|
||||
|
||||
.login-logo .logo-icon img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.login-logo .logo-icon.custom-logo {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 150px;
|
||||
max-height: 80px;
|
||||
}
|
||||
|
||||
.login-logo .logo-icon.custom-logo img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 150px;
|
||||
max-height: 80px;
|
||||
filter: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.login-logo h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-logo p {
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.login-card .form-control {
|
||||
border: 2px solid #e9ecef;
|
||||
border-radius: 10px;
|
||||
padding: 12px 16px;
|
||||
font-size: 0.95rem;
|
||||
transition: all 0.3s ease;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.login-card .form-control:focus {
|
||||
border-color: #1e88e5;
|
||||
box-shadow: 0 0 0 4px rgba(30, 136, 229, 0.15);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.login-card .form-control::placeholder {
|
||||
color: #adb5bd;
|
||||
}
|
||||
|
||||
.login-card .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-card .form-group label {
|
||||
font-weight: 500;
|
||||
color: #495057;
|
||||
margin-bottom: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.login-card .btn-login {
|
||||
background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
padding: 12px 18px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
width: 100%;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(21, 101, 192, 0.4);
|
||||
}
|
||||
|
||||
.login-card .btn-login:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(21, 101, 192, 0.5);
|
||||
}
|
||||
|
||||
.login-card .btn-login:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.login-card .form-check {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.login-card .form-check-input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 0;
|
||||
border: 2px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.login-card .form-check-input:checked {
|
||||
background-color: #1e88e5;
|
||||
border-color: #1e88e5;
|
||||
}
|
||||
|
||||
.login-card .form-check-label {
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.login-footer p {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-footer a {
|
||||
color: #1e88e5;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Alert styles for login page */
|
||||
.login-alert {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1050;
|
||||
min-width: 300px;
|
||||
max-width: 90%;
|
||||
border-radius: 10px;
|
||||
padding: 12px 20px;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
animation: slideDown 0.4s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.login-alert.alert-danger {
|
||||
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 15px rgba(238, 90, 90, 0.4);
|
||||
}
|
||||
|
||||
.login-alert.alert-success {
|
||||
background: linear-gradient(135deg, #51cf66 0%, #40c057 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 15px rgba(64, 192, 87, 0.4);
|
||||
}
|
||||
|
||||
/* Input icons */
|
||||
.input-icon-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .form-control {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .input-icon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #adb5bd;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.input-icon-wrapper .form-control:focus + .input-icon,
|
||||
.input-icon-wrapper .form-control:not(:placeholder-shown) + .input-icon {
|
||||
color: #1e88e5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Javascript -->
|
||||
<?php
|
||||
echo Theme::jquery();
|
||||
echo Theme::jsBootstrap();
|
||||
?>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginHead') ?>
|
||||
</head>
|
||||
|
||||
<body class="login">
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginBodyBegin') ?>
|
||||
|
||||
<!-- Alert -->
|
||||
<?php if (Alert::defined()): ?>
|
||||
<div id="login-alert" class="login-alert alert <?php echo (Alert::status() == ALERT_STATUS_FAIL) ? 'alert-danger' : 'alert-success' ?>">
|
||||
<?php echo Alert::get() ?>
|
||||
</div>
|
||||
<script>
|
||||
setTimeout(function() {
|
||||
document.getElementById('login-alert').style.display = 'none';
|
||||
}, <?php echo ALERT_DISAPPEAR_IN * 1000 ?>);
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<?php
|
||||
if (Sanitize::pathFile(PATH_ADMIN_VIEWS, $layout['view'] . '.php')) {
|
||||
include(PATH_ADMIN_VIEWS . $layout['view'] . '.php');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugins -->
|
||||
<?php Theme::plugins('loginBodyEnd') ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="pattern-0" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" viewBox="0 0 100 100">
|
||||
<path d="M 0 0 L 50 0 L 50 100 L 0 100 Z" style="fill: black;"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<path style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;" d="M 140.612 16.07 C 136.565 10.367 125.853 69.255 108.381 129.061 C 103.577 145.502 110.407 162.089 112.885 176.473 C 117.048 183.779 121.184 194.444 124.691 207.736 C 125.873 212.214 126.903 216.775 127.823 221.339 C 118.109 245.954 112.626 273.846 112.626 303.409 C 112.626 330.642 117.299 356.445 125.623 379.586 C 141.303 391.431 156.518 408.669 169.013 430.093 C 174.86 440.118 179.69 450.381 183.539 460.577 C 203.547 475.159 226.618 483.493 251.189 483.493 C 274.393 483.493 296.256 476.068 315.472 462.963 C 319.453 451.983 324.113 440.618 330.877 430.093 C 344.265 409.265 360.773 389.253 377.633 377.13 C 389.314 358.536 390.837 330.762 389.75 303.409 C 388.621 275.027 384.678 248.146 375.666 224.253 C 376.446 218.449 377.415 212.643 378.618 206.935 C 381.644 192.557 385.537 181.154 389.621 173.676 C 391.233 159.61 396.683 143.363 391.511 127.64 C 370.872 64.898 373.494 118.034 367.485 123.062 C 359.888 129.421 319.716 67.053 321.298 129.061 C 321.471 135.825 321.836 142.432 322.359 148.856 C 301.557 132.637 276.381 152.664 250.36 152.664 C 223.685 152.664 199.605 133.116 178.463 150.095 C 178.74 142.832 178.79 135.327 178.593 127.64 C 177.01 65.631 165.781 51.533 140.612 16.07 Z" id="path2987"/>
|
||||
<path id="path3763" d="M 248.613 379.622 C 238.675 379.622 215.913 399.093 215.913 412.414 C 215.913 416.062 217.038 419.515 219.042 422.614 C 222.816 424.2 226.478 426.509 229.486 429.38 C 230.893 430.722 232.055 432.096 232.981 433.462 C 237.797 435.415 243.351 436.53 249.265 436.53 C 254.852 436.53 260.114 435.536 264.738 433.78 C 265.698 432.311 266.929 430.827 268.446 429.38 C 271.669 426.304 275.642 423.875 279.701 422.286 C 281.573 419.274 282.618 415.932 282.618 412.414 C 282.618 399.093 259.202 379.622 248.613 379.622 Z" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;"/>
|
||||
<path style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-width: 24.1239;" d="M 218.799 311.887 C 253.953 253.834 192.034 175.403 161.146 240.701 C 147.314 269.942 179.823 338.489 218.799 311.887 Z" id="path3779"/>
|
||||
<path style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0); stroke-miterlimit: 4; stroke-width: 18;" d="M 311.951 273.021 C 311.951 278.795 306.666 283.478 300.147 283.478 C 293.629 283.478 288.343 278.795 288.343 273.021 C 288.343 267.245 293.629 262.563 300.147 262.563 C 306.666 262.563 311.951 267.245 311.951 273.021 Z" id="path3785"/>
|
||||
<path style="stroke: rgb(0, 0, 0); stroke-miterlimit: 4; fill: rgb(255, 255, 255); stroke-width: 24.1239;" d="M 229.289 269.988 C 229.289 285.489 216.409 298.058 200.518 298.058 C 184.631 298.058 171.749 285.489 171.749 269.988 C 171.749 254.478 184.631 241.912 200.518 241.912 C 216.409 241.912 229.289 254.478 229.289 269.988 Z" id="path-1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title'=>$L->g('About'), 'icon'=>'info-circle'));
|
||||
|
||||
echo '
|
||||
<table class="table table-striped mt-3">
|
||||
<tbody>
|
||||
';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>Bludit Edition</td>';
|
||||
if (defined('BLUDIT_PRO')) {
|
||||
echo '<td>PRO - '.$L->g('Thanks for supporting Bludit').' <span class="fa fa-heart" style="color: #ffc107"></span></td>';
|
||||
} else {
|
||||
echo '<td>Standard - <a target="_blank" href="https://pro.bludit.com">'.$L->g('Upgrade to Bludit PRO').'</a></td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>Bludit Version</td>';
|
||||
echo '<td>'.BLUDIT_VERSION.'</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>Bludit Codename</td>';
|
||||
echo '<td>'.BLUDIT_CODENAME.'</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>Bludit Build Number</td>';
|
||||
echo '<td>'.BLUDIT_BUILD.'</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>Disk usage</td>';
|
||||
echo '<td>'.Filesystem::bytesToHumanFileSize(Filesystem::getSize(PATH_ROOT)).'</td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td><a href="'.HTML_PATH_ADMIN_ROOT.'developers'.'">Bludit Developers</a></td>';
|
||||
echo '<td></td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'themes' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('Blocks'), 'icon'=>'box')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
foreach ($blocks->getAll() as $block) {
|
||||
echo Bootstrap::formTitle(array('title'=>$block->title()));
|
||||
|
||||
if (Text::isNotEmpty( $block->description() )) {
|
||||
echo Bootstrap::alert(array('class'=>'alert-primary', 'text'=>$block->description()));
|
||||
}
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'key[]',
|
||||
'label'=>$L->g('Key'),
|
||||
'value'=>$block->key(),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>'',
|
||||
'readonly'=>true
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'title[]',
|
||||
'label'=>$L->g('title'),
|
||||
'value'=>$block->title(),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formTextarea(array(
|
||||
'name'=>'value[]',
|
||||
'label'=>$L->g('Value'),
|
||||
'value'=>$block->value(),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>'',
|
||||
'rows'=>5
|
||||
));
|
||||
}
|
||||
|
||||
echo Bootstrap::formClose();
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
echo Bootstrap::pageTitle(array('title'=>$L->g('Categories'), 'icon'=>'tags'));
|
||||
|
||||
echo Bootstrap::link(array(
|
||||
'title'=>$L->g('Add a new category'),
|
||||
'href'=>HTML_PATH_ADMIN_ROOT.'new-category',
|
||||
'icon'=>'plus'
|
||||
));
|
||||
|
||||
echo '
|
||||
<table class="table table-striped mt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('Name').'</th>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('URL').'</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
';
|
||||
|
||||
foreach ($categories->keys() as $key) {
|
||||
$category = new Category($key);
|
||||
echo '<tr>';
|
||||
echo '<td><a href="'.HTML_PATH_ADMIN_ROOT.'edit-category/'.$key.'">'.$category->name().'</a></td>';
|
||||
echo '<td><a href="'.$category->permalink().'">'.$url->filters('category', false).$key.'</a></td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'plugin-form')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<?php if ($plugin->formButtons()): ?>
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$plugin->name(), 'icon'=>'cog')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// Compatibility warning
|
||||
if (!$plugin->isCompatible()) {
|
||||
echo '<div class="alert alert-warning mt-2">' . $L->g('This plugin may not be supported by this version of Bludit') . '</div>';
|
||||
}
|
||||
|
||||
// Print the plugin form
|
||||
echo $plugin->form();
|
||||
?>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title'=>$L->g('Content'), 'icon'=>'archive'));
|
||||
|
||||
function moveTypeIcon($type) {
|
||||
$icons = array(
|
||||
'published' => 'fa-file-text-o',
|
||||
'sticky' => 'fa-thumb-tack',
|
||||
'static' => 'fa-file',
|
||||
'draft' => 'fa-pencil',
|
||||
);
|
||||
return isset($icons[$type]) ? $icons[$type] : 'fa-file';
|
||||
}
|
||||
|
||||
function moveTypeLabel($current, $target, $L) {
|
||||
if ($target === 'sticky') {
|
||||
return $L->g('Sticky');
|
||||
}
|
||||
if ($current === 'sticky' && $target === 'published') {
|
||||
return $L->g('Unstick');
|
||||
}
|
||||
$labels = array(
|
||||
'published' => $L->g('Move to Page'),
|
||||
'static' => $L->g('Move to Static'),
|
||||
'draft' => $L->g('Move to Draft'),
|
||||
);
|
||||
return isset($labels[$target]) ? $labels[$target] : $target;
|
||||
}
|
||||
|
||||
// Render a single row (or row + nested children) for a page key.
|
||||
// $type controls which columns/buttons are shown; $isSticky adds the Sticky badge
|
||||
// and flips the toggle button into "Unstick" mode.
|
||||
function tableRow($pageKey, $type, $isSticky = false, $renderChildren = false) {
|
||||
global $url;
|
||||
global $L;
|
||||
|
||||
try {
|
||||
$page = new Page($pageKey);
|
||||
} catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
$showURL = ($type === 'published' || $type === 'static' || $type === 'sticky');
|
||||
|
||||
// Allowed "Move to" transitions per current type.
|
||||
$moves = array(
|
||||
'published' => array('sticky', 'static', 'draft'),
|
||||
'sticky' => array('published', 'static', 'draft'),
|
||||
'draft' => array('published', 'static'),
|
||||
'static' => array('published', 'draft'),
|
||||
);
|
||||
|
||||
$dateLabel = '';
|
||||
if ($type === 'scheduled') {
|
||||
$dateLabel = $L->g('Scheduled').': '.$page->date(SCHEDULED_DATE_FORMAT);
|
||||
} elseif ((ORDER_BY === 'position') || ($type !== 'published' && $type !== 'sticky')) {
|
||||
$dateLabel = $L->g('Position').': '.$page->position();
|
||||
} else {
|
||||
$dateLabel = $page->date(MANAGE_CONTENT_DATE_FORMAT);
|
||||
}
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td class="pt-3">';
|
||||
echo '<div>';
|
||||
echo '<a style="font-size: 1.1em" href="'.HTML_PATH_ADMIN_ROOT.'edit-content/'.$page->key().'">';
|
||||
echo ($page->title() ? $page->title() : '<span class="label-empty-title">'.$L->g('Empty title').'</span> ');
|
||||
echo '</a>';
|
||||
if ($isSticky) {
|
||||
echo ' <span class="badge badge-warning align-middle ml-1" title="'.$L->g('Sticky').'"><i class="fa fa-thumb-tack"></i> '.$L->g('Sticky').'</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div><p style="font-size: 0.8em" class="m-0 text-uppercase text-muted">'.$dateLabel.'</p></div>';
|
||||
echo '</td>';
|
||||
|
||||
if ($showURL) {
|
||||
$friendlyURL = Text::isEmpty($url->filters('page')) ? '/'.$page->key() : '/'.$url->filters('page').'/'.$page->key();
|
||||
echo '<td class="pt-3 d-none d-xl-table-cell contentURL"><a target="_blank" href="'.$page->permalink().'" title="'.$friendlyURL.'">'.$friendlyURL.'</a></td>';
|
||||
}
|
||||
|
||||
echo '<td class="contentTools pt-3 text-center align-middle">'.PHP_EOL;
|
||||
echo '<div class="dropdown actionsDropdown">';
|
||||
echo '<button class="btn btn-link text-secondary p-1 actionsDropdownToggle" type="button" data-toggle="dropdown" data-boundary="viewport" aria-haspopup="true" aria-expanded="false" title="'.$L->g('Actions').'"><i class="fa fa-bars"></i></button>';
|
||||
echo '<div class="dropdown-menu dropdown-menu-right">';
|
||||
|
||||
// View / Edit
|
||||
if ($showURL) {
|
||||
echo '<a class="dropdown-item" target="_blank" href="'.$page->permalink().'"><i class="fa fa-desktop fa-fw mr-2"></i>'.$L->g('View').'</a>';
|
||||
}
|
||||
echo '<a class="dropdown-item" href="'.HTML_PATH_ADMIN_ROOT.'edit-content/'.$page->key().'"><i class="fa fa-edit fa-fw mr-2"></i>'.$L->g('Edit').'</a>';
|
||||
|
||||
// Sticky / Unstick toggle, between View/Edit and Move-to.
|
||||
$stickyToggleTarget = false;
|
||||
if ($type === 'published') {
|
||||
$stickyToggleTarget = 'sticky';
|
||||
} elseif ($type === 'sticky') {
|
||||
$stickyToggleTarget = 'published';
|
||||
}
|
||||
if ($stickyToggleTarget) {
|
||||
echo '<div class="dropdown-divider"></div>';
|
||||
echo '<a href="#" class="dropdown-item changeTypeButton" data-key="'.$page->key().'" data-type="'.$stickyToggleTarget.'"><i class="fa '.moveTypeIcon($stickyToggleTarget).' fa-fw mr-2"></i>'.moveTypeLabel($type, $stickyToggleTarget, $L).'</a>';
|
||||
}
|
||||
|
||||
// Move to ... (everything except the sticky toggle target rendered above).
|
||||
if (isset($moves[$type])) {
|
||||
$remaining = array();
|
||||
foreach ($moves[$type] as $target) {
|
||||
if ($target !== $stickyToggleTarget) {
|
||||
$remaining[] = $target;
|
||||
}
|
||||
}
|
||||
if (!empty($remaining)) {
|
||||
echo '<div class="dropdown-divider"></div>';
|
||||
foreach ($remaining as $target) {
|
||||
echo '<a href="#" class="dropdown-item changeTypeButton" data-key="'.$page->key().'" data-type="'.$target.'"><i class="fa '.moveTypeIcon($target).' fa-fw mr-2"></i>'.moveTypeLabel($type, $target, $L).'</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($page->children()) == 0) {
|
||||
echo '<div class="dropdown-divider"></div>';
|
||||
echo '<a href="#" class="dropdown-item text-danger deletePageButton" data-toggle="modal" data-target="#jsdeletePageModal" data-key="'.$page->key().'"><i class="fa fa-trash fa-fw mr-2"></i>'.$L->g('Delete').'</a>';
|
||||
}
|
||||
echo '</div></div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
if ($renderChildren) {
|
||||
foreach ($page->children() as $child) {
|
||||
echo '<tr>';
|
||||
echo '<td class="child">';
|
||||
echo '<div>';
|
||||
echo '<a style="font-size: 1.1em" href="'.HTML_PATH_ADMIN_ROOT.'edit-content/'.$child->key().'">';
|
||||
echo ($child->title() ? $child->title() : '<span class="label-empty-title">'.$L->g('Empty title').'</span> ');
|
||||
echo '</a>';
|
||||
echo '</div>';
|
||||
echo '<div><p style="font-size: 0.8em" class="m-0 text-uppercase text-muted">'.$L->g('Position').': '.$child->position().'</p></div>';
|
||||
echo '</td>';
|
||||
|
||||
if ($showURL) {
|
||||
$friendlyChildURL = Text::isEmpty($url->filters('page')) ? '/'.$child->key() : '/'.$url->filters('page').'/'.$child->key();
|
||||
echo '<td class="d-none d-xl-table-cell contentURL"><a target="_blank" href="'.$child->permalink().'" title="'.$friendlyChildURL.'">'.$friendlyChildURL.'</a></td>';
|
||||
}
|
||||
|
||||
echo '<td class="contentTools pt-3 text-center align-middle">'.PHP_EOL;
|
||||
echo '<div class="dropdown actionsDropdown">';
|
||||
echo '<button class="btn btn-link text-secondary p-1 actionsDropdownToggle" type="button" data-toggle="dropdown" data-boundary="viewport" aria-haspopup="true" aria-expanded="false" title="'.$L->g('Actions').'"><i class="fa fa-bars"></i></button>';
|
||||
echo '<div class="dropdown-menu dropdown-menu-right">';
|
||||
if ($showURL) {
|
||||
echo '<a class="dropdown-item" target="_blank" href="'.$child->permalink().'"><i class="fa fa-desktop fa-fw mr-2"></i>'.$L->g('View').'</a>';
|
||||
}
|
||||
echo '<a class="dropdown-item" href="'.HTML_PATH_ADMIN_ROOT.'edit-content/'.$child->key().'"><i class="fa fa-edit fa-fw mr-2"></i>'.$L->g('Edit').'</a>';
|
||||
echo '<div class="dropdown-divider"></div>';
|
||||
echo '<a href="#" class="dropdown-item text-danger deletePageButton" data-toggle="modal" data-target="#jsdeletePageModal" data-key="'.$child->key().'"><i class="fa fa-trash fa-fw mr-2"></i>'.$L->g('Delete').'</a>';
|
||||
echo '</div></div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render rows for a list, applying the parent/child nesting rules used by the
|
||||
// Static tab and by the Pages/Sticky lists when ORDER_BY is "position".
|
||||
function tableRows($list, $type, $isSticky = false) {
|
||||
$nestChildren = ($type === 'static') || (ORDER_BY === 'position');
|
||||
foreach ($list as $pageKey) {
|
||||
try {
|
||||
$page = new Page($pageKey);
|
||||
} catch (Exception $e) {
|
||||
continue;
|
||||
}
|
||||
if ($nestChildren) {
|
||||
if ($page->isChild()) {
|
||||
continue;
|
||||
}
|
||||
tableRow($pageKey, $type, $isSticky, true);
|
||||
} else {
|
||||
tableRow($pageKey, $type, $isSticky, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render a full table for a single tab (Static, Scheduled, Draft, Autosave).
|
||||
function table($type) {
|
||||
global $L;
|
||||
global $drafts;
|
||||
global $scheduled;
|
||||
global $static;
|
||||
global $autosave;
|
||||
|
||||
if ($type === 'draft') {
|
||||
$list = $drafts;
|
||||
$emptyMessage = $L->g('There are no draft pages at this moment.');
|
||||
} elseif ($type === 'scheduled') {
|
||||
$list = $scheduled;
|
||||
$emptyMessage = $L->g('There are no scheduled pages at this moment.');
|
||||
} elseif ($type === 'static') {
|
||||
$list = $static;
|
||||
$emptyMessage = $L->g('There are no static pages at this moment.');
|
||||
} elseif ($type === 'autosave') {
|
||||
$list = $autosave;
|
||||
$emptyMessage = '';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($list) && $type !== 'autosave') {
|
||||
echo '<p class="mt-4 text-muted">'.$emptyMessage.'</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<table class="table mt-3"><thead><tr>';
|
||||
echo '<th class="border-0" scope="col">'.$L->g('Title').'</th>';
|
||||
if ($type === 'static') {
|
||||
echo '<th class="border-0 d-none d-xl-table-cell" scope="col">'.$L->g('URL').'</th>';
|
||||
}
|
||||
echo '<th class="border-0 text-center d-sm-table-cell" scope="col">'.$L->g('Actions').'</th>';
|
||||
echo '</tr></thead><tbody>';
|
||||
tableRows($list, $type);
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
// Render the Pages tab: sticky rows first, then the paginated published list,
|
||||
// in a single table.
|
||||
function tablePages() {
|
||||
global $L;
|
||||
global $published;
|
||||
global $sticky;
|
||||
global $url;
|
||||
|
||||
$isFirstPage = ($url->pageNumber() <= 1);
|
||||
|
||||
if (empty($published) && (empty($sticky) || !$isFirstPage)) {
|
||||
echo '<p class="mt-4 text-muted">'.$L->g('There are no pages at this moment.').'</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<table class="table mt-3"><thead><tr>';
|
||||
echo '<th class="border-0" scope="col">'.$L->g('Title').'</th>';
|
||||
echo '<th class="border-0 d-none d-xl-table-cell" scope="col">'.$L->g('URL').'</th>';
|
||||
echo '<th class="border-0 text-center d-sm-table-cell" scope="col">'.$L->g('Actions').'</th>';
|
||||
echo '</tr></thead><tbody>';
|
||||
if (!empty($sticky) && $isFirstPage) {
|
||||
tableRows($sticky, 'sticky', true);
|
||||
}
|
||||
if (!empty($published)) {
|
||||
tableRows($published, 'published', false);
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<!-- TABS -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="pages-tab" data-toggle="tab" href="#pages" role="tab"><?php $L->p('Pages') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="static-tab" data-toggle="tab" href="#static" role="tab"><?php $L->p('Static') ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="scheduled-tab" data-toggle="tab" href="#scheduled" role="tab"><?php $L->p('Scheduled') ?> <?php if (count($scheduled)>0) { echo '<span class="badge badge-danger">'.count($scheduled).'</span>'; } ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="draft-tab" data-toggle="tab" href="#draft" role="tab"><?php $L->p('Draft') ?></a>
|
||||
</li>
|
||||
<?php if (!empty($autosave)): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="autosave-tab" data-toggle="tab" href="#autosave" role="tab"><?php $L->p('Autosave') ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<!-- TABS PAGES (includes sticky on top) -->
|
||||
<div class="tab-pane show active" id="pages" role="tabpanel">
|
||||
|
||||
<?php tablePages(); ?>
|
||||
|
||||
<?php if (Paginator::numberOfPages() > 1): ?>
|
||||
<!-- Paginator -->
|
||||
<nav class="paginator">
|
||||
<ul class="pagination flex-wrap justify-content-center">
|
||||
|
||||
<!-- First button -->
|
||||
<li class="page-item <?php if (!Paginator::showPrev()) echo 'disabled' ?>">
|
||||
<a class="page-link" href="<?php echo Paginator::firstPageUrl() ?>"><span class="align-middle fa fa-media-skip-backward"></span> <?php echo $L->get('First'); ?></a>
|
||||
</li>
|
||||
|
||||
<!-- Previous button -->
|
||||
<li class="page-item <?php if (!Paginator::showPrev()) echo 'disabled' ?>">
|
||||
<a class="page-link" href="<?php echo Paginator::previousPageUrl() ?>"><?php echo $L->get('Previous'); ?></a>
|
||||
</li>
|
||||
|
||||
<!-- Next button -->
|
||||
<li class="page-item <?php if (!Paginator::showNext()) echo 'disabled' ?>">
|
||||
<a class="page-link" href="<?php echo Paginator::nextPageUrl() ?>"><?php echo $L->get('Next'); ?></a>
|
||||
</li>
|
||||
|
||||
<!-- Last button -->
|
||||
<li class="page-item <?php if (!Paginator::showNext()) echo 'disabled' ?>">
|
||||
<a class="page-link" href="<?php echo Paginator::lastPageUrl() ?>"><?php echo $L->get('Last'); ?> <span class="align-middle fa fa-media-skip-forward"></span></a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS STATIC -->
|
||||
<div class="tab-pane" id="static" role="tabpanel">
|
||||
<?php table('static'); ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS SCHEDULED -->
|
||||
<div class="tab-pane" id="scheduled" role="tabpanel">
|
||||
<?php table('scheduled'); ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS DRAFT -->
|
||||
<div class="tab-pane" id="draft" role="tabpanel">
|
||||
<?php table('draft'); ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS AUTOSAVE -->
|
||||
<?php if (!empty($autosave)): ?>
|
||||
<div class="tab-pane" id="autosave" role="tabpanel">
|
||||
<?php table('autosave'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Modal for delete page -->
|
||||
<?php
|
||||
echo Bootstrap::modal(array(
|
||||
'buttonPrimary'=>$L->g('Delete'),
|
||||
'buttonPrimaryClass'=>'btn-danger deletePageModalAcceptButton',
|
||||
'buttonSecondary'=>$L->g('Cancel'),
|
||||
'buttonSecondaryClass'=>'btn-link',
|
||||
'modalTitle'=>$L->g('Delete content'),
|
||||
'modalText'=>$L->g('Are you sure you want to delete this page'),
|
||||
'modalId'=>'jsdeletePageModal'
|
||||
));
|
||||
?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var key = false;
|
||||
|
||||
// Button for delete a page in the table
|
||||
$(document).on("click", ".deletePageButton", function() {
|
||||
key = $(this).data('key');
|
||||
});
|
||||
|
||||
// Event from button accept from the modal
|
||||
$(".deletePageModalAcceptButton").on("click", function() {
|
||||
var currentTab = window.location.hash ? window.location.hash.substring(1) : 'pages';
|
||||
|
||||
var form = jQuery('<form>', {
|
||||
'action': HTML_PATH_ADMIN_ROOT+'edit-content/'+key,
|
||||
'method': 'post',
|
||||
'target': '_top'
|
||||
}).append(jQuery('<input>', {
|
||||
'type': 'hidden',
|
||||
'name': 'tokenCSRF',
|
||||
'value': tokenCSRF
|
||||
})).append(jQuery('<input>', {
|
||||
'type': 'hidden',
|
||||
'name': 'key',
|
||||
'value': key
|
||||
})).append(jQuery('<input>', {
|
||||
'type': 'hidden',
|
||||
'name': 'type',
|
||||
'value': 'delete'
|
||||
})).append(jQuery('<input>', {
|
||||
'type': 'hidden',
|
||||
'name': 'tab',
|
||||
'value': currentTab
|
||||
}));
|
||||
|
||||
form.hide().appendTo("body").submit();
|
||||
});
|
||||
|
||||
// Move-to: change page type via AJAX
|
||||
$(document).on("click", ".changeTypeButton", function(e) {
|
||||
e.preventDefault();
|
||||
var $btn = $(this);
|
||||
if ($btn.data('busy')) { return; }
|
||||
$btn.data('busy', true).css('opacity', 0.5);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/change-type",
|
||||
data: {
|
||||
tokenCSRF: tokenCSRF,
|
||||
key: $btn.data('key'),
|
||||
type: $btn.data('type')
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(response) {
|
||||
if (response && response.status === 0) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
$btn.data('busy', false).css('opacity', 1);
|
||||
alert((response && response.message) ? response.message : <?php echo json_encode($L->g('Failed to change type.')); ?>);
|
||||
}
|
||||
}).fail(function() {
|
||||
$btn.data('busy', false).css('opacity', 1);
|
||||
alert(<?php echo json_encode($L->g('Failed to change type.')); ?>);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Open the tab defined in the URL
|
||||
const anchor = window.location.hash;
|
||||
$(`a[href="${anchor}"]`).tab('show');
|
||||
</script>
|
||||
@@ -0,0 +1,352 @@
|
||||
<div id="dashboard" class="container">
|
||||
|
||||
<!-- Search with welcome message -->
|
||||
<?php
|
||||
$username = $login->username();
|
||||
$user = new User($username);
|
||||
$name = '';
|
||||
if ($user->nickname()) {
|
||||
$name = $user->nickname();
|
||||
} elseif ($user->firstName()) {
|
||||
$name = $user->firstName();
|
||||
}
|
||||
?>
|
||||
<div class="quick-search-trigger mb-4" id="searchTrigger">
|
||||
<div class="quick-search-icon">
|
||||
<span class="fa fa-hand-spock-o" id="hello-icon"></span>
|
||||
</div>
|
||||
<span class="quick-search-text">
|
||||
<span id="hello-text"><?php echo $L->g('welcome') . ($name ? ', ' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') : '') ?></span>
|
||||
<small class="quick-search-hint"><?php $L->p('click-here-for-quick-search') ?></small>
|
||||
</span>
|
||||
<span class="quick-search-shortcut">⌘K</span>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var date = new Date()
|
||||
var hours = date.getHours()
|
||||
var icon, greeting
|
||||
var suffix = <?php echo json_encode($name ? ', ' . $name : '', JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?>
|
||||
if (hours >= 6 && hours < 12) {
|
||||
icon = 'fa-sun-o'; greeting = <?php echo json_encode($L->g('good-morning'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?> + suffix
|
||||
} else if (hours >= 12 && hours < 18) {
|
||||
icon = 'fa-sun-o'; greeting = <?php echo json_encode($L->g('good-afternoon'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?> + suffix
|
||||
} else if (hours >= 18 && hours < 22) {
|
||||
icon = 'fa-moon-o'; greeting = <?php echo json_encode($L->g('good-evening'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?> + suffix
|
||||
} else {
|
||||
icon = 'fa-moon-o'; greeting = <?php echo json_encode($L->g('good-night'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?> + suffix
|
||||
}
|
||||
$('#hello-icon').attr('class', 'fa ' + icon)
|
||||
$('#hello-text').text(greeting)
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Quick Search Modal -->
|
||||
<div class="quick-search-modal" id="searchModal">
|
||||
<div class="quick-search-overlay" id="searchOverlay"></div>
|
||||
<div class="quick-search-content">
|
||||
<div class="quick-search-header">
|
||||
<span class="fa fa-search"></span>
|
||||
<input type="text" id="jsclippy" class="quick-search-input" placeholder="<?php $L->p('search-placeholder') ?>">
|
||||
</div>
|
||||
<div id="searchResults" class="quick-search-results"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var searchInput = $('#jsclippy');
|
||||
var searchResults = $('#searchResults');
|
||||
var modal = $('#searchModal');
|
||||
var trigger = $('#searchTrigger');
|
||||
var overlay = $('#searchOverlay');
|
||||
var searchTimeout;
|
||||
|
||||
function openSearch() {
|
||||
modal.addClass('active');
|
||||
$('body').css('overflow', 'hidden');
|
||||
setTimeout(function() {
|
||||
searchInput.focus();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
modal.removeClass('active');
|
||||
$('body').css('overflow', '');
|
||||
searchInput.val('');
|
||||
searchResults.empty();
|
||||
}
|
||||
|
||||
function performSearch(query) {
|
||||
if (!query) {
|
||||
searchResults.empty();
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/clippy",
|
||||
data: { query: query },
|
||||
success: function(data) {
|
||||
searchResults.empty();
|
||||
|
||||
if (data.results && data.results.length > 0) {
|
||||
data.results.forEach(function(item) {
|
||||
var resultHtml = '';
|
||||
if (item.type == 'menu') {
|
||||
resultHtml = '<a href="' + item.url + '" class="search-suggestion">';
|
||||
resultHtml += '<span class="fa fa-' + item.icon + '"></span>' + item.text + '</a>';
|
||||
} else {
|
||||
resultHtml = '<div class="search-suggestion">';
|
||||
resultHtml += '<div class="search-suggestion-item">' + item.text + ' <span class="badge badge-pill badge-light">' + item.type + '</span></div>';
|
||||
resultHtml += '<div class="search-suggestion-options">';
|
||||
resultHtml += '<a target="_blank" href="' + DOMAIN_PAGES + item.id + '"><?php $L->p('view') ?></a>';
|
||||
resultHtml += '<a class="ml-2" href="' + DOMAIN_ADMIN + 'edit-content/' + item.id + '"><?php $L->p('edit') ?></a>';
|
||||
resultHtml += '</div></div>';
|
||||
}
|
||||
searchResults.append(resultHtml);
|
||||
});
|
||||
} else {
|
||||
searchResults.html('<div class="search-no-results"><?php $L->p("no-results-found") ?></div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
searchInput.on('input', function() {
|
||||
clearTimeout(searchTimeout);
|
||||
var query = $(this).val();
|
||||
searchTimeout = setTimeout(function() {
|
||||
performSearch(query);
|
||||
}, 300);
|
||||
});
|
||||
|
||||
trigger.on('click', openSearch);
|
||||
overlay.on('click', closeSearch);
|
||||
|
||||
$(document).on('keydown', function(e) {
|
||||
if (e.key === 'Escape' && modal.hasClass('active')) {
|
||||
closeSearch();
|
||||
}
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
openSearch();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Dashboard Metric Cards -->
|
||||
<div class="container px-0">
|
||||
<div class="row">
|
||||
|
||||
<!-- Content Metrics Card -->
|
||||
<div class="col-lg col-12 mb-4">
|
||||
<div class="card metric-card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<h5 class="card-title mb-0"><?php $L->p('Content') ?></h5>
|
||||
</div>
|
||||
<div class="mt-3 metric-card-list">
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="<?php echo HTML_PATH_ADMIN_ROOT.'content' ?>" class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span><?php $L->p('Published') ?></span>
|
||||
<span class="badge badge-primary badge-pill"><?php echo count($pages->getPublishedDB()); ?></span>
|
||||
</a>
|
||||
<a href="<?php echo HTML_PATH_ADMIN_ROOT.'content#draft' ?>" class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span><?php $L->p('Drafts') ?></span>
|
||||
<span class="badge badge-primary badge-pill"><?php echo count($pages->getDraftDB()); ?></span>
|
||||
</a>
|
||||
<a href="<?php echo HTML_PATH_ADMIN_ROOT.'content#scheduled' ?>" class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span><?php $L->p('Scheduled') ?></span>
|
||||
<span class="badge badge-primary badge-pill"><?php echo count($pages->getScheduledDB()); ?></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php
|
||||
// Categories Card - Only show if Categories plugin is active
|
||||
if (pluginActivated('pluginCategories')) {
|
||||
$categoryList = $categories->keys();
|
||||
?>
|
||||
<!-- Categories Card -->
|
||||
<div class="col-lg col-12 mb-4">
|
||||
<div class="card metric-card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<h5 class="card-title mb-0"><?php $L->p('Categories') ?></h5>
|
||||
</div>
|
||||
<div class="mt-3 metric-card-list">
|
||||
<?php if (!empty($categoryList)): ?>
|
||||
<div class="list-group list-group-flush">
|
||||
<?php foreach ($categoryList as $categoryKey):
|
||||
$category = new Category($categoryKey);
|
||||
$pageCount = count($category->pages());
|
||||
?>
|
||||
<a href="<?php echo HTML_PATH_ADMIN_ROOT . 'edit-category/' . $categoryKey ?>" class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span><?php echo $category->name() ?></span>
|
||||
<span class="badge badge-primary badge-pill"><?php echo $pageCount ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p class="text-muted text-center py-3"><?php $L->p('No categories') ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
// Tags Card - Only show if Tags plugin is active
|
||||
if (pluginActivated('pluginTags')) {
|
||||
$tagList = $tags->keys();
|
||||
?>
|
||||
<!-- Tags Card -->
|
||||
<div class="col-lg col-12 mb-4">
|
||||
<div class="card metric-card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<h5 class="card-title mb-0"><?php $L->p('Tags') ?></h5>
|
||||
</div>
|
||||
<div class="mt-3 metric-card-list">
|
||||
<?php if (!empty($tagList)): ?>
|
||||
<div class="list-group list-group-flush">
|
||||
<?php foreach ($tagList as $tagKey):
|
||||
$tag = new Tag($tagKey);
|
||||
$pageCount = count($tag->pages());
|
||||
?>
|
||||
<a href="<?php echo HTML_PATH_ADMIN_ROOT . 'content/tag/' . $tagKey ?>" class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span><?php echo $tag->name() ?></span>
|
||||
<span class="badge badge-primary badge-pill"><?php echo $pageCount ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p class="text-muted text-center py-3"><?php $L->p('No tags') ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Analytics Section - Only show if Visits Stats plugin is active
|
||||
$visitsStats = getPlugin('pluginVisitsStats');
|
||||
if ($visitsStats && $visitsStats->installed()):
|
||||
$currentDate = Date::current('Y-m-d');
|
||||
$visitsToday = $visitsStats->visits($currentDate);
|
||||
$uniqueVisitors = $visitsStats->uniqueVisitors($currentDate);
|
||||
$weekData = $visitsStats->getLastDaysData(7);
|
||||
?>
|
||||
<!-- Analytics Section -->
|
||||
<div class="analytics-section mb-4">
|
||||
<ul class="list-group list-group-striped b-0 mb-3">
|
||||
<li class="list-group-item">
|
||||
<h4 class="m-0"><?php $L->p('Analytics') ?></h4>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-3 col-12 mb-3 mb-lg-0">
|
||||
<div class="row text-center">
|
||||
<div class="col-4 col-lg-12 mb-0 mb-lg-4">
|
||||
<div class="metric-value"><?php echo $visitsToday; ?></div>
|
||||
<div class="metric-label"><?php $L->p('Visits Today') ?></div>
|
||||
</div>
|
||||
<div class="col-4 col-lg-12 mb-0 mb-lg-4">
|
||||
<div class="metric-value"><?php echo $uniqueVisitors; ?></div>
|
||||
<div class="metric-label"><?php $L->p('Unique Visitors') ?></div>
|
||||
</div>
|
||||
<div class="col-4 col-lg-12">
|
||||
<div class="metric-value"><?php echo $weekData['total']; ?></div>
|
||||
<div class="metric-label"><?php $L->p('7-Day Total') ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 col-12">
|
||||
<canvas id="analytics-chart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
var ctx = document.getElementById('analytics-chart');
|
||||
if (!ctx || typeof Chart === 'undefined') { return; }
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?php echo json_encode($weekData['labels']); ?>,
|
||||
datasets: [{
|
||||
label: <?php echo json_encode($L->g('unique-visitors'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?>,
|
||||
backgroundColor: 'rgba(0,120,212,0.45)',
|
||||
borderColor: 'rgba(0,120,212,0.75)',
|
||||
borderWidth: 1,
|
||||
data: <?php echo json_encode($weekData['unique']); ?>
|
||||
}, {
|
||||
label: <?php echo json_encode($L->g('visits-today'), JSON_HEX_TAG | JSON_UNESCAPED_UNICODE) ?>,
|
||||
backgroundColor: 'rgba(148,163,184,0.5)',
|
||||
borderColor: 'rgba(100,116,139,0.8)',
|
||||
borderWidth: 1,
|
||||
data: <?php echo json_encode($weekData['visits']); ?>
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
aspectRatio: 4,
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
labels: { fontSize: 11, boxWidth: 12, fontColor: '#475569' }
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: { beginAtZero: true, stepSize: 1, fontColor: '#94A3B8', fontSize: 11 },
|
||||
gridLines: { color: 'rgba(0,0,0,0.05)', zeroLineColor: 'rgba(0,0,0,0.1)' }
|
||||
}],
|
||||
xAxes: [{
|
||||
ticks: { fontColor: '#94A3B8', fontSize: 11 },
|
||||
gridLines: { display: false }
|
||||
}]
|
||||
},
|
||||
tooltips: { mode: 'index', intersect: false }
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Notifications -->
|
||||
<div class="mt-4">
|
||||
<ul class="list-group list-group-striped b-0">
|
||||
<li class="list-group-item">
|
||||
<h4 class="m-0"><?php $L->p('Notifications') ?></h4>
|
||||
</li>
|
||||
<?php
|
||||
$logs = array_slice($syslog->db, 0, NOTIFICATIONS_AMOUNT);
|
||||
foreach ($logs as $log) {
|
||||
$phrase = $L->g($log['dictionaryKey']);
|
||||
echo '<li class="list-group-item">';
|
||||
echo $phrase;
|
||||
if (!empty($log['notes'])) {
|
||||
echo ' « <b>' . htmlspecialchars($log['notes'], ENT_QUOTES, 'UTF-8') . '</b> »';
|
||||
}
|
||||
echo '<br><span class="notification-date"><small>';
|
||||
echo Date::format($log['date'], DB_DATE_FORMAT, NOTIFICATIONS_DATE_FORMAT);
|
||||
echo ' [ ' . htmlspecialchars($log['username'], ENT_QUOTES, 'UTF-8') . ' ]';
|
||||
echo '</small></span>';
|
||||
echo '</li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title'=>$L->g('Developers'), 'icon'=>'gears'));
|
||||
|
||||
echo '<h2 class="mb-4 mt-4"><b>PHP version: '.phpversion().'</b></h2>';
|
||||
|
||||
// PHP Ini
|
||||
$uploadOptions = array(
|
||||
'upload_max_filesize'=>ini_get('upload_max_filesize'),
|
||||
'post_max_size'=>ini_get('post_max_size'),
|
||||
'upload_tmp_dir'=>ini_get('upload_tmp_dir')
|
||||
);
|
||||
printTable('File Uploads', $uploadOptions);
|
||||
|
||||
// Loaded extensions
|
||||
printTable('Server information ( $_SERVER )', $_SERVER);
|
||||
|
||||
// PHP Ini
|
||||
printTable('PHP Configuration options ( ini_get_all() )', ini_get_all());
|
||||
|
||||
// Loaded extensions
|
||||
printTable('Loaded extensions',get_loaded_extensions());
|
||||
|
||||
// Locales installed
|
||||
exec('locale -a', $locales);
|
||||
printTable('Locales installed', $locales);
|
||||
|
||||
echo '<hr>';
|
||||
echo '<h2>BLUDIT</h2>';
|
||||
echo '<hr>';
|
||||
|
||||
// Constanst defined by Bludit
|
||||
$constants = get_defined_constants(true);
|
||||
printTable('Bludit Constants', $constants['user']);
|
||||
|
||||
// Site object
|
||||
printTable('$site object database',$site->db);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#jsdeleteModal"><?php $L->p('Delete') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'dashboard' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('Edit Category'), 'icon'=>'cog')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'action',
|
||||
'value'=>'edit'
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'oldKey',
|
||||
'value'=>$categoryMap['key']
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'name',
|
||||
'label'=>$L->g('Name'),
|
||||
'value'=>$categoryMap['name'],
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formTextarea(array(
|
||||
'name'=>'description',
|
||||
'label'=>$L->g('Description'),
|
||||
'value'=>isset($categoryMap['description'])?$categoryMap['description']:'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>'',
|
||||
'rows'=>3
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'template',
|
||||
'label'=>$L->g('Template'),
|
||||
'value'=>isset($categoryMap['template'])?$categoryMap['template']:'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'newKey',
|
||||
'label'=>$L->g('Friendly URL'),
|
||||
'value'=>$categoryMap['key'],
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>DOMAIN_CATEGORIES.$categoryMap['key']
|
||||
));
|
||||
|
||||
echo Bootstrap::formClose();
|
||||
|
||||
?>
|
||||
|
||||
<!-- Modal for delete category -->
|
||||
<?php
|
||||
echo Bootstrap::modal(array(
|
||||
'buttonPrimary'=>$L->g('Delete'),
|
||||
'buttonPrimaryClass'=>'btn-danger jsbuttonDeleteAccept',
|
||||
'buttonSecondary'=>$L->g('Cancel'),
|
||||
'buttonSecondaryClass'=>'btn-link',
|
||||
'modalTitle'=>$L->g('Delete category'),
|
||||
'modalText'=>$L->g('Are you sure you want to delete this category?'),
|
||||
'modalId'=>'jsdeleteModal'
|
||||
));
|
||||
?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Delete content
|
||||
$(".jsbuttonDeleteAccept").on("click", function() {
|
||||
$("#jsaction").val("delete");
|
||||
$("#jsform").submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,564 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php
|
||||
|
||||
// FORM START
|
||||
echo Bootstrap::formOpen(array(
|
||||
'id' => 'jsform',
|
||||
'class' => 'd-flex flex-column h-100'
|
||||
));
|
||||
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'tokenCSRF',
|
||||
'value' => $security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// UUID
|
||||
// The UUID is generated in the controller
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'uuid',
|
||||
'value' => $page->uuid()
|
||||
));
|
||||
|
||||
// Type = published, draft, sticky, static
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'type',
|
||||
'value' => $page->type()
|
||||
));
|
||||
|
||||
// Cover image
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'coverImage',
|
||||
'value' => $page->coverImage(false)
|
||||
));
|
||||
|
||||
// Content
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'content',
|
||||
'value' => ''
|
||||
));
|
||||
|
||||
// Current page key
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'key',
|
||||
'value' => $page->key()
|
||||
));
|
||||
?>
|
||||
|
||||
<!-- TOOLBAR -->
|
||||
<div id="jseditorToolbar" class="mb-1">
|
||||
<div id="jseditorToolbarRight" class="btn-group btn-group-sm float-right" role="group" aria-label="Toolbar right">
|
||||
<button type="button" class="btn btn-light" id="jsmediaManagerOpenModal" data-toggle="modal" data-target="#jsmediaManagerModal"><span class="fa fa-image"></span> <?php $L->p('Images') ?></button>
|
||||
<?php Theme::plugins('editorToolbar') ?>
|
||||
<button type="button" class="btn btn-light" id="jsoptionsSidebar" style="z-index:30"><span class="fa fa-cog"></span> <?php $L->p('Options') ?></button>
|
||||
</div>
|
||||
|
||||
<div id="jseditorToolbarLeft">
|
||||
<button type="button" class="btn btn-sm btn-primary" id="jsbuttonSave"><?php echo $L->g('Save') ?></button>
|
||||
<button id="jsbuttonPreview" type="button" class="btn btn-sm btn-secondary"><?php $L->p('Preview') ?></button>
|
||||
<span id="jsswitchButton" data-switch="<?php echo ($page->draft() ? 'draft' : 'publish') ?>" class="ml-2 text-secondary switch-button"><i class="fa fa-square switch-icon-<?php echo ($page->draft() ? 'draft' : 'publish') ?>"></i> <?php echo ($page->draft() ? $L->g('Draft') : $L->g('Publish')) ?></span>
|
||||
</div>
|
||||
|
||||
<?php if ($page->scheduled()) : ?>
|
||||
<div class="alert alert-warning p-1 mt-1 mb-0"><?php $L->p('scheduled') ?>: <?php echo $page->date(SCHEDULED_DATE_FORMAT) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#jsoptionsSidebar").on("click", function() {
|
||||
$("#jseditorSidebar").toggle();
|
||||
$("#jsshadow").toggle();
|
||||
});
|
||||
|
||||
$("#jsshadow").on("click", function() {
|
||||
$("#jseditorSidebar").toggle();
|
||||
$("#jsshadow").toggle();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- SIDEBAR OPTIONS -->
|
||||
<div id="jseditorSidebar">
|
||||
<nav>
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
<a class="nav-link active show" id="nav-general-tab" data-toggle="tab" href="#nav-general" role="tab" aria-controls="general"><?php $L->p('General') ?></a>
|
||||
<a class="nav-link" id="nav-advanced-tab" data-toggle="tab" href="#nav-advanced" role="tab" aria-controls="advanced"><?php $L->p('Advanced') ?></a>
|
||||
<?php if (!empty($site->customFields())) : ?>
|
||||
<a class="nav-link" id="nav-custom-tab" data-toggle="tab" href="#nav-custom" role="tab" aria-controls="custom"><?php $L->p('Custom') ?></a>
|
||||
<?php endif ?>
|
||||
<a class="nav-link" id="nav-seo-tab" data-toggle="tab" href="#nav-seo" role="tab" aria-controls="seo"><?php $L->p('SEO') ?></a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="tab-content pr-3 pl-3 pb-3">
|
||||
<div id="nav-general" class="tab-pane fade show active" role="tabpanel" aria-labelledby="general-tab">
|
||||
<?php
|
||||
// Category
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'category',
|
||||
'label' => $L->g('Category'),
|
||||
'selected' => $page->categoryKey(),
|
||||
'class' => '',
|
||||
'emptyOption' => '- ' . $L->g('Uncategorized') . ' -',
|
||||
'options' => $categories->getKeyNameArray()
|
||||
));
|
||||
|
||||
// Description
|
||||
echo Bootstrap::formTextareaBlock(array(
|
||||
'name' => 'description',
|
||||
'label' => $L->g('Description'),
|
||||
'selected' => '',
|
||||
'class' => '',
|
||||
'value' => $page->description(),
|
||||
'rows' => 5,
|
||||
'placeholder' => $L->get('this-field-can-help-describe-the-content')
|
||||
));
|
||||
?>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php
|
||||
$coverImage = $page->coverImage(false);
|
||||
$externalCoverImage = '';
|
||||
if (filter_var($coverImage, FILTER_VALIDATE_URL)) {
|
||||
$coverImage = '';
|
||||
$externalCoverImage = $page->coverImage(false);
|
||||
}
|
||||
?>
|
||||
<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100"><?php $L->p('Cover Image') ?></label>
|
||||
<div>
|
||||
<img id="jscoverImagePreview" class="mx-auto d-block w-100" alt="Cover image preview" src="<?php echo (empty($coverImage) ? HTML_PATH_CORE_IMG . 'default.svg' : $page->coverImage()) ?>" />
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<button type="button" id="jsbuttonSelectCoverImage" class="btn btn-primary btn-sm"><?php echo $L->g('Select cover image') ?></button>
|
||||
<button type="button" id="jsbuttonRemoveCoverImage" class="btn btn-secondary btn-sm"><?php echo $L->g('Remove cover image') ?></button>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#jscoverImagePreview").on("click", function() {
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
$("#jsbuttonSelectCoverImage").on("click", function() {
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
$("#jsbuttonRemoveCoverImage").on("click", function() {
|
||||
$("#jscoverImage").val('');
|
||||
$("#jscoverImagePreview").attr('src', HTML_PATH_CORE_IMG + 'default.svg');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div id="nav-advanced" class="tab-pane fade" role="tabpanel" aria-labelledby="advanced-tab">
|
||||
<?php
|
||||
// Date
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'date',
|
||||
'label' => $L->g('Date'),
|
||||
'placeholder' => '',
|
||||
'value' => $page->dateRaw(),
|
||||
'tip' => $L->g('date-format-format')
|
||||
));
|
||||
|
||||
// Type
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'typeSelector',
|
||||
'label' => $L->g('Type'),
|
||||
'selected' => $page->type(),
|
||||
'options' => array(
|
||||
'published' => '- ' . $L->g('Default') . ' -',
|
||||
'sticky' => $L->g('Sticky'),
|
||||
'static' => $L->g('Static')
|
||||
),
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
// Position
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'position',
|
||||
'label' => $L->g('Position'),
|
||||
'tip' => $L->g('Field used when ordering content by position'),
|
||||
'value' => $page->position()
|
||||
));
|
||||
|
||||
// Tags
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'tags',
|
||||
'label' => $L->g('Tags'),
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Write the tags separated by commas'),
|
||||
'value' => $page->tags()
|
||||
));
|
||||
|
||||
// Parent
|
||||
try {
|
||||
$options = array();
|
||||
$parentKey = $page->parent();
|
||||
if (!empty($parentKey)) {
|
||||
$parent = new Page($parentKey);
|
||||
$options = array($parentKey => $parent->title());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'parent',
|
||||
'label' => $L->g('Parent'),
|
||||
'options' => $options,
|
||||
'selected' => false,
|
||||
'class' => '',
|
||||
'tip' => $L->g('Start typing a page title to see a list of suggestions.'),
|
||||
));
|
||||
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var parent = $("#jsparent").select2({
|
||||
placeholder: "",
|
||||
allowClear: true,
|
||||
theme: "bootstrap4",
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/get-published",
|
||||
data: function(params) {
|
||||
var query = {
|
||||
checkIsParent: true,
|
||||
query: params.term
|
||||
}
|
||||
return query;
|
||||
},
|
||||
processResults: function(data) {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
escapeMarkup: function(markup) {
|
||||
return markup;
|
||||
},
|
||||
templateResult: function(data) {
|
||||
var html = data.text
|
||||
if (data.type == "static") {
|
||||
html += '<span class="badge badge-pill badge-light">' + data.type + '</span>';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
// Template
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'template',
|
||||
'label' => $L->g('Template'),
|
||||
'placeholder' => '',
|
||||
'value' => $page->template(),
|
||||
'tip' => $L->g('Write a template name to filter the page in the theme and change the style of the page.')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'externalCoverImage',
|
||||
'label' => $L->g('External cover image'),
|
||||
'placeholder' => "https://",
|
||||
'value' => $externalCoverImage,
|
||||
'tip' => $L->g('Set a cover image from external URL, such as a CDN or some server dedicated for images.')
|
||||
));
|
||||
|
||||
// Username
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => '',
|
||||
'label' => $L->g('Author'),
|
||||
'placeholder' => '',
|
||||
'value' => $page->username(),
|
||||
'tip' => '',
|
||||
'disabled' => true
|
||||
));
|
||||
?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Changes in External cover image input
|
||||
$("#jsexternalCoverImage").change(function() {
|
||||
$("#jscoverImage").val($(this).val());
|
||||
});
|
||||
|
||||
// Datepicker
|
||||
$("#jsdate").datetimepicker({
|
||||
format: DB_DATE_FORMAT
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($site->customFields())) : ?>
|
||||
<div id="nav-custom" class="tab-pane fade" role="tabpanel" aria-labelledby="custom-tab">
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (!isset($options['position'])) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'value' => (isset($options['default']) ? $options['default'] : ''),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'value' => $page->custom($field)
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => $page->custom($field),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : '')
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div id="nav-seo" class="tab-pane fade" role="tabpanel" aria-labelledby="seo-tab">
|
||||
<?php
|
||||
// Friendly URL
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'slug',
|
||||
'tip' => $L->g('URL associated with the content'),
|
||||
'label' => $L->g('Friendly URL'),
|
||||
'placeholder' => $L->g('Leave empty for autocomplete by Bludit.'),
|
||||
'value' => $page->slug()
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'noindex',
|
||||
'label' => 'Robots',
|
||||
'labelForCheckbox' => $L->g('apply-code-noindex-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => $page->noindex(),
|
||||
'tip' => $L->g('This tells search engines not to show this page in their search results.')
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'nofollow',
|
||||
'label' => '',
|
||||
'labelForCheckbox' => $L->g('apply-code-nofollow-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => $page->nofollow(),
|
||||
'tip' => $L->g('This tells search engines not to follow links on this page.')
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'noarchive',
|
||||
'label' => '',
|
||||
'labelForCheckbox' => $L->g('apply-code-noarchive-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => $page->noarchive(),
|
||||
'tip' => $L->g('This tells search engines not to save a cached copy of this page.')
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom fields: TOP -->
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (isset($options['position']) && ($options['position'] == 'top')) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'value' => $page->custom($field),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'class' => 'mb-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => $page->custom($field),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'class' => 'mb-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Title -->
|
||||
<div class="form-group mb-1">
|
||||
<input id="jstitle" name="title" type="text" dir="auto" class="form-control form-control-lg rounded-0" value="<?php echo $page->title() ?>" placeholder="<?php $L->p('Enter title') ?>">
|
||||
</div>
|
||||
|
||||
<!-- Editor -->
|
||||
<textarea id="jseditor" class="editable h-100" style=""><?php echo $page->contentRaw(true) ?></textarea>
|
||||
|
||||
<!-- Custom fields: BOTTOM -->
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (isset($options['position']) && ($options['position'] == 'bottom')) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'value' => $page->custom($field),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'class' => 'mt-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => $page->custom($field),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'class' => 'mt-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal for Delete page -->
|
||||
<div id="jsdeletePageModal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<h3><?php $L->p('Delete content') ?></h3>
|
||||
<p><?php $L->p('Are you sure you want to delete this page') ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link" data-dismiss="modal"><?php $L->p('Cancel') ?></button>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal" id="jsbuttonDeleteAccept"><?php $L->p('Delete') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#jsbuttonDeleteAccept").on("click", function() {
|
||||
$("#jstype").val("delete");
|
||||
$("#jscontent").val("");
|
||||
$("#jsform").submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<!-- Modal for Media Manager -->
|
||||
<?php include(PATH_ADMIN_THEMES . 'booty/html/media.php'); ?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
// Define function if they don't exist
|
||||
// This helps if the user doesn't activate any plugin as editor
|
||||
if (typeof editorGetContent != "function") {
|
||||
window.editorGetContent = function() {
|
||||
return $("#jseditor").val();
|
||||
};
|
||||
}
|
||||
if (typeof editorInsertMedia != "function") {
|
||||
window.editorInsertMedia = function(filename) {
|
||||
$("#jseditor").val($('#jseditor').val() + '<img src="' + filename + '" alt="">');
|
||||
};
|
||||
}
|
||||
if (typeof editorInsertLinkedMedia != "function") {
|
||||
window.editorInsertLinkedMedia = function(filename, link) {
|
||||
$("#jseditor").val($('#jseditor').val() + '<a href="' + link + '"><img src="' + filename + '" alt=""></a>');
|
||||
};
|
||||
}
|
||||
|
||||
// Button switch
|
||||
$("#jsswitchButton").on("click", function() {
|
||||
if ($(this).data("switch") == "publish") {
|
||||
$(this).html('<i class="fa fa-square switch-icon-draft"></i> <?php $L->p('Draft') ?>');
|
||||
$(this).data("switch", "draft");
|
||||
} else {
|
||||
$(this).html('<i class="fa fa-square switch-icon-publish"></i> <?php $L->p('Publish') ?>');
|
||||
$(this).data("switch", "publish");
|
||||
}
|
||||
});
|
||||
|
||||
// Button preview
|
||||
$("#jsbuttonPreview").on("click", function() {
|
||||
var uuid = $("#jsuuid").val();
|
||||
var title = $("#jstitle").val();
|
||||
var content = editorGetContent();
|
||||
var ajax = new bluditAjax();
|
||||
bluditAjax.saveAsDraft(uuid, title, content).then(function(data) {
|
||||
var preview = window.open("<?php echo DOMAIN_PAGES . 'autosave-' . $page->uuid() . '?preview=' . hash_hmac('sha256', 'autosave-' . $page->uuid(), DB_SITE) ?>", "bludit-preview");
|
||||
preview.focus();
|
||||
});
|
||||
});
|
||||
|
||||
// Button Save
|
||||
$("#jsbuttonSave").on("click", function() {
|
||||
// If the switch is setted to "published", get the value from the selector
|
||||
if ($("#jsswitchButton").data("switch") == "publish") {
|
||||
var value = $("#jstypeSelector option:selected").val();
|
||||
$("#jstype").val(value);
|
||||
} else {
|
||||
$("#jstype").val("draft");
|
||||
}
|
||||
|
||||
// Get the content
|
||||
$("#jscontent").val(editorGetContent());
|
||||
|
||||
// Submit the form
|
||||
$("#jsform").submit();
|
||||
});
|
||||
|
||||
// Button Save as draft
|
||||
$("#jsbuttonDraft").on("click", function() {
|
||||
// Set the type as draft
|
||||
$("#jstype").val("draft");
|
||||
|
||||
// Get the content
|
||||
$("#jscontent").val(editorGetContent());
|
||||
|
||||
// Submit the form
|
||||
$("#jsform").submit();
|
||||
});
|
||||
|
||||
// Autosave
|
||||
var currentContent = editorGetContent();
|
||||
setInterval(function() {
|
||||
var uuid = $("#jsuuid").val();
|
||||
var title = $("#jstitle").val() + "[<?php $L->p('Autosave') ?>]";
|
||||
var content = editorGetContent();
|
||||
// Autosave when content has at least 100 characters
|
||||
if (content.length < 100) {
|
||||
return false;
|
||||
}
|
||||
// Autosave only when the user change the content
|
||||
if (currentContent != content) {
|
||||
currentContent = content;
|
||||
bluditAjax.saveAsDraft(uuid, title, content).then(function(data) {
|
||||
if (data.status == 0) {
|
||||
showAlert("<?php $L->p('Autosave') ?>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 1000 * 60 * AUTOSAVE_INTERVAL);
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,334 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id' => 'jsform', 'class' => 'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT . 'users' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title' => $L->g('Edit user'), 'icon' => 'user')); ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS -->
|
||||
<nav class="mb-3">
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
<a class="nav-item nav-link active" id="nav-profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="nav-profile" aria-selected="false"><?php $L->p('Profile') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-picture-tab" data-toggle="tab" href="#picture" role="tab" aria-controls="nav-picture" aria-selected="false"><?php $L->p('Profile picture') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-security-tab" data-toggle="tab" href="#security" role="tab" aria-controls="nav-security" aria-selected="false"><?php $L->p('Security') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-social-tab" data-toggle="tab" href="#social" role="tab" aria-controls="nav-social" aria-selected="false"><?php $L->p('Social Networks') ?></a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'tokenCSRF',
|
||||
'value' => $security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// Username
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'username',
|
||||
'value' => $user->username()
|
||||
));
|
||||
?>
|
||||
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
<!-- Profile tab -->
|
||||
<div class="tab-pane fade show active" id="profile" role="tabpanel" aria-labelledby="nav-profile-tab">
|
||||
<?php
|
||||
// Display username but disable the field
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'usernameDisabled',
|
||||
'label' => $L->g('Username'),
|
||||
'value' => $user->username(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'disabled' => true,
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
if ($login->role() === 'admin') {
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'role',
|
||||
'label' => $L->g('Role'),
|
||||
'options' => array('author' => $L->g('Author'), 'editor' => $L->g('Editor'), 'admin' => $L->g('Administrator')),
|
||||
'selected' => $user->role(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('author-can-write-and-edit-their-own-content')
|
||||
));
|
||||
}
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'email',
|
||||
'label' => $L->g('Email'),
|
||||
'value' => $user->email(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'nickname',
|
||||
'label' => $L->g('Nickname'),
|
||||
'value' => $user->nickname(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('The nickname is almost used in the themes to display the author of the content')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'firstName',
|
||||
'label' => $L->g('First Name'),
|
||||
'value' => $user->firstName(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'lastName',
|
||||
'label' => $L->g('Last Name'),
|
||||
'value' => $user->lastName(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Profile picture tab -->
|
||||
<div class="tab-pane fade" id="picture" role="tabpanel" aria-labelledby="nav-picture-tab">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-sm-12 p-0 pr-2">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="jsprofilePictureInputFile" name="profilePictureInputFile">
|
||||
<label class="custom-file-label" for="jsprofilePictureInputFile"><?php $L->p('Upload image'); ?></label>
|
||||
</div>
|
||||
<!-- <button id="jsbuttonRemovePicture" type="button" class="btn btn-primary w-100 mt-4 mb-4"><i class="fa fa-trash"></i> Remove picture</button> -->
|
||||
</div>
|
||||
<div class="col-lg-8 col-sm-12 p-0 text-center">
|
||||
<img id="jsprofilePicturePreview" class="img-fluid img-thumbnail" alt="Profile picture preview" src="<?php echo (Sanitize::pathFile(PATH_UPLOADS_PROFILES . $user->username() . '.png') ? DOMAIN_UPLOADS_PROFILES . $user->username() . '.png?version=' . time() : HTML_PATH_CORE_IMG . 'default.svg') ?>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// $("#jsbuttonRemovePicture").on("click", function() {
|
||||
// var username = $("#jsusername").val();
|
||||
// bluditAjax.removeProfilePicture(username);
|
||||
// $("#jsprofilePicturePreview").attr("src", "<?php echo HTML_PATH_CORE_IMG . 'default.svg' ?>");
|
||||
// });
|
||||
|
||||
$("#jsprofilePictureInputFile").on("change", function() {
|
||||
var formData = new FormData();
|
||||
formData.append('tokenCSRF', tokenCSRF);
|
||||
formData.append('profilePictureInputFile', $(this)[0].files[0]);
|
||||
formData.append('username', $("#jsusername").val());
|
||||
$.ajax({
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/profile-picture-upload",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false
|
||||
}).done(function(data) {
|
||||
if (data.status == 0) {
|
||||
$("#jsprofilePicturePreview").attr('src', data.absoluteURL + "?time=" + Math.random());
|
||||
} else {
|
||||
showAlert(data.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<!-- Security tab -->
|
||||
<div class="tab-pane fade" id="security" role="tabpanel" aria-labelledby="nav-security-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Password')));
|
||||
|
||||
echo '
|
||||
<div class="form-group">
|
||||
<a href="' . HTML_PATH_ADMIN_ROOT . 'user-password/' . $user->username() . '" class="btn btn-primary mr-2">' . $L->g('Change password') . '</a>
|
||||
</div>
|
||||
';
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Authentication Token')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'tokenAuth',
|
||||
'label' => $L->g('Token'),
|
||||
'value' => $user->tokenAuth(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('this-token-is-similar-to-a-password-it-should-not-be-shared')
|
||||
));
|
||||
|
||||
if (checkRole(array('admin'), false)) {
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Status')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'status',
|
||||
'label' => $L->g('Current status'),
|
||||
'value' => $user->enabled() ? $L->g('Enabled') : $L->g('Disabled'),
|
||||
'class' => '',
|
||||
'disabled' => true,
|
||||
'tip' => $user->enabled() ? '' : $L->g('To enable the user you must set a new password')
|
||||
));
|
||||
|
||||
if ($user->enabled()) {
|
||||
echo '
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-warning mr-2" id="jsdisableUser" name="disableUser">' . $L->g('Disable user') . '</button>
|
||||
<button type="submit" class="btn btn-danger mr-2" id="jsdeleteUserAndKeepContent" name="deleteUserAndKeepContent">' . $L->g('Delete user and keep content') . '</button>
|
||||
<button type="submit" class="btn btn-danger mr-2" id="jsdeleteUserAndDeleteContent" name="deleteUserAndDeleteContent">' . $L->g('Delete user and delete content') . '</button>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Social Networks tab -->
|
||||
<div class="tab-pane fade" id="social" role="tabpanel" aria-labelledby="nav-social-tab">
|
||||
<?php
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'twitter',
|
||||
'label' => 'Twitter',
|
||||
'value' => $user->twitter(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'facebook',
|
||||
'label' => 'Facebook',
|
||||
'value' => $user->facebook(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'codepen',
|
||||
'label' => 'CodePen',
|
||||
'value' => $user->codepen(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'instagram',
|
||||
'label' => 'Instagram',
|
||||
'value' => $user->instagram(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'gitlab',
|
||||
'label' => 'GitLab',
|
||||
'value' => $user->gitlab(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'github',
|
||||
'label' => 'GitHub',
|
||||
'value' => $user->github(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'linkedin',
|
||||
'label' => 'LinkedIn',
|
||||
'value' => $user->linkedin(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'xing',
|
||||
'label' => 'Xing',
|
||||
'value' => $user->xing(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'telegram',
|
||||
'label' => 'Telegram',
|
||||
'value' => $user->telegram(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'mastodon',
|
||||
'label' => 'Mastodon',
|
||||
'value' => $user->mastodon(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'vk',
|
||||
'label' => 'VK',
|
||||
'value' => $user->vk(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'youtube',
|
||||
'label' => 'Youtube',
|
||||
'value' => $user->youtube(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'bluesky',
|
||||
'label' => 'Bluesky',
|
||||
'value' => $user->bluesky(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
|
||||
<script>
|
||||
// Open current tab after refresh page
|
||||
$(function() {
|
||||
$('a[data-toggle="tab"]').on('click', function(e) {
|
||||
window.localStorage.setItem('activeTab', $(e.target).attr('href'));
|
||||
console.log($(e.target).attr('href'));
|
||||
});
|
||||
var activeTab = window.localStorage.getItem('activeTab');
|
||||
if (activeTab) {
|
||||
$('#nav-tab a[href="' + activeTab + '"]').tab('show');
|
||||
//window.localStorage.removeItem("activeTab");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Logo and title
|
||||
$logoPath = HTML_PATH_CORE_IMG . 'logo.svg';
|
||||
$logoClass = 'logo-icon';
|
||||
if (defined('BLUDIT_PRO') && $site->logo(false)) {
|
||||
$logoPath = $site->logo(true);
|
||||
$logoClass = 'logo-icon custom-logo';
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="login-logo">
|
||||
<div class="' . $logoClass . '">
|
||||
<img src="' . $logoPath . '" alt="Logo">
|
||||
</div>
|
||||
<h1>' . (defined('BLUDIT_PRO') ? Sanitize::html($site->title()) : 'BLUDIT') . '</h1>
|
||||
</div>
|
||||
';
|
||||
|
||||
echo Bootstrap::formOpen(array());
|
||||
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'tokenCSRF',
|
||||
'value' => $security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// Username field with icon
|
||||
echo '
|
||||
<div class="form-group">
|
||||
<label for="jsusername">' . $L->g('Username') . '</label>
|
||||
<div class="input-icon-wrapper">
|
||||
<input type="text"
|
||||
dir="auto"
|
||||
value="' . (isset($_POST['username']) ? Sanitize::html($_POST['username']) : '') . '"
|
||||
class="form-control"
|
||||
id="jsusername"
|
||||
name="username"
|
||||
placeholder="' . $L->g('Username') . '"
|
||||
autocomplete="username"
|
||||
autofocus>
|
||||
<span class="input-icon">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
// Password field with icon
|
||||
echo '
|
||||
<div class="form-group">
|
||||
<label for="jspassword">' . $L->g('Password') . '</label>
|
||||
<div class="input-icon-wrapper">
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
id="jspassword"
|
||||
name="password"
|
||||
placeholder="' . $L->g('Password') . '"
|
||||
autocomplete="current-password">
|
||||
<span class="input-icon">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
// Remember me checkbox
|
||||
echo '
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="true" id="jsremember" name="remember">
|
||||
<label class="form-check-label" for="jsremember">' . $L->g('Remember me') . '</label>
|
||||
</div>
|
||||
';
|
||||
|
||||
// Submit button
|
||||
echo '
|
||||
<button type="submit" class="btn btn-login" name="save">
|
||||
<span>' . $L->g('Login') . '</span>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left: 8px; vertical-align: middle;">
|
||||
<path d="M5 12h14"></path>
|
||||
<path d="M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
';
|
||||
|
||||
echo '</form>';
|
||||
|
||||
// Footer
|
||||
if (!defined('BLUDIT_PRO')) {
|
||||
echo '
|
||||
<div class="login-footer">
|
||||
<p>Powered by <a href="https://www.bludit.com" target="_blank" rel="noopener">Bludit</a></p>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'categories' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('New category'), 'icon'=>'tag')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'name',
|
||||
'label'=>$L->g('Name'),
|
||||
'value'=>isset($_POST['category'])?$_POST['category']:'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formTextarea(array(
|
||||
'name'=>'description',
|
||||
'label'=>$L->g('Description'),
|
||||
'value'=>isset($_POST['description'])?$_POST['description']:'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>'',
|
||||
'rows'=>3
|
||||
));
|
||||
?>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
@@ -0,0 +1,516 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php
|
||||
|
||||
// Start form
|
||||
echo Bootstrap::formOpen(array(
|
||||
'id' => 'jsform',
|
||||
'class' => 'd-flex flex-column h-100'
|
||||
));
|
||||
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'tokenCSRF',
|
||||
'value' => $security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// UUID
|
||||
// The UUID is generated in the controller
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'uuid',
|
||||
'value' => $uuid
|
||||
));
|
||||
|
||||
// Type = published, draft, sticky, static
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'type',
|
||||
'value' => $site->defaultContentStatus()
|
||||
));
|
||||
|
||||
// Cover image
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'coverImage',
|
||||
'value' => ''
|
||||
));
|
||||
|
||||
// Content
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'content',
|
||||
'value' => ''
|
||||
));
|
||||
?>
|
||||
|
||||
<!-- TOOLBAR -->
|
||||
<div id="jseditorToolbar" class="mb-1">
|
||||
<div id="jseditorToolbarRight" class="btn-group btn-group-sm float-right" role="group" aria-label="Toolbar right">
|
||||
<button type="button" class="btn btn-light" id="jsmediaManagerOpenModal" data-toggle="modal" data-target="#jsmediaManagerModal"><span class="fa fa-image"></span> <?php $L->p('Images') ?></button>
|
||||
<?php Theme::plugins('editorToolbar') ?>
|
||||
<button type="button" class="btn btn-light" id="jsoptionsSidebar" style="z-index:30"><span class="fa fa-cog"></span> <?php $L->p('Options') ?></button>
|
||||
</div>
|
||||
|
||||
<div id="jseditorToolbarLeft">
|
||||
<button id="jsbuttonSave" type="button" class="btn btn-sm btn-primary"><?php $L->p('Save') ?></button>
|
||||
<button id="jsbuttonPreview" type="button" class="btn btn-sm btn-secondary"><?php $L->p('Preview') ?></button>
|
||||
<?php if ($site->defaultContentStatus() == 'draft'): ?>
|
||||
<span id="jsbuttonSwitch" data-switch="draft" class="ml-2 text-secondary switch-button"><i class="fa fa-square switch-icon-draft"></i> <?php $L->p('Draft') ?></span>
|
||||
<?php else: ?>
|
||||
<span id="jsbuttonSwitch" data-switch="publish" class="ml-2 text-secondary switch-button"><i class="fa fa-square switch-icon-publish"></i> <?php $L->p('Publish') ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#jsoptionsSidebar").on("click", function() {
|
||||
$("#jseditorSidebar").toggle();
|
||||
$("#jsshadow").toggle();
|
||||
});
|
||||
|
||||
$("#jsshadow").on("click", function() {
|
||||
$("#jseditorSidebar").toggle();
|
||||
$("#jsshadow").toggle();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- SIDEBAR OPTIONS -->
|
||||
<div id="jseditorSidebar">
|
||||
<nav>
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
<a class="nav-link active show" id="nav-general-tab" data-toggle="tab" href="#nav-general" role="tab" aria-controls="general"><?php $L->p('General') ?></a>
|
||||
<a class="nav-link" id="nav-advanced-tab" data-toggle="tab" href="#nav-advanced" role="tab" aria-controls="advanced"><?php $L->p('Advanced') ?></a>
|
||||
<?php if (!empty($site->customFields())) : ?>
|
||||
<a class="nav-link" id="nav-custom-tab" data-toggle="tab" href="#nav-custom" role="tab" aria-controls="custom"><?php $L->p('Custom') ?></a>
|
||||
<?php endif ?>
|
||||
<a class="nav-link" id="nav-seo-tab" data-toggle="tab" href="#nav-seo" role="tab" aria-controls="seo"><?php $L->p('SEO') ?></a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="tab-content pr-3 pl-3 pb-3">
|
||||
<div id="nav-general" class="tab-pane fade show active" role="tabpanel" aria-labelledby="general-tab">
|
||||
<?php
|
||||
// Category
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'category',
|
||||
'label' => $L->g('Category'),
|
||||
'selected' => '',
|
||||
'class' => '',
|
||||
'emptyOption' => '- ' . $L->g('Uncategorized') . ' -',
|
||||
'options' => $categories->getKeyNameArray()
|
||||
));
|
||||
|
||||
// Description
|
||||
echo Bootstrap::formTextareaBlock(array(
|
||||
'name' => 'description',
|
||||
'label' => $L->g('Description'),
|
||||
'selected' => '',
|
||||
'class' => '',
|
||||
'value' => '',
|
||||
'rows' => 5,
|
||||
'placeholder' => $L->get('this-field-can-help-describe-the-content')
|
||||
));
|
||||
?>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<label class="mt-4 mb-2 pb-2 border-bottom text-uppercase w-100"><?php $L->p('Cover Image') ?></label>
|
||||
<div>
|
||||
<img id="jscoverImagePreview" class="mx-auto d-block w-100" alt="Cover image preview" src="<?php echo HTML_PATH_CORE_IMG ?>default.svg" />
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<button type="button" id="jsbuttonSelectCoverImage" class="btn btn-primary btn-sm"><?php echo $L->g('Select cover image') ?></button>
|
||||
<button type="button" id="jsbuttonRemoveCoverImage" class="btn btn-secondary btn-sm"><?php echo $L->g('Remove cover image') ?></button>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#jscoverImagePreview").on("click", function() {
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
$("#jsbuttonSelectCoverImage").on("click", function() {
|
||||
openMediaManager();
|
||||
});
|
||||
|
||||
$("#jsbuttonRemoveCoverImage").on("click", function() {
|
||||
$("#jscoverImage").val('');
|
||||
$("#jscoverImagePreview").attr('src', HTML_PATH_CORE_IMG + 'default.svg');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div id="nav-advanced" class="tab-pane fade" role="tabpanel" aria-labelledby="advanced-tab">
|
||||
<?php
|
||||
// Date
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'date',
|
||||
'label' => $L->g('Date'),
|
||||
'placeholder' => '',
|
||||
'value' => Date::current(DB_DATE_FORMAT),
|
||||
'tip' => $L->g('date-format-format')
|
||||
));
|
||||
|
||||
// Type
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'typeSelector',
|
||||
'label' => $L->g('Type'),
|
||||
'selected' => '',
|
||||
'options' => array(
|
||||
'published' => '- ' . $L->g('Default') . ' -',
|
||||
'sticky' => $L->g('Sticky'),
|
||||
'static' => $L->g('Static')
|
||||
),
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
// Position
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'position',
|
||||
'label' => $L->g('Position'),
|
||||
'tip' => $L->g('Field used when ordering content by position'),
|
||||
'value' => $pages->nextPositionNumber()
|
||||
));
|
||||
|
||||
// Tags
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'tags',
|
||||
'label' => $L->g('Tags'),
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Write the tags separated by commas')
|
||||
));
|
||||
|
||||
// Parent
|
||||
echo Bootstrap::formSelectBlock(array(
|
||||
'name' => 'parent',
|
||||
'label' => $L->g('Parent'),
|
||||
'options' => array(),
|
||||
'selected' => false,
|
||||
'class' => '',
|
||||
'tip' => $L->g('Start typing a page title to see a list of suggestions.'),
|
||||
));
|
||||
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var parent = $("#jsparent").select2({
|
||||
placeholder: "",
|
||||
allowClear: true,
|
||||
theme: "bootstrap4",
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/get-published",
|
||||
data: function(params) {
|
||||
var query = {
|
||||
checkIsParent: true,
|
||||
query: params.term
|
||||
}
|
||||
return query;
|
||||
},
|
||||
processResults: function(data) {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
escapeMarkup: function(markup) {
|
||||
return markup;
|
||||
},
|
||||
templateResult: function(data) {
|
||||
var html = data.text;
|
||||
if (data.type == "static") {
|
||||
html += '<span class="badge badge-pill badge-light">' + data.type + '</span>';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
// Template
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'template',
|
||||
'label' => $L->g('Template'),
|
||||
'placeholder' => '',
|
||||
'value' => '',
|
||||
'tip' => $L->g('Write a template name to filter the page in the theme and change the style of the page.')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'externalCoverImage',
|
||||
'label' => $L->g('External cover image'),
|
||||
'placeholder' => "https://",
|
||||
'value' => '',
|
||||
'tip' => $L->g('Set a cover image from external URL, such as a CDN or some server dedicated for images.')
|
||||
));
|
||||
|
||||
// Username
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => '',
|
||||
'label' => $L->g('Author'),
|
||||
'placeholder' => '',
|
||||
'value' => $login->username(),
|
||||
'tip' => '',
|
||||
'disabled' => true
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
// Changes in External cover image input
|
||||
$("#jsexternalCoverImage").change(function() {
|
||||
$("#jscoverImage").val($(this).val());
|
||||
});
|
||||
|
||||
// Generate slug when the user type the title
|
||||
$("#jstitle").keyup(function() {
|
||||
var text = $(this).val();
|
||||
var parent = $("#jsparent").val();
|
||||
var currentKey = "";
|
||||
var ajax = new bluditAjax();
|
||||
var callBack = $("#jsslug");
|
||||
ajax.generateSlug(text, parent, currentKey, callBack);
|
||||
});
|
||||
|
||||
// Datepicker
|
||||
$("#jsdate").datetimepicker({
|
||||
format: DB_DATE_FORMAT
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<?php if (!empty($site->customFields())) : ?>
|
||||
<div id="nav-custom" class="tab-pane fade" role="tabpanel" aria-labelledby="custom-tab">
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (!isset($options['position'])) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'value' => (isset($options['default']) ? $options['default'] : ''),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : '')
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => (isset($options['checked']) ? true : false),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : '')
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div id="nav-seo" class="tab-pane fade" role="tabpanel" aria-labelledby="seo-tab">
|
||||
<?php
|
||||
// Friendly URL
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'slug',
|
||||
'tip' => $L->g('URL associated with the content'),
|
||||
'label' => $L->g('Friendly URL'),
|
||||
'placeholder' => $L->g('Leave empty for autocomplete by Bludit.')
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'noindex',
|
||||
'label' => 'Robots',
|
||||
'labelForCheckbox' => $L->g('apply-code-noindex-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => false,
|
||||
'tip' => $L->g('This tells search engines not to show this page in their search results.')
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'nofollow',
|
||||
'label' => '',
|
||||
'labelForCheckbox' => $L->g('apply-code-nofollow-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => false,
|
||||
'tip' => $L->g('This tells search engines not to follow links on this page.')
|
||||
));
|
||||
|
||||
// Robots
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'noarchive',
|
||||
'label' => '',
|
||||
'labelForCheckbox' => $L->g('apply-code-noarchive-code-to-this-page'),
|
||||
'placeholder' => '',
|
||||
'checked' => false,
|
||||
'tip' => $L->g('This tells search engines not to save a cached copy of this page.')
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom fields: TOP -->
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (isset($options['position']) && ($options['position'] == 'top')) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'value' => (isset($options['default']) ? $options['default'] : ''),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'class' => 'mb-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => (isset($options['checked']) ? true : false),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'class' => 'mb-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<!-- Title -->
|
||||
<div id="jseditorTitle" class="form-group mb-1">
|
||||
<input id="jstitle" name="title" type="text" dir="auto" class="form-control form-control-lg rounded-0" value="" placeholder="<?php $L->p('Enter title') ?>">
|
||||
</div>
|
||||
|
||||
<!-- Editor -->
|
||||
<textarea id="jseditor" class="editable h-100 mb-1"></textarea>
|
||||
|
||||
<!-- Custom fields: BOTTOM -->
|
||||
<?php
|
||||
$customFields = $site->customFields();
|
||||
foreach ($customFields as $field => $options) {
|
||||
if (isset($options['position']) && ($options['position'] == 'bottom')) {
|
||||
if ($options['type'] == "string") {
|
||||
echo Bootstrap::formInputTextBlock(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'value' => (isset($options['default']) ? $options['default'] : ''),
|
||||
'tip' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'class' => 'mt-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
|
||||
));
|
||||
} elseif ($options['type'] == "bool") {
|
||||
echo Bootstrap::formCheckbox(array(
|
||||
'name' => 'custom[' . $field . ']',
|
||||
'label' => (isset($options['label']) ? $options['label'] : ''),
|
||||
'placeholder' => (isset($options['placeholder']) ? $options['placeholder'] : ''),
|
||||
'checked' => (isset($options['checked']) ? true : false),
|
||||
'labelForCheckbox' => (isset($options['tip']) ? $options['tip'] : ''),
|
||||
'class' => 'mt-2',
|
||||
'labelClass' => 'mb-2 pb-2 border-bottom text-uppercase w-100'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal for Media Manager -->
|
||||
<?php include(PATH_ADMIN_THEMES . 'booty/html/media.php'); ?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
// Define functions if they don't exist
|
||||
// This helps if the user doesn't activate any plugin as editor
|
||||
if (typeof editorGetContent != "function") {
|
||||
window.editorGetContent = function() {
|
||||
return $("#jseditor").val();
|
||||
};
|
||||
}
|
||||
if (typeof editorInsertMedia != "function") {
|
||||
window.editorInsertMedia = function(filename) {
|
||||
$("#jseditor").val($('#jseditor').val() + '<img src="' + filename + '" alt="">');
|
||||
};
|
||||
}
|
||||
if (typeof editorInsertLinkedMedia != "function") {
|
||||
window.editorInsertLinkedMedia = function(filename, link) {
|
||||
$("#jseditor").val($('#jseditor').val() + '<a href="' + link + '"><img src="' + filename + '" alt=""></a>');
|
||||
};
|
||||
}
|
||||
|
||||
// Button switch
|
||||
$("#jsbuttonSwitch").on("click", function() {
|
||||
if ($(this).data("switch") == "publish") {
|
||||
$(this).html('<i class="fa fa-square switch-icon-draft"></i> <?php $L->p('Draft') ?>');
|
||||
$(this).data("switch", "draft");
|
||||
} else {
|
||||
$(this).html('<i class="fa fa-square switch-icon-publish"></i> <?php $L->p('Publish') ?>');
|
||||
$(this).data("switch", "publish");
|
||||
}
|
||||
});
|
||||
|
||||
// Button preview
|
||||
$("#jsbuttonPreview").on("click", function() {
|
||||
var uuid = $("#jsuuid").val();
|
||||
var title = $("#jstitle").val();
|
||||
var content = editorGetContent();
|
||||
bluditAjax.saveAsDraft(uuid, title, content).then(function(data) {
|
||||
var preview = window.open("<?php echo DOMAIN_PAGES . 'autosave-' . $uuid . '?preview=' . hash_hmac('sha256', 'autosave-' . $uuid, DB_SITE) ?>", "bludit-preview");
|
||||
preview.focus();
|
||||
});
|
||||
});
|
||||
|
||||
// Button Save
|
||||
$("#jsbuttonSave").on("click", function() {
|
||||
let actionParameters = '';
|
||||
|
||||
// If the switch is setted to "published", get the value from the selector
|
||||
if ($("#jsbuttonSwitch").data("switch") == "publish") {
|
||||
var value = $("#jstypeSelector option:selected").val();
|
||||
$("#jstype").val(value);
|
||||
actionParameters = '#' + value;
|
||||
} else {
|
||||
$("#jstype").val("draft");
|
||||
actionParameters = '#draft';
|
||||
}
|
||||
|
||||
// Get the content
|
||||
$("#jscontent").val(editorGetContent());
|
||||
|
||||
// Submit the form
|
||||
$("#jsform").attr('action', actionParameters);
|
||||
$("#jsform").submit();
|
||||
});
|
||||
|
||||
// Autosave
|
||||
var currentContent = editorGetContent();
|
||||
setInterval(function() {
|
||||
var uuid = $("#jsuuid").val();
|
||||
var title = $("#jstitle").val() + "[<?php $L->p('Autosave') ?>]";
|
||||
var content = editorGetContent();
|
||||
// Autosave when content has at least 100 characters
|
||||
if (content.length < 100) {
|
||||
return false;
|
||||
}
|
||||
// Autosave only when the user change the content
|
||||
if (currentContent != content) {
|
||||
currentContent = content;
|
||||
bluditAjax.saveAsDraft(uuid, title, content).then(function(data) {
|
||||
if (data.status == 0) {
|
||||
showAlert("<?php $L->p('Autosave') ?>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 1000 * 60 * AUTOSAVE_INTERVAL);
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'users' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('Add a new user'), 'icon'=>'user')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'new_username',
|
||||
'label'=>$L->g('Username'),
|
||||
'value'=>(isset($_POST['new_username'])?$_POST['new_username']:''),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'new_password',
|
||||
'type'=>'password',
|
||||
'label'=>$L->g('Password'),
|
||||
'value'=>'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'confirm_password',
|
||||
'type'=>'password',
|
||||
'label'=>$L->g('Confirm Password'),
|
||||
'value'=>'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name'=>'role',
|
||||
'label'=>$L->g('Role'),
|
||||
'options'=>array('author'=>$L->g('Author'), 'editor'=>$L->g('Editor'), 'admin'=>$L->g('Administrator')),
|
||||
'selected'=>'Author',
|
||||
'class'=>'',
|
||||
'tip'=>$L->g('author-can-write-and-edit-their-own-content')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'email',
|
||||
'label'=>$L->g('Email'),
|
||||
'value'=>(isset($_POST['email'])?$_POST['email']:''),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
?>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="button" class="btn btn-primary btn-sm jsbuttonSave" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'plugins' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('Plugins position'), 'icon'=>'tags')); ?>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-primary"><?php $L->p('Drag and Drop to sort the plugins') ?></div>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'plugin-list',
|
||||
'value'=>''
|
||||
));
|
||||
|
||||
echo '<ul class="list-group list-group-sortable">';
|
||||
foreach ($plugins['siteSidebar'] as $Plugin) {
|
||||
echo '<li class="list-group-item" data-plugin="'.$Plugin->className().'"><span class="fa fa-arrows-v"></span> '.$Plugin->name().'</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
?>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('.list-group-sortable').sortable({
|
||||
placeholderClass: 'list-group-item'
|
||||
});
|
||||
|
||||
$(".jsbuttonSave").on("click", function() {
|
||||
var tmp = [];
|
||||
$("li.list-group-item").each(function() {
|
||||
tmp.push( $(this).attr("data-plugin") );
|
||||
});
|
||||
$("#jsplugin-list").attr("value", tmp.join(",") );
|
||||
$("#jsform").submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title' => $L->g('Plugins'), 'icon' => 'puzzle-piece'));
|
||||
|
||||
echo Bootstrap::link(array(
|
||||
'title' => $L->g('Change the position of the plugins'),
|
||||
'href' => HTML_PATH_ADMIN_ROOT . 'plugins-position',
|
||||
'icon' => 'arrows'
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Search plugins')));
|
||||
|
||||
?>
|
||||
|
||||
<input type="text" dir="auto" class="form-control" id="search" placeholder="<?php $L->p('Search') ?>">
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#search").on("keyup", function() {
|
||||
var textToSearch = $(this).val().toLowerCase();
|
||||
$(".searchItem").each(function() {
|
||||
var item = $(this);
|
||||
item.hide();
|
||||
item.find(".searchText").each(function() {
|
||||
var element = $(this).text().toLowerCase();
|
||||
if (element.indexOf(textToSearch) != -1) {
|
||||
item.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Enabled plugins')));
|
||||
|
||||
echo '
|
||||
<table class="table">
|
||||
<tbody>
|
||||
';
|
||||
|
||||
// Show installed plugins
|
||||
foreach ($pluginsInstalled as $plugin) {
|
||||
|
||||
if ($plugin->type() == 'theme') {
|
||||
// Do not display theme's plugins
|
||||
continue;
|
||||
}
|
||||
|
||||
echo '<tr id="' . $plugin->className() . '" class="bg-light searchItem">';
|
||||
|
||||
echo '<td class="align-middle pt-3 pb-3 w-25">
|
||||
<div class="searchText">' . $plugin->name() . '</div>
|
||||
<div class="mt-1">';
|
||||
if (method_exists($plugin, 'form')) {
|
||||
echo '<a class="mr-3" href="' . HTML_PATH_ADMIN_ROOT . 'configure-plugin/' . $plugin->className() . '">' . $L->g('Settings') . '</a>';
|
||||
}
|
||||
echo '<a href="' . HTML_PATH_ADMIN_ROOT . 'uninstall-plugin/' . $plugin->className() . '">' . $L->g('Deactivate') . '</a>';
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="searchText align-middle d-none d-sm-table-cell">';
|
||||
echo $plugin->description();
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">';
|
||||
echo '<span>' . $plugin->version() . '</span>';
|
||||
if (!$plugin->isCompatible()) {
|
||||
echo ' <span class="badge badge-pill badge-warning" title="' . $L->g('This plugin may not be supported by this version of Bludit') . '">' . $L->g('Update') . '</span>';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">
|
||||
<a target="_blank" href="' . $plugin->website() . '">' . $plugin->author() . '</a>
|
||||
</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Disabled plugins')));
|
||||
|
||||
echo '
|
||||
<table class="table">
|
||||
<tbody>
|
||||
';
|
||||
|
||||
// Plugins not installed
|
||||
$pluginsNotInstalled = array_diff_key($plugins['all'], $pluginsInstalled);
|
||||
foreach ($pluginsNotInstalled as $plugin) {
|
||||
|
||||
if ($plugin->type() == 'theme') {
|
||||
// Do not display theme's plugins
|
||||
continue;
|
||||
}
|
||||
echo '<tr id="' . $plugin->className() . '" class="searchItem">';
|
||||
|
||||
echo '<td class="align-middle pt-3 pb-3 w-25">
|
||||
<div class="searchText">' . $plugin->name() . '</div>
|
||||
<div class="mt-1">
|
||||
<a href="' . HTML_PATH_ADMIN_ROOT . 'install-plugin/' . $plugin->className() . '">' . $L->g('Activate') . '</a>
|
||||
</div>
|
||||
</td>';
|
||||
|
||||
echo '<td class="searchText align-middle d-none d-sm-table-cell">';
|
||||
echo $plugin->description();
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">';
|
||||
echo '<span>' . $plugin->version() . '</span>';
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">
|
||||
<a target="_blank" href="' . $plugin->website() . '">' . $plugin->author() . '</a>
|
||||
</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
@@ -0,0 +1,650 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id' => 'jsform', 'class' => 'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT . 'dashboard' ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title' => $L->g('Settings'), 'icon' => 'cog')); ?>
|
||||
</div>
|
||||
|
||||
<!-- TABS -->
|
||||
<nav class="mb-3">
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
<a class="nav-item nav-link active" id="nav-general-tab" data-toggle="tab" href="#general" role="tab" aria-controls="nav-general" aria-selected="false"><?php $L->p('General') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-advanced-tab" data-toggle="tab" href="#advanced" role="tab" aria-controls="nav-advanced" aria-selected="false"><?php $L->p('Advanced') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-seo-tab" data-toggle="tab" href="#seo" role="tab" aria-controls="nav-seo" aria-selected="false"><?php $L->p('SEO') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-social-tab" data-toggle="tab" href="#social" role="tab" aria-controls="nav-social" aria-selected="false"><?php $L->p('Social Networks') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-images-tab" data-toggle="tab" href="#images" role="tab" aria-controls="nav-images" aria-selected="false"><?php $L->p('Images') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-language-tab" data-toggle="tab" href="#language" role="tab" aria-controls="nav-language" aria-selected="false"><?php $L->p('Language') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-custom-fields-tab" data-toggle="tab" href="#custom-fields" role="tab" aria-controls="nav-custom-fields" aria-selected="false"><?php $L->p('Custom fields') ?></a>
|
||||
<a class="nav-item nav-link" id="nav-logo-tab" data-toggle="tab" href="#logo" role="tab" aria-controls="nav-logo" aria-selected="false"><?php $L->p('Logo') ?></a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name' => 'tokenCSRF',
|
||||
'value' => $security->getTokenCSRF()
|
||||
));
|
||||
?>
|
||||
|
||||
<!-- General tab -->
|
||||
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
||||
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Site')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'title',
|
||||
'label' => $L->g('Site title'),
|
||||
'value' => $site->title(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('use-this-field-to-name-your-site')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'slogan',
|
||||
'label' => $L->g('Site slogan'),
|
||||
'value' => $site->slogan(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('use-this-field-to-add-a-catchy-phrase')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'description',
|
||||
'label' => $L->g('Site description'),
|
||||
'value' => $site->description(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('you-can-add-a-site-description-to-provide')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'footer',
|
||||
'label' => $L->g('Footer text'),
|
||||
'value' => $site->footer(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('you-can-add-a-small-text-on-the-bottom')
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Advanced tab -->
|
||||
<div class="tab-pane fade" id="advanced" role="tabpanel" aria-labelledby="advanced-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Content')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'itemsPerPage',
|
||||
'label' => $L->g('Items per page'),
|
||||
'value' => $site->itemsPerPage(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Number of items to show per page')
|
||||
));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'orderBy',
|
||||
'label' => $L->g('Order content by'),
|
||||
'options' => array('date' => $L->g('Date'), 'position' => $L->g('Position')),
|
||||
'selected' => $site->orderBy(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('order-the-content-by-date-to-build-a-blog')
|
||||
));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'defaultContentStatus',
|
||||
'label' => $L->g('Default content status'),
|
||||
'options' => array('published' => $L->g('Published'), 'draft' => $L->g('Draft')),
|
||||
'selected' => $site->defaultContentStatus(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('default-status-for-new-content')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Predefined pages')));
|
||||
|
||||
// Homepage
|
||||
try {
|
||||
$options = array();
|
||||
$homeKey = $site->homepage();
|
||||
if (!empty($homeKey)) {
|
||||
$home = new Page($homeKey);
|
||||
$options = array($homeKey => $home->title());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'homepage',
|
||||
'label' => $L->g('Homepage'),
|
||||
'options' => $options,
|
||||
'selected' => false,
|
||||
'class' => '',
|
||||
'tip' => $L->g('Returning page for the main page')
|
||||
));
|
||||
?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var homepage = $("#jshomepage").select2({
|
||||
placeholder: "<?php $L->p('Start typing to see a list of suggestions.') ?>",
|
||||
allowClear: true,
|
||||
theme: "bootstrap4",
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/get-published",
|
||||
data: function(params) {
|
||||
var query = {
|
||||
query: params.term
|
||||
}
|
||||
return query;
|
||||
},
|
||||
processResults: function(data) {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
escapeMarkup: function(markup) {
|
||||
return markup;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
// Page not found 404
|
||||
try {
|
||||
$options = array();
|
||||
$pageNotFoundKey = $site->pageNotFound();
|
||||
if (!empty($pageNotFoundKey)) {
|
||||
$pageNotFound = new Page($pageNotFoundKey);
|
||||
$options = array($pageNotFoundKey => $pageNotFound->title());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'pageNotFound',
|
||||
'label' => $L->g('Page not found'),
|
||||
'options' => $options,
|
||||
'selected' => false,
|
||||
'class' => '',
|
||||
'tip' => $L->g('Returning page when the page doesnt exist')
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var homepage = $("#jspageNotFound").select2({
|
||||
placeholder: "<?php $L->p('Start typing to see a list of suggestions.') ?>",
|
||||
allowClear: true,
|
||||
theme: "bootstrap4",
|
||||
minimumInputLength: 2,
|
||||
ajax: {
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/get-published",
|
||||
data: function(params) {
|
||||
var query = {
|
||||
query: params.term
|
||||
}
|
||||
return query;
|
||||
},
|
||||
processResults: function(data) {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
escapeMarkup: function(markup) {
|
||||
return markup;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Email account settings')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'emailFrom',
|
||||
'label' => $L->g('Sender email'),
|
||||
'value' => $site->emailFrom(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Emails will be sent from this address')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Autosave')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'autosaveInterval',
|
||||
'label' => $L->g('Interval'),
|
||||
'value' => $site->autosaveInterval(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Number in minutes for every execution of autosave')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Site URL')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'url',
|
||||
'label' => 'URL',
|
||||
'value' => $site->url(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('full-url-of-your-site'),
|
||||
'placeholder' => 'https://'
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Page content')));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'markdownParser',
|
||||
'label' => $L->g('Markdown parser'),
|
||||
'options' => array('true' => $L->g('Enabled'), 'false' => $L->g('Disabled')),
|
||||
'selected' => ($site->markdownParser() ? 'true' : 'false'),
|
||||
'class' => '',
|
||||
'tip' => $L->g('Enable the markdown parser for the content of the page.')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('URL Filters')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'uriPage',
|
||||
'label' => $L->g('Pages'),
|
||||
'value' => $site->uriFilters('page'),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => DOMAIN_PAGES
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'uriTag',
|
||||
'label' => $L->g('Tags'),
|
||||
'value' => $site->uriFilters('tag'),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => DOMAIN_TAGS
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'uriCategory',
|
||||
'label' => $L->g('Category'),
|
||||
'value' => $site->uriFilters('category'),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => DOMAIN_CATEGORIES
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'uriBlog',
|
||||
'label' => $L->g('Blog'),
|
||||
'value' => $site->uriFilters('blog'),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => DOMAIN . $site->uriFilters('blog'),
|
||||
'disabled' => Text::isEmpty($site->uriFilters('blog'))
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- SEO tab -->
|
||||
<div class="tab-pane fade" id="seo" role="tabpanel" aria-labelledby="seo-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Extreme friendly URL')));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'extremeFriendly',
|
||||
'label' => $L->g('Allow Unicode'),
|
||||
'options' => array('true' => $L->g('Enabled'), 'false' => $L->g('Disabled')),
|
||||
'selected' => ($site->extremeFriendly() ? 'true' : 'false'),
|
||||
'class' => '',
|
||||
'tip' => $L->g('Allow unicode characters in the URL and some part of the system.')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Title formats')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'titleFormatHomepage',
|
||||
'label' => $L->g('Homepage'),
|
||||
'value' => $site->titleFormatHomepage(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Variables allowed') . ' <code>{{site-title}}</code> <code>{{site-slogan}}</code> <code>{{site-description}}</code>',
|
||||
'placeholder' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'titleFormatPages',
|
||||
'label' => $L->g('Pages'),
|
||||
'value' => $site->titleFormatPages(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Variables allowed') . ' <code>{{page-title}}</code> <code>{{page-description}}</code> <code>{{site-title}}</code> <code>{{site-slogan}}</code> <code>{{site-description}}</code>',
|
||||
'placeholder' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'titleFormatCategory',
|
||||
'label' => $L->g('Category'),
|
||||
'value' => $site->titleFormatCategory(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Variables allowed') . ' <code>{{category-name}}</code> <code>{{site-title}}</code> <code>{{site-slogan}}</code> <code>{{site-description}}</code>',
|
||||
'placeholder' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'titleFormatTag',
|
||||
'label' => $L->g('Tag'),
|
||||
'value' => $site->titleFormatTag(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Variables allowed') . ' <code>{{tag-name}}</code> <code>{{site-title}}</code> <code>{{site-slogan}}</code> <code>{{site-description}}</code>',
|
||||
'placeholder' => ''
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Social Network tab -->
|
||||
<div class="tab-pane fade" id="social" role="tabpanel" aria-labelledby="social-tab">
|
||||
<?php
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'twitter',
|
||||
'label' => 'Twitter',
|
||||
'value' => $site->twitter(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'facebook',
|
||||
'label' => 'Facebook',
|
||||
'value' => $site->facebook(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'codepen',
|
||||
'label' => 'CodePen',
|
||||
'value' => $site->codepen(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'instagram',
|
||||
'label' => 'Instagram',
|
||||
'value' => $site->instagram(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'gitlab',
|
||||
'label' => 'GitLab',
|
||||
'value' => $site->gitlab(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'github',
|
||||
'label' => 'GitHub',
|
||||
'value' => $site->github(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'linkedin',
|
||||
'label' => 'LinkedIn',
|
||||
'value' => $site->linkedin(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'xing',
|
||||
'label' => 'Xing',
|
||||
'value' => $site->xing(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'telegram',
|
||||
'label' => 'Telegram',
|
||||
'value' => $site->telegram(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'mastodon',
|
||||
'label' => 'Mastodon',
|
||||
'value' => $site->mastodon(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'dribbble',
|
||||
'label' => 'Dribbble',
|
||||
'value' => $site->dribbble(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'vk',
|
||||
'label' => 'VK',
|
||||
'value' => $site->vk(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'youtube',
|
||||
'label' => 'Youtube',
|
||||
'value' => $site->youtube(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'bluesky',
|
||||
'label' => 'Bluesky',
|
||||
'value' => $site->bluesky(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => ''
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Images tab -->
|
||||
<div class="tab-pane fade" id="images" role="tabpanel" aria-labelledby="images-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Thumbnails')));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'thumbnailEnable',
|
||||
'label' => $L->g('Thumbnail generation'),
|
||||
'options' => array('true' => $L->g('Enabled'), 'false' => $L->g('Disabled')),
|
||||
'selected' => ($site->thumbnailEnable() ? 'true' : 'false'),
|
||||
'class' => '',
|
||||
'tip' => $L->g('Enable or disable automatic thumbnail generation on image upload.')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'thumbnailWidth',
|
||||
'label' => $L->g('Width'),
|
||||
'value' => $site->thumbnailWidth(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Thumbnail width in pixels')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'thumbnailHeight',
|
||||
'label' => $L->g('Height'),
|
||||
'value' => $site->thumbnailHeight(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Thumbnail height in pixels')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'thumbnailQuality',
|
||||
'label' => $L->g('Quality'),
|
||||
'value' => $site->thumbnailQuality(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Thumbnail quality in percentage')
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Timezone and language tab -->
|
||||
<div class="tab-pane fade" id="language" role="tabpanel" aria-labelledby="language-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Language and timezone')));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'language',
|
||||
'label' => $L->g('Language'),
|
||||
'options' => $L->getLanguageList(),
|
||||
'selected' => $site->language(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('select-your-sites-language')
|
||||
));
|
||||
|
||||
echo Bootstrap::formSelect(array(
|
||||
'name' => 'timezone',
|
||||
'label' => $L->g('Timezone'),
|
||||
'options' => Date::timezoneList(),
|
||||
'selected' => $site->timezone(),
|
||||
'class' => '',
|
||||
'tip' => $L->g('select-a-timezone-for-a-correct')
|
||||
));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'locale',
|
||||
'label' => $L->g('Locale'),
|
||||
'value' => $site->locale(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('with-the-locales-you-can-set-the-regional-user-interface')
|
||||
));
|
||||
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Date and time formats')));
|
||||
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name' => 'dateFormat',
|
||||
'label' => $L->g('Date format'),
|
||||
'value' => $site->dateFormat(),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('Current format') . ': ' . Date::current($site->dateFormat())
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Custom fields -->
|
||||
<div class="tab-pane fade" id="custom-fields" role="tabpanel" aria-labelledby="custom-fields-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Custom fields')));
|
||||
|
||||
echo Bootstrap::formTextarea(array(
|
||||
'name' => 'customFields',
|
||||
'label' => 'JSON Format',
|
||||
'value' => json_encode($site->customFields(), JSON_PRETTY_PRINT),
|
||||
'class' => '',
|
||||
'placeholder' => '',
|
||||
'tip' => $L->g('define-custom-fields-for-the-content'),
|
||||
'rows' => 15
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Site logo tab -->
|
||||
<div class="tab-pane fade" id="logo" role="tabpanel" aria-labelledby="logo-tab">
|
||||
<?php
|
||||
echo Bootstrap::formTitle(array('title' => $L->g('Site logo')));
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-sm-12 p-0 pr-2">
|
||||
<div class="custom-file">
|
||||
<input id="jssiteLogoInputFile" class="custom-file-input" type="file" name="inputFile">
|
||||
<label for="jssiteLogoInputFile" class="custom-file-label"><?php $L->p('Upload image'); ?></label>
|
||||
</div>
|
||||
<button id="jsbuttonRemoveLogo" type="button" class="btn btn-primary w-100 mt-4 mb-4"><i class="fa fa-trash"></i><?php $L->p('Remove logo') ?></button>
|
||||
</div>
|
||||
<div class="col-lg-8 col-sm-12 p-0 text-center">
|
||||
<img id="jssiteLogoPreview" class="img-fluid img-thumbnail" alt="Site logo preview" src="<?php echo ($site->logo() ? DOMAIN_UPLOADS . $site->logo(false) . '?version=' . time() : HTML_PATH_CORE_IMG . 'default.svg') ?>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$("#jsbuttonRemoveLogo").on("click", function() {
|
||||
bluditAjax.removeLogo();
|
||||
$("#jssiteLogoPreview").attr("src", "<?php echo HTML_PATH_CORE_IMG . 'default.svg' ?>");
|
||||
});
|
||||
|
||||
$("#jssiteLogoInputFile").on("change", function() {
|
||||
var formData = new FormData();
|
||||
formData.append('tokenCSRF', tokenCSRF);
|
||||
formData.append('inputFile', $(this)[0].files[0]);
|
||||
$.ajax({
|
||||
url: HTML_PATH_ADMIN_ROOT + "ajax/logo-upload",
|
||||
type: "POST",
|
||||
data: formData,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false
|
||||
}).done(function(data) {
|
||||
if (data.status == 0) {
|
||||
$("#jssiteLogoPreview").attr('src', data.absoluteURL + "?time=" + Math.random());
|
||||
} else {
|
||||
showAlert(data.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
|
||||
<script>
|
||||
// Open current tab after refresh page
|
||||
$(function() {
|
||||
$('a[data-toggle="tab"]').on('click', function(e) {
|
||||
window.localStorage.setItem('activeTab', $(e.target).attr('href'));
|
||||
});
|
||||
var activeTab = window.localStorage.getItem('activeTab');
|
||||
if (activeTab) {
|
||||
$('#nav-tab a[href="' + activeTab + '"]').tab('show');
|
||||
//window.localStorage.removeItem("activeTab");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title' => $L->g('Themes'), 'icon' => 'desktop'));
|
||||
|
||||
echo '
|
||||
<table class="table mt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-bottom-0 w-25" scope="col">' . $L->g('Name') . '</th>
|
||||
<th class="border-bottom-0 d-none d-sm-table-cell" scope="col">' . $L->g('Description') . '</th>
|
||||
<th class="text-center border-bottom-0 d-none d-lg-table-cell" scope="col">' . $L->g('Version') . '</th>
|
||||
<th class="text-center border-bottom-0 d-none d-lg-table-cell" scope="col">' . $L->g('Author') . '</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
';
|
||||
|
||||
foreach ($themes as $theme) {
|
||||
echo '
|
||||
<tr ' . ($theme['dirname'] == $site->theme() ? 'class="bg-light"' : '') . '>
|
||||
<td class="align-middle pt-3 pb-3">
|
||||
<div>'.$theme['name'].($theme['dirname']==$site->theme()?'<span class="badge badge-primary ml-2">'.$L->g('Active').'</span>':'').'</div>
|
||||
<div class="mt-1">
|
||||
';
|
||||
|
||||
if ($theme['dirname'] != $site->theme()) {
|
||||
echo '<a href="' . HTML_PATH_ADMIN_ROOT . 'install-theme/' . $theme['dirname'] . '">' . $L->g('Activate') . '</a>';
|
||||
} else {
|
||||
if (isset($theme['plugin'])) {
|
||||
echo '<a href="' . HTML_PATH_ADMIN_ROOT . 'configure-plugin/' . $theme['plugin'] . '">' . $L->g('Settings') . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '
|
||||
</div>
|
||||
</td>
|
||||
';
|
||||
|
||||
echo '<td class="align-middle d-none d-sm-table-cell">';
|
||||
echo $theme['description'];
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">';
|
||||
echo '<span>' . $theme['version'] . '</span>';
|
||||
echo '</td>';
|
||||
|
||||
echo '<td class="text-center align-middle d-none d-lg-table-cell">
|
||||
<a target="_blank" href="' . $theme['website'] . '">' . $theme['author'] . '</a>
|
||||
</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php echo Bootstrap::formOpen(array('id'=>'jsform', 'class'=>'tab-content')); ?>
|
||||
|
||||
<div class="align-middle">
|
||||
<div class="float-right mt-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="save"><?php $L->p('Save') ?></button>
|
||||
<a class="btn btn-secondary btn-sm" href="<?php echo HTML_PATH_ADMIN_ROOT.'edit-user/'.$user->username() ?>" role="button"><?php $L->p('Cancel') ?></a>
|
||||
</div>
|
||||
<?php echo Bootstrap::pageTitle(array('title'=>$L->g('Change password'), 'icon'=>'user')); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Token CSRF
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'tokenCSRF',
|
||||
'value'=>$security->getTokenCSRF()
|
||||
));
|
||||
|
||||
// Username
|
||||
echo Bootstrap::formInputHidden(array(
|
||||
'name'=>'username',
|
||||
'value'=>$user->username()
|
||||
));
|
||||
|
||||
// Username disabled
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'usernameDisabled',
|
||||
'label'=>$L->g('Username'),
|
||||
'value'=>$user->username(),
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'disabled'=>true,
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
// New password
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'newPassword',
|
||||
'label'=>$L->g('New password'),
|
||||
'type'=>'password',
|
||||
'value'=>'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
|
||||
// Confirm password
|
||||
echo Bootstrap::formInputText(array(
|
||||
'name'=>'confirmPassword',
|
||||
'label'=>$L->g('Confirm new password'),
|
||||
'type'=>'password',
|
||||
'value'=>'',
|
||||
'class'=>'',
|
||||
'placeholder'=>'',
|
||||
'tip'=>''
|
||||
));
|
||||
?>
|
||||
|
||||
<?php echo Bootstrap::formClose(); ?>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
|
||||
|
||||
<?php
|
||||
|
||||
echo Bootstrap::pageTitle(array('title'=>$L->g('Users'), 'icon'=>'users'));
|
||||
|
||||
echo Bootstrap::link(array(
|
||||
'title'=>$L->g('add-a-new-user'),
|
||||
'href'=>HTML_PATH_ADMIN_ROOT.'new-user',
|
||||
'icon'=>'plus'
|
||||
));
|
||||
|
||||
echo '
|
||||
<table class="table table-striped mt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('Username').'</th>
|
||||
<th class="border-bottom-0 d-none d-lg-table-cell" scope="col">'.$L->g('Nickname').'</th>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('Email').'</th>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('Status').'</th>
|
||||
<th class="border-bottom-0" scope="col">'.$L->g('Role').'</th>
|
||||
<th class="border-bottom-0 d-none d-lg-table-cell" scope="col">'.$L->g('Registered').'</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
';
|
||||
|
||||
$list = $users->keys();
|
||||
foreach ($list as $username) {
|
||||
try {
|
||||
$user = new User($username);
|
||||
echo '<tr>';
|
||||
echo '<td><img class="profilePicture mr-1" alt="" src="'.(Sanitize::pathFile(PATH_UPLOADS_PROFILES.$user->username().'.png')?DOMAIN_UPLOADS_PROFILES.$user->username().'.png':HTML_PATH_CORE_IMG.'default.svg').'" /><a href="'.HTML_PATH_ADMIN_ROOT.'edit-user/'.$username.'">'.$username.'</a></td>';
|
||||
echo '<td class="d-none d-lg-table-cell">'.$user->nickname().'</td>';
|
||||
echo '<td>'.$user->email().'</td>';
|
||||
echo '<td>'.($user->enabled()?'<b>'.$L->g('Enabled').'</b>':$L->g('Disabled')).'</td>';
|
||||
if ($user->role()=='admin') {
|
||||
echo '<td>'.$L->g('Administrator').'</td>';
|
||||
} elseif ($user->role()=='editor') {
|
||||
echo '<td>'.$L->g('Editor').'</td>';
|
||||
} elseif ($user->role()=='author') {
|
||||
echo '<td>'.$L->g('Author').'</td>';
|
||||
} else {
|
||||
echo '<td>'.$L->g('Reader').'</td>';
|
||||
}
|
||||
echo '<td class="d-none d-lg-table-cell">'.Date::format($user->registered(), DB_DATE_FORMAT, ADMIN_PANEL_DATE_FORMAT).'</td>';
|
||||
echo '</tr>';
|
||||
} catch (Exception $e) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
|
||||
echo '
|
||||
</tbody>
|
||||
</table>
|
||||
';
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Change a page's type. Allowed types: published, sticky, static, draft.
|
||||
| Allowed transitions are restricted to the same set on both ends — anything
|
||||
| else (autosave, scheduled) goes through the normal edit flow.
|
||||
|
|
||||
| @_POST['key'] string Page key
|
||||
| @_POST['type'] string Target type
|
||||
|
|
||||
| @return JSON { status, message, key, type }
|
||||
*/
|
||||
|
||||
checkRole(array('admin', 'editor', 'author'));
|
||||
|
||||
$allowed = array('published', 'sticky', 'static', 'draft');
|
||||
|
||||
$key = isset($_POST['key']) ? Sanitize::html($_POST['key']) : false;
|
||||
$newType = isset($_POST['type']) ? Sanitize::html($_POST['type']) : false;
|
||||
|
||||
if (empty($key) || !$pages->exists($key)) {
|
||||
ajaxResponse(1, $L->g('Page not found.'));
|
||||
}
|
||||
|
||||
if (!in_array($newType, $allowed, true)) {
|
||||
ajaxResponse(1, $L->g('Target type is not allowed.'));
|
||||
}
|
||||
|
||||
$current = $pages->db[$key]['type'];
|
||||
if (!in_array($current, $allowed, true)) {
|
||||
ajaxResponse(1, $L->g('Current page type cannot be changed from this menu.'));
|
||||
}
|
||||
|
||||
if ($current === $newType) {
|
||||
ajaxResponse(0, $L->g('Page type unchanged.'), array(
|
||||
'key' => $key,
|
||||
'type' => $newType
|
||||
));
|
||||
}
|
||||
|
||||
// Authors can only change their own pages
|
||||
if (checkRole(array('author'), false)) {
|
||||
if ($pages->db[$key]['username'] !== $login->username()) {
|
||||
ajaxResponse(1, $L->g('Permission denied.'));
|
||||
}
|
||||
}
|
||||
|
||||
// Don't let a static parent be moved away from "static" while it has children;
|
||||
// otherwise the descendants get orphaned in the static tree (getStaticDB filters by type).
|
||||
if ($current === 'static' && $newType !== 'static') {
|
||||
try {
|
||||
$page = new Page($key);
|
||||
if (count($page->children()) > 0) {
|
||||
ajaxResponse(1, $L->g('Cannot change type while the page has children.'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
ajaxResponse(1, $L->g('Page not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($pages->setField($key, 'type', $newType) === false) {
|
||||
ajaxResponse(1, $L->g('Failed to update page type.'));
|
||||
}
|
||||
|
||||
ajaxResponse(0, $L->g('Page type updated.'), array(
|
||||
'key' => $key,
|
||||
'type' => $newType
|
||||
));
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// $_GET
|
||||
// ----------------------------------------------------------------------------
|
||||
// (string) $_GET['query']
|
||||
$query = isset($_GET['query']) ? Text::lowercase($_GET['query']) : false;
|
||||
// ----------------------------------------------------------------------------
|
||||
if ($query===false) {
|
||||
ajaxResponse(1, 'Invalid query.');
|
||||
}
|
||||
|
||||
$result = array();
|
||||
|
||||
// MENU
|
||||
if (Text::stringContains(Text::lowercase($L->g('New content')), $query)) {
|
||||
$tmp = array('disabled'=>true, 'icon'=>'plus-circle', 'type'=>'menu');
|
||||
$tmp['text'] = $L->g('New content');
|
||||
$tmp['url'] = HTML_PATH_ADMIN_ROOT.'new-content';
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
if (Text::stringContains(Text::lowercase($L->g('New category')), $query)) {
|
||||
$tmp = array('disabled'=>true, 'icon'=>'tag', 'type'=>'menu');
|
||||
$tmp['text'] = $L->g('New category');
|
||||
$tmp['url'] = HTML_PATH_ADMIN_ROOT.'new-category';
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
if (Text::stringContains(Text::lowercase($L->g('New user')), $query)) {
|
||||
$tmp = array('disabled'=>true, 'icon'=>'user', 'type'=>'menu');
|
||||
$tmp['text'] = $L->g('New user');
|
||||
$tmp['url'] = HTML_PATH_ADMIN_ROOT.'new-user';
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
if (Text::stringContains(Text::lowercase($L->g('Categories')), $query)) {
|
||||
$tmp = array('disabled'=>true, 'icon'=>'tags', 'type'=>'menu');
|
||||
$tmp['text'] = $L->g('Categories');
|
||||
$tmp['url'] = HTML_PATH_ADMIN_ROOT.'categories';
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
if (Text::stringContains(Text::lowercase($L->g('Users')), $query)) {
|
||||
$tmp = array('disabled'=>true, 'icon'=>'users', 'type'=>'menu');
|
||||
$tmp['text'] = $L->g('Users');
|
||||
$tmp['url'] = HTML_PATH_ADMIN_ROOT.'users';
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
|
||||
|
||||
// PAGES
|
||||
$pagesKey = $pages->getDB();
|
||||
foreach ($pagesKey as $pageKey) {
|
||||
try {
|
||||
$page = new Page($pageKey);
|
||||
$lowerTitle = Text::lowercase($page->title());
|
||||
if (Text::stringContains($lowerTitle, $query)) {
|
||||
$tmp = array('disabled'=>true);
|
||||
$tmp['id'] = $page->key();
|
||||
$tmp['text'] = $page->title();
|
||||
$tmp['type'] = $page->type();
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
exit (json_encode(array('results'=>$result)));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Search for pages that have in the title the string $query and returns the array of pages
|
||||
|
|
||||
| @_GET['published'] boolean True to search in published database
|
||||
| @_GET['static'] boolean True to search in static database
|
||||
| @_GET['sticky'] boolean True to search in sticky database
|
||||
| @_GET['scheduled'] boolean True to search in scheduled database
|
||||
| @_GET['draft'] boolean True to search in draft database
|
||||
| @_GET['query'] string Text to search in the title
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_GET
|
||||
// ----------------------------------------------------------------------------
|
||||
$published = empty($_GET['published']) ? false:true;
|
||||
$static = empty($_GET['static']) ? false:true;
|
||||
$sticky = empty($_GET['sticky']) ? false:true;
|
||||
$scheduled = empty($_GET['scheduled']) ? false:true;
|
||||
$draft = empty($_GET['draft']) ? false:true;
|
||||
$query = isset($_GET['query']) ? Text::lowercase($_GET['query']) : false;
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
if ($query===false) {
|
||||
ajaxResponse(1, 'Invalid query.');
|
||||
}
|
||||
|
||||
$pageNumber = 1;
|
||||
$numberOfItems = -1;
|
||||
$pagesKey = $pages->getList($pageNumber, $numberOfItems, $published, $static, $sticky, $draft, $scheduled);
|
||||
$tmp = array();
|
||||
foreach ($pagesKey as $pageKey) {
|
||||
try {
|
||||
$page = new Page($pageKey);
|
||||
$lowerTitle = Text::lowercase($page->title());
|
||||
if (Text::stringContains($lowerTitle, $query)) {
|
||||
$tmp[$page->key()] = $page->json(true);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
exit (json_encode($tmp));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Delete an image from a particular page
|
||||
|
|
||||
| @_POST['filename'] string Name of the file to delete
|
||||
| @_POST['uuid'] string Page UUID
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
$filename = isset($_POST['filename']) ? $_POST['filename'] : false;
|
||||
$uuid = empty($_POST['uuid']) ? false : $_POST['uuid'];
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
if ($filename===false) {
|
||||
ajaxResponse(1, 'The filename is empty.');
|
||||
}
|
||||
|
||||
if ($uuid && IMAGE_RESTRICT) {
|
||||
if (Text::stringContains($uuid, DS, false)) {
|
||||
ajaxResponse(1, 'Invalid uuid.');
|
||||
}
|
||||
$imagePath = PATH_UPLOADS_PAGES.$uuid.DS;
|
||||
$thumbnailPath = PATH_UPLOADS_PAGES.$uuid.DS.'thumbnails'.DS;
|
||||
} else {
|
||||
$imagePath = PATH_UPLOADS;
|
||||
$thumbnailPath = PATH_UPLOADS_THUMBNAILS;
|
||||
}
|
||||
|
||||
// Delete the original
|
||||
if (Sanitize::pathFile($imagePath.$filename)) {
|
||||
Filesystem::rmfile($imagePath.$filename);
|
||||
}
|
||||
|
||||
// Delete the thumbnail. Exact-name match is the fast path (new uploads have
|
||||
// matching extensions). If no exact match, fall back to any allowed-extension
|
||||
// match on the basename — this recovers legacy pairs where thumbnails were
|
||||
// forced to .jpg while the original kept its real extension. Before deleting
|
||||
// a mismatched candidate, verify no other original owns that extension, to
|
||||
// avoid taking out an unrelated image's thumbnail.
|
||||
if (Sanitize::pathFile($thumbnailPath.$filename) && is_file($thumbnailPath.$filename)) {
|
||||
Filesystem::rmfile($thumbnailPath.$filename);
|
||||
} else {
|
||||
$base = pathinfo($filename, PATHINFO_FILENAME);
|
||||
foreach ($GLOBALS['ALLOWED_IMG_EXTENSION'] as $ext) {
|
||||
$candidate = $base.'.'.$ext;
|
||||
if ($candidate === $filename) {
|
||||
continue;
|
||||
}
|
||||
if (is_file($imagePath.$candidate)) {
|
||||
continue;
|
||||
}
|
||||
if (Sanitize::pathFile($thumbnailPath.$candidate) && is_file($thumbnailPath.$candidate)) {
|
||||
Filesystem::rmfile($thumbnailPath.$candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ajaxResponse(0, 'Image deleted.');
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Generate a slug text for the URL
|
||||
|
|
||||
| @_POST['text'] string The text from where is generated the slug
|
||||
| @_POST['parentKey'] string The parent key if the page has one
|
||||
| @_POST['currentKey'] string The current page key
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
$text = isset($_POST['text']) ? $_POST['text'] : '';
|
||||
$parent = isset($_POST['parentKey']) ? $_POST['parentKey'] : '';
|
||||
$oldKey = isset($_POST['currentKey']) ? $_POST['currentKey'] : '';
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
$slug = $pages->generateKey($text, $parent, $returnSlug=true, $oldKey);
|
||||
|
||||
ajaxResponse(0, 'Slug generated.', array(
|
||||
'slug'=>$slug
|
||||
));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Returns a list of pages and the title contains the query string
|
||||
| The returned list have published, sticky and statics pages
|
||||
|
|
||||
| @_POST['query'] string The string to search in the title of the pages
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_GET
|
||||
// ----------------------------------------------------------------------------
|
||||
// (string) $_GET['query']
|
||||
$query = isset($_GET['query']) ? Text::lowercase($_GET['query']) : false;
|
||||
// (boolean) $_GET['checkIsParent']
|
||||
$checkIsParent = empty($_GET['checkIsParent']) ? false : true;
|
||||
// ----------------------------------------------------------------------------
|
||||
if ($query===false) {
|
||||
ajaxResponse(1, 'Invalid query.');
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$pagesKey = $pages->getDB();
|
||||
foreach ($pagesKey as $pageKey) {
|
||||
try {
|
||||
$page = new Page($pageKey);
|
||||
if ($page->isParent() || !$checkIsParent) {
|
||||
// Check page status
|
||||
if ($page->published() || $page->sticky() || $page->isStatic()) {
|
||||
// Check if the query contains in the title
|
||||
$lowerTitle = Text::lowercase($page->title());
|
||||
if (Text::stringContains($lowerTitle, $query)) {
|
||||
$tmp = array('disabled'=>false);
|
||||
$tmp['id'] = $page->key();
|
||||
$tmp['text'] = $page->title();
|
||||
$tmp['type'] = $page->type();
|
||||
array_push($result, $tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
exit (json_encode(array('results'=>$result)));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Returns a list of images from a particular page
|
||||
|
|
||||
| @_POST['pageNumber'] int Page number for the paginator
|
||||
| @_POST['path'] string Pre-defined name for the directory to read, its pre-defined to avoid security issues
|
||||
| @_POST['uuid'] string Page UUID
|
||||
|
|
||||
| @return array Each file is an object with 'filename' (original) and
|
||||
| 'thumbnail' (resolved preview filename — may differ from
|
||||
| the original for legacy pairs or fall back to it when no
|
||||
| thumbnail exists).
|
||||
*/
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
// $_POST['pageNumber'] > 0
|
||||
$pageNumber = empty($_POST['pageNumber']) ? 1 : (int)$_POST['pageNumber'];
|
||||
$pageNumber = $pageNumber - 1;
|
||||
|
||||
$path = empty($_POST['path']) ? false : $_POST['path'];
|
||||
$uuid = empty($_POST['uuid']) ? false : $_POST['uuid'];
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// The only accepted value is kept for backward-compat with clients that
|
||||
// preserve the old contract; the server now scans originals regardless.
|
||||
if ($path !== 'thumbnails') {
|
||||
ajaxResponse(1, 'Invalid path.');
|
||||
}
|
||||
|
||||
// Resolve the originals and thumbnails directories
|
||||
if ($uuid && IMAGE_RESTRICT) {
|
||||
if (Text::stringContains($uuid, DS, false)) {
|
||||
ajaxResponse(1, 'Invalid uuid.');
|
||||
}
|
||||
$imagePath = PATH_UPLOADS_PAGES.$uuid.DS;
|
||||
$thumbnailPath = PATH_UPLOADS_PAGES.$uuid.DS.'thumbnails'.DS;
|
||||
} else {
|
||||
$imagePath = PATH_UPLOADS;
|
||||
$thumbnailPath = PATH_UPLOADS_THUMBNAILS;
|
||||
}
|
||||
|
||||
// Scan originals and pair each with its matching thumbnail
|
||||
$listOfFilesByPage = mediaManagerListImages($imagePath, $thumbnailPath, MEDIA_MANAGER_NUMBER_OF_FILES);
|
||||
|
||||
if (isset($listOfFilesByPage[$pageNumber])) {
|
||||
ajaxResponse(0, 'List of files and number of chunks.', array(
|
||||
'numberOfPages'=>count($listOfFilesByPage),
|
||||
'files'=>$listOfFilesByPage[$pageNumber]
|
||||
));
|
||||
}
|
||||
|
||||
ajaxResponse(0, 'List of files and number of chunks.', array(
|
||||
'numberOfPages'=>0,
|
||||
'files'=>array()
|
||||
));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Delete the site logo
|
||||
| This script delete the file and set and empty string in the database
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// Delete the file
|
||||
$logoFilename = $site->logo(false);
|
||||
if ($logoFilename) {
|
||||
Filesystem::rmfile(PATH_UPLOADS.$logoFilename);
|
||||
}
|
||||
|
||||
// Remove the logo from the database
|
||||
$site->set(array('logo'=>''));
|
||||
|
||||
ajaxResponse(0, 'Logo removed.');
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Upload site logo
|
||||
| The final filename is the site's name and the extension is the same as the file uploaded
|
||||
|
|
||||
| @_FILES['inputFile'] multipart/form-data File from form
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
if (!isset($_FILES['inputFile'])) {
|
||||
ajaxResponse(1, 'Error trying to upload the site logo.');
|
||||
}
|
||||
|
||||
// Check path traversal on $filename
|
||||
if (Text::stringContains($_FILES['inputFile']['name'], DS, false)) {
|
||||
$message = 'Path traversal detected.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Block dotfiles
|
||||
if (strpos($_FILES['inputFile']['name'], '.') === 0) {
|
||||
$message = 'File type not allowed.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// File extension
|
||||
$fileExtension = Filesystem::extension($_FILES['inputFile']['name']);
|
||||
$fileExtension = Text::lowercase($fileExtension);
|
||||
if (!in_array($fileExtension, $GLOBALS['ALLOWED_IMG_EXTENSION'])) {
|
||||
$message = $L->g('File type is not supported. Allowed types:') . ' ' . implode(', ', $GLOBALS['ALLOWED_IMG_EXTENSION']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// File MIME Type
|
||||
$fileMimeType = Filesystem::mimeType($_FILES['inputFile']['tmp_name']);
|
||||
if ($fileMimeType !== false) {
|
||||
if (!in_array($fileMimeType, $GLOBALS['ALLOWED_IMG_MIMETYPES'])) {
|
||||
$message = $L->g('File mime type is not supported. Allowed types:') . ' ' . implode(', ', $GLOBALS['ALLOWED_IMG_MIMETYPES']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
// Final filename
|
||||
$filename = 'logo.' . $fileExtension;
|
||||
if (Text::isNotEmpty($site->title())) {
|
||||
$sanitizedTitle = Text::removeSpecialCharacters($site->title(), '-');
|
||||
$sanitizedTitle = Text::removeQuotes($sanitizedTitle);
|
||||
$sanitizedTitle = Text::removeSpaces($sanitizedTitle, '-');
|
||||
$sanitizedTitle = trim($sanitizedTitle, '-');
|
||||
if (Text::isNotEmpty($sanitizedTitle)) {
|
||||
$filename = $sanitizedTitle . '.' . $fileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old image
|
||||
$oldFilename = $site->logo(false);
|
||||
if ($oldFilename) {
|
||||
Filesystem::rmfile(PATH_UPLOADS . $oldFilename);
|
||||
}
|
||||
|
||||
// Move from temporary directory to uploads
|
||||
Filesystem::mv($_FILES['inputFile']['tmp_name'], PATH_UPLOADS . $filename);
|
||||
|
||||
// Permissions
|
||||
chmod(PATH_UPLOADS . $filename, 0644);
|
||||
|
||||
// Store the filename in the database
|
||||
$site->set(array('logo' => $filename));
|
||||
|
||||
ajaxResponse(0, 'Image uploaded.', array(
|
||||
'filename' => $filename,
|
||||
'absoluteURL' => DOMAIN_UPLOADS . $filename,
|
||||
'absolutePath' => PATH_UPLOADS . $filename
|
||||
));
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
// (string) $_POST['username']
|
||||
$username = empty($_POST['username']) ? false : $_POST['username'];
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
if ($username===false) {
|
||||
ajaxResponse(1, 'Error in username.');
|
||||
}
|
||||
|
||||
if ( ($login->role()!='admin') && ($login->username()!=$username) ) {
|
||||
ajaxResponse(1, 'Error in username.');
|
||||
}
|
||||
|
||||
if (!isset($_FILES['profilePictureInputFile'])) {
|
||||
ajaxResponse(1, 'Error trying to upload the profile picture.');
|
||||
}
|
||||
|
||||
// Check path traversal
|
||||
if (Text::stringContains($username, DS, false)) {
|
||||
$message = 'Path traversal detected.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Block dotfiles
|
||||
if (strpos($_FILES['profilePictureInputFile']['name'], '.') === 0) {
|
||||
$message = 'File type not allowed.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Sanitize username for filename to prevent issues with special characters
|
||||
$sanitizedUsername = Text::removeSpecialCharacters($username, '-');
|
||||
$sanitizedUsername = Text::removeQuotes($sanitizedUsername);
|
||||
$sanitizedUsername = Text::removeSpaces($sanitizedUsername, '-');
|
||||
|
||||
// Check file extension
|
||||
$fileExtension = Filesystem::extension($_FILES['profilePictureInputFile']['name']);
|
||||
$fileExtension = Text::lowercase($fileExtension);
|
||||
if (!in_array($fileExtension, $GLOBALS['ALLOWED_IMG_EXTENSION']) ) {
|
||||
$message = $L->g('File type is not supported. Allowed types:').' '.implode(', ',$GLOBALS['ALLOWED_IMG_EXTENSION']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Check file MIME Type
|
||||
$fileMimeType = Filesystem::mimeType($_FILES['profilePictureInputFile']['tmp_name']);
|
||||
if ($fileMimeType!==false) {
|
||||
if (!in_array($fileMimeType, $GLOBALS['ALLOWED_IMG_MIMETYPES'])) {
|
||||
$message = $L->g('File mime type is not supported. Allowed types:').' '.implode(', ',$GLOBALS['ALLOWED_IMG_MIMETYPES']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
// Tmp filename
|
||||
$tmpFilename = $sanitizedUsername.'.'.$fileExtension;
|
||||
|
||||
// Final filename
|
||||
$filename = $sanitizedUsername.'.png';
|
||||
|
||||
// Ensure Bludit tmp directory exists
|
||||
if (!Filesystem::directoryExists(PATH_TMP)) {
|
||||
if (!Filesystem::mkdir(PATH_TMP, true)) {
|
||||
$message = 'Temporary directory does not exist and cannot be created.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
// Move from temporary directory to uploads folder
|
||||
$moved = rename($_FILES['profilePictureInputFile']['tmp_name'], PATH_TMP.$tmpFilename);
|
||||
if (!$moved) {
|
||||
$message = 'Error moving uploaded file to temporary directory.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Resize and convert to png
|
||||
$image = new Image();
|
||||
if ($image->setImage(PATH_TMP.$tmpFilename, PROFILE_IMG_WIDTH, PROFILE_IMG_HEIGHT, 'crop') === false) {
|
||||
Filesystem::rmfile(PATH_TMP.$tmpFilename);
|
||||
$message = 'Profile picture upload failed: GD cannot decode the image (unsupported format or corrupted file).';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
$image->saveImage(PATH_UPLOADS_PROFILES.$filename, PROFILE_IMG_QUALITY, false, true);
|
||||
|
||||
// Delete temporary file
|
||||
Filesystem::rmfile(PATH_TMP.$tmpFilename);
|
||||
|
||||
// Permissions
|
||||
chmod(PATH_UPLOADS_PROFILES.$filename, 0644);
|
||||
|
||||
ajaxResponse(0, 'Image uploaded.', array(
|
||||
'filename'=>$filename,
|
||||
'absoluteURL'=>DOMAIN_UPLOADS_PROFILES.$filename,
|
||||
'absolutePath'=>PATH_UPLOADS_PROFILES.$filename
|
||||
));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Create/edit a page and save as draft
|
||||
| If the UUID already exists the page is updated
|
||||
|
|
||||
| @_POST['title'] string Page title
|
||||
| @_POST['content'] string Page content
|
||||
| @_POST['uuid'] string Page uuid
|
||||
| @_POST['uuid'] string Page type, by default is draft
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
$title = isset($_POST['title']) ? $_POST['title'] : false;
|
||||
$content = isset($_POST['content']) ? $_POST['content'] : false;
|
||||
$uuid = isset($_POST['uuid']) ? $_POST['uuid'] : false;
|
||||
$type = isset($_POST['type']) ? $_POST['type'] : 'draft';
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Check UUID
|
||||
if (empty($uuid)) {
|
||||
ajaxResponse(1, 'Save as draft fail. UUID not defined.');
|
||||
}
|
||||
|
||||
$page = array(
|
||||
'uuid'=>$uuid,
|
||||
'key'=>$uuid,
|
||||
'slug'=>$uuid,
|
||||
'title'=>$title,
|
||||
'content'=>$content,
|
||||
'type'=>$type
|
||||
);
|
||||
|
||||
// Get the page key by the UUID
|
||||
$pageKey = $pages->getByUUID($uuid);
|
||||
|
||||
// if pageKey is empty means the page doesn't exist
|
||||
if (empty($pageKey)) {
|
||||
createPage($page);
|
||||
} else {
|
||||
editPage($page);
|
||||
}
|
||||
|
||||
ajaxResponse(0, 'Save as draft successfully.', array(
|
||||
'uuid'=>$uuid
|
||||
));
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
/*
|
||||
| Upload an image to a particular page
|
||||
|
|
||||
| @_POST['uuid'] string Page uuid
|
||||
|
|
||||
| @return array
|
||||
*/
|
||||
|
||||
// $_POST
|
||||
// ----------------------------------------------------------------------------
|
||||
$uuid = empty($_POST['uuid']) ? false : $_POST['uuid'];
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Check path traversal on $uuid
|
||||
if ($uuid) {
|
||||
if (Text::stringContains($uuid, DS, false)) {
|
||||
$message = 'Path traversal detected.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
// Set upload directory
|
||||
if ($uuid && IMAGE_RESTRICT) {
|
||||
$imageDirectory = PATH_UPLOADS_PAGES . $uuid . DS;
|
||||
$thumbnailDirectory = $imageDirectory . 'thumbnails' . DS;
|
||||
if (!Filesystem::directoryExists($thumbnailDirectory)) {
|
||||
Filesystem::mkdir($thumbnailDirectory, true);
|
||||
}
|
||||
} else {
|
||||
$imageDirectory = PATH_UPLOADS;
|
||||
$thumbnailDirectory = PATH_UPLOADS_THUMBNAILS;
|
||||
}
|
||||
|
||||
$images = array();
|
||||
foreach ($_FILES['images']['name'] as $uuid => $filename) {
|
||||
// Check for errors
|
||||
if ($_FILES['images']['error'][$uuid] != 0) {
|
||||
$message = $L->g('Maximum load file size allowed:') . ' ' . ini_get('upload_max_filesize');
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Convert URL characters such as spaces or quotes to characters
|
||||
$filename = urldecode($filename);
|
||||
|
||||
// Sanitize filename to prevent issues with special characters
|
||||
$filenameWithoutExt = Filesystem::filename($filename);
|
||||
$filenameWithoutExt = Text::removeSpecialCharacters($filenameWithoutExt, '-');
|
||||
$filenameWithoutExt = Text::removeQuotes($filenameWithoutExt);
|
||||
$filenameWithoutExt = Text::removeSpaces($filenameWithoutExt, '-');
|
||||
$fileExtension = Filesystem::extension($filename);
|
||||
$filename = $filenameWithoutExt . '.' . $fileExtension;
|
||||
|
||||
// Block dotfiles
|
||||
if (strpos($filename, '.') === 0) {
|
||||
$message = 'File type not allowed.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Check path traversal on $filename
|
||||
if (Text::stringContains($filename, DS, false)) {
|
||||
$message = 'Path traversal detected.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Check file extension
|
||||
$fileExtension = Filesystem::extension($filename);
|
||||
$fileExtension = Text::lowercase($fileExtension);
|
||||
if (!in_array($fileExtension, $GLOBALS['ALLOWED_IMG_EXTENSION'])) {
|
||||
$message = $L->g('File type is not supported. Allowed types:') . ' ' . implode(', ', $GLOBALS['ALLOWED_IMG_EXTENSION']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Check file MIME Type
|
||||
$fileMimeType = Filesystem::mimeType($_FILES['images']['tmp_name'][$uuid]);
|
||||
if ($fileMimeType === false) {
|
||||
$message = $L->g('File mime type is not supported. Allowed types:') . ' ' . implode(', ', $GLOBALS['ALLOWED_IMG_MIMETYPES']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
if (!in_array($fileMimeType, $GLOBALS['ALLOWED_IMG_MIMETYPES'])) {
|
||||
$message = $L->g('File mime type is not supported. Allowed types:') . ' ' . implode(', ', $GLOBALS['ALLOWED_IMG_MIMETYPES']);
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Ensure Bludit tmp directory exists
|
||||
if (!Filesystem::directoryExists(PATH_TMP)) {
|
||||
if (!Filesystem::mkdir(PATH_TMP, true)) {
|
||||
$message = 'Temporary directory does not exist and cannot be created.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
// Move from PHP tmp file to Bludit tmp directory
|
||||
$moved = Filesystem::mv($_FILES['images']['tmp_name'][$uuid], PATH_TMP . $filename);
|
||||
if (!$moved) {
|
||||
$message = 'Error moving uploaded file to temporary directory.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
|
||||
// Transform the image and generate the thumbnail
|
||||
$image = transformImage(PATH_TMP . $filename, $imageDirectory, $thumbnailDirectory);
|
||||
|
||||
if ($image) {
|
||||
chmod($image, 0644);
|
||||
$filename = Filesystem::filename($image);
|
||||
array_push($images, $filename);
|
||||
} else {
|
||||
$message = 'Error after transformImage() function.';
|
||||
Log::set($message, LOG_TYPE_ERROR);
|
||||
ajaxResponse(1, $message);
|
||||
}
|
||||
}
|
||||
|
||||
ajaxResponse(0, 'Images uploaded.', array(
|
||||
'images' => $images
|
||||
));
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Start the session
|
||||
// If the session is not possible to start the admin area is not available
|
||||
Session::start($site->urlPath(), $site->isHTTPS());
|
||||
if (Session::started()===false) {
|
||||
exit('Bludit CMS. Session initialization failed.');
|
||||
}
|
||||
|
||||
$login = new Login();
|
||||
|
||||
$layout = array(
|
||||
'controller'=>null,
|
||||
'view'=>null,
|
||||
'template'=>'index.php',
|
||||
'slug'=>null,
|
||||
'plugin'=>false,
|
||||
'parameters'=>null,
|
||||
'title'=>'Bludit'
|
||||
);
|
||||
|
||||
// Get the Controller
|
||||
$explodeSlug = $url->explodeSlug();
|
||||
$layout['controller'] = $layout['view'] = $layout['slug'] = empty($explodeSlug[0])?'dashboard':$explodeSlug[0];
|
||||
unset($explodeSlug[0]);
|
||||
|
||||
// Get the Plugins
|
||||
include(PATH_RULES.'60.plugins.php');
|
||||
// Check if the user want to access to an admin controller or view from a plugin
|
||||
if ($layout['controller'] === 'plugin' && !empty($explodeSlug)) {
|
||||
// Lowercase plugins class name to search by case-insensitive
|
||||
$pluginsLowerCases = array_change_key_case($pluginsInstalled);
|
||||
$pluginName = Text::lowercase(array_shift($explodeSlug));
|
||||
if (isset($pluginsLowerCases[$pluginName])) {
|
||||
$layout['plugin'] = $pluginsLowerCases[$pluginName];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the URL parameters
|
||||
$layout['parameters'] = implode('/', $explodeSlug);
|
||||
|
||||
// --- AJAX ---
|
||||
if ($layout['slug']==='ajax') {
|
||||
if ($login->isLogged()) {
|
||||
// Rules: Security check CSRF
|
||||
include(PATH_RULES.'99.security.php');
|
||||
|
||||
// Load the ajax file
|
||||
if (Sanitize::pathFile(PATH_AJAX, $layout['parameters'].'.php')) {
|
||||
include(PATH_AJAX.$layout['parameters'].'.php');
|
||||
}
|
||||
}
|
||||
header('HTTP/1.1 401 User not logged.');
|
||||
exit(0);
|
||||
}
|
||||
// --- ADMIN AREA ---
|
||||
else
|
||||
{
|
||||
// Boot rules
|
||||
include(PATH_RULES.'69.pages.php');
|
||||
include(PATH_RULES.'99.header.php');
|
||||
include(PATH_RULES.'99.paginator.php');
|
||||
include(PATH_RULES.'99.themes.php');
|
||||
include(PATH_RULES.'99.security.php');
|
||||
|
||||
// Page not found.
|
||||
// User not logged.
|
||||
// Slug is login.
|
||||
if ($url->notFound() || !$login->isLogged() || ($url->slug()==='login') ) {
|
||||
$layout['controller'] = 'login';
|
||||
$layout['view'] = 'login';
|
||||
$layout['template'] = 'login.php';
|
||||
|
||||
// Generate the tokenCSRF for the user not logged, when the user log-in the token will be changed.
|
||||
$security->generateTokenCSRF();
|
||||
}
|
||||
|
||||
// Define variables
|
||||
$ADMIN_CONTROLLER = $layout['controller'];
|
||||
$ADMIN_VIEW = $layout['view'];
|
||||
|
||||
// Load plugins before the admin area will be load.
|
||||
Theme::plugins('beforeAdminLoad');
|
||||
|
||||
// Load init.php if the theme has one.
|
||||
if (Sanitize::pathFile(PATH_ADMIN_THEMES, $site->adminTheme().DS.'init.php')) {
|
||||
include(PATH_ADMIN_THEMES.$site->adminTheme().DS.'init.php');
|
||||
}
|
||||
|
||||
// Load controller.
|
||||
if (Sanitize::pathFile(PATH_ADMIN_CONTROLLERS, $layout['controller'].'.php')) {
|
||||
include(PATH_ADMIN_CONTROLLERS.$layout['controller'].'.php');
|
||||
} elseif ($layout['plugin'] && method_exists($layout['plugin'], 'adminController')) {
|
||||
$layout['plugin']->adminController();
|
||||
}
|
||||
|
||||
// Load view and theme.
|
||||
if (Sanitize::pathFile(PATH_ADMIN_THEMES, $site->adminTheme().DS.$layout['template'])) {
|
||||
include(PATH_ADMIN_THEMES.$site->adminTheme().DS.$layout['template']);
|
||||
}
|
||||
|
||||
// Load plugins after the admin area is loaded.
|
||||
Theme::plugins('afterAdminLoad');
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Bludit version
|
||||
define('BLUDIT_VERSION', '3.22.0');
|
||||
define('BLUDIT_CODENAME', 'BrownBear');
|
||||
define('BLUDIT_RELEASE_DATE', '2026-05-10');
|
||||
define('BLUDIT_BUILD', '20260510');
|
||||
|
||||
// Change to TRUE for debugging
|
||||
define('DEBUG_MODE', FALSE);
|
||||
define('DEBUG_TYPE', 'INFO'); // INFO, TRACE
|
||||
|
||||
// This determines whether errors should be printed to the screen as part of the output or if they should be hidden from the user.
|
||||
ini_set("display_errors", 0);
|
||||
|
||||
// Even when display_errors is on, errors that occur during PHP's startup sequence are not displayed.
|
||||
// It's strongly recommended to keep display_startup_errors off, except for debugging.
|
||||
ini_set('display_startup_errors', 0);
|
||||
|
||||
// If disabled, error message will be solely plain text instead HTML code.
|
||||
ini_set("html_errors", 0);
|
||||
|
||||
// Tells whether script error messages should be logged to the server's error log or error_log.
|
||||
ini_set('log_errors', 1);
|
||||
|
||||
if (DEBUG_MODE) {
|
||||
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
|
||||
} else {
|
||||
error_reporting(E_ERROR);
|
||||
}
|
||||
|
||||
// PHP paths
|
||||
// PATH_ROOT and PATH_BOOT are defined in index.php
|
||||
define('PATH_LANGUAGES', PATH_ROOT . 'bl-languages' . DS);
|
||||
define('PATH_THEMES', PATH_ROOT . 'bl-themes' . DS);
|
||||
define('PATH_PLUGINS', PATH_ROOT . 'bl-plugins' . DS);
|
||||
define('PATH_KERNEL', PATH_ROOT . 'bl-kernel' . DS);
|
||||
define('PATH_CONTENT', PATH_ROOT . 'bl-content' . DS);
|
||||
|
||||
define('PATH_ABSTRACT', PATH_KERNEL . 'abstract' . DS);
|
||||
define('PATH_RULES', PATH_KERNEL . 'boot' . DS . 'rules' . DS);
|
||||
define('PATH_HELPERS', PATH_KERNEL . 'helpers' . DS);
|
||||
define('PATH_AJAX', PATH_KERNEL . 'ajax' . DS);
|
||||
define('PATH_CORE_JS', PATH_KERNEL . 'js' . DS);
|
||||
|
||||
define('PATH_PAGES', PATH_CONTENT . 'pages' . DS);
|
||||
define('PATH_DATABASES', PATH_CONTENT . 'databases' . DS);
|
||||
define('PATH_PLUGINS_DATABASES', PATH_CONTENT . 'databases' . DS . 'plugins' . DS);
|
||||
define('PATH_TMP', PATH_CONTENT . 'tmp' . DS);
|
||||
define('PATH_UPLOADS', PATH_CONTENT . 'uploads' . DS);
|
||||
define('PATH_WORKSPACES', PATH_CONTENT . 'workspaces' . DS);
|
||||
|
||||
define('PATH_UPLOADS_PAGES', PATH_UPLOADS . 'pages' . DS);
|
||||
define('PATH_UPLOADS_PROFILES', PATH_UPLOADS . 'profiles' . DS);
|
||||
define('PATH_UPLOADS_THUMBNAILS', PATH_UPLOADS . 'thumbnails' . DS);
|
||||
|
||||
define('PATH_ADMIN', PATH_KERNEL . 'admin' . DS);
|
||||
define('PATH_ADMIN_THEMES', PATH_ADMIN . 'themes' . DS);
|
||||
define('PATH_ADMIN_CONTROLLERS', PATH_ADMIN . 'controllers' . DS);
|
||||
define('PATH_ADMIN_VIEWS', PATH_ADMIN . 'views' . DS);
|
||||
|
||||
define('DEBUG_FILE', PATH_CONTENT . 'debug.txt');
|
||||
|
||||
// PAGES DATABASE
|
||||
define('DB_PAGES', PATH_DATABASES . 'pages.php');
|
||||
define('DB_SITE', PATH_DATABASES . 'site.php');
|
||||
define('DB_CATEGORIES', PATH_DATABASES . 'categories.php');
|
||||
define('DB_TAGS', PATH_DATABASES . 'tags.php');
|
||||
define('DB_SYSLOG', PATH_DATABASES . 'syslog.php');
|
||||
define('DB_USERS', PATH_DATABASES . 'users.php');
|
||||
define('DB_SECURITY', PATH_DATABASES . 'security.php');
|
||||
|
||||
// User environment variables
|
||||
include(PATH_KERNEL . 'boot' . DS . 'variables.php');
|
||||
|
||||
// Set internal character encoding
|
||||
mb_internal_encoding(CHARSET);
|
||||
|
||||
// Set HTTP output character encoding
|
||||
mb_http_output(CHARSET);
|
||||
|
||||
// Inclde Abstract Classes
|
||||
include(PATH_ABSTRACT . 'dbjson.class.php');
|
||||
include(PATH_ABSTRACT . 'dblist.class.php');
|
||||
include(PATH_ABSTRACT . 'plugin.class.php');
|
||||
|
||||
// Inclde Classes
|
||||
include(PATH_KERNEL . 'pages.class.php');
|
||||
include(PATH_KERNEL . 'users.class.php');
|
||||
include(PATH_KERNEL . 'tags.class.php');
|
||||
include(PATH_KERNEL . 'language.class.php');
|
||||
include(PATH_KERNEL . 'site.class.php');
|
||||
include(PATH_KERNEL . 'categories.class.php');
|
||||
include(PATH_KERNEL . 'syslog.class.php');
|
||||
include(PATH_KERNEL . 'pagex.class.php');
|
||||
include(PATH_KERNEL . 'category.class.php');
|
||||
include(PATH_KERNEL . 'tag.class.php');
|
||||
include(PATH_KERNEL . 'user.class.php');
|
||||
include(PATH_KERNEL . 'url.class.php');
|
||||
include(PATH_KERNEL . 'login.class.php');
|
||||
include(PATH_KERNEL . 'parsedown.class.php');
|
||||
include(PATH_KERNEL . 'security.class.php');
|
||||
|
||||
// Include functions
|
||||
include(PATH_KERNEL . 'functions.php');
|
||||
|
||||
// Include Helpers Classes
|
||||
include(PATH_HELPERS . 'text.class.php');
|
||||
include(PATH_HELPERS . 'log.class.php');
|
||||
include(PATH_HELPERS . 'date.class.php');
|
||||
include(PATH_HELPERS . 'theme.class.php');
|
||||
include(PATH_HELPERS . 'session.class.php');
|
||||
include(PATH_HELPERS . 'redirect.class.php');
|
||||
include(PATH_HELPERS . 'sanitize.class.php');
|
||||
include(PATH_HELPERS . 'valid.class.php');
|
||||
include(PATH_HELPERS . 'email.class.php');
|
||||
include(PATH_HELPERS . 'filesystem.class.php');
|
||||
include(PATH_HELPERS . 'alert.class.php');
|
||||
include(PATH_HELPERS . 'paginator.class.php');
|
||||
include(PATH_HELPERS . 'image.class.php');
|
||||
include(PATH_HELPERS . 'tcp.class.php');
|
||||
include(PATH_HELPERS . 'dom.class.php');
|
||||
include(PATH_HELPERS . 'cookie.class.php');
|
||||
/**
|
||||
* ---------------------------------------------------------------------------
|
||||
* If you have bypassed the license check, I understand.
|
||||
* But please consider supporting the project on Patreon if you use this
|
||||
* commercially. It helps me keep the core free for everyone.
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
define('BLUDIT_PRO_HASH', substr(md5(BLUDIT_BUILD), 0, 8));
|
||||
$_bluditProFile = PATH_KERNEL . 'bludit.pro.' . BLUDIT_PRO_HASH . '.php';
|
||||
if (file_exists($_bluditProFile)) {
|
||||
include($_bluditProFile);
|
||||
}
|
||||
unset($_bluditProFile);
|
||||
|
||||
// Objects
|
||||
$pages = new Pages();
|
||||
$users = new Users();
|
||||
$tags = new Tags();
|
||||
$categories = new Categories();
|
||||
$site = new Site();
|
||||
$url = new Url();
|
||||
$security = new Security();
|
||||
$syslog = new Syslog();
|
||||
|
||||
// --- Relative paths ---
|
||||
// These paths are relative for the user / web browsing.
|
||||
|
||||
// Base URL
|
||||
// The user can define the base URL.
|
||||
// Left empty if you want to Bludit try to detect the base URL.
|
||||
$base = '';
|
||||
|
||||
if (!empty($_SERVER['DOCUMENT_ROOT']) && !empty($_SERVER['SCRIPT_NAME']) && empty($base)) {
|
||||
$base = str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_NAME']);
|
||||
$base = dirname($base);
|
||||
} elseif (empty($base)) {
|
||||
$base = empty($_SERVER['SCRIPT_NAME']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
|
||||
$base = dirname($base);
|
||||
}
|
||||
|
||||
if (strpos($_SERVER['REQUEST_URI'], $base) !== 0) {
|
||||
$base = '/';
|
||||
} elseif ($base != DS) {
|
||||
$base = trim($base, '/');
|
||||
$base = '/' . $base . '/';
|
||||
} else {
|
||||
// Workaround for Windows Web Servers
|
||||
$base = '/';
|
||||
}
|
||||
|
||||
define('HTML_PATH_ROOT', $base);
|
||||
define('HTML_PATH_THEMES', HTML_PATH_ROOT . 'bl-themes/');
|
||||
define('HTML_PATH_THEME', HTML_PATH_THEMES . $site->theme() . '/');
|
||||
define('HTML_PATH_THEME_CSS', HTML_PATH_THEME . 'css/');
|
||||
define('HTML_PATH_THEME_JS', HTML_PATH_THEME . 'js/');
|
||||
define('HTML_PATH_THEME_IMG', HTML_PATH_THEME . 'img/');
|
||||
define('HTML_PATH_ADMIN_ROOT', HTML_PATH_ROOT . ADMIN_URI_FILTER . '/');
|
||||
define('HTML_PATH_ADMIN_THEME', HTML_PATH_ROOT . 'bl-kernel/admin/themes/' . $site->adminTheme() . '/');
|
||||
define('HTML_PATH_ADMIN_THEME_JS', HTML_PATH_ADMIN_THEME . 'js/');
|
||||
define('HTML_PATH_ADMIN_THEME_CSS', HTML_PATH_ADMIN_THEME . 'css/');
|
||||
define('HTML_PATH_CORE_JS', HTML_PATH_ROOT . 'bl-kernel/js/');
|
||||
define('HTML_PATH_CORE_CSS', HTML_PATH_ROOT . 'bl-kernel/css/');
|
||||
define('HTML_PATH_CORE_IMG', HTML_PATH_ROOT . 'bl-kernel/img/');
|
||||
define('HTML_PATH_CONTENT', HTML_PATH_ROOT . 'bl-content/');
|
||||
define('HTML_PATH_UPLOADS', HTML_PATH_ROOT . 'bl-content/uploads/');
|
||||
define('HTML_PATH_UPLOADS_PAGES', HTML_PATH_UPLOADS . 'pages/');
|
||||
define('HTML_PATH_UPLOADS_PROFILES', HTML_PATH_UPLOADS . 'profiles/');
|
||||
define('HTML_PATH_UPLOADS_THUMBNAILS', HTML_PATH_UPLOADS . 'thumbnails/');
|
||||
define('HTML_PATH_PLUGINS', HTML_PATH_ROOT . 'bl-plugins/');
|
||||
|
||||
// --- Objects with dependency ---
|
||||
$language = new Language($site->language());
|
||||
$url->checkFilters($site->uriFilters());
|
||||
|
||||
// --- CONSTANTS with dependency ---
|
||||
|
||||
// Tag URI filter
|
||||
define('TAG_URI_FILTER', $url->filters('tag'));
|
||||
|
||||
// Category URI filter
|
||||
define('CATEGORY_URI_FILTER', $url->filters('category'));
|
||||
|
||||
// Page URI filter
|
||||
define('PAGE_URI_FILTER', $url->filters('page'));
|
||||
|
||||
// Content order by: date / position
|
||||
define('ORDER_BY', $site->orderBy());
|
||||
|
||||
// Allow unicode characters in the URL
|
||||
define('EXTREME_FRIENDLY_URL', $site->extremeFriendly());
|
||||
|
||||
// Minutes to execute the autosave function
|
||||
define('AUTOSAVE_INTERVAL', $site->autosaveInterval());
|
||||
|
||||
// TRUE for upload images restric to a pages, FALSE to upload images in common
|
||||
define('IMAGE_RESTRICT', $site->imageRestrict());
|
||||
|
||||
// TRUE to convert relatives images to absoultes, FALSE No changes apply
|
||||
define('IMAGE_RELATIVE_TO_ABSOLUTE', $site->imageRelativeToAbsolute());
|
||||
|
||||
// TRUE if the markdown parser is enabled
|
||||
define('MARKDOWN_PARSER', $site->markdownParser());
|
||||
|
||||
// --- PHP paths with dependency ---
|
||||
// These paths are absolutes for the OS
|
||||
define('THEME_DIR', PATH_ROOT . 'bl-themes' . DS . $site->theme() . DS);
|
||||
define('THEME_DIR_PHP', THEME_DIR . 'php' . DS);
|
||||
define('THEME_DIR_CSS', THEME_DIR . 'css' . DS);
|
||||
define('THEME_DIR_JS', THEME_DIR . 'js' . DS);
|
||||
define('THEME_DIR_IMG', THEME_DIR . 'img' . DS);
|
||||
define('THEME_DIR_LANG', THEME_DIR . 'languages' . DS);
|
||||
|
||||
// --- Absolute paths with domain ---
|
||||
// These paths are absolutes for the user / web browsing.
|
||||
define('DOMAIN', $site->domain());
|
||||
define('DOMAIN_BASE', DOMAIN . HTML_PATH_ROOT);
|
||||
define('DOMAIN_CORE_JS', DOMAIN . HTML_PATH_CORE_JS);
|
||||
define('DOMAIN_CORE_CSS', DOMAIN . HTML_PATH_CORE_CSS);
|
||||
define('DOMAIN_THEME', DOMAIN . HTML_PATH_THEME);
|
||||
define('DOMAIN_THEME_CSS', DOMAIN . HTML_PATH_THEME_CSS);
|
||||
define('DOMAIN_THEME_JS', DOMAIN . HTML_PATH_THEME_JS);
|
||||
define('DOMAIN_THEME_IMG', DOMAIN . HTML_PATH_THEME_IMG);
|
||||
define('DOMAIN_ADMIN_THEME', DOMAIN . HTML_PATH_ADMIN_THEME);
|
||||
define('DOMAIN_ADMIN_THEME_CSS', DOMAIN . HTML_PATH_ADMIN_THEME_CSS);
|
||||
define('DOMAIN_ADMIN_THEME_JS', DOMAIN . HTML_PATH_ADMIN_THEME_JS);
|
||||
define('DOMAIN_UPLOADS', DOMAIN . HTML_PATH_UPLOADS);
|
||||
define('DOMAIN_UPLOADS_PAGES', DOMAIN . HTML_PATH_UPLOADS_PAGES);
|
||||
define('DOMAIN_UPLOADS_PROFILES', DOMAIN . HTML_PATH_UPLOADS_PROFILES);
|
||||
define('DOMAIN_UPLOADS_THUMBNAILS', DOMAIN . HTML_PATH_UPLOADS_THUMBNAILS);
|
||||
define('DOMAIN_PLUGINS', DOMAIN . HTML_PATH_PLUGINS);
|
||||
define('DOMAIN_CONTENT', DOMAIN . HTML_PATH_CONTENT);
|
||||
|
||||
define('DOMAIN_ADMIN', DOMAIN_BASE . ADMIN_URI_FILTER . '/');
|
||||
|
||||
define('DOMAIN_TAGS', Text::addSlashes(DOMAIN_BASE . TAG_URI_FILTER, false, true));
|
||||
define('DOMAIN_CATEGORIES', Text::addSlashes(DOMAIN_BASE . CATEGORY_URI_FILTER, false, true));
|
||||
define('DOMAIN_PAGES', Text::addSlashes(DOMAIN_BASE . PAGE_URI_FILTER, false, true));
|
||||
|
||||
$ADMIN_CONTROLLER = '';
|
||||
$ADMIN_VIEW = '';
|
||||
$ID_EXECUTION = uniqid(); // string 13 characters long
|
||||
$WHERE_AM_I = $url->whereAmI();
|
||||
|
||||
// --- Objects shortcuts ---
|
||||
$L = $language;
|
||||
|
||||
// DEBUG: Print constants
|
||||
// $arr = array_filter(get_defined_constants(), 'is_string');
|
||||
// echo json_encode($arr);
|
||||
// exit;
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Variables
|
||||
// ============================================================================
|
||||
|
||||
$plugins = array(
|
||||
'siteHead'=>array(),
|
||||
'siteBodyBegin'=>array(),
|
||||
'siteBodyEnd'=>array(),
|
||||
'siteSidebar'=>array(),
|
||||
'beforeSiteLoad'=>array(),
|
||||
'afterSiteLoad'=>array(),
|
||||
|
||||
'pageBegin'=>array(),
|
||||
'pageEnd'=>array(),
|
||||
|
||||
'beforeAdminLoad'=>array(),
|
||||
'afterAdminLoad'=>array(),
|
||||
'adminHead'=>array(),
|
||||
'adminBodyBegin'=>array(),
|
||||
'adminBodyEnd'=>array(),
|
||||
'adminSidebar'=>array(),
|
||||
'adminContentSidebar'=>array(),
|
||||
'dashboard'=>array(),
|
||||
'editorToolbar'=>array(),
|
||||
|
||||
'beforeAll'=>array(),
|
||||
'afterAll'=>array(),
|
||||
|
||||
'paginator'=>array(),
|
||||
|
||||
'afterPageCreate'=>array(),
|
||||
'afterPageModify'=>array(),
|
||||
'afterPageDelete'=>array(),
|
||||
|
||||
'loginHead'=>array(),
|
||||
'loginBodyBegin'=>array(),
|
||||
'loginBodyEnd'=>array(),
|
||||
|
||||
'all'=>array()
|
||||
);
|
||||
|
||||
$pluginsEvents = $plugins;
|
||||
unset($pluginsEvents['all']);
|
||||
|
||||
$pluginsInstalled = array();
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
function buildPlugins()
|
||||
{
|
||||
global $plugins;
|
||||
global $pluginsEvents;
|
||||
global $pluginsInstalled;
|
||||
global $L;
|
||||
global $site;
|
||||
|
||||
// Get declared clasess BEFORE load plugins clasess
|
||||
$currentDeclaredClasess = get_declared_classes();
|
||||
|
||||
// List plugins directories
|
||||
$list = Filesystem::listDirectories(PATH_PLUGINS);
|
||||
// Load each plugin clasess
|
||||
foreach ($list as $pluginPath) {
|
||||
// Check if the directory has the plugin.php
|
||||
if (file_exists($pluginPath.DS.'plugin.php')) {
|
||||
include_once($pluginPath.DS.'plugin.php');
|
||||
}
|
||||
}
|
||||
|
||||
// Get plugins clasess loaded
|
||||
$pluginsDeclaredClasess = array_diff(get_declared_classes(), $currentDeclaredClasess);
|
||||
|
||||
foreach ($pluginsDeclaredClasess as $pluginClass) {
|
||||
$Plugin = new $pluginClass;
|
||||
|
||||
// Check if the plugin is translated
|
||||
$languageFilename = PATH_PLUGINS.$Plugin->directoryName().DS.'languages'.DS.$site->language().'.json';
|
||||
if (!Sanitize::pathFile($languageFilename)) {
|
||||
$languageFilename = PATH_PLUGINS.$Plugin->directoryName().DS.'languages'.DS.DEFAULT_LANGUAGE_FILE;
|
||||
}
|
||||
|
||||
$database = file_get_contents($languageFilename);
|
||||
$database = json_decode($database, true);
|
||||
|
||||
// Set name and description from the language file
|
||||
$Plugin->setMetadata('name',$database['plugin-data']['name']);
|
||||
$Plugin->setMetadata('description',$database['plugin-data']['description']);
|
||||
|
||||
// Remove name and description from the language file loaded and add new words if there are
|
||||
// This function overwrite the key=>value
|
||||
unset($database['plugin-data']);
|
||||
if (!empty($database)) {
|
||||
$L->add($database);
|
||||
}
|
||||
|
||||
// $plugins['all'] Array with all plugins, installed and not installed
|
||||
$plugins['all'][$pluginClass] = $Plugin;
|
||||
|
||||
// If the plugin is installed insert on the hooks
|
||||
if ($Plugin->installed()) {
|
||||
// Include custom hooks
|
||||
if (!empty($Plugin->customHooks)) {
|
||||
foreach ($Plugin->customHooks as $customHook) {
|
||||
if (!isset($plugins[$customHook])) {
|
||||
$plugins[$customHook] = array();
|
||||
$pluginsEvents[$customHook] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pluginsInstalled[$pluginClass] = $Plugin;
|
||||
foreach ($pluginsEvents as $event=>$value) {
|
||||
if (method_exists($Plugin, $event)) {
|
||||
array_push($plugins[$event], $Plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the plugins by the position for the site sidebar
|
||||
uasort($plugins['siteSidebar'], function ($a, $b) {
|
||||
return $a->position() <=> $b->position();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main
|
||||
// ============================================================================
|
||||
|
||||
buildPlugins();
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Redirect admin, from /admin to /admin/
|
||||
if ($url->uri()==HTML_PATH_ROOT.ADMIN_URI_FILTER) {
|
||||
Redirect::url(DOMAIN_ADMIN);
|
||||
}
|
||||
|
||||
// Redirect blog, from /blog to /blog/
|
||||
// This rule only works when the user set a page as homepage
|
||||
if ($url->uri()==HTML_PATH_ROOT.'blog' && $site->homepage()) {
|
||||
$filter = $url->filters('blog');
|
||||
$finalURL = Text::addSlashes(DOMAIN_BASE.$filter, false, true);
|
||||
Redirect::url($finalURL);
|
||||
}
|
||||
|
||||
// Redirect pages, from /my-page/ to /my-page
|
||||
if ($url->whereAmI()=='page' && !$url->notFound()) {
|
||||
$pageKey = $url->slug();
|
||||
if (Text::endsWith($pageKey, '/')) {
|
||||
$pageKey = rtrim($pageKey, '/');
|
||||
Redirect::url(DOMAIN_PAGES.$pageKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Variables
|
||||
// ============================================================================
|
||||
|
||||
// Array with pages, each page is a Page Object
|
||||
// Filtered by pagenumber, number of items per page and sorted by date/position
|
||||
/*
|
||||
array(
|
||||
0 => Page Object,
|
||||
1 => Page Object,
|
||||
...
|
||||
N => Page Object
|
||||
)
|
||||
*/
|
||||
$content = array();
|
||||
|
||||
// Page filtered by the user, is a Page Object
|
||||
$page = false;
|
||||
|
||||
// Array with static content, each item is a Page Object
|
||||
// Order by position
|
||||
/*
|
||||
array(
|
||||
0 => Page Object,
|
||||
1 => Page Object,
|
||||
...
|
||||
N => Page Object
|
||||
)
|
||||
*/
|
||||
$staticContent = $staticPages = buildStaticPages();
|
||||
|
||||
// ============================================================================
|
||||
// Main
|
||||
// ============================================================================
|
||||
|
||||
// Execute the scheduler
|
||||
if ($pages->scheduler()) {
|
||||
// Execute plugins with the hook afterPageCreate
|
||||
Theme::plugins('afterPageCreate');
|
||||
|
||||
reindexTags();
|
||||
reindexCategories();
|
||||
|
||||
// Add to syslog
|
||||
$syslog->add(array(
|
||||
'dictionaryKey'=>'content-published-from-scheduler',
|
||||
'notes'=>''
|
||||
));
|
||||
}
|
||||
|
||||
// Set home page if the user defined one
|
||||
if ($site->homepage() && $url->whereAmI()==='home') {
|
||||
$pageKey = $site->homepage();
|
||||
if ($pages->exists($pageKey)) {
|
||||
$url->setSlug($pageKey);
|
||||
$content[0] = $page = buildThePage();
|
||||
}
|
||||
}
|
||||
|
||||
// Build specific page
|
||||
elseif ($url->whereAmI()==='page') {
|
||||
$content[0] = $page = buildThePage();
|
||||
}
|
||||
// Build content by tag
|
||||
elseif ($url->whereAmI()==='tag') {
|
||||
$content = buildPagesByTag();
|
||||
}
|
||||
// Build content by category
|
||||
elseif ($url->whereAmI()==='category') {
|
||||
$content = buildPagesByCategory();
|
||||
}
|
||||
// Build content for the homepage
|
||||
elseif ( ($url->whereAmI()==='home') || ($url->whereAmI()==='blog') ) {
|
||||
$content = buildPagesForHome();
|
||||
}
|
||||
|
||||
if (isset($content[0])) {
|
||||
$page = $content[0];
|
||||
}
|
||||
|
||||
// If set notFound, create the page 404
|
||||
if ($url->notFound()) {
|
||||
$content[0] = $page = buildErrorPage();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
header('HTTP/1.0 '.$url->httpCode().' '.$url->httpMessage());
|
||||
header('X-Powered-By: Bludit');
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Current page number
|
||||
$currentPage = $url->pageNumber();
|
||||
Paginator::set('currentPage', $currentPage);
|
||||
|
||||
if ($url->whereAmI()=='admin') {
|
||||
$itemsPerPage = ITEMS_PER_PAGE_ADMIN;
|
||||
$numberOfItems = $pages->count(true);
|
||||
} elseif ($url->whereAmI()=='tag') {
|
||||
$itemsPerPage = $site->itemsPerPage();
|
||||
$tagKey = $url->slug();
|
||||
$numberOfItems = $tags->numberOfPages($tagKey);
|
||||
} elseif ($url->whereAmI()=='category') {
|
||||
$itemsPerPage = $site->itemsPerPage();
|
||||
$categoryKey = $url->slug();
|
||||
$numberOfItems = $categories->numberOfPages($categoryKey);
|
||||
} else {
|
||||
$itemsPerPage = $site->itemsPerPage();
|
||||
$numberOfItems = $pages->count(true);
|
||||
}
|
||||
|
||||
// Execute hook from plugins
|
||||
Theme::plugins('paginator');
|
||||
|
||||
// Items per page
|
||||
Paginator::set('itemsPerPage', $itemsPerPage);
|
||||
|
||||
// Amount of items
|
||||
Paginator::set('numberOfItems', $numberOfItems);
|
||||
|
||||
// Amount of pages
|
||||
$numberOfPages = (int) max(ceil($numberOfItems / $itemsPerPage), 1);
|
||||
Paginator::set('numberOfPages', $numberOfPages);
|
||||
|
||||
// TRUE if exists a next page to show
|
||||
$showNext = $numberOfPages > $currentPage;
|
||||
Paginator::set('showNext', $showNext);
|
||||
|
||||
// TRUE if exists a previous page to show
|
||||
$showPrev = $currentPage > Paginator::firstPage();
|
||||
Paginator::set('showPrev', $showPrev);
|
||||
|
||||
// TRUE if exists a next and previous page to show
|
||||
$showNextPrev = $showNext && $showPrev;
|
||||
Paginator::set('showNextPrev', $showNextPrev);
|
||||
|
||||
// Integer with the next page
|
||||
$nextPage = max(0, $currentPage+1);
|
||||
Paginator::set('nextPage', $nextPage);
|
||||
|
||||
// Integer with the previous page
|
||||
$prevPage = min($numberOfPages, $currentPage-1);
|
||||
Paginator::set('prevPage', $prevPage);
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Variables
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// Main before POST
|
||||
// ============================================================================
|
||||
|
||||
// ============================================================================
|
||||
// POST Method
|
||||
// ============================================================================
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$token = isset($_POST['tokenCSRF']) ? Sanitize::html($_POST['tokenCSRF']) : false;
|
||||
if (!$security->validateTokenCSRF($token)) {
|
||||
Log::set(__FILE__.LOG_SEP.'Error occurred when trying to validate the tokenCSRF.', ALERT_STATUS_FAIL);
|
||||
Log::set(__FILE__.LOG_SEP.'Token via POST ['.$token.']', ALERT_STATUS_FAIL);
|
||||
|
||||
Session::destroy();
|
||||
Redirect::page('login');
|
||||
} else {
|
||||
unset( $_POST['tokenCSRF'] );
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main after POST
|
||||
// ============================================================================
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// ============================================================================
|
||||
// Variables
|
||||
// ============================================================================
|
||||
$themePlugin = getPlugin($site->theme()); // Returns plugin object or False
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
// ============================================================================
|
||||
|
||||
function buildThemes()
|
||||
{
|
||||
global $site;
|
||||
|
||||
$themes = array();
|
||||
$themesPaths = Filesystem::listDirectories(PATH_THEMES);
|
||||
|
||||
foreach ($themesPaths as $themePath) {
|
||||
// Check if the theme is translated.
|
||||
$languageFilename = $themePath . DS . 'languages' . DS . $site->language() . '.json';
|
||||
if (!Sanitize::pathFile($languageFilename)) {
|
||||
$languageFilename = $themePath . DS . 'languages' . DS . DEFAULT_LANGUAGE_FILE;
|
||||
}
|
||||
|
||||
if (Sanitize::pathFile($languageFilename)) {
|
||||
$database = file_get_contents($languageFilename);
|
||||
$database = json_decode($database, true);
|
||||
if (empty($database)) {
|
||||
Log::set('99.themes.php' . LOG_SEP . 'Language file error on theme ' . $themePath);
|
||||
break;
|
||||
}
|
||||
|
||||
$database = $database['theme-data'];
|
||||
|
||||
$database['dirname'] = basename($themePath);
|
||||
|
||||
// --- Metadata ---
|
||||
$filenameMetadata = $themePath . DS . 'metadata.json';
|
||||
|
||||
if (Sanitize::pathFile($filenameMetadata)) {
|
||||
$metadataString = file_get_contents($filenameMetadata);
|
||||
$metadata = json_decode($metadataString, true);
|
||||
|
||||
$database['compatible'] = false;
|
||||
if (!empty($metadata['compatible'])) {
|
||||
$bluditRoot = explode('.', BLUDIT_VERSION);
|
||||
$compatible = explode(',', $metadata['compatible']);
|
||||
foreach ($compatible as $version) {
|
||||
$root = explode('.', $version);
|
||||
if ($root[0] == $bluditRoot[0] && $root[1] == $bluditRoot[1]) {
|
||||
$database['compatible'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$database = $database + $metadata;
|
||||
array_push($themes, $database);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main
|
||||
// ============================================================================
|
||||
|
||||
// Load the language file
|
||||
$languageFilename = THEME_DIR . 'languages' . DS . $site->language() . '.json';
|
||||
if (!Sanitize::pathFile($languageFilename)) {
|
||||
$languageFilename = THEME_DIR . 'languages' . DS . DEFAULT_LANGUAGE_FILE;
|
||||
}
|
||||
|
||||
if (Sanitize::pathFile($languageFilename)) {
|
||||
$database = file_get_contents($languageFilename);
|
||||
$database = json_decode($database, true);
|
||||
|
||||
// Remote the name and description.
|
||||
unset($database['theme-data']);
|
||||
|
||||
// Load words from the theme language
|
||||
if (!empty($database)) {
|
||||
$L->add($database);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
// Load plugins rules
|
||||
include(PATH_RULES.'60.plugins.php');
|
||||
|
||||
// Plugins before all
|
||||
Theme::plugins('beforeAll');
|
||||
|
||||
// Load rules
|
||||
include(PATH_RULES.'60.router.php');
|
||||
include(PATH_RULES.'69.pages.php');
|
||||
include(PATH_RULES.'99.header.php');
|
||||
include(PATH_RULES.'99.paginator.php');
|
||||
include(PATH_RULES.'99.themes.php');
|
||||
|
||||
// Plugins before site loaded
|
||||
Theme::plugins('beforeSiteLoad');
|
||||
|
||||
// Theme init.php
|
||||
if (Sanitize::pathFile(PATH_THEMES, $site->theme().DS.'init.php')) {
|
||||
include(PATH_THEMES.$site->theme().DS.'init.php');
|
||||
}
|
||||
|
||||
// Theme HTML
|
||||
if (Sanitize::pathFile(PATH_THEMES, $site->theme().DS.'index.php')) {
|
||||
include(PATH_THEMES.$site->theme().DS.'index.php');
|
||||
} else {
|
||||
$L->p('Please check your theme configuration in the admin panel. Check for an active theme.');
|
||||
}
|
||||
|
||||
// Plugins after site loaded
|
||||
Theme::plugins('afterSiteLoad');
|
||||
|
||||
// Plugins after all
|
||||
Theme::plugins('afterAll');
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
/*
|
||||
Environment variables
|
||||
If you are going to do some changes is recommended do it before the installation
|
||||
*/
|
||||
|
||||
// Log
|
||||
define('LOG_SEP', ' | ');
|
||||
define('LOG_TYPE_INFO', '[INFO]');
|
||||
define('LOG_TYPE_WARN', '[WARN]');
|
||||
define('LOG_TYPE_ERROR', '[ERROR]');
|
||||
|
||||
// Protecting against Symlink attacks
|
||||
define('CHECK_SYMBOLIC_LINKS', TRUE);
|
||||
|
||||
// Alert status ok
|
||||
define('ALERT_STATUS_OK', 0);
|
||||
|
||||
// Alert status fail
|
||||
define('ALERT_STATUS_FAIL', 1);
|
||||
|
||||
// Profile image size
|
||||
define('PROFILE_IMG_WIDTH', 400);
|
||||
define('PROFILE_IMG_HEIGHT', 400);
|
||||
define('PROFILE_IMG_QUALITY', 100); // 100%
|
||||
|
||||
// Items per page for admin area
|
||||
define('ITEMS_PER_PAGE_ADMIN', 20);
|
||||
|
||||
// Password length
|
||||
define('PASSWORD_LENGTH', 6);
|
||||
|
||||
// Password salt length
|
||||
define('SALT_LENGTH', 8);
|
||||
|
||||
// Page brake string
|
||||
define('PAGE_BREAK', '<!-- pagebreak -->');
|
||||
|
||||
// Remember me
|
||||
define('REMEMBER_COOKIE_USERNAME', 'BLUDITREMEMBERUSERNAME');
|
||||
define('REMEMBER_COOKIE_TOKEN', 'BLUDITREMEMBERTOKEN');
|
||||
define('REMEMBER_COOKIE_EXPIRE_IN_DAYS', 30);
|
||||
|
||||
// Filename
|
||||
define('FILENAME', 'index.txt');
|
||||
|
||||
// Database date format
|
||||
define('DB_DATE_FORMAT', 'Y-m-d H:i:s');
|
||||
|
||||
// Database date format
|
||||
define('BACKUP_DATE_FORMAT', 'Y-m-d-H-i-s');
|
||||
|
||||
// Sitemap date format
|
||||
define('SITEMAP_DATE_FORMAT', 'Y-m-d');
|
||||
|
||||
// Date format for Manage Content, Manage Users
|
||||
define('ADMIN_PANEL_DATE_FORMAT', 'D, j M Y, H:i');
|
||||
|
||||
// Date format for Dashboard schedule posts
|
||||
define('SCHEDULED_DATE_FORMAT', 'D, j M Y, H:i');
|
||||
|
||||
// Notifications date format
|
||||
define('NOTIFICATIONS_DATE_FORMAT', 'D, j M Y, H:i');
|
||||
|
||||
// Manage content date format
|
||||
define('MANAGE_CONTENT_DATE_FORMAT', 'D, j M Y, H:i');
|
||||
|
||||
// Amount of items to show on notification panel
|
||||
define('NOTIFICATIONS_AMOUNT', 10);
|
||||
|
||||
// Token time to live for login via email. The offset is defined by http://php.net/manual/en/datetime.modify.php
|
||||
define('TOKEN_EMAIL_TTL', '+15 minutes');
|
||||
|
||||
// Charset, default UTF-8.
|
||||
define('CHARSET', 'UTF-8');
|
||||
|
||||
// Permissions for new directories
|
||||
define('DIR_PERMISSIONS', 0755);
|
||||
|
||||
// Admin URI filter to access to the admin panel
|
||||
define('ADMIN_URI_FILTER', 'admin');
|
||||
|
||||
// Default language file, in this case is English
|
||||
define('DEFAULT_LANGUAGE_FILE', 'en.json');
|
||||
|
||||
// Session timeout server side, gc_maxlifetime
|
||||
// 3600 = 1hour
|
||||
define('SESSION_GC_MAXLIFETIME', 3600);
|
||||
|
||||
// Session lifetime of the cookie in seconds which is sent to the browser
|
||||
// The value 0 means until the browser is closed
|
||||
define('SESSION_COOKIE_LIFE_TIME', 0);
|
||||
|
||||
// Alert notification disappear in X seconds
|
||||
define('ALERT_DISAPPEAR_IN', 3);
|
||||
|
||||
// Number of images to show in the media manager per page
|
||||
define('MEDIA_MANAGER_NUMBER_OF_FILES', 5);
|
||||
|
||||
// Sort the image by date
|
||||
define('MEDIA_MANAGER_SORT_BY_DATE', true);
|
||||
|
||||
// Constant arrays using define are not allowed in PHP 5.6 or earlier
|
||||
|
||||
// Type of pages included in the tag database
|
||||
$GLOBALS['DB_TAGS_TYPES'] = array('published','static','sticky');
|
||||
|
||||
// Allowed image extensions — used by image upload endpoints (logo, profile picture, upload-images) and transformImage()
|
||||
$GLOBALS['ALLOWED_IMG_EXTENSION'] = array('gif', 'png', 'jpg', 'jpeg', 'svg', 'webp');
|
||||
|
||||
// Allowed image mime types
|
||||
$GLOBALS['ALLOWED_IMG_MIMETYPES'] = array('image/gif', 'image/png', 'image/jpeg', 'image/svg+xml', 'image/webp');
|
||||
|
||||
// Allowed file extensions — used by API file upload and any non-image upload endpoint
|
||||
$GLOBALS['ALLOWED_FILE_EXTENSIONS'] = array('gif', 'png', 'jpg', 'jpeg', 'webp', 'pdf', 'txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'tar', 'gz', 'mp3', 'mp4', 'wav', 'ogg', 'json', 'md');
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
class Categories extends dbList {
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct(DB_CATEGORIES);
|
||||
}
|
||||
|
||||
function numberOfPages($key)
|
||||
{
|
||||
return $this->countItems($key);
|
||||
}
|
||||
|
||||
public function reindex()
|
||||
{
|
||||
global $pages;
|
||||
|
||||
// Foreach category
|
||||
foreach ($this->db as $key=>$value) {
|
||||
$this->db[$key]['list'] = array();
|
||||
}
|
||||
|
||||
// Get pages database
|
||||
$db = $pages->getDB(false);
|
||||
foreach ($db as $pageKey=>$pageFields) {
|
||||
if (!empty($pageFields['category'])) {
|
||||
$categoryKey = $pageFields['category'];
|
||||
if (isset($this->db[$categoryKey]['list'])) {
|
||||
if (
|
||||
($db[$pageKey]['type']=='published') ||
|
||||
($db[$pageKey]['type']=='sticky') ||
|
||||
($db[$pageKey]['type']=='static')
|
||||
) {
|
||||
array_push($this->db[$categoryKey]['list'], $pageKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php defined('BLUDIT') or die('Bludit CMS.');
|
||||
|
||||
class Category {
|
||||
|
||||
protected $vars;
|
||||
|
||||
function __construct($key)
|
||||
{
|
||||
global $categories;
|
||||
if (isset($categories->db[$key])) {
|
||||
$this->vars['name'] = $categories->db[$key]['name'];
|
||||
$this->vars['template'] = $categories->db[$key]['template'];
|
||||
$this->vars['description'] = $categories->db[$key]['description'];
|
||||
$this->vars['key'] = $key;
|
||||
$this->vars['permalink'] = DOMAIN_CATEGORIES . $key;
|
||||
$this->vars['list'] = $categories->db[$key]['list'];
|
||||
} else {
|
||||
$errorMessage = 'Category not found in database by key ['.$key.']';
|
||||
Log::set(__METHOD__.LOG_SEP.$errorMessage);
|
||||
throw new Exception($errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public function getValue($field)
|
||||
{
|
||||
if (isset($this->vars[$field])) {
|
||||
return $this->vars[$field];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->getValue('key');
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->getValue('name');
|
||||
}
|
||||
|
||||
public function permalink()
|
||||
{
|
||||
return $this->getValue('permalink');
|
||||
}
|
||||
|
||||
public function template()
|
||||
{
|
||||
return $this->getValue('template');
|
||||
}
|
||||
|
||||
public function description()
|
||||
{
|
||||
return $this->getValue('description');
|
||||
}
|
||||
|
||||
// Returns an array with the keys of pages linked to the category
|
||||
public function pages()
|
||||
{
|
||||
return $this->getValue('list');
|
||||
}
|
||||
|
||||
// Returns an array in json format with all the data of the tag
|
||||
public function json($returnsArray=false)
|
||||
{
|
||||
$tmp['key'] = $this->key();
|
||||
$tmp['name'] = $this->name();
|
||||
$tmp['description'] = $this->description();
|
||||
$tmp['permalink'] = $this->permalink();
|
||||
$tmp['pages'] = $this->pages();
|
||||
|
||||
if ($returnsArray) {
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
return json_encode($tmp);
|
||||
}
|
||||
}
|
||||
+1345
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user