| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- const { form, button, div, h2, p, section, input, label, br, a, img, span, textarea } = require("../server/node_modules/hyperaxe");
- const moment = require("../server/node_modules/moment");
- const { template, i18n } = require('./main_views');
- const { config } = require('../server/SSB_server.js');
- const { renderUrl } = require('../backend/renderUrl');
- const userId = config.keys.id;
- const getFilteredImages = (filter, images, userId) => {
- const now = Date.now();
- let filtered =
- filter === 'mine' ? images.filter(img => img.author === userId) :
- filter === 'recent' ? images.filter(img => new Date(img.createdAt).getTime() >= now - 86400000) :
- filter === 'meme' ? images.filter(img => img.meme) :
- filter === 'top' ? [...images].sort((a, b) => {
- const sum = o => Object.values(o || {}).reduce((s, n) => s + n, 0);
- return sum(b.opinions) - sum(a.opinions);
- }) :
- images;
- return filtered.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
- };
- const renderImageActions = (filter, imgObj) => {
- return filter === 'mine' ? div({ class: "image-actions" },
- form({ method: "GET", action: `/images/edit/${encodeURIComponent(imgObj.key)}` },
- button({ class: "update-btn", type: "submit" }, i18n.imageUpdateButton)
- ),
- form({ method: "POST", action: `/images/delete/${encodeURIComponent(imgObj.key)}` },
- button({ class: "delete-btn", type: "submit" }, i18n.imageDeleteButton)
- )
- ) : null;
- };
- const renderImageList = (filteredImages, filter) => {
- return filteredImages.length > 0
- ? filteredImages.map(imgObj => {
- const commentCount = typeof imgObj.commentCount === 'number' ? imgObj.commentCount : 0;
- return div({ class: "tags-header" },
- renderImageActions(filter, imgObj),
- form({ method: "GET", action: `/images/${encodeURIComponent(imgObj.key)}` },
- button({ type: "submit", class: "filter-btn" }, i18n.viewDetails)
- ),
- imgObj.title ? h2(imgObj.title) : null,
- a({ href: `#img-${encodeURIComponent(imgObj.key)}` },
- img({ src: `/blob/${encodeURIComponent(imgObj.url)}` })
- ),
- imgObj.description ? p(...renderUrl(imgObj.description)) : null,
- imgObj.tags?.length
- ? div({ class: "card-tags" },
- imgObj.tags.map(tag =>
- a({
- href: `/search?query=%23${encodeURIComponent(tag)}`,
- class: "tag-link",
- style: "margin-right: 0.8em; margin-bottom: 0.5em;"
- },
- `#${tag}`
- )
- )
- )
- : null,
- div({ class: 'card-comments-summary' },
- span({ class: 'card-label' }, i18n.voteCommentsLabel + ':'),
- span({ class: 'card-value' }, String(commentCount)),
- br, br,
- form({ method: 'GET', action: `/images/${encodeURIComponent(imgObj.key)}` },
- button({ type: 'submit', class: 'filter-btn' }, i18n.voteCommentsForumButton)
- )
- ),
- br,
- p({ class: 'card-footer' },
- span(
- { class: 'date-link' },
- `${moment(imgObj.createdAt).format('YYYY/MM/DD HH:mm:ss')} ${i18n.performed} `
- ),
- a(
- { href: `/author/${encodeURIComponent(imgObj.author)}`, class: 'user-link' },
- `${imgObj.author}`
- )
- ),
- div({ class: "voting-buttons" },
- ['interesting', 'necessary', 'funny', 'disgusting', 'sensible', 'propaganda', 'adultOnly', 'boring', 'confusing', 'inspiring', 'spam']
- .map(category =>
- form({ method: "POST", action: `/images/opinions/${encodeURIComponent(imgObj.key)}/${category}` },
- button(
- { class: "vote-btn" },
- `${i18n[`vote${category.charAt(0).toUpperCase() + category.slice(1)}`]} [${imgObj.opinions?.[category] || 0}]`
- )
- )
- )
- )
- );
- })
- : div(i18n.noImages);
- };
- const renderImageForm = (filter, imageId, imageToEdit) => {
- return div({ class: "div-center image-form" },
- form({
- action: filter === 'edit'
- ? `/images/update/${encodeURIComponent(imageId)}`
- : "/images/create",
- method: "POST", enctype: "multipart/form-data"
- },
- label(i18n.imageFileLabel), br(),
- input({ type: "file", name: "image", required: filter !== "edit" }), br(), br(),
- imageToEdit?.url ? img({ src: `/blob/${encodeURIComponent(imageToEdit.url)}`, class: "image-detail" }) : null,
- br(),
- label(i18n.imageTagsLabel), br(),
- input({ type: "text", name: "tags", placeholder: i18n.imageTagsPlaceholder, value: imageToEdit?.tags?.join(',') || '' }), br(), br(),
- label(i18n.imageTitleLabel), br(),
- input({ type: "text", name: "title", placeholder: i18n.imageTitlePlaceholder, value: imageToEdit?.title || '' }), br(), br(),
- label(i18n.imageDescriptionLabel), br(),
- textarea({ name: "description", placeholder: i18n.imageDescriptionPlaceholder, rows:"4", value: imageToEdit?.description || '' }), br(), br(),
- label(i18n.imageMemeLabel),
- input({ type: "checkbox", name: "meme", ...(imageToEdit?.meme ? { checked: true } : {}) }), br(), br(),
- button({ type: "submit" }, filter === 'edit' ? i18n.imageUpdateButton : i18n.imageCreateButton)
- )
- );
- };
- const renderGallery = (sortedImages) => {
- return div({ class: "gallery" },
- sortedImages.length
- ? sortedImages.map(imgObj =>
- a({ href: `#img-${encodeURIComponent(imgObj.key)}`, class: "gallery-item" },
- img({ src: `/blob/${encodeURIComponent(imgObj.url)}`, alt: imgObj.title || "", class: "gallery-image" })
- )
- )
- : div(i18n.noImages)
- );
- };
- const renderLightbox = (sortedImages) => {
- return sortedImages.map(imgObj =>
- div(
- { id: `img-${encodeURIComponent(imgObj.key)}`, class: "lightbox" },
- a({ href: "#", class: "lightbox-close" }, "×"),
- img({ src: `/blob/${encodeURIComponent(imgObj.url)}`, class: "lightbox-image", alt: imgObj.title || "" })
- )
- );
- };
- const renderImageCommentsSection = (imageId, comments = []) => {
- const commentsCount = Array.isArray(comments) ? comments.length : 0;
- return div({ class: 'vote-comments-section' },
- div({ class: 'comments-count' },
- span({ class: 'card-label' }, i18n.voteCommentsLabel + ': '),
- span({ class: 'card-value' }, String(commentsCount))
- ),
- div({ class: 'comment-form-wrapper' },
- h2({ class: 'comment-form-title' }, i18n.voteNewCommentLabel),
- form({
- method: 'POST',
- action: `/images/${encodeURIComponent(imageId)}/comments`,
- class: 'comment-form'
- },
- textarea({
- id: 'comment-text',
- name: 'text',
- required: true,
- rows: 4,
- class: 'comment-textarea',
- placeholder: i18n.voteNewCommentPlaceholder
- }),
- br(),
- button({ type: 'submit', class: 'comment-submit-btn' }, i18n.voteNewCommentButton)
- )
- ),
- comments && comments.length
- ? div({ class: 'comments-list' },
- comments.map(c => {
- const author = c.value && c.value.author ? c.value.author : '';
- const ts = c.value && c.value.timestamp ? c.value.timestamp : c.timestamp;
- const absDate = ts ? moment(ts).format('YYYY/MM/DD HH:mm:ss') : '';
- const relDate = ts ? moment(ts).fromNow() : '';
- const userName = author && author.includes('@') ? author.split('@')[1] : author;
- return div({ class: 'votations-comment-card' },
- span({ class: 'created-at' },
- span(i18n.createdBy),
- author
- ? a(
- { href: `/author/${encodeURIComponent(author)}` },
- `@${userName}`
- )
- : span('(unknown)'),
- absDate ? span(' | ') : '',
- absDate ? span({ class: 'votations-comment-date' }, absDate) : '',
- relDate ? span({ class: 'votations-comment-date' }, ' | ', i18n.sendTime) : '',
- relDate
- ? a(
- {
- href: `/thread/${encodeURIComponent(c.value.content.fork || c.value.content.root)}#${encodeURIComponent(c.key)}`
- },
- relDate
- )
- : ''
- ),
- p({
- class: 'votations-comment-text',
- innerHTML: (c.value && c.value.content && c.value.content.text) || ''
- })
- );
- })
- )
- : p({ class: 'votations-no-comments' }, i18n.voteNoCommentsYet)
- );
- };
- exports.imageView = async (images, filter, imageId) => {
- const title = filter === 'mine' ? i18n.imageMineSectionTitle :
- filter === 'create' ? i18n.imageCreateSectionTitle :
- filter === 'edit' ? i18n.imageUpdateSectionTitle :
- filter === 'gallery' ? i18n.imageGallerySectionTitle :
- filter === 'meme' ? i18n.imageMemeSectionTitle :
- filter === 'recent' ? i18n.imageRecentSectionTitle :
- filter === 'top' ? i18n.imageTopSectionTitle :
- i18n.imageAllSectionTitle;
- const filteredImages = getFilteredImages(filter, images, userId);
- const imageToEdit = images.find(img => img.key === imageId);
- return template(
- title,
- section(
- div({ class: "tags-header" },
- h2(i18n.imageCreateSectionTitle),
- p(i18n.imageDescription)
- ),
- div({ class: "filters" },
- form({ method: "GET", action: "/images" },
- ["all", "mine", "recent", "top", "gallery", "meme"].map(f =>
- button({
- type: "submit", name: "filter", value: f,
- class: filter === f ? "filter-btn active" : "filter-btn"
- },
- i18n[`imageFilter${f.charAt(0).toUpperCase() + f.slice(1)}`]
- )
- ),
- button({ type: "submit", name: "filter", value: "create", class: "create-button" },
- i18n.imageCreateButton)
- )
- )
- ),
- section(
- (filter === 'create' || filter === 'edit')
- ? renderImageForm(filter, imageId, imageToEdit)
- : filter === 'gallery'
- ? renderGallery(filteredImages)
- : renderImageList(filteredImages, filter)
- ),
- ...renderLightbox(filteredImages)
- );
- };
- exports.singleImageView = async (image, filter, comments = []) => {
- const isAuthor = image.author === userId;
- const hasOpinions = Object.keys(image.opinions || {}).length > 0;
- return template(
- i18n.imageTitle,
- section(
- div({ class: "filters" },
- form({ method: "GET", action: "/images" },
- button({ type: "submit", name: "filter", value: "all", class: filter === 'all' ? 'filter-btn active' : 'filter-btn' }, i18n.imageFilterAll),
- button({ type: "submit", name: "filter", value: "mine", class: filter === 'mine' ? 'filter-btn active' : 'filter-btn' }, i18n.imageFilterMine),
- button({ type: "submit", name: "filter", value: "meme", class: filter === 'meme' ? 'filter-btn active' : 'filter-btn' }, i18n.imageFilterMeme),
- button({ type: "submit", name: "filter", value: "top", class: filter === 'top' ? 'filter-btn active' : 'filter-btn' }, i18n.imageFilterTop),
- button({ type: "submit", name: "filter", value: "recent", class: filter === 'recent' ? 'filter-btn active' : 'filter-btn' }, i18n.imageFilterRecent),
- button({ type: "submit", name: "filter", value: "create", class: "create-button" }, i18n.imageCreateButton)
- )
- ),
- div({ class: "tags-header" },
- isAuthor ? div({ class: "image-actions" },
- !hasOpinions
- ? form({ method: "GET", action: `/images/edit/${encodeURIComponent(image.key)}` },
- button({ class: "update-btn", type: "submit" }, i18n.imageUpdateButton)
- )
- : null,
- form({ method: "POST", action: `/images/delete/${encodeURIComponent(image.key)}` },
- button({ class: "delete-btn", type: "submit" }, i18n.imageDeleteButton)
- )
- ) : null,
- h2(image.title),
- image.url ? img({ src: `/blob/${encodeURIComponent(image.url)}` }) : null,
- p(...renderUrl(image.description)),
- image.tags?.length
- ? div({ class: "card-tags" },
- image.tags.map(tag =>
- a({
- href: `/search?query=%23${encodeURIComponent(tag)}`,
- class: "tag-link",
- style: "margin-right: 0.8em; margin-bottom: 0.5em;"
- },
- `#${tag}`
- )
- )
- )
- : null,
- br,
- p({ class: 'card-footer' },
- span(
- { class: 'date-link' },
- `${moment(image.createdAt).format('YYYY/MM/DD HH:mm:ss')} ${i18n.performed} `
- ),
- a(
- { href: `/author/${encodeURIComponent(image.author)}`, class: 'user-link' },
- `${image.author}`
- )
- )
- ),
- div({ class: "voting-buttons" },
- ['interesting', 'necessary', 'funny', 'disgusting', 'sensible', 'propaganda', 'adultOnly', 'boring', 'confusing', 'inspiring', 'spam']
- .map(category =>
- form({ method: "POST", action: `/images/opinions/${encodeURIComponent(image.key)}/${category}` },
- button(
- { class: "vote-btn" },
- `${i18n[`vote${category.charAt(0).toUpperCase() + category.slice(1)}`]} [${image.opinions?.[category] || 0}]`
- )
- )
- )
- ),
- renderImageCommentsSection(image.key, comments)
- )
- );
- };
|