Skip to content

doc: add Google Analytics#4792

Open
Saviq wants to merge 1 commit intomainfrom
MIRENG-1691-enable-analytics
Open

doc: add Google Analytics#4792
Saviq wants to merge 1 commit intomainfrom
MIRENG-1691-enable-analytics

Conversation

@Saviq
Copy link
Copy Markdown
Contributor

@Saviq Saviq commented Mar 23, 2026

What's new?

Adds GA integration to the published documentation.

Ref.: https://github.com/canonical/RTD-cookie-banner-integration

How to test

Check that the cookie banner opens up in incognito mode.

Checklist

  • Tests added and pass
  • Adequate documentation added
  • (optional) Added Screenshots or videos

@Saviq Saviq requested a review from a team as a code owner March 23, 2026 16:50
Copilot AI review requested due to automatic review settings March 23, 2026 16:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Google Analytics (via Google Tag Manager) and a cookie-consent banner to the Sphinx-built documentation, wiring in custom templates and static assets under doc/sphinx/.sphinx.

Changes:

  • Configure Sphinx to load custom templates/static assets and include cookie-banner CSS + JS bundle.
  • Add custom header.html (with GTM loader) and footer.html (with “Manage your tracker settings” link).
  • Add the cookie banner CSS/JS assets and update pre-commit exclusions for the .sphinx subtree.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
doc/sphinx/conf.py Points Sphinx at .sphinx/_templates + .sphinx/_static and injects the cookie-banner CSS/JS.
doc/sphinx/.sphinx/_templates/header.html Adds a custom docs header and injects the GTM loader snippet.
doc/sphinx/.sphinx/_templates/footer.html Adds footer markup including the “Manage your tracker settings” entry point.
doc/sphinx/.sphinx/_static/cookie-banner.css Provides styling for the cookie banner/manager UI.
doc/sphinx/.sphinx/_static/bundle.js Implements consent UI + gtag consent updates + user_id cookie behavior.
.pre-commit-config.yaml Excludes the .sphinx subtree from pre-commit hooks.

{% endif %}
{% endif %}
</div>
<div class="right-details"><a href="" class="js-revoke-cookie-manager muted-link">Manage your tracker settings</a></div>
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Manage your tracker settings” control is an <a href=""> which navigates to the current page URL if JavaScript fails or is delayed, and it doesn’t convey button semantics. Consider changing this to a <button> (preferred) or at least href="#" with appropriate ARIA so it behaves correctly for keyboard/screen-reader users.

