From 75e92e1bd7b3611df1f43fe6e22a376eca4a7285 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 17 Nov 2020 14:44:18 -0500 Subject: [PATCH] REFACTOR: The Favcount library needs global variables This moves the library into our lib folder, and refactored it to more modern Javascript. I've kept the MIT license at the top of the file. Doing this allows us to import it as a library in Ember CLI and ditch yet another global variable. --- .../discourse/app/lib/update-tab-count.js | 67 ++++++++++++ .../discourse/app/services/document-title.js | 3 +- app/assets/javascripts/vendor.js | 1 - lib/tasks/javascript.rake | 2 - package.json | 1 - vendor/assets/javascripts/favcount.js | 102 ------------------ yarn.lock | 4 - 7 files changed, 69 insertions(+), 111 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/lib/update-tab-count.js delete mode 100644 vendor/assets/javascripts/favcount.js diff --git a/app/assets/javascripts/discourse/app/lib/update-tab-count.js b/app/assets/javascripts/discourse/app/lib/update-tab-count.js new file mode 100644 index 00000000000..db574730a90 --- /dev/null +++ b/app/assets/javascripts/discourse/app/lib/update-tab-count.js @@ -0,0 +1,67 @@ +// This file's code is based on Favcount by Chris Hunt, Copyright 2013 Chris Hunt, MIT License + +function renderIcon(canvas, img, count) { + count = Math.round(count); + if (isNaN(count) || count < 1) { + count = ""; + } else if (count < 10) { + count = " " + count; + } else if (count > 99) { + count = "99"; + } + + // Scale canvas elements based on favicon size + let multiplier = img.width / 16; + let fontSize = multiplier * 11; + let xOffset = multiplier; + let shadow = multiplier * 2; + + canvas.height = canvas.width = img.width; + let ctx = canvas.getContext("2d"); + ctx.font = `bold ${fontSize}px Helvetica, Arial, sans-serif`; + + if (count) { + ctx.globalAlpha = 0.4; + } + ctx.drawImage(img, 0, 0); + ctx.globalAlpha = 1.0; + + // Draw white drop shadow + ctx.shadowColor = "#FFF"; + ctx.shadowBlur = shadow; + ctx.shadowOffsetX = 0; + ctx.shadowOffsetY = 0; + + // Draw white border + ctx.fillStyle = "#FFF"; + ctx.fillText(count, xOffset, fontSize); + ctx.fillText(count, xOffset + multiplier, fontSize); + ctx.fillText(count, xOffset, fontSize + multiplier); + ctx.fillText(count, xOffset + multiplier, fontSize + multiplier); + + // Draw black count + ctx.fillStyle = "#000"; + ctx.fillText(count, xOffset + multiplier / 2.0, fontSize + multiplier / 2.0); + + // Replace favicon with new favicon + let newFavicon = document.createElement("link"); + newFavicon.rel = "icon"; + newFavicon.href = canvas.toDataURL("image/png"); + let favicon = document.querySelector("link[rel=icon]"); + + let head = document.querySelector("head"); + if (favicon) { + head.removeChild(favicon); + } + head.appendChild(newFavicon); +} + +export default function tabCount(url, count) { + let canvas = document.createElement("canvas"); + if (canvas.getContext) { + let img = document.createElement("img"); + img.crossOrigin = "anonymous"; + img.onload = () => renderIcon(canvas, img, count); + img.src = url; + } +} diff --git a/app/assets/javascripts/discourse/app/services/document-title.js b/app/assets/javascripts/discourse/app/services/document-title.js index 944940c0988..5fea2a8b2a9 100644 --- a/app/assets/javascripts/discourse/app/services/document-title.js +++ b/app/assets/javascripts/discourse/app/services/document-title.js @@ -1,6 +1,7 @@ import Service from "@ember/service"; import { inject as service } from "@ember/service"; import getURL from "discourse-common/lib/get-url"; +import updateTabCount from "discourse/lib/update-tab-count"; export default Service.extend({ appEvents: service(), @@ -100,7 +101,7 @@ export default Service.extend({ url = getURL("/favicon/proxied?" + encodeURIComponent(url)); } - new window.Favcount(url).set(this._displayCount()); + updateTabCount(url, this._displayCount()); } }, }); diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js index e6c081a193c..6ab4a12dcae 100644 --- a/app/assets/javascripts/vendor.js +++ b/app/assets/javascripts/vendor.js @@ -9,7 +9,6 @@ //= require popper.js //= require bootstrap-modal.js //= require caret_position -//= require favcount.js //= require jquery.ba-resize.js //= require jquery.color.js //= require jquery.fileupload.js diff --git a/lib/tasks/javascript.rake b/lib/tasks/javascript.rake index 27ba82f8a39..a1bc19f04bb 100644 --- a/lib/tasks/javascript.rake +++ b/lib/tasks/javascript.rake @@ -59,8 +59,6 @@ def dependencies }, { source: 'spectrum-colorpicker/spectrum.css', public: true - }, { - source: 'favcount/favcount.js' }, { source: 'handlebars/dist/handlebars.js' }, { diff --git a/package.json b/package.json index bc68a43701a..15b4d4b1915 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "chart.js": "2.9.3", "chartjs-plugin-datalabels": "^0.7.0", "eslint-config-discourse": "^1.1.5", - "favcount": "https://github.com/chrishunt/favcount", "handlebars": "^4.7.0", "highlight.js": "https://github.com/highlightjs/highlight.js", "intersection-observer": "^0.5.1", diff --git a/vendor/assets/javascripts/favcount.js b/vendor/assets/javascripts/favcount.js deleted file mode 100644 index dabd6704864..00000000000 --- a/vendor/assets/javascripts/favcount.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * favcount.js v1.5.0 - * http://chrishunt.co/favcount - * Dynamically updates the favicon with a number. - * - * Copyright 2013, Chris Hunt - * Released under the MIT license - */ - -(function(){ - function Favcount(icon) { - this.icon = icon; - this.opacity = 0.4; - this.canvas = document.createElement('canvas'); - this.font = "Helvetica, Arial, sans-serif"; - } - - Favcount.prototype.set = function(count) { - var self = this, - img = document.createElement('img'); - - if (self.canvas.getContext) { - img.crossOrigin = "anonymous"; - - img.onload = function() { - drawCanvas(self.canvas, self.opacity, self.font, img, normalize(count)); - }; - - img.src = this.icon; - } - }; - - function normalize(count) { - count = Math.round(count); - - if (isNaN(count) || count < 1) { - return ''; - } else if (count < 10) { - return ' ' + count; - } else if (count > 99) { - return '99'; - } else { - return count; - } - } - - function drawCanvas(canvas, opacity, font, img, count) { - var head = document.getElementsByTagName('head')[0], - favicon = document.querySelector('link[rel=icon]'), - newFavicon = document.createElement('link'), - multiplier, fontSize, context, xOffset, yOffset, border, shadow; - - // Scale canvas elements based on favicon size - multiplier = img.width / 16; - fontSize = multiplier * 11; - xOffset = multiplier; - yOffset = multiplier * 11; - border = multiplier; - shadow = multiplier * 2; - - canvas.height = canvas.width = img.width; - context = canvas.getContext('2d'); - context.font = 'bold ' + fontSize + 'px ' + font; - - // Draw faded favicon background - if (count) { context.globalAlpha = opacity; } - context.drawImage(img, 0, 0); - context.globalAlpha = 1.0; - - // Draw white drop shadow - context.shadowColor = '#FFF'; - context.shadowBlur = shadow; - context.shadowOffsetX = 0; - context.shadowOffsetY = 0; - - // Draw white border - context.fillStyle = '#FFF'; - context.fillText(count, xOffset, yOffset); - context.fillText(count, xOffset + border, yOffset); - context.fillText(count, xOffset, yOffset + border); - context.fillText(count, xOffset + border, yOffset + border); - - // Draw black count - context.fillStyle = '#000'; - context.fillText(count, - xOffset + (border / 2.0), - yOffset + (border / 2.0) - ); - - // Replace favicon with new favicon - newFavicon.rel = 'icon'; - newFavicon.href = canvas.toDataURL('image/png'); - if (favicon) { head.removeChild(favicon); } - head.appendChild(newFavicon); - } - - this.Favcount = Favcount; -}).call(this); - -(function(){ - Favcount.VERSION = '1.5.1'; -}).call(this); diff --git a/yarn.lock b/yarn.lock index 9d7b9ebf803..483c5a306c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1227,10 +1227,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -"favcount@https://github.com/chrishunt/favcount": - version "0.0.0" - resolved "https://github.com/chrishunt/favcount#d053eac5ce33e2e299363ab927103e2ff6c7361e" - fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"