UNPKG

@underpostnet/underpost

Version:
470 lines (443 loc) 16.1 kB
import { getCapVariableName, newInstance, random, range, uniqueArray } from './CommonJs.js'; import { marked } from 'marked'; import { getBlobFromUint8ArrayFile, getDataFromInputFile, getQueryParams, getRawContentFile, htmls, } from './VanillaJs.js'; import { Panel } from './Panel.js'; import { NotificationManager } from './NotificationManager.js'; import { DocumentService } from '../../services/document/document.service.js'; import { FileService } from '../../services/file/file.service.js'; import { getSrcFromFileData } from './Input.js'; import { imageShimmer, renderCssAttr } from './Css.js'; import { Translate } from './Translate.js'; import { Modal } from './Modal.js'; import { listenQueryPathInstance, setQueryPath } from './Router.js'; const PanelForm = { Data: {}, instance: async function ( options = { idPanel: '', heightTopBar: 50, heightBottomBar: 50, defaultUrlImage: '', Elements: {}, parentIdModal: undefined, route: 'home', htmlFormHeader: async () => '', firsUpdateEvent: async () => {}, }, ) { const { idPanel, heightTopBar, heightBottomBar, defaultUrlImage, Elements } = options; let prefixTags = [idPanel, 'public']; this.Data[idPanel] = { originData: [], data: [], filesData: [], }; const formData = [ { id: 'panel-title', model: 'title', inputType: 'text', rules: [{ type: 'isEmpty' }], panel: { type: 'title' }, }, { id: 'panel-createdAt', model: 'createdAt', inputType: 'datetime-local', panel: { type: 'subtitle' }, rules: [{ type: 'isEmpty' }], disableRender: true, }, { id: 'panel-fileId', model: 'fileId', inputType: 'file', rules: [], panel: {}, }, { id: 'panel-tags', model: 'tags', label: { disabled: true, }, inputType: 'text', panel: { type: 'tags' }, // panel: { // type: 'info-row-pin', // icon: { // value: html``, // }, // }, rules: [{ type: 'isEmpty' }], }, { id: 'panel-mdFileId', model: 'mdFileId', inputType: 'md', panel: { type: 'info-row' }, rules: [], label: { disabled: true, }, }, ]; const titleIcon = html`<i class="fa-solid fa-quote-left"></i>`; const panelRender = async ({ data }) => await Panel.Render({ idPanel, formData, heightTopBar, heightBottomBar, data, htmlFormHeader: options.htmlFormHeader, parentIdModal: options.parentIdModal, originData: () => PanelForm.Data[idPanel].originData, filesData: () => PanelForm.Data[idPanel].filesData, scrollClassContainer: options.scrollClassContainer ? options.scrollClassContainer : 'main-body', titleIcon, route: options.route, formContainerClass: 'session-in-log-in', onClick: async function ({ payload }) { if (options.route) { setQueryPath({ path: options.route, queryPath: payload._id }); if (options.parentIdModal) Modal.Data[options.parentIdModal].query = `${window.location.search}`; if (PanelForm.Data[idPanel].updatePanel) await PanelForm.Data[idPanel].updatePanel(); } }, callBackPanelRender: async function (options) { if (options.data.ssr) { return await options.htmlRender({ render: imageShimmer(), }); } if (!options.data.fileId) return await options.htmlRender({ render: html` <img class="abs center" style="${renderCssAttr({ style: { width: '100px', height: '100px', opacity: 0.2, }, })}" src="${defaultUrlImage}" /> `, }); return await options.fileRender({ file: PanelForm.Data[idPanel].filesData.find((f) => f._id === options.data._id).fileId.fileBlob, style: { overflow: 'auto', width: '100%', height: 'auto', }, }); }, on: { remove: async function ({ e, data }) { e.preventDefault(); const confirmResult = await Modal.RenderConfirm({ html: async () => { return html` <div class="in section-mp" style="text-align: center"> ${Translate.Render('confirm-delete-item')} <br /> "${data.title}" </div> `; }, id: `delete-${idPanel}`, }); if (confirmResult.status === 'confirm') { const { status, message } = await DocumentService.delete({ id: data._id, }); NotificationManager.Push({ html: status, status, }); if (getQueryParams().cid === data.id) { setQueryPath({ path: options.route, queryPath: '' }); if (PanelForm.Data[idPanel].updatePanel) await PanelForm.Data[idPanel].updatePanel(); } return { status }; } return { status: 'error' }; }, add: async function ({ data, editId }) { let mdFileId; const mdFileName = `${getCapVariableName(data.title)}.md`; const location = `${prefixTags.join('/')}`; const blob = new Blob([data.mdFileId], { type: 'text/markdown' }); const md = new File([blob], mdFileName, { type: 'text/markdown' }); const tags = uniqueArray( data.tags .replaceAll('/', ',') .replaceAll('-', ',') .replaceAll(' ', ',') .split(',') .map((t) => t.trim()) .filter((t) => t) .concat(prefixTags), ); let originObj, originFileObj, indexOriginObj; if (editId) { indexOriginObj = PanelForm.Data[idPanel].originData.findIndex((d) => d._id === editId); if (indexOriginObj > -1) { originObj = PanelForm.Data[idPanel].originData[indexOriginObj]; originFileObj = PanelForm.Data[idPanel].filesData.find((d) => d._id === editId); } } const mdBlob = { data: { data: await getDataFromInputFile(md), }, mimetype: md.type, name: md.name, }; const mdPlain = await getRawContentFile(getBlobFromUint8ArrayFile(mdBlob.data.data, mdBlob.mimetype)); const baseNewDoc = newInstance(data); baseNewDoc.tags = tags.filter((t) => !prefixTags.includes(t)); baseNewDoc.mdFileId = marked.parse(data.mdFileId); baseNewDoc.userId = Elements.Data.user.main.model.user._id; baseNewDoc.tools = true; const documents = []; let message = ''; let status = 'success'; let indexFormDoc = -1; const filesData = data.fileId ? data.fileId : [null]; for (const file of filesData) { indexFormDoc++; let fileId; await (async () => { const body = new FormData(); body.append('md', md); if (file) body.append('file', file); const { status, data } = await FileService.post({ body }); // await timer(3000); NotificationManager.Push({ html: Translate.Render(`${status}-upload-file`), status, }); if (status === 'success') { mdFileId = data[0]._id; if (data[1]) fileId = data[1]._id; } })(); const body = { location, tags, fileId, mdFileId, title: data.title, }; const { status: documentStatus, message: documentMessage, data: documentData, } = originObj && indexFormDoc === 0 ? await DocumentService.put({ id: originObj._id, body }) : await DocumentService.post({ body, }); const newDoc = { ...baseNewDoc, fileId: file ? URL.createObjectURL(file) : undefined, _id: documentData._id, id: documentData._id, createdAt: documentData.createdAt, }; if (documentStatus === 'error') status = 'error'; if (message) message += `${indexFormDoc === 0 ? '' : ', '}${documentMessage}`; const filesData = { id: documentData._id, _id: documentData._id, mdFileId: { mdBlob, mdPlain }, fileId: { fileBlob: file ? { data: { data: await getDataFromInputFile(file), }, mimetype: file.type, name: file.name, } : undefined, filePlain: undefined, }, }; if (originObj && indexFormDoc === 0) { PanelForm.Data[idPanel].originData[indexOriginObj] = documentData; PanelForm.Data[idPanel].data[indexOriginObj] = newDoc; PanelForm.Data[idPanel].filesData[indexOriginObj] = filesData; } else { PanelForm.Data[idPanel].originData.push(documentData); PanelForm.Data[idPanel].data.push(newDoc); PanelForm.Data[idPanel].filesData.push(filesData); } documents.push(newDoc); } NotificationManager.Push({ html: status === 'success' ? originObj ? Translate.Render('success-edit-post') : Translate.Render('success-add-post') : message, status: status, }); setQueryPath({ path: options.route, queryPath: documents.map((d) => d._id).join(',') }); if (options.parentIdModal) Modal.Data[options.parentIdModal].query = `${window.location.search}`; return { data: documents, status, message }; }, }, }); const getPanelData = async () => { const result = await DocumentService.get({ id: `public/?tags=${prefixTags.join(',')}${getQueryParams().cid ? `&cid=${getQueryParams().cid}` : ''}`, }); NotificationManager.Push({ html: result.status === 'success' ? Translate.Render('success-get-posts') : result.message, status: result.status, }); if (result.status === 'success') { PanelForm.Data[idPanel].originData = newInstance(result.data); PanelForm.Data[idPanel].filesData = []; PanelForm.Data[idPanel].data = []; for (const documentObject of result.data) { let mdFileId, fileId; let mdBlob, fileBlob; let mdPlain, filePlain; { const { data: [file], status, } = await FileService.get({ id: documentObject.mdFileId }); // const ext = file.name.split('.')[file.name.split('.').length - 1]; mdBlob = file; mdPlain = await getRawContentFile(getBlobFromUint8ArrayFile(file.data.data, file.mimetype)); mdFileId = newInstance(mdPlain); } if (documentObject.fileId) { const { data: [file], status, } = await FileService.get({ id: documentObject.fileId._id }); // const ext = file.name.split('.')[file.name.split('.').length - 1]; fileBlob = file; filePlain = undefined; fileId = getSrcFromFileData(file); } PanelForm.Data[idPanel].filesData.push({ id: documentObject._id, _id: documentObject._id, mdFileId: { mdBlob, mdPlain }, fileId: { fileBlob, filePlain }, }); PanelForm.Data[idPanel].data.push({ id: documentObject._id, title: documentObject.title, createdAt: documentObject.createdAt, tags: documentObject.tags.filter((t) => !prefixTags.includes(t)), mdFileId: marked.parse(mdFileId), userId: documentObject.userId._id, fileId, tools: Elements.Data.user.main.model.user._id === documentObject.userId._id, _id: documentObject._id, }); } } }; const renderSrrPanelData = async () => await panelRender({ data: range(0, 0).map((i) => ({ id: i, title: html`<div class="fl"> <div class="in fll ssr-shimmer-search-box" style="${renderCssAttr({ style: { width: '80%', height: '30px', top: '-13px', left: '10px', }, })}" ></div> </div>`, createdAt: html`<div class="fl"> <div class="in fll ssr-shimmer-search-box" style="${renderCssAttr({ style: { width: '50%', height: '30px', left: '-5px', }, })}" ></div> </div>`, mdFileId: html`<div class="fl section-mp"> <div class="in fll ssr-shimmer-search-box" style="${renderCssAttr({ style: { width: '80%', height: '30px', }, })}" ></div> </div>`.repeat(random(2, 4)), ssr: true, })), }); let firsUpdateEvent = false; let lastCid; this.Data[idPanel].updatePanel = async () => { const cid = getQueryParams().cid ? getQueryParams().cid : ''; if (lastCid === cid) return; lastCid = cid; if (options.route === 'home') Modal.homeCid = newInstance(cid); htmls(`.${options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body'}`, await renderSrrPanelData()); await getPanelData(); htmls( `.${options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body'}`, await panelRender({ data: this.Data[idPanel].data }), ); if (!firsUpdateEvent && options.firsUpdateEvent) { firsUpdateEvent = true; await options.firsUpdateEvent(); } }; if (options.route) { listenQueryPathInstance({ id: options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body', routeId: options.route, event: async (path) => { await this.Data[idPanel].updatePanel(); }, }); if (!options.parentIdModal) Modal.Data['modal-menu'].onHome[idPanel] = async () => { lastCid = undefined; setQueryPath({ path: options.route, queryPath: '' }); await this.Data[idPanel].updatePanel(); }; } if (options.parentIdModal) { htmls(`.html-${options.parentIdModal}`, await renderSrrPanelData()); return ''; } return await renderSrrPanelData(); }, }; export { PanelForm };