V2 dev into master #21
@@ -1,4 +1,5 @@
|
||||
# NeoCMS
|
||||
|
||||
## Version 2.0
|
||||
|
||||
Version 2.0 is a complete rewrite to ensure we support the latest jQuery and TinyMCE GPL version.
|
||||
@@ -16,6 +17,7 @@ To install:
|
||||
* PHP 8 on Linux. None of that Windows Server crap
|
||||
|
||||
## Known Bugs
|
||||
|
||||
* Templating (New Page) not yet implemented
|
||||
* File (not images) uploads need to be implemented
|
||||
* Not completely tested
|
||||
|
||||
@@ -6,9 +6,61 @@ switch ($_REQUEST["action"]) {
|
||||
case "save":
|
||||
if (!empty($_POST['uri']) && !empty($_POST['content'])) {
|
||||
$_SESSION['core']->saveContent($_POST['uri'], $_POST['content']);
|
||||
die("Page Updated.");
|
||||
echo 'Page Updated.';
|
||||
} else {
|
||||
die('Unable to save page');
|
||||
echo 'Unable to save page';
|
||||
}
|
||||
break;
|
||||
|
||||
/**
|
||||
* getTemplates AJAX call to get list of files
|
||||
*/
|
||||
case "getTemplates":
|
||||
header('Content-type: application/json');
|
||||
$files = array_diff(scandir("../templates/"), array('..', '.'));
|
||||
$returnArray = [];
|
||||
foreach ($files as $file) {
|
||||
$returnArray[] = array("id" => $file, "name" => str_replace(array(".html", ".htm"), "", $file));
|
||||
}
|
||||
echo json_encode($returnArray);
|
||||
break;
|
||||
|
||||
/**
|
||||
* newPage AJAX call to take a template file and create a new page
|
||||
*/
|
||||
case "newPage":
|
||||
header('Content-type: application/json');
|
||||
|
||||
$filename = str_replace("..", "", $_POST['filename']);
|
||||
$template = str_replace("..", "", $_POST['template']);
|
||||
if (!str_ends_with($filename, ".htm") && !str_ends_with($filename, ".html")) {
|
||||
$filename .= ".html";
|
||||
}
|
||||
|
||||
// Some vhosts can supply a trailing slash on DOCUMENT_ROOT so tidy it up
|
||||
$destination = str_replace("//", "/", $_SERVER['DOCUMENT_ROOT'] . "/" . $filename);
|
||||
|
||||
|
||||
if (!file_exists("../templates/" . $template)) die(json_encode(array("error" => "Template not found")));
|
||||
if (file_exists($destination)) die(json_encode(array("error" => "Page or file already exists")));
|
||||
|
||||
file_put_contents($destination, file_get_contents("../templates/" . $template));
|
||||
if (!file_exists($destination)) die(json_encode(array("error" => "Template copy failed")));
|
||||
echo json_encode(array("ok" => "DONE_THE_NEEDFUL", "url" => str_replace("//", "/", "/" . $filename)));
|
||||
break;
|
||||
|
||||
case "getPages":
|
||||
header('Content-type: application/json');
|
||||
$it = new RecursiveDirectoryIterator("../../");
|
||||
$returnArray = [];
|
||||
foreach (new RecursiveIteratorIterator($it) as $file) {
|
||||
// Strip document root from URI, so relative
|
||||
$file = str_replace($_SERVER["DOCUMENT_ROOT"], "", $file->getRealPath());
|
||||
|
||||
if (!str_starts_with($file, "/cms/") && (str_ends_with($file, ".html") || str_ends_with($file, ".htm")))
|
||||
$returnArray[] = array("name" => $file, "url" => $file);
|
||||
}
|
||||
echo json_encode($returnArray);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -100,3 +100,72 @@ body {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
New Page Modal
|
||||
*/
|
||||
|
||||
#newPageDialog {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.newpage-content {
|
||||
padding: 20px;
|
||||
background-color: #fefefe;
|
||||
border: 1px solid #888;
|
||||
width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.newpage-content form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.newpage-content label {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.newpage-content input[type="text"] {
|
||||
margin-bottom: 20px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#newPageForm label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
File List Modal
|
||||
*/
|
||||
|
||||
#fileListDialog {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filelist-content {
|
||||
padding: 20px;
|
||||
background-color: #fefefe;
|
||||
border: 1px solid #888;
|
||||
width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#fileList {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#fileList li {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
background-color: #f0f0f0;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#fileList li:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+29
-1
@@ -3,16 +3,20 @@ require_once "neoCMSCore.php";
|
||||
require_once "init.php";
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en-gb">
|
||||
<head>
|
||||
<title>NeoCMS</title>
|
||||
<!-- Include jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.14.0/jquery-ui.min.js" crossorigin="anonymous"></script>
|
||||
<!-- Include TinyMCE -->
|
||||
<script src="/cms/tinymce/tinymce.min.js"></script>
|
||||
<!-- Include Bootstrap for modal -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||
|
||||
<!-- Include JqueryUI CSS -->
|
||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.14.0/themes/base/jquery-ui.css">
|
||||
|
||||
<!-- Include editor styles -->
|
||||
<link rel="stylesheet" href="/cms/css/editor.css">
|
||||
|
||||
@@ -58,6 +62,30 @@ require_once "init.php";
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--New Page modal -->
|
||||
<div id="newPageDialog" title="Create a New Page">
|
||||
<div class="newpage-content">
|
||||
<form id="newPageForm">
|
||||
<div id="radioList">
|
||||
<!-- Radio buttons will be populated here -->
|
||||
</div>
|
||||
<label for="filename">New Filename:</label>
|
||||
<input type="text" id="filename" name="filename" placeholder="Enter new filename" required>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page list modal -->
|
||||
<div id="fileListDialog" title="Select an Existing Page">
|
||||
<div class="filelist-content">
|
||||
<ul id="fileList">
|
||||
<!-- File names will be populated here -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/cms/js/cms.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
+112
-2
@@ -51,6 +51,7 @@ $(document).ready(function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Save changes made to a div, but not save to the file on the server
|
||||
$('#saveBtn').click(function () {
|
||||
// Get the data from TinyMCE
|
||||
var data = tinymce.get('editor').getContent();
|
||||
@@ -69,13 +70,122 @@ $(document).ready(function () {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Saving changes to the page
|
||||
$('#savePage').click(() => {
|
||||
$.post("./controller/", {
|
||||
$.post("/cms/controller/", {
|
||||
action: "save",
|
||||
uri: $('#frameContainer').contents().get(0).location.pathname,
|
||||
content: new XMLSerializer().serializeToString($('#frameContainer').contents().get(0))
|
||||
}, function (data) {
|
||||
alert(data)
|
||||
// alert(data)
|
||||
});
|
||||
});
|
||||
|
||||
// Show dialog for page templates
|
||||
$("#newPage").click(function () {
|
||||
loadListOfTemplates(); // Call the function to load items when the modal is opened
|
||||
$("#newPageDialog").dialog({
|
||||
modal: true,
|
||||
width: 500,
|
||||
buttons: {
|
||||
Close: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle form submission for creating a new page
|
||||
$("#newPageForm").submit(function (event) {
|
||||
event.preventDefault(); // Prevent the default form submission
|
||||
|
||||
let selectedItemId = $('input[name="item"]:checked').val();
|
||||
let filename = $("#filename").val();
|
||||
|
||||
$.ajax({
|
||||
url: "/cms/controller/?action=newPage",
|
||||
method: "POST",
|
||||
data: {
|
||||
template: selectedItemId,
|
||||
filename: filename
|
||||
},
|
||||
success: function (response) {
|
||||
if (typeof response.error != "undefined") {
|
||||
alert(response.error);
|
||||
} else {
|
||||
$('#frameContainer').contents().get(0).location.href = response.url;
|
||||
$("#newPageForm").dialog("close"); // Close the modal on success
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert('Failed to create the new page.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Function to load the items via an AJAX GET request and populate the radio buttons for page templates
|
||||
function loadListOfTemplates() {
|
||||
$.ajax({
|
||||
url: "/cms/controller/?action=getTemplates",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
let radioList = $('#radioList');
|
||||
radioList.empty(); // Clear previous content
|
||||
data.forEach(function (item, index) {
|
||||
radioList.append(`
|
||||
<label>
|
||||
<input type="radio" name="item" value="${item.id}" ${index === 0 ? 'checked' : ''}>
|
||||
${item.name}
|
||||
</label>
|
||||
`);
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
alert('Failed to load templates.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to load the list of filenames via AJAX
|
||||
function loadListOfPages() {
|
||||
$.ajax({
|
||||
url: "/cms/controller/?action=getPages", // Replace with your actual API endpoint
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
let fileList = $('#fileList');
|
||||
fileList.empty(); // Clear previous list
|
||||
|
||||
data.forEach(function (file) {
|
||||
fileList.append(`<li data-url="${file.url}">${file.name}</li>`);
|
||||
});
|
||||
|
||||
// Add click event to list items to redirect
|
||||
$("#fileList li").click(function () {
|
||||
const fileUrl = $(this).data("url");
|
||||
$('#frameContainer').contents().get(0).location.href = fileUrl; // Redirect to the clicked file's URL
|
||||
$("#fileListDialog").dialog("close"); // Close the modal
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
alert('Failed to load file list.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle 'Select Page' button
|
||||
$("#selectPage").click(function () {
|
||||
loadListOfPages(); // Call function to load the file list
|
||||
$("#fileList").dialog({
|
||||
modal: true,
|
||||
width: 500,
|
||||
buttons: {
|
||||
Close: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -24,6 +24,7 @@ if(isset($_POST['username']) && isset($_POST['password'])){
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #eef1f5;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 350px;
|
||||
margin: 100px auto;
|
||||
@@ -32,16 +33,19 @@ if(isset($_POST['username']) && isset($_POST['password'])){
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.login-container h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.login-container label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
.login-container input[type="text"],
|
||||
.login-container input[type="password"] {
|
||||
width: 100%;
|
||||
@@ -51,6 +55,7 @@ if(isset($_POST['username']) && isset($_POST['password'])){
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.login-container button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
@@ -61,9 +66,11 @@ if(isset($_POST['username']) && isset($_POST['password'])){
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login-container button:hover {
|
||||
background-color: #005bb5;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff4d4d;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Welcome to NeoCMS</title>
|
||||
<link href="/cms/css/welcome.style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<img alt="Application Logo" class="logo" src="/cms/img/welcomeLogo.png">
|
||||
</header>
|
||||
<main>
|
||||
<h1>Welcome to NeoCMS</h1>
|
||||
<p>This is another example template, found in /cms/templates/ - remove me and replace me with your own site
|
||||
templates!</p>
|
||||
<p class="editable">
|
||||
This box is editable!<br/>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Quisque sit amet accumsan tortor. Itaque earum rerum hic tenetur a sapiente delectus.
|
||||
</p>
|
||||
</main>
|
||||
<footer>
|
||||
<p>© 2024 Andy Dixon</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Welcome to NeoCMS</title>
|
||||
<link href="/cms/css/welcome.style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<img alt="Application Logo" class="logo" src="/cms/img/welcomeLogo.png">
|
||||
</header>
|
||||
<main>
|
||||
<h1>Welcome to NeoCMS</h1>
|
||||
<p>This is an example template, found in /cms/templates/ - remove me and replace me with your own site
|
||||
templates!</p>
|
||||
<p class="editable">
|
||||
This box is editable!<br/>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Quisque sit amet accumsan tortor. Itaque earum rerum hic tenetur a sapiente delectus.
|
||||
</p>
|
||||
</main>
|
||||
<footer>
|
||||
<p>© 2024 Andy Dixon</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+907
-68
File diff suppressed because it is too large
Load Diff
+9
-3
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Welcome to Our Application</title>
|
||||
<title>Welcome to NeoCMS</title>
|
||||
<link href="/cms/css/welcome.style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
@@ -11,9 +11,15 @@
|
||||
</header>
|
||||
<main>
|
||||
<h1>Welcome to NeoCMS</h1>
|
||||
<p>Put some content in here</p>
|
||||
<p>Introducing a cutting-edge CMS designed to effortlessly integrate with your existing flat-file website—no
|
||||
database required. Our databaseless WYSIWYG content management system empowers you to create, edit, and manage
|
||||
content visually, all while maintaining the simplicity and speed of a flat-file setup. Enjoy a seamless
|
||||
experience that combines the flexibility of a modern CMS with the efficiency of a static website, allowing you
|
||||
to focus on content without the complexity of database management. Perfect for developers and creators looking
|
||||
to streamline workflows without sacrificing control or performance.</p>
|
||||
|
||||
<p class="editable">
|
||||
This box is editable!<br/>
|
||||
This box is editable! Just click me to edit me!<br/>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Quisque sit amet accumsan tortor. Itaque earum rerum hic tenetur a sapiente delectus.
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user