older-blog-posts #56
39
dist/api/blog/blogData.php
vendored
39
dist/api/blog/blogData.php
vendored
@ -673,9 +673,17 @@ EOD;
|
|||||||
*/
|
*/
|
||||||
public function changeHTMLSrc(string $body, string $to, string $from): string
|
public function changeHTMLSrc(string $body, string $to, string $from): string
|
||||||
{
|
{
|
||||||
|
// $body = preg_replace_callback('/>([^<]+)</', function($matches) {
|
||||||
|
// // Convert special characters to HTML entities
|
||||||
|
// return '>' . htmlentities(trim($matches[1]), ENT_QUOTES | ENT_HTML5, 'UTF-8') . '<';
|
||||||
|
// }, $body);
|
||||||
|
|
||||||
$htmlDoc = new DOMDocument();
|
$htmlDoc = new DOMDocument();
|
||||||
$body = mb_convert_encoding($body, "HTML-ENTITIES", "UTF-8");
|
|
||||||
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
// Load the raw HTML content into DOMDocument
|
||||||
|
@$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
||||||
|
|
||||||
|
// Get the body and process images
|
||||||
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
||||||
$imgs = $doc->getElementsByTagName('img');
|
$imgs = $doc->getElementsByTagName('img');
|
||||||
|
|
||||||
@ -688,9 +696,11 @@ EOD;
|
|||||||
$srcList[] = $src;
|
$srcList[] = $src;
|
||||||
$fileName = basename($src);
|
$fileName = basename($src);
|
||||||
|
|
||||||
|
// Update the src attribute to the new location
|
||||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename files and clean up old ones
|
||||||
$files = scandir($from);
|
$files = scandir($from);
|
||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
{
|
{
|
||||||
@ -706,15 +716,36 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the HTML content for output
|
||||||
$newBody = '';
|
$newBody = '';
|
||||||
foreach ($doc->childNodes as $node)
|
foreach ($doc->childNodes as $node)
|
||||||
{
|
{
|
||||||
$newHTML = $htmlDoc->saveHTML($node);
|
// Only convert text nodes to HTML entities
|
||||||
$newBody .= mb_convert_encoding($newHTML, "UTF-8", mb_detect_encoding($newHTML));
|
if ($node->nodeType === XML_TEXT_NODE)
|
||||||
|
{
|
||||||
|
$newBody .= $this->convertToHtmlEntities($node->nodeValue); // Convert text nodes
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$newBody .= $htmlDoc->saveHTML($node); // Keep HTML tags intact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $newBody;
|
return $newBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert all characters in a string to HTML entities while leaving HTML tags intact.
|
||||||
|
* @param string $text - The text to convert
|
||||||
|
* @return string - The converted text with HTML entities
|
||||||
|
*/
|
||||||
|
private function convertToHtmlEntities(string $text): string
|
||||||
|
{
|
||||||
|
// Convert characters to HTML entities using mb_encode_numericentity
|
||||||
|
return htmlentities($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all posts with the given category
|
* Get all posts with the given category
|
||||||
* @param string $category - Category of the post
|
* @param string $category - Category of the post
|
||||||
|
2
dist/blog/css/main.css
vendored
2
dist/blog/css/main.css
vendored
File diff suppressed because one or more lines are too long
2
dist/blog/js/index.js
vendored
2
dist/blog/js/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/blog/js/prism.js
vendored
2
dist/blog/js/prism.js
vendored
File diff suppressed because one or more lines are too long
2
dist/editor/js/CKEditor/ckeditor.js
vendored
2
dist/editor/js/CKEditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
2
dist/editor/js/editor.js
vendored
2
dist/editor/js/editor.js
vendored
File diff suppressed because one or more lines are too long
2786
package-lock.json
generated
2786
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -674,8 +674,11 @@ EOD;
|
|||||||
public function changeHTMLSrc(string $body, string $to, string $from): string
|
public function changeHTMLSrc(string $body, string $to, string $from): string
|
||||||
{
|
{
|
||||||
$htmlDoc = new DOMDocument();
|
$htmlDoc = new DOMDocument();
|
||||||
$body = mb_convert_encoding($body, "HTML-ENTITIES", "UTF-8");
|
|
||||||
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
// Load the raw HTML content into DOMDocument
|
||||||
|
@$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
||||||
|
|
||||||
|
// Get the body and process images
|
||||||
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
||||||
$imgs = $doc->getElementsByTagName('img');
|
$imgs = $doc->getElementsByTagName('img');
|
||||||
|
|
||||||
@ -688,9 +691,11 @@ EOD;
|
|||||||
$srcList[] = $src;
|
$srcList[] = $src;
|
||||||
$fileName = basename($src);
|
$fileName = basename($src);
|
||||||
|
|
||||||
|
// Update the src attribute to the new location
|
||||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename files and clean up old ones
|
||||||
$files = scandir($from);
|
$files = scandir($from);
|
||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
{
|
{
|
||||||
@ -706,15 +711,36 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the HTML content for output
|
||||||
$newBody = '';
|
$newBody = '';
|
||||||
foreach ($doc->childNodes as $node)
|
foreach ($doc->childNodes as $node)
|
||||||
{
|
{
|
||||||
$newHTML = $htmlDoc->saveHTML($node);
|
// Only convert text nodes to HTML entities
|
||||||
$newBody .= mb_convert_encoding($newHTML, "UTF-8", mb_detect_encoding($newHTML));
|
if ($node->nodeType === XML_TEXT_NODE)
|
||||||
|
{
|
||||||
|
$newBody .= $this->convertToHtmlEntities($node->nodeValue); // Convert text nodes
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$newBody .= $htmlDoc->saveHTML($node); // Keep HTML tags intact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $newBody;
|
return $newBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert all characters in a string to HTML entities while leaving HTML tags intact.
|
||||||
|
* @param string $text - The text to convert
|
||||||
|
* @return string - The converted text with HTML entities
|
||||||
|
*/
|
||||||
|
private function convertToHtmlEntities(string $text): string
|
||||||
|
{
|
||||||
|
// Convert characters to HTML entities using mb_encode_numericentity
|
||||||
|
return htmlentities($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all posts with the given category
|
* Get all posts with the given category
|
||||||
* @param string $category - Category of the post
|
* @param string $category - Category of the post
|
||||||
|
@ -123,3 +123,102 @@ section.largePost .outerContent .postContent a {
|
|||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts {
|
||||||
|
/*max-width: 90%;*/
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .carousel {
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
display: flex;
|
||||||
|
width: 2.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: 1.625em;
|
||||||
|
color: white;
|
||||||
|
background: var(--mutedBlack);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow:hover {
|
||||||
|
background: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .carouselOuter {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #allCarouselItems {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1em;
|
||||||
|
transition: transform 0.5s ease-in-out;
|
||||||
|
left: 0;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid var(--primaryDefault);
|
||||||
|
-webkit-border-radius: 0.625rem;
|
||||||
|
-moz-border-radius: 0.625rem;
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
width: 30em;
|
||||||
|
height: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem img {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: left;
|
||||||
|
-webkit-border-radius: 0.625rem;
|
||||||
|
-moz-border-radius: 0.625rem;
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem .content {
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin: 0 2em 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
@import "home.css";
|
@import "home.css";
|
||||||
@import "category.css";
|
@import "category.css";
|
||||||
|
|
||||||
|
div.menuBar a.link::before, main a.link::before,
|
||||||
|
div.menuBar a.link::after, main a.link::after {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal Styling */
|
||||||
.policy {
|
.policy {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -73,6 +79,11 @@
|
|||||||
|
|
||||||
@media screen and (max-width: 90em) {
|
@media screen and (max-width: 90em) {
|
||||||
|
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 25em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
|
|
||||||
div.mainContent {
|
div.mainContent {
|
||||||
@ -124,6 +135,25 @@
|
|||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
section#individualPost {
|
section#individualPost {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
@ -219,6 +249,24 @@
|
|||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -1.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -1.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
|
|
||||||
aside.sideContent > div.authorInfo {
|
aside.sideContent > div.authorInfo {
|
||||||
|
@ -41,7 +41,6 @@ function goToURL(url)
|
|||||||
if (url === '/blog' || url === 'blog' || url === '/blog/')
|
if (url === '/blog' || url === 'blog' || url === '/blog/')
|
||||||
{
|
{
|
||||||
loadHomeContent();
|
loadHomeContent();
|
||||||
// window.history.pushState(null, null, url);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +161,10 @@ function submitNewsletter()
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unsubscribe by email
|
||||||
|
* @param email the email to unsubscribe
|
||||||
|
*/
|
||||||
function unsubscribe(email)
|
function unsubscribe(email)
|
||||||
{
|
{
|
||||||
fetch(`/api/blog/newsletter/${email}`, {
|
fetch(`/api/blog/newsletter/${email}`, {
|
||||||
@ -243,6 +246,32 @@ function createLargePost(post)
|
|||||||
return outerContent;
|
return outerContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a card post element
|
||||||
|
* @param post the object
|
||||||
|
* @returns {HTMLDivElement} the outer content of the post
|
||||||
|
*/
|
||||||
|
function createCardPost(post)
|
||||||
|
{
|
||||||
|
let cardItem = document.createElement('div');
|
||||||
|
cardItem.classList.add('cardItem');
|
||||||
|
cardItem.id = 'post' + post.ID;
|
||||||
|
let img = document.createElement('img');
|
||||||
|
img.className = 'cardImg';
|
||||||
|
img.src = post.headerImg.replaceAll('%2F', '/');
|
||||||
|
img.alt = post.title;
|
||||||
|
cardItem.appendChild(img);
|
||||||
|
let content = document.createElement('div');
|
||||||
|
content.classList.add('content');
|
||||||
|
content.innerHTML = `
|
||||||
|
<h2>${post.title}</h2>
|
||||||
|
<h3>Last updated: ${createFormattedDate(post.dateModified)}</h3>
|
||||||
|
<a href="/blog/post/${post.title}" class="btn btnPrimary">See Post</a>
|
||||||
|
`;
|
||||||
|
cardItem.appendChild(content);
|
||||||
|
return cardItem;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the home content
|
* Loads the home content
|
||||||
*/
|
*/
|
||||||
@ -250,6 +279,30 @@ function loadHomeContent()
|
|||||||
{
|
{
|
||||||
fetch('/api/blog/post').then(res => res.json().then(json =>
|
fetch('/api/blog/post').then(res => res.json().then(json =>
|
||||||
{
|
{
|
||||||
|
// older posts outside the carousel and loop
|
||||||
|
let olderPosts = document.createElement('section');
|
||||||
|
olderPosts.classList.add('largePost');
|
||||||
|
olderPosts.id = 'olderPosts';
|
||||||
|
let h1 = document.createElement('h1');
|
||||||
|
h1.innerHTML = 'older posts';
|
||||||
|
olderPosts.appendChild(h1);
|
||||||
|
|
||||||
|
let carousel = document.createElement('div');
|
||||||
|
carousel.classList.add('carousel');
|
||||||
|
carousel.innerHTML += `<div class="arrow" id="prev"><i class="fa-solid fa-chevron-left"></i></div>
|
||||||
|
<div class="arrow" id="next"><i class="fa-solid fa-chevron-right"></i></div>
|
||||||
|
`;
|
||||||
|
let carouselOuter = document.createElement('div');
|
||||||
|
let carouselInner = document.createElement('div');
|
||||||
|
let allCarouselItems = document.createElement('div');
|
||||||
|
carouselOuter.classList.add('carouselOuter');
|
||||||
|
carouselInner.id = 'carouselInner';
|
||||||
|
allCarouselItems.id = 'allCarouselItems';
|
||||||
|
carouselOuter.appendChild(allCarouselItems);
|
||||||
|
carouselOuter.appendChild(carouselInner);
|
||||||
|
carousel.appendChild(carouselOuter);
|
||||||
|
olderPosts.appendChild(carousel);
|
||||||
|
|
||||||
for (let i = 0; i < json.length; i++)
|
for (let i = 0; i < json.length; i++)
|
||||||
{
|
{
|
||||||
if (json[i].featured === 1)
|
if (json[i].featured === 1)
|
||||||
@ -278,10 +331,142 @@ function loadHomeContent()
|
|||||||
document.querySelector('#main').appendChild(latestPost);
|
document.querySelector('#main').appendChild(latestPost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > 1)
|
||||||
|
{
|
||||||
|
allCarouselItems.appendChild(createCardPost(json[i]));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
document.querySelector('#main').appendChild(olderPosts);
|
||||||
|
//carousel loop
|
||||||
|
carouselLoop(carouselInner, allCarouselItems);
|
||||||
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the loop for the carousel
|
||||||
|
* @param {HTMLDivElement} carouselInner
|
||||||
|
* @param {HTMLDivElement} allItems
|
||||||
|
*/
|
||||||
|
function carouselLoop(carouselInner, allItems)
|
||||||
|
{
|
||||||
|
const prev = document.querySelector('#prev');
|
||||||
|
const next = document.querySelector('#next');
|
||||||
|
const mediaBig = window.matchMedia('(max-width: 75em)');
|
||||||
|
const mediaSmall = window.matchMedia('(max-width: 30em)');
|
||||||
|
let cards = document.querySelectorAll('#allCarouselItems .cardItem');
|
||||||
|
let visibleCardsCount = 3;
|
||||||
|
|
||||||
|
if (mediaBig.matches)
|
||||||
|
{
|
||||||
|
visibleCardsCount = 2; // only show 2 cards if on a slightly smaller screen e.g. tablet/laptop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaSmall.matches)
|
||||||
|
{
|
||||||
|
visibleCardsCount = 1; // only show 1 card if on a mobile, although it'll only work on portrait
|
||||||
|
}
|
||||||
|
|
||||||
|
let visibleCards = [];
|
||||||
|
|
||||||
|
// put the first n (3, 2, or 1) cards in the carousel
|
||||||
|
for (let i = 0; i < visibleCardsCount; i++)
|
||||||
|
{
|
||||||
|
carouselInner.appendChild(cards[i]);
|
||||||
|
visibleCards.push(cards[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next.addEventListener('click', () =>
|
||||||
|
{
|
||||||
|
const firstCard = visibleCards.shift();
|
||||||
|
firstCard.style.visibility = 'hidden'; // hide the first card
|
||||||
|
|
||||||
|
// add the next card to the end and off the screen
|
||||||
|
const nextCard = allItems.querySelector('.cardItem');
|
||||||
|
nextCard.style.transform = 'translateX(100%)';
|
||||||
|
nextCard.style.transition = 'none';
|
||||||
|
carouselInner.appendChild(nextCard);
|
||||||
|
visibleCards.push(nextCard);
|
||||||
|
|
||||||
|
// transition all the cards to the left after 50ms
|
||||||
|
// i.e. after the next card is added hence the setTimeout
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move all the cards to the left
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'transform 0.5s ease-out';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(-100%)';
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// after 500ms move all cards back to the center and move
|
||||||
|
// the first card to the hidden div
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move the first card back to the center
|
||||||
|
// instantly and move it to the hidden div
|
||||||
|
firstCard.style.transition = 'none';
|
||||||
|
firstCard.style.transform = 'translateX(0)';
|
||||||
|
allItems.appendChild(firstCard);
|
||||||
|
firstCard.style.visibility = 'visible'; // make it visible again
|
||||||
|
|
||||||
|
// for the remaining cards, reset them
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'none';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(0%)';
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
// everything is done in reverse
|
||||||
|
prev.addEventListener('click', () =>
|
||||||
|
{
|
||||||
|
const lastCard = visibleCards.pop();
|
||||||
|
lastCard.style.visibility = 'hidden'; // hide the last card
|
||||||
|
|
||||||
|
// add the previous card to the beginning and off the screen
|
||||||
|
const prevCard = allItems.querySelector('.cardItem:last-child');
|
||||||
|
prevCard.style.transform = 'translateX(-100%)';
|
||||||
|
prevCard.style.transition = 'none';
|
||||||
|
carouselInner.insertBefore(prevCard, carouselInner.firstChild);
|
||||||
|
visibleCards.unshift(prevCard);
|
||||||
|
|
||||||
|
// transition all the cards to the right after 50ms
|
||||||
|
// i.e. after the previous card is added hence the setTimeout
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move all the cards to the right
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'transform 0.5s ease-out';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(100%)';
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// after 500ms move all cards back to the center and move
|
||||||
|
// the last card to the hidden div
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move the last card back to the center
|
||||||
|
// instantly and move it to the hidden div
|
||||||
|
lastCard.style.transition = 'none';
|
||||||
|
lastCard.style.transform = 'translateX(0)';
|
||||||
|
allItems.insertBefore(lastCard, allItems.firstChild);
|
||||||
|
lastCard.style.visibility = 'visible';
|
||||||
|
|
||||||
|
// for the remaining cards reset them
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'none';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(0%)';
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the latest and featured posts
|
* Gets the latest and featured posts
|
||||||
* @returns {Promise<any[]>} the latest and featured posts
|
* @returns {Promise<any[]>} the latest and featured posts
|
||||||
@ -848,6 +1033,9 @@ function loadPrivacyPolicy()
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the cookie policy
|
||||||
|
*/
|
||||||
function loadCookiePolicy()
|
function loadCookiePolicy()
|
||||||
{
|
{
|
||||||
document.querySelector('#main').innerHTML = `
|
document.querySelector('#main').innerHTML = `
|
||||||
|
@ -876,7 +876,7 @@ function createEditors(...ids)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
`<iframe width="560" height="315" style="text-align:center;" src="https://www.youtube.com/embed/${id}${time ? `?start=${time}` : ''}" ` +
|
`<iframe width="560" height="315" style="text-align:center;" src="https://www.youtube.com/embed/${id}${time ? `?start=${time}` : ''}" ` +
|
||||||
'frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>' +
|
'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>' +
|
||||||
'</iframe>'
|
'</iframe>'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -1229,7 +1229,7 @@ function updateProjectItem(id, e)
|
|||||||
data['gitLink'] = document.querySelector(`#git${id}proj`).value;
|
data['gitLink'] = document.querySelector(`#git${id}proj`).value;
|
||||||
|
|
||||||
let imgData = new FormData();
|
let imgData = new FormData();
|
||||||
imgData.append("img", document.querySelector(`#img${id}`).files[0]);
|
imgData.append('img', document.querySelector(`#img${id}proj`).files[0]);
|
||||||
|
|
||||||
fetch("/api/projectData/" + id, {
|
fetch("/api/projectData/" + id, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
@ -1254,8 +1254,8 @@ function updateProjectItem(id, e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("updating image")
|
console.log("updating image")
|
||||||
@ -1293,8 +1293,8 @@ function updateProjectItem(id, e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#projectImage${id}`).src = updatedProjectImage.imgLocation;
|
document.querySelector(`#projectImage${id}`).src = updatedProjectImage.imgLocation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user