implemented additional todo functionality
This commit is contained in:
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
*.env
|
*.env
|
||||||
composer.lock
|
composer.lock
|
||||||
/vendor/
|
/vendor/
|
||||||
/data/profile_pictures
|
data/profile_pictures
|
||||||
/data/articles
|
data/articles
|
||||||
/data/tmp
|
data/tmp
|
||||||
import.sql
|
import.sql
|
||||||
|
|||||||
@@ -3,16 +3,8 @@
|
|||||||
function todo_actions()
|
function todo_actions()
|
||||||
{
|
{
|
||||||
$actions = '
|
$actions = '
|
||||||
<div class="todo_actions">
|
<div id="todo_actions">
|
||||||
<form method="post">
|
<button value="new" class="button">New</button>
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
<button name="action" value="new">New</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
';
|
';
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,12 @@ function todo_display($todos)
|
|||||||
<div class="todo_category_window">
|
<div class="todo_category_window">
|
||||||
';
|
';
|
||||||
|
|
||||||
foreach ($categories as $c)
|
|
||||||
$c = array_reverse($c);
|
|
||||||
|
|
||||||
foreach (array_keys($categories) as $key)
|
foreach (array_keys($categories) as $key)
|
||||||
$display .= todo_category($key, $categories[$key]);
|
$display .= todo_category($key, $categories[$key]);
|
||||||
|
|
||||||
$display .= '
|
$display .= '
|
||||||
</div>
|
</div>
|
||||||
|
' . todo_modal(null, 'new_todo_item') . '
|
||||||
</div>
|
</div>
|
||||||
';
|
';
|
||||||
|
|
||||||
|
|||||||
@@ -7,20 +7,17 @@ function todo_item($todo)
|
|||||||
<div class="row left_margin">
|
<div class="row left_margin">
|
||||||
<div class="column center">
|
<div class="column center">
|
||||||
<label class="form_checkbox_container no_margin">
|
<label class="form_checkbox_container no_margin">
|
||||||
<input type="hidden" name="todo_id" value="' . $todo['todo_id'] . '">
|
<input type="hidden" name="todo_id" value="' . (isset($todo['todo_id']) ? $todo['todo_id'] : '') . '">
|
||||||
|
|
||||||
<input type="checkbox"' . ($todo['status'] == 'completed' ? ' checked' : '') . '>
|
<input type="checkbox"' . (!empty($todo) ? ($todo['status'] == 'completed' ? ' checked' : '') : '') . '>
|
||||||
<span class="checkmark no_margin"></span>
|
<span class="checkmark no_margin"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="column center">
|
<div class="column center modal_activation_area">
|
||||||
<small>' . $todo['task'] . '</small>
|
<small>' . $todo['title'] . '</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
' . todo_modal($todo, null) . '
|
||||||
|
|
||||||
<div class="todo_item_details" style="display: none;">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
';
|
';
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,76 @@
|
|||||||
<?php
|
<?php
|
||||||
function modal() {}
|
function todo_modal($todo = [], $id = null)
|
||||||
|
{
|
||||||
|
if (!isset($todo)) {
|
||||||
|
$todo['created_at'] = '';
|
||||||
|
$todo['updated_at'] = '';
|
||||||
|
$todo['completed_at'] = '';
|
||||||
|
$todo['todo_id'] = '';
|
||||||
|
$todo['title'] = '';
|
||||||
|
$todo['description'] = '';
|
||||||
|
$todo['priority'] = '';
|
||||||
|
$todo['due_date'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$modal = '
|
||||||
|
<div class="modal card todo_item_details"' . (isset($id) ? ' id="' . $id . '"' : '') . '>
|
||||||
|
<div id="modal_content">
|
||||||
|
<div class="form_card">
|
||||||
|
<div class="row_space_between">
|
||||||
|
<h5 class="underline">Item View</h5>
|
||||||
|
';
|
||||||
|
|
||||||
|
if (!empty($todo['title'])) {
|
||||||
|
$modal .= '
|
||||||
|
<div class="column over_right_margin">
|
||||||
|
<small>Created: ' . $todo['created_at'] . '</small>
|
||||||
|
<small>Updated: ' . $todo['updated_at'] . '</small>
|
||||||
|
<small>Completed: ' . $todo['completed_at'] . '</small>
|
||||||
|
</div>
|
||||||
|
';
|
||||||
|
}
|
||||||
|
|
||||||
|
$modal .= '
|
||||||
|
</div>
|
||||||
|
<span class="modal_close">×</span>
|
||||||
|
<form>
|
||||||
|
<input type="hidden" name="todo_id" value="' . (!empty($todo['todo_id']) ? $todo['todo_id'] : '-1') . '">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="column full_width">
|
||||||
|
<label for="title">Title:</label>
|
||||||
|
<input id="title" name="title" value="' . $todo['title'] . '" placeholder="Task Title" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="column full_width">
|
||||||
|
<label for="description">Description:</label>
|
||||||
|
<textarea id="description" name="description">' . $todo['description'] . '</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row_space_between">
|
||||||
|
<div class="column">
|
||||||
|
<label for="priority">Priority:</label>
|
||||||
|
<select id="priority" name="priority">
|
||||||
|
<option value="low"' . ($todo['priority'] == 'low' ? ' checked' : '') . '>Low</option>
|
||||||
|
<option value="medium"' . ($todo['priority'] == 'medium' ? ' checked' : '') . '>Medium</option>
|
||||||
|
<option value="high"' . ($todo['priority'] == 'high' ? ' checked' : '') . '>High</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<label for="due_date">Due Date:</label>
|
||||||
|
<input type="datetime-local" id="due_date" name="due_date" value="' . format_date($todo['due_date']) . '">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" class="button" value="' . (!empty($todo['todo_id']) ? 'Update Item' : 'Create Item') . '">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
';
|
||||||
|
|
||||||
|
return $modal;
|
||||||
|
}
|
||||||
|
|||||||
+9
-55
@@ -33,6 +33,8 @@ a,
|
|||||||
th,
|
th,
|
||||||
td,
|
td,
|
||||||
li,
|
li,
|
||||||
|
select,
|
||||||
|
option,
|
||||||
span {
|
span {
|
||||||
font-family: 'Hack Nerd Font Mono', Hack, sans-serif;
|
font-family: 'Hack Nerd Font Mono', Hack, sans-serif;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -352,6 +354,8 @@ textarea:-webkit-autofill,
|
|||||||
input:-webkit-autofill:hover,
|
input:-webkit-autofill:hover,
|
||||||
textarea:-webkit-autofill:hover,
|
textarea:-webkit-autofill:hover,
|
||||||
input:-webkit-autofill:focus,
|
input:-webkit-autofill:focus,
|
||||||
|
select,
|
||||||
|
option,
|
||||||
textarea {
|
textarea {
|
||||||
/* Try this first */
|
/* Try this first */
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@@ -361,6 +365,11 @@ textarea {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition-duration: 500ms;
|
transition-duration: 500ms;
|
||||||
resize: none;
|
resize: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="datetime_local"] {
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
@@ -746,63 +755,8 @@ hr {
|
|||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo_display {
|
|
||||||
margin: 0 auto;
|
|
||||||
margin-top: 25px;
|
|
||||||
width: 80%;
|
|
||||||
height: 80vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_actions {
|
|
||||||
padding: 15px;
|
|
||||||
border: 2px solid white;
|
|
||||||
border-radius: 8px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_actions form {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_category_window {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow-x: scroll;
|
|
||||||
overflow-y: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_category {
|
|
||||||
display: block;
|
|
||||||
min-width: 400px;
|
|
||||||
margin-right: 50px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_category h4 {
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo_item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
@media screen and (max-width: 992px) {
|
||||||
body {
|
body {
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/********** Width & Sizing **********/
|
||||||
|
.full_width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/********** Borders & Outlines **********/
|
/********** Borders & Outlines **********/
|
||||||
.std_border,
|
.std_border,
|
||||||
.med_border,
|
.med_border,
|
||||||
@@ -62,6 +67,10 @@
|
|||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.over_right_margin {
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
.bottom_margin {
|
.bottom_margin {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
@@ -93,3 +102,73 @@
|
|||||||
.left_padding {
|
.left_padding {
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********** FORMS **********/
|
||||||
|
|
||||||
|
|
||||||
|
/********** TODO ITEMS **********/
|
||||||
|
.todo_display {
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 25px;
|
||||||
|
width: 80%;
|
||||||
|
height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todo_actions {
|
||||||
|
padding: 15px;
|
||||||
|
border: 2px solid white;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_category_window {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_category {
|
||||||
|
display: block;
|
||||||
|
min-width: 400px;
|
||||||
|
margin-right: 50px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_category h4 {
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo_item_details {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_activation_area {}
|
||||||
|
|
||||||
|
.modal_activation_area:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
#### Overview:
|
|
||||||
This site is built in PHP with MariaDB and a Golang HTTP server. Composer is being used to supply the following PHP packages:
|
|
||||||
|
|
||||||
- `vlucas/phpdotenv`
|
|
||||||
- `erusev/parsedown`
|
|
||||||
- `wildbit/postmark-php`
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 19/03/2025 - Foundations:
|
|
||||||
Tonight, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/5af0547864f730091c98d64cc18014bc69d0a041) the first major feature implementation. The database is designed, and a component has been created for article cards, and markdown parsing into HTML for the articles themselves.
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 20/03/2025 - Refining UX:
|
|
||||||
Just now, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/c0fc9e9d0053975837ae48fa1db93b5095d33146) the second major feature implementation. I've narrowed in on the database design with small tweaks, setup some dynamic page loading on articles.php, created a navigation bar, a dark/light mode button, and styled everything up. It's shaping up pretty well!
|
|
||||||
|
|
||||||
There's a lot more work to be done. The entire login system needs to be implemented, user homepages, account management, admin panels, the article composer...the list goes on.
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 25/03/2025 - Account Management:
|
|
||||||
Just now, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/9a45075010434a4dedd0c5d48a78ff6be3bcfddc) the third major feature implementation: account management! Not the most exciting thing ever, but it is important for the long term success of this project. With that completed, v0.0.9 is completed! Though I prematurely labeled the commit v0.1.0...But in any case there's a lot to go before release.
|
|
||||||
|
|
||||||
There is now a sign up and login user flow, a user page with basic settings, and authorization for accessing things like the article composer. Oh yeah, I got a basic version of that running in [this commit](https://github.com/quaxlyqueen/vintagecoding.net/tree/0a27cd1f5cd02735d06a64090a05937a5d6bcf3a) a few hours ago.
|
|
||||||
|
|
||||||
Two major tasks remain prior to v0.1.0. First, I still need to finish implementing the image upload on new sign ups (and for changing a profile picture), but that should be relatively minor. Second, I need to use author information to flesh out article pages.
|
|
||||||
|
|
||||||
I'm now setting my sights on v0.2.0, and the myriad of features I'm planning on implementing for that. It'll be the account and customization overhaul. Tools for the owner and administrator(s), enabling users to request their role to be changed to contributor or administrator, user home pages with their own custom CSS, the ability to theme the site however they please, and mobile support! I'm excited just thinking about it. It'll require a MAJOR overhaul of the CSS, but thanks to the minimalist aesthetic, the CSS file is only a few hundred disorganized lines.
|
|
||||||
|
|
||||||
I've put maybe 30 hours into this project so far. I'm not sure if that's good or bad, but not getting crazy with the CSS has saved a **ton** of time. And, I really like how it's looking. I'm really excited about this project and I am giddy to see how much I can get implemented by the release on 25/05/2025 -- two months! I'm starting an *unpaid* internship tomorrow, so I probably won't have the time to put 30 hours a week into this. For now, I'm just excited to see what the future holds.
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 01/04/2025 - Basic Security & Administration:
|
|
||||||
Earlier today, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/cec9091ee01839b133ecbbc5616463a759837dda) a major security fix along with getting CI/CD setup, and last night I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/b9bb620ae01134431ff1941e7577ba58eee84e42) a secure overhaul of the 'Remember Me' functionality. I didn't write about it then, but a few days ago I also [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/ff7e799b7fd2822cf27e0afe47274de222b2b508) the image upload along with a image cropper. Still buggy as hell, but its a start. And a couple days ago I [committed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e6735a9a206a207b6fab704785451a6309944ddd) admin functionality to manage users and articles. I would've thought I'd slow down, but I'm just trucking along.
|
|
||||||
|
|
||||||
Specifically, the 'Remember Me' functionality is now using a token system, a randomly generated 1024 bit string, associated with the user ID and hashed values of both the remote address and (if used) forwarded for headers. If these don't match what is stored in the database, this should mean that the client browser/device is not the original browser/device used to create the token.
|
|
||||||
|
|
||||||
For the other security fix, I converted all of the `mysqli` statements to prepared statements. This is to mitigate the risk of SQL Injection attacks. Particularly since this site is live (though I'm not promoting it so it is still 'unreleased'), it is important to ensure that despite the lack of sensitive information, would-be attackers are unable to access user information, gain admin access, or compromise the server in any way.
|
|
||||||
|
|
||||||
Onto the user home pages! Here's a general breakdown of what I have in mind. Every user has a homepage that they can customize the CSS for. Effectively, give the users a place to make their own. Eventually even change the layout and structure of their page. For now, the page is going to have some pretty simple information: a list of articles written by the user, the number of articles they have read, and the number their articles have been read. More is to come in the future, but that's a long way out.
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 08/04/2025 - Image Cropping & Editing Articles:
|
|
||||||
Yesterday, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e5b3e048b8dc6731fa383778c26eba47186e5310) an update to the image cropper. In other words, it *actually* works now lol. I was driving home from class and I just realized that I needed to both offset the position from the window to the image, and scale the coordinates based on the size of the image. And just a moment ago, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e829e2e56695af5b77074f926c8d0c270e501f4b) editing articles. And here and there, I've worked on some basic Cross Site Scripting preventative measures, honeypots on signup to help prevent bots, and basic mobile responsiveness.
|
|
||||||
|
|
||||||
With some work being done with security now, I'm having second thoughts about allowing users to have custom CSS on their homepages. I'll punt that off till later.
|
|
||||||
|
|
||||||
All in all, things are going smoothly! I'm pretty proud of what I've built so far, and it has been quite educational. From prepared SQL statements, to XSS, form processing, and secure 'remember me' functionality. I'm not sure how much this site will be used by anyone else, and if that is the case I'll eventually just use this as a personal blog.
|
|
||||||
|
|
||||||
---
|
|
||||||
#### 12/04/2025 - Enhanced Markdown Editing Experience:
|
|
||||||
This was my first foray into the world of AJAX. I just [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/fb35e9322647878386bcc3be572cd404b38fd91b) the implementation of a markdown preview while composing or editing articles. The possibilities are **very** exciting, I'm already thinking of other places that the AJAX would be useful for.
|
|
||||||
|
|
||||||
Next, I'm looking to introduce Vim motions to the site, for general navigation and also for article composition and editing. It'll be an interesting challenge I think, and I could use the JavaScript practice.
|
|
||||||
|
|
||||||
I haven't said this previously, but I am *loving* PHP. Such a joy to work with, and pair that with AJAX for a very interactive experience? Phenomenal DX. I've been looking at an interesting project, [NativePHP](https://nativephp.com), that I'd like to eventually use for another project.
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 671 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 411 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 KiB |
+20
-7
@@ -7,21 +7,34 @@ if (isset($_POST['ajax_id'])) {
|
|||||||
handle_todo();
|
handle_todo();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
echo 'Received malformed request.';
|
$response = [
|
||||||
|
'error' => 'Malformed URI request.',
|
||||||
|
];
|
||||||
|
|
||||||
|
echo json_encode($response);
|
||||||
|
}
|
||||||
|
|
||||||
function handle_todo()
|
function handle_todo()
|
||||||
{
|
{
|
||||||
$response = [];
|
|
||||||
|
|
||||||
include 'functions/todo_functions.php';
|
include 'functions/todo_functions.php';
|
||||||
|
$response = ['log' => []];
|
||||||
if (isset($_POST['todo_id']) && isset($_POST['action_id']) && isset($_POST['status'])) {
|
if (isset($_POST['todo_id']) && isset($_POST['action_id'])) {
|
||||||
|
$response['log'][] = 'Required parameters met.';
|
||||||
switch ($_POST['action_id']) {
|
switch ($_POST['action_id']) {
|
||||||
case 'status':
|
case 'status':
|
||||||
$response['todo_status'] = $_POST['status'];
|
$response['log'][] = 'Changing status on ' . $_POST['todo_id'] . ' to ' . $_POST['status'] . '.';
|
||||||
change_status($_POST['todo_id'], $_POST['status']);
|
change_status($_POST['todo_id'], $_POST['status']);
|
||||||
break;
|
break;
|
||||||
|
case 'create_update_todo':
|
||||||
|
if ($_POST['todo_id'] != -1) {
|
||||||
|
$response['log'][] = 'Updating todo information on ' . $_POST['todo_id'] . '.';
|
||||||
|
update_todo($_POST['todo_id'], urldecode($_POST['todo']));
|
||||||
|
} else {
|
||||||
|
$response['log'][] = 'Creating todo information on ' . $_POST['todo_id'] . '.';
|
||||||
|
create_todo(urldecode($_POST['todo']));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,3 +178,8 @@ function pretty_dump($arr)
|
|||||||
echo '</pre>';
|
echo '</pre>';
|
||||||
return ob_get_clean();
|
return ob_get_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function format_date($date)
|
||||||
|
{
|
||||||
|
return (explode(' ', $date))[0];
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,3 +53,17 @@ function change_status($todo_id, $status)
|
|||||||
{
|
{
|
||||||
exec_stmt('UPDATE todos SET status = ? WHERE todo_id = ?', 'si', $status, $todo_id);
|
exec_stmt('UPDATE todos SET status = ? WHERE todo_id = ?', 'si', $status, $todo_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function create_todo($todo)
|
||||||
|
{
|
||||||
|
exec_stmt('INSERT INTO todos (title, description, priority, due_date, category, status) VALUES (?,?,?,?,?,?)', 'ssssss', $todo['title'], $todo['description'], $todo['priority'], $todo['due_date'], $todo['category'], 'open');
|
||||||
|
}
|
||||||
|
function update_todo($todo_id, $todo)
|
||||||
|
{
|
||||||
|
exec_stmt('UPDATE todos SET title = ? WHERE todo_id = ?', 'si', $todo['title'], $todo_id);
|
||||||
|
exec_stmt('UPDATE todos SET description = ? WHERE todo_id = ?', 'si', $todo['description'], $todo_id);
|
||||||
|
exec_stmt('UPDATE todos SET priority = ? WHERE todo_id = ?', 'si', $todo['priority'], $todo_id);
|
||||||
|
exec_stmt('UPDATE todos SET due_date = ? WHERE todo_id = ?', 'si', $todo['due_date'], $todo_id);
|
||||||
|
exec_stmt('UPDATE todos SET category = ? WHERE todo_id = ?', 'si', $todo['category'], $todo_id);
|
||||||
|
exec_stmt('UPDATE todos SET status = ? WHERE todo_id = ?', 'si', $todo['status'], $todo_id);
|
||||||
|
}
|
||||||
|
|||||||
+64
-2
@@ -15,10 +15,72 @@
|
|||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
var todos = document.getElementsByClassName('todo_item');
|
var todos = document.getElementsByClassName('todo_item');
|
||||||
//var todos = document.querySelectorAll('todo_item');
|
var action_items = (document.getElementById('todo_actions')).querySelectorAll('button');
|
||||||
|
|
||||||
|
// General Modal handling
|
||||||
|
function handle_modal(modal) {
|
||||||
|
console.log('handling modal');
|
||||||
|
let modal_close = modal.querySelector('.modal_close');
|
||||||
|
let submit_button = modal.querySelector('input[type="submit"]');
|
||||||
|
modal.style.display = 'block';
|
||||||
|
|
||||||
|
modal_close.addEventListener('click', function() {
|
||||||
|
modal.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
submit_button.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let todo = {
|
||||||
|
'title': modal.querySelector('#title').value,
|
||||||
|
'description': modal.querySelector('#description'),
|
||||||
|
'priority': modal.querySelector('#priority'),
|
||||||
|
'due_date': modal.querySelector('#due_date'),
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch('director.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: 'ajax_id=todo&action_id=create_update_todo&todo_id=' + this.todo_id + '&todo=' + encodeURIComponent(JSON.stringify(todo)),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json(); // Or handle other response formats
|
||||||
|
})
|
||||||
|
.then(responseData => {
|
||||||
|
console.log('Response received:', responseData);
|
||||||
|
// Handle the server's response
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < action_items.length; i++) {
|
||||||
|
let action = action_items[i];
|
||||||
|
|
||||||
|
action.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
switch (action.value) {
|
||||||
|
case 'new':
|
||||||
|
let new_todo_item = document.querySelector('#new_todo_item');
|
||||||
|
handle_modal(new_todo_item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < todos.length; i++) {
|
for (let i = 0; i < todos.length; i++) {
|
||||||
var item = todos[i];
|
let item = todos[i];
|
||||||
|
|
||||||
|
// Detailed todo item view via a modal
|
||||||
|
let modal_button = item.querySelector('.modal_activation_area');
|
||||||
|
let modal = item.querySelector('.modal');
|
||||||
|
modal_button.addEventListener('click', () => handle_modal(modal));
|
||||||
|
|
||||||
|
// Checkboxes & AJAX for updating the DB
|
||||||
var checkbox = item.querySelector('input[type="checkbox"]');
|
var checkbox = item.querySelector('input[type="checkbox"]');
|
||||||
checkbox.todo_id = item.querySelector('input[name="todo_id"]').value;
|
checkbox.todo_id = item.querySelector('input[name="todo_id"]').value;
|
||||||
checkbox.is_checked = checkbox.checked;
|
checkbox.is_checked = checkbox.checked;
|
||||||
|
|||||||
Reference in New Issue
Block a user