Merge branch 'main' into thetempusproject-com

This commit is contained in:
Joey Kimsey
2025-01-30 13:25:16 -05:00
69 changed files with 527 additions and 949 deletions

View File

@ -35,7 +35,7 @@ class Config extends BedrockConfig {
case 'radio':
case 'bool':
case 'boolean':
$fieldHtml = Forms::getSwitchHtml( $fieldname, [ 'true', 'false' ], $node['value'] );
$fieldHtml = Forms::getSwitchHtml( $fieldname, $node['value'] );
break;
case 'select':
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $node['value'] );

View File

@ -19,6 +19,7 @@ use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Upload;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Classes\Config;
class Preferences {
public static $preferences = false;
@ -208,6 +209,15 @@ class Preferences {
if ( $tempPrefsArray['type'] == 'checkbox' ) {
$tempPrefsArray['type'] = 'switch';
}
if ( 'file' === $tempPrefsArray['type'] ) {
// dv( Config::getValue( 'uploads/images' ) );
if ( ! Config::getValue( 'uploads/images' ) ) {
Debug::info( 'Preference hidden because uploads are disabled.' );
continue;
}
}
$inputTypes[ $tempPrefsArray['type'] ][] = self::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['value'], $tempPrefsArray['options'] );
}
foreach ( $inputTypes as $skip => $items ) {
@ -295,6 +305,7 @@ class Preferences {
$prefsArray[$name] = $route . Upload::last();
} else {
Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
unset( $prefsArray[$name] );
}
}
}

View File

@ -32,8 +32,6 @@ class Groups extends AdminController {
self::$title = 'Admin - Groups';
self::$group = new Group;
self::$permissions = new Permissions;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/groups' );
Components::set( 'ADMINNAV', $view );
}
public function create( $data = null ) {

View File

@ -17,9 +17,12 @@ use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\User;
use TheTempusProject\Models\Comments;
use TheTempusProject\Models\Posts;
use TheTempusProject\Models\Contact;
use TheTempusProject\Plugins\Comments as CommentPlugin;
use TheTempusProject\Plugins\Blog as BlogPlugin;
use TheTempusProject\Plugins\Contact as ContactPlugin;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Input;
class Home extends AdminController {
public static $user;
@ -32,12 +35,12 @@ class Home extends AdminController {
}
public function index() {
Components::set( 'commentDash', '' );
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
$plugin = new CommentPlugin;
if ( ! $plugin->checkEnabled() ) {
Debug::info( 'Comments Plugin is disabled in the control panel.' );
Components::set( 'commentDash', '' );
} else {
$comments = new Comments;
$commentList = Views::simpleView( 'comments.admin.dashboard', $comments->recent( 'all', 5 ) );
@ -58,10 +61,28 @@ class Home extends AdminController {
}
}
if ( class_exists( 'TheTempusProject\Plugins\Contact' ) ) {
$plugin = new ContactPlugin;
if ( ! $plugin->checkEnabled() ) {
Debug::info( 'Contact Plugin is disabled in the control panel.' );
Components::set( 'contactDash', '' );
} else {
$posts = new Contact;
$postsList = Views::simpleView( 'contact.admin.dashboard', $posts->listPaginated( 5 ) );
Components::set( 'contactDash', $postsList );
}
}
self::$user = new User;
$users = Views::simpleView( 'admin.dashboard.users', self::$user->recent( 5 ) );
Components::set( 'userDash', $users );
if ( Input::exists( 'submit' ) ) {
$results = Views::simpleView( 'admin.dashboard.users', self::$user->search( Input::post('searchTerm') ) );
Components::set( 'searchResults', $results );
}
Views::view( 'admin.dashboard.dash' );
}
}

View File

@ -0,0 +1,114 @@
<?php
/**
* app/controllers/admin/tokens.php
*
* This is the admin app/user tokens controller.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Controllers\Admin;
use TheTempusProject\Classes\Forms as TTPForms;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\Token;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class Images extends AdminController {
public function __construct() {
parent::__construct();
self::$title = 'Admin - Images';
}
public function create() {
if ( Input::exists( 'submit' ) ) {
if ( !TTPForms::check( 'addImage' ) ) {
Issues::add( 'error', [ 'There was an error with your image.' => Check::userErrors() ] );
}
if ( Input::exists( 'folder' ) ) {
$folder = Input::post('folder');
} else {
// IMAGE_DIRECTORY
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
}
$upload = Upload::image( 'upload', $folder );
if ( $upload ) {
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
$out = $route . Upload::last();
} else {
Debug::error( 'There was an error with your upload.');
Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
}
// if ( self::$token->create(
// Input::post( 'name' ),
// Input::post( 'notes' ),
// Input::post( 'token_type' )
// ) ) {
// Session::flash( 'success', 'Token Created' );
// Redirect::to( 'admin/images' );
// }
}
Views::view( 'admin.images.create' );
}
public function delete( $id = null ) {
if ( self::$token->delete( [ $id ] ) ) {
Session::flash( 'success', 'Token deleted.' );
}
Redirect::to( 'admin/images' );
}
public function edit( $id = null ) {
$token = self::$token->findById( $id );
if ( Input::exists( 'submit' ) ) {
if ( !TTPForms::check( 'adminEditToken' ) ) {
Issues::add( 'error', [ 'There was an error with your token.' => Check::userErrors() ] );
} else {
if ( self::$token->update(
$id,
Input::post( 'name' ),
Input::post( 'notes' ),
Input::post( 'token_type' )
) ) {
Session::flash( 'success', 'Token Updated' );
Redirect::to( 'admin/images' );
}
}
}
Forms::selectOption( $token->token_type );
return Views::view( 'admin.images.edit', $token );
}
public function index() {
return Views::view( 'admin.images.list', self::$token->listPaginated() );
}
public function view( $id = null ) {
return Views::view( 'admin.images.view', self::$token->findById( $id ) );
}
}

View File

@ -30,8 +30,6 @@ class Plugins extends AdminController {
self::$title = 'Admin - Installed Plugins';
$this->installer = new Installer;
$this->plugins = $this->installer->getAvailablePlugins();
$view = Navigation::activePageSelect( 'nav.admin', '/admin/plugins' );
Components::set( 'ADMINNAV', $view );
}
public function index() {

View File

@ -31,8 +31,6 @@ class Routes extends AdminController {
parent::__construct();
self::$title = 'Admin - Redirects';
self::$routes = new RoutesClass;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/routes' );
Components::set( 'ADMINNAV', $view );
}
public function create() {

View File

@ -18,6 +18,7 @@ use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Models\User;
use TheTempusProject\Models\Subscribe;
use TheTempusProject\Plugins\Subscribe as Plugin;
class SendMail extends AdminController {
public static $user;
@ -27,10 +28,24 @@ class SendMail extends AdminController {
parent::__construct();
self::$title = 'Admin - Send Mail';
self::$user = new User;
self::$subscribe = new Subscribe;
if ( class_exists( 'TheTempusProject\Plugins\Subscribe' ) ) {
$plugin = new Plugin;
if ( ! $plugin->checkEnabled() ) {
Issues::add( 'notice', 'Subscriptions are disabled so those feature will be unavailable.' );
} else {
self::$subscribe = new Subscribe;
}
} else {
Issues::add( 'notice', 'Subscriptions plugin is not installed so those feature will be unavailable.' );
}
}
private function emailSubscribers( $params ) {
if ( empty( self::$subscribe ) ) {
Issues::add( 'error', 'Subscriptions plugin is unavailable' );
return;
}
$list = self::$subscribe->list();
if ( empty( $list ) ) {
Issues::add( 'error', 'No subscribers found' );

View File

@ -31,8 +31,6 @@ class Tokens extends AdminController {
parent::__construct();
self::$title = 'Admin - Tokens';
self::$token = new Token;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/tokens' );
Components::set( 'ADMINNAV', $view );
}
public function create() {

View File

@ -37,8 +37,6 @@ class Users extends AdminController {
self::$title = 'Admin - Users';
self::$user = new User;
self::$group = new Group;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/users' );
Components::set( 'ADMINNAV', $view );
}
public function create() {

View File

@ -1,35 +0,0 @@
<?php
/**
* app/controllers/alpha.php
*
* This is the friends and family alpha controller.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Controllers;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Houdini\Classes\Views;
class Alpha extends Controller {
public function index() {
self::$title = 'Friends and Family Alpha';
self::$pageDescription = 'The Tempus Project friends and family alpha has begun. Please join me and take part in bringing a dream to reality.';
Views::view( 'alpha.index' );
}
public function crashcourse() {
self::$title = 'Friends and Family Crash-Course';
self::$pageDescription = 'The Tempus Project runs not only this site, but it can be used and deployed for any number of sites. This crash course is intended to give you all the knowledge you will need to start building your own applications powered by The Tempus Project.';
Views::view( 'alpha.crashcourse' );
}
public function certification() {
self::$title = 'Friends and Family Certification';
self::$pageDescription = 'The Tempus Project runs not only this site, but it can be used and deployed for any number of sites. This certification course is intended to give experienced users all the information they will need to start building your own applications powered by The Tempus Project.';
Views::view( 'alpha.certification' );
}
}

View File

@ -1,3 +0,0 @@
<?php
// the idea is that this will be info pages for the plugin various/info
?>

View File

@ -24,6 +24,7 @@ use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Bedrock\Classes\Config;
class Register extends Controller {
public function confirm( $code = null ) {
@ -46,6 +47,11 @@ class Register extends Controller {
public function index() {
self::$title = '{SITENAME} Sign Up';
self::$pageDescription = 'Many features of {SITENAME} are disabled or hidden from unregistered users. On this page you can sign up for an account to access all the app has to offer.';
if ( ! Config::getValue( 'main/registrationEnabled' ) ) {
return Issues::add( 'notice', 'The site administrator has disable the ability to register a new account.' );
}
Components::set( 'TERMS', Views::simpleView( 'terms' ) );
if ( App::$isLoggedIn ) {
return Issues::add( 'notice', 'You are currently logged in.' );

View File

@ -101,7 +101,7 @@ class Usercp extends Controller {
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
Navigation::activePageSelect( $menu, null, true, true );
$prefs = new Preferences;
$fields = App::$activePrefs;
$userPrefs = App::$activePrefs;
if ( Input::exists( 'submit' ) ) {
$fields = $prefs->convertFormToArray( true, false );
// @TODO now i may need to rework the form checker to work with this....
@ -110,6 +110,12 @@ class Usercp extends Controller {
// }
self::$user->updatePrefs( $fields, App::$activeUser->ID );
Issues::add( 'success', 'Your preferences have been updated.' );
// if the image upload fails, need to fall back on original
if ( empty( $fields['avatar'] ) ) {
$fields['avatar'] = $userPrefs['avatar'];
}
} else {
$fields = $userPrefs;
}
Components::set( 'AVATAR_SETTINGS', $fields['avatar'] );
Components::set( 'PREFERENCES_FORM', $prefs->getFormHtml( $fields ) );

View File

@ -21,9 +21,18 @@
.context-second-bg {
background-color: #1e1e1e;
}
.context-third-bg {
background-color: #3a3a3a;
}
.bg-default {
background-color: #2c2c2c;
}
hr {
color: #f5f5f5;
}
.bg-none,.bg-warning {
color: #000 !important;
}
@ -140,11 +149,10 @@ body {
background-color: #1f1f1f;
color: #e0e0e0;
}
.form-control:focus {
color: #e0e0e0;
/* border-color: #85bd3e; */
border-color: #1b947f;
border-color: #1e90ff;
background-color: #1f1f1f;
/* box-shadow: 0 0 0 .25rem #1b947f; */
box-shadow: 0 0 0 .25rem #85bd3e;
box-shadow: 0 0 0 .25rem rgba(30, 144, 255, .5);
}

