diff --git a/app/views/common/_calendar.html.erb b/app/views/common/_calendar.html.erb index 704f865..393a09a 100644 --- a/app/views/common/_calendar.html.erb +++ b/app/views/common/_calendar.html.erb @@ -1,3 +1,5 @@ +<%= javascript_include_tag('dynamic_favicon', plugin: :redmine_qbo_calendar) %> + <% # Check if toggles are active via query params only_appointments = params[:only_appointments] == '1' diff --git a/app/views/customer_appointments/edit.html.erb b/app/views/customer_appointments/edit.html.erb index 8db5cd9..0084ae4 100644 --- a/app/views/customer_appointments/edit.html.erb +++ b/app/views/customer_appointments/edit.html.erb @@ -1,3 +1,5 @@ +<%= javascript_include_tag('dynamic_favicon', plugin: :redmine_qbo_calendar) %> +

Edit Appointment

<%= render "form" %> \ No newline at end of file diff --git a/app/views/customer_appointments/new.html.erb b/app/views/customer_appointments/new.html.erb index 852510f..b440001 100644 --- a/app/views/customer_appointments/new.html.erb +++ b/app/views/customer_appointments/new.html.erb @@ -1,3 +1,5 @@ +<%= javascript_include_tag('dynamic_favicon', plugin: :redmine_qbo_calendar) %> +

New Appointment

<%= render "form" %> \ No newline at end of file diff --git a/app/views/customer_appointments/show.html.erb b/app/views/customer_appointments/show.html.erb index 6ad3250..57950a9 100644 --- a/app/views/customer_appointments/show.html.erb +++ b/app/views/customer_appointments/show.html.erb @@ -1,3 +1,5 @@ +<%= javascript_include_tag('dynamic_favicon', plugin: :redmine_qbo_calendar) %> +
<%= link_to issues_calendar_path do %> <%= l(:button_calendar) %> diff --git a/assets/javascripts/dynamic_favicon.js b/assets/javascripts/dynamic_favicon.js new file mode 100644 index 0000000..ffb57b1 --- /dev/null +++ b/assets/javascripts/dynamic_favicon.js @@ -0,0 +1,140 @@ +(function() { + 'use strict'; + + console.log('[Redmine QBO Calendar] dynamic_favicon.js loaded (Simplified Canvas PNG)'); + + const FAVICON_ID = 'redmine-qbo-calendar-favicon'; + + function generatePngFaviconUrl(day, callback) { + const svg = ` + + + + + + + + + + + + + + OSOR + + + + ${day} + + + + `; + + const cleanSvg = svg.replace(/\n/g, '').replace(/\s+/g, ' ').trim(); + const svgDataUrl = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(cleanSvg))); + + const canvas = document.createElement('canvas'); + canvas.width = 64; + canvas.height = 64; + const ctx = canvas.getContext('2d'); + + const img = new Image(); + + img.onload = function() { + ctx.drawImage(img, 0, 0, 64, 64); + const pngDataUrl = canvas.toDataURL('image/png'); + callback(pngDataUrl); + }; + + img.src = svgDataUrl; + } + + function setFavicon() { + const day = new Date().getDate(); + + generatePngFaviconUrl(day, function(newFaviconUrl) { + const existingIcons = document.querySelectorAll('link[rel*="icon"]'); + + if (existingIcons.length > 0) { + existingIcons.forEach(function(icon) { + icon.type = 'image/png'; + icon.rel = 'icon'; + icon.href = newFaviconUrl; + }); + } else { + const favicon = document.createElement('link'); + favicon.id = FAVICON_ID; + favicon.rel = 'icon'; + favicon.type = 'image/png'; + favicon.href = newFaviconUrl; + document.head.appendChild(favicon); + } + + console.log( + '[OSOR Calendar] favicon updated (Simplified PNG)', + { day: day } + ); + }); + } + + function initialize() { + console.log('[OSOR Calendar] initializing favicon'); + setTimeout(setFavicon, 150); + } + + if (document.readyState === 'loading') { + document.addEventListener( + 'DOMContentLoaded', + initialize + ); + } else { + initialize(); + } + +})(); \ No newline at end of file