forked from izu/student-web-if-development-kit
fix(tapops): deteksi format file dan format tag
This commit is contained in:
@@ -7,6 +7,56 @@ export class DocumentFormatter {
|
||||
{ key: 'praktik', match: ['praktik', 'praktek', 'kerja praktik', 'kp'] },
|
||||
];
|
||||
|
||||
static TAG_ABBREVIATIONS = new Set(['kp', 'sop', 'ta', 'krs', 'khs', 'sks', 'pkl', 'mbkm']);
|
||||
|
||||
static FILE_TYPE_RULES = [
|
||||
{ extensions: ['pdf'], mimeTypes: ['application/pdf'], icon: 'fas fa-file-pdf', css: 'doc-type-pdf' },
|
||||
{
|
||||
extensions: ['doc', 'docx'],
|
||||
mimeTypes: [
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
],
|
||||
fallbackType: 'docx',
|
||||
icon: 'fas fa-file-word',
|
||||
css: 'doc-type-docx',
|
||||
},
|
||||
{
|
||||
extensions: ['ppt', 'pptx'],
|
||||
mimeTypes: [
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
],
|
||||
fallbackType: 'pptx',
|
||||
icon: 'fas fa-file-powerpoint',
|
||||
css: 'doc-type-pptx',
|
||||
},
|
||||
{
|
||||
extensions: ['xls', 'xlsx'],
|
||||
mimeTypes: [
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
],
|
||||
fallbackType: 'xlsx',
|
||||
icon: 'fas fa-file-excel',
|
||||
css: 'doc-type-xlsx',
|
||||
},
|
||||
{ extensions: ['csv'], mimeTypes: ['text/csv'], icon: 'fas fa-file-csv', css: 'doc-type-xlsx' },
|
||||
{ extensions: ['txt', 'rtf', 'md'], mimeTypes: ['text/plain', 'application/rtf'], icon: 'fas fa-file-alt', css: 'doc-type-txt' },
|
||||
{
|
||||
extensions: ['zip', 'rar', '7z', 'tar', 'gz'],
|
||||
mimeTypes: ['application/zip', 'application/x-rar-compressed', 'application/x-7z-compressed', 'application/gzip'],
|
||||
icon: 'fas fa-file-archive',
|
||||
css: 'doc-type-archive',
|
||||
},
|
||||
{
|
||||
extensions: ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'],
|
||||
mimePrefix: 'image/',
|
||||
icon: 'fas fa-file-image',
|
||||
css: 'doc-type-image',
|
||||
},
|
||||
];
|
||||
|
||||
static formatDate(iso) {
|
||||
if (!iso) return '';
|
||||
const date = new Date(iso);
|
||||
@@ -26,14 +76,83 @@ export class DocumentFormatter {
|
||||
}
|
||||
|
||||
static fileTypeFromName(name) {
|
||||
const lower = (name || '').toLowerCase();
|
||||
if (lower.endsWith('.docx') || lower.endsWith('.doc')) return 'docx';
|
||||
return 'pdf';
|
||||
return this.fileInfoFromName(name).type;
|
||||
}
|
||||
|
||||
static fileInfoFromName(name) {
|
||||
const extension = this.extensionFromName(name);
|
||||
const rule = this.FILE_TYPE_RULES.find(item => item.extensions.includes(extension));
|
||||
|
||||
if (!rule) {
|
||||
return {
|
||||
type: extension || 'file',
|
||||
icon: 'fas fa-file',
|
||||
css: 'doc-type-file',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: extension,
|
||||
icon: rule.icon,
|
||||
css: rule.css,
|
||||
};
|
||||
}
|
||||
|
||||
static fileInfoFromItem(item) {
|
||||
const file = item?.file && typeof item.file === 'object' ? item.file : {};
|
||||
const nameCandidates = [
|
||||
file.filename_download,
|
||||
file.filename_disk,
|
||||
item?.nama_berkas,
|
||||
];
|
||||
|
||||
for (const name of nameCandidates) {
|
||||
const info = this.fileInfoFromName(name);
|
||||
if (info.type !== 'file') return info;
|
||||
}
|
||||
|
||||
return this.fileInfoFromMime(file.type);
|
||||
}
|
||||
|
||||
static fileInfoFromMime(type) {
|
||||
const mime = String(type || '').trim().toLowerCase();
|
||||
if (!mime) return this.fileInfoFromName('');
|
||||
|
||||
const rule = this.FILE_TYPE_RULES.find(item => (
|
||||
item.mimeTypes?.includes(mime) || (item.mimePrefix && mime.startsWith(item.mimePrefix))
|
||||
));
|
||||
|
||||
if (!rule) return this.fileInfoFromName('');
|
||||
|
||||
return {
|
||||
type: rule.fallbackType || rule.extensions[0],
|
||||
icon: rule.icon,
|
||||
css: rule.css,
|
||||
};
|
||||
}
|
||||
|
||||
static extensionFromName(name) {
|
||||
const normalized = String(name || '').trim().toLowerCase();
|
||||
const lastSegment = normalized.split(/[\\/]/).pop() || '';
|
||||
const extensionStart = lastSegment.lastIndexOf('.');
|
||||
|
||||
if (extensionStart <= 0 || extensionStart === lastSegment.length - 1) return '';
|
||||
return lastSegment.slice(extensionStart + 1);
|
||||
}
|
||||
|
||||
static downloadFilename(name, type) {
|
||||
const ext = `.${type}`;
|
||||
return name.toLowerCase().endsWith(ext) ? name : `${name}${ext}`;
|
||||
if (!name) return `dokumen${ext}`;
|
||||
return name.toLowerCase().endsWith(ext.toLowerCase()) ? name : `${name}${ext}`;
|
||||
}
|
||||
|
||||
static downloadFilenameFromItem(item) {
|
||||
const file = item?.file && typeof item.file === 'object' ? item.file : {};
|
||||
const originalFilename = file.filename_download || file.filename_disk;
|
||||
if (originalFilename) return originalFilename;
|
||||
|
||||
const fileType = this.fileInfoFromItem(item).type;
|
||||
return this.downloadFilename(item?.nama_berkas || 'dokumen', fileType);
|
||||
}
|
||||
|
||||
static escapeHtml(str) {
|
||||
@@ -50,6 +169,20 @@ export class DocumentFormatter {
|
||||
return this.escapeHtml(str);
|
||||
}
|
||||
|
||||
static formatTag(tag) {
|
||||
const value = String(tag).trim().replace(/\s+/g, ' ');
|
||||
if (!value) return value;
|
||||
|
||||
return value.split(' ').map(word => {
|
||||
const lower = word.toLowerCase();
|
||||
if (this.TAG_ABBREVIATIONS.has(lower) || /^[A-Z0-9]{2,}$/.test(word)) {
|
||||
return lower.toUpperCase();
|
||||
}
|
||||
|
||||
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
static parseTags(raw) {
|
||||
if (!raw) return [];
|
||||
const str = String(raw).trim();
|
||||
|
||||
Reference in New Issue
Block a user