xyboox

kiosk-mode

Dec 20th, 2020
1,175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const ha = document.querySelector('home-assistant');
  2. const main = ha.shadowRoot.querySelector('home-assistant-main').shadowRoot;
  3. const panel = main.querySelector('partial-panel-resolver');
  4. const drawerLayout = main.querySelector('app-drawer-layout');
  5. let llAttempts = 1;
  6. let interv;
  7.  
  8. function getConfigObj() {
  9.   const ll = main.querySelector('ha-panel-lovelace');
  10.  
  11.   if (!ll || !ll.lovelace || !ll.lovelace.config) {
  12.     return;
  13.   } else {
  14.     return ll && ll.lovelace.config.kiosk_mode
  15.       ? ll.lovelace.config.kiosk_mode
  16.       : {};
  17.   }
  18. }
  19.  
  20. function getConfig() {
  21.   return new Promise((resolve, reject) => {
  22.     interv = setInterval(() => {
  23.       console.log('Attempt #%s', llAttempts);
  24.       if (getConfigObj()) {
  25.         interv = clearInterval(interv);
  26.         resolve(getConfigObj());
  27.       } else {
  28.         llAttempts++;
  29.         if (llAttempts == 10) {
  30.           interv = clearInterval(interv);
  31.           resolve(null);
  32.         }
  33.       }
  34.     }, 100);
  35.   });
  36. }
  37.  
  38. // Return true if any keyword is found in location.
  39. function locIncludes(keywords) {
  40.   const url = window.location.search;
  41.   return keywords.some((x) => url.includes(x));
  42. }
  43.  
  44. // Check if element exists and if style element already exists.
  45. function styleCheck(elem) {
  46.   return elem && !elem.querySelector('#kiosk_mode');
  47. }
  48.  
  49. // Insert style element.
  50. function addStyles(css, elem) {
  51.   const style = document.createElement('style');
  52.   style.setAttribute('id', 'kiosk_mode');
  53.   style.innerHTML = css;
  54.   elem.appendChild(style);
  55.   window.dispatchEvent(new Event('resize'));
  56. }
  57.  
  58. // Set localStorage item.
  59. function setCache(k, v) {
  60.   window.localStorage.setItem(k, v);
  61. }
  62.  
  63. // Retrieve localStorage item as bool.
  64. function cacheAsBool(k) {
  65.   return window.localStorage.getItem(k) == 'true';
  66. }
  67.  
  68. // Clear cache if requested.
  69. if (window.location.search.includes('clear_km_cache')) {
  70.   ['kmHeader', 'kmSidebar'].forEach((k) => setCache(k, 'false'));
  71. }
  72.  
  73. function kiosk_mode() {
  74.   const url = window.location.search;
  75.   const hass = ha.hass;
  76.  
  77.   // Disable styling if "disable_km" in URL.
  78.   if (url.includes('disable_km')) return;
  79.  
  80.   // Retrieve localStorage values & query string options.
  81.   let hide_header =
  82.     cacheAsBool('kmHeader') || locIncludes(['kiosk', 'hide_header']);
  83.   let hide_sidebar =
  84.     cacheAsBool('kmSidebar') || locIncludes(['kiosk', 'hide_sidebar']);
  85.  
  86.   getConfig().then((config) => {
  87.     if (!config) {
  88.       return;
  89.     }
  90.  
  91.     const adminConf = config.admin_settings;
  92.     const nonAdminConf = config.non_admin_settings;
  93.     let userConf = config.user_settings;
  94.     const queryStringsSet = hide_sidebar || hide_header;
  95.  
  96.     // Use config values only if config strings and cache aren't used.
  97.     hide_header = queryStringsSet
  98.       ? hide_header
  99.       : config.kiosk || config.hide_header;
  100.     hide_sidebar = queryStringsSet
  101.       ? hide_sidebar
  102.       : config.kiosk || config.hide_sidebar;
  103.  
  104.     if (adminConf && hass.user.is_admin) {
  105.       hide_header = adminConf.kiosk || adminConf.hide_header;
  106.       hide_sidebar = adminConf.kiosk || adminConf.hide_sidebar;
  107.     }
  108.  
  109.     if (nonAdminConf && !hass.user.is_admin) {
  110.       hide_header = nonAdminConf.kiosk || nonAdminConf.hide_header;
  111.       hide_sidebar = nonAdminConf.kiosk || nonAdminConf.hide_sidebar;
  112.     }
  113.  
  114.     if (userConf) {
  115.       if (!Array.isArray(userConf)) userConf = [userConf];
  116.       for (let conf of userConf) {
  117.         let users = conf.users;
  118.         if (!Array.isArray(conf.users)) users = [users];
  119.         if (
  120.           users.some((x) => x.toLowerCase() == hass.user.name.toLowerCase())
  121.         ) {
  122.           hide_header = conf.kiosk || conf.hide_header;
  123.           hide_sidebar = conf.kiosk || conf.hide_sidebar;
  124.         }
  125.       }
  126.     }
  127.  
  128.     // Only run if needed.
  129.     if (hide_sidebar || hide_header) {
  130.       const lovelace = main.querySelector('ha-panel-lovelace');
  131.       const huiRoot = lovelace
  132.         ? lovelace.shadowRoot.querySelector('hui-root').shadowRoot
  133.         : null;
  134.       const toolbar = huiRoot ? huiRoot.querySelector('app-toolbar') : null;
  135.  
  136.       // Insert style element for kiosk or hide_header options.
  137.       if (hide_header && styleCheck(huiRoot)) {
  138.         const css =
  139.           '#view { min-height: 100vh !important } app-header { display: none }';
  140.         addStyles(css, huiRoot);
  141.  
  142.         // Set localStorage cache for hiding header.
  143.         if (url.includes('cache')) setCache('kmHeader', 'true');
  144.       }
  145.  
  146.       // Insert style element for kiosk or hide_sidebar options.
  147.       if (hide_sidebar && styleCheck(drawerLayout)) {
  148.         const css =
  149.           ':host { --app-drawer-width: 0 !important } #drawer { display: none }';
  150.         addStyles(css, drawerLayout);
  151.  
  152.         // Hide menu button.
  153.         if (styleCheck(toolbar))
  154.           addStyles('ha-menu-button { display:none !important } ', toolbar);
  155.  
  156.         // Set localStorage cache for hiding sidebar.
  157.         if (url.includes('cache')) setCache('kmSidebar', 'true');
  158.       }
  159.     }
  160.   });
  161. }
  162.  
  163. // Initial run.
  164. kiosk_mode();
  165.  
  166. // Watch for changes in partial-panel-resolver's children.
  167. new MutationObserver(lovelaceWatch).observe(panel, {childList: true});
  168.  
  169. // If new lovelace panel was added watch for hui-root to appear.
  170. function lovelaceWatch(mutations) {
  171.   for (let mutation of mutations) {
  172.     for (let node of mutation.addedNodes) {
  173.       if (node.localName == 'ha-panel-lovelace') {
  174.         new MutationObserver(rootWatch).observe(node.shadowRoot, {
  175.           childList: true,
  176.         });
  177.         return;
  178.       }
  179.     }
  180.   }
  181. }
  182.  
  183. // When hui-root appears watch it's children.
  184. function rootWatch(mutations) {
  185.   for (let mutation of mutations) {
  186.     for (let node of mutation.addedNodes) {
  187.       if (node.localName == 'hui-root') {
  188.         new MutationObserver(appLayoutWatch).observe(node.shadowRoot, {
  189.           childList: true,
  190.         });
  191.         return;
  192.       }
  193.     }
  194.   }
  195. }
  196.  
  197. // When ha-app-layout appears we can run.
  198. function appLayoutWatch(mutations) {
  199.   for (let mutation of mutations) {
  200.     for (let node of mutation.addedNodes) {
  201.       if (node.localName == 'ha-app-layout') {
  202.         kiosk_mode();
  203.         return;
  204.       }
  205.     }
  206.   }
  207. }
  208.  
  209. // Overly complicated console tag.
  210. const conInfo = {header: '%c≡ kiosk-mode'.padEnd(27), ver: '%cversion *DEV '};
  211. const br = '%c\n';
  212. const maxLen = Math.max(...Object.values(conInfo).map((el) => el.length));
  213. for (const [key] of Object.entries(conInfo)) {
  214.   if (conInfo[key].length <= maxLen) conInfo[key] = conInfo[key].padEnd(maxLen);
  215.   if (key == 'header') conInfo[key] = `${conInfo[key].slice(0, -1)}⋮ `;
  216. }
  217. const header =
  218.   'display:inline-block;border-width:1px 1px 0 1px;border-style:solid;border-color:#424242;color:white;background:#03a9f4;font-size:12px;padding:4px 4.5px 5px 6px;';
  219. const info =
  220.   'border-width:0px 1px 1px 1px;padding:7px;background:white;color:#424242;line-height:0.7;';
  221. console.info(
  222.   conInfo.header + br + conInfo.ver,
  223.   header,
  224.   '',
  225.   `${header} ${info}`
  226. );
  227.  
Advertisement
Add Comment
Please, Sign In to add comment