Post editing (from file!)

This commit is contained in:
pedrocx486 2023-02-11 21:46:06 -03:00
parent ccce6a3e20
commit 6ce1bb2a48
3 changed files with 129 additions and 19 deletions

View file

@ -1,8 +0,0 @@
{
"postTitle": "Hello World!",
"timestamp": "1654062776",
"editedTimestamp": "",
"postContent": "Welcome to my humble blog! This blog is hosted using a blog platform loosely based on my [ngx-dumblog](http:\/\/github.com\/pedroCX486\/ngx-dumblog) project. My intent is to make this look more and more retro with time.\r\n \r\nAnd before you ask, it's availabe [here](http:\/\/git.pedrocx486.club\/pedrocx486\/ngx-retroblog).\r\n \r\nFor more info (maybe), check [The Club](https:\/\/pedrocx486.club)!",
"filename": "hello-world",
"draft": false
}

View file

@ -1,11 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { VueShowdown } from 'vue-showdown'; import { VueShowdown } from 'vue-showdown';
import { downloadFile, parseFilename } from './file-manager.service'; import { downloadFile, parseFilename, loadFromFile } from './file-manager.service';
import { Archive } from './types'; import { Archive, Post } from './types';
import { generateTimestamp, parseTimestampToUTC, generatePostObj } from './post-utilities.service'; import { generateTimestamp, parseTimestampToUTC, generatePostObj } from './post-utilities.service';
import { getArchive, getPost } from './http-helper.service'; import { getArchive, getPost } from './http-helper.service';
// TODO:
// Modal requesting blog install base url.
// Fetch archive from install and show posts in a list.
// Allow selection of posts form list and load them.
// Save post and archive.
const postTitle = ref(''); const postTitle = ref('');
const postContent = ref(''); const postContent = ref('');
const postTimestamp = ref(''); const postTimestamp = ref('');
@ -18,12 +24,33 @@ let timestampUpdateInterval: number;
const archive = ref<Archive[]>(); const archive = ref<Archive[]>();
const loadArchive = (baseUrl: string) => { const openLoadModal = (): void => {
alert('Not implemented, yet.');
}
const loadArchive = (baseUrl: string): void => {
getArchive(baseUrl).then(res => { getArchive(baseUrl).then(res => {
archive.value = res; archive.value = res;
}); });
} }
const loadPostFromFile = (file: any): void => {
loadFromFile(file.target.files[0]).then((res: Post) => {
postTitle.value = res.postTitle;
postContent.value = res.postContent;
postTimestamp.value = res.timestamp;
isDraft.value = res.draft;
isEditingExisting.value = true;
clearInterval(timestampUpdateInterval);
timestampUpdateInterval = setInterval(() => {
editedTimestamp.value = generateTimestamp();
}, 33);
});
}
const loadPost = (baseUrl: string, filename: string): void => { const loadPost = (baseUrl: string, filename: string): void => {
getPost(baseUrl, filename).then(res => { getPost(baseUrl, filename).then(res => {
postTitle.value = res.postTitle; postTitle.value = res.postTitle;
@ -69,9 +96,6 @@ onMounted(() => {
timestampUpdateInterval = setInterval(() => { timestampUpdateInterval = setInterval(() => {
postTimestamp.value = generateTimestamp(); postTimestamp.value = generateTimestamp();
}, 33); }, 33);
// For debugging.
// loadPost('localhost:3000', 'hello-world');
}); });
const computedFilename = computed(() => parseFilename(postTitle.value)) const computedFilename = computed(() => parseFilename(postTitle.value))
@ -99,7 +123,12 @@ const computedEditedTimestamp = computed(() => parseTimestampToUTC(editedTimesta
Created on: {{ computedTimestamp }} <br /> Created on: {{ computedTimestamp }} <br />
<span v-if="isEditingExisting">Edited on: {{ computedEditedTimestamp }} <br /></span> <span v-if="isEditingExisting">Edited on: {{ computedEditedTimestamp }} <br /></span>
Is it a draft? {{ isDraft? 'Yes': 'No' }}. <br /> Is it a draft? {{ isDraft? 'Yes': 'No' }}. <br />
<button class="btn-primary" @click="savePost">Save (ngx-retroblog format)</button> <div class="footer-buttons">
<button class="btn-primary" @click="savePost">Save (ngx-retroblog format)</button> &nbsp;
<button class="btn-primary" @click="openLoadModal">Load Post (from Archive)</button> &nbsp; <br />
<input type="file" accept=".json" id="file-input" @change="loadPostFromFile($event)">
<label for="file-input">Load Post (from File)</label>
</div>
</div> </div>
</template> </template>
@ -182,6 +211,47 @@ button {
padding: 0.2rem; padding: 0.2rem;
} }
.footer-buttons {
text-align: center;
}
#file-input {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
#file-input+label {
display: inline-block;
cursor: pointer;
transition: all 0.3s ease-in-out;
text-decoration: none;
padding: 0.55rem;
border: none;
box-shadow: #000a 4px 4px;
color: white;
background-color: rgb(97, 0, 162);
position: absolute;
font-size: 0.8rem;
margin-top: 0.3rem;
width: 20.7rem;
text-align: center;
margin-left: -11.2rem;
}
#file-input:focus+label,
#file-input+label:hover {
box-shadow: 0px 0px 7px rgb(97, 0, 162);
color: white;
}
label {
margin-bottom: 0 !important;
}
@media only screen and (hover: none) { @media only screen and (hover: none) {
.wrapper { .wrapper {
flex-direction: column; flex-direction: column;

View file

@ -1,3 +1,5 @@
import { Post } from "./types";
export const parseFilename = (titleToFilename: string): string => { export const parseFilename = (titleToFilename: string): string => {
if (!titleToFilename) { if (!titleToFilename) {
return 'None yet.' return 'None yet.'
@ -9,11 +11,13 @@ export const parseFilename = (titleToFilename: string): string => {
titleToFilename = titleToFilename.slice(0, -1); titleToFilename = titleToFilename.slice(0, -1);
} }
if (titleToFilename.length > 50) { // Limit filename size // Limit filename size
if (titleToFilename.length > 50) {
titleToFilename = titleToFilename.substring(0, 50); titleToFilename = titleToFilename.substring(0, 50);
if (titleToFilename.includes('-')) { if (titleToFilename.includes('-')) {
titleToFilename = titleToFilename.substring(0, Math.min(titleToFilename.length, titleToFilename.lastIndexOf('-'))); // Re-trim to avoid cutting a word in half. // Re-trim to avoid cutting a word in half.
titleToFilename = titleToFilename.substring(0, Math.min(titleToFilename.length, titleToFilename.lastIndexOf('-')));
} }
} }
@ -27,3 +31,47 @@ export const downloadFile = (postObj: any, fileName: string, archiveFile?: boole
a.setAttribute('href', window.URL.createObjectURL(blob)); a.setAttribute('href', window.URL.createObjectURL(blob));
a.click(); a.click();
} }
// Bad code ahead. Sail with caution!
export const loadFromFile = (file: any): Promise<Post> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
if (!file) {
reject('No file!');
}
reader.onload = (event => {
const contents: any = (event.target as FileReader).result;
// Yes, this is extremely hacky.
const objCompare: Post = {
postTitle: "",
timestamp: "",
editedTimestamp: "",
postContent: "",
filename: "",
draft: false
};
// And yes, I know this is crazy but it works.
try {
if (Object.keys(JSON.parse(contents.toString())).toString() === Object.keys(objCompare).toString()) {
resolve(JSON.parse(contents.toString()));
} else {
alert('Invalid file! Are you sure it\'s an Dumblog compatible JSON?');
reject('Invalid file!');
}
} catch (e) {
alert('Error loading file! Check the console for more info.');
console.log(e);
reject('Error loading file!');
}
});
reader.onerror = reject;
reader.readAsText(file);
});
}