Suggested change
<div class="right-details"><a href="" class="js-revoke-cookie-manager muted-link">Manage your tracker settings</a></div>
<div class="right-details"><button type="button" class="js-revoke-cookie-manager muted-link">Manage your tracker settings</button></div>

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
(()=>{"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function t(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,c(o.key),o)}}function n(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),Object.defineProperty(e,"prototype",{writable:!1}),e}function o(e,t,n){return(t=c(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach(function(t){o(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function c(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}var s=[{id:"essential",enableSwitcher:!1,content:{default:{title:"Essential",description:"Enables the core functionality on our websites, such as navigation, access to secure areas, video players and payments. Our websites cannot function properly without these cookies; they can only be disabled by changing your browser preferences.",activeText:"Always active"},zh:{title:"必要性",description:"启用网站核心功能,例如导航,访问安全区域,视频播放器和支付。没有这些cookie网站不能正常工作;它们仅可通过修改浏览器偏好设置禁用。",activeText:"默认接受"},ja:{title:"エッセンシャル",description:"当社ウェブサイトの基本的な機能(ナビゲーション、保護された情報へのアクセス、動画プレーヤー、支払いなど)を有効にするために必要なクッキーです。これらのクッキーが無効になっている場合、当社ウェブサイトは正しく動作しません。 これらはブラウザ設定の変更によってのみ無効化できます。",activeText:"常に有効"}}},{id:"performance",enableSwitcher:!0,content:{default:{title:"Performance",description:"Collects information on usage on our websites, for example, which pages are most frequently visited."},zh:{title:"表现性",description:"网站使用信息收集,例如哪些网页被频繁访问。"},ja:{title:"パフォーマンス",description:"当社ウェブサイトの利用状況(例:どのページの訪問頻度が高いかなど)に関する情報を収集します。"}}},{id:"functionality",enableSwitcher:!0,content:{default:{title:"Functional",description:"Recognizes you when you return to our websites. This enables us to personalize content, greet you by name, remember your preferences, and helps you share pages on social networks."},zh:{title:"功能性",description:"当你返回到我们网站时能识别您。这使得我们能个性化内容,欢迎您,记住您的偏好设置,以及帮助您分享网页到社交媒体。"},ja:{title:"機能性",description:"再訪時にユーザーを識別し、パーソナライズされたコンテンツの表示、お客様のお名前を用いた挨拶メッセージ、ユーザー設定の記憶を可能にします。また、ソーシャルネットワークでページを共有しやすくする機能にも使用されます。"}}}],l={default:{notification:{title:"Your tracker settings",body1:'We use cookies and similar methods to recognize visitors and remember preferences. We also use them to measure campaign effectiveness and analyze traffic on our websites. By selecting ‘Accept‘, you consent to the use of these methods by us and trusted third parties. For further details or to change your consent choices at any time see our <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">cookie policy</a>.',buttonManage:"Manage your tracker settings",buttonAcceptAll:"Accept all"},manager:{title:"Tracking choices",body1:"We use cookies to recognize visitors and remember your preferences. They enhance user experience, personalize content and ads, provide social media features, measure campaign effectiveness, and analyze traffic on our websites.",body2:'Select the types of trackers you consent to, both by us, and third parties. Learn more at <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">data privacy: cookie policy</a> - you can change your choices at any time from the footer of the site.',acceptAll:"Accept all",SavePreferences:"Save preferences"}},zh:{notification:{title:"您的追踪器设置",body1:'我们使用 cookie 和相似的方法来识别访问者和记住访问者的偏好设置,并用来衡量活动的效果和分析 Canonical 旗下所有网站的流量。选择”接受“,您同意我们和受信的第三方来使用这些资料。更多细节或者随时变更您的选择,请阅读我们的<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies"> cookie 策略</a>。',buttonManage:"管理您的追踪器设置",buttonAcceptAll:"接受"},manager:{title:"追踪选项",body1:"我们使用cookie来识别访问者和记住您的偏好设置 它们增强用户体验,使内容和广告个性化,提供社交媒体功能,衡量活动效果和网站流量分析。",body2:'选择您同意授予我们和受信的第三方的追踪类型。点击<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">数据隐私:cookie策略</a>了解更多,您可以在网站底部随时更改您的选择。',acceptAll:"接受全部",SavePreferences:"保存偏好设置"}},ja:{notification:{title:"トラッキング機能の設定",body1:'当社は、訪問者を識別し、設定を記憶するために<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">クッキー</a>および類似の手法を使用しています。また、キャンペーンの効果測定や当社ウェブサイト上のトラフィックの分析にもクッキーを利用します。',body2:"「同意」を選択すると、当社および信頼できる第三者によるこれらの手法の利用に同意したものとみなされます。詳細や同意設定の変更は、いつでも当社のクッキーポリシーでご確認いただけます。",buttonManage:"トラッキング機能の設定の管理",buttonAcceptAll:"同意する"},manager:{title:"トラッキング機能の選択",body1:"当社は、訪問者を識別し、設定を記憶するためにクッキーおよび類似の手法を使用しています。これらの手法は、ユーザー体験の向上、パーソナライズされたコンテンツや広告の表示、ソーシャルメディア機能の提供、キャンペーン効果の測定、そして当社ウェブサイト上のトラフィック分析にも役立ちます。",body2:'当社および信頼できる第三者による、どの種類のトラッキング機能を利用することに同意されるかを選択してください。詳細は<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies" /> データプライバシー:クッキーポリシー</a> をご覧ください。設定は、当社ウェブサイトのフッターからいつでも変更できます。',acceptAll:"すべて同意",SavePreferences:"設定を保存"}}},d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"denied"},u=["security_storage"],p=["ad_storage","ad_user_data","ad_personalization","analytics_storage"],h=["functionality_storage","personalization_storage"],f=["ad_storage","ad_user_data","ad_personalization","analytics_storage","functionality_storage","personalization_storage"],y=function(e){var t=new Date;t.setTime(t.getTime()+31536e6);var n="expires="+t.toUTCString();document.cookie="_cookies_accepted="+e+"; "+n+"; samesite=lax;path=/;",S(e)&&w()},g=function(e){for(var t=document.cookie.split(";"),n="",o="",i=0;i<t.length;i++){for(var a=t[i];" "==a.charAt(0);)a=a.substring(1);o=a.substring(e.length,a.length),0===a.indexOf(e)&&"true"!==o&&(n=o)}return n},b=function(e){return l[e]?l[e]:l.default},v=function(e,t){return e.content[t]?e.content[t]:e.content.default},m=function(e){var t=k(d,e);_(t)},k=function(e,t){var n=a({},e);return u.forEach(function(e){n[e]="granted"}),"performance"===t?p.forEach(function(e){n[e]="granted"}):"functionality"===t?h.forEach(function(e){n[e]="granted"}):"all"===t&&f.forEach(function(e){n[e]="granted"}),n},_=function(e){window.gtag("consent","update",e)},w=function(){"object"===("undefined"==typeof dataLayer?"undefined":r(dataLayer))&&dataLayer.push({event:"pageview"})},S=function(e){return"all"==e||"performance"==e},j=function(e){e.addEventListener("click",function(e){var t=e.target;if(t.closest&&(t=t.closest('[class*="p-accordion__tab"]')),t){var n="true"===t.getAttribute("aria-expanded");!function(e,t){var n=document.getElementById(e.getAttribute("aria-controls"));n&&(e.setAttribute("aria-expanded",t),n.setAttribute("aria-hidden",!t))}(t,!n)}})},E=function(e,t){return function(){y(e),m(e),t()}};function A(){var e=g("_cookies_service_up=");if(e&&"1"===e){var t=g("_cookies_accepted=");t&&fetch("/cookies/set-preferences",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({preferences:{consent:t}})}).catch(function(e){return console.error("Error sending preferences:",e)})}}var L=function(){return n(function t(n,o,i){e(this,t),this.container=n,this.renderManager=o,this.destroyComponent=i},[{key:"getNotificationMarkup",value:function(e){var t=b(e).notification;return'\n <div class="p-modal cookie-notification-modal" id="modal">\n <div class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header grid-row">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content" class="grid-row">\n <div class="grid-col-5">\n <p class="u-no-max-width').concat(t.body2?" u-no-margin--bottom":"",'">').concat(t.body1,"</p>\n ").concat(t.body2?'<p class="u-no-max-width">'.concat(t.body2,"</p> "):"",'\n </div>\n <div class="cookie-notification-buttons grid-col-3 u-vertically-center">\n <p class="u-no-margin--bottom">\n <button class="p-button--link is-inline js-manage">').concat(t.buttonManage,'</button>\n <button class="p-button--positive js-close-all" id="cookie-policy-button-accept-all">').concat(t.buttonAcceptAll,"</button>\n </p>\n </div>\n </div>")}},{key:"render",value:function(e){this.container.innerHTML=this.getNotificationMarkup(e),this.initaliseListeners()}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close-all").addEventListener("click",function(){E("all",e.destroyComponent)(),A()}),this.container.querySelector(".js-manage").addEventListener("click",function(){e.renderManager()})}}])}(),O=function(){return n(function t(n,o,i){e(this,t),this.language=i,this.id=n.id,this.title=v(n,i).title,this.description=v(n,i).description,this.activeText=v(n,i).activeText,this.enableSwitcher=n.enableSwitcher,this.container=o,this.element,this.onChange=n.onChange||function(){},this.render()},[{key:"render",value:function(){var e,t=this.cookieIsTrue(),n=document.createElement("div");n.innerHTML='\n <li class="controls p-accordion__group"> \n <div role="heading" aria-level="3" class="p-accordion__heading">\n <button type="button" class="p-accordion__tab" id="'.concat(this.id,'-tab" aria-controls="').concat(this.id,'-section" aria-expanded="false">\n <span class="p-heading--5 u-no-padding--top u-no-margin--bottom" style="margin-right: 1rem;">').concat(this.title,"</span>\n ").concat(this.enableSwitcher?"\n ".concat('<label class="p-accordion__switch u-align--right u-no-margin--bottom p-switch">\n <input type="checkbox" class="p-switch__input js-'.concat(this.id,'-switch" ').concat((t||!this.enableSwitcher)&&'checked="" ',"\n ").concat(!this.enableSwitcher&&'disabled="disabled"','> \n <span class="p-switch__slider"></span>\n </label>\n '),"\n "):'<span class="p-accordion__switch u-text--muted u-align--right">'.concat(this.activeText,"</span>"),'\n </button>\n \n </div>\n <section class="p-accordion__panel" id="').concat(this.id,'-section" aria-hidden="true" aria-labelledby="').concat(this.id,'-tab">\n <p>').concat(this.description,'</p>\n </section>\n </li>\n <hr class="p-rule--muted" />\n '),this.container.appendChild(n),this.element=n.querySelector(".js-".concat(this.id,"-switch")),null===(e=this.element)||void 0===e||e.addEventListener("change",this.onChange)}},{key:"cookieIsTrue",value:function(){var e=g("_cookies_accepted=");return!(!e||e!==this.id&&"all"!==e)||e&&e===this.id}},{key:"isChecked",value:function(){return!!this.element&&this.element.checked}},{key:"getId",value:function(){return this.id}}])}(),C=function(){return n(function t(n,o){e(this,t),this.container=n,this.controlsStore=[],this.destroyComponent=o},[{key:"getManagerMarkup",value:function(e){var t=b(e).manager;return'\n <div class="p-modal cookie-manager-modal" id="modal">\n <section class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content">\n <p>').concat(t.body1,"</p>\n <p>").concat(t.body2,"</p>\n ").concat(t.body3?"<p>".concat(t.body3,"</p>"):"",'\n <aside class="p-accordion">\n <ul class="p-accordion__list controls">\n </ul>\n </aside>\n <p class="u-no-margin--bottom u-float-right">\n <button class="p-button--positive js-close" id="cookie-policy-button-accept-all">').concat(t.acceptAll,'</button>\n <button class="p-button js-save-preferences">').concat(t.SavePreferences,"</button>\n </p>\n </div>\n </section>\n </div>")}},{key:"render",value:function(e){var t=this;this.container.innerHTML=this.getManagerMarkup(e);var n=this.container.querySelector(".controls");s.forEach(function(o){var i=new O(a(a({},o),{},{onChange:function(){return t.updateAcceptButton()}}),n,e);t.controlsStore.push(i)}),this.updateAcceptButton(),this.initaliseListeners()}},{key:"updateAcceptButton",value:function(){var e=this.controlsStore.filter(function(e){return"essential"!==e.getId()}).every(function(e){return e.isChecked()});this.container.querySelector(".js-close").style.display=e?"none":"inline-block"}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close").addEventListener("click",function(){E("all",e.destroyComponent)(),A()});for(var t=document.querySelectorAll(".p-accordion"),n=0,o=t.length;n<o;n++)j(t[n]);this.container.querySelector(".js-save-preferences").addEventListener("click",function(){e.savePreferences(),A(),e.destroyComponent()})}},{key:"savePreferences",value:function(){var e=this.controlsStore.filter(function(e){return e.isChecked()});this.controlsStore.length-1===e.length?y("all"):0===e.length?y("essential"):this.controlsStore.forEach(function(e){e.isChecked()&&y(e.getId())}),function(e){var t=e.filter(function(e){return e.isChecked()}),n=a({},d);t.forEach(function(e){n=k(n,e.id)}),_(n)}(this.controlsStore)}}])}();window.gtag||(window.dataLayer=window.dataLayer||[],window.gtag=function(){dataLayer.push(arguments)},window.gtag("consent","default",d));var P=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=null,n=document.documentElement.lang,o=!1,i=function(e){e&&e.preventDefault(),null===t&&((t=document.createElement("dialog")).classList.add("cookie-policy"),t.style.pointerEvents="none",t.setAttribute("open",!0),t.style.borderStyle="none",document.body.appendChild(t),new L(t,a,c).render(n),document.getElementById("cookie-policy-button-accept-all").focus())},a=function(){new C(t,c).render(n)},c=function(){"function"==typeof e&&e(),document.body.removeChild(t),t=null},r=function(){if(!o){var e;o=!0,(e=g("_cookies_accepted="))&&m(e);var t=document.querySelector(".js-revoke-cookie-manager");t&&t.addEventListener("click",i),function(){var e=g("_cookies_accepted=");return!e||"true"==e||"unset"==e}()&&"hide"!==new URLSearchParams(window.location.search).get("cp")&&i()}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",r,!1):r()},T=function(e){document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"))},x=T("_cookies_accepted");function z(){var e,t;if(("all"===(null===(e=x=T("_cookies_accepted"))||void 0===e?void 0:e[2])||"performance"===(null===(t=x)||void 0===t?void 0:t[2]))&&!T("user_id")){var n=([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)});document.cookie="user_id="+n+";max-age=31536000;",dataLayer.push({user_id:n})}}x?(z(),P()):P(z)})(); No newline at end of file
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bundle.js sets a persistent user_id cookie (document.cookie = "user_id=...;max-age=...") without path=/ and without SameSite/Secure attributes. This can lead to path-scoped duplicates and weaker cookie handling than intended. Set cookie attributes explicitly (at least path=/; SameSite=Lax; Secure on HTTPS) to make behavior consistent and reduce risk of unintended exposure.

Suggested change
(()=>{"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function t(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,c(o.key),o)}}function n(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),Object.defineProperty(e,"prototype",{writable:!1}),e}function o(e,t,n){return(t=c(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach(function(t){o(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function c(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}var s=[{id:"essential",enableSwitcher:!1,content:{default:{title:"Essential",description:"Enables the core functionality on our websites, such as navigation, access to secure areas, video players and payments. Our websites cannot function properly without these cookies; they can only be disabled by changing your browser preferences.",activeText:"Always active"},zh:{title:"必要性",description:"启用网站核心功能,例如导航,访问安全区域,视频播放器和支付。没有这些cookie网站不能正常工作;它们仅可通过修改浏览器偏好设置禁用。",activeText:"默认接受"},ja:{title:"エッセンシャル",description:"当社ウェブサイトの基本的な機能(ナビゲーション、保護された情報へのアクセス、動画プレーヤー、支払いなど)を有効にするために必要なクッキーです。これらのクッキーが無効になっている場合、当社ウェブサイトは正しく動作しません。 これらはブラウザ設定の変更によってのみ無効化できます。",activeText:"常に有効"}}},{id:"performance",enableSwitcher:!0,content:{default:{title:"Performance",description:"Collects information on usage on our websites, for example, which pages are most frequently visited."},zh:{title:"表现性",description:"网站使用信息收集,例如哪些网页被频繁访问。"},ja:{title:"パフォーマンス",description:"当社ウェブサイトの利用状況(例:どのページの訪問頻度が高いかなど)に関する情報を収集します。"}}},{id:"functionality",enableSwitcher:!0,content:{default:{title:"Functional",description:"Recognizes you when you return to our websites. This enables us to personalize content, greet you by name, remember your preferences, and helps you share pages on social networks."},zh:{title:"功能性",description:"当你返回到我们网站时能识别您。这使得我们能个性化内容,欢迎您,记住您的偏好设置,以及帮助您分享网页到社交媒体。"},ja:{title:"機能性",description:"再訪時にユーザーを識別し、パーソナライズされたコンテンツの表示、お客様のお名前を用いた挨拶メッセージ、ユーザー設定の記憶を可能にします。また、ソーシャルネットワークでページを共有しやすくする機能にも使用されます。"}}}],l={default:{notification:{title:"Your tracker settings",body1:'We use cookies and similar methods to recognize visitors and remember preferences. We also use them to measure campaign effectiveness and analyze traffic on our websites. By selecting ‘Accept‘, you consent to the use of these methods by us and trusted third parties. For further details or to change your consent choices at any time see our <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">cookie policy</a>.',buttonManage:"Manage your tracker settings",buttonAcceptAll:"Accept all"},manager:{title:"Tracking choices",body1:"We use cookies to recognize visitors and remember your preferences. They enhance user experience, personalize content and ads, provide social media features, measure campaign effectiveness, and analyze traffic on our websites.",body2:'Select the types of trackers you consent to, both by us, and third parties. Learn more at <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">data privacy: cookie policy</a> - you can change your choices at any time from the footer of the site.',acceptAll:"Accept all",SavePreferences:"Save preferences"}},zh:{notification:{title:"您的追踪器设置",body1:'我们使用 cookie 和相似的方法来识别访问者和记住访问者的偏好设置,并用来衡量活动的效果和分析 Canonical 旗下所有网站的流量。选择”接受“,您同意我们和受信的第三方来使用这些资料。更多细节或者随时变更您的选择,请阅读我们的<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies"> cookie 策略</a>。',buttonManage:"管理您的追踪器设置",buttonAcceptAll:"接受"},manager:{title:"追踪选项",body1:"我们使用cookie来识别访问者和记住您的偏好设置 它们增强用户体验,使内容和广告个性化,提供社交媒体功能,衡量活动效果和网站流量分析。",body2:'选择您同意授予我们和受信的第三方的追踪类型。点击<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">数据隐私:cookie策略</a>了解更多,您可以在网站底部随时更改您的选择。',acceptAll:"接受全部",SavePreferences:"保存偏好设置"}},ja:{notification:{title:"トラッキング機能の設定",body1:'当社は、訪問者を識別し、設定を記憶するために<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">クッキー</a>および類似の手法を使用しています。また、キャンペーンの効果測定や当社ウェブサイト上のトラフィックの分析にもクッキーを利用します。',body2:"「同意」を選択すると、当社および信頼できる第三者によるこれらの手法の利用に同意したものとみなされます。詳細や同意設定の変更は、いつでも当社のクッキーポリシーでご確認いただけます。",buttonManage:"トラッキング機能の設定の管理",buttonAcceptAll:"同意する"},manager:{title:"トラッキング機能の選択",body1:"当社は、訪問者を識別し、設定を記憶するためにクッキーおよび類似の手法を使用しています。これらの手法は、ユーザー体験の向上、パーソナライズされたコンテンツや広告の表示、ソーシャルメディア機能の提供、キャンペーン効果の測定、そして当社ウェブサイト上のトラフィック分析にも役立ちます。",body2:'当社および信頼できる第三者による、どの種類のトラッキング機能を利用することに同意されるかを選択してください。詳細は<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies" /> データプライバシー:クッキーポリシー</a> をご覧ください。設定は、当社ウェブサイトのフッターからいつでも変更できます。',acceptAll:"すべて同意",SavePreferences:"設定を保存"}}},d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"denied"},u=["security_storage"],p=["ad_storage","ad_user_data","ad_personalization","analytics_storage"],h=["functionality_storage","personalization_storage"],f=["ad_storage","ad_user_data","ad_personalization","analytics_storage","functionality_storage","personalization_storage"],y=function(e){var t=new Date;t.setTime(t.getTime()+31536e6);var n="expires="+t.toUTCString();document.cookie="_cookies_accepted="+e+"; "+n+"; samesite=lax;path=/;",S(e)&&w()},g=function(e){for(var t=document.cookie.split(";"),n="",o="",i=0;i<t.length;i++){for(var a=t[i];" "==a.charAt(0);)a=a.substring(1);o=a.substring(e.length,a.length),0===a.indexOf(e)&&"true"!==o&&(n=o)}return n},b=function(e){return l[e]?l[e]:l.default},v=function(e,t){return e.content[t]?e.content[t]:e.content.default},m=function(e){var t=k(d,e);_(t)},k=function(e,t){var n=a({},e);return u.forEach(function(e){n[e]="granted"}),"performance"===t?p.forEach(function(e){n[e]="granted"}):"functionality"===t?h.forEach(function(e){n[e]="granted"}):"all"===t&&f.forEach(function(e){n[e]="granted"}),n},_=function(e){window.gtag("consent","update",e)},w=function(){"object"===("undefined"==typeof dataLayer?"undefined":r(dataLayer))&&dataLayer.push({event:"pageview"})},S=function(e){return"all"==e||"performance"==e},j=function(e){e.addEventListener("click",function(e){var t=e.target;if(t.closest&&(t=t.closest('[class*="p-accordion__tab"]')),t){var n="true"===t.getAttribute("aria-expanded");!function(e,t){var n=document.getElementById(e.getAttribute("aria-controls"));n&&(e.setAttribute("aria-expanded",t),n.setAttribute("aria-hidden",!t))}(t,!n)}})},E=function(e,t){return function(){y(e),m(e),t()}};function A(){var e=g("_cookies_service_up=");if(e&&"1"===e){var t=g("_cookies_accepted=");t&&fetch("/cookies/set-preferences",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({preferences:{consent:t}})}).catch(function(e){return console.error("Error sending preferences:",e)})}}var L=function(){return n(function t(n,o,i){e(this,t),this.container=n,this.renderManager=o,this.destroyComponent=i},[{key:"getNotificationMarkup",value:function(e){var t=b(e).notification;return'\n <div class="p-modal cookie-notification-modal" id="modal">\n <div class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header grid-row">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content" class="grid-row">\n <div class="grid-col-5">\n <p class="u-no-max-width').concat(t.body2?" u-no-margin--bottom":"",'">').concat(t.body1,"</p>\n ").concat(t.body2?'<p class="u-no-max-width">'.concat(t.body2,"</p> "):"",'\n </div>\n <div class="cookie-notification-buttons grid-col-3 u-vertically-center">\n <p class="u-no-margin--bottom">\n <button class="p-button--link is-inline js-manage">').concat(t.buttonManage,'</button>\n <button class="p-button--positive js-close-all" id="cookie-policy-button-accept-all">').concat(t.buttonAcceptAll,"</button>\n </p>\n </div>\n </div>")}},{key:"render",value:function(e){this.container.innerHTML=this.getNotificationMarkup(e),this.initaliseListeners()}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close-all").addEventListener("click",function(){E("all",e.destroyComponent)(),A()}),this.container.querySelector(".js-manage").addEventListener("click",function(){e.renderManager()})}}])}(),O=function(){return n(function t(n,o,i){e(this,t),this.language=i,this.id=n.id,this.title=v(n,i).title,this.description=v(n,i).description,this.activeText=v(n,i).activeText,this.enableSwitcher=n.enableSwitcher,this.container=o,this.element,this.onChange=n.onChange||function(){},this.render()},[{key:"render",value:function(){var e,t=this.cookieIsTrue(),n=document.createElement("div");n.innerHTML='\n <li class="controls p-accordion__group"> \n <div role="heading" aria-level="3" class="p-accordion__heading">\n <button type="button" class="p-accordion__tab" id="'.concat(this.id,'-tab" aria-controls="').concat(this.id,'-section" aria-expanded="false">\n <span class="p-heading--5 u-no-padding--top u-no-margin--bottom" style="margin-right: 1rem;">').concat(this.title,"</span>\n ").concat(this.enableSwitcher?"\n ".concat('<label class="p-accordion__switch u-align--right u-no-margin--bottom p-switch">\n <input type="checkbox" class="p-switch__input js-'.concat(this.id,'-switch" ').concat((t||!this.enableSwitcher)&&'checked="" ',"\n ").concat(!this.enableSwitcher&&'disabled="disabled"','> \n <span class="p-switch__slider"></span>\n </label>\n '),"\n "):'<span class="p-accordion__switch u-text--muted u-align--right">'.concat(this.activeText,"</span>"),'\n </button>\n \n </div>\n <section class="p-accordion__panel" id="').concat(this.id,'-section" aria-hidden="true" aria-labelledby="').concat(this.id,'-tab">\n <p>').concat(this.description,'</p>\n </section>\n </li>\n <hr class="p-rule--muted" />\n '),this.container.appendChild(n),this.element=n.querySelector(".js-".concat(this.id,"-switch")),null===(e=this.element)||void 0===e||e.addEventListener("change",this.onChange)}},{key:"cookieIsTrue",value:function(){var e=g("_cookies_accepted=");return!(!e||e!==this.id&&"all"!==e)||e&&e===this.id}},{key:"isChecked",value:function(){return!!this.element&&this.element.checked}},{key:"getId",value:function(){return this.id}}])}(),C=function(){return n(function t(n,o){e(this,t),this.container=n,this.controlsStore=[],this.destroyComponent=o},[{key:"getManagerMarkup",value:function(e){var t=b(e).manager;return'\n <div class="p-modal cookie-manager-modal" id="modal">\n <section class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content">\n <p>').concat(t.body1,"</p>\n <p>").concat(t.body2,"</p>\n ").concat(t.body3?"<p>".concat(t.body3,"</p>"):"",'\n <aside class="p-accordion">\n <ul class="p-accordion__list controls">\n </ul>\n </aside>\n <p class="u-no-margin--bottom u-float-right">\n <button class="p-button--positive js-close" id="cookie-policy-button-accept-all">').concat(t.acceptAll,'</button>\n <button class="p-button js-save-preferences">').concat(t.SavePreferences,"</button>\n </p>\n </div>\n </section>\n </div>")}},{key:"render",value:function(e){var t=this;this.container.innerHTML=this.getManagerMarkup(e);var n=this.container.querySelector(".controls");s.forEach(function(o){var i=new O(a(a({},o),{},{onChange:function(){return t.updateAcceptButton()}}),n,e);t.controlsStore.push(i)}),this.updateAcceptButton(),this.initaliseListeners()}},{key:"updateAcceptButton",value:function(){var e=this.controlsStore.filter(function(e){return"essential"!==e.getId()}).every(function(e){return e.isChecked()});this.container.querySelector(".js-close").style.display=e?"none":"inline-block"}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close").addEventListener("click",function(){E("all",e.destroyComponent)(),A()});for(var t=document.querySelectorAll(".p-accordion"),n=0,o=t.length;n<o;n++)j(t[n]);this.container.querySelector(".js-save-preferences").addEventListener("click",function(){e.savePreferences(),A(),e.destroyComponent()})}},{key:"savePreferences",value:function(){var e=this.controlsStore.filter(function(e){return e.isChecked()});this.controlsStore.length-1===e.length?y("all"):0===e.length?y("essential"):this.controlsStore.forEach(function(e){e.isChecked()&&y(e.getId())}),function(e){var t=e.filter(function(e){return e.isChecked()}),n=a({},d);t.forEach(function(e){n=k(n,e.id)}),_(n)}(this.controlsStore)}}])}();window.gtag||(window.dataLayer=window.dataLayer||[],window.gtag=function(){dataLayer.push(arguments)},window.gtag("consent","default",d));var P=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=null,n=document.documentElement.lang,o=!1,i=function(e){e&&e.preventDefault(),null===t&&((t=document.createElement("dialog")).classList.add("cookie-policy"),t.style.pointerEvents="none",t.setAttribute("open",!0),t.style.borderStyle="none",document.body.appendChild(t),new L(t,a,c).render(n),document.getElementById("cookie-policy-button-accept-all").focus())},a=function(){new C(t,c).render(n)},c=function(){"function"==typeof e&&e(),document.body.removeChild(t),t=null},r=function(){if(!o){var e;o=!0,(e=g("_cookies_accepted="))&&m(e);var t=document.querySelector(".js-revoke-cookie-manager");t&&t.addEventListener("click",i),function(){var e=g("_cookies_accepted=");return!e||"true"==e||"unset"==e}()&&"hide"!==new URLSearchParams(window.location.search).get("cp")&&i()}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",r,!1):r()},T=function(e){document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"))},x=T("_cookies_accepted");function z(){var e,t;if(("all"===(null===(e=x=T("_cookies_accepted"))||void 0===e?void 0:e[2])||"performance"===(null===(t=x)||void 0===t?void 0:t[2]))&&!T("user_id")){var n=([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)});document.cookie="user_id="+n+";max-age=31536000;",dataLayer.push({user_id:n})}}x?(z(),P()):P(z)})();
(()=>{"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function t(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,c(o.key),o)}}function n(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),Object.defineProperty(e,"prototype",{writable:!1}),e}function o(e,t,n){return(t=c(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach(function(t){o(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function c(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}var s=[{id:"essential",enableSwitcher:!1,content:{default:{title:"Essential",description:"Enables the core functionality on our websites, such as navigation, access to secure areas, video players and payments. Our websites cannot function properly without these cookies; they can only be disabled by changing your browser preferences.",activeText:"Always active"},zh:{title:"必要性",description:"启用网站核心功能,例如导航,访问安全区域,视频播放器和支付。没有这些cookie网站不能正常工作;它们仅可通过修改浏览器偏好设置禁用。",activeText:"默认接受"},ja:{title:"エッセンシャル",description:"当社ウェブサイトの基本的な機能(ナビゲーション、保護された情報へのアクセス、動画プレーヤー、支払いなど)を有効にするために必要なクッキーです。これらのクッキーが無効になっている場合、当社ウェブサイトは正しく動作しません。 これらはブラウザ設定の変更によってのみ無効化できます。",activeText:"常に有効"}}},{id:"performance",enableSwitcher:!0,content:{default:{title:"Performance",description:"Collects information on usage on our websites, for example, which pages are most frequently visited."},zh:{title:"表现性",description:"网站使用信息收集,例如哪些网页被频繁访问。"},ja:{title:"パフォーマンス",description:"当社ウェブサイトの利用状況(例:どのページの訪問頻度が高いかなど)に関する情報を収集します。"}}},{id:"functionality",enableSwitcher:!0,content:{default:{title:"Functional",description:"Recognizes you when you return to our websites. This enables us to personalize content, greet you by name, remember your preferences, and helps you share pages on social networks."},zh:{title:"功能性",description:"当你返回到我们网站时能识别您。这使得我们能个性化内容,欢迎您,记住您的偏好设置,以及帮助您分享网页到社交媒体。"},ja:{title:"機能性",description:"再訪時にユーザーを識別し、パーソナライズされたコンテンツの表示、お客様のお名前を用いた挨拶メッセージ、ユーザー設定の記憶を可能にします。また、ソーシャルネットワークでページを共有しやすくする機能にも使用されます。"}}}],l={default:{notification:{title:"Your tracker settings",body1:'We use cookies and similar methods to recognize visitors and remember preferences. We also use them to measure campaign effectiveness and analyze traffic on our websites. By selecting ‘Accept‘, you consent to the use of these methods by us and trusted third parties. For further details or to change your consent choices at any time see our <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">cookie policy</a>.',buttonManage:"Manage your tracker settings",buttonAcceptAll:"Accept all"},manager:{title:"Tracking choices",body1:"We use cookies to recognize visitors and remember your preferences. They enhance user experience, personalize content and ads, provide social media features, measure campaign effectiveness, and analyze traffic on our websites.",body2:'Select the types of trackers you consent to, both by us, and third parties. Learn more at <a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">data privacy: cookie policy</a> - you can change your choices at any time from the footer of the site.',acceptAll:"Accept all",SavePreferences:"Save preferences"}},zh:{notification:{title:"您的追踪器设置",body1:'我们使用 cookie 和相似的方法来识别访问者和记住访问者的偏好设置,并用来衡量活动的效果和分析 Canonical 旗下所有网站的流量。选择”接受“,您同意我们和受信的第三方来使用这些资料。更多细节或者随时变更您的选择,请阅读我们的<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies"> cookie 策略</a>。',buttonManage:"管理您的追踪器设置",buttonAcceptAll:"接受"},manager:{title:"追踪选项",body1:"我们使用cookie来识别访问者和记住您的偏好设置 它们增强用户体验,使内容和广告个性化,提供社交媒体功能,衡量活动效果和网站流量分析。",body2:'选择您同意授予我们和受信的第三方的追踪类型。点击<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">数据隐私:cookie策略</a>了解更多,您可以在网站底部随时更改您的选择。',acceptAll:"接受全部",SavePreferences:"保存偏好设置"}},ja:{notification:{title:"トラッキング機能の設定",body1:'当社は、訪問者を識別し、設定を記憶するために<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies">クッキー</a>および類似の手法を使用しています。また、キャンペーンの効果測定や当社ウェブサイト上のトラフィックの分析にもクッキーを利用します。',body2:"「同意」を選択すると、当社および信頼できる第三者によるこれらの手法の利用に同意したものとみなされます。詳細や同意設定の変更は、いつでも当社のクッキーポリシーでご確認いただけます。",buttonManage:"トラッキング機能の設定の管理",buttonAcceptAll:"同意する"},manager:{title:"トラッキング機能の選択",body1:"当社は、訪問者を識別し、設定を記憶するためにクッキーおよび類似の手法を使用しています。これらの手法は、ユーザー体験の向上、パーソナライズされたコンテンツや広告の表示、ソーシャルメディア機能の提供、キャンペーン効果の測定、そして当社ウェブサイト上のトラフィック分析にも役立ちます。",body2:'当社および信頼できる第三者による、どの種類のトラッキング機能を利用することに同意されるかを選択してください。詳細は<a href="https://canonical.com/legal/data-privacy?cp=hide#cookies" /> データプライバシー:クッキーポリシー</a> をご覧ください。設定は、当社ウェブサイトのフッターからいつでも変更できます。',acceptAll:"すべて同意",SavePreferences:"設定を保存"}}},d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"denied"},u=["security_storage"],p=["ad_storage","ad_user_data","ad_personalization","analytics_storage"],h=["functionality_storage","personalization_storage"],f=["ad_storage","ad_user_data","ad_personalization","analytics_storage","functionality_storage","personalization_storage"],y=function(e){var t=new Date;t.setTime(t.getTime()+31536e6);var n="expires="+t.toUTCString();document.cookie="_cookies_accepted="+e+"; "+n+"; samesite=lax;path=/;",S(e)&&w()},g=function(e){for(var t=document.cookie.split(";"),n="",o="",i=0;i<t.length;i++){for(var a=t[i];" "==a.charAt(0);)a=a.substring(1);o=a.substring(e.length,a.length),0===a.indexOf(e)&&"true"!==o&&(n=o)}return n},b=function(e){return l[e]?l[e]:l.default},v=function(e,t){return e.content[t]?e.content[t]:e.content.default},m=function(e){var t=k(d,e);_(t)},k=function(e,t){var n=a({},e);return u.forEach(function(e){n[e]="granted"}),"performance"===t?p.forEach(function(e){n[e]="granted"}):"functionality"===t?h.forEach(function(e){n[e]="granted"}):"all"===t&&f.forEach(function(e){n[e]="granted"}),n},_=function(e){window.gtag("consent","update",e)},w=function(){"object"===("undefined"==typeof dataLayer?"undefined":r(dataLayer))&&dataLayer.push({event:"pageview"})},S=function(e){return"all"==e||"performance"==e},j=function(e){e.addEventListener("click",function(e){var t=e.target;if(t.closest&&(t=t.closest('[class*="p-accordion__tab"]')),t){var n="true"===t.getAttribute("aria-expanded");!function(e,t){var n=document.getElementById(e.getAttribute("aria-controls"));n&&(e.setAttribute("aria-expanded",t),n.setAttribute("aria-hidden",!t))}(t,!n)}})},E=function(e,t){return function(){y(e),m(e),t()}};function A(){var e=g("_cookies_service_up=");if(e&&"1"===e){var t=g("_cookies_accepted=");t&&fetch("/cookies/set-preferences",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({preferences:{consent:t}})}).catch(function(e){return console.error("Error sending preferences:",e)})}}var L=function(){return n(function t(n,o,i){e(this,t),this.container=n,this.renderManager=o,this.destroyComponent=i},[{key:"getNotificationMarkup",value:function(e){var t=b(e).notification;return'\n <div class="p-modal cookie-notification-modal" id="modal">\n <div class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header grid-row">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content" class="grid-row">\n <div class="grid-col-5">\n <p class="u-no-max-width').concat(t.body2?" u-no-margin--bottom":"",'">').concat(t.body1,"</p>\n ").concat(t.body2?'<p class="u-no-max-width">'.concat(t.body2,"</p> "):"",'\n </div>\n <div class="cookie-notification-buttons grid-col-3 u-vertically-center">\n <p class="u-no-margin--bottom">\n <button class="p-button--link is-inline js-manage">').concat(t.buttonManage,'</button>\n <button class="p-button--positive js-close-all" id="cookie-policy-button-accept-all">').concat(t.buttonAcceptAll,"</button>\n </p>\n </div>\n </div>")}},{key:"render",value:function(e){this.container.innerHTML=this.getNotificationMarkup(e),this.initaliseListeners()}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close-all").addEventListener("click",function(){E("all",e.destroyComponent)(),A()}),this.container.querySelector(".js-manage").addEventListener("click",function(){e.renderManager()})}}])}(),O=function(){return n(function t(n,o,i){e(this,t),this.language=i,this.id=n.id,this.title=v(n,i).title,this.description=v(n,i).description,this.activeText=v(n,i).activeText,this.enableSwitcher=n.enableSwitcher,this.container=o,this.element,this.onChange=n.onChange||function(){},this.render()},[{key:"render",value:function(){var e,t=this.cookieIsTrue(),n=document.createElement("div");n.innerHTML='\n <li class="controls p-accordion__group"> \n <div role="heading" aria-level="3" class="p-accordion__heading">\n <button type="button" class="p-accordion__tab" id="'.concat(this.id,'-tab" aria-controls="').concat(this.id,'-section" aria-expanded="false">\n <span class="p-heading--5 u-no-padding--top u-no-margin--bottom" style="margin-right: 1rem;">').concat(this.title,"</span>\n ").concat(this.enableSwitcher?"\n ".concat('<label class="p-accordion__switch u-align--right u-no-margin--bottom p-switch">\n <input type="checkbox" class="p-switch__input js-'.concat(this.id,'-switch" ').concat((t||!this.enableSwitcher)&&'checked="" ',"\n ").concat(!this.enableSwitcher&&'disabled="disabled"','> \n <span class="p-switch__slider"></span>\n </label>\n '),"\n "):'<span class="p-accordion__switch u-text--muted u-align--right">'.concat(this.activeText,"</span>"),'\n </button>\n \n </div>\n <section class="p-accordion__panel" id="').concat(this.id,'-section" aria-hidden="true" aria-labelledby="').concat(this.id,'-tab">\n <p>').concat(this.description,'</p>\n </section>\n </li>\n <hr class="p-rule--muted" />\n '),this.container.appendChild(n),this.element=n.querySelector(".js-".concat(this.id,"-switch")),null===(e=this.element)||void 0===e||e.addEventListener("change",this.onChange)}},{key:"cookieIsTrue",value:function(){var e=g("_cookies_accepted=");return!(!e||e!==this.id&&"all"!==e)||e&&e===this.id}},{key:"isChecked",value:function(){return!!this.element&&this.element.checked}},{key:"getId",value:function(){return this.id}}])}(),C=function(){return n(function t(n,o){e(this,t),this.container=n,this.controlsStore=[],this.destroyComponent=o},[{key:"getManagerMarkup",value:function(e){var t=b(e).manager;return'\n <div class="p-modal cookie-manager-modal" id="modal">\n <section class="p-modal__dialog" role="dialog" aria-labelledby="cookie-policy-title" aria-describedby="cookie-policy-content">\n <header class="p-modal__header">\n <h2 class="p-modal__title p-heading--4" id="cookie-policy-title">'.concat(t.title,'</h2>\n </header>\n <div id="cookie-policy-content">\n <p>').concat(t.body1,"</p>\n <p>").concat(t.body2,"</p>\n ").concat(t.body3?"<p>".concat(t.body3,"</p>"):"",'\n <aside class="p-accordion">\n <ul class="p-accordion__list controls">\n </ul>\n </aside>\n <p class="u-no-margin--bottom u-float-right">\n <button class="p-button--positive js-close" id="cookie-policy-button-accept-all">').concat(t.acceptAll,'</button>\n <button class="p-button js-save-preferences">').concat(t.SavePreferences,"</button>\n </p>\n </div>\n </section>\n </div>")}},{key:"render",value:function(e){var t=this;this.container.innerHTML=this.getManagerMarkup(e);var n=this.container.querySelector(".controls");s.forEach(function(o){var i=new O(a(a({},o),{},{onChange:function(){return t.updateAcceptButton()}}),n,e);t.controlsStore.push(i)}),this.updateAcceptButton(),this.initaliseListeners()}},{key:"updateAcceptButton",value:function(){var e=this.controlsStore.filter(function(e){return"essential"!==e.getId()}).every(function(e){return e.isChecked()});this.container.querySelector(".js-close").style.display=e?"none":"inline-block"}},{key:"initaliseListeners",value:function(){var e=this;this.container.querySelector(".js-close").addEventListener("click",function(){E("all",e.destroyComponent)(),A()});for(var t=document.querySelectorAll(".p-accordion"),n=0,o=t.length;n<o;n++)j(t[n]);this.container.querySelector(".js-save-preferences").addEventListener("click",function(){e.savePreferences(),A(),e.destroyComponent()})}},{key:"savePreferences",value:function(){var e=this.controlsStore.filter(function(e){return e.isChecked()});this.controlsStore.length-1===e.length?y("all"):0===e.length?y("essential"):this.controlsStore.forEach(function(e){e.isChecked()&&y(e.getId())}),function(e){var t=e.filter(function(e){return e.isChecked()}),n=a({},d);t.forEach(function(e){n=k(n,e.id)}),_(n)}(this.controlsStore)}}])}();window.gtag||(window.dataLayer=window.dataLayer||[],window.gtag=function(){dataLayer.push(arguments)},window.gtag("consent","default",d));var P=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=null,n=document.documentElement.lang,o=!1,i=function(e){e&&e.preventDefault(),null===t&&((t=document.createElement("dialog")).classList.add("cookie-policy"),t.style.pointerEvents="none",t.setAttribute("open",!0),t.style.borderStyle="none",document.body.appendChild(t),new L(t,a,c).render(n),document.getElementById("cookie-policy-button-accept-all").focus())},a=function(){new C(t,c).render(n)},c=function(){"function"==typeof e&&e(),document.body.removeChild(t),t=null},r=function(){if(!o){var e;o=!0,(e=g("_cookies_accepted="))&&m(e);var t=document.querySelector(".js-revoke-cookie-manager");t&&t.addEventListener("click",i),function(){var e=g("_cookies_accepted=");return!e||"true"==e||"unset"==e}()&&"hide"!==new URLSearchParams(window.location.search).get("cp")&&i()}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",r,!1):r()},T=function(e){document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"))},x=T("_cookies_accepted");function z(){var e,t;if(("all"===(null===(e=x=T("_cookies_accepted"))||void 0===e?void 0:e[2])||"performance"===(null===(t=x)||void 0===t?void 0:t[2]))&&!T("user_id")){var n=([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,function(e){return(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)}),o="user_id="+n+";max-age=31536000;path=/;SameSite=Lax";"https:"===location.protocol&&(o+=";Secure"),document.cookie=o,dataLayer.push({user_id:n})}}x?(z(),P()):P(z)})();

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +28
.cookie-policy hr.is-fixed-width {
margin-left: auto;
margin-right: auto;
max-width: 78rem;
width: calc(100% - 2rem)
}

@media(min-width: 620px) {
.cookie-policy hr.is-fixed-width {
max-width:77rem;
width: calc(100% - 3rem)
}
}

.row .cookie-policy hr.is-fixed-width,.cookie-policy .row hr.is-fixed-width,.grid-row .cookie-policy hr.is-fixed-width,.cookie-policy .grid-row hr.is-fixed-width,.u-fixed-width .cookie-policy hr.is-fixed-width,.cookie-policy .u-fixed-width hr.is-fixed-width {
width: 100%
}

.cookie-policy .is-accent.p-heading--4,.cookie-policy .is-accent.p-modal__title,.cookie-policy h4.is-accent,.cookie-policy .is-accent.p-heading--3,.cookie-policy h3.is-accent,.cookie-policy .is-accent.p-heading--2,.cookie-policy h2.is-accent,.cookie-policy .is-accent.p-heading--1,.cookie-policy h1.is-accent {
color: var(--vf-color-accent)
}

.cookie-policy h6,.cookie-policy h5,.cookie-policy h4,.cookie-policy h3,.cookie-policy h2,.cookie-policy h1,.cookie-policy .p-heading--6,.cookie-policy h6,.cookie-policy .p-heading--5,.cookie-policy h5,.cookie-policy .p-heading--4,.cookie-policy .p-modal__title,.cookie-policy h4,.cookie-policy .p-heading--3,.cookie-policy h3,.cookie-policy .p-heading--display,.cookie-policy .p-heading--2,.cookie-policy h2,.cookie-policy .p-heading--1,.cookie-policy h1 {
font-style: normal;
margin-top: 0;
max-width: 40em
}

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a very large, unminified CSS file (~3.6k lines) to be loaded on every docs page. That increases page weight and can noticeably slow docs loads on low-bandwidth/mobile connections. Consider shipping a minified version and/or trimming the stylesheet to only the rules needed for the cookie banner, to reduce the static asset footprint.

Suggested change
.cookie-policy hr.is-fixed-width {
margin-left: auto;
margin-right: auto;
max-width: 78rem;
width: calc(100% - 2rem)
}
@media(min-width: 620px) {
.cookie-policy hr.is-fixed-width {
max-width:77rem;
width: calc(100% - 3rem)
}
}
.row .cookie-policy hr.is-fixed-width,.cookie-policy .row hr.is-fixed-width,.grid-row .cookie-policy hr.is-fixed-width,.cookie-policy .grid-row hr.is-fixed-width,.u-fixed-width .cookie-policy hr.is-fixed-width,.cookie-policy .u-fixed-width hr.is-fixed-width {
width: 100%
}
.cookie-policy .is-accent.p-heading--4,.cookie-policy .is-accent.p-modal__title,.cookie-policy h4.is-accent,.cookie-policy .is-accent.p-heading--3,.cookie-policy h3.is-accent,.cookie-policy .is-accent.p-heading--2,.cookie-policy h2.is-accent,.cookie-policy .is-accent.p-heading--1,.cookie-policy h1.is-accent {
color: var(--vf-color-accent)
}
.cookie-policy h6,.cookie-policy h5,.cookie-policy h4,.cookie-policy h3,.cookie-policy h2,.cookie-policy h1,.cookie-policy .p-heading--6,.cookie-policy h6,.cookie-policy .p-heading--5,.cookie-policy h5,.cookie-policy .p-heading--4,.cookie-policy .p-modal__title,.cookie-policy h4,.cookie-policy .p-heading--3,.cookie-policy h3,.cookie-policy .p-heading--display,.cookie-policy .p-heading--2,.cookie-policy h2,.cookie-policy .p-heading--1,.cookie-policy h1 {
font-style: normal;
margin-top: 0;
max-width: 40em
}
.cookie-policy hr.is-fixed-width{margin-left:auto;margin-right:auto;max-width:78rem;width:calc(100% - 2rem)}
@media(min-width:620px){.cookie-policy hr.is-fixed-width{max-width:77rem;width:calc(100% - 3rem)}}
.row .cookie-policy hr.is-fixed-width,.cookie-policy .row hr.is-fixed-width,.grid-row .cookie-policy hr.is-fixed-width,.cookie-policy .grid-row hr.is-fixed-width,.u-fixed-width .cookie-policy hr.is-fixed-width,.cookie-policy .u-fixed-width hr.is-fixed-width{width:100%}
.cookie-policy .is-accent.p-heading--4,.cookie-policy .is-accent.p-modal__title,.cookie-policy h4.is-accent,.cookie-policy .is-accent.p-heading--3,.cookie-policy h3.is-accent,.cookie-policy .is-accent.p-heading--2,.cookie-policy h2.is-accent,.cookie-policy .is-accent.p-heading--1,.cookie-policy h1.is-accent{color:var(--vf-color-accent)}
.cookie-policy h6,.cookie-policy h5,.cookie-policy h4,.cookie-policy h3,.cookie-policy h2,.cookie-policy h1,.cookie-policy .p-heading--6,.cookie-policy .p-heading--5,.cookie-policy .p-heading--4,.cookie-policy .p-modal__title,.cookie-policy .p-heading--3,.cookie-policy .p-heading--display,.cookie-policy .p-heading--2,.cookie-policy .p-heading--1{font-style:normal;margin-top:0;max-width:40em}

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +21
<!-- Google Tag Manager -->
<script>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
var f = d.getElementsByTagName(s)[0];
var j = d.createElement(s);
var dl = '';
if (l != 'dataLayer') {
dl = '&l=' + l;
}
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-KNX3CJC');
</script>
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Google Tag Manager loader runs here without first establishing a default Consent Mode state. If bundle.js is injected later in the page (common in Sphinx themes), GTM may initialize before gtag('consent','default', …) is applied, which can allow tags to fire before the user has made a choice. Initialize window.dataLayer/window.gtag and set the default consent state (all denied) immediately before loading GTM to ensure consent is enforced from the first request.

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +34
<img src="{{ pathto(product_tag,1) }}" alt="Logo" class="p-logo-image">
<div class="p-logo-text p-heading--4">{{ project }}
</div>
</a>
</li>

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

product_tag is rendered as the logo image source, but there is no tag.png (or other referenced file) anywhere under the configured html_static_path in this repo. This will produce a broken image in the docs header unless the asset is added or product_tag is changed to an existing image/URL.

Suggested change
<img src="{{ pathto(product_tag,1) }}" alt="Logo" class="p-logo-image">
<div class="p-logo-text p-heading--4">{{ project }}
</div>
</a>
</li>
<div class="p-logo-text p-heading--4">{{ project }}
</div>
</a>
</li>

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +26
<div class="p-navigation__nav" role="menubar">

<ul class="p-navigation__links" role="menu">

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navigation markup uses role="menubar"/role="menu", which are intended for application-style menus and carry strict keyboard interaction expectations. For a site header navigation, this can reduce accessibility in screen readers. Consider using a semantic <nav> with an aria-label and removing these menu roles unless you also implement full menubar keyboard behavior.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

TICS Quality Gate

✔️ Passed

No changed files applicable for TICS analysis quality gating.

TICS / TICS / Run TICS analysis

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants