通用评论

helper.js 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import { REGEXP, IMAGE_SPLIT } from "./constant";
  2. import emoji, { prefixUrl } from "./emoji";
  3. const emojiObejct = arrayToObject(emoji, "title");
  4. export function isFunction(functionToCheck) {
  5. return (
  6. functionToCheck && {}.toString.call(functionToCheck) === "[object Function]"
  7. );
  8. }
  9. export function isUrl(userInput) {
  10. // 需完整匹配
  11. const regexp = /^((http(s)?:)?\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
  12. var res = userInput.match(regexp);
  13. if (res === null) return false;
  14. else return true;
  15. }
  16. /**
  17. * 将对象数组转换为对象
  18. * @param {array} array Array of Objects
  19. * @param {string} keyField string
  20. */
  21. export function arrayToObject(array, keyField) {
  22. return array.reduce((obj, item) => {
  23. obj[item[keyField]] = item;
  24. return obj;
  25. }, {});
  26. }
  27. /**
  28. * HTML 编码
  29. * 将 < > 等字符串进行编码
  30. * @param {string} str 文本
  31. */
  32. export function htmlEncode(str) {
  33. if (!str) return "";
  34. return str.replace(/[<>]/gim, function(i) {
  35. return "&#" + i.charCodeAt(0) + ";";
  36. });
  37. }
  38. /**
  39. * 渲染编辑器
  40. * [x] => <img src="x" />
  41. * @param {strig} content
  42. */
  43. export function renderContent(content, onClick) {
  44. let newContent = content;
  45. if (newContent.indexOf(IMAGE_SPLIT) !== -1) {
  46. newContent = newContent.split(IMAGE_SPLIT);
  47. newContent.pop();
  48. newContent = newContent.join("");
  49. }
  50. // 不包含在标签内的链接
  51. const innerUrl = /((http(s)?:)?\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)(?![^<>]*>|[^"]*?<\/a)/g;
  52. const data = htmlEncode(newContent)
  53. .replace(REGEXP, function(a, b) {
  54. const src = a.slice(1, -1);
  55. // 兼容旧的评
  56. // 因为旧的评论用 [img url] 方式存储的
  57. if (isUrl(src)) {
  58. return `<a href="${src}" rel="noopener noreferrer" target="_blank"><img class="comment-img" src="${src}" alt="${src}" /></a>`;
  59. }
  60. // 如果不存在对应的表情, 则返回原文
  61. const emoji = emojiObejct[src];
  62. if (emoji) {
  63. return `<img class="comment-emoji" src="${prefixUrl}${emoji.value}.${
  64. emoji.ext
  65. }" alt="${emoji.title}" />`;
  66. }
  67. return `[${src}]`;
  68. })
  69. .replace(innerUrl, function(a, b) {
  70. const protocol = /^(https?:)?\/\//;
  71. const hasProtocol = protocol.test(a);
  72. const url = hasProtocol ? a : `//${a}`;
  73. // target="_blank" 存在安全性问题
  74. // return `<a href="${url}" target="_blank" rel="noopener noreferrer" >${a}</a>`;
  75. return `<a href="${url}">${a}</a>`;
  76. })
  77. .replace(/\n/g, "<br />");
  78. return data;
  79. }