View File

@ -8,11 +8,17 @@
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
.context-other-bg {
.context-other-bg {
background-color: #eaeaea;
}
.nav-link.active {
font-weight: bold; /* Make the text bold */
}
hr {
color: #000;
}
.context-main-bg {
background-color: #f7f7f7;
@ -57,7 +63,7 @@
bottom: 2.5px;
left: 5px;
transition: transform 0.3s ease-in-out;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 4px #00000033;
}
/* Change background color when checked */
@ -70,14 +76,6 @@
transform: translateX(25px); /* Adjust based on switch width */
}
.context-main {
color: #000;
}

View File

@ -1,218 +0,0 @@
/**
* app/css/wysiwyg.css
*
* This file is for the wysiwyg editor's css.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Helvetica Neue', 'Helvetica', arial, sans-serif;
}
/* WYSIWYG Editor */
.wp-webdeasy-comment-editor {
width: 40rem;
min-height: 18rem;
box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
border-top: 6px solid #4a4a4a;
border-radius: 3px;
margin: 2rem 0;
.toolbar {
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
.line {
display: flex;
border-bottom: 1px solid #e2e2e2;
&:last-child {
border-bottom: none;
}
.box {
display: flex;
border-left: 1px solid #e2e2e2;
.editor-btn {
display: block;
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: .2s ease all;
&:hover, &.active {
background-color: #e1e1e1;
cursor: pointer;
}
&.icon img {
width: 15px;
padding: 9px;
box-sizing: content-box;
}
&.icon.smaller img {
width: 16px;
}
&.has-submenu {
width: 20px;
padding: 0 10px;
&::after {
content: '';
width: 6px;
height: 6px;
position: absolute;
background-image: url(https://img.icons8.com/ios-glyphs/30/000000/chevron-down.png);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
right: 4px;
}
.submenu {
display: none;
position: absolute;
top: 34px;
left: -1px;
z-index: 10;
background-color: #FFF;
border: 1px solid #b5b5b5;
border-top: none;
.btn {
width: 39px;
}
&:hover {
display: block;
}
}
&:hover .submenu {
display: block;
}
}
}
}
}
}
.content-area {
padding: 15px 12px;
line-height: 1.5;
.visuell-view {
outline: none;
min-height: 12rem;
p {
margin: 12px 0;
}
}
.html-view {
outline: none;
display: none;
width: 100%;
height: 200px;
border: none;
resize: none;
}
}
}
/* Modal */
.modal {
z-index: 40;
display: none;
.modal-wrapper {
background-color: #FFF;
padding: 1rem;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 20rem;
min-height: 10rem;
z-index: 41;
.close {
position: absolute;
top: 1rem;
right: 1rem;
cursor: pointer;
}
.modal-content {
flex-direction: column;
h3 {
margin-top: 0;
}
input {
margin: 1rem 0;
padding: .5rem;
}
input[type="text"] {
width: calc(100% - 1rem);
}
.row {
label {
margin-left: .5rem;
}
}
button {
background-color: #D2434F;
border: 0;
color: #FFF;
padding: .5rem 1.2rem;
cursor: pointer;
}
}
}
.modal-bg {
position: fixed;
background-color: rgba(0, 0, 0, .3);
width: 100vw;
height: 100vh;
top: 0;
left: 0;
}
}
/* Codepen Footer */
footer {
position: fixed;
bottom: 0;
display: flex;
p {
margin: 0.5rem 1rem;
font-size: 12px;
}
a {
text-decoration: none;
font-weight: bold;
color: #000;
}
}

View File

@ -121,7 +121,10 @@ document.addEventListener('DOMContentLoaded', function () {
// Update current button states
if ( 'enabled' == currentState ) {
darkModeStylesheet.disabled = false;
toggleButton.checked = true;
if ( toggleButton ) {
toggleButton.checked = true;
}
if ( enableButton ) {
enableButton.innerText = 'Disable Now';
@ -151,27 +154,29 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
toggleButton.addEventListener('click', function () {
if (darkModeStylesheet.disabled) {
toggleDarkModePref( true );
darkModeStylesheet.disabled = false;
localStorage.setItem('darkMode', 'enabled');
} else {
toggleDarkModePref( false );
darkModeStylesheet.disabled = true;
localStorage.setItem('darkMode', 'disabled');
}
document.querySelectorAll('.table-striped').forEach((table) => {
if (localStorage.getItem('darkMode') === 'enabled') {
table.classList.add('table-dark');
table.classList.remove('table-light');
if ( toggleButton ) {
toggleButton.addEventListener('click', function () {
if (darkModeStylesheet.disabled) {
toggleDarkModePref( true );
darkModeStylesheet.disabled = false;
localStorage.setItem('darkMode', 'enabled');
} else {
table.classList.add('table-light');
table.classList.remove('table-dark');
toggleDarkModePref( false );
darkModeStylesheet.disabled = true;
localStorage.setItem('darkMode', 'disabled');
}
document.querySelectorAll('.table-striped').forEach((table) => {
if (localStorage.getItem('darkMode') === 'enabled') {
table.classList.add('table-dark');
table.classList.remove('table-light');
} else {
table.classList.add('table-light');
table.classList.remove('table-dark');
}
});
});
});
}
function toggleDarkModePref( value ) {
var fields = {};

View File

@ -1,233 +0,0 @@
/**
* app/js/wysiwyg.js
*
* This is css used in the debuging console.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
// define vars
const editor = document.getElementsByClassName('wp-webdeasy-comment-editor')[0];
const toolbar = editor.getElementsByClassName('toolbar')[0];
const buttons = toolbar.querySelectorAll('.editor-btn:not(.has-submenu)');
const contentArea = editor.getElementsByClassName('content-area')[0];
const visuellView = contentArea.getElementsByClassName('visuell-view')[0];
const htmlView = contentArea.getElementsByClassName('html-view')[0];
const modal = document.getElementsByClassName('modal')[0];
// add active tag event
document.addEventListener('selectionchange', selectionChange);
// add paste event
visuellView.addEventListener('paste', pasteEvent);
// add paragraph tag on new line
contentArea.addEventListener('keypress', addParagraphTag);
// add toolbar button actions
for(let i = 0; i < buttons.length; i++) {
let button = buttons[i];
button.addEventListener('click', function(e) {
let action = this.dataset.action;
switch(action) {
case 'toggle-view':
execCodeAction(this, editor);
break;
case 'createLink':
execLinkAction();
break;
default:
execDefaultAction(action);
}
});
}
/**
* This function toggles between visual and html view
*/
function execCodeAction(button, editor) {
if(button.classList.contains('active')) { // show visuell view
visuellView.innerHTML = htmlView.value;
htmlView.style.display = 'none';
visuellView.style.display = 'block';
button.classList.remove('active');
} else { // show html view
htmlView.innerText = visuellView.innerHTML;
visuellView.style.display = 'none';
htmlView.style.display = 'block';
button.classList.add('active');
}
}
/**
* This function adds a link to the current selection
*/
function execLinkAction() {
modal.style.display = 'block';
let selection = saveSelection();
let submit = modal.querySelectorAll('button.done')[0];
let close = modal.querySelectorAll('.close')[0];
// done button active => add link
submit.addEventListener('click', function(e) {
e.preventDefault();
let newTabCheckbox = modal.querySelectorAll('#new-tab')[0];
let linkInput = modal.querySelectorAll('#linkValue')[0];
let linkValue = linkInput.value;
let newTab = newTabCheckbox.checked;
restoreSelection(selection);
if(window.getSelection().toString()) {
let a = document.createElement('a');
a.href = linkValue;
if(newTab) a.target = '_blank';
window.getSelection().getRangeAt(0).surroundContents(a);
}
modal.style.display = 'none';
linkInput.value = '';
// deregister modal events
submit.removeEventListener('click', arguments.callee);
close.removeEventListener('click', arguments.callee);
});
// close modal on X click
close.addEventListener('click', function(e) {
e.preventDefault();
let linkInput = modal.querySelectorAll('#linkValue')[0];
modal.style.display = 'none';
linkInput.value = '';
// deregister modal events
submit.removeEventListener('click', arguments.callee);
close.removeEventListener('click', arguments.callee);
});
}
/**
* This function executes all 'normal' actions
*/
function execDefaultAction(action) {
document.execCommand(action, false);
}
/**
* Saves the current selection
*/
function saveSelection() {
if(window.getSelection) {
sel = window.getSelection();
if(sel.getRangeAt && sel.rangeCount) {
let ranges = [];
for(var i = 0, len = sel.rangeCount; i < len; ++i) {
ranges.push(sel.getRangeAt(i));
}
return ranges;
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange();
}
return null;
}
/**
* Loads a saved selection
*/
function restoreSelection(savedSel) {
if(savedSel) {
if(window.getSelection) {
sel = window.getSelection();
sel.removeAllRanges();
for(var i = 0, len = savedSel.length; i < len; ++i) {
sel.addRange(savedSel[i]);
}
} else if(document.selection && savedSel.select) {
savedSel.select();
}
}
}
/**
* Sets the current selected format buttons active/inactive
*/
function selectionChange(e) {
for(let i = 0; i < buttons.length; i++) {
let button = buttons[i];
// don't remove active class on code toggle button
if(button.dataset.action === 'toggle-view') continue;
button.classList.remove('active');
}
if(!childOf(window.getSelection().anchorNode.parentNode, editor)) return false;
parentTagActive(window.getSelection().anchorNode.parentNode);
}
/**
* Checks if the passed child has the passed parent
*/
function childOf(child, parent) {
return parent.contains(child);
}
/**
* Sets the tag active that is responsible for the current element
*/
function parentTagActive(elem) {
if(!elem ||!elem.classList || elem.classList.contains('visuell-view')) return false;
let toolbarButton;
// active by tag names
let tagName = elem.tagName.toLowerCase();
toolbarButton = document.querySelectorAll(`.toolbar .editor-btn[data-tag-name="${tagName}"]`)[0];
if(toolbarButton) {
toolbarButton.classList.add('active');
}
// active by text-align
let textAlign = elem.style.textAlign;
toolbarButton = document.querySelectorAll(`.toolbar .editor-btn[data-style="textAlign:${textAlign}"]`)[0];
if(toolbarButton) {
toolbarButton.classList.add('active');
}
return parentTagActive(elem.parentNode);
}
/**
* Handles the paste event and removes all HTML tags
*/
function pasteEvent(e) {
e.preventDefault();
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertHTML', false, text);
}
/**
* This functions adds a paragraph tag when the enter key is pressed
*/
function addParagraphTag(evt) {
if (evt.keyCode == '13') {
// don't add a p tag on list item
if(window.getSelection().anchorNode.parentNode.tagName === 'LI') return;
document.execCommand('formatBlock', false, 'p');
}
}

View File

@ -29,8 +29,6 @@ class Blog extends AdminController {
parent::__construct();
self::$posts = new Posts;
self::$title = 'Admin - Blog';
$view = Navigation::activePageSelect( 'nav.admin', '/admin/blog' );
Components::set( 'ADMINNAV', $view );
}
public function index( $data = null ) {
@ -46,7 +44,7 @@ class Blog extends AdminController {
return $this->index();
}
$result = self::$posts->newPost( Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'submit' ) );
$result = self::$posts->newPost( Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'slug' ), Input::post( 'submit' ) );
if ( $result ) {
Issues::add( 'success', 'Your post has been created.' );
return $this->index();
@ -67,7 +65,7 @@ class Blog extends AdminController {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return $this->index();
}
if ( self::$posts->updatePost( $data, Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'submit' ) ) === true ) {
if ( self::$posts->updatePost( $data, Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'slug' ), Input::post( 'submit' ) ) === true ) {
Issues::add( 'success', 'Post Updated.' );
return $this->index();
}

View File

@ -105,7 +105,10 @@ class Blog extends Controller {
}
$post = self::$posts->findById( $id );
if ( empty( $post ) ) {
return $this->index();
$post = self::$posts->findBySlug( $id );
if ( empty( $post ) ) {
return $this->index();
}
}
Debug::log( 'Controller initiated: ' . __METHOD__ . '.' );
self::$title = 'Blog Post';
@ -134,8 +137,6 @@ class Blog extends Controller {
}
}
$post = self::$posts->findById( $id );
self::$title .= ' - ' . $post->title;
self::$pageDescription = strip_tags( $post->contentSummaryNoLink );
Views::view( 'blog.post', $post );

View File

@ -32,6 +32,7 @@ class Posts extends DatabaseModel {
[ 'edited', 'int', '10' ],
[ 'draft', 'int', '1' ],
[ 'title', 'varchar', '86' ],
[ 'slug', 'varchar', '64' ],
[ 'content', 'text', '' ],
];
@ -45,7 +46,7 @@ class Posts extends DatabaseModel {
}
}
public function newPost( $title, $post, $draft ) {
public function newPost( $title, $post, $slug, $draft ) {
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'modelBlog: illegal title.' );
@ -59,6 +60,7 @@ class Posts extends DatabaseModel {
$fields = [
'author' => App::$activeUser->ID,
'draft' => $draft,
'slug' => $slug,
'created' => time(),
'edited' => time(),
'content' => Sanitize::rich( $post ),
@ -73,7 +75,7 @@ class Posts extends DatabaseModel {
return true;
}
public function updatePost( $id, $title, $content, $draft ) {
public function updatePost( $id, $title, $content, $slug, $draft ) {
if ( empty( self::$log ) ) {
self::$log = new Log;
}
@ -94,6 +96,7 @@ class Posts extends DatabaseModel {
}
$fields = [
'draft' => $draft,
'slug' => $slug,
'edited' => time(),
'content' => Sanitize::rich( $content ),
'title' => $title,
@ -132,22 +135,29 @@ class Posts extends DatabaseModel {
$draft = '';
$authorName = self::$user->getUsername( $instance->author );
// Summarize
if ( ! empty( $instance->slug ) ) {
$identifier = $instance->slug;
} else {
$identifier = $instance->ID;
}
$cleanPost = Sanitize::contentShort( $instance->content );
// By Word
$wordsArray = explode( ' ', $cleanPost );
$postLine = explode( "\n", $cleanPost );
$spaceSummary = implode( ' ', array_splice( $wordsArray, 0, 100 ) );
$lineSummary = implode( "\n", array_splice( $postLine, 0, 5 ) );
if ( strlen( $spaceSummary ) < strlen( $lineSummary ) ) {
$contentSummaryNoLink = $spaceSummary;
$contentSummary = $spaceSummary;
if ( count( $wordsArray, 1 ) >= 100 ) {
$contentSummaryNoLink = $contentSummary;
$contentSummary .= '... <a href="{ROOT_URL}blog/post/' . $instance->ID . '" class="text-decoration-none">Read More</a>';
}
$wordSummary = implode( ' ', array_splice( $wordsArray, 0, 100 ) );
// By Line
$linesArray = explode( "\n", $cleanPost );
$lineSummary = implode( "\n", array_splice( $linesArray, 0, 5 ) );
if ( strlen( $wordSummary ) < strlen( $lineSummary ) ) {
$contentSummaryNoLink = $wordSummary;
$contentSummary = $wordSummary . '... <a href="{ROOT_URL}blog/post/' . $identifier . '" class="text-decoration-none">Read More</a>';
} else {
$contentSummaryNoLink = $lineSummary;
$contentSummary = $lineSummary . '... <a href="{ROOT_URL}blog/post/' . $instance->ID . '" class="text-decoration-none">Read More</a>';
$contentSummary = $lineSummary . '... <a href="{ROOT_URL}blog/post/' . $identifier . '" class="text-decoration-none">Read More</a>';
}
$instance->contentSummaryNoLink = $contentSummaryNoLink;
$instance->contentSummary = $contentSummary;
@ -158,12 +168,15 @@ class Posts extends DatabaseModel {
$draft = ' <b>Draft</b>';
}
$instance->isDraft = $draft;
$instance->authorName = $authorName;
$instance->authorName = \ucfirst( $authorName );
if ( self::$comments !== false ) {
$instance->commentCount = self::$comments->count( 'blog', $instance->ID );
} else {
$instance->commentCount = 0;
}
$instance->content = Filters::applyOne( 'mentions.0', $instance->content, true );
$instance->content = Filters::applyOne( 'hashtags.0', $instance->content, true );
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
@ -291,6 +304,22 @@ class Posts extends DatabaseModel {
return $this->filter( $postData->results() );
}
public function findBySlug( $slug, $includeDraft = false ) {
$whereClause = [];
if ( $includeDraft !== true ) {
$whereClause = ['draft', '=', '0', 'AND'];
}
$whereClause = array_merge( $whereClause, ['slug', '=', $slug] );
$postData = self::$db->get( $this->tableName, $whereClause );
if ( !$postData->count() ) {
Debug::info( 'No Blog posts found.' );
return false;
}
return $this->filter( $postData->first() );
}
public function byMonth( $month, $year = 0, $includeDraft = false ) {
if ( 0 === $year ) {
$year = date( 'Y' );

View File

@ -12,6 +12,14 @@
</div>
</div>
<!-- Slug -->
<div class="mb-3 row">
<label for="slug" class="col-lg-3 col-form-label text-end">URL Slug (for pretty linking):</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="slug" id="slug" required>
</div>
</div>
<!-- form buttons -->
<div class="mb-3 row">
<div class="offset-3 col-lg-6">

View File

@ -12,6 +12,14 @@
</div>
</div>
<!-- Slug -->
<div class="mb-3 row">
<label for="slug" class="col-lg-3 col-form-label text-end">URL Slug (for pretty linking):</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="slug" id="slug" value="{slug}" required>
</div>
</div>
<!-- form buttons -->
<div class="mb-3 row">
<div class="offset-3 col-lg-6">

View File

@ -21,7 +21,7 @@
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}admin/blog/view/{ID}">{title}</a>{isDraft}</td>
<td><a href="{ROOT_URL}admin/blog/view/{ID}" class="text-decoration-none">{title}</a>{isDraft}</td>
<td>{authorName}</td>
<td>{commentCount}</td>
<td>{DTC}{created}{/DTC}</td>

View File

@ -1,7 +1,7 @@
{LOOP}
<article class="blog-post">
<h2 class="blog-post-title mb-1">{title}</h2>
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{author}" class="text-decoration-none">{authorName}</a></p>
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{authorName}" class="text-decoration-none">{authorName}</a></p>
<div class="well">
{contentSummary}
</div>

View File

@ -3,7 +3,7 @@
<div class="blog-post">
<h2 class="blog-post-title">{title}</h2>
<hr>
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{author}" class="text-decoration-none">{authorName}</a></p>
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{authorName}" class="text-decoration-none">{authorName}</a></p>
{content}
{ADMIN}
<hr>

View File

@ -1,11 +1,15 @@
<div class="p-4">
<h4 class="fst-italic">Archives</h4>
<ul class="list-unstyled mb-0">
{LOOP}
<li>({count}) <a href="{ROOT_URL}blog/month/{month}/{year}" class="text-decoration-none">{monthText} {year}</a></li>
{/LOOP}
{ALT}
<li>None To Show</li>
{/ALT}
</ul>
<div class="card context-main-bg">
<div class="card-header">
<h3 class="card-title">Archives</h3>
</div>
<div class="card-body">
<ol class="list-unstyled">
{LOOP}
<li>({count}) <a href="{ROOT_URL}blog/month/{month}/{year}" class="text-decoration-none">{monthText} {year}</a></li>
{/LOOP}
{ALT}
<li>None To Show</li>
{/ALT}
</ol>
</div>
</div>

View File

@ -27,8 +27,6 @@ class Contact extends AdminController {
parent::__construct();
self::$title = 'Admin - Contact';
self::$contact = new ContactModel;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/contact' );
Components::set( 'ADMINNAV', $view );
}
public function view( $id = null ) {

View File

@ -0,0 +1,29 @@
<table class="table context-main">
<thead>
<tr>
<th style="width: 5%"></th>
<th style="width: 25%"></th>
<th style="width: 55%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{ID}</td>
<td>{DTC}{time}{/DTC}</td>
<td>{feedback}</td>
<td><a href="{ROOT_URL}admin/contact/view/{ID}" class="btn btn-sm btn-primary"><i class="fa fa-fw fa-upload"></i></a></td>
<td><a href="{ROOT_URL}admin/contact/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td class="text-center" colspan="5">
No Contact forms to show.
</td>
</tr>
{/ALT}
</tbody>
</table>

View File

@ -1,40 +0,0 @@
<?php
/**
* app/plugins/redirects/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Redirects
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins;
use ReflectionClass;
use TheTempusProject\Classes\Installer;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\TheTempusProject as App;
class Redirects extends Plugin {
public $pluginName = 'TP Redirects';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = 'A simple plugin which adds redirects.';
public $permissionMatrix = [
'redirects' => [
'pretty' => 'Can modify redirects',
'default' => false,
],
];
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-external-link"></i> Redirects',
'url' => '{ROOT_URL}admin/routes',
],
];
}

View File

@ -34,14 +34,16 @@ class AdminLoader extends DefaultLoader {
}
$links[$key]->url = '#' . $name . 'Dropdown';
$links[$key]->text = '<span>' . $link->text . '</span><i class="fa fa-fw fa-caret-down ms-2"></i>';
$links[$key]->duuuuuuuh = Views::simpleView( 'nav.adminSub', $out );
$links[$key]->subnav = Views::simpleView( 'nav.adminSub', $out );
} else {
$links[$key]->linkClasses = 'nav-link';
$links[$key]->linkAttributes = '';
$links[$key]->duuuuuuuh = '';
$links[$key]->subnav = '';
}
}
Components::set( 'ADMIN_LINKS', Views::simpleView( 'nav.admin', $links ) );
$menu = Views::simpleView( 'nav.admin', $links );
$activeMenu = Navigation::activePageSelect( $menu, Input::get( 'url' ), false, true );
Components::set( 'ADMIN_LINKS', $activeMenu );
Navigation::setCrumbComponent( 'ADMIN_BREADCRUMBS', Input::get( 'url' ) );
}
}

View File

@ -73,7 +73,9 @@ class DefaultLoader extends Loader {
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet" disabled>' );
}
Components::set( 'topNavRight', Template::parse( App::$topNavRight . '{STATUS}' ) );
Components::set( 'topNavLeft', Views::simpleView( 'nav.main', Navigation::getMenuLinks( App::MAIN_MENU_NAME ) ) );
$menu = Views::simpleView( 'nav.main', Navigation::getMenuLinks( App::MAIN_MENU_NAME ) );
$activeMenu = Navigation::activePageSelect( $menu, Input::get( 'url' ), false, true );
Components::set( 'topNavLeft', $activeMenu );
Components::set( 'colorSelect', Views::simpleView( 'forms.colorSelect' ) );
Components::set( 'iconSelect', Views::simpleView( 'forms.iconSelect' ) );
Navigation::setCrumbComponent( 'BREADCRUMB', Input::get( 'url' ) );

View File

@ -8,9 +8,38 @@
{commentDash}
</div>
</div>
<div class="row">
<div class="col-10 offset-1">
{contactDash}
</div>
</div>
<div class="row">
<div class="col-10 offset-1">
{blogDash}
</div>
</div>
</div>
<legend class="text-center my-2">Results</legend>
<form method="post">
<fieldset>
<!-- Search -->
<div class="mb-3 row">
<label for="searchTerm" class="col-lg-6 col-form-label text-end">Search:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="searchTerm" id="searchTerm">
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Search</button>
</div>
</fieldset>
</form>
<div class="col-5 offset-1">
{searchResults}
</div>

View File

@ -18,8 +18,8 @@
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}admin/groups/view/{ID}">{name}</a></td>
<td><a href="{ROOT_URL}admin/groups/listmembers/{ID}">{userCount}</a></td>
<td><a href="{ROOT_URL}admin/groups/view/{ID}" class="text-decoration-none">{name}</a></td>
<td><a href="{ROOT_URL}admin/groups/listmembers/{ID}" class="text-decoration-none">{userCount}</a></td>
<td><a href="{ROOT_URL}admin/groups/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/groups/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
<td>

View File

@ -1,40 +1,43 @@
<h1>{groupName} <small>user list</small></h1>
{PAGINATION}
<form action="{ROOT_URL}admin/users/delete" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 5%">ID</th>
<th style="width: 55%">Username</th>
<th style="width: 25%">Joined</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<input type="checkbox" onchange="checkAll(this)" name="check.u" value="U_[]">
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{ID}</td>
<td><a href='{ROOT_URL}admin/users/view/{ID}'>{username}</a></td>
<td>{DTC date}{registered}{/DTC}</td>
<td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
<td>
<input type="checkbox" value="{ID}" name="U_[]">
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
</form>
<div class="context-main-bg context-main p-3">
<legend class="text-center">{groupName} <small>user list</small></legend>
<hr>
{ADMIN_BREADCRUMBS}
<form action="{ROOT_URL}admin/users/delete" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 5%">ID</th>
<th style="width: 55%">Username</th>
<th style="width: 25%">Joined</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<input type="checkbox" onchange="checkAll(this)" name="check.u" value="U_[]">
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{ID}</td>
<td><a href='{ROOT_URL}admin/users/view/{ID}' class="text-decoration-none">{username}</a></td>
<td>{DTC date}{registered}{/DTC}</td>
<td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
<td>
<input type="checkbox" value="{ID}" name="U_[]">
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
</form>
</div>

View File

@ -17,7 +17,7 @@
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}admin/plugins/view/{name}">{name}</a></td>
<td><a href="{ROOT_URL}admin/plugins/view/{name}" class="text-decoration-none">{name}</a></td>
<td>{enabled_txt}</td>
<td>{installStatus}</td>
<td>{version}</td>

View File

@ -22,7 +22,7 @@
{LOOP}
<tr>
<td align="center">{ID}</td>
<td><a href='{ROOT_URL}admin/routes/view/{ID}'>{nickname}</a></td>
<td><a href='{ROOT_URL}admin/routes/view/{ID}' class="text-decoration-none">{nickname}</a></td>
<td>{redirect_type}</td>
<td>{original_url}</td>
<td>{forwarded_url}</td>

View File

@ -1,4 +1,6 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Settings</legend>
<hr>
{ADMIN_BREADCRUMBS}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
<fieldset>

View File

@ -14,7 +14,7 @@
<tbody>
{LOOP}
<tr>
<td><a href='{ROOT_URL}admin/tokens/view/{ID}'>{name}</a></td>
<td><a href='{ROOT_URL}admin/tokens/view/{ID}' class="text-decoration-none">{name}</a></td>
<td>{token_type}</td>
<td><a href="{ROOT_URL}admin/tokens/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/tokens/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>

View File

@ -20,7 +20,7 @@
{LOOP}
<tr>
<td align="center">{ID}</td>
<td><a href='{ROOT_URL}admin/users/view/{ID}'>{username}</a></td>
<td><a href='{ROOT_URL}admin/users/view/{ID}' class="text-decoration-none">{username}</a></td>
<td>{DTC date}{registered}{/DTC}</td>
<td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>

View File

@ -1,30 +0,0 @@
<div class="container">
<div class="row">
<div class="col-lg-9 col-md-9 col-sm-12 col-centered">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h2>Welcome to The Tempus-Project Friends and Family Alpha.</h2>
<hr>
<p>This project is now entering its third official version and nearly its tenth year of development. What a long journey it has been to get here.</p>
<p>With that being said, I won't waste your time with a journey down memory road. If you have been sent this page, clearly I trust you, or one of our mutual friends is an asshole. Both equally possible... The main purpose of inviting you was to ask for your help.</p>
<h2>What I need</h2>
<p>With any application, there are bugs. The best developers I have had the pleasure of working with make mundane every day mistakes just like everyone else. This obviously includes myself. With any project you spend years working on, you will develop blind spots, or places where even if something was broken, you would skip right past it and never notice.</p>
<p>I would like your help in identifying these such blind spots.</p>
<h2>What you can do to help.</h2>
<p>Currently there is a bug-report form at the bottom, usable by anyone with a registered account. I have also built an administrator system that allows me to track progress of these bugs and ensure they get fixed. In addition to tracking bugs, there is a public suggestions system and a publicly viewable to-do list.</p>
<p>I will need some users to help test very specific things like permissions for various groups. I will need some trusted users to act as administrators and test features. I will also just need some people to use and interact with the site to ensure they aren't encountering any bugs.</p>
<p>There are a ton of things you can do to help!</p>
<ul>
<li>Report any bugs!!! ( there is a bug-report link at the bottom of every page )</li>
<li>Register an account</li>
<li>Subscribe to the mailing list</li>
<li>Browse blog posts</li>
<li>Make suggestions for improvements or new features</li>
<li>Leave comments on the blog and other features.</li>
<li>Keep an eye out for email or messages requesting specific help.</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,16 +0,0 @@
<link rel="stylesheet" href="{ROOT_URL}app/css/debug.css" crossorigin="anonymous">
<div id="debug-wrapper">
<div id="debug-header">
<p><b>Debug Log:</b></p>
<button id="debug-copy" name="debug-copy">Copy</button>
</div>
<div id="debug-log">
{DEBUGGING_LOG}
</div>
</div>
<script language="JavaScript" type="text/javascript">
$("#debug-copy").on("click", function(){
copyAll("debug-log");
console.log('copied');
});
</script>

View File

@ -1,9 +0,0 @@
<link rel="stylesheet" href="{ROOT_URL}app/css/debug.css" crossorigin="anonymous">
<div id="wrapper">
<div id="menu">
<p class="welcome"><b>Debug Dump:</b></p>
</div>
<div>
<pre>{DUMP}</pre>
</div>
</div>

View File

@ -1 +1 @@
<span>© 2024 {SITENAME}, Powered by <a href="https://thetempusproject.com" class="text-decoration-none">The Tempus Project</a>.</span>
<span>© 2025 {SITENAME}, Powered by <a href="https://thetempusproject.com" class="text-decoration-none">The Tempus Project</a>.</span>

View File

@ -1 +0,0 @@
<p> Hey there, it looks like you found our hastags! Unfortunately I haven't finished building them out just yet. Check back soon!</p>

View File

@ -20,11 +20,11 @@
</p>
<!-- Call-to-Action Buttons -->
<div class="d-flex justify-content-center gap-3 mt-4">
<a href="/login" class="btn btn-success btn-lg">
<a href="/home/login" class="btn btn-success btn-lg">
<i class="fa fa-sign-in-alt me-2"></i> Log In
</a>
<a href="/dashboard" class="btn btn-outline-success btn-lg">
<i class="fa fa-cogs me-2"></i> Go to Dashboard
<a href="/home/index" class="btn btn-outline-success btn-lg">
<i class="fa fa-cogs me-2"></i> Go to Homepage
</a>
</div>
</div>

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<legend class="my-3 text-center">Configure</legend>

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<p class="my-4">All models are required for proper installation of The Tempus Project. In this step, we will add the database tables required for these models. In the next step, you'll be able to select which plugins you would like installed.</p>

View File

@ -1,12 +1,12 @@
<ul class="nav nav-tabs justify-content-center" role="tablist">
<li class="nav-item {menu-Welcome}"><a href="#" class="nav-link">Welcome</a></li>
<li class="nav-item {menu-Terms}"><a href="#" class="nav-link">Terms</a></li>
<li class="nav-item {menu-Verify}"><a href="#" class="nav-link">Verify</a></li>
<li class="nav-item {menu-Configure}"><a href="#" class="nav-link">Configure</a></li>
<li class="nav-item {menu-Routing}"><a href="#" class="nav-link">Routing</a></li>
<li class="nav-item {menu-Models}"><a href="#" class="nav-link">Models</a></li>
<li class="nav-item {menu-Plugins}"><a href="#" class="nav-link">Plugins</a></li>
<li class="nav-item {menu-Resources}"><a href="#" class="nav-link">Resources</a></li>
<li class="nav-item {menu-User}"><a href="#" class="nav-link">User</a></li>
<li class="nav-item {menu-Complete}"><a href="#" class="nav-link">Complete</a></li>
</ul>
<div class="nav nav-tabs justify-content-center pt-3 col-10 offset-1" id="nav-tab" role="tablist">
<button class="nav-link {menu-Welcome}" type="button" role="tab">Welcome</button>
<button class="nav-link {menu-Terms}" type="button" role="tab">Terms</button>
<button class="nav-link {menu-Verify}" type="button" role="tab">Verify</button>
<button class="nav-link {menu-Configure}" type="button" role="tab">Configure</button>
<button class="nav-link {menu-Routing}" type="button" role="tab">Routing</button>
<button class="nav-link {menu-Models}" type="button" role="tab">Models</button>
<button class="nav-link {menu-Plugins}" type="button" role="tab">Plugins</button>
<button class="nav-link {menu-Resources}" type="button" role="tab">Resources</button>
<button class="nav-link {menu-User}" type="button" role="tab">User</button>
<button class="nav-link {menu-Complete}" type="button" role="tab">Complete</button>
</div>

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<p class="my-4">

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<p class="my-4">

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<p class="mt-4">The Tempus Project uses rewrites in htaccess files (Apache), or location directives (Nginx), to automatically route all incoming traffic through the app. In this step, we will help set-up and then test that the required configurations have been made.</p>

View File

@ -1,7 +1,7 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<div class="col-10">
<div class="install-terms col-lg-8 mx-auto mt-4">
{TERMS}
</div>

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10 pt-4">
<form action="" method="post" class="form-horizontal">

View File

@ -1,5 +1,5 @@
{installer-nav}
<div class="container">
<div class="context-main-bg my-3 pb-3 rounded col-10 offset-1">
{installer-nav}
<div class="row justify-content-center">
<div class="col-md-10">
<h2 class="mt-4">Requirements</h2>

View File

@ -0,0 +1,17 @@
<div class="container">
<div class="row justify-content-center">
<div class="col-md-10 text-center">
<div class="context-main-bg my-3 pb-3 rounded">
{installer-nav}
<h1 class="mt-4">Welcome to The Tempus Project Installer.</h1>
<p>
This installer will guide you through the process of installing and configuring The Tempus Project. Do not forget to delete this file once you have completed installation.
</p>
<form action="" method="post">
<input type="hidden" name="token" value="{TOKEN}">
<button class="btn btn-lg btn-primary center-block" type="submit" name="submit" id="submit" value="submit">Begin Installation</button><br>
</form>
</div>
</div>
</div>
</div>

View File

@ -4,7 +4,7 @@
<a href="{url}" class="text-white {linkClasses}" {linkAttributes}>
{text}
</a>
{duuuuuuuh}
{subnav}
</li>
{/LOOP}
</ul>

View File

@ -1,6 +1,6 @@
<ul class="collapse list-unstyled ms-3 text-small shadow" id="{dropdownName}Dropdown">
{LOOP}
<li class="nav-item"><a href="{url}" class="nav-link text-white">{text}</a></li>
<li class="nav-item"><a href="{url}" class="submenu nav-link text-white">{text}</a></li>
{/LOOP}
</ul>

View File

@ -1,5 +1,13 @@
<ul class="nav col-12 col-lg-auto mb-2 justify-content-center mb-md-0 mx-auto">
{LOOP}
<li><a href="{url}" class="nav-link px-2 text-white">{text}</a></li>
{/LOOP}
</ul>
<nav class="navbar navbar-expand col-12 col-lg-auto mb-2 justify-content-center mb-md-0 mx-auto">
<div class="container-fluid">
<ul class="navbar-nav">
{LOOP}
<li class="nav-item">
<a href="{url}" class="nav-link px-2 text-white">
{text}
</a>
</li>
{/LOOP}
</ul>
</div>
</nav>

View File

@ -1,52 +0,0 @@
<div class="col-sm-6 col-md-4 col-sm-offset-3 col-md-offset-4">
<div class="card">
<!-- Default panel contents -->
<div class="card-header">Material Design Switch Demos</div>
<!-- List group -->
<ul class="list-group">
<li class="list-group-item">
Bootstrap Switch Default
<div class="material-switch float-right">
<input id="someSwitchOptionDefault" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionDefault" class="label-default"></label>
</div>
</li>
<li class="list-group-item">
Bootstrap Switch Primary
<div class="material-switch float-right">
<input id="someSwitchOptionPrimary" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionPrimary" class="label-primary"></label>
</div>
</li>
<li class="list-group-item">
Bootstrap Switch Success
<div class="material-switch float-right">
<input id="someSwitchOptionSuccess" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionSuccess" class="label-success"></label>
</div>
</li>
<li class="list-group-item">
Bootstrap Switch Info
<div class="material-switch float-right">
<input id="someSwitchOptionInfo" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionInfo" class="label-info"></label>
</div>
</li>
<li class="list-group-item">
Bootstrap Switch Warning
<div class="material-switch float-right">
<input id="someSwitchOptionWarning" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionWarning" class="label-warning"></label>
</div>
</li>
<li class="list-group-item">
Bootstrap Switch Danger
<div class="material-switch float-right">
<input id="someSwitchOptionDanger" name="someSwitchOption001" type="checkbox"/>
<label for="someSwitchOptionDanger" class="label-danger"></label>
</div>
</li>
</ul>
</div>
</div>

View File

@ -1 +0,0 @@
lul, testing

View File

@ -3,7 +3,7 @@
<hr>
<div class="row justify-content-center">
<div class="col-md-6">
<form action="" method="post" class="">
<form action="" method="post" class="" enctype="multipart/form-data">
<fieldset>
{PREFERENCES_FORM}
</fieldset>

View File

@ -1,104 +0,0 @@
<div class="wp-webdeasy-comment-editor">
<div class="toolbar">
<div class="line">
<div class="box">
<span class="editor-btn icon smaller" data-action="bold" data-tag-name="b" title="Bold">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/bold.png"/>
</span>
<span class="editor-btn icon smaller" data-action="italic" data-tag-name="i" title="Italic">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/italic.png"/>
</span>
<span class="editor-btn icon smaller" data-action="underline" data-tag-name="u" title="Underline">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/underline.png"/>
</span>
<span class="editor-btn icon smaller" data-action="strikeThrough" data-tag-name="strike" title="Strike through">
<img src="https://img.icons8.com/fluency-systems-filled/30/000000/strikethrough.png"/>
</span>
</div>
<div class="box">
<span class="editor-btn icon has-submenu">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/align-left.png"/>
<div class="submenu">
<span class="editor-btn icon" data-action="justifyLeft" data-style="textAlign:left" title="Justify left">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/align-left.png"/>
</span>
<span class="editor-btn icon" data-action="justifyCenter" data-style="textAlign:center" title="Justify center">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/align-center.png"/>
</span>
<span class="editor-btn icon" data-action="justifyRight" data-style="textAlign:right" title="Justify right">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/align-right.png"/>
</span>
<span class="editor-btn icon" data-action="formatBlock" data-style="textAlign:justify" title="Justify block">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/align-justify.png"/>
</span>
</div>
</span>
<span class="editor-btn icon" data-action="insertOrderedList" data-tag-name="ol" title="Insert ordered list">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/numbered-list.png"/>
</span>
<span class="editor-btn icon" data-action="insertUnorderedList" data-tag-name="ul" title="Insert unordered list">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/bulleted-list.png"/>
</span>
<span class="editor-btn icon" data-action="outdent" title="Outdent" data-required-tag="li">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/outdent.png"/>
</span>
<span class="editor-btn icon" data-action="indent" title="Indent">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/indent.png"/>
</span>
</div>
<div class="box">
<span class="editor-btn icon" data-action="insertHorizontalRule" title="Insert horizontal rule">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/horizontal-line.png"/>
</span>
</div>
</div>
<div class="line">
<div class="box">
<span class="editor-btn icon smaller" data-action="undo" title="Undo">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/undo--v1.png"/>
</span>
<span class="editor-btn icon" data-action="removeFormat" title="Remove format">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/remove-format.png"/>
</span>
</div>
<div class="box">
<span class="editor-btn icon smaller" data-action="createLink" title="Insert Link">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/add-link.png"/>
</span>
<span class="editor-btn icon smaller" data-action="unlink" data-tag-name="a" title="Unlink">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/delete-link.png"/>
</span>
</div>
<div class="box">
<span class="editor-btn icon" data-action="toggle-view" title="Show HTML-Code">
<img src="https://img.icons8.com/fluency-systems-filled/48/000000/source-code.png"/>
</span>
</div>
</div>
</div>
<div class="content-area">
<div class="visuell-view" contenteditable>
<p style="text-align: center;">Welcome to my <b>WYSIWYG</b> Editor <i>(What you see is what you get)</i>!</p>
<p style="text-align: center;">It's only made of <u>HTML5</u>, <i><u>CSS3</u> </i>and pure <u>JavaScript</u>, <strike>no framework</strike>!</p>
<hr>
<p style="text-align: center;"><b>See for yourself! 😃</b></p>
<p style="text-align: center;"><b>Tutorial available <a href="https://webdeasy.de/en/program-your-own-wysiwyg-editor-in-10-minutes/?referer=cp-YoVmBx">here</a>! 😋</b></p>
</div>
<textarea class="html-view"></textarea>
</div>
</div>
<div class="modal">
<div class="modal-bg"></div>
<div class="modal-wrapper">
<div class="close"></div>
<div class="modal-content" id="modalCreateLink">
<h3>Insert Link</h3>
<input type="text" id="linkValue" placeholder="Link (example: https://webdeasy.de/)">
<div class="row">
<input type="checkbox" id="new-tab">
<label for="new-tab">Open in new Tab?</label>
</div>
<button class="done">Done</button>
</div>
</div>
</div>

View File

@ -100,6 +100,10 @@ class TheTempusProject extends Bedrock {
'text' => '<i class="fa fa-fw fa-shield-halved"></i> Tokens',
'url' => '{ROOT_URL}admin/tokens',
],
[
'text' => '<i class="fa-solid fa-image"></i> Images',
'url' => '{ROOT_URL}admin/images',
],
[
'text' => '<i class="fa fa-fw fa-arrow-down"></i> Modules',
'url' => [
@ -143,6 +147,7 @@ class TheTempusProject extends Bedrock {
[
'text' => 'Home',
'url' => '{ROOT_URL}home/index',
'filter' => 'notloggedin',
],
[
'text' => 'Libraries',
@ -299,6 +304,11 @@ class TheTempusProject extends Bedrock {
"pretty" => "Enable CSRF Token for all forms.",
"default" => true
],
"registrationEnabled" => [
"type" => "radio",
"pretty" => "Allow new users to register an account.",
"default" => true
],
"loginLimit" => [
"type" => "text",
"pretty" => "Maximum Login Attempts per hour",
@ -312,17 +322,15 @@ class TheTempusProject extends Bedrock {
],
"uploads" => [
"images" => [
"type"=> "radio",
"pretty"=> "Upload Images Enabled",
"default"=> true,
"protected"=> true,
"value"=> true,
"type" => "radio",
"pretty" => "Upload Images Enabled",
"default" => true,
"value" => true,
],
"maxImageSize"=> [
"type" => "text",
"pretty" => "Maximum size for image uploads",
"default" => 500000,
"protected" => true,
"value" => 500000,
]
],

View File

@ -22,9 +22,9 @@
{
"components/jquery": "1.9.*",
"fortawesome/font-awesome": "4.7",
"thetempusproject/bedrock": "1.0.10",
"thetempusproject/canary": "1.0.5",
"thetempusproject/houdini": "1.0.8",
"thetempusproject/bedrock": "1.1.1",
"thetempusproject/canary": "1.0.6",
"thetempusproject/houdini": "2.0.2",
"twbs/bootstrap": "5.2.3"
},
"autoload":

44
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "60848437b2d65e726d854a96b9afcf22",
"content-hash": "b54d2da34f833481cff28144a669b2aa",
"packages": [
{
"name": "components/jquery",
@ -26,14 +26,14 @@
"type": "component",
"extra": {
"component": {
"scripts": [
"jquery.js"
],
"files": [
"jquery.min.js",
"jquery-migrate.js",
"jquery-migrate.min.js",
"jquery.min.map"
],
"scripts": [
"jquery.js"
]
}
},
@ -303,17 +303,17 @@
},
{
"name": "thetempusproject/bedrock",
"version": "1.0.10",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://git.thetempusproject.com/the-tempus-project/bedrock",
"reference": "42ade08306525488f2449a2f4e3e05569eee9822"
"reference": "bcd73d58f9d7df41b5ec0f12871ff15cfcc215ae"
},
"require": {
"php": ">=8.1.0",
"thetempusproject/canary": ">=1.0",
"thetempusproject/hermes": ">=1.0",
"thetempusproject/houdini": ">=1.0"
"thetempusproject/canary": "1.0.6",
"thetempusproject/hermes": "1.0.3",
"thetempusproject/houdini": "2.0.2"
},
"type": "library",
"autoload": {
@ -344,15 +344,15 @@
"framework",
"mvc"
],
"time": "2024-08-21T10:12:54+00:00"
"time": "2025-01-27T05:07:05+00:00"
},
{
"name": "thetempusproject/canary",
"version": "1.0.5",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://git.thetempusproject.com/the-tempus-project/canary",
"reference": "35415fbf3c5888ccdb8a8695989176a120026c7f"
"reference": "44b2ad688cff933964ec2ff50b408d94c7f51e40"
},
"require": {
"php": ">=8.1.0"
@ -387,15 +387,15 @@
"thetempusproject",
"tools"
],
"time": "2024-08-20T10:26:09+00:00"
"time": "2025-01-22T01:39:34+00:00"
},
{
"name": "thetempusproject/hermes",
"version": "1.0.2",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://git.thetempusproject.com/the-tempus-project/hermes",
"reference": "31c51c1a5bad2871df800c89f27ace0a49848583"
"reference": "4b4e06a98f0f01695bda18de240bb3294d096ef4"
},
"require": {
"php": ">=8.1.0"
@ -430,20 +430,20 @@
"thetempusproject",
"tools"
],
"time": "2024-08-20T10:26:47+00:00"
"time": "2025-01-22T01:43:15+00:00"
},
{
"name": "thetempusproject/houdini",
"version": "1.0.8",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://git.thetempusproject.com/the-tempus-project/houdini",
"reference": "d9e61d3f8f5d10f3fa7ba31907a4b3c1edc76614"
"reference": "fb027a4ebc327e709ad3da29a4cf112894c2b7e6"
},
"require": {
"php": ">=8.1.0",
"thetempusproject/canary": ">=1.0",
"thetempusproject/hermes": ">=1.0"
"thetempusproject/canary": "1.0.6",
"thetempusproject/hermes": "1.0.3"
},
"type": "library",
"autoload": {
@ -474,7 +474,7 @@
"thetempusproject",
"tools"
],
"time": "2024-08-20T10:30:48+00:00"
"time": "2025-01-27T05:02:14+00:00"
},
{
"name": "twbs/bootstrap",
@ -535,5 +535,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.3.0"
}