Popover displaying clickable usernames in voting value
This commit is contained in:
parent
75e0ec90dd
commit
37b8d96a78
7 changed files with 227 additions and 172 deletions
|
@ -1,7 +1,8 @@
|
|||
{%- for vote in votes -%}
|
||||
{% from 'macros/forum-username.html' import forum_username with context -%}
|
||||
{% for vote in votes -%}
|
||||
<div class="row">
|
||||
<div class="col-3 text-nowrap text-start">{{ loop.revindex|localize }}.</div>
|
||||
<div class="col-6 text-nowrap text-start">{{ vote.user.username }}</div>
|
||||
<div class="col-6 text-nowrap text-start">{{ forum_username(user=vote.user) }}</div>
|
||||
<div class="col-3 text-nowrap text-end {% if vote.value > 0 -%}
|
||||
text-success
|
||||
{%- elif vote.value < 0 -%}
|
||||
|
|
|
@ -14,7 +14,8 @@ class VotingValueDetailsView(TemplateView):
|
|||
obj = super().get_context_data()
|
||||
votes = CommentVote.objects.filter(comment=comment_pk).order_by('-pk')
|
||||
user_pks = set(x.user_id for x in votes)
|
||||
users = User.objects.only('username').in_bulk(id_list=user_pks)
|
||||
users = User.objects.only(
|
||||
*User.F_USERNAME_DISPLAYED).in_bulk(id_list=user_pks)
|
||||
for vote in votes:
|
||||
vote.user = users[vote.user_id]
|
||||
obj.update(votes=votes)
|
||||
|
|
|
@ -88,10 +88,60 @@ export interface TopicBoundFunctionsType {
|
|||
getALink: (scrollToPk: number) => string
|
||||
}
|
||||
|
||||
export let urlTemplates: TopicCommentListingUrltemplateType
|
||||
|
||||
function initializeUrls(options: TopicCommentListingOptionsType): void {
|
||||
const urls = options.urls
|
||||
urlTemplates = {
|
||||
commentListing: template(
|
||||
urls.commentListing.backend
|
||||
.replace(urls.commentListing.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.commentListing.commentPk, '{commentPk}')
|
||||
),
|
||||
expandCommentsDown: template(
|
||||
urls.expandCommentsDown.backend
|
||||
.replace(urls.expandCommentsDown.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsDown.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsDown.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsUp: template(
|
||||
urls.expandCommentsUp.backend
|
||||
.replace(urls.expandCommentsUp.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsUp.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsUp.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsUpRecursive: template(
|
||||
urls.expandCommentsUpRecursive.backend
|
||||
.replace(urls.expandCommentsUpRecursive.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsUpRecursive.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsUpRecursive.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsEntireThread: template(
|
||||
urls.expandCommentsEntireThread.backend
|
||||
.replace(urls.expandCommentsEntireThread.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsEntireThread.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsEntireThread.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
getTopicSlugByPk: template(
|
||||
urls.getTopicSlugByPk.backend
|
||||
.replace(urls.getTopicSlugByPk.commentPk, '{commentPk}')
|
||||
),
|
||||
getVotingValueDetails: template(
|
||||
urls.getVotingValueDetails.backend
|
||||
.replace(urls.getVotingValueDetails.commentPk, '{commentPk}')
|
||||
)
|
||||
}
|
||||
if (urls.commentListingPageNo) {
|
||||
urlTemplates.commentListingPageNo = template(
|
||||
urls.commentListingPageNo.backend
|
||||
.replace(urls.commentListingPageNo.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.commentListingPageNo.pageId, '{pageId}')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TopicCommentListing {
|
||||
private readonly options: TopicCommentListingOptionsType
|
||||
private urlTemplates!: TopicCommentListingUrltemplateType
|
||||
|
||||
private boundFunctions!: TopicBoundFunctionsType
|
||||
private root!: HTMLElement
|
||||
private readonly comments = new Map<number, OneComment>()
|
||||
|
@ -170,29 +220,29 @@ class TopicCommentListing {
|
|||
private getALink(scrollToPk: number): string {
|
||||
switch (this.options.listingMode) {
|
||||
case 'commentListing':
|
||||
return this.urlTemplates.commentListing({
|
||||
return urlTemplates.commentListing({
|
||||
topicSlug: this.options.topicSlugOriginal, commentPk: scrollToPk
|
||||
})
|
||||
case 'expandCommentsDown':
|
||||
return this.urlTemplates.expandCommentsDown({
|
||||
return urlTemplates.expandCommentsDown({
|
||||
topicSlug: this.options.topicSlugOriginal,
|
||||
commentPk: this.options.commentPk,
|
||||
scrollToPk
|
||||
})
|
||||
case 'expandCommentsUp':
|
||||
return this.urlTemplates.expandCommentsUp({
|
||||
return urlTemplates.expandCommentsUp({
|
||||
topicSlug: this.options.topicSlugOriginal,
|
||||
commentPk: this.options.commentPk,
|
||||
scrollToPk
|
||||
})
|
||||
case 'expandCommentsUpRecursive':
|
||||
return this.urlTemplates.expandCommentsUpRecursive({
|
||||
return urlTemplates.expandCommentsUpRecursive({
|
||||
topicSlug: this.options.topicSlugOriginal,
|
||||
commentPk: this.options.commentPk,
|
||||
scrollToPk
|
||||
})
|
||||
case 'expandCommentsEntireThread':
|
||||
return this.urlTemplates.expandCommentsEntireThread({
|
||||
return urlTemplates.expandCommentsEntireThread({
|
||||
topicSlug: this.options.topicSlugOriginal,
|
||||
commentPk: this.options.commentPk,
|
||||
scrollToPk
|
||||
|
@ -206,64 +256,13 @@ class TopicCommentListing {
|
|||
history.replaceState(null, '', path)
|
||||
}
|
||||
|
||||
private initializeUrls(): void {
|
||||
const urls = this.options.urls
|
||||
this.urlTemplates = {
|
||||
commentListing: template(
|
||||
urls.commentListing.backend
|
||||
.replace(urls.commentListing.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.commentListing.commentPk, '{commentPk}')
|
||||
),
|
||||
expandCommentsDown: template(
|
||||
urls.expandCommentsDown.backend
|
||||
.replace(urls.expandCommentsDown.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsDown.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsDown.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsUp: template(
|
||||
urls.expandCommentsUp.backend
|
||||
.replace(urls.expandCommentsUp.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsUp.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsUp.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsUpRecursive: template(
|
||||
urls.expandCommentsUpRecursive.backend
|
||||
.replace(urls.expandCommentsUpRecursive.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsUpRecursive.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsUpRecursive.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
expandCommentsEntireThread: template(
|
||||
urls.expandCommentsEntireThread.backend
|
||||
.replace(urls.expandCommentsEntireThread.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.expandCommentsEntireThread.commentPk, '{commentPk}')
|
||||
.replace(urls.expandCommentsEntireThread.scrollToPk, '{scrollToPk}')
|
||||
),
|
||||
getTopicSlugByPk: template(
|
||||
urls.getTopicSlugByPk.backend
|
||||
.replace(urls.getTopicSlugByPk.commentPk, '{commentPk}')
|
||||
),
|
||||
getVotingValueDetails: template(
|
||||
urls.getVotingValueDetails.backend
|
||||
.replace(urls.getVotingValueDetails.commentPk, '{commentPk}')
|
||||
)
|
||||
}
|
||||
if (urls.commentListingPageNo) {
|
||||
this.urlTemplates.commentListingPageNo = template(
|
||||
urls.commentListingPageNo.backend
|
||||
.replace(urls.commentListingPageNo.exampleSlug, '{topicSlug}')
|
||||
.replace(urls.commentListingPageNo.pageId, '{pageId}')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private initializeOneComment(rootEl: HTMLElement): void {
|
||||
const commentPk = parseInt(<string>rootEl.dataset.forumCommentPk)
|
||||
this.comments.set(commentPk, new OneComment({
|
||||
root: rootEl,
|
||||
commentPk,
|
||||
boundFunctions: this.boundFunctions,
|
||||
strings: this.options.strings,
|
||||
urlTemplates: this.urlTemplates
|
||||
strings: this.options.strings
|
||||
}))
|
||||
addOnremoveCallback(rootEl, this.teardownOneComment.bind(this))
|
||||
}
|
||||
|
@ -298,11 +297,11 @@ class TopicCommentListing {
|
|||
}
|
||||
|
||||
private async onPaginate(pageNo: number): Promise<void> {
|
||||
if (!this.urlTemplates.commentListingPageNo) {
|
||||
console.error('this.urlTemplates.commentListingPageNo is unset')
|
||||
if (!urlTemplates.commentListingPageNo) {
|
||||
console.error('urlTemplates.commentListingPageNo is unset')
|
||||
return
|
||||
}
|
||||
document.location.href = this.urlTemplates.commentListingPageNo({
|
||||
document.location.href = urlTemplates.commentListingPageNo({
|
||||
topicSlug: this.options.topicSlugOriginal,
|
||||
pageId: pageNo
|
||||
})
|
||||
|
@ -347,7 +346,6 @@ class TopicCommentListing {
|
|||
}
|
||||
|
||||
initialize(): void {
|
||||
this.initializeUrls()
|
||||
this.initializeBoundFunctions()
|
||||
this.initializeWrappers()
|
||||
this.initializePaginators()
|
||||
|
@ -358,6 +356,7 @@ class TopicCommentListing {
|
|||
|
||||
export function init(options: TopicCommentListingOptionsType): void {
|
||||
oneCommentInit()
|
||||
initializeUrls(options)
|
||||
const obj = new TopicCommentListing(options)
|
||||
obj.initialize()
|
||||
}
|
||||
|
|
|
@ -1,86 +1,129 @@
|
|||
import { getSvgIcon, loaderTemplate } from './common'
|
||||
import {
|
||||
type TopicCommentListingUrltemplateType
|
||||
} from '../topic-comment-listing'
|
||||
import { loaderTemplate } from './common'
|
||||
import {
|
||||
add as popoverAdd, getFunctions, type GetFunctionsReturnType
|
||||
} from './popover.ts'
|
||||
import { add as newPopoverAdd } from './new-popover.ts'
|
||||
type ForumPopoverEl,
|
||||
type ForumPopoverTipEl,
|
||||
add as newPopoverAdd,
|
||||
teardown as newPopoverTeardown
|
||||
} from './new-popover.ts'
|
||||
import { urlTemplates } from '../topic-comment-listing'
|
||||
import { mdiLinkOff } from '@mdi/js'
|
||||
import { add as usernameAdd } from './username.ts'
|
||||
|
||||
export class VotingValue {
|
||||
private readonly rootEl: HTMLAnchorElement
|
||||
private readonly commentPk: number
|
||||
private readonly urlTemplates: TopicCommentListingUrltemplateType
|
||||
private cachedContent?: string | Element
|
||||
private popoverFunctions!: GetFunctionsReturnType
|
||||
const errorIcon = getSvgIcon(mdiLinkOff)
|
||||
|
||||
constructor (
|
||||
rootEl: HTMLAnchorElement, commentPk: number,
|
||||
urlTemplates: TopicCommentListingUrltemplateType
|
||||
) {
|
||||
this.rootEl = rootEl
|
||||
this.commentPk = commentPk
|
||||
this.urlTemplates = urlTemplates
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
// this.rootEl.setAttribute('title', loaderTemplate.outerHTML)
|
||||
this.rootEl.addEventListener('click', ev => {
|
||||
ev.preventDefault()
|
||||
})
|
||||
newPopoverAdd(this.rootEl, {
|
||||
callbacks: {
|
||||
onTipInserted: (el): void => {
|
||||
console.debug('onTipInserted', this, arguments)
|
||||
},
|
||||
onTipRemoved: (el): void => {
|
||||
console.debug('onTipRemoved', el.forumPopoverTip)
|
||||
}
|
||||
},
|
||||
popoverOpts: {
|
||||
content: (el): string | Element => {
|
||||
console.debug('XXX', el)
|
||||
if (this.cachedContent == null) {
|
||||
this.cachedContent = <SVGElement>loaderTemplate.cloneNode(true)
|
||||
setTimeout(() => {
|
||||
this.cachedContent = 'asd'
|
||||
if (el.forumPopoverTip) {
|
||||
el.forumPopoverTip
|
||||
.getElementsByClassName('popover-body').item(0)
|
||||
?.replaceChildren(this.cachedContent)
|
||||
el.forumPopoverConfig.popoverObj.update()
|
||||
} else console.debug('NO TIP')
|
||||
}, 3000)
|
||||
}
|
||||
return this.cachedContent
|
||||
},
|
||||
html: true,
|
||||
sanitize: false,
|
||||
container: <HTMLElement>this.rootEl.parentElement,
|
||||
title: 'cucc'
|
||||
}
|
||||
})
|
||||
// popoverAdd(this.rootEl, {
|
||||
// callbacks: {
|
||||
// getContent: this.getContent.bind(this),
|
||||
// // getTitle: this.getTitle.bind(this),
|
||||
// onDomInsertedTip: this.onDomInsertedTip.bind(this),
|
||||
// onDomRemovedTip: this.onDomRemovedTip.bind(this)
|
||||
// },
|
||||
// html: true,
|
||||
// delay: {
|
||||
// show: 250,
|
||||
// hide: 0
|
||||
// },
|
||||
// showOnClick: true,
|
||||
// sanitize: false,
|
||||
// initialContent: loaderTemplate.outerHTML
|
||||
// })
|
||||
// this.popoverFunctions = getFunctions(this.rootEl)
|
||||
// newPopoverAdd(this.rootEl, {
|
||||
// onTipInserted: (x) => {}
|
||||
// })
|
||||
}
|
||||
|
||||
teardown(): void { }
|
||||
interface StoredObjType {
|
||||
commentPk: number
|
||||
cachedContent?: string | Element
|
||||
}
|
||||
|
||||
const storedObjs = new Map<HTMLAnchorElement, StoredObjType>()
|
||||
|
||||
function onClickElement(e: MouseEvent | PointerEvent): void {
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
function onClickUsernameInTip(ev: MouseEvent | PointerEvent): void {
|
||||
if (!(ev.target instanceof HTMLAnchorElement)) return
|
||||
const elWrapper: ForumPopoverTipEl<HTMLDivElement> | null =
|
||||
ev.target.closest('.voting-value-popover-wrapper')
|
||||
if (!(elWrapper instanceof HTMLDivElement)) return
|
||||
elWrapper.forumPopoverEl.forumPopoverConfig.popoverObj.hide()
|
||||
}
|
||||
|
||||
function onTipInserted(el: ForumPopoverEl<HTMLAnchorElement>): void {
|
||||
const elTipBody = el.forumPopoverTip
|
||||
?.getElementsByClassName('popover-body').item(0)
|
||||
if (!elTipBody) return
|
||||
elTipBody.querySelectorAll<HTMLAnchorElement>(
|
||||
'a.forum-username'
|
||||
).forEach((el) => {
|
||||
usernameAdd(el)
|
||||
el.addEventListener(
|
||||
'click', onClickUsernameInTip, { once: true, passive: true })
|
||||
})
|
||||
}
|
||||
|
||||
function onTipRemoved(el: ForumPopoverEl<HTMLAnchorElement>): void {
|
||||
const elTipBody = el.forumPopoverTip
|
||||
?.getElementsByClassName('popover-body').item(0)
|
||||
if (!elTipBody) return
|
||||
elTipBody.querySelectorAll<HTMLAnchorElement>(
|
||||
'a.forum-username'
|
||||
).forEach((el) => {
|
||||
el.removeEventListener('click', onClickUsernameInTip)
|
||||
})
|
||||
}
|
||||
|
||||
function displayError(el: ForumPopoverEl<HTMLAnchorElement>): void {
|
||||
if (!el.forumPopoverTip) return
|
||||
el.forumPopoverTip
|
||||
.getElementsByClassName('popover-body').item(0)
|
||||
?.replaceChildren(errorIcon.cloneNode(true))
|
||||
el.forumPopoverConfig.popoverObj.update()
|
||||
}
|
||||
|
||||
async function loadVotingContent(
|
||||
el: ForumPopoverEl<HTMLAnchorElement>
|
||||
): Promise<void> {
|
||||
const config = storedObjs.get(el)
|
||||
if (!config) {
|
||||
displayError(el)
|
||||
return
|
||||
}
|
||||
const url = urlTemplates.getVotingValueDetails({
|
||||
commentPk: config.commentPk
|
||||
})
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
displayError(el)
|
||||
return
|
||||
}
|
||||
config.cachedContent = await response.text()
|
||||
const elTipBody = el.forumPopoverTip
|
||||
?.getElementsByClassName('popover-body').item(0)
|
||||
if (elTipBody instanceof HTMLElement) {
|
||||
elTipBody.innerHTML = config.cachedContent
|
||||
elTipBody.querySelectorAll<HTMLAnchorElement>(
|
||||
'a.forum-username'
|
||||
).forEach((el) => {
|
||||
usernameAdd(el)
|
||||
el.addEventListener(
|
||||
'click', onClickUsernameInTip, { once: true, passive: true })
|
||||
})
|
||||
el.forumPopoverConfig.popoverObj.update()
|
||||
}
|
||||
}
|
||||
|
||||
function getContent(el: ForumPopoverEl<HTMLAnchorElement>): string | Element {
|
||||
const storedObj = storedObjs.get(el)
|
||||
if (!storedObj) return <SVGElement>errorIcon.cloneNode(true)
|
||||
if (storedObj.cachedContent == null) {
|
||||
storedObj.cachedContent = <SVGElement>loaderTemplate.cloneNode(true)
|
||||
void loadVotingContent(el).then()
|
||||
}
|
||||
return storedObj.cachedContent
|
||||
}
|
||||
|
||||
export function add(elRoot: HTMLAnchorElement, commentPk: number): void {
|
||||
if (storedObjs.has(elRoot)) {
|
||||
throw new Error(`VotingValue.add: ${elRoot.outerHTML} already initialized`)
|
||||
}
|
||||
storedObjs.set(elRoot, { commentPk })
|
||||
newPopoverAdd(elRoot, {
|
||||
callbacks: { onTipInserted, onTipRemoved },
|
||||
popoverOpts: {
|
||||
content: getContent,
|
||||
html: true,
|
||||
sanitize: false,
|
||||
// title: 'cucc',
|
||||
container: <HTMLElement>elRoot.parentElement,
|
||||
customClass: 'voting-value-popover-wrapper'
|
||||
}
|
||||
})
|
||||
elRoot.addEventListener('click', onClickElement)
|
||||
}
|
||||
|
||||
export function teardown(el: HTMLAnchorElement): void {
|
||||
el.removeEventListener('click', onClickElement)
|
||||
newPopoverTeardown(el)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Popover from 'bootstrap/js/src/popover.js'
|
||||
import { addOnremoveCallback } from './mutation-observer'
|
||||
|
||||
type ForumPopoverEl<ElCls extends HTMLElement> = ElCls & {
|
||||
export type ForumPopoverEl<ElCls extends HTMLElement> = ElCls & {
|
||||
forumPopoverConfig: StoredConfigType<ElCls>
|
||||
forumPopoverTip?: ForumPopoverTipEl<ElCls>
|
||||
}
|
||||
|
||||
type ForumPopoverTipEl<ElCls extends HTMLElement> = ElCls & {
|
||||
export type ForumPopoverTipEl<ElCls extends HTMLElement> = ElCls & {
|
||||
forumPopoverEl: ForumPopoverEl<ElCls>
|
||||
}
|
||||
|
||||
|
@ -97,16 +97,16 @@ function onTipInserted<ElCls extends HTMLElement>(
|
|||
this: ForumPopoverEl<ElCls>
|
||||
): void {
|
||||
const config = this.forumPopoverConfig
|
||||
if (config.callbacks?.onTipInserted) config.callbacks.onTipInserted(this)
|
||||
// @ts-expect-error `tip` exists, it's just not in the type definition
|
||||
const elTip = <ForumPopoverTipEl<ElCls>>config.popoverObj.tip
|
||||
elTip.forumPopoverEl = this
|
||||
this.forumPopoverTip = elTip
|
||||
addOnremoveCallback(elTip, onTipRemoved)
|
||||
if (config.callbacks?.onTipInserted) config.callbacks.onTipInserted(this)
|
||||
elTip.addEventListener('mouseenter', onMouseEnterTip)
|
||||
elTip.addEventListener('mouseleave', onMouseLeaveTip)
|
||||
elTip.addEventListener('focusin', onFocusinTip)
|
||||
elTip.addEventListener('focusout', onFocusoutTip)
|
||||
addOnremoveCallback(elTip, onTipRemoved)
|
||||
}
|
||||
|
||||
function onFocusinElement<ElCls extends HTMLElement>(
|
||||
|
@ -141,6 +141,13 @@ function onMouseleaveElement<ElCls extends HTMLElement>(
|
|||
hidePopover(config)
|
||||
}
|
||||
|
||||
function onPopoverHidden<ElCls extends HTMLElement>(
|
||||
this: ForumPopoverEl<ElCls>
|
||||
): void {
|
||||
const config = this.forumPopoverConfig
|
||||
config.isShown = config.isTipFocused = config.isTipHovered = false
|
||||
}
|
||||
|
||||
// The content() function is executed twice (probable bootstrap bug):
|
||||
// use this function as an umbrella to only call it once
|
||||
function onGetContent<ElCls extends HTMLElement>(
|
||||
|
@ -266,17 +273,18 @@ export function add<ElCls extends HTMLElement>(
|
|||
configurable: true
|
||||
})
|
||||
el.addEventListener('inserted.bs.popover', onTipInserted)
|
||||
el.addEventListener('hidden.bs.popover', onPopoverHidden)
|
||||
el.addEventListener('focusin', onFocusinElement)
|
||||
el.addEventListener('focusout', onFocusoutElement)
|
||||
el.addEventListener('mouseenter', onMouseenterElement)
|
||||
el.addEventListener('mouseleave', onMouseleaveElement)
|
||||
// popoverConfig.popoverObj.show()
|
||||
}
|
||||
|
||||
export function teardown<ElCls extends HTMLElement>(el: ElCls): void {
|
||||
if (!isForumPopoverEl(el)) return
|
||||
el.forumPopoverConfig.popoverObj.dispose()
|
||||
el.removeEventListener('inserted.bs.popover', onTipInserted)
|
||||
el.removeEventListener('hidden.bs.popover', onPopoverHidden)
|
||||
el.removeEventListener('focusin', onFocusinElement)
|
||||
el.removeEventListener('focusout', onFocusoutElement)
|
||||
el.removeEventListener('mouseenter', onMouseenterElement)
|
||||
|
|
|
@ -4,9 +4,12 @@ import { add as popoverAdd } from './popover.ts'
|
|||
import { add as toastAdd } from './toast.ts'
|
||||
import { add as usernameAdd } from './username.ts'
|
||||
import { add as timeActualizerAdd } from './time-actualizer.ts'
|
||||
import { VotingValue } from './comment-voting-details.ts'
|
||||
import {
|
||||
type TopicCommentListingUrltemplateType, type TopicBoundFunctionsType
|
||||
add as votingValueAdd, teardown as votingValueTeardown
|
||||
} from './comment-voting-details.ts'
|
||||
import {
|
||||
type TopicBoundFunctionsType,
|
||||
urlTemplates
|
||||
} from '../topic-comment-listing.ts'
|
||||
import {
|
||||
mdiArrowLeft, mdiArrowLeftRight, mdiArrowRight, mdiCogOutline
|
||||
|
@ -47,16 +50,13 @@ export class OneComment {
|
|||
private readonly strings: PassedStringsType
|
||||
private readonly elBody: HTMLDivElement
|
||||
private readonly elBtnCommentActions: HTMLButtonElement
|
||||
private readonly urlTemplates: TopicCommentListingUrltemplateType
|
||||
private actionsPopoverReferences?: ActionsPopoverReferencesType
|
||||
private readonly votingValue?: VotingValue
|
||||
|
||||
constructor ({ root, commentPk, boundFunctions, strings, urlTemplates }: {
|
||||
constructor ({ root, commentPk, boundFunctions, strings }: {
|
||||
root: HTMLElement
|
||||
commentPk: number
|
||||
boundFunctions: TopicBoundFunctionsType
|
||||
strings: PassedStringsType
|
||||
urlTemplates: TopicCommentListingUrltemplateType
|
||||
}) {
|
||||
this.rootEl = root
|
||||
this.commentPk = commentPk
|
||||
|
@ -65,7 +65,6 @@ export class OneComment {
|
|||
onClickCommentNumber: this.onClickCommentNumber.bind(this)
|
||||
}
|
||||
this.strings = strings
|
||||
this.urlTemplates = urlTemplates
|
||||
const aEls = <HTMLCollectionOf<HTMLAnchorElement>>
|
||||
root.getElementsByClassName('forum-username')
|
||||
this.elBody = <HTMLDivElement>root.getElementsByClassName('card-block')[0]
|
||||
|
@ -76,16 +75,14 @@ export class OneComment {
|
|||
timeActualizerAdd(
|
||||
<HTMLCollectionOf<HTMLTimeElement>>
|
||||
root.getElementsByClassName('forum-time'))
|
||||
this.votingValue = this.initVotingValue()
|
||||
this.initVotingValue()
|
||||
this.initializeCallbacks()
|
||||
}
|
||||
|
||||
private initVotingValue(): VotingValue | undefined {
|
||||
const rootEl = this.rootEl.getElementsByClassName('voting-value')[0]
|
||||
if (!(rootEl instanceof HTMLAnchorElement)) return
|
||||
const obj = new VotingValue(rootEl, this.commentPk, this.urlTemplates)
|
||||
obj.initialize()
|
||||
return obj
|
||||
const elRoot = this.rootEl.getElementsByClassName('voting-value')[0]
|
||||
if (!(elRoot instanceof HTMLAnchorElement)) return
|
||||
votingValueAdd(elRoot, this.commentPk)
|
||||
}
|
||||
|
||||
private onSuccessClipboardCopy(): void {
|
||||
|
@ -189,25 +186,25 @@ export class OneComment {
|
|||
if (typeof topicSlug !== 'string') return
|
||||
if (this.actionsPopoverReferences?.elExpandCommentsDown) {
|
||||
this.actionsPopoverReferences.elExpandCommentsDown.href =
|
||||
this.urlTemplates.expandCommentsDown({
|
||||
urlTemplates.expandCommentsDown({
|
||||
topicSlug, commentPk: this.commentPk, scrollToPk: this.commentPk
|
||||
})
|
||||
}
|
||||
if (this.actionsPopoverReferences?.elExpandCommentsUp) {
|
||||
this.actionsPopoverReferences.elExpandCommentsUp.href =
|
||||
this.urlTemplates.expandCommentsUp({
|
||||
urlTemplates.expandCommentsUp({
|
||||
topicSlug, commentPk: this.commentPk, scrollToPk: this.commentPk
|
||||
})
|
||||
}
|
||||
if (this.actionsPopoverReferences?.elExpandCommentsUpRecursive) {
|
||||
this.actionsPopoverReferences.elExpandCommentsUpRecursive.href =
|
||||
this.urlTemplates.expandCommentsUpRecursive({
|
||||
urlTemplates.expandCommentsUpRecursive({
|
||||
topicSlug, commentPk: this.commentPk, scrollToPk: this.commentPk
|
||||
})
|
||||
}
|
||||
if (this.actionsPopoverReferences?.elExpandCommentsInThread) {
|
||||
this.actionsPopoverReferences.elExpandCommentsInThread.href =
|
||||
this.urlTemplates.expandCommentsEntireThread({
|
||||
urlTemplates.expandCommentsEntireThread({
|
||||
topicSlug, commentPk: this.commentPk, scrollToPk: this.commentPk
|
||||
})
|
||||
}
|
||||
|
@ -315,6 +312,12 @@ export class OneComment {
|
|||
this.initializeActionsPopover(prevCommentLink)
|
||||
}
|
||||
|
||||
private teardownVotingValue(): void {
|
||||
const elRoot = this.rootEl.getElementsByClassName('voting-value')[0]
|
||||
if (!(elRoot instanceof HTMLAnchorElement)) return
|
||||
votingValueTeardown(elRoot)
|
||||
}
|
||||
|
||||
teardown(): void {
|
||||
this.elAnchorCommentNumber.removeEventListener(
|
||||
'click', this.boundFunctions.onClickCommentNumber)
|
||||
|
@ -332,7 +335,7 @@ export class OneComment {
|
|||
}
|
||||
for (const el of this.oneReplies.values()) this.teardownOneReply(el)
|
||||
this.oneReplies.clear()
|
||||
this.votingValue?.teardown()
|
||||
this.teardownVotingValue()
|
||||
}
|
||||
|
||||
flashHighlight(): void {
|
||||
|
|
|
@ -206,7 +206,7 @@ class Username {
|
|||
html: true,
|
||||
sanitize: false,
|
||||
customClass: 'forum-username-tooltip-wrapper',
|
||||
trigger: 'hover',
|
||||
trigger: 'hover focus',
|
||||
delay: {
|
||||
show: 250,
|
||||
hide: 0
|
||||
|
|
Loading…
Reference in a new issue