Conversation
There was a problem hiding this comment.
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) andfooter.html(with “Manage your tracker settings” link). - Add the cookie banner CSS/JS assets and update pre-commit exclusions for the
.sphinxsubtree.
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> |
There was a problem hiding this comment.
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.
| <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> |
| @@ -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 | |||
There was a problem hiding this comment.
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.
| (()=>{"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)})(); |
| .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 | ||
| } | ||
|
|
There was a problem hiding this comment.
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.
| .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} |
| <!-- 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> |
There was a problem hiding this comment.
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.
| <img src="{{ pathto(product_tag,1) }}" alt="Logo" class="p-logo-image"> | ||
| <div class="p-logo-text p-heading--4">{{ project }} | ||
| </div> | ||
| </a> | ||
| </li> | ||
|
|
There was a problem hiding this comment.
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.
| <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> |
| <div class="p-navigation__nav" role="menubar"> | ||
|
|
||
| <ul class="p-navigation__links" role="menu"> | ||
|
|
There was a problem hiding this comment.
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.
TICS Quality Gate✔️ PassedNo changed files applicable for TICS analysis quality gating. TICS / TICS / Run TICS analysis |
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