diff --git a/_config.yml b/_config.yml
index da4ee3d..36c9211 100644
--- a/_config.yml
+++ b/_config.yml
@@ -659,7 +659,7 @@ artalk:
# --------------------------------------
chat:
- # Choose: chatra/tidio/crisp
+ # Choose: chatra/tidio/crisp/knocket
# Leave it empty if you don't need chat
use:
# Chat Button [recommend]
@@ -680,6 +680,10 @@ tidio:
crisp:
website_id:
+# https://trtc.io/solutions/knocket
+knocket:
+ identifier:
+
# --------------------------------------
# Analysis
# --------------------------------------
diff --git a/layout/includes/page/shuoshuo.pug b/layout/includes/page/shuoshuo.pug
index 3e5f15b..fd93334 100644
--- a/layout/includes/page/shuoshuo.pug
+++ b/layout/includes/page/shuoshuo.pug
@@ -54,6 +54,8 @@
(() => {
const limitConfig = !{ JSON.stringify(page.limit || {}) }
+ const escapeHtml = str => String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''')
+
const sortDataByDate = data => data.sort((a, b) => new Date(b.date) - new Date(a.date))
const filterDataByLimit = (data, limit) => {
@@ -64,49 +66,47 @@
return data.filter(item => new Date(item.date) >= limitDate)
}
return data
- };
+ }
+
+ const dateFormatter = new Intl.DateTimeFormat('en-GB', {
+ timeZone: !{JSON.stringify(config.timezone || '')} || Intl.DateTimeFormat().resolvedOptions().timeZone,
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ hour12: false
+ })
const formatToTimeZone = (date) => {
const fullDate = date.length === 10 ? `${date} 00:00:00` : date
- const visitorTimeZone = '#{config.timezone}' || Intl.DateTimeFormat().resolvedOptions().timeZone
- const options = {
- timeZone: visitorTimeZone,
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit',
- hour12: false
- }
- const [day, month, year, hour, minute, second] = new Intl.DateTimeFormat('en-GB', options)
- .format(new Date(fullDate))
- .match(/\d+/g)
+ const [day, month, year, hour, minute, second] = dateFormatter.format(new Date(fullDate)).match(/\d+/g)
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
}
const addLazyload = str => {
- const config = {
+ const lazyConfig = {
enable: !{Boolean(enable)},
native: !{Boolean(native)},
- field: '!{field}',
- placeholder: '!{url_for(placeholder)}',
+ field: !{JSON.stringify(field || '')},
+ placeholder: !{JSON.stringify(url_for(placeholder))},
}
- if (!config.enable || config.field !== 'site') return str
+ if (!lazyConfig.enable || lazyConfig.field !== 'site' || str.indexOf(' {
- if (config.native) {
+ if (lazyConfig.native) {
img.setAttribute('loading', 'lazy')
} else {
const src = img.getAttribute('src')
img.setAttribute('data-lazy-src', src)
- if (config.placeholder) {
- img.setAttribute('src', config.placeholder)
+ if (lazyConfig.placeholder) {
+ img.setAttribute('src', lazyConfig.placeholder)
} else {
img.removeAttribute('src')
}
@@ -119,19 +119,18 @@
const itemsPerPage = 8
let totalPages = 0
let data = []
- let inputEventsAttached = false // Flag to mark if input event listeners have been added
const renderData = (dataSlice) => {
const content = dataSlice.map(item => {
const formattedDate = formatToTimeZone(item.date)
- const tags = item.tags && item.tags.map(tag => `${tag}`).join('') || ''
- const commentButton = item.key && !{commentsJsLoad}
+ const tags = item.tags && item.tags.map(tag => `${escapeHtml(tag)}`).join('') || ''
+ const commentButton = item.key && !{commentsJsLoad || false}
? `
${this.highlightKeyword(content, slice)}...
` - }) - - resultItem += '${this.highlightKeyword(content, slice)}...
` + }) + + resultItem += '