Skip to content

Commit

Permalink
feat: add read more
Browse files Browse the repository at this point in the history
  • Loading branch information
dewanakl committed Dec 7, 2024
1 parent c0541a5 commit fb5f465
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 20 deletions.
14 changes: 7 additions & 7 deletions js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ export const admin = (() => {
document.getElementById('editComment').checked = Boolean(res.data.can_edit);
document.getElementById('deleteComment').checked = Boolean(res.data.can_delete);
});
};

const getStatUser = () => {
request(HTTP_GET, '/api/stats').token(session.getToken()).send().then((res) => {
document.getElementById('count-comment').innerHTML = res.data.comments.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
document.getElementById('count-like').innerHTML = res.data.likes.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
Expand Down Expand Up @@ -205,6 +203,7 @@ export const admin = (() => {

const login = async (button) => {
const btn = util.disableButton(button);

const formEmail = document.getElementById('loginEmail');
const formPassword = document.getElementById('loginPassword');

Expand All @@ -214,7 +213,6 @@ export const admin = (() => {
const res = await session.login(dto.postSessionRequest(formEmail.value, formPassword.value));
if (res) {
getUserDetail();
getStatUser();
comment.comment();
bootstrap.Modal.getOrCreateInstance('#loginModal').hide();
formEmail.value = null;
Expand Down Expand Up @@ -252,22 +250,24 @@ export const admin = (() => {
theme.spyTop();
comment.init();

if (!session.isAdmin() || !session.getToken() || (JSON.parse(atob((session.getToken()).split('.')[1])).exp ?? 0) < (Date.now() / 1000)) {
try {
// window.atob can throw error
if (!session.isAdmin() || !session.getToken() || (JSON.parse(window.atob((session.getToken()).split('.')[1]))?.exp ?? 0) < (Date.now() / 1000)) {
throw new Error('invalid token');
}
} catch {
bootstrap.Modal.getOrCreateInstance('#loginModal').show();
return;
}

getUserDetail();
getStatUser();
comment.comment();
};

return {
init,
login,
logout,
getUserDetail,
getStatUser,
changeFilterBadWord,
replyComment,
editComment,
Expand Down
9 changes: 6 additions & 3 deletions js/card.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,17 @@ export const card = (() => {

const renderBody = (comment, is_parent) => {
const text = theme.isDarkMode('light', 'dark');
const original = convertMarkdownToHTML(util.escapeHtml(comment.comment));
const moreThan200 = original.length > 200;

return `
<div class="d-flex flex-wrap justify-content-between align-items-center">
<p class="text-${text} text-truncate m-0 p-0">${renderTitle(comment, is_parent)}</p>
<small class="text-${text} m-0 p-0" style="font-size: 0.75rem;">${comment.created_at}</small>
</div>
<hr class="text-${text} my-1">
<p class="text-${text} my-1 mx-0 p-0" style="white-space: pre-wrap !important; font-size: 0.95rem;" id="content-${comment.uuid}">${convertMarkdownToHTML(util.escapeHtml(comment.comment))}</p>`;
<p class="text-${text} my-1 mx-0 p-0" style="white-space: pre-wrap !important; font-size: 0.95rem;" ${moreThan200 ? `data-comment="${util.base64Encode(original)}"` : ''} id="content-${comment.uuid}">${moreThan200 ? (original.slice(0, 200) + '...') : original}</p>
${moreThan200 ? `<p class="mb-2 mt-0 mx-0 p-0"><a class="text-${text}" style="font-size: 0.85rem;" data-show="false" onclick="comment.showMore(this, '${comment.uuid}')">Selengkapnya</a></p>` : ''}`;
};

const renderContent = (comment, is_parent) => {
Expand All @@ -171,7 +174,7 @@ export const card = (() => {
inner.id = `inner-${id}`;
inner.innerHTML = `
<label for="form-inner-${id}" class="form-label" style="font-size: 0.95rem;"><i class="fa-solid fa-reply me-1"></i>Reply</label>
<textarea class="form-control shadow-sm rounded-4 mb-2" id="form-inner-${id}" placeholder="Type reply comment" offline-disabled></textarea>
<textarea class="form-control shadow-sm rounded-4 mb-2" id="form-inner-${id}" placeholder="Type reply comment" rows="4" offline-disabled></textarea>
<div class="d-flex flex-wrap justify-content-end align-items-center mb-0">
<button style="font-size: 0.8rem;" onclick="comment.cancel('${id}')" class="btn btn-sm btn-outline-${theme.isDarkMode('light', 'dark')} rounded-4 py-0 me-1" offline-disabled>Cancel</button>
<button style="font-size: 0.8rem;" onclick="comment.send(this)" data-uuid="${id}" class="btn btn-sm btn-outline-${theme.isDarkMode('light', 'dark')} rounded-4 py-0" offline-disabled>Send</button>
Expand All @@ -191,7 +194,7 @@ export const card = (() => {
<option value="1" ${presence ? 'selected' : ''}>Datang</option>
<option value="2" ${presence ? '' : 'selected'}>Berhalangan</option>
</select>` : ''}
<textarea class="form-control shadow-sm rounded-4 mb-2" id="form-inner-${id}" data-original="" placeholder="Type update comment" offline-disabled></textarea>
<textarea class="form-control shadow-sm rounded-4 mb-2" id="form-inner-${id}" placeholder="Type update comment" rows="4" offline-disabled></textarea>
<div class="d-flex flex-wrap justify-content-end align-items-center mb-0">
<button style="font-size: 0.8rem;" onclick="comment.cancel('${id}')" class="btn btn-sm btn-outline-${theme.isDarkMode('light', 'dark')} rounded-4 py-0 me-1" offline-disabled>Cancel</button>
<button style="font-size: 0.8rem;" onclick="comment.update(this)" data-uuid="${id}" class="btn btn-sm btn-outline-${theme.isDarkMode('light', 'dark')} rounded-4 py-0" offline-disabled>Update</button>
Expand Down
32 changes: 25 additions & 7 deletions js/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export const comment = (() => {
let tracker = null;
let showHide = null;

const changeButton = (id, disabled) => {
document.querySelector(`[data-button-action="${id}"]`).childNodes.forEach((e) => e.disabled = disabled);
};
const changeButton = (id, disabled) => document.querySelector(`[data-button-action="${id}"]`).childNodes.forEach((e) => e.disabled = disabled);

const remove = async (button) => {
if (!confirm('Are you sure?')) {
Expand Down Expand Up @@ -77,7 +75,7 @@ export const comment = (() => {
isChecklist = badge.classList.contains('text-success');
}

if (id && form.value === form.getAttribute('data-original') && isChecklist === isPresent) {
if (id && util.base64Encode(form.value) === form.getAttribute('data-original') && isChecklist === isPresent) {
changeButton(id, false);
document.getElementById(`inner-${id}`).remove();
return;
Expand Down Expand Up @@ -112,7 +110,15 @@ export const comment = (() => {
if (status) {
changeButton(id, false);
document.getElementById(`inner-${id}`).remove();
document.getElementById(`content-${id}`).innerHTML = card.convertMarkdownToHTML(util.escapeHtml(form.value));

const show = document.querySelector(`[onclick="comment.showMore(this, '${id}')"]`);
const original = card.convertMarkdownToHTML(util.escapeHtml(form.value));
const content = document.getElementById(`content-${id}`);

content.innerHTML = show && show.getAttribute('data-show') == 'false' ? original.slice(0, 200) + '...' : original;
if (original.length > 200) {
content.setAttribute('data-comment', util.base64Encode(original));
}

if (presence) {
document.getElementById('form-presence').value = isPresent ? '1' : '2';
Expand Down Expand Up @@ -307,8 +313,9 @@ export const comment = (() => {
}

document.getElementById(`button-${id}`).insertAdjacentElement('afterend', card.renderEdit(id, res.data.presence));
document.getElementById(`form-inner-${id}`).value = res.data.comment;
document.getElementById(`form-inner-${id}`).setAttribute('data-original', res.data.comment);
const formInner = document.getElementById(`form-inner-${id}`);
formInner.value = res.data.comment;
formInner.setAttribute('data-original', util.base64Encode(res.data.comment));
});

btn.restore();
Expand Down Expand Up @@ -402,6 +409,16 @@ export const comment = (() => {
}
};

const showMore = (anchor, uuid) => {
const comment = document.getElementById(`content-${uuid}`);
const original = util.base64Decode(comment.getAttribute('data-comment'));
const isCollapsed = anchor.getAttribute('data-show') === 'false';

comment.innerHTML = isCollapsed ? original : original.slice(0, 200) + '...';
anchor.innerText = isCollapsed ? 'Sebagian' : 'Selengkapnya';
anchor.setAttribute('data-show', isCollapsed ? 'true' : 'false');
};

const fetchTracker = (comment) => {
if (comment.comments) {
comment.comments.forEach(fetchTracker);
Expand Down Expand Up @@ -458,6 +475,7 @@ export const comment = (() => {
remove,
update,
comment,
showMore,
showOrHide,
};
})();
4 changes: 1 addition & 3 deletions js/offline.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ export const offline = (() => {
changeState();
};

const isOnline = () => {
return online;
};
const isOnline = () => online;

const addAbort = (callback) => {
abort.push(callback);
Expand Down
14 changes: 14 additions & 0 deletions js/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ export const util = (() => {
}, timeout);
};

const base64Encode = (str) => {
const encoder = new TextEncoder();
const encodedBytes = encoder.encode(str);
return btoa(String.fromCharCode(...encodedBytes));
};

const base64Decode = (str) => {
const decoder = new TextDecoder();
const decodedBytes = Uint8Array.from(atob(str), (c) => c.charCodeAt(0));
return decoder.decode(decodedBytes);
};

const close = () => {
storage('information').set('info', true);
};
Expand All @@ -113,6 +125,8 @@ export const util = (() => {
opacity,
animate,
escapeHtml,
base64Encode,
base64Decode,
disableButton,
addLoadingCheckbox,
};
Expand Down

0 comments on commit fb5f465

Please sign in to comment.