You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DisqusJS/src/disqus.js

726 lines
34 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* The variable used in DisqusJS
*
* DisqusJS Mode
* @param {string} disqusjs.mode = dsqjs | disqus - Set which mode to use, should store and get in localStorage
* @param {string} disqusjs.sortType = popular | asc(oldest first) | desc(latest first) - Set which sort type to use, should store and get in localStorage
*
* DisqusJS Config
* @param {string} disqusjs.config.shortname - The disqus shortname
* @param {string} disqusjs.config.siteName - The Forum Name
* @param {string} disqusjs.config.identifier - The identifier of the page
* @param {string} disqusjs.config.title - The title of the page
* @param {string} disqusjs.config.url - The url of the page
* @param {string} disqusjs.config.api - Where to get data
* @param {string} disqusjs.config.apikey - The apikey used to request Disqus API
* @param {number} disqusjs.config.nesting - The max nesting level of Disqus comment
* @param {string} disqusjs.config.nocomment - The msg when there is no comment
* @param {string} disqusjs.config.admin - The disqus forum admin username
* @param {string} disqusjs.config.adminLabel - The disqus moderator badge text
*
* DisqusJS Info
* @param {string} disqusjs.page.id = The thread id, used at next API call
* @param {string} disqusjs.page.next = The cursor of next page of list
* @param {boolean} disqusjs.page.isClosed - Whether the comment is closed
* @param {number} disqusjs.page.length - How many comment in the thread
*/
function DisqusJS(config) {
((window, document, localStorage, fetch, Promise) => {
// 封装一下基于 Object.asign 的方法
function _extends(...args) {
_extends = Object.assign || function (target) {
for (const source of arguments) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
}
return _extends.apply(this, args);
};
const $$ = (elementID) => document.getElementById(elementID);
/**
* msg - 提示信息
*
* @param {string} url
*/
const msg = (str) => {
const msgEl = $$('dsqjs-msg');
if (msgEl) msgEl.innerHTML = str;
}
// 定义一些常量
const CLICK = 'click';
const DISQUS_CONTAINER_EL_ID = 'disqus_thread';
const DSQJS_STORAGE_KEY_SORT_TYPE = 'dsqjs_sort'
/**
* htmlTpl - DisqusJS 的 HTML 模板片段
*
* msg: DisqusJS 提示信息模板
* footer: 尾部信息模板
*/
/*
target="_blank" rel="external nofollow noopener noreferrer"
*/
const HTML_TPL_A_ATTR = `target="_blank" rel="external nofollow noopener noreferrer"`;
/*
<div id="dsqjs-msg"></div>
*/
const HTML_TPL_EL_MSG = `<div id="dsqjs-msg"></div>`;
/*
<footer>
<p class="dsqjs-footer">Powered by <a class="dsqjs-disqus-logo" href="https://disqus.com" ${HTML_TPL_A_ATTR}></a>&nbsp;&amp;&nbsp;<a href="https://disqusjs.skk.moe" target="_blank">DisqusJS</a>
</p>
</footer>
*/
const HTML_TPL_EL_FOOTER = `<footer><p class="dsqjs-footer">Powered by <a class="dsqjs-disqus-logo" href="https://disqus.com" ${HTML_TPL_A_ATTR}></a>&nbsp;&amp;&nbsp;<a href="https://disqusjs.skk.moe" target="_blank">DisqusJS</a></p></footer>`;
/*
<header class="dsqjs-header" id="dsqjs-header">
<nav class="dsqjs-nav dsqjs-clearfix">
<ul>
<li class="dsqjs-nav-tab dsqjs-tab-active"><span>${num} Comments</span></li>
<li class="dsqjs-nav-tab">${title}</li>
</ul>
<div class="dsqjs-order">
<input class="dsqjs-order-radio" id="dsqjs-order-desc" type="radio" name="comment-order" value="desc" checked="true">
<label class="dsqjs-order-label" for="dsqjs-order-desc" title="按从新到旧">最新</label>
<input class="dsqjs-order-radio" id="dsqjs-order-asc" type="radio" name="comment-order" value="asc">
<label class="dsqjs-order-label" for="dsqjs-order-asc" title="按从旧到新">最早</label>
<input class="dsqjs-order-radio" id="dsqjs-order-popular" type="radio" name="comment-order" value="popular">
<label class="dsqjs-order-label" for="dsqjs-order-popular" title="按评分从高到低">最佳</label>
</div>
</nav>
</header>
*/
const HTML_TPL_EL_HEADER = (num, title) => `<header class="dsqjs-header" id="dsqjs-header"><nav class="dsqjs-nav dsqjs-clearfix"><ul><li class="dsqjs-nav-tab dsqjs-tab-active"><span>${num} Comments</span></li><li class="dsqjs-nav-tab">${title}</li></ul><div class="dsqjs-order"><input class="dsqjs-order-radio" id="dsqjs-order-desc" type="radio" name="comment-order" value="desc" checked="true"><label class="dsqjs-order-label" for="dsqjs-order-desc" title="按从新到旧">最新</label><input class="dsqjs-order-radio" id="dsqjs-order-asc" type="radio" name="comment-order" value="asc"><label class="dsqjs-order-label" for="dsqjs-order-asc" title="按从旧到新">最早</label><input class="dsqjs-order-radio" id="dsqjs-order-popular" type="radio" name="comment-order" value="popular"><label class="dsqjs-order-label" for="dsqjs-order-popular" title="按评分从高到低">最佳</label></div></nav></header>`;
const HTML_TPL_EL_COMMENT = ({ avatarEl, createdAt }, authorEl, message) => `<div class="dsqjs-post-item dsqjs-clearfix"><div class="dsqjs-post-avatar">${avatarEl}</div><div class="dsqjs-post-body"><div class="dsqjs-post-header">${authorEl}<span class="dsqjs-meta"><time>${formatDate(createdAt)}</time></span></div><div class="dsqjs-post-content">${message}</div></div></div>`;
const HTML_TPL_EL_ASK_FOR_FULL = '如需完整体验请针对 disq.us | disquscdn.com | disqus.com 启用代理并 <a id="dsqjs-reload-disqus" class="dsqjs-msg-btn">尝试完整 Disqus 模式</a> | <a id="dsqjs-force-disqus" class="dsqjs-msg-btn">强制完整 Disqus 模式</a>';
/**
* _get(url) - 对 Fetch 的一个封装
*
* @param {string} url
* @return {Object} - 一个 Promise 对象,返回请求结果
*/
const _get = (url) => fetch(url, { method: 'GET' })
.then(resp => Promise.all([resp.ok, resp.status, resp.json(), resp.headers])).then(([ok, status, data, headers]) => {
if (ok) {
return {
ok,
status,
data,
headers
};
} else {
throw new Error;
}
}).catch(error => {
throw error;
});
// localstorage 操作类
// 用于持久化某些数据(如 newComment 的评论者的相关信息)
/**
* setLS(kwy, value) - 设置 localStorage
*
* @param {string} key
* @param {string} value
*/
const setLS = (key, value) => {
try {
localStorage.setItem(key, value);
} catch (e) {
}
}
/**
* formatDate(date) - 解析 date 为 yyyy-MM-dd hh:mm:ss
*
* @param {string} date - 传入评论创建日期XML 格式)
* @return {string} - 格式化后的日期
*/
const formatDate = (date) => {
// 不足两位补 0
const x = (input) => (input < 10) ? `0${input}` : input;
// 将传入的 date 转化为时间戳
date = Date.parse(new Date(date));
// Disqus API 返回的是 UTC 时间,所以在时间戳上加 28800000 毫秒补上 8 小时时差
date = new Date(date + 8 * 60 * 60 * 1000);
const y = date.getFullYear();
const m = x(date.getMonth() + 1);
const d = x(date.getDate());
const h = x(date.getHours());
const minute = x(date.getMinutes());
return `${y}-${m}-${d} ${h}:${minute}`;
}
/*
* loadDisqus() - 加载 Disqus
*/
function loadDisqus() {
if (window.DISQUS) {
window.DISQUS.reset({
reload: true,
config() {
this.page.identifier = disqusjs.config.identifier;
this.page.url = disqusjs.config.url;
this.page.title = disqusjs.config.title;
}
});
} else {
const s = document.createElement('script');
// 显示提示信息
// Disqus 加载成功以后会把 #disqus_thread 内的内容全部覆盖
$$(DISQUS_CONTAINER_EL_ID).innerHTML = `<div id="dsqjs"><section><div id="dsqjs-msg">评论完整模式加载中... 如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理,或切换至 <a id="dsqjs-force-dsqjs" class="dsqjs-msg-btn">评论基础模式</a></div></section>${HTML_TPL_EL_FOOTER}</div>`
$$('dsqjs-force-dsqjs').addEventListener(CLICK, useDsqjs);
s.src = `https://${disqusjs.config.shortname}.disqus.com/embed.js`;
s.setAttribute('data-timestamp', +new Date());
(document.head || document.body).appendChild(s);
}
}
function checkDisqus() {
$$(DISQUS_CONTAINER_EL_ID).innerHTML = `<div id="dsqjs"><section><div id="dsqjs-msg">正在检查 Disqus 能否访问...</div></section>${HTML_TPL_EL_FOOTER}</div>`;
// 测试 Disqus 的域名
// *.disquscdn.com 没有被墙所以不做检查
const domain = ['disqus.com', `${disqusjs.config.shortname}.disqus.com`];
let test = 0;
let success = 0;
const checker = () => {
if (domain.length === test && test === success) {
// 测试域名数量 ==== 测试次数 === 成功次数
// 如果 true 则认定可以 Disqus 可以连通
useDisqus()
} else if (domain.length === test) {
// 否则认为 Disqus 无法连通
useDsqjs()
}
// 如果测试域名数量不等于测试次数则说明测试还没有完成,不执行任何操作
}
const runcheck = (domain) => {
const img = new Image;
// 处理加载超时
const timeout = setTimeout(() => {
img.onerror = img.onload = null;
test++;
checker()
}, 3000);
img.onerror = () => {
clearTimeout(timeout);
test++;
checker()
}
img.onload = () => {
clearTimeout(timeout);
test++;
success++;
checker()
}
img.src = `https://${domain}/favicon.ico?${+(new Date)}=${+(new Date)}`
}
for (const i of domain) {
runcheck(i);
}
}
function assignClickEventForAskForFulButton() {
$$('dsqjs-reload-disqus').addEventListener(CLICK, checkDisqus);
$$('dsqjs-force-disqus').addEventListener(CLICK, useDisqus);
}
function loadDsqjs() {
// DisqusJS 加载中信息
msg(`评论基础模式加载中... ${HTML_TPL_EL_ASK_FOR_FULL}`)
assignClickEventForAskForFulButton();
/*
* 获取 Thread 信息
* Disqus API 只支持通过 Thread ID 获取评论列表,所以必须先通过 identifier 获取当前页面 Thread ID
*
* API Docs: https://disqus.com/api/docs/threads/list/
* API URI: /3.0/threads/list.json?forum=[disqus_shortname]&thread=ident:[identifier]&api_key=[apikey]
*/
const url = `${disqusjs.config.api}3.0/threads/list.json?forum=${disqusjs.config.shortname}&thread=ident:${disqusjs.config.identifier}&api_key=${apikey()}`;
_get(url).then(({ data }) => {
if (data.code === 0 && data.response.length === 1) {
const { id, title, isClosed, posts: length } = data.response[0];
disqusjs.page = { id, title, isClosed, length, comment: [] };
// 在 #disqus_thread 中填充 DisqusJS Container
$$(DISQUS_CONTAINER_EL_ID).innerHTML = `<div id="dsqjs"><div id="dsqjs-msg">评论基础模式加载中... ${HTML_TPL_EL_ASK_FOR_FULL}</div>${HTML_TPL_EL_HEADER(resp.posts, disqusjs.config.siteName)}<section class="dsqjs-post-container"><ul class="dsqjs-post-list" id="dsqjs-post-container"><p class="dsqjs-no-comment">评论列表加载中...</p></ul><a id="dsqjs-load-more" class="dsqjs-load-more dsqjs-hide">加载更多评论</a></section>${HTML_TPL_EL_FOOTER}</div>`;
assignClickEventForAskForFulButton();
$$(`dsqjs-order-${disqusjs.sortType}`).setAttribute('checked', 'true');
// 获取评论列表
getComment()
} else if (data.code === 0 && data.response.length !== 1) {
// 当前页面可能还未初始化(需要创建 thread
// Disqus API 的 threads/create 需要在服务端发起请求,不支持 AJAX Call
msg('当前 Thread 尚未创建。是否切换至 <a id="dsqjs-force-disqus" class="dsqjs-msg-btn">完整 Disqus 模式</a>')
$$('dsqjs-force-disqus').addEventListener(CLICK, useDisqus);
} else {
throw new Error;
}
}).catch(loadError)
/*
* getComment(cursor) - 获取评论列表
*
* @param {string} cursor - 传入 cursor 用于加载下一页的评论
*/
const getComment = (cursor = '') => {
const $loadMoreBtn = $$('dsqjs-load-more');
const $orderRadio = document.getElementsByClassName('dsqjs-order-radio');
const $loadHideCommentInDisqus = document.getElementsByClassName('dsqjs-has-more-btn');
const unregisterListenerForSwitchTypeRadioAndGetMoreCommentBtn = () => {
// 为按钮们取消事件,避免重复绑定
// 重新 getComment() 时会重新绑定
for (const i of $orderRadio) {
i.removeEventListener('change', switchSortType);
};
$loadMoreBtn.removeEventListener(CLICK, getMoreComment);
for (const i of $loadHideCommentInDisqus) {
i.removeEventListener(CLICK, checkDisqus);
};
}
const getMoreComment = () => {
unregisterListenerForSwitchTypeRadioAndGetMoreCommentBtn();
// 加载下一页评论
getComment(disqusjs.page.next);
}
const getCommentError = () => {
if (cursor === '') {
loadError();
} else {
$loadMoreBtn.classList.remove('dsqjs-disabled');
// 在按钮上显示提示信息
$loadMoreBtn.innerHTML = '加载更多评论失败,点击重试';
// 重新在按钮上绑定 加载更多按钮
$loadMoreBtn.addEventListener(CLICK, getMoreComment);
}
};
// 切换排序方式
const switchSortType = ({ target }) => {
// 通过 event.target 获取被选中的按钮
disqusjs.sortType = target.getAttribute('value');
// 将结果在 localStorage 中持久化
setLS(DSQJS_STORAGE_KEY_SORT_TYPE, disqusjs.sortType);
unregisterListenerForSwitchTypeRadioAndGetMoreCommentBtn();
// 清空评论列表和其它参数
disqusjs.page.comment = [];
disqusjs.page.next = ''; // 不然切换排序方式以后以后加载更多评论就会重复加载
// 显示加载中提示信息
// 反正只有评论基础模式已经加载成功了才会看到排序选项,所以无所谓再提示一次 Disqus 不可访问了
$$('dsqjs-post-container').innerHTML = '<p class="dsqjs-no-comment">正在切换排序方式...</p>';
// 把 加载更多评论 隐藏起来
$loadMoreBtn.classList.add('dsqjs-hide');
getComment();
}
// 处理传入的 cursor
const cursorParam = (cursor === '') ? '' : `&cursor=${cursor}`;
// 在发起请求前禁用 加载更多评论 按钮防止重复调用
$loadMoreBtn.classList.add('dsqjs-disabled')
/*
* 获取评论列表
*
* API Docs: https://disqus.com/api/docs/posts/list/
* API URI: /3.0/posts/list.json?forum=[shortname]&thread=[thread id]&api_key=[apikey]
*
* https://github.com/SukkaW/DisqusJS/issues/6
* 可以使用 include=deleted 来获得已被删除评论列表
*
* https://blog.fooleap.org/disqus-api-comments-order-by-desc.html
* 处理评论嵌套问题,使用了一个隐藏 API /threads/listPostsThreaded
* 用法和 /threads/listPosts 相似,和 /threads/post 的区别也只有 include 字段不同
* 这个能够返回已删除评论,所以也不需要 include=deleted 了
* sort 字段提供三个取值:
* - desc (降序)
* - asc (升序)
* - popular最热
* 这个 API 的问题在于被嵌套的评论总是降序,看起来很不习惯
*
* 每次加载翻页评论的时候合并数据并进行重排序
* 用户切换排序方式的时候直接取出进行重新渲染
*/
const sortCommentParseDate = ({ createdAt }) => Date.parse(new Date(createdAt));
const sortCommentparentAsc = (a, b) => {
if (a.parent && b.parent) {
return sortCommentParseDate(a) - sortCommentParseDate(b);
} else {
return 0;
}
};
const url = `${disqusjs.config.api}3.0/threads/listPostsThreaded?forum=${disqusjs.config.shortname}&thread=${disqusjs.page.id}${cursorParam}&api_key=${apikey()}&order=${disqusjs.sortType}`;
_get(url).then(({ data }) => {
if (data.code === 0 && data.response.length > 0) {
// 解禁 加载更多评论
$loadMoreBtn.classList.remove('dsqjs-disabled');
// 将获得的评论数据和当前页面已有的评论数据合并
disqusjs.page.comment.push(...data.response)
// 将所有的子评论进行降序排列
disqusjs.page.comment.sort(sortCommentparentAsc);
// 用当前页面的所有评论数据进行渲染
renderComment(disqusjs.page.comment);
// 为排序按钮们委托事件
for (const i of $orderRadio) {
i.addEventListener('change', switchSortType);
}
for (const i of $loadHideCommentInDisqus) {
i.addEventListener(CLICK, checkDisqus);
};
if (data.cursor.hasNext) {
// 将 cursor.next 存入 disqusjs 变量中供不能传参的不匿名函数使用
disqusjs.page.next = data.cursor.next;
// 确保 加载更多评论按钮 文字正常
$loadMoreBtn.innerHTML = '加载更多评论'
// 显示 加载更多评论 按钮
$loadMoreBtn.classList.remove('dsqjs-hide');
$loadMoreBtn.addEventListener(CLICK, getMoreComment);
} else {
// 没有更多评论了,确保按钮隐藏
$loadMoreBtn.classList.add('dsqjs-hide');
}
} else if (data.code === 0 && data.response.length === 0) {
// 当前没有评论,显示提示信息
msg(`你可能无法访问 Disqus已启用评论基础模式。${HTML_TPL_EL_ASK_FOR_FULL}`)
$$('dsqjs-post-container').innerHTML = `<p class="dsqjs-no-comment" >${disqusjs.config.nocomment}</p>`
assignClickEventForAskForFulButton();
$$('dsqjs-force-disqus').addEventListener(CLICK, useDsqjs);
} else {
throw new Error;
}
}).catch(getCommentError);
}
/*
* parseCommentData(data) - 解析评论列表
*
* @param {Array} data - 评论列表 JSON
* @return {Array} - 解析后的评论列表数据
*/
const parseCommentData = (data) => {
let topLevelComments = [];
let childComments = [];
let commentJSON = (comment) => ({
comment,
author: comment.author.name,
// 如果不设置 admin 会返回 undefined所以需要嘴一个判断
isPrimary: (disqusjs.config.admin ? (comment.author.username === disqusjs.config.admin) : false),
children: getChildren(+comment.id),
/*
* Disqus 改变了 Private API 的行为
* https://github.com/fooleap/disqus-php-api/issues/44
* 默认隐藏更多的评论,通过 hasMore 字段判断
*/
// 将 hasMore 字段提升到上层字段中
hasMore: comment.hasMore
});
const getChildren = (id) => {
// 如果没有子评论,就不需要解析子评论了
if (childComments.length === 0) return null;
const list = [];
for (const comment of childComments) {
if (comment.parent === id) {
list.unshift(commentJSON(comment));
}
}
return (list.length) ? list : null
}
data.forEach((comment) => {
// 如果没有 comment.parent 说明是第一级评论
const c = comment.parent ? childComments : topLevelComments;
c.push(comment);
});
return topLevelComments.map(comment => commentJSON(comment));
}
/*
* renderCommentData(data) - 渲染评论列表
*
* @param {Array} data - 从 getComment() 获取到的 JSON
*/
const renderComment = (data) => {
/*
* processData(data) - 处理评论列表
*
* @param {Array} data - 解析后的评论列表 JSON
*/
const processData = (data) => {
// 处理 Disqus Profile URL
if (data.comment.author.profileUrl) {
/*
Avatar Element
<a href="${data.comment.author.profileUrl}" ${HTML_TPL_A_ATTR}>
<img src="${data.comment.author.avatar.cache}">
</a>
Author Element
<span class="dsqjs-post-author">
<a href="${data.comment.author.profileUrl}" ${HTML_TPL_A_ATTR}>${data.comment.author.name}</a>
</span>
*/
data.comment.avatarEl = `<a href="${data.comment.author.profileUrl}"><img src="${replaceDisquscdn(data.comment.author.avatar.cache)}" ${HTML_TPL_A_ATTR}></a>`
data.comment.authorEl = `<span class="dsqjs-post-author"><a href="${data.comment.author.profileUrl}" ${HTML_TPL_A_ATTR}>${data.comment.author.name}</a></span>`
} else {
data.comment.avatarEl = `<img src="${replaceDisquscdn(data.comment.author.avatar.cache)}">`
data.comment.authorEl = `<span class="dsqjs-post-author">${data.comment.author.name}</span>`
}
// 处理 Admin Label
// 需要同时设置 isPrimary 和 adminLabeladmin 已经在 processData() 中做过判断了
if (disqusjs.config.adminLabel && data.isPrimary) {
data.comment.authorEl += `<span class="dsqjs-admin-badge">${disqusjs.config.adminLabel}</span>`;
}
return data;
}
/**
* removeDisqUs(msg) - 将 comment 中的短链接 disq.us 去除
* @param {string} msg - 评论信息
* @return {string} msg - 经过处理的评论信息
*/
const removeDisqUs = (msg) => {
const el = document.createElement('div');
el.innerHTML = msg;
const aTag = el.getElementsByTagName('a');
for (const i of aTag) {
const link = decodeURIComponent(i.href.replace(/https:\/\/disq.us\/url\?url=/g, '')).replace(/(.*):.+cuid=.*/, '$1');
i.href = link;
i.innerHTML = link;
i.rel = 'external noopener nofollow noreferrer';
i.target = '_blank';
}
return el.innerHTML;
}
/**
* replaceDisquscdn(str) - 将 a.disquscdn.com 替换为 c.disquscdn.com
* @param {string} str - 字符串
* @return {string} - 替换后的字符串
*/
const replaceDisquscdn = (str) => str.replace('/a.disquscdn.com/ig', 'c.disquscdn.com');
const renderPostItem = (s) => {
let authorEl = '';
let message = '';
if (s.isDeleted) {
message = `<small>此评论已被删除</small>`;
} else {
authorEl = `${s.authorEl}<span class="dsqjs-bullet"></span>`;
message = removeDisqUs(replaceDisquscdn(s.message));
}
return HTML_TPL_EL_COMMENT(s, authorEl, message)
}
const childrenComments = (data) => {
const nesting = data.nesting;
const children = (data.children || []);
if (!children) {
return;
}
let html = '';
// 如果当前评论嵌套数大于 4 则不再右移
if (nesting < disqusjs.config.nesting) {
html = '<ul class="dsqjs-post-list dsqjs-children">';
} else {
html = '<ul class="dsqjs-post-list">';
}
children.map((comment) => {
comment = processData(comment);
comment.nesting = nesting + 1;
// 处理可能存在的隐藏回复
let hasMoreEl = '';
if (comment.hasMore) {
hasMoreEl = `<p class="dsqjs-has-more">切换至 <a class="dsqjs-has-more-btn" id="load-more-${comment.comment.id}" data-more-id="comment-${comment.comment.id}">完整 Disqus 模式</a> 显示更多回复</p>`
}
html += `<li data-id="comment-${comment.comment.id}" id="comment-${comment.comment.id}">${renderPostItem(comment.comment)}${childrenComments(comment)}${hasMoreEl}</li>`;
});
html += '</ul>';
if (html.length !== 0) {
return html;
} else {
return;
}
}
let html = '';
parseCommentData(data).map((comment) => {
// 如果有子评论,设置当前评论前套数为 1
if (comment.children) {
comment.nesting = 1;
}
comment = processData(comment);
// 处理可能存在的隐藏回复
let hasMoreEl = '';
if (comment.hasMore) {
hasMoreEl = `<p class="dsqjs-has-more">切换至 <a id="load-more-${comment.comment.id}">完整 Disqus 模式</a> 显示更多回复</p>`
}
html += `<li data-id="comment-${comment.comment.id}" id="comment-${comment.comment.id}">${renderPostItem(comment.comment)}${childrenComments(comment)}${hasMoreEl}</li>`;
});
// 增加提示信息
msg(`你可能无法访问 Disqus已启用评论基础模式。${HTML_TPL_EL_ASK_FOR_FULL}`)
$$('dsqjs-post-container').innerHTML = html;
// 为 checkDisqus 和 useDsqjs 按钮添加事件
assignClickEventForAskForFulButton();
}
}
/*
* loadError() - 评论基础模式加载出现错误
*/
function loadError(err) {
console.log(err);
msg('评论基础模式加载失败,是否 <a id="dsqjs-reload-dsqjs" class="dsqjs-msg-btn">重载</a> 或 <a id="dsqjs-reload-disqus" class="dsqjs-msg-btn">尝试完整 Disqus 模式</a> ');
$$('dsqjs-reload-dsqjs').addEventListener(CLICK, loadDsqjs);
$$('dsqjs-reload-disqus').addEventListener(CLICK, checkDisqus);
}
/*
* useDsqjs() - 强制使用 DisqusJS
* useDsqjs() - 强制使用 Disqus
*/
function useDsqjs() {
setLS('dsqjs_mode', 'dsqjs');
loadDsqjs();
}
function useDisqus() {
setLS('dsqjs_mode', 'disqus');
loadDisqus();
}
const disqusjs = {};
const currentPageFullUrl = document.location.origin + document.location.pathname + document.location.search;
disqusjs.config = _extends({
api: 'https://disqus.skk.moe/disqus/',
identifier: currentPageFullUrl,
url: currentPageFullUrl,
title: document.title,
siteName: '',
nesting: parseInt(config.nesting) || 4,
nocomment: '这里冷冷清清的,一条评论都没有'
}, config);
// 定义 disqusjs.page之后会填充 thread id、title 等数据
disqusjs.page = {};
// 通过 用户配置的 apikey 来判断是否需要使用随机取值
const disqusJsApiKeys = disqusjs.config.apikey;
const apikey = () => (Array.isArray(disqusJsApiKeys)) ? disqusJsApiKeys[Math.floor(Math.random() * disqusJsApiKeys.length)] : disqusJsApiKeys;
/*
* window.disqus_config - 从 disqusjs.config 获取 Disqus 所需的配置
*/
window.disqus_config = function () {
this.page.url = disqusjs.config.url;
this.page.identifier = disqusjs.config.identifier;
this.page.title = disqusjs.config.title;
};
// 填充 DisqusJS 的 Container
$$(DISQUS_CONTAINER_EL_ID).innerHTML = `<div id="dsqjs">${HTML_TPL_EL_MSG}${HTML_TPL_EL_FOOTER}</div>`
function initDsqjs() {
disqusjs.mode = localStorage.getItem('dsqjs_mode');
disqusjs.sortType = localStorage.getItem(DSQJS_STORAGE_KEY_SORT_TYPE) || localStorage.getItem('disqus.sort');
if (!disqusjs.sortType) {
setLS(DSQJS_STORAGE_KEY_SORT_TYPE, 'desc');
disqusjs.sortType = 'desc';
}
if (disqusjs.mode === 'disqus') {
loadDisqus();
} else if (disqusjs.mode === 'dsqjs') {
loadDsqjs();
} else {
// 没有在 localStorage 中找到 disqusjs_mode 相关内容,开始检查访客的 Disqus 可用性
// 也作为不支持 localStorage 的浏览器的 fallback
checkDisqus();
}
}
// 引入 Fetch 以后,一堆浏览器将不再被支持,所以加个判断,劝退一些浏览器
if (!fetch || !localStorage || !Promise) {
msg(`你的浏览器版本过低,不兼容评论基础模式。${HTML_TPL_EL_ASK_FOR_FULL}`);
assignClickEventForAskForFulButton();
} else {
initDsqjs();
}
})(window, document, localStorage, fetch, Promise);
}
// CommonJS 模块
try { module.exports = DisqusJS; } catch (e) { }