favicon.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. let defaultUrl = null;
  2. let currentSlug = null;
  3. const imageCache = {};
  4. const urlCache = {};
  5. const withImage = function (url, action) {
  6. if (imageCache[url]) {
  7. return action(imageCache[url]);
  8. } else {
  9. const img = new Image();
  10. img.crossOrigin = "anonymous";
  11. img.src = url;
  12. return (img.onload = () => {
  13. imageCache[url] = img;
  14. return action(img);
  15. });
  16. }
  17. };
  18. this.setFaviconForDoc = function (doc) {
  19. if (currentSlug === doc.slug) {
  20. return;
  21. }
  22. const favicon = $('link[rel="icon"]');
  23. if (defaultUrl === null) {
  24. defaultUrl = favicon.href;
  25. }
  26. if (urlCache[doc.slug]) {
  27. favicon.href = urlCache[doc.slug];
  28. currentSlug = doc.slug;
  29. return;
  30. }
  31. const iconEl = $(`._icon-${doc.slug.split("~")[0]}`);
  32. if (iconEl === null) {
  33. return;
  34. }
  35. const styles = window.getComputedStyle(iconEl, ":before");
  36. const backgroundPositionX = styles["background-position-x"];
  37. const backgroundPositionY = styles["background-position-y"];
  38. if (backgroundPositionX === undefined || backgroundPositionY === undefined) {
  39. return;
  40. }
  41. const bgUrl = app.config.favicon_spritesheet;
  42. const sourceSize = 16;
  43. const sourceX = Math.abs(parseInt(backgroundPositionX.slice(0, -2)));
  44. const sourceY = Math.abs(parseInt(backgroundPositionY.slice(0, -2)));
  45. return withImage(bgUrl, (docImg) =>
  46. withImage(defaultUrl, function (defaultImg) {
  47. const size = defaultImg.width;
  48. const canvas = document.createElement("canvas");
  49. const ctx = canvas.getContext("2d");
  50. canvas.width = size;
  51. canvas.height = size;
  52. ctx.drawImage(defaultImg, 0, 0);
  53. const docIconPercentage = 65;
  54. const destinationCoords = (size / 100) * (100 - docIconPercentage);
  55. const destinationSize = (size / 100) * docIconPercentage;
  56. ctx.drawImage(
  57. docImg,
  58. sourceX,
  59. sourceY,
  60. sourceSize,
  61. sourceSize,
  62. destinationCoords,
  63. destinationCoords,
  64. destinationSize,
  65. destinationSize,
  66. );
  67. try {
  68. urlCache[doc.slug] = canvas.toDataURL();
  69. favicon.href = urlCache[doc.slug];
  70. return (currentSlug = doc.slug);
  71. } catch (error) {
  72. Raven.captureException(error, { level: "info" });
  73. return this.resetFavicon();
  74. }
  75. }),
  76. );
  77. };
  78. this.resetFavicon = function () {
  79. if (defaultUrl !== null && currentSlug !== null) {
  80. $('link[rel="icon"]').href = defaultUrl;
  81. return (currentSlug = null);
  82. }
  83. };