1<!doctype html> 2<html lang="en"> 3<head > 4 <meta charset="utf-8"/> 5<meta name="title" content="Featured Products"/> 6<meta name="description" content="Healthcare4all Ltd"/> 7<meta name="keywords" content="Healthcare4all Ltd"/> 8<meta name="robots" content="INDEX,FOLLOW"/> 9<meta name="viewport" content="width=device-width, initial-scale=1"/> 10<title>Featured Products</title> 11<link rel="stylesheet" type="text/css" media="all" href="https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/css/styles.css" /> 12<link rel="stylesheet" type="text/css" media="all" href="https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Trustpilot_Reviews/css/trustpilot.min.css" />
13<script type="text/javascript" src="https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Smile_ElasticsuiteTracker/js/tracking.js"></script>
13 14<link rel="canonical" href="https://www.healthcare4all.co.uk/featured-products" /> 15<link rel="icon" type="image/x-icon" href="https://www.healthcare4all.co.uk/media/favicon/stores/1/favicon.png" /> 16<link rel="shortcut icon" type="image/x-icon" href="https://www.healthcare4all.co.uk/media/favicon/stores/1/favicon.png" /> 17 <!-- glopal_head -->
18<script> 19// <![CDATA[ 20var _webinterpret = _webinterpret || {}; 21_webinterpret.plugin_version = 'magento2-1.14.22'; 22_webinterpret.page_store_view_id = '1'; 23_webinterpret.page_short_name = 'healthcare4all'; 24// ]]> 25</script>
vendor: 1 bytes, line 25
25
26<script async type="text/javascript" src="https://cdn-redirector.glopal.com/common/js/webinterpret-loader.js"></script>
26 27<!-- end glopal_head --> 28
28<script> 29 //<![CDATA[ 30 function userConsentEsTraking(config) 31 { 32 return config.cookieRestrictionEnabled == false || hyva.getCookie(config.cookieRestrictionName) !== null; 33 } 34 35 try { 36 smileTracker.setConfig({ 37 beaconUrl : 'https://www.healthcare4all.co.uk/elasticsuite/tracker/hit/image/h.png', 38 telemetryUrl : 'https://t.elasticsuite.io/track', 39 telemetryEnabled : '', 40 sessionConfig : {"visit_cookie_name":"STUID","visit_cookie_lifetime":"3600","visitor_cookie_lifetime":"365","visitor_cookie_name":"STVID","domain":"www.healthcare4all.co.uk","path":"\/"}, 41 endpointUrl : 'https://www.healthcare4all.co.uk/rest/V1/elasticsuite-tracker/hit' 42 }); 43 44 smileTracker.addPageVar('store_id', '1'); 45 46 document.addEventListener('DOMContentLoaded', function () { 47 if (userConsentEsTraking({"cookieRestrictionEnabled":"0","cookieRestrictionName":"user_allowed_save_cookie"})) { 48 smileTracker.sendTag(); 49 } 50 }); 51 } catch (err) { 52 ; 53 } 54 //]]> 55 </script>
55 56
56<script> 57 var BASE_URL = 'https://www.healthcare4all.co.uk/'; 58 var THEME_PATH = 'https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB'; 59 var COOKIE_CONFIG = { 60 "expires": null, 61 "path": "\u002F", 62 "domain": ".www.healthcare4all.co.uk", 63 "secure": true, 64 "lifetime": "3600", 65 "cookie_restriction_enabled": false }; 66 var CURRENT_STORE_CODE = 'default'; 67 var CURRENT_WEBSITE_ID = '1'; 68 69 window.hyva = window.hyva || {} 70 71 window.cookie_consent_groups = window.cookie_consent_groups || {} 72 window.cookie_consent_groups['necessary'] = true; 73 74 window.cookie_consent_config = window.cookie_consent_config || {}; 75 window.cookie_consent_config['necessary'] = [].concat( 76 window.cookie_consent_config['necessary'] || [], 77 [ 78 'user_allowed_save_cookie', 79 'form_key', 80 'mage-messages', 81 'private_content_version', 82 'mage-cache-sessid', 83 'last_visited_store', 84 'section_data_ids' 85 ] 86 ); 87</script>
vendor: 1 bytes, line 87
87
88<script> 89 (function( hyva, undefined ) { 90 91 function lifetimeToExpires(options, defaults) { 92 93 const lifetime = options.lifetime || defaults.lifetime; 94 95 if (lifetime) { 96 const date = new Date; 97 date.setTime(date.getTime() + lifetime * 1000); 98 return date; 99 } 100 101 return null; 102 } 103 104 function generateRandomString() { 105 106 const allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 107 length = 16; 108 109 let formKey = '', 110 charactersLength = allowedCharacters.length; 111 112 for (let i = 0; i < length; i++) { 113 formKey += allowedCharacters[Math.round(Math.random() * (charactersLength - 1))] 114 } 115 116 return formKey; 117 } 118 119 const sessionCookieMarker = {noLifetime: true} 120 121 const cookieTempStorage = {}; 122 123 const internalCookie = { 124 get(name) { 125 const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); 126 return v ? v[2] : null; 127 }, 128 set(name, value, days, skipSetDomain) { 129 let expires, 130 path, 131 domain, 132 secure, 133 samesite; 134 135 const defaultCookieConfig = { 136 expires: null, 137 path: '/', 138 domain: null, 139 secure: false, 140 lifetime: null, 141 samesite: 'lax' 142 }; 143 144 const cookieConfig = window.COOKIE_CONFIG || {}; 145 146 expires = days && days !== sessionCookieMarker 147 ? lifetimeToExpires({lifetime: 24 * 60 * 60 * days, expires: null}, defaultCookieConfig) 148 : lifetimeToExpires(window.COOKIE_CONFIG, defaultCookieConfig) || defaultCookieConfig.expires; 149 150 path = cookieConfig.path || defaultCookieConfig.path; 151 domain = !skipSetDomain && (cookieConfig.domain || defaultCookieConfig.domain); 152 secure = cookieConfig.secure || defaultCookieConfig.secure; 153 samesite = cookieConfig.samesite || defaultCookieConfig.samesite; 154 155 document.cookie = name + "=" + encodeURIComponent(value) + 156 (expires && days !== sessionCookieMarker ? '; expires=' + expires.toGMTString() : '') + 157 (path ? '; path=' + path : '') + 158 (domain ? '; domain=' + domain : '') + 159 (secure ? '; secure' : '') + 160 (samesite ? '; samesite=' + samesite : 'lax'); 161 }, 162 isWebsiteAllowedToSaveCookie() { 163 const allowedCookies = this.get('user_allowed_save_cookie'); 164 if (allowedCookies) { 165 const allowedWebsites = JSON.parse(unescape(allowedCookies)); 166 167 return allowedWebsites[CURRENT_WEBSITE_ID] === 1; 168 } 169 return false; 170 }, 171 getGroupByCookieName(name) { 172 const cookieConsentConfig = window.cookie_consent_config || {}; 173 let group = null; 174 for (let prop in cookieConsentConfig) { 175 if (!cookieConsentConfig.hasOwnProperty(prop)) continue; 176 if (cookieConsentConfig[prop].includes(name)) { 177 group = prop; 178 break; 179 } 180 } 181 return group; 182 }, 183 isCookieAllowed(name) { 184 const cookieGroup = this.getGroupByCookieName(name); 185 return cookieGroup 186 ? window.cookie_consent_groups[cookieGroup] 187 : this.isWebsiteAllowedToSaveCookie(); 188 }, 189 saveTempStorageCookies() { 190 for (const [name, data] of Object.entries(cookieTempStorage)) { 191 if (this.isCookieAllowed(name)) { 192 this.set(name, data['value'], data['days'], data['skipSetDomain']); 193 delete cookieTempStorage[name]; 194 } 195 } 196 } 197 }; 198 199 hyva.getCookie = (name) => { 200 const cookieConfig = window.COOKIE_CONFIG || {}; 201 202 if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) { 203 return cookieTempStorage[name] ? cookieTempStorage[name]['value'] : null; 204 } 205 206 return internalCookie.get(name); 207 } 208 209 hyva.setCookie = (name, value, days, skipSetDomain) => { 210 const cookieConfig = window.COOKIE_CONFIG || {}; 211 212 if (cookieConfig.cookie_restriction_enabled && ! internalCookie.isCookieAllowed(name)) { 213 cookieTempStorage[name] = {value, days, skipSetDomain}; 214 return; 215 } 216 return internalCookie.set(name, value, days, skipSetDomain); 217 } 218 219 220 hyva.setSessionCookie = (name, value, skipSetDomain) => { 221 return hyva.setCookie(name, value, sessionCookieMarker, skipSetDomain) 222 } 223 224 hyva.getBrowserStorage = () => { 225 const browserStorage = window.localStorage || window.sessionStorage; 226 if (!browserStorage) { 227 console.warn('Browser Storage is unavailable'); 228 return false;
229 } 230 try { 231 browserStorage.setItem('storage_test', '1'); 232 browserStorage.removeItem('storage_test'); 233 } catch (error) { 234 console.warn('Browser Storage is not accessible', error); 235 return false; 236 } 237 return browserStorage; 238 } 239 240 hyva.postForm = (postParams) => { 241 const form = document.createElement("form"); 242 243 let data = postParams.data; 244 245 if (! postParams.skipUenc && ! data.uenc) { 246 data.uenc = btoa(window.location.href); 247 } 248 form.method = "POST"; 249 form.action = postParams.action; 250 251 Object.keys(postParams.data).map(key => { 252 const field = document.createElement("input"); 253 field.type = 'hidden' 254 field.value = postParams.data[key]; 255 field.name = key; 256 form.appendChild(field); 257 }); 258 259 const form_key = document.createElement("input"); 260 form_key.type = 'hidden'; 261 form_key.value = hyva.getFormKey(); 262 form_key.name="form_key"; 263 form.appendChild(form_key); 264 265 document.body.appendChild(form); 266 267 form.submit(); 268 } 269 270 hyva.getFormKey = function () { 271 let formKey = hyva.getCookie('form_key'); 272 273 if (!formKey) { 274 formKey = generateRandomString(); 275 hyva.setCookie('form_key', formKey); 276 } 277 278 return formKey; 279 } 280 281 hyva.formatPrice = (value, showSign, options = {}) => { 282 const groupSeparator = options.groupSeparator; 283 const decimalSeparator = options.decimalSeparator 284 delete options.groupSeparator; 285 delete options.decimalSeparator; 286 const formatter = new Intl.NumberFormat( 287 'en\u002DGB', 288 Object.assign({ 289 style: 'currency', 290 currency: 'GBP', 291 signDisplay: showSign ? 'always' : 'auto' 292 }, options) 293 ); 294 return (typeof Intl.NumberFormat.prototype.formatToParts === 'function') ? 295 formatter.formatToParts(value).map(({type, value}) => { 296 switch (type) { 297 case 'currency': 298 return '\u00A3' || value; 299 case 'minusSign': 300 return '- '; 301 case 'plusSign': 302 return '+ '; 303 case 'group': 304 return groupSeparator !== undefined ? groupSeparator : value; 305 case 'decimal': 306 return decimalSeparator !== undefined ? decimalSeparator : value; 307 default : 308 return value; 309 } 310 }).reduce((string, part) => string + part) : 311 formatter.format(value); 312 } 313 314 const formatStr = function (str, nStart) { 315 const args = Array.from(arguments).slice(2); 316 317 return str.replace(/(%+)([0-9]+)/g, (m, p, n) => { 318 const idx = parseInt(n) - nStart; 319 320 if (args[idx] === null || args[idx] === void 0) { 321 return m; 322 } 323 return p.length % 2 324 ? p.slice(0, -1).replace('%%', '%') + args[idx] 325 : p.replace('%%', '%') + n; 326 }) 327 } 328 329 hyva.str = function (string) { 330 const args = Array.from(arguments); 331 args.splice(1, 0, 1); 332 333 return formatStr.apply(undefined, args); 334 } 335 336 hyva.strf = function () { 337 const args = Array.from(arguments); 338 args.splice(1, 0, 0); 339 340 return formatStr.apply(undefined, args); 341 } 342 343 /** 344 * Take a html string as `content` parameter and 345 * extract an element from the DOM to replace in 346 * the current page under the same selector, 347 * defined by `targetSelector` 348 */ 349 hyva.replaceDomElement = (targetSelector, content) => { 350 // Parse the content and extract the DOM node using the `targetSelector` 351 const parser = new DOMParser(); 352 const doc = parser.parseFromString(content, 'text/html');
353 const contentNode = doc.querySelector(targetSelector); 354 355 // Bail if content or target can't be found 356 if (!contentNode || !document.querySelector(targetSelector)) { 357 return; 358 } 359 360 hyva.activateScripts(contentNode); 361 362 // Replace the old DOM node with the new content 363 document.querySelector(targetSelector).replaceWith(contentNode); 364 365 // Reload customerSectionData and display cookie-messages if present 366 window.dispatchEvent(new CustomEvent("reload-customer-section-data")); 367 hyva.initMessages(); 368 } 369 370 hyva.removeScripts = (contentNode) => { 371 const scripts = contentNode.getElementsByTagName('script'); 372 for (let i = 0; i < scripts.length; i++) { 373 scripts[i].parentNode.removeChild(scripts[i]); 374 } 375 const templates = contentNode.getElementsByTagName('template'); 376 for (let i = 0; i < templates.length; i++) { 377 const container = document.createElement('div'); 378 container.innerHTML = templates[i].innerHTML; 379 hyva.removeScripts(container); 380 templates[i].innerHTML = container.innerHTML; 381 } 382 } 383 384 hyva.activateScripts = (contentNode) => { 385 // Create new array from HTMLCollection to avoid mutation of collection while manipulating the DOM. 386 const scripts = Array.from(contentNode.getElementsByTagName('script')); 387 388 // Iterate over all script tags to duplicate+inject each into the head 389 for (const original of scripts) { 390 const script = document.createElement('script'); 391 original.type && (script.type = original.type); 392 script.innerHTML = original.innerHTML; 393 394 // Remove the original (non-executing) script from the contentNode 395 original.parentNode.removeChild(original) 396 397 // Add script to head 398 document.head.appendChild(script); 399 } 400 401 return contentNode; 402 } 403 404 const replace = {['+']: '-', ['/']: '_', ['=']: ','}; 405 hyva.getUenc = () => btoa(window.location.href).replace(/[+/=]/g, match => replace[match]); 406 407 let currentTrap; 408 409 const focusableElements = (rootElement) => { 410 const selector = 'button, [href], input, select, textarea, details, [tabindex]:not([tabindex="-1"]'; 411 return Array.from(rootElement.querySelectorAll(selector)) 412 .filter(el => { 413 return el.style.display !== 'none' 414 && !el.disabled 415 && el.tabIndex !== -1 416 && (el.offsetWidth || el.offsetHeight || el.getClientRects().length) 417 }) 418 } 419 420 const focusTrap = (e) => { 421 const isTabPressed = e.key === 'Tab' || e.keyCode === 9; 422 if (!isTabPressed) return; 423 424 const focusable = focusableElements(currentTrap) 425 const firstFocusableElement = focusable[0] 426 const lastFocusableElement = focusable[focusable.length - 1] 427 428 e.shiftKey 429 ? document.activeElement === firstFocusableElement && (lastFocusableElement.focus(), e.preventDefault()) 430 : document.activeElement === lastFocusableElement && (firstFocusableElement.focus(), e.preventDefault()) 431 }; 432 433 hyva.releaseFocus = (rootElement) => { 434 if (currentTrap && (!rootElement || rootElement === currentTrap)) { 435 currentTrap.removeEventListener('keydown', focusTrap) 436 currentTrap = null 437 } 438 } 439 hyva.trapFocus = (rootElement) => { 440 if (!rootElement) return; 441 hyva.releaseFocus() 442 currentTrap = rootElement 443 rootElement.addEventListener('keydown', focusTrap) 444 const firstElement = focusableElements(rootElement)[0] 445 firstElement && firstElement.focus() 446 } 447 448 hyva.safeParseNumber = (rawValue) => { 449 const number = rawValue ? parseFloat(rawValue) : null; 450 451 return Array.isArray(number) || isNaN(number) ? rawValue : number; 452 } 453 454 const toCamelCase = s => s.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(''); 455 hyva.createBooleanObject = (name, value = false, additionalMethods = {}) => { 456 457 const camelCase = toCamelCase(name);
458 const key = '__hyva_bool_' + name 459 460 return new Proxy(Object.assign( 461 additionalMethods, 462 { 463 [key]: !!value, 464 [name]() {return !!this[key]}, 465 ['!' + name]() {return !this[key]}, // @deprecated This does not work with non-CSP Alpine 466 ['not' + camelCase]() {return !this[key]}, 467 ['toggle' + camelCase]() {this[key] = !this[key]}, 468 [`set${camelCase}True`]() {this[key] = true}, 469 [`set${camelCase}False`]() {this[key] = false}, 470 } 471 ), { 472 set(target, prop, value) { 473 return prop === name 474 ? (target[key] = !!value) 475 : Reflect.set(...arguments); 476 } 477 }) 478 } 479 480 hyva.alpineInitialized = (fn) => window.addEventListener('alpine:initialized', fn, {once: true}) 481 window.addEventListener('alpine:init', () => Alpine.data('{}', () => ({})), {once: true}); 482 window.addEventListener('user-allowed-save-cookie', () => internalCookie.saveTempStorageCookies()) 483 484 }( window.hyva = window.hyva || {} )); 485 //# sourceURL=hyva.js 486</script>
486 487<!-- GA4 E-commerce Tracking (Hyva compatible) -->
vendor: 64 bytes, lines 487-488
487 488<script async src="https://www.googletagmanager.com/gtag/js?id=
488G-WFVLSTM3MV
vendor: 12 bytes, line 488
488"></script>
489<script> 490 window.dataLayer = window.dataLayer || []; 491 function gtag(){dataLayer.push(arguments);} 492 gtag('js', new Date()); 493 gtag('set', 'developer_id.dYjhlMD', true); 494 gtag('config', 'G\u002DWFVLSTM3MV'); 495 window.HC4A_GA_DEBUG = window.HC4A_GA_DEBUG || (location.hostname.indexOf('staging') !== -1); 496 function hc4aGa(name, payload){ 497 try { if (typeof gtag === 'function') { gtag('event', name, payload); } 498 if (window.HC4A_GA_DEBUG) console.log('[HC4A GA4] ' + name, payload); } catch(e){} 499 } 500 501 </script>
501 502 503
504<script> 505(function () { 506 'use strict'; 507 508 // ---- add_to_cart: catch fetch, XHR and form POSTs to checkout/cart/add ---- 509 function isAddToCart(url) { return typeof url === 'string' && url.indexOf('checkout/cart/add') !== -1; } 510 511 function fireAddToCart() { 512 try { 513 var nameEl = document.querySelector('.page-title span, [data-ui-id="page-title-wrapper"]'); 514 var priceEl = document.querySelector('[data-price-type="finalPrice"] .price, .product-info-main .price'); 515 var skuEl = document.querySelector('[itemprop="sku"], .product.attribute.sku .value'); 516 var name = nameEl ? nameEl.textContent.trim() : (document.title || ''); 517 var price = priceEl ? parseFloat(priceEl.textContent.replace(/[^0-9.]/g, '')) : 0; 518 var sku = skuEl ? skuEl.textContent.trim() : ''; 519 hc4aGa('add_to_cart', { currency: 'GBP', value: price, 520 items: [{ item_id: sku, item_name: name, price: price, quantity: 1 }] }); 521 } catch (e) {} 522 } 523 524 var origFetch = window.fetch; 525 if (origFetch) { 526 window.fetch = function (url) { if (isAddToCart(url)) fireAddToCart(); return origFetch.apply(this, arguments); }; 527 } 528 var origOpen = window.XMLHttpRequest && window.XMLHttpRequest.prototype.open; 529 if (origOpen) { 530 window.XMLHttpRequest.prototype.open = function (method, url) { 531 if (isAddToCart(url)) this.addEventListener('loadstart', fireAddToCart); 532 return origOpen.apply(this, arguments); 533 }; 534 } 535 document.addEventListener('submit', function (ev) { 536 try { var f = ev.target; if (f && f.action && isAddToCart(f.action)) fireAddToCart(); } catch (e) {} 537 }, true); 538 539 // ---- begin_checkout: on the checkout page, from the cart section ---- 540 function onCheckoutPage() { 541 var p = location.pathname; 542 return p.indexOf('/checkout') !== -1 && p.indexOf('success') === -1 && p.indexOf('cart') === -1; 543 } 544 if (onCheckoutPage()) { 545 (origFetch || window.fetch)('/customer/section/load?sections=cart&force_new_section_timestamp=true', { credentials: 'same-origin' }) 546 .then(function (r) { return r.json(); }) 547 .then(function (d) { 548 var cart = d && d.cart ? d.cart : {}; 549 var items = (cart.items || []).map(function (it) { 550 return { item_id: it.product_sku || it.item_id || '', item_name: it.product_name || '', 551 price: parseFloat(it.product_price_value || it.price || 0), quantity: parseInt(it.qty || 1, 10) }; 552 }); 553 hc4aGa('begin_checkout', { 554 currency: 'GBP', 555 value: parseFloat((cart.subtotalAmount != null ? cart.subtotalAmount : cart.subtotal) || 0), 556 items: items 557 }); 558 }).catch(function () {}); 559 } 560})(); 561</script>
vendor: 1 bytes, line 561
561
562<script type="speculationrules"> 563{ 564 "tag": "Hyva Theme", 565 "prefetch": [{ 566 "source": "document", 567 "where": { 568 "and": [ 569 { "href_matches": "/*" }, 570 { "not": { 571 "href_matches": ["/customer/*","/search/*","/sales/*","/wishlist/*","/checkout/*","/paypal/*","/newsletter/*","/stores/store/redirect/*"] }}, 572 { "not": { 573 "selector_matches": [".no-preload", ".do-not-prerender", "[download]", "[rel~=nofollow]", "[target]"] 574 }} 575 ] 576 }, 577 "eagerness": "moderate" 578 }] 579} 580</script>
580 581</head> 582<body id="html-body" class="page-with-filter page-products categorypath-featured-products category-featured-products catalog-category-view page-layout-2columns-left"> 583
583<script> 584 function cookieNoticeInit() { 585 return { 586 show: true, 587 position : {"left":0,"bottom":0}, 588 bgColor : "#222222;", 589 colorTitle : "#ffffff", 590 colorContent : "#ffffff", 591 colorAccept : "#ffffff", 592 bgColorAccept : "#9fba27", 593 bgColorMoreInfo : "#222222", 594 colorMoreInfo : "#0a88cc", 595 autoHideMsg : "5000", 596 init : function () { 597 this.checkCookie(); 598 if (this.autoHideMsg != 0) { 599 this.autoHideMessage(this.autoHideMsg); 600 } 601 }, 602 autoHideMessage: function (seconds) { 603 var self = this; 604 if (seconds != 0) { 605 setTimeout(function () { 606 self.show = false; 607 }, seconds); 608 } 609 }, 610 setCookie: function () { 611 var cname = 'cookienotice', 612 cvalue = 'bss', 613 exdays = 180, 614 date = new Date(); 615 this.show = false; 616 date.setTime(date.getTime() + (exdays * 24 * 60 * 60 * 1000)); 617 var expires = "expires=" + date.toUTCString(); 618 document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; 619 }, 620 getCookie: function (cname) { 621 var name = cname + "="; 622 var allCookies = document.cookie.split(';'); 623 for (var i = 0; i < allCookies.length; i++) { 624 var cookie = allCookies[i]; 625 while (cookie.charAt(0) == ' ') { 626 cookie = cookie.substring(1); 627 } 628 if (cookie.indexOf(name) == 0) { 629 return cookie.substring(name.length, cookie.length); 630 } 631 } 632 return ""; 633 }, 634 checkCookie: function () { 635 var cookieNotice = this.getCookie("cookienotice"); 636 this.bgColor = this.bgColor.replace(";", ""); 637 this.position['background-color'] = this.bgColor; 638 if (cookieNotice == "") { 639 Object.assign(document.getElementById('bss-cookie-notice').style,this.position); 640 document.getElementsByClassName('cookie-title')[0].style.color = this.colorTitle; 641 document.getElementsByClassName('cookie-content')[0].style.color = this.colorContent; 642 document.getElementsByClassName('btn-cookie-accept')[0].style.color = this.colorAccept; 643 document.getElementsByClassName('btn-cookie-accept')[0].style.backgroundColor = this.bgColorAccept; 644 document.getElementsByClassName('btn-cookie-more-infor')[0].style.color = this.colorMoreInfo; 645 document.getElementsByClassName('btn-cookie-more-infor')[0].style.backgroundColor = this.bgColorMoreInfo; 646 } else { 647 this.show = false; 648 } 649 } 650 } 651 } 652 </script>
652 653 <div id="bss-cookie-notice" x-data="cookieNoticeInit()" x-init="init()" x-show="show" x-cloak > 654 <h4 class="cookie-title mx-0 my-2"> 655 Approve The Cookies </h4> 656 <p class="cookie-content mb-2"> 657 This website uses cookies to improve your user experience </p> 658 <button @click="setCookie()" class="btn-cookie btn-cookie-accept inline-flex btn btn-primary mb-1"> 659 I accept </button> 660 <a class="btn-cookie btn-cookie-more-infor inline-flex btn btn-primary" 661 href="https://www.healthcare4all.co.uk/" target="_blank"> 662 Read more </a> 663 </div> 664 <input name="form_key" type="hidden" value="0TWtmpCcpZOzi078" /> 665 <noscript> 666 <section 667 class="message global noscript border-b-2 border-blue-500 bg-blue-50 shadow-none m-0 px-0 rounded-none font-normal" 668 aria-labelledby="messageGlobalNoScriptMessage" 669 > 670 <div class="container text-center"> 671 <p id="messageGlobalNoScriptMessage"> 672 <strong>JavaScript seems to be disabled in your browser.</strong> 673 <span> 674 For the best experience on our site, be sure to turn on Javascript in your browser. </span> 675 </p> 676 </div> 677 </section> 678 </noscript> 679 680 681 682<div class="header-top text-white text-sm leading-5 font-semibold p-2 flex items-center" style="gap:1rem; background-color:#089A8A"> 683 <div class="flex-1 text-center flex items-center justify-center gap-4"> 684 <span class="hidden md:inline">Delivering quality & service since 2006</span> 685 <span class="md:hidden">Est. 2006</span> 686 <span class="opacity-50">|</span> 687 <a href="https://www.trustpilot.com/review/www.healthcare4all.co.uk" 688 target="_blank" rel="noopener" 689 class="text-white text-sm font-semibold no-underline hover:underline"> 690 Review us on <span>★</span> Trustpilot 691 </a> 692 </div> 693</div>
694<script> 695 document.body.addEventListener('touchstart', () => {}, {passive: true}) 696</script>
696 697<div class="page-wrapper"><header class="page-header"><a class="action skip sr-only focus:not-sr-only focus:absolute focus:z-40 focus:bg-white 698 contentarea" 699 href="#contentarea"> 700 <span> 701 Skip to Content </span> 702</a> 703
703<script type="application/javascript" async 704 src="https://static.klaviyo.com/onsite/js/VrQzR5/klaviyo.js"></script>
704 705 706 <div x-data="initKlaviyoCustomerTracking()" 707 @private-content-loaded.window="sendCustomerDataToKlaviyo(event.detail.data)"></div> 708
708<script> 709 !function(){if(!window.klaviyo){window._klOnsite=window._klOnsite||[];try{window.klaviyo=new Proxy({},{get:function(n,i){return"push"===i?function(){var n;(n=window._klOnsite).push.apply(n,arguments)}:function(){for(var n=arguments.length,o=new Array(n),w=0;w<n;w++)o[w]=arguments[w];var t="function"==typeof o[o.length-1]?o.pop():void 0,e=new Promise((function(n){window._klOnsite.push([i].concat(o,[function(i){t&&t(i),n(i)}]))}));return e}}})}catch(n){window.klaviyo=window.klaviyo||[],window.klaviyo.push=function(){var n;(n=window._klOnsite).push.apply(n,arguments)}}}}(); 710 711 function initKlaviyoCustomerTracking() { 712 return { 713 sendCustomerDataToKlaviyo(data) { 714 window.klaviyo = window.klaviyo || []; 715 const customer = data.customer; 716 717 window.klaviyo.isIdentified().then((identified)=> { 718 if(customer && customer.email && !identified) { 719 window.klaviyo.identify({ 720 '$email': customer.email, 721 '$first_name': customer.firstname ? customer.firstname : '', 722 '$last_name': customer.lastname ? customer.lastname : '' 723 }); 724 } 725 }); 726 } 727 } 728 } 729 </script>
vendor: 1 bytes, line 729
729
730<script> 731 function initHeader () { 732 return { 733 searchOpen: false, 734 cart: {}, 735 init() { 736 this.checkHeaderSize(); 737 }, 738 checkHeaderSize() { 739 const tealBar = document.querySelector('.header-top'); 740 const pageHeader = document.querySelector('.page-header'); 741 if (!pageHeader) return; 742 const tealH = tealBar ? tealBar.offsetHeight : 0; 743 const headerH = pageHeader.offsetHeight; 744 document.documentElement.style.setProperty("--page-header-height", `${headerH}px`); 745 const bc = document.querySelector('nav.breadcrumbs'); 746 if (bc) bc.style.top = (tealH + headerH) + 'px'; 747 }, 748 summaryCount() { 749 return this.cart.summary_count || 0; 750 }, 751 isCartOpen: false, 752 getData() { 753 const data = this.$event.detail.data; 754 if (data.cart) { this.cart = data.cart } 755 }, 756 ariaLabel() { 757 return 'Toggle\u0020minicart, ' + 758 (this.isCartEmpty() ? 'Cart\u0020is\u0020empty' : ( 759 Math.abs(this.summaryCount()) > 1 ? 760 hyva.str('\u00251\u0020items', this.summaryCount()) : 761 hyva.str('\u00251\u0020item', this.summaryCount()) 762 )) 763 }, 764 isCartEmpty() { 765 return !this.summaryCount() 766 }, 767 openCart() { 768 this.$dispatch('toggle-cart', { 769 isOpen: true 770 }) 771 }, 772 toggleCart() { 773 const event = this.$event; 774 if (event.detail && event.detail.isOpen !== undefined) { 775 this.isCartOpen = event.detail.isOpen 776 if (!this.isCartOpen && this.$refs && this.$refs.cartButton) { 777 this.$refs.cartButton.focus() 778 } 779 } else { 780 this.isCartOpen = true 781 } 782 }, 783 searchClosed() { 784 return !this.searchOpen; 785 }, 786 toggleSearchForm() { 787 this.searchOpen = !this.searchOpen; 788 this.$dispatch('search-open'); 789 }, 790 searchClose() { 791 this.searchOpen = false; 792 }, 793 searchEscape() { 794 this.searchOpen = false; 795 this.$refs.searchButton.focus(); 796 } 797 } 798 } 799 800 function initCompareHeader() { 801 return { 802 compareProducts: null, 803 itemCount: 0, 804 hiddenIfEmpty() { 805 return { 806 'hidden': this.itemCount < 1 807 } 808 }, 809 linkAriaLabel() { 810 const countLabel = this.itemCount > 1 811 ? hyva.str('\u00251\u0020Items', this.itemCount) 812 : hyva.str('\u00251\u0020Item', this.itemCount); 813 return `Compare\u0020Products (${countLabel})`; 814 }, 815 receiveCompareData() { 816 const data = this.$event.detail.data; 817 if (data['compare-products'] && data['compare-products'].count) { 818 this.compareProducts = data['compare-products']; 819 this.itemCount = this.compareProducts.count; 820 } 821 }, 822 itemCountLabel() { 823 return `(${this.itemCount})`; 824 } 825 } 826 } 827 828 function initWishlistHeader() { 829 return { 830 wishlistProducts: null, 831 itemCount: 0, 832 linkAriaLabel() { 833 const countLabel = this.itemCount > 1 834 ? hyva.str('\u00251\u0020Items', this.itemCount) 835 : hyva.str('\u00251\u0020Item', this.itemCount); 836 return `Wishlist\u0020Products (${countLabel})`; 837 }, 838 receiveWishlistData() { 839 const data = this.$event.detail.data; 840 841 this.itemCount = data.wishlist && data.wishlist.items 842 ? data.wishlist.items.length 843 : 0; 844 } 845 } 846 } 847 848 window.addEventListener('alpine:init', () => { 849 Alpine.data('initHeader', initHeader); 850 Alpine.data('initCompareHeader', initCompareHeader); 851 Alpine.data('initWishlistHeader', initWishlistHeader); 852 }, { once: true }) 853</script>
853 854<div 855 id="header" 856 class="z-30 relative bg-white" 857 x-data="initHeader" 858 @private-content-loaded.window="getData" 859 @resize.window.debounce="checkHeaderSize" 860> 861 <div class="container pt-3.5 lg:pb-3.5 grid grid-cols-[auto_minmax(0px,1fr)_auto] 862 lg:grid-cols-[auto_minmax(0px,1fr)_auto] gap-y-3.5 lg:gap-y-0 gap-x-4 lg:gap-x-10 items-center"> 863 <nav 864 x-data="initMenuMobile" 865 @load.window="setActiveMenu" 866 @keydown.window.escape="closeMenu" 867 class="navigation lg:hidden" 868 aria-label="Site navigation" 869 role="navigation" 870> 871 <!-- mobile --> 872 <button 873 x-ref="mobileMenuTrigger" 874 @click="openMenu" 875 :class="triggerButtonClass" 876 type="button" 877 aria-label="Open menu" 878 aria-haspopup="menu" 879 :aria-expanded="open" 880 :hidden="open" 881 > 882 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="p-3" width="48" height="48" :class="triggerSvgClass" aria-hidden="true"> 883 <path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16"/> 884</svg> 885 </button> 886 <div 887 x-ref="mobileMenuNavLinks" 888 class=" 889 z-20 fixed top-0 right-0 w-full h-full p-1 hidden 890 flex-col border-t border-container bg-container-lighter 891 overflow-y-auto overflow-x-hidden 892 " 893 :class="mobileMenuNavLinksClass" 894 :aria-hidden="closed" 895 role="dialog" 896 aria-modal="true" 897 > 898 <ul 899 class="border-t flex flex-col gap-y-1 mt-16" 900 aria-label="Site navigation links" 901 > 902 <li 903 data-child-id="category-node-218-main" 904 class="level-0" 905 > 906 <div 907 class="flex items-center transition-transform duration-150 ease-in-out transform" 908 :class="level0TranslateClass" 909 > 910 <a 911 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 912 bg-container-lighter border-container level-0 913 " 914 href="https://www.healthcare4all.co.uk/offers" 915 title="Offers" 916 > 917 Offers </a> 918 </div> 919 </li> 920 <li 921 data-child-id="category-node-222-main" 922 class="level-0" 923 > 924 <div 925 class="flex items-center transition-transform duration-150 ease-in-out transform" 926 :class="level0TranslateClass" 927 > 928 <a 929 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 930 bg-container-lighter border-container level-0 931 " 932 href="https://www.healthcare4all.co.uk/featured-products" 933 title="Featured Products" 934 > 935 Featured Products </a> 936 </div> 937 </li> 938 <li 939 data-child-id="category-node-223-main" 940 class="level-0" 941 > 942 <div 943 class="flex items-center transition-transform duration-150 ease-in-out transform" 944 :class="level0TranslateClass" 945 > 946 <a 947 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 948 bg-container-lighter border-container level-0 949 " 950 href="https://www.healthcare4all.co.uk/respiratory" 951 title="Respiratory" 952 > 953 Respiratory </a> 954 <button 955 data-index="category-node-223" 956 @click="openSubcategory" 957 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 958 bg-container-lighter border-container" 959 aria-label="Open Respiratory subcategories" 960 aria-haspopup="true" 961 :aria-expanded="mobilePanelActiveIdMatchesIndex" 962 > 963 <div class="w-8 h-8 border rounded"> 964 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 965 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 966</svg> 967 </div> 968 </button> 969 </div> 970 <div 971 data-index="category-node-223" 972 data-child-id="category-node-223" 973 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 974 :class="childMenuClass" 975 > 976 <ul 977 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 978 data-index="category-node-223" 979 :class="level1TranslateClass" 980 aria-label="Subcategories" 981 > 982 <li> 983 <button 984 type="button" 985 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 986 data-index="'category-node-223-main'" 987 @click="backToMainCategories" 988 aria-label="Back to main categories" 989 > 990 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 991 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 992</svg>
993 <span class="ml-4"> 994 Respiratory </span> 995 </button> 996 </li> 997 <li> 998 <a 999 href="https://www.healthcare4all.co.uk/respiratory" 1000 title="Respiratory" 1001 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1002 bg-container-lighter border-container 1003 " 1004 > 1005 <span class="ml-10"> 1006 View All </span> 1007 </a> 1008 </li> 1009 <li> 1010 <a 1011 href="https://www.healthcare4all.co.uk/respiratory/asthma-allergy" 1012 title="Asthma & Allergy" 1013 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1014 bg-container-lighter border-container 1015 " 1016 > 1017 <span class="ml-10 text-base text-gray-700"> 1018 Asthma & Allergy </span> 1019 </a> 1020 </li> 1021 <li> 1022 <a 1023 href="https://www.healthcare4all.co.uk/respiratory/nebulisers" 1024 title="Nebulisers" 1025 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1026 bg-container-lighter border-container 1027 " 1028 > 1029 <span class="ml-10 text-base text-gray-700"> 1030 Nebulisers </span> 1031 </a> 1032 </li> 1033 <li> 1034 <a 1035 href="https://www.healthcare4all.co.uk/respiratory/nebuliser-accessories" 1036 title="Nebuliser Accessories" 1037 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1038 bg-container-lighter border-container 1039 " 1040 > 1041 <span class="ml-10 text-base text-gray-700"> 1042 Nebuliser Accessories </span> 1043 </a> 1044 </li> 1045 <li> 1046 <a 1047 href="https://www.healthcare4all.co.uk/respiratory/inhaler-training-equipment" 1048 title="Inhaler Training Equipment" 1049 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1050 bg-container-lighter border-container 1051 " 1052 >
1053 <span class="ml-10 text-base text-gray-700"> 1054 Inhaler Training Equipment </span> 1055 </a> 1056 </li> 1057 <li> 1058 <a 1059 href="https://www.healthcare4all.co.uk/respiratory/oxygen-concentrators" 1060 title="Oxygen Concentrators" 1061 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1062 bg-container-lighter border-container 1063 " 1064 > 1065 <span class="ml-10 text-base text-gray-700"> 1066 Oxygen Concentrators </span> 1067 </a> 1068 </li> 1069 <li> 1070 <a 1071 href="https://www.healthcare4all.co.uk/respiratory/colds-flu" 1072 title="Colds & Flu" 1073 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1074 bg-container-lighter border-container 1075 " 1076 > 1077 <span class="ml-10 text-base text-gray-700"> 1078 Colds & Flu </span> 1079 </a> 1080 </li> 1081 </ul> 1082 <button 1083 @click="closeMenu" 1084 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1085 aria-label="Close menu" 1086 > 1087 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1088 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1089</svg> 1090 </button> 1091 </div> 1092 </li> 1093 <li 1094 data-child-id="category-node-224-main" 1095 class="level-0" 1096 > 1097 <div 1098 class="flex items-center transition-transform duration-150 ease-in-out transform" 1099 :class="level0TranslateClass" 1100 > 1101 <a 1102 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1103 bg-container-lighter border-container level-0 1104 " 1105 href="https://www.healthcare4all.co.uk/monitors" 1106 title="Monitors" 1107 > 1108 Monitors </a> 1109 <button 1110 data-index="category-node-224" 1111 @click="openSubcategory" 1112 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 1113 bg-container-lighter border-container" 1114 aria-label="Open Monitors subcategories" 1115 aria-haspopup="true" 1116 :aria-expanded="mobilePanelActiveIdMatchesIndex" 1117 > 1118 <div class="w-8 h-8 border rounded"> 1119 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 1120 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 1121</svg> 1122 </div> 1123 </button> 1124 </div> 1125 <div 1126 data-index="category-node-224" 1127 data-child-id="category-node-224" 1128 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 1129 :class="childMenuClass" 1130 > 1131 <ul 1132 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 1133 data-index="category-node-224" 1134 :class="level1TranslateClass" 1135 aria-label="Subcategories" 1136 > 1137 <li> 1138 <button 1139 type="button" 1140 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 1141 data-index="'category-node-224-main'" 1142 @click="backToMainCategories" 1143 aria-label="Back to main categories" 1144 > 1145 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1146 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 1147</svg>
1148 <span class="ml-4"> 1149 Monitors </span> 1150 </button> 1151 </li> 1152 <li> 1153 <a 1154 href="https://www.healthcare4all.co.uk/monitors" 1155 title="Monitors" 1156 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1157 bg-container-lighter border-container 1158 " 1159 > 1160 <span class="ml-10"> 1161 View All </span> 1162 </a> 1163 </li> 1164 <li> 1165 <a 1166 href="https://www.healthcare4all.co.uk/monitors/blood-pressure" 1167 title="Blood Pressure" 1168 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1169 bg-container-lighter border-container 1170 " 1171 > 1172 <span class="ml-10 text-base text-gray-700"> 1173 Blood Pressure </span> 1174 </a> 1175 </li> 1176 <li> 1177 <a 1178 href="https://www.healthcare4all.co.uk/monitors/diabetic-equipment" 1179 title="Diabetic Equipment" 1180 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1181 bg-container-lighter border-container 1182 " 1183 > 1184 <span class="ml-10 text-base text-gray-700"> 1185 Diabetic Equipment </span> 1186 </a> 1187 </li> 1188 <li> 1189 <a 1190 href="https://www.healthcare4all.co.uk/monitors/ecg-monitors" 1191 title="ECG Monitors" 1192 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1193 bg-container-lighter border-container 1194 " 1195 > 1196 <span class="ml-10 text-base text-gray-700"> 1197 ECG Monitors </span> 1198 </a> 1199 </li> 1200 <li> 1201 <a 1202 href="https://www.healthcare4all.co.uk/monitors/diagnostic-equipment" 1203 title="Diagnostic Equipment" 1204 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1205 bg-container-lighter border-container 1206 " 1207 >
1208 <span class="ml-10 text-base text-gray-700"> 1209 Diagnostic Equipment </span> 1210 </a> 1211 </li> 1212 <li> 1213 <a 1214 href="https://www.healthcare4all.co.uk/monitors/pulse-oximeters" 1215 title="Pulse Oximeters" 1216 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1217 bg-container-lighter border-container 1218 " 1219 > 1220 <span class="ml-10 text-base text-gray-700"> 1221 Pulse Oximeters </span> 1222 </a> 1223 </li> 1224 <li> 1225 <a 1226 href="https://www.healthcare4all.co.uk/monitors/thermometers" 1227 title="Thermometers" 1228 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1229 bg-container-lighter border-container 1230 " 1231 > 1232 <span class="ml-10 text-base text-gray-700"> 1233 Thermometers </span> 1234 </a> 1235 </li> 1236 </ul> 1237 <button 1238 @click="closeMenu" 1239 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1240 aria-label="Close menu" 1241 > 1242 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1243 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1244</svg> 1245 </button> 1246 </div> 1247 </li> 1248 <li 1249 data-child-id="category-node-225-main" 1250 class="level-0" 1251 > 1252 <div 1253 class="flex items-center transition-transform duration-150 ease-in-out transform" 1254 :class="level0TranslateClass" 1255 > 1256 <a 1257 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1258 bg-container-lighter border-container level-0 1259 " 1260 href="https://www.healthcare4all.co.uk/health-beauty" 1261 title="Health & Beauty" 1262 > 1263 Health & Beauty </a> 1264 <button 1265 data-index="category-node-225" 1266 @click="openSubcategory" 1267 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 1268 bg-container-lighter border-container" 1269 aria-label="Open Health & Beauty subcategories" 1270 aria-haspopup="true" 1271 :aria-expanded="mobilePanelActiveIdMatchesIndex" 1272 > 1273 <div class="w-8 h-8 border rounded"> 1274 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 1275 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 1276</svg> 1277 </div> 1278 </button> 1279 </div> 1280 <div 1281 data-index="category-node-225" 1282 data-child-id="category-node-225" 1283 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 1284 :class="childMenuClass" 1285 > 1286 <ul 1287 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 1288 data-index="category-node-225" 1289 :class="level1TranslateClass" 1290 aria-label="Subcategories" 1291 > 1292 <li> 1293 <button 1294 type="button" 1295 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 1296 data-index="'category-node-225-main'" 1297 @click="backToMainCategories" 1298 aria-label="Back to main categories" 1299 > 1300 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1301 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 1302</svg>
1303 <span class="ml-4"> 1304 Health & Beauty </span> 1305 </button> 1306 </li> 1307 <li> 1308 <a 1309 href="https://www.healthcare4all.co.uk/health-beauty" 1310 title="Health & Beauty" 1311 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1312 bg-container-lighter border-container 1313 " 1314 > 1315 <span class="ml-10"> 1316 View All </span> 1317 </a> 1318 </li> 1319 <li> 1320 <a 1321 href="https://www.healthcare4all.co.uk/health-beauty/skincare" 1322 title="Skincare" 1323 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1324 bg-container-lighter border-container 1325 " 1326 > 1327 <span class="ml-10 text-base text-gray-700"> 1328 Skincare </span> 1329 </a> 1330 </li> 1331 <li> 1332 <a 1333 href="https://www.healthcare4all.co.uk/health-beauty/ladies-hair-removal" 1334 title="Ladies Hair Removal" 1335 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1336 bg-container-lighter border-container 1337 " 1338 > 1339 <span class="ml-10 text-base text-gray-700"> 1340 Ladies Hair Removal </span> 1341 </a> 1342 </li> 1343 <li> 1344 <a 1345 href="https://www.healthcare4all.co.uk/health-beauty/first-aid-dressings" 1346 title="First Aid & Dressings" 1347 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1348 bg-container-lighter border-container 1349 " 1350 > 1351 <span class="ml-10 text-base text-gray-700"> 1352 First Aid & Dressings </span> 1353 </a> 1354 </li> 1355 <li> 1356 <a 1357 href="https://www.healthcare4all.co.uk/health-beauty/beauty" 1358 title="Beauty" 1359 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1360 bg-container-lighter border-container 1361 " 1362 >
1363 <span class="ml-10 text-base text-gray-700"> 1364 Beauty </span> 1365 </a> 1366 </li> 1367 <li> 1368 <a 1369 href="https://www.healthcare4all.co.uk/health-beauty/footcare" 1370 title="Footcare" 1371 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1372 bg-container-lighter border-container 1373 " 1374 > 1375 <span class="ml-10 text-base text-gray-700"> 1376 Footcare </span> 1377 </a> 1378 </li> 1379 <li> 1380 <a 1381 href="https://www.healthcare4all.co.uk/health-beauty/massage" 1382 title="Massage" 1383 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1384 bg-container-lighter border-container 1385 " 1386 > 1387 <span class="ml-10 text-base text-gray-700"> 1388 Massage </span> 1389 </a> 1390 </li> 1391 <li> 1392 <a 1393 href="https://www.healthcare4all.co.uk/health-beauty/therapy" 1394 title="Therapy" 1395 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1396 bg-container-lighter border-container 1397 " 1398 > 1399 <span class="ml-10 text-base text-gray-700"> 1400 Therapy </span> 1401 </a> 1402 </li> 1403 <li> 1404 <a 1405 href="https://www.healthcare4all.co.uk/health-beauty/fitness" 1406 title="Fitness" 1407 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1408 bg-container-lighter border-container 1409 " 1410 > 1411 <span class="ml-10 text-base text-gray-700"> 1412 Fitness </span> 1413 </a> 1414 </li> 1415 <li> 1416 <a 1417 href="https://www.healthcare4all.co.uk/health-beauty/male-grooming-shavers" 1418 title="Male Grooming/Shavers" 1419 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1420 bg-container-lighter border-container 1421 " 1422 >
1423 <span class="ml-10 text-base text-gray-700"> 1424 Male Grooming/Shavers </span> 1425 </a> 1426 </li> 1427 <li> 1428 <a 1429 href="https://www.healthcare4all.co.uk/health-beauty/stairlifts" 1430 title="Stairlifts" 1431 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1432 bg-container-lighter border-container 1433 " 1434 > 1435 <span class="ml-10 text-base text-gray-700"> 1436 Stairlifts </span> 1437 </a> 1438 </li> 1439 <li> 1440 <a 1441 href="https://www.healthcare4all.co.uk/health-beauty/petcare" 1442 title="Petcare" 1443 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1444 bg-container-lighter border-container 1445 " 1446 > 1447 <span class="ml-10 text-base text-gray-700"> 1448 Petcare </span> 1449 </a> 1450 </li> 1451 <li> 1452 <a 1453 href="https://www.healthcare4all.co.uk/health-beauty/haircare" 1454 title="Haircare" 1455 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1456 bg-container-lighter border-container 1457 " 1458 > 1459 <span class="ml-10 text-base text-gray-700"> 1460 Haircare </span> 1461 </a> 1462 </li> 1463 </ul> 1464 <button 1465 @click="closeMenu" 1466 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1467 aria-label="Close menu" 1468 > 1469 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1470 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1471</svg> 1472 </button> 1473 </div> 1474 </li> 1475 <li 1476 data-child-id="category-node-226-main" 1477 class="level-0" 1478 > 1479 <div 1480 class="flex items-center transition-transform duration-150 ease-in-out transform" 1481 :class="level0TranslateClass" 1482 > 1483 <a 1484 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1485 bg-container-lighter border-container level-0 1486 " 1487 href="https://www.healthcare4all.co.uk/eyes-ears-mouth" 1488 title="Eyes, Ears & Mouth" 1489 > 1490 Eyes, Ears & Mouth </a> 1491 <button 1492 data-index="category-node-226" 1493 @click="openSubcategory" 1494 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 1495 bg-container-lighter border-container" 1496 aria-label="Open Eyes, Ears & Mouth subcategories" 1497 aria-haspopup="true" 1498 :aria-expanded="mobilePanelActiveIdMatchesIndex" 1499 > 1500 <div class="w-8 h-8 border rounded"> 1501 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 1502 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 1503</svg> 1504 </div> 1505 </button> 1506 </div> 1507 <div 1508 data-index="category-node-226" 1509 data-child-id="category-node-226" 1510 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 1511 :class="childMenuClass" 1512 > 1513 <ul 1514 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 1515 data-index="category-node-226" 1516 :class="level1TranslateClass" 1517 aria-label="Subcategories" 1518 > 1519 <li> 1520 <button 1521 type="button" 1522 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 1523 data-index="'category-node-226-main'" 1524 @click="backToMainCategories" 1525 aria-label="Back to main categories" 1526 > 1527 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1528 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 1529</svg>
1530 <span class="ml-4"> 1531 Eyes, Ears & Mouth </span> 1532 </button> 1533 </li> 1534 <li> 1535 <a 1536 href="https://www.healthcare4all.co.uk/eyes-ears-mouth" 1537 title="Eyes, Ears & Mouth" 1538 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1539 bg-container-lighter border-container 1540 " 1541 > 1542 <span class="ml-10"> 1543 View All </span> 1544 </a> 1545 </li> 1546 <li> 1547 <a 1548 href="https://www.healthcare4all.co.uk/eyes-ears-mouth/eye-care" 1549 title="Eye Care" 1550 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1551 bg-container-lighter border-container 1552 " 1553 > 1554 <span class="ml-10 text-base text-gray-700"> 1555 Eye Care </span> 1556 </a> 1557 </li> 1558 <li> 1559 <a 1560 href="https://www.healthcare4all.co.uk/eyes-ears-mouth/ear-care" 1561 title="Ear Care" 1562 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1563 bg-container-lighter border-container 1564 " 1565 > 1566 <span class="ml-10 text-base text-gray-700"> 1567 Ear Care </span> 1568 </a> 1569 </li> 1570 <li> 1571 <a 1572 href="https://www.healthcare4all.co.uk/eyes-ears-mouth/dental-hygiene" 1573 title="Dental Hygiene" 1574 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1575 bg-container-lighter border-container 1576 " 1577 > 1578 <span class="ml-10 text-base text-gray-700"> 1579 Dental Hygiene </span> 1580 </a> 1581 </li> 1582 </ul> 1583 <button 1584 @click="closeMenu" 1585 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1586 aria-label="Close menu" 1587 > 1588 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1589 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1590</svg> 1591 </button> 1592 </div> 1593 </li> 1594 <li 1595 data-child-id="category-node-227-main" 1596 class="level-0" 1597 > 1598 <div 1599 class="flex items-center transition-transform duration-150 ease-in-out transform" 1600 :class="level0TranslateClass" 1601 > 1602 <a 1603 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1604 bg-container-lighter border-container level-0 1605 " 1606 href="https://www.healthcare4all.co.uk/pain-relief" 1607 title="Pain Relief" 1608 > 1609 Pain Relief </a> 1610 <button 1611 data-index="category-node-227" 1612 @click="openSubcategory" 1613 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 1614 bg-container-lighter border-container" 1615 aria-label="Open Pain Relief subcategories" 1616 aria-haspopup="true" 1617 :aria-expanded="mobilePanelActiveIdMatchesIndex" 1618 > 1619 <div class="w-8 h-8 border rounded"> 1620 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 1621 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 1622</svg> 1623 </div> 1624 </button> 1625 </div> 1626 <div 1627 data-index="category-node-227" 1628 data-child-id="category-node-227" 1629 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 1630 :class="childMenuClass" 1631 > 1632 <ul 1633 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 1634 data-index="category-node-227" 1635 :class="level1TranslateClass" 1636 aria-label="Subcategories" 1637 > 1638 <li> 1639 <button 1640 type="button" 1641 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 1642 data-index="'category-node-227-main'" 1643 @click="backToMainCategories" 1644 aria-label="Back to main categories" 1645 > 1646 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1647 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 1648</svg>
1649 <span class="ml-4"> 1650 Pain Relief </span> 1651 </button> 1652 </li> 1653 <li> 1654 <a 1655 href="https://www.healthcare4all.co.uk/pain-relief" 1656 title="Pain Relief" 1657 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1658 bg-container-lighter border-container 1659 " 1660 > 1661 <span class="ml-10"> 1662 View All </span> 1663 </a> 1664 </li> 1665 <li> 1666 <a 1667 href="https://www.healthcare4all.co.uk/pain-relief/pain-relief-tens" 1668 title="Pain Relief + TENS" 1669 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1670 bg-container-lighter border-container 1671 " 1672 > 1673 <span class="ml-10 text-base text-gray-700"> 1674 Pain Relief + TENS </span> 1675 </a> 1676 </li> 1677 </ul> 1678 <button 1679 @click="closeMenu" 1680 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1681 aria-label="Close menu" 1682 > 1683 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1684 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1685</svg> 1686 </button> 1687 </div> 1688 </li> 1689 <li 1690 data-child-id="category-node-228-main" 1691 class="level-0" 1692 > 1693 <div 1694 class="flex items-center transition-transform duration-150 ease-in-out transform" 1695 :class="level0TranslateClass" 1696 > 1697 <a 1698 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1699 bg-container-lighter border-container level-0 1700 " 1701 href="https://www.healthcare4all.co.uk/mother-and-baby" 1702 title="Mother and Baby" 1703 > 1704 Mother and Baby </a> 1705 <button 1706 data-index="category-node-228" 1707 @click="openSubcategory" 1708 class="absolute right-0 flex items-center justify-center w-11 h-11 mr-8 cursor-pointer 1709 bg-container-lighter border-container" 1710 aria-label="Open Mother and Baby subcategories" 1711 aria-haspopup="true" 1712 :aria-expanded="mobilePanelActiveIdMatchesIndex" 1713 > 1714 <div class="w-8 h-8 border rounded"> 1715 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-full h-full p-1" width="24" height="24" aria-hidden="true"> 1716 <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/> 1717</svg> 1718 </div> 1719 </button> 1720 </div> 1721 <div 1722 data-index="category-node-228" 1723 data-child-id="category-node-228" 1724 class="absolute top-0 right-0 z-10 flex flex-col gap-1 w-full h-full p-1 bg-container-lighter" 1725 :class="childMenuClass" 1726 > 1727 <ul 1728 class="mt-16 transition-transform duration-200 ease-in-out translate-x-full transform" 1729 data-index="category-node-228" 1730 :class="level1TranslateClass" 1731 aria-label="Subcategories" 1732 > 1733 <li> 1734 <button 1735 type="button" 1736 class="flex items-center px-8 py-4 border-b cursor-pointer bg-container border-container w-full border-t" 1737 data-index="'category-node-228-main'" 1738 @click="backToMainCategories" 1739 aria-label="Back to main categories" 1740 > 1741 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1742 <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/> 1743</svg>
1744 <span class="ml-4"> 1745 Mother and Baby </span> 1746 </button> 1747 </li> 1748 <li> 1749 <a 1750 href="https://www.healthcare4all.co.uk/mother-and-baby" 1751 title="Mother and Baby" 1752 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1753 bg-container-lighter border-container 1754 " 1755 > 1756 <span class="ml-10"> 1757 View All </span> 1758 </a> 1759 </li> 1760 <li> 1761 <a 1762 href="https://www.healthcare4all.co.uk/mother-and-baby/baby-maternity" 1763 title="Baby & Maternity" 1764 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1765 bg-container-lighter border-container 1766 " 1767 > 1768 <span class="ml-10 text-base text-gray-700"> 1769 Baby & Maternity </span> 1770 </a> 1771 </li> 1772 </ul> 1773 <button 1774 @click="closeMenu" 1775 class="absolute flex justify-end w-16 self-end mb-1 transition-none" 1776 aria-label="Close menu" 1777 > 1778 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1779 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1780</svg> 1781 </button> 1782 </div> 1783 </li> 1784 <li 1785 data-child-id="magefan-blog-main" 1786 class="level-0" 1787 > 1788 <div 1789 class="flex items-center transition-transform duration-150 ease-in-out transform" 1790 :class="level0TranslateClass" 1791 > 1792 <a 1793 class="flex items-center w-full px-8 py-4 border-b cursor-pointer 1794 bg-container-lighter border-container level-0 1795 " 1796 href="https://www.healthcare4all.co.uk/blog" 1797 title="Blog" 1798 > 1799 Blog </a> 1800 </div> 1801 </li> 1802 </ul> 1803 <div id="mobile-menu-glopal-slot" class="px-8 py-4 border-t border-container mt-auto 1804 transition-transform duration-150 ease-in-out transform" 1805 :class="level0TranslateClass" 1806 ></div> 1807 <button 1808 @click="closeMenu" 1809 class="absolute flex justify-end w-16 self-end mb-1" 1810 aria-label="Close menu" 1811 type="button" 1812 > 1813 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="hidden p-4" width="64" height="64" :class="triggerCloseSvgClass" aria-hidden="true"> 1814 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1815</svg> 1816 </button> 1817 </div> 1818</nav>
1819<script> 1820 const initMenuMobile = () => { 1821 return { 1822 mobilePanelActiveId: null, 1823 1824 open: false, 1825 closed() { 1826 return !this.open 1827 }, 1828 1829 triggerButtonClass() { 1830 return { 1831 'overflow-x-hidden overflow-y-auto fixed top-0 left-0 w-full': this.open 1832 } 1833 }, 1834 triggerSvgClass() { 1835 return { 1836 'hidden': this.open, 1837 'block': !this.open 1838 } 1839 }, 1840 triggerCloseSvgClass() { 1841 return { 1842 'hidden': !this.open, 1843 'block': this.open 1844 } 1845 }, 1846 mobileMenuNavLinksClass() { 1847 return { 1848 'flex': this.open, 1849 'hidden': !this.open 1850 } 1851 }, 1852 level0TranslateClass() { 1853 return { 1854 '-translate-x-full': this.mobilePanelActiveId, 1855 'translate-x-0': !this.mobilePanelActiveId 1856 } 1857 }, 1858 level1TranslateClass() { 1859 return { 1860 'translate-x-full': !this.mobilePanelActiveIdMatchesIndex(), 1861 'translate-x-0': this.mobilePanelActiveIdMatchesIndex(), 1862 } 1863 }, 1864 childMenuClass() { 1865 return { 1866 'hidden': !this.mobilePanelActiveIdMatchesIndex() 1867 } 1868 }, 1869 1870 mobilePanelActiveIdMatchesIndex() { 1871 return this.mobilePanelActiveId === this.$el.dataset.index 1872 }, 1873
1874 setActiveMenu() { 1875 const menuNode = this.$root 1876 1877 Array.from(menuNode.querySelectorAll('a')).filter(link => { 1878 return link.href === window.location.href.split('?')[0] 1879 }).map(item => { 1880 item.classList.add('underline') 1881 1882 item.closest('li.level-0') && 1883 item.closest('li.level-0').querySelector('a.level-0').classList.add('underline') 1884 }) 1885 }, 1886 openMenu() { 1887 this.open = true 1888 this.$nextTick(() => hyva.trapFocus(this.$refs['mobileMenuNavLinks'])) 1889 // Prevent from body scrolling while mobile menu opened 1890 document.body.style.overflow = 'hidden' 1891 document.body.classList.add('mobile-menu-open') 1892 }, 1893 closeMenu() { 1894 document.body.style.overflow = '' 1895 document.body.classList.remove('mobile-menu-open') 1896 1897 if (this.open) { 1898 this.$nextTick(() => this.$refs['mobileMenuTrigger'].focus() || hyva.releaseFocus()); 1899 } 1900 1901 this.open = false 1902 this.mobilePanelActiveId = null 1903 }, 1904 openSubcategory() { 1905 const 1906 index = this.$el.dataset.index, 1907 menuNodeRef = document.querySelector('[data-child-id=' + index + ']') 1908 1909 this.mobilePanelActiveId = this.mobilePanelActiveId === index ? 0 : index 1910 this.$nextTick(() => hyva.trapFocus(menuNodeRef)) 1911 }, 1912 backToMainCategories() { 1913 const 1914 index = this.$el.dataset.index, 1915 menuNodeRef = document.querySelector('[data-child-id=' + index + ']') 1916 1917 this.mobilePanelActiveId = 0 1918 this.$nextTick(() => { 1919 hyva.trapFocus(this.$refs['mobileMenuNavLinks']) 1920 menuNodeRef.querySelector('a').focus() 1921 }) 1922 } 1923 } 1924 } 1925 1926 window.addEventListener('alpine:init', () => Alpine.data('initMenuMobile', initMenuMobile), {once: true}) 1927</script>
1927 1928 1929<a 1930 class="inline-block align-middle" 1931 href="https://www.healthcare4all.co.uk/" 1932 title="Go to Home page" 1933> 1934 <img 1935 src="https://www.healthcare4all.co.uk/media/logo/stores/1/HC4A_logo.svg" 1936 alt="Healthcare4all" 1937 width="262" 1938 height="40" 1939 loading="eager" 1940 fetchpriority="high" 1941 > 1942 </a> 1943 1944 <div class="ml-auto flex gap-0.5 items-center lg:order-2"> 1945 1946<a 1947 id="compare-link" 1948 class="relative hidden md:inline-block rounded p-1 hover:bg-primary/10 outline-offset-2 invisible" 1949 :class="hiddenIfEmpty" 1950 href="https://www.healthcare4all.co.uk/catalog/product_compare/index/" 1951 title="Compare Products" 1952 x-data="initCompareHeader" 1953 @private-content-loaded.window="receiveCompareData" 1954 :aria-label="linkAriaLabel" 1955> 1956 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1957 <path stroke-linecap="round" stroke-linejoin="round" d="M3 6l3 1m0 0l-3 9a5.002 5.002 0 006.001 0M6 7l3 9M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9m-3-9l-6-2m0-2v2m0 16V5m0 16H9m3 0h3"/> 1958</svg> 1959 <span 1960 x-text="itemCount" 1961 class="absolute -top-1.5 -right-1.5 px-2 py-0.5 rounded-full bg-blue-200 text-blue-800 1962 text-xs font-semibold leading-none text-center uppercase tabular-nums" 1963 aria-hidden="true" 1964 ></span> 1965</a> 1966 1967 1968 1969 1970<div 1971 class="relative inline-block" 1972 x-data="initCustomerMenu" 1973 @keyup.escape="setOpenFalse" 1974 @click.outside="setOpenFalse" 1975> 1976 <button 1977 type="button" 1978 id="customer-menu" 1979 class="block rounded p-1 hover:bg-primary/10 outline-offset-2" 1980 @click="toggleOpen" 1981 :aria-expanded="ariaExpanded" 1982 aria-label="My Account" 1983 aria-haspopup="true" 1984 > 1985 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 1986 <path stroke-linecap="round" stroke-linejoin="round" d="M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> 1987</svg> 1988 </button> 1989 <nav 1990 class="z-30 absolute -right-4 w-48 sm:w-56 mt-2 py-2 px-1 overflow-auto 1991 rounded shadow-lg lg:mt-3 bg-container-lighter" 1992 x-cloak 1993 x-show="open" 1994 x-transition 1995 aria-labelledby="customer-menu" 1996 > 1997 1998<a 1999 id="catalog.compare.link.logged.out" 2000 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100 relative" 2001 href="https://www.healthcare4all.co.uk/catalog/product_compare/index/" 2002 title="Compare Products" 2003 x-data="initCompareHeader" 2004 @private-content-loaded.window="receiveCompareData" 2005> 2006 Compare Products <template x-if="itemCount"> 2007 <span class="tabular-nums" x-text="itemCountLabel"></span> 2008 </template> 2009</a> 2010 2011<a id="customer.header.sign.in.link" 2012 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100" 2013 onclick="hyva.setCookie && hyva.setCookie( 2014 'login_redirect', 2015 window.location.href, 2016 1 2017 )" 2018 href="https://www.healthcare4all.co.uk/customer/account/index/" 2019 title="Sign In" 2020> 2021 Sign In</a> 2022 2023 <a id="customer.header.register.link" 2024 class="block px-4 py-2 lg:px-5 lg:py-2 hover:bg-gray-100" 2025 href="https://www.healthcare4all.co.uk/customer/account/create/" 2026 title="Create an Account" 2027 > 2028 Create an Account </a> 2029 </nav> 2030</div>
2031<script> 2032 function initCustomerMenu() { 2033 return hyva.createBooleanObject('open', false, { 2034 ariaExpanded() { 2035 return this.open() ? 'true' : 'false'; 2036 } 2037 }) 2038 } 2039 window.addEventListener('alpine:init', () => Alpine.data('initCustomerMenu', initCustomerMenu), {once: true}) 2040</script>
2040 2041 2042 2043 <button 2044 id="menu-cart-icon" 2045 class="relative inline-block rounded p-1 hover:bg-primary/10 outline-offset-2" 2046 x-ref="cartButton" 2047 :aria-disabled="isCartEmpty" 2048 :aria-label="ariaLabel" 2049 @click.prevent="openCart" 2050 @toggle-cart.window="toggleCart" 2051 :aria-expanded="isCartOpen" 2052 aria-haspopup="dialog" 2053 > 2054 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2055 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/> 2056</svg> 2057 <span 2058 x-text="summaryCount" 2059 x-show="summaryCount" 2060 x-cloak 2061 class="absolute -top-1.5 -right-1.5 px-2 py-0.5 rounded-full bg-green-200 text-green-800 2062 text-xs font-semibold leading-none text-center uppercase tabular-nums" 2063 aria-hidden="true" 2064 ></span> 2065 </button> 2066 </div> 2067 2068 <div class="col-span-full py-4 lg:py-0 lg:col-auto lg:order-1 2069 [border-image:conic-gradient(theme(colors.slate.200)_0_0)_fill_0//0_100vw] lg:[border-image:none]"> 2070
2071<script> 2072 function initMiniSearchComponent() { 2073 return { 2074 show:false, 2075 formSelector: "#search_mini_form", 2076 url: "https://www.healthcare4all.co.uk/search/ajax/suggest/", 2077 destinationSelector: "#search_autocomplete", 2078 templates: {"term":{"title":"Search terms","template":"Hyva_SmileElasticsuite::core\/autocomplete\/term.phtml"},"product":{"title":"Products","template":"Hyva_SmileElasticsuite::catalog\/autocomplete\/product.phtml"},"category":{"title":"Categories","template":"Hyva_SmileElasticsuite::catalog\/autocomplete\/category.phtml"},"product_attribute":{"title":"Attributes","template":"Hyva_SmileElasticsuite::catalog\/autocomplete\/product_attribute.phtml","titleRenderer":"renderEsAutocompleteTitleAttribute"},"cms_page":{"title":"Cms page","template":"Hyva_SmileElasticsuite::cms-search\/autocomplete\/cms.phtml"}}, 2079 priceFormat: {"pattern":"\u00a3%s","precision":2,"requiredPrecision":2,"decimalSymbol":".","groupSymbol":",","groupLength":3,"integerRequired":false}, 2080 minSearchLength: 1, 2081 searchResultsByType: {}, 2082 currentRequest: null, 2083 2084 /** 2085 * Get search results. 2086 */ 2087 getSearchResults: function () { 2088 let value = document.querySelector('#search').value.trim(); 2089 2090 if (value.length < parseInt(this.minSearchLength, 10)) { 2091 this.searchResultsByType = []; 2092 2093 return false; 2094 } 2095 2096 let url = this.url + '?' + new URLSearchParams({ 2097 q: document.querySelector('#search').value, 2098 _: Date.now() 2099 }).toString(); 2100 2101 if (this.currentRequest !== null) { 2102 this.currentRequest.abort(); 2103 } 2104 this.currentRequest = new AbortController(); 2105 2106 fetch(url, { 2107 method: 'GET', 2108 signal: this.currentRequest.signal, 2109 }).then((response) => { 2110 if (response.ok) { 2111 return response.json(); 2112 } 2113 }).then((data) => { 2114 this.show = data.length > 0; 2115 2116 this.searchResultsByType = data.reduce((acc, result) => { 2117 if (! acc[result.type]) acc[result.type] = []; 2118 acc[result.type].push(result); 2119 return acc; 2120 }, {}); 2121 }).catch((error) => { 2122 ; 2123 }); 2124 }, 2125 } 2126 } 2127</script>
2127 2128<search 2129 id="elasticsuite-search-container" 2130 x-data="initMiniSearchComponent()" 2131 @click.away="show = false" 2132> 2133 <form class="form minisearch container px-0" id="search_mini_form" action="https://www.healthcare4all.co.uk/catalogsearch/result/" method="get"> 2134 <div class="flex items-stretch"> 2135 <label class="sr-only" for="search" data-role="minisearch-label"> 2136 <span>Search</span> 2137 </label> 2138 <input 2139 id="search" 2140 x-ref="searchInput" 2141 type="search" 2142 autocapitalize="off" 2143 autocomplete="off" 2144 autocorrect="off" 2145 name="q" 2146 value="" 2147 placeholder="Search entire store here..." 2148 maxlength="128" 2149 class="w-full border-slate-300 rounded-l-md rounded-r-none focus:border-[#089A8A] focus:ring-[#089A8A]" 2150 @input.debounce.300="getSearchResults()" 2151 @search-open.window.debounce.10="$el.focus(); $el.select()" 2152 > 2153 <button 2154 type="submit" 2155 title="Search" 2156 class="action search btn justify-center rounded-md text-base hover:shadow-lg active:shadow disabled:shadow-none transition rounded-l-none rounded-r-md shadow-none px-3 2157 text-white border border-transparent disabled:bg-slate-600 disabled:text-slate-50 disabled:opacity-70 flex items-center" 2158 style="background-color: #089A8A; border-top-left-radius: 0; border-bottom-left-radius: 0;" 2159 aria-label="Search" 2160 > 2161 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 2162 <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/> 2163</svg> 2164 </button> 2165 </div> 2166 <div id="search_autocomplete" class="search-autocomplete relative w-full" x-show="show" x-cloak> 2167 <div class="z-10 absolute bg-white border border-gray-200 shadow-lg rounded-b-lg w-full flex flex-col md:flex-row"> 2168 <template x-for="searchResultByType in Object.values(searchResultsByType)"> 2169 <div :class="searchResultByType.hasOwnProperty(0) && searchResultByType[0].type === 'product' 2170 ? 'flex-1 border-t md:border-t-0 md:border-l border-gray-200' 2171 : 'md:w-52 shrink-0'"> 2172 <template x-if="searchResultByType.hasOwnProperty(0) && templates[searchResultByType[0].type].title && templates[searchResultByType[0].type].titleRenderer === undefined"> 2173 <div class="font-bold text-xs uppercase tracking-wide text-gray-500 pt-3 pb-1 px-3 border-b border-gray-100" x-text="templates[searchResultByType[0].type].title"></div> 2174 </template> 2175 <template x-if="searchResultByType.hasOwnProperty(0) && templates[searchResultByType[0].type].titleRenderer !== undefined"> 2176 <div class="font-bold text-xs uppercase tracking-wide text-gray-500 pt-3 pb-1 px-3 border-b border-gray-100" x-text="window[templates[searchResultByType[0].type].titleRenderer](searchResultByType)"></div> 2177 </template> 2178 2179 <template x-for="searchResult in searchResultByType"> 2180 <div class="hover:bg-slate-50"> 2181 2182<template x-if="searchResult.type == 'term'"> 2183 <a class="w-full block p-2" 2184 x-bind:href="'https://www.healthcare4all.co.uk/catalogsearch/result/?q=' + searchResult.title" 2185 :title="searchResult.title"> 2186 <span class="text-sm" x-text="searchResult.title"></span> 2187 <span class="text-sm" x-text="'(' + searchResult.num_results + ')'"></span> 2188 </a> 2189</template> 2190 2191<template x-if="searchResult.type == 'product'"> 2192 <a class="w-full block" :href="searchResult.url" :title="searchResult.title"> 2193 <div class="grid grid-cols-4 gap-4 p-3"> 2194 <div> 2195 <img :src="searchResult.image" class="inline-block" /> 2196 </div> 2197 <div class="col-span-3">
2198 <span class="text-sm" x-text="searchResult.title"></span> 2199 <span class="text-sm font-bold" x-html="searchResult.price"></span> 2200 </div> 2201 </div> 2202 </a> 2203</template> 2204 2205<template x-if="searchResult.type == 'category'"> 2206 <a class="w-full block p-2" :href="searchResult.url" :title="searchResult.title"> 2207 <span class="text-sm italic block text-gray-500" x-text="searchResult.breadcrumb.join(' > ').concat(' > ')"></span> 2208 <span class="text-sm" x-text="searchResult.title"></span> 2209 </a> 2210</template> 2211 2212<template x-if="searchResult.type == 'product_attribute'"> 2213 <a class="w-full block p-2" :href="searchResult.url" :title="searchResult.title"> 2214 <span class="text-sm" x-text="searchResult.title"></span> 2215 <span class="text-xs uppercase text-gray-500" x-text="searchResult.attribute_label" style="vertical-align: super;"></span> 2216 </a> 2217</template> 2218
2219<script> 2220 function renderEsAutocompleteTitleAttribute(data) 2221 { 2222 data = data.filter(function(item) { 2223 return item.type === 'product_attribute'; 2224 }).map(function(item) { 2225 return item['attribute_label'] 2226 }).reduce(function(prev, item) { 2227 if (item in prev) { 2228 prev[item]++; 2229 } else { 2230 prev[item] = 1; 2231 } 2232 return prev; 2233 }, {}); 2234 2235 data = Object.entries(data).sort(function(item1, item2) { 2236 return item2[1] - item1[1] 2237 }).map(function(item) {return item[0]}); 2238 2239 if (data.length > 2) { 2240 data = data.slice(0, 2); 2241 data.push('...'); 2242 } 2243 2244 return data.join(', '); 2245 } 2246</script>
2246 2247 2248<template x-if="searchResult.type == 'cms_page'"> 2249 <a class="w-full block p-2" :href="searchResult.url" :title="searchResult.title"> 2250 <span class="text-sm" x-text="searchResult.title"></span> 2251 </a> 2252</template> 2253 </div> 2254 </template> 2255 </div> 2256 </template> 2257 </div> 2258 </div> 2259 </form> 2260</search> 2261 </div> 2262 </div> 2263 2264 <div class="menubg hidden lg:block"> 2265 <div class="container"> 2266 <div x-data="initMenuDesktop_6ac3dca589135()" 2267 class="z-20 order-2 sm:order-1 lg:order-2 navigation hidden lg:block w-full" 2268> 2269 <!-- desktop --> 2270 <div x-ref="nav-desktop" 2271 class="hidden lg:block w-full"> 2272 <nav 2273 class="relative" 2274 aria-label="Main menu" 2275 > 2276 <ul class="flex justify-center flex-wrap gap-x-4 pt-0 pb-4"> 2277 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2278 @mouseenter="hoverPanelActiveId = 'category-node-218'" 2279 @mouseleave="hoverPanelActiveId = 0" 2280 @keyup.escape="hoverPanelActiveId = 0" 2281 > 2282 <span class="flex items-center text-md"> 2283 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2284 href="https://www.healthcare4all.co.uk/offers" 2285 title="Offers" 2286 @focus="hoverPanelActiveId = 0" 2287 > 2288 Offers </a> 2289 </span> 2290 </li> 2291 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2292 @mouseenter="hoverPanelActiveId = 'category-node-222'" 2293 @mouseleave="hoverPanelActiveId = 0" 2294 @keyup.escape="hoverPanelActiveId = 0" 2295 > 2296 <span class="flex items-center text-md"> 2297 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2298 href="https://www.healthcare4all.co.uk/featured-products" 2299 title="Featured Products" 2300 @focus="hoverPanelActiveId = 0" 2301 > 2302 Featured Products </a> 2303 </span> 2304 </li> 2305 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2306 @mouseenter="hoverPanelActiveId = 'category-node-223'" 2307 @mouseleave="hoverPanelActiveId = 0" 2308 @keyup.escape="hoverPanelActiveId = 0" 2309 > 2310 <span class="flex items-center text-md"> 2311 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2312 href="https://www.healthcare4all.co.uk/respiratory" 2313 title="Respiratory" 2314 @focus="hoverPanelActiveId = 0" 2315 > 2316 Respiratory </a> 2317 <button 2318 type="button" 2319 data-sr-button-id="category-node-223" 2320 :aria-expanded="hoverPanelActiveId === 'category-node-223' ? 'true' : 'false'" 2321 @click="openMenuOnClick('category-node-223')" 2322 class="rounded p-1 text-gray-500" 2323 > 2324 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2325 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2326</svg>
2327 <span class="sr-only"> 2328 Show submenu for Respiratory category </span> 2329 </button> 2330 </span> 2331 <ul 2332 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2333 :class="{ 2334 'hidden' : hoverPanelActiveId !== 'category-node-223', 2335 'block' : hoverPanelActiveId === 'category-node-223' 2336 }" 2337 > 2338 <li> 2339 <a href="https://www.healthcare4all.co.uk/respiratory/asthma-allergy" 2340 title="Asthma & Allergy" 2341 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2342 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2343 > 2344 <span class="text-base text-gray-700"> 2345 Asthma & Allergy </span> 2346 </a> 2347 </li> 2348 <li> 2349 <a href="https://www.healthcare4all.co.uk/respiratory/nebulisers" 2350 title="Nebulisers" 2351 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2352 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2353 > 2354 <span class="text-base text-gray-700"> 2355 Nebulisers </span> 2356 </a> 2357 </li> 2358 <li> 2359 <a href="https://www.healthcare4all.co.uk/respiratory/nebuliser-accessories" 2360 title="Nebuliser Accessories" 2361 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2362 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2363 > 2364 <span class="text-base text-gray-700"> 2365 Nebuliser Accessories </span> 2366 </a> 2367 </li> 2368 <li> 2369 <a href="https://www.healthcare4all.co.uk/respiratory/inhaler-training-equipment" 2370 title="Inhaler Training Equipment" 2371 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2372 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2373 >
2374 <span class="text-base text-gray-700"> 2375 Inhaler Training Equipment </span> 2376 </a> 2377 </li> 2378 <li> 2379 <a href="https://www.healthcare4all.co.uk/respiratory/oxygen-concentrators" 2380 title="Oxygen Concentrators" 2381 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2382 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2383 > 2384 <span class="text-base text-gray-700"> 2385 Oxygen Concentrators </span> 2386 </a> 2387 </li> 2388 <li> 2389 <a href="https://www.healthcare4all.co.uk/respiratory/colds-flu" 2390 title="Colds & Flu" 2391 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2392 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D223]').focus())" 2393 > 2394 <span class="text-base text-gray-700"> 2395 Colds & Flu </span> 2396 </a> 2397 </li> 2398 </ul> 2399 </li> 2400 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2401 @mouseenter="hoverPanelActiveId = 'category-node-224'" 2402 @mouseleave="hoverPanelActiveId = 0" 2403 @keyup.escape="hoverPanelActiveId = 0" 2404 > 2405 <span class="flex items-center text-md"> 2406 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2407 href="https://www.healthcare4all.co.uk/monitors" 2408 title="Monitors" 2409 @focus="hoverPanelActiveId = 0" 2410 > 2411 Monitors </a> 2412 <button 2413 type="button" 2414 data-sr-button-id="category-node-224" 2415 :aria-expanded="hoverPanelActiveId === 'category-node-224' ? 'true' : 'false'" 2416 @click="openMenuOnClick('category-node-224')" 2417 class="rounded p-1 text-gray-500" 2418 > 2419 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2420 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2421</svg> 2422 <span class="sr-only"> 2423 Show submenu for Monitors category </span> 2424 </button> 2425 </span> 2426 <ul 2427 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2428 :class="{ 2429 'hidden' : hoverPanelActiveId !== 'category-node-224', 2430 'block' : hoverPanelActiveId === 'category-node-224' 2431 }" 2432 > 2433 <li> 2434 <a href="https://www.healthcare4all.co.uk/monitors/blood-pressure" 2435 title="Blood Pressure" 2436 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2437 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2438 >
2439 <span class="text-base text-gray-700"> 2440 Blood Pressure </span> 2441 </a> 2442 </li> 2443 <li> 2444 <a href="https://www.healthcare4all.co.uk/monitors/diabetic-equipment" 2445 title="Diabetic Equipment" 2446 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2447 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2448 > 2449 <span class="text-base text-gray-700"> 2450 Diabetic Equipment </span> 2451 </a> 2452 </li> 2453 <li> 2454 <a href="https://www.healthcare4all.co.uk/monitors/ecg-monitors" 2455 title="ECG Monitors" 2456 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2457 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2458 > 2459 <span class="text-base text-gray-700"> 2460 ECG Monitors </span> 2461 </a> 2462 </li> 2463 <li> 2464 <a href="https://www.healthcare4all.co.uk/monitors/diagnostic-equipment" 2465 title="Diagnostic Equipment" 2466 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2467 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2468 > 2469 <span class="text-base text-gray-700"> 2470 Diagnostic Equipment </span> 2471 </a> 2472 </li> 2473 <li> 2474 <a href="https://www.healthcare4all.co.uk/monitors/pulse-oximeters" 2475 title="Pulse Oximeters" 2476 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2477 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2478 > 2479 <span class="text-base text-gray-700"> 2480 Pulse Oximeters </span> 2481 </a> 2482 </li> 2483 <li> 2484 <a href="https://www.healthcare4all.co.uk/monitors/thermometers" 2485 title="Thermometers" 2486 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2487 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D224]').focus())" 2488 >
2489 <span class="text-base text-gray-700"> 2490 Thermometers </span> 2491 </a> 2492 </li> 2493 </ul> 2494 </li> 2495 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2496 @mouseenter="hoverPanelActiveId = 'category-node-225'" 2497 @mouseleave="hoverPanelActiveId = 0" 2498 @keyup.escape="hoverPanelActiveId = 0" 2499 > 2500 <span class="flex items-center text-md"> 2501 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2502 href="https://www.healthcare4all.co.uk/health-beauty" 2503 title="Health & Beauty" 2504 @focus="hoverPanelActiveId = 0" 2505 > 2506 Health & Beauty </a> 2507 <button 2508 type="button" 2509 data-sr-button-id="category-node-225" 2510 :aria-expanded="hoverPanelActiveId === 'category-node-225' ? 'true' : 'false'" 2511 @click="openMenuOnClick('category-node-225')" 2512 class="rounded p-1 text-gray-500" 2513 > 2514 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2515 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2516</svg> 2517 <span class="sr-only"> 2518 Show submenu for Health & Beauty category </span> 2519 </button> 2520 </span> 2521 <ul 2522 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2523 :class="{ 2524 'hidden' : hoverPanelActiveId !== 'category-node-225', 2525 'block' : hoverPanelActiveId === 'category-node-225' 2526 }" 2527 > 2528 <li> 2529 <a href="https://www.healthcare4all.co.uk/health-beauty/skincare" 2530 title="Skincare" 2531 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2532 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2533 > 2534 <span class="text-base text-gray-700"> 2535 Skincare </span> 2536 </a> 2537 </li> 2538 <li> 2539 <a href="https://www.healthcare4all.co.uk/health-beauty/ladies-hair-removal" 2540 title="Ladies Hair Removal" 2541 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2542 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2543 >
2544 <span class="text-base text-gray-700"> 2545 Ladies Hair Removal </span> 2546 </a> 2547 </li> 2548 <li> 2549 <a href="https://www.healthcare4all.co.uk/health-beauty/first-aid-dressings" 2550 title="First Aid & Dressings" 2551 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2552 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2553 > 2554 <span class="text-base text-gray-700"> 2555 First Aid & Dressings </span> 2556 </a> 2557 </li> 2558 <li> 2559 <a href="https://www.healthcare4all.co.uk/health-beauty/beauty" 2560 title="Beauty" 2561 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2562 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2563 > 2564 <span class="text-base text-gray-700"> 2565 Beauty </span> 2566 </a> 2567 </li> 2568 <li> 2569 <a href="https://www.healthcare4all.co.uk/health-beauty/footcare" 2570 title="Footcare" 2571 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2572 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2573 > 2574 <span class="text-base text-gray-700"> 2575 Footcare </span> 2576 </a> 2577 </li> 2578 <li> 2579 <a href="https://www.healthcare4all.co.uk/health-beauty/massage" 2580 title="Massage" 2581 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2582 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2583 > 2584 <span class="text-base text-gray-700"> 2585 Massage </span> 2586 </a> 2587 </li> 2588 <li> 2589 <a href="https://www.healthcare4all.co.uk/health-beauty/therapy" 2590 title="Therapy" 2591 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2592 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2593 >
2594 <span class="text-base text-gray-700"> 2595 Therapy </span> 2596 </a> 2597 </li> 2598 <li> 2599 <a href="https://www.healthcare4all.co.uk/health-beauty/fitness" 2600 title="Fitness" 2601 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2602 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2603 > 2604 <span class="text-base text-gray-700"> 2605 Fitness </span> 2606 </a> 2607 </li> 2608 <li> 2609 <a href="https://www.healthcare4all.co.uk/health-beauty/male-grooming-shavers" 2610 title="Male Grooming/Shavers" 2611 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2612 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2613 > 2614 <span class="text-base text-gray-700"> 2615 Male Grooming/Shavers </span> 2616 </a> 2617 </li> 2618 <li> 2619 <a href="https://www.healthcare4all.co.uk/health-beauty/stairlifts" 2620 title="Stairlifts" 2621 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2622 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2623 > 2624 <span class="text-base text-gray-700"> 2625 Stairlifts </span> 2626 </a> 2627 </li> 2628 <li> 2629 <a href="https://www.healthcare4all.co.uk/health-beauty/petcare" 2630 title="Petcare" 2631 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2632 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2633 > 2634 <span class="text-base text-gray-700"> 2635 Petcare </span> 2636 </a> 2637 </li> 2638 <li> 2639 <a href="https://www.healthcare4all.co.uk/health-beauty/haircare" 2640 title="Haircare" 2641 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2642 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D225]').focus())" 2643 >
2644 <span class="text-base text-gray-700"> 2645 Haircare </span> 2646 </a> 2647 </li> 2648 </ul> 2649 </li> 2650 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2651 @mouseenter="hoverPanelActiveId = 'category-node-226'" 2652 @mouseleave="hoverPanelActiveId = 0" 2653 @keyup.escape="hoverPanelActiveId = 0" 2654 > 2655 <span class="flex items-center text-md"> 2656 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2657 href="https://www.healthcare4all.co.uk/eyes-ears-mouth" 2658 title="Eyes, Ears & Mouth" 2659 @focus="hoverPanelActiveId = 0" 2660 > 2661 Eyes, Ears & Mouth </a> 2662 <button 2663 type="button" 2664 data-sr-button-id="category-node-226" 2665 :aria-expanded="hoverPanelActiveId === 'category-node-226' ? 'true' : 'false'" 2666 @click="openMenuOnClick('category-node-226')" 2667 class="rounded p-1 text-gray-500" 2668 > 2669 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2670 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2671</svg> 2672 <span class="sr-only"> 2673 Show submenu for Eyes, Ears & Mouth category </span> 2674 </button> 2675 </span> 2676 <ul 2677 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2678 :class="{ 2679 'hidden' : hoverPanelActiveId !== 'category-node-226', 2680 'block' : hoverPanelActiveId === 'category-node-226' 2681 }" 2682 > 2683 <li> 2684 <a href="https://www.healthcare4all.co.uk/eyes-ears-mouth/eye-care" 2685 title="Eye Care" 2686 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2687 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D226]').focus())" 2688 > 2689 <span class="text-base text-gray-700"> 2690 Eye Care </span> 2691 </a> 2692 </li> 2693 <li> 2694 <a href="https://www.healthcare4all.co.uk/eyes-ears-mouth/ear-care" 2695 title="Ear Care" 2696 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2697 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D226]').focus())" 2698 >
2699 <span class="text-base text-gray-700"> 2700 Ear Care </span> 2701 </a> 2702 </li> 2703 <li> 2704 <a href="https://www.healthcare4all.co.uk/eyes-ears-mouth/dental-hygiene" 2705 title="Dental Hygiene" 2706 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2707 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D226]').focus())" 2708 > 2709 <span class="text-base text-gray-700"> 2710 Dental Hygiene </span> 2711 </a> 2712 </li> 2713 </ul> 2714 </li> 2715 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2716 @mouseenter="hoverPanelActiveId = 'category-node-227'" 2717 @mouseleave="hoverPanelActiveId = 0" 2718 @keyup.escape="hoverPanelActiveId = 0" 2719 > 2720 <span class="flex items-center text-md"> 2721 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2722 href="https://www.healthcare4all.co.uk/pain-relief" 2723 title="Pain Relief" 2724 @focus="hoverPanelActiveId = 0" 2725 > 2726 Pain Relief </a> 2727 <button 2728 type="button" 2729 data-sr-button-id="category-node-227" 2730 :aria-expanded="hoverPanelActiveId === 'category-node-227' ? 'true' : 'false'" 2731 @click="openMenuOnClick('category-node-227')" 2732 class="rounded p-1 text-gray-500" 2733 > 2734 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2735 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2736</svg> 2737 <span class="sr-only"> 2738 Show submenu for Pain Relief category </span> 2739 </button> 2740 </span> 2741 <ul 2742 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2743 :class="{ 2744 'hidden' : hoverPanelActiveId !== 'category-node-227', 2745 'block' : hoverPanelActiveId === 'category-node-227' 2746 }" 2747 > 2748 <li> 2749 <a href="https://www.healthcare4all.co.uk/pain-relief/pain-relief-tens" 2750 title="Pain Relief + TENS" 2751 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2752 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D227]').focus())" 2753 >
2754 <span class="text-base text-gray-700"> 2755 Pain Relief + TENS </span> 2756 </a> 2757 </li> 2758 </ul> 2759 </li> 2760 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2761 @mouseenter="hoverPanelActiveId = 'category-node-228'" 2762 @mouseleave="hoverPanelActiveId = 0" 2763 @keyup.escape="hoverPanelActiveId = 0" 2764 > 2765 <span class="flex items-center text-md"> 2766 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2767 href="https://www.healthcare4all.co.uk/mother-and-baby" 2768 title="Mother and Baby" 2769 @focus="hoverPanelActiveId = 0" 2770 > 2771 Mother and Baby </a> 2772 <button 2773 type="button" 2774 data-sr-button-id="category-node-228" 2775 :aria-expanded="hoverPanelActiveId === 'category-node-228' ? 'true' : 'false'" 2776 @click="openMenuOnClick('category-node-228')" 2777 class="rounded p-1 text-gray-500" 2778 > 2779 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="flex self-center" width="20" height="20" aria-hidden="true"> 2780 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 2781</svg> 2782 <span class="sr-only"> 2783 Show submenu for Mother and Baby category </span> 2784 </button> 2785 </span> 2786 <ul 2787 class="absolute top-full z-10 hidden px-6 py-4 mt-0.5 -ml-6 shadow-lg bg-container-lighter/95" 2788 :class="{ 2789 'hidden' : hoverPanelActiveId !== 'category-node-228', 2790 'block' : hoverPanelActiveId === 'category-node-228' 2791 }" 2792 > 2793 <li> 2794 <a href="https://www.healthcare4all.co.uk/mother-and-baby/baby-maternity" 2795 title="Baby & Maternity" 2796 class="block w-full px-3 py-1 my-1 whitespace-nowrap first:mt-0 hover:underline aria-[current=page]:underline" 2797 @keyup.escape="$nextTick(() => document.querySelector('[data-sr-button-id=category\u002Dnode\u002D228]').focus())" 2798 > 2799 <span class="text-base text-gray-700"> 2800 Baby & Maternity </span> 2801 </a> 2802 </li> 2803 </ul> 2804 </li> 2805 <li class="relative level-0 border-b-2 border-transparent hover:border-primary data-[active]:border-primary" 2806 @mouseenter="hoverPanelActiveId = 'magefan-blog'" 2807 @mouseleave="hoverPanelActiveId = 0" 2808 @keyup.escape="hoverPanelActiveId = 0" 2809 >
2810 <span class="flex items-center text-md"> 2811 <a class="w-full text-base text-gray-700 level-0 py-2 px-0.5" 2812 href="https://www.healthcare4all.co.uk/blog" 2813 title="Blog" 2814 @focus="hoverPanelActiveId = 0" 2815 > 2816 Blog </a> 2817 </span> 2818 </li> 2819 </ul> 2820 </nav> 2821 </div> 2822</div>
2823<script> 2824 'use strict'; 2825 2826 const initMenuDesktop_6ac3dca589135 = () => { 2827 return { 2828 hoverPanelActiveId: null, 2829 init() { 2830 this.setActiveMenu(this.$root); 2831 }, 2832 setActiveMenu(menuNode) { 2833 Array.from(menuNode.querySelectorAll('a')).filter(link => { 2834 return link.href === window.location.href.split('?')[0]; 2835 }).map(item => { 2836 item.setAttribute('aria-current', 'page'); 2837 item.closest('li.level-0').setAttribute('data-active', 'true'); 2838 }); 2839 }, 2840 openMenuOnClick(menuNode) { 2841 if (menuNode === this.hoverPanelActiveId) { 2842 this.hoverPanelActiveId = 0; 2843 } else { 2844 this.hoverPanelActiveId = menuNode 2845 } 2846 } 2847 } 2848 } 2849</script>
2849 2850 </div> 2851 </div> 2852 2853
2854<script> 2855 function initCartDrawer() { 2856 return { 2857 open: false, 2858 isLoading: false, 2859 cart: {}, 2860 maxItemsToDisplay: 10, 2861 itemsCount: 0, 2862 showSku: false, 2863 autocompleteNumber: 100, 2864 init() { 2865 if (document.prerendering) { 2866 document.addEventListener("prerenderingchange", () => { 2867 window.dispatchEvent( 2868 new CustomEvent('reload-customer-section-data') 2869 ); 2870 }, { once: true }); 2871 } 2872 }, 2873 showDetails() { 2874 return this.item.options && this.item.options.length || this.showSku; 2875 }, 2876 cartIsEmpty() { 2877 return this.itemsCount === 0 2878 }, 2879 getData() { 2880 const data = this.$event.detail.data; 2881 2882 if (data.cart) { 2883 this.cart = data.cart; 2884 this.itemsCount = data.cart.items && data.cart.items.length || 0; 2885 this.setCartItems(); 2886 } 2887 this.isLoading = false; 2888 }, 2889 cartItems: [], 2890 getItemCountTitle() { 2891 return hyva.strf('\u00250\u0020of\u0020\u00251\u0020products\u0020in\u0020cart\u0020displayed', this.maxItemsToDisplay, this.itemsCount) 2892 }, 2893 shouldShowItemCount() { 2894 return this.maxItemsToDisplay && this.maxItemsToDisplay < this.itemsCount; 2895 }, 2896 setCartItems() { 2897 this.cartItems = this.cart.items && this.cart.items.sort((a, b) => b.item_id - a.item_id) || []; 2898 2899 if (this.maxItemsToDisplay > 0) { 2900 this.cartItems = this.cartItems.slice(0, parseInt(this.maxItemsToDisplay, 10)); 2901 } 2902 }, 2903 updateItemQty(event) { 2904 const form = event.target; 2905 this.isLoading = true; 2906 hyvaAjaxFormMinicart({ form, redirect: false }, () => { 2907 this.isLoading = false; 2908 }); 2909 }, 2910 deleteItemFromCart() { 2911 const itemId = this.item.item_id; 2912 const formKey = hyva.getFormKey(); 2913 this.isLoading = true; 2914 2915 hyvaAjaxFormMinicart({ 2916 url: BASE_URL + 'checkout/sidebar/removeItem/', 2917 body: 'form_key=' + formKey + '&item_id=' + itemId, 2918 message: 'You\u0020removed\u0020the\u0020item.' 2919 }, () => { 2920 this.isLoading = false 2921 }); 2922 }, 2923 toggleCartDrawer(event) { 2924 this.open = event.detail?.isOpen ?? !this.open; 2925 }, 2926 openCartDrawer() { 2927 this.open = true; 2928 }, 2929 closeCartDrawer() { 2930 this.open = false; 2931 }, 2932 getSectionDataExtraActions() { 2933 if (!this.cart.extra_actions) { 2934 return ''; 2935 } 2936 2937 const contentNode = document.createElement('div'); 2938 contentNode.innerHTML = this.cart.extra_actions; 2939 2940 hyva.activateScripts(contentNode); 2941 2942 return contentNode.innerHTML; 2943 }, 2944 productIsVisibleInSite() { 2945 return this.item.product_has_url && this.item.is_visible_in_site_visibility 2946 }, 2947 productIsNotVisibleInSite() { 2948 return !this.productIsVisibleInSite() 2949 }, 2950 productIsNotGroupedAndVisibleInSite() { 2951 return this.item.product_type !== 'grouped' && this.item.is_visible_in_site_visibility 2952 }, 2953 productAriaLabel() { 2954 return hyva.strf(this.$el.dataset.ariaLabel, this.item.product_name) 2955 }, 2956 proceedToCheckout() { 2957 this.closeCartDrawer() 2958 2959 this.$dispatch( 2960 'toggle-authentication', 2961 { 2962 url: 'https://www.healthcare4all.co.uk/checkout/' 2963 } 2964 ) 2965 }, 2966 setItemMessage(itemId, message) { 2967 const items = this.cartItems;
2968 items.forEach((item) => { 2969 if (item.item_id === itemId) { 2970 item.message = message; 2971 } 2972 }); 2973 }, 2974 cartListeners: { 2975 ['@private-content-loaded.window'](event) { 2976 this.getData(event.detail.data); 2977 }, 2978 ['@toggle-cart.window'](event) { 2979 this.toggleCartDrawer(event); 2980 }, 2981 ['@minicart-error-message.window'](event) { 2982 if (!event.detail) return; 2983 const { itemId, message } = event.detail; 2984 this.setItemMessage(itemId, message); 2985 }, 2986 ["@pageshow.window"](event) { 2987 if (event.persisted) { 2988 this.open = false; 2989 window.dispatchEvent(new CustomEvent("reload-customer-section-data")); 2990 } 2991 } 2992 } 2993 } 2994 } 2995 2996 window.addEventListener('alpine:init', () => { 2997 Alpine.data('initCartDrawer', initCartDrawer); 2998 }, { once: true }) 2999 3000 async function hyvaAjaxFormMinicart( 3001 { 3002 form = null, 3003 url = '', 3004 body = '', 3005 redirect = 'default', 3006 message = '', 3007 } = {}, 3008 callback = () => {} 3009 ) { 3010 const formData = body ? body : (form ? new FormData(form) : ''); 3011 const postUrl = url ? url : (form ? form.action : ''); 3012 if (!formData || !postUrl) { 3013 console.warn('You must provide the form or formData and postUrl!'); 3014 return; 3015 } 3016 3017 const formUenc = hyva.getUenc(); 3018 const itemId = body ? new URLSearchParams(body).get('item_id') : formData.get('item_id'); 3019 let bodyUrl = new URLSearchParams(formData); 3020 bodyUrl.append('uenc', formUenc); 3021 3022 try { 3023 const response = await fetch(postUrl, { 3024 method: 'POST', 3025 body: bodyUrl.toString(), 3026 mode: 'cors', 3027 credentials: 'include', 3028 headers: { 3029 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 3030 'X-Requested-With': 'XMLHttpRequest' 3031 } 3032 }); 3033 3034 if (!response.ok) { 3035 return form.submit(); 3036 } 3037 3038 if (redirect === 'default' && response.redirected) { 3039 return window.location.href = response.url; 3040 } else if (redirect !== 'default' && redirect !== false) { 3041 return window.location.href = redirect; 3042 } 3043 3044 const responseBody = await response.json(); 3045 3046 if (!responseBody.success) { 3047 throw responseBody.error_message; 3048 } 3049 3050 window.dispatchEvent(new CustomEvent('reload-customer-section-data')); 3051 } catch (error) { 3052 window.dispatchEvent(new CustomEvent('minicart-error-message', { detail: { itemId, message: error } })); 3053 } finally { 3054 callback(); 3055 } 3056 } 3057</script>
3057 3058 3059<dialog 3060 id="cart-drawer" 3061 aria-labelledby="cart-drawer-title" 3062 class="w-[480px] md:w-[640px] h-full max-h-full me-0 open:flex flex-col transition ease-out duration-300 motion-reduce:duration-0 rounded-e-none" 3063 x-data="initCartDrawer" 3064 x-bind="cartListeners" 3065 x-show="open" 3066 x-htmldialog="closeCartDrawer" 3067 closeby="any" 3068 x-transition:enter="transition ease-in-out duration-500" 3069 x-transition:enter-start="translate-x-full" 3070 x-transition:enter-end="translate-x-0" 3071 x-transition:leave="transition ease-in-out duration-300" 3072 x-transition:leave-start="translate-x-0" 3073 x-transition:leave-end="translate-x-full" 3074> 3075 3076 <div class="flex gap-2 justify-between items-center"> 3077 <p id="cart-drawer-title" class="text-2xl"> 3078 <strong>My Cart</strong> 3079 <span 3080 class="items-total text-xs" 3081 x-show="shouldShowItemCount" 3082 x-text="getItemCountTitle" 3083 ></span> 3084 </p> 3085 <button 3086 type="button" 3087 class="btn bg-transparent border-transparent p-2" 3088 @click="closeCartDrawer" 3089 aria-label="Close minicart" 3090 > 3091 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg> 3092 </button> 3093 </div> 3094 3095 3096 <template x-if="cartIsEmpty"> 3097 <div class="grow grid place-items-center"> 3098 <div class="text-center"> 3099 <svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="inline-block text-fg/30 max-w-full h-auto" aria-hidden="true"><path d="m15 11-1 9M19 11l-4-7M2 11h20M3.5 11l1.6 7.4a2 2 0 0 0 2 1.6h9.8a2 2 0 0 0 2-1.6l1.7-7.4M4.5 15.5h15M5 11l4-7M9 11l1 9"/></svg> 3100 <p class="mt-10 text-xl"> 3101 <strong>Cart is empty</strong> 3102 </p> 3103 </div> 3104 </div> 3105 </template> 3106 3107 <template x-if="itemsCount"> 3108 <ul class="grow flex flex-col overflow-y-auto overscroll-y-contain mask-overflow mask-dir-y"> 3109 <template x-for="item in cartItems"> 3110 <li class="flex gap-4 md:gap-6 items-start py-4 px-1 border-b border-slate-200"> 3111 <template x-if="productIsVisibleInSite"> 3112 <a 3113 class="block shrink-0 max-w-[25%]" 3114 :href="item.product_url" 3115 data-aria-label="Product "%0"" 3116 :title="item.product_name" 3117 > 3118 <img 3119 :src="item.product_image.src" 3120 :width="item.product_image.width" 3121 :height="item.product_image.height" 3122 loading="lazy" 3123 :alt="item.product_name" 3124 > 3125 </a> 3126 </template> 3127 <template x-if="productIsNotVisibleInSite"> 3128 <div class="block shrink-0 max-w-[25%]"> 3129 <img 3130 :src="item.product_image.src" 3131 :width="item.product_image.width" 3132 :height="item.product_image.height" 3133 loading="lazy" 3134 :alt="item.product_name" 3135 /> 3136 </div> 3137 </template> 3138 <div class="grow space-y-4"> 3139 <div class="flex gap-2 justify-between items-center"> 3140 <p class="text-lg"> 3141 <span x-html="item.qty"></span> x <strong x-html="item.product_name"></strong> 3142 </p>
3143 <span class="price-box" x-html="item.product_price"></span> 3144 </div> 3145 <template x-if="showDetails"> 3146 <dl class="table text-sm"> 3147 <template x-if="showSku"> 3148 <div class="table-row"> 3149 <dt class="table-cell font-normal min-w-16 pe-2 pb-2"> 3150 Sku </dt> 3151 <dd class="table-cell font-bold pb-2" x-html="item.product_sku"></dd> 3152 </div> 3153 </template> 3154 <template x-for="option in item.options"> 3155 <div class="table-row"> 3156 <dt 3157 class="table-cell font-normal min-w-16 pe-2 pb-2" 3158 x-text="option.label" 3159 ></dt> 3160 <dd class="table-cell font-bold pb-2" x-html="option.value"></dd> 3161 </div> 3162 </template> 3163 </dl> 3164 </template> 3165 <div class="flex flex-wrap gap-2 justify-end items-center"> 3166 <div class="inline-flex flex-wrap items-center gap-1"> 3167 <a 3168 :href="item.configure_url" 3169 x-show="productIsNotGroupedAndVisibleInSite" 3170 class="btn p-2" 3171 data-aria-label="Edit product "%0"" 3172 :aria-label="productAriaLabel" 3173 > 3174 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497zM15 5l4 4"/></svg> 3175 </a> 3176 <button 3177 type="button" 3178 class="btn p-2" 3179 @click="deleteItemFromCart" 3180 data-aria-label="Remove product "%0" from cart" 3181 :aria-label="productAriaLabel" 3182 > 3183 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg> 3184 </button> 3185 </div> 3186 <template x-if="item.message"> 3187 <div class="message error" x-text="item.message"></div> 3188 </template> 3189 </div> 3190 </div> 3191 </li> 3192 </template> 3193 </ul> 3194 </template> 3195 3196 3197 <template x-if="itemsCount"> 3198 <div> 3199 3200 <dl class="flex gap-2 justify-between items-center text-sm font-bold"> 3201 <dt>Subtotal</dt> 3202 <dd x-text="hyva.formatPrice((cart.items || []).reduce((s,i) => s + parseFloat(i.product_price_value || 0) * (i.qty || 1), 0))"></dd> 3203 </dl> 3204 3205 <div class="flex flex-col gap-y-4 mt-8"> 3206 <a 3207 @click.prevent.stop="proceedToCheckout" 3208 href="https://www.healthcare4all.co.uk/checkout/" 3209 class="btn btn-primary" 3210 > 3211 Checkout </a> 3212 <a 3213 href="https://www.healthcare4all.co.uk/checkout/cart/" 3214 class="btn btn-secondary" 3215 > 3216 View and Edit Cart </a>
3217 <div x-html="getSectionDataExtraActions"></div> 3218 </div> 3219 </div> 3220 </template> 3221 3222 <template x-if="cartIsEmpty"> 3223 <div class="flex flex-col"> 3224 <button 3225 type="button" 3226 @click="closeCartDrawer" 3227 class="btn btn-primary" 3228 >Continue Shopping</button> 3229 </div> 3230 </template> 3231 3232 <div 3233 class="z-50 fixed inset-0 flex justify-center items-center bg-white/70 select-none" 3234 x-show="isLoading" 3235 x-cloak 3236 x-transition.opacity.duration.200ms 3237> 3238 <div class="flex items-center"> 3239 <svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" stroke-linecap="round" class="animate-spin" aria-hidden="true"> 3240 <circle style="opacity: .3;" cx="12" cy="12" r="10"/> 3241 <path fill="none" stroke-width="2" d="M12,2 a10,10 0 0,1 10,10"/> 3242</svg> 3243 <div class="ml-10 text-xl"> 3244 Loading... </div> 3245 </div> 3246</div> 3247</dialog> 3248
3248<script> 3249 function initAuthentication() { 3250 return { 3251 open: false, 3252 close() { 3253 this.open = false; 3254 }, 3255 forceAuthentication: false, 3256 checkoutUrl: 'https://www.healthcare4all.co.uk/checkout/index/', 3257 errors: 0, 3258 hasCaptchaToken: 0, 3259 displayErrorMessage: false, 3260 errorMessages: [], 3261 setErrorMessages(message) { 3262 this.errorMessages = [message]; 3263 this.displayErrorMessage = true; 3264 }, 3265 submitForm() { 3266 // Do not rename $form, the variable is expected to be declared in the recaptcha output 3267 const $form = document.querySelector('#login-form'); 3268 if (!this.hasCaptchaToken) { 3269 this.errors = 1; 3270 3271 3272 const executeGreCaptcha = () => { 3273 grecaptcha.ready(() => { 3274 grecaptcha.execute( 3275 '6Lc7_50sAAAAAG_oXG0fwI0gVEkpJtqxB2S2A2ce', 3276 {action: 'submit'} 3277 ).then((token) => { 3278 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 3279 3280 if (tokenElement && token && token.length > 0) { 3281 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 3282 this.errors = 0; 3283 this.hasCaptchaToken = 1; 3284 (this.submitForm || $form.submit).call(this); 3285 } else { 3286 this.errors = 1; 3287 const error = tokenElement 3288 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 3289 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 3290 if (this.setErrorMessages) { 3291 this.setErrorMessages([error]) 3292 this.displayErrorMessage = true; 3293 } else { 3294 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 3295 } 3296 } 3297 }).catch(exception => { 3298 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 3299 }); 3300 }) 3301 } 3302 3303 if (window.grecaptcha) { 3304 executeGreCaptcha(); 3305 } else { 3306 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6Lc7_50sAAAAAG_oXG0fwI0gVEkpJtqxB2S2A2ce"; 3307 const script = document.createElement('script'); 3308 script.setAttribute('type', 'text/javascript'); 3309 script.setAttribute('src', recaptchaUrl); 3310 document.head.appendChild(script); 3311 3312 script.addEventListener("load", executeGreCaptcha, false); 3313 } 3314 } 3315 3316 if (this.errors === 0) { 3317 this.dispatchLoginRequest($form); 3318 } 3319 }, 3320 onPrivateContentLoaded() { 3321 const data = this.$event.detail.data; 3322 const isLoggedIn = data.customer && data.customer.firstname; 3323 if (data.cart && !isLoggedIn) { 3324 this.forceAuthentication = !data.cart.isGuestCheckoutAllowed; 3325 } 3326 }, 3327 redirectIfAuthenticated() { 3328 const event = this.$event; 3329 this.open = this.forceAuthentication; 3330 3331 if (event.detail && event.detail.url) { 3332 this.checkoutUrl = event.detail.url; 3333 } 3334 if (!this.forceAuthentication) { 3335 window.location.href = this.checkoutUrl; 3336 } 3337 }, 3338 resetErrors() { 3339 this.errors = 0; 3340 }, 3341 dispatchLoginRequest(form) { 3342 this.isLoading = true; 3343 const username = this.$refs['customer-email'].value; 3344 const password = this.$refs['customer-password'].value; 3345 const formKey = hyva.getFormKey(); 3346 const bodyFields = { 3347 'username': username, 3348 'password': password, 3349 'formKey': formKey 3350 }; 3351 const fieldName = 'g\u002Drecaptcha\u002Dresponse'; 3352 const recaptchaField = fieldName && form[fieldName]; 3353 if (recaptchaField) { 3354 bodyFields[fieldName] = recaptchaField.value; 3355 } 3356 fetch('https://www.healthcare4all.co.uk/customer/ajax/login/', { 3357 method: 'POST', 3358 headers: { 3359 'Content-Type': 'application/json', 3360 'X-Requested-With': 'XMLHttpRequest' 3361 }, 3362 body: JSON.stringify(bodyFields) 3363 } 3364 ).then(response => { 3365 return response.json() 3366 } 3367 ).then(data => { 3368 this.isLoading = false;
3369 if (data.errors) { 3370 this.setErrorMessages(data.message); 3371 this.errors = 1; 3372 this.hasCaptchaToken = 0; 3373 } else { 3374 window.location.href = this.checkoutUrl; 3375 } 3376 }); 3377 }, 3378 eventListeners: { 3379 ['@private-content-loaded.window']() { 3380 this.onPrivateContentLoaded(); 3381 }, 3382 ['@toggle-authentication.window']() { 3383 this.redirectIfAuthenticated(); 3384 }, 3385 ['@pageshow.window'](event) { 3386 if (event.persisted) { 3387 this.close(); 3388 }; 3389 } 3390 } 3391 } 3392 } 3393 3394 window.addEventListener('alpine:init', () => Alpine.data('initAuthentication', initAuthentication), {once: true}) 3395</script>
3395 3396 3397<dialog 3398 id="authentication-popup" 3399 aria-labelledby="authentication-popup-title" 3400 class="open:flex flex-col transition ease-out duration-300 motion-reduce:duration-0 p-0" 3401 x-data="initAuthentication" 3402 x-bind="eventListeners" 3403 x-show="open" 3404 x-htmldialog="close" 3405 closeby="any" 3406 x-transition 3407> 3408 <div class="pt-8 px-8"> 3409 <div class="flex gap-2 justify-between items-center"> 3410 <p id="authentication-popup-title" class="text-xl"> 3411 <strong>Customer Login</strong> 3412 </p> 3413 <button 3414 type="button" 3415 class="btn bg-transparent border-transparent p-2" 3416 @click="close" 3417 aria-label="Close panel" 3418 > 3419 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg> 3420 </button> 3421 </div> 3422 3423 <div class="message error" x-show="errors" x-cloak> 3424 <template x-for="(message, index) in errorMessages" :key="index"> 3425 <div> 3426 <template x-if="message"> 3427 <span x-html="message"></span> 3428 </template> 3429 </div> 3430 </template> 3431 </div> 3432 </div> 3433 3434 <div class="block-customer-login p-8"> 3435 <p id="authenticate-customer-login" class="text-lg mb-2"> 3436 <strong>Checkout using your account</strong> 3437 </p> 3438 3439 <form 3440 id="login-form" 3441 class="form form-login" 3442 method="post" 3443 @submit.prevent="submitForm" 3444 > 3445 <div class="control"> 3446 <input type="hidden" 3447 value="" 3448 name="g-recaptcha-response" 3449 > 3450</div> 3451 <input name="context" type="hidden" value="checkout"> 3452 3453 <div class="flex flex-col gap-4"> 3454 <div class="field email required"> 3455 <label for="form-login-username"> 3456 <span>Email Address</span> 3457 </label> 3458 <div class="control"> 3459 <input 3460 id="form-login-username" 3461 name="username" 3462 type="email" 3463 class="form-input w-full" 3464 required 3465 autocomplete="off" 3466 x-ref="customer-email" 3467 @change="resetErrors" 3468 > 3469 </div> 3470 </div> 3471 <div class="field password required"> 3472 <label for="form-login-password"> 3473 <span>Password</span> 3474 </label> 3475 <div class="control"> 3476 <input 3477 id="form-login-password" 3478 name="password" 3479 type="password" 3480 class="form-input w-full" 3481 required 3482 autocomplete="off" 3483 x-ref="customer-password" 3484 @change="resetErrors" 3485 > 3486 </div> 3487 </div> 3488 </div> 3489 3490 <div class="actions-toolbar"> 3491 <button 3492 type="submit" 3493 class="btn btn-primary" 3494 > 3495 Sign In </button> 3496 <a 3497 href="https://www.healthcare4all.co.uk/customer/account/forgotpassword/" 3498 class="underline hover:no-underline" 3499 > 3500 Forgot Your Password? </a> 3501 </div> 3502 </form> 3503 <p class="prose my-4 text-sm"> 3504 <em>This form is protected by reCAPTCHA - the <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">Google Privacy Policy</a> and <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Terms of Service</a> apply.</em> 3505</p> 3506 </div> 3507 <div class="block-new-customer p-8 border-t border-gray-300">
3508 <p id="authenticate-new-customer" class="text-lg mb-2"> 3509 <strong>Checkout as a new customer</strong> 3510 </p> 3511 3512 <div class="block-content"> 3513 <p class="mb-1"> 3514 Creating an account has many benefits: </p> 3515 <ul class="list-disc pl-5"> 3516 <li> See order and shipping status</li> 3517 <li> Track order history</li> 3518 <li> Check out faster</li> 3519 </ul> 3520 <div class="actions-toolbar mt-6 mb-2"> 3521 <a href="https://www.healthcare4all.co.uk/customer/account/create/" 3522 class="inline-flex btn btn-primary"> 3523 Create an Account </a> 3524 </div> 3525 </div> 3526 </div> 3527</dialog> 3528</div> 3529 3530<!-- Glopal language selector: override mobile hide + clone into burger menu --> 3531<style> 3532 body #wi-country-selector-button, 3533 body #wi-country-selector-button *, 3534 body [id^="wi-"] *, 3535 body [class*="glopal"] *, 3536 body [class*="wi-cs"] * { 3537 box-shadow: none !important; 3538 -webkit-box-shadow: none !important; 3539 filter: none !important; 3540 border: none !important; 3541 outline: none !important; 3542 background-color: transparent !important; 3543 } 3544 .tp-break { display: none; } 3545 @media only screen and (max-width: 767px) { 3546 body #wi-country-selector-button.glopal-design-discreet-branding { 3547 display: block !important; 3548 } 3549 .tp-break { display: inline; } 3550 } 3551 body.mobile-menu-open #wi-country-selector-button { 3552 display: none !important; 3553 } 3554 /* Sticky header: teal bar + header + breadcrumbs all pin */ 3555 .header-top { 3556 position: sticky !important; 3557 top: 0 !important; 3558 z-index: 31 !important; 3559 } 3560 .page-header { 3561 position: sticky !important; 3562 top: 36px !important; /* height of teal bar (text-sm + p-2 ≈ 36px) */ 3563 z-index: 30 !important; 3564 background: #fff; 3565 box-shadow: 0 1px 3px rgba(0,0,0,0.08); 3566 } 3567 nav.breadcrumbs { 3568 position: sticky !important; 3569 z-index: 29 !important; 3570 /* top set by JS below */ 3571 } 3572 /* Search box: teal focus ring + proportionate width */ 3573 #search { 3574 max-width: none !important; 3575 width: 100% !important; 3576 } 3577 #search:focus { 3578 border-color: #089A8A !important; 3579 box-shadow: none !important; 3580 outline: none !important; 3581 ring: none !important; 3582 --tw-ring-shadow: none !important; 3583 } 3584 /* Align search input and button edges */ 3585 #search_mini_form .flex { 3586 align-items: stretch; 3587 } 3588 #search { 3589 border-right: none !important; 3590 } 3591 #search_mini_form .action.search { 3592 border-top-left-radius: 0 !important; 3593 border-bottom-left-radius: 0 !important; 3594 } 3595 /* Star ratings: horizontal layout + gold fill for filled stars */ 3596 .rating-summary { 3597 display: flex !important; 3598 flex-direction: row !important; 3599 align-items: center; 3600 gap: 1px; 3601 } 3602 .rating-summary svg { 3603 color: #d1d5db; 3604 } 3605 .rating-summary svg.fill-current { 3606 color: #f59e0b; 3607 fill: #f59e0b; 3608 } 3609 .rating-summary span svg { 3610 color: #f59e0b; 3611 } 3612 /* Price range slider: override blue bg-primary with teal */ 3613 .es-range-slider .bg-primary { 3614 background-color: #089A8A !important; 3615 } 3616 /* OK button and any btn-primary in filters */ 3617 .smile-es-range-slider .btn-primary, 3618 .filter-options .btn-primary { 3619 background-color: #089A8A !important; 3620 } 3621 #search_mini_form { 3622 width: 100%; 3623 float: none !important; 3624 } 3625 @media (min-width: 1024px) { 3626 #elasticsuite-search-container { 3627 max-width: 75%; 3628 margin-left: auto; 3629 } 3630 } 3631 /* Add top padding on CMS/info pages between breadcrumb and content */ 3632 .cms-page-view .column.main { 3633 padding-top: 1.5rem; 3634 } 3635 /* Product page: cap gallery image height */ 3636 .catalog-product-view #gallery .relative.mb-6 { 3637 max-height: 400px; 3638 overflow: hidden; 3639 } 3640 .catalog-product-view #gallery img { 3641 max-height: 400px !important; 3642 width: auto !important; 3643 margin: 0 auto; 3644 } 3645 /* Hide the Description section from the tabs (it's now in the right column) */ 3646 .catalog-product-view section#description { 3647 display: none; 3648 } 3649 /* Cart page: push Proceed to Checkout down to align with Update Shopping Cart */ 3650 .checkout-cart-index .btn-checkout { 3651 margin-top: 4.8rem !important; 3652 } 3653 /* Cart page: grid layout for cart items matching prod site columns (desktop only) */ 3654 @media (min-width: 1024px) { 3655 .cart-item-grid, 3656 .checkout-cart-index .cart-item-row { 3657 display: grid; 3658 grid-template-columns: 1fr 100px 80px 100px 40px; 3659 gap: 0.5rem; 3660 align-items: center; 3661 } 3662 } 3663 .checkout-cart-index .cart-item-row { 3664 padding: 0.75rem 0; 3665 border-bottom: 1px solid #e5e7eb; 3666 } 3667 .checkout-cart-index .cart-item-row:last-child { 3668 border-bottom: none; 3669 } 3670 .cart-col-item { 3671 display: flex; 3672 gap: 1rem; 3673 align-items: center; 3674 } 3675 .cart-col-item .product-item-photo img { 3676 max-width: 80px; 3677 height: auto; 3678 } 3679 .cart-col-price, 3680 .cart-col-qty, 3681 .cart-col-subtotal { 3682 text-align: center; 3683 } 3684 .cart-col-actions { 3685 display: flex; 3686 justify-content: flex-end; 3687 gap: 0.25rem; 3688 } 3689 /* Mobile: stack cart items vertically */ 3690 @media (max-width: 1023px) { 3691 .checkout-cart-index .cart-item-row { 3692 display: flex; 3693 flex-wrap: wrap; 3694 gap: 0.5rem; 3695 } 3696 .cart-col-item { 3697 width: 100%; 3698 } 3699 .cart-col-price, 3700 .cart-col-qty, 3701 .cart-col-subtotal { 3702 text-align: left; 3703 } 3704 } 3705 /* Cart page: place "You might also like" and "Promotions" side by side */ 3706 @media (min-width: 768px) { 3707 .cart-sliders-row { 3708 display: flex; 3709 gap: 1.5rem; 3710 margin-top: 2rem; 3711 } 3712 .cart-sliders-row > * { 3713 flex: 1 1 50%; 3714 min-width: 0; 3715 } 3716 .cart-sliders-row > *:first-child:not(:last-child) { 3717 border-right: 2px solid #089A8A; 3718 padding-right: 1.5rem; 3719 } 3720 /* Uniform tile heights: force column layout and fixed section heights */ 3721 .cart-sliders-row .product-item { 3722 flex-direction: column !important; 3723 } 3724 .cart-sliders-row .product-item .product-item-photo { 3725 width: 100% !important; 3726 height: 200px; 3727 display: flex; 3728 align-items: center; 3729 justify-content: center; 3730 } 3731 .cart-sliders-row .product-item .product-item-photo img { 3732 max-height: 200px; 3733 object-fit: contain; 3734 } 3735 .cart-sliders-row .product-info { 3736 width: 100% !important; 3737 padding-left: 0 !important; 3738 } 3739 .cart-sliders-row .product-item-link { 3740 height: 4.5em; 3741 } 3742 .cart-sliders-row .rating-summary { 3743 height: 1.5em; 3744 margin-bottom: 0.25em; 3745 } 3746 .cart-sliders-row .product-item .price-box { 3747 min-height: 6.5em; 3748 } 3749 .cart-sliders-row .product-item .cart-button { 3750 margin-top: auto; 3751 } 3752 } 3753 /* Clamp product names to 3 lines on product cards to prevent star ratings overlapping */ 3754 .product-item-link { 3755 display: -webkit-box !important; 3756 -webkit-line-clamp: 3; 3757 -webkit-box-orient: vertical; 3758 overflow: hidden; 3759 text-overflow: ellipsis; 3760 } 3761 /* Override blue btn-primary with teal across the whole site */ 3762 .btn-primary, 3763 button.btn-primary, 3764 a.btn-primary { 3765 background-color: #089A8A !important; 3766 border-color: #089A8A !important; 3767 } 3768 .btn-primary:hover, 3769 button.btn-primary:hover, 3770 a.btn-primary:hover { 3771 background-color: #067a6d !important; 3772 border-color: #067a6d !important; 3773 } 3774 /* Cookie notice: white text + vertically align both buttons */
3775 #bss-cookie-notice .btn-cookie { 3776 color: #fff !important; 3777 vertical-align: middle; 3778 margin-bottom: 0.25rem !important; 3779 } 3780 /* Override blue btn-secondary outline with teal */ 3781 .btn-secondary, 3782 button.btn-secondary, 3783 a.btn-secondary { 3784 border-color: #089A8A !important; 3785 color: #089A8A !important; 3786 } 3787 .btn-secondary:hover, 3788 button.btn-secondary:hover, 3789 a.btn-secondary:hover { 3790 border-color: #067a6d !important; 3791 color: #067a6d !important; 3792 } 3793 /* Consistent section heading underlines */ 3794 .slider-title-row, 3795 [x-snap-slider] > .flex.justify-between, 3796 .template-2-1 .block-title-wrap { 3797 border-bottom: 2px solid #9ca3af !important; 3798 padding-bottom: 0.5rem !important; 3799 } 3800 /* Blog widget: title bar — match product slider headings */ 3801 .template-2-1 .block-title-wrap { 3802 display: flex !important; 3803 align-items: center; 3804 justify-content: space-between; 3805 gap: 0.75rem; 3806 background: none !important; 3807 padding: 0 !important; 3808 margin-bottom: 1rem; 3809 border-bottom: none; 3810 padding-bottom: 0.5rem !important; 3811 } 3812 .template-2-1 .block-title-wrap .block-title { 3813 font-size: 1.5rem; 3814 font-weight: 700; 3815 color: #4b5563; 3816 background: none !important; 3817 padding: 0 !important; 3818 text-transform: uppercase; 3819 } 3820 .template-2-1 .block-title-wrap .view-all { 3821 display: flex; 3822 align-items: center; 3823 } 3824 .template-2-1 .block-title-wrap .view-all a { 3825 display: inline-flex; 3826 align-items: center; 3827 gap: 0.5rem; 3828 text-decoration: none; 3829 color: #374151; 3830 font-weight: 500; 3831 } 3832 .template-2-1 .block-title-wrap .view-all button { 3833 display: inline-flex; 3834 align-items: center; 3835 } 3836 /* Override Tailwind bg-primary used on buttons, links, etc. */ 3837 .bg-primary { 3838 background-color: #089A8A !important; 3839 } 3840 .border-primary { 3841 border-color: #089A8A !important; 3842 } 3843 .hover\:border-primary:hover, 3844 [data-active], 3845 li[data-active], 3846 .level-0[data-active], 3847 .level-0:hover { 3848 border-color: #089A8A !important; 3849 } 3850 .hover\:bg-primary:hover { 3851 background-color: #067a6d !important; 3852 } 3853 /* Product card: equal height with buttons pinned to bottom */ 3854 /* Slider track: stretch children to tallest card */ 3855 .product-slider [data-track] { 3856 align-items: stretch !important; 3857 } 3858 /* Slider slide wrappers: fill height */ 3859 .product-slider [data-track] > div { 3860 display: flex !important; 3861 flex-direction: column !important; 3862 } 3863 /* All product cards (grid + slider): flex column full height */ 3864 .product-item, 3865 form.product-item { 3866 display: flex !important; 3867 flex-direction: column !important; 3868 flex-grow: 1 !important; 3869 height: 100% !important; 3870 } 3871 .product-info { 3872 display: flex !important; 3873 flex-direction: column !important; 3874 flex-grow: 1 !important; 3875 } 3876 /* Product name: reserve 3 lines and absorb any extra card height */ 3877 .product-info > div:first-child { 3878 min-height: 5.25rem; /* 3 lines × 1.75rem line-height */ 3879 flex-grow: 1 !important; 3880 } 3881 /* Fixed height for star ratings row so prices align even when no stars */ 3882 .product-info > div:nth-child(2) { 3883 min-height: 1.75rem; 3884 } 3885 /* Glopal flag: vertically centred in teal header bar */ 3886 body #wi-country-selector-button { 3887 position: fixed !important; 3888 top: 6px !important; 3889 right: 80px !important; 3890 z-index: 50 !important; 3891 } 3892 @media only screen and (max-width: 1023px) { 3893 body #wi-country-selector-button { 3894 top: 6px !important; 3895 right: 50px !important; 3896 } 3897 } 3898 /* Cart drawer: <dialog> — vendor uses dialog but compiled CSS missing utilities */ 3899 #cart-drawer { 3900 position: fixed; 3901 top: 0; 3902 right: 0; 3903 bottom: auto; 3904 left: auto; 3905 margin: 0; 3906 padding: 1.25rem 1.5rem; 3907 border: none; 3908 width: 420px; 3909 max-width: 90vw; 3910 height: auto !important; 3911 max-height: 100vh; 3912 background: white; 3913 display: none; 3914 flex-direction: column; 3915 border-radius: 0; 3916 z-index: 100; 3917 box-shadow: -4px 0 20px rgba(0,0,0,0.15); 3918 } 3919 #cart-drawer[open] { display: flex; } 3920 #cart-drawer::backdrop { background-color: rgba(0,0,0,0.5); } 3921 /* Header: title + close */ 3922 #cart-drawer > .flex.justify-between { 3923 flex-shrink: 0; 3924 padding-bottom: 0.75rem; 3925 border-bottom: 1px solid #e5e7eb; 3926 } 3927 /* Close button: red circle */ 3928 #cart-drawer > .flex.justify-between button { 3929 background: #ef4444 !important; 3930 border-color: #ef4444 !important; 3931 color: white !important; 3932 border-radius: 50%; 3933 width: 2rem; 3934 height: 2rem; 3935 padding: 0.25rem !important; 3936 display: flex; 3937 align-items: center; 3938 justify-content: center; 3939 flex-shrink: 0; 3940 } 3941 #cart-drawer > .flex.justify-between button:hover { background: #dc2626 !important; } 3942 /* EVERYTHING inside drawer: no growing */ 3943 #cart-drawer > * { 3944 flex-grow: 0 !important; 3945 flex-shrink: 0 !important; 3946 } 3947 /* Items list: scroll if many items */ 3948 #cart-drawer > ul { 3949 overflow-y: auto; 3950 margin: 0; 3951 padding: 0; 3952 list-style: none; 3953 max-height: 60vh; 3954 flex-shrink: 1 !important; 3955 } 3956 /* Empty cart icon area can grow to fill */ 3957 #cart-drawer > .grow { flex-grow: 1 !important; } 3958 /* Item rows */ 3959 #cart-drawer li { 3960 display: flex; 3961 gap: 0.75rem; 3962 align-items: flex-start; 3963 padding: 0.75rem 0; 3964 border-bottom: 1px solid #e5e7eb; 3965 } 3966 /* Product image */ 3967 #cart-drawer li a[class*="shrink"], 3968 #cart-drawer li div[class*="shrink"] { 3969 max-width: 70px !important; 3970 flex-shrink: 0; 3971 } 3972 #cart-drawer li img { width: 70px; height: auto; border-radius: 4px; } 3973 /* Product info */ 3974 #cart-drawer li > .grow { flex-grow: 1; } 3975 #cart-drawer li .space-y-4 > * + * { margin-top: 0.5rem; } 3976 /* Edit/delete buttons: smaller, inline */ 3977 #cart-drawer li .btn.p-2 { 3978 padding: 0.375rem !important; 3979 background: #f3f4f6 !important; 3980 border-color: #e5e7eb !important; 3981 color: #374151 !important; 3982 border-radius: 6px; 3983 } 3984 #cart-drawer li .btn.p-2:hover { background: #e5e7eb !important; } 3985 /* Empty cart state */ 3986 #cart-drawer .grow.grid { flex-grow: 1; } 3987 /* Footer: subtotal + actions */ 3988 #cart-drawer > template + div:not(.grow):not(.fixed) { 3989 padding-top: 1rem; 3990 border-top: 1px solid #e5e7eb; 3991 } 3992 #cart-drawer dl { margin-bottom: 0.75rem; } 3993 /* Checkout + View Cart buttons */ 3994 #cart-drawer .btn-primary { 3995 display: block !important; 3996 width: 100%; 3997 text-align: center; 3998 padding: 0.75rem 1.5rem; 3999 } 4000 #cart-drawer .btn-secondary { 4001 display: block !important; 4002 width: 100%; 4003 text-align: center; 4004 padding: 0.75rem 1.5rem; 4005 border: 1px solid #089A8A; 4006 color: #089A8A; 4007 background: white; 4008 } 4009 #cart-drawer .btn-secondary:hover { background: #f0fdf9; } 4010 /* Continue Shopping button (empty cart) */ 4011 #cart-drawer > template + .flex.flex-col { margin-top: auto; flex-shrink: 0; } 4012 /* Loading overlay */ 4013 #cart-drawer > .fixed { position: absolute !important; } 4014 /* Responsive YouTube/video iframes in product descriptions, blog posts, CMS content */ 4015 .description-content iframe, 4016 .post-content iframe, 4017 .post-description iframe, 4018 .cms-content iframe, 4019 .product.attribute.description iframe, 4020 .magefan-blog-post iframe { 4021 max-width: 100% !important; 4022 width: 100% !important; 4023 aspect-ratio: 16 / 9; 4024 height: auto !important; 4025 } 4026</style>
4027<script> 4028</script>
vendor: 1 bytes, line 4028
4028
4029<script> 4030 (function() { 4031 function stripStyles(el) { 4032 if (!el) return; 4033 var props = ['box-shadow', '-webkit-box-shadow', 'filter', 'border', 'outline', 'background-color']; 4034 props.forEach(function(p) { el.style.setProperty(p, p === 'background-color' ? 'transparent' : 'none', 'important'); }); 4035 el.querySelectorAll('*').forEach(function(child) { 4036 props.forEach(function(p) { child.style.setProperty(p, p === 'background-color' ? 'transparent' : 'none', 'important'); }); 4037 }); 4038 } 4039 4040 function cloneGlopalToMobileMenu() { 4041 const widget = document.getElementById('wi-country-selector-button'); 4042 const slot = document.getElementById('mobile-menu-glopal-slot'); 4043 if (!widget || !slot || slot.hasChildNodes()) return; 4044 const clone = widget.cloneNode(true); 4045 clone.removeAttribute('id'); 4046 clone.style.cssText = 'position:static !important; display:block !important;'; 4047 slot.appendChild(clone); 4048 } 4049 4050 function onGlopalReady() { 4051 const widget = document.getElementById('wi-country-selector-button'); 4052 if (!widget) return; 4053 stripStyles(widget); 4054 cloneGlopalToMobileMenu(); 4055 // Keep stripping in case Glopal re-applies styles 4056 new MutationObserver(function() { stripStyles(widget); }) 4057 .observe(widget, { attributes: true, attributeFilter: ['style', 'class'], subtree: true, childList: true }); 4058 } 4059 4060 // Glopal widget loads async via JS — watch for it 4061 const observer = new MutationObserver(function() { 4062 if (document.getElementById('wi-country-selector-button')) { 4063 observer.disconnect(); 4064 onGlopalReady(); 4065 } 4066 }); 4067 observer.observe(document.body, { childList: true, subtree: true }); 4068 4069 // Fallback in case it's already loaded 4070 if (document.readyState === 'complete') { 4071 onGlopalReady(); 4072 } else { 4073 window.addEventListener('load', onGlopalReady); 4074 } 4075 })(); 4076</script>
4076 4077</header><div class="top-container"> 4078<nav class="breadcrumbs bg-surface shadow-sm" aria-label="Breadcrumb"> 4079 <div class="container"> 4080 <ol class="items list-reset py-4 rounded flex flex-wrap text-grey text-sm"> 4081 <li class="item flex home"> 4082 <a 4083 href="https://www.healthcare4all.co.uk/" 4084 aria-label="Go to Home Page" 4085 >Home</a> 4086 </li> 4087 <li class="item flex category222"> 4088 <span aria-hidden="true" class="separator text-fg-secondary px-2">/</span> 4089 <a 4090 href="https://www.healthcare4all.co.uk/featured-products" 4091 class="text-fg-secondary" 4092 aria-current="page" 4093 >Featured Products</a> 4094 </li> 4095 </ol> 4096 </div> 4097</nav> 4098 4099
4099<script type="application/ld+json"> 4100 { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type":"ListItem","position":1,"item":{"@id":"https:\/\/www.healthcare4all.co.uk\/","name":"Home"}},{"@type":"ListItem","position":2,"item":{"@id":"https:\/\/www.healthcare4all.co.uk\/featured-products","name":"Featured Products"}}] } 4101 </script>
4101 4102</div><main id="maincontent" class="page-main"><div id="contentarea" tabindex="-1"></div> 4103<div class="page messages">
4103<script> 4104 function initMessages() { 4105 "use strict"; 4106 return { 4107 messages: window.mageMessages || [], 4108 isEmpty() { 4109 return this.messages.reduce( 4110 function (isEmpty, message) { 4111 return isEmpty && message === undefined 4112 }, true 4113 ) 4114 }, 4115 hasMessages() { 4116 return !this.isEmpty(); 4117 }, 4118 hasMessage() { 4119 return !!this.message; 4120 }, 4121 removeMessage() { 4122 this.messages[this.index] = undefined; 4123 }, 4124 addMessages(messages, hideAfter) { 4125 messages.map((message) => { 4126 if (!message.text || !message.text.trim()) return; 4127 this.messages = this.messages.concat(message); 4128 if (hideAfter === undefined && message.type === 'success' && window.defaultSuccessMessageTimeout) { 4129 hideAfter = window.defaultSuccessMessageTimeout; 4130 } 4131 if (hideAfter) { 4132 this.setHideTimeOut(this.messages.length -1, hideAfter); 4133 } 4134 }); 4135 }, 4136 setHideTimeOut(messageIndex, hideAfter) { 4137 setTimeout((messageIndex) => { 4138 this.messages[messageIndex] = undefined; 4139 }, hideAfter, messageIndex); 4140 }, 4141 eventListeners: { 4142 ['@messages-loaded.window'](event) { 4143 this.addMessages(event.detail.messages, event.detail.hideAfter) 4144 }, 4145 ['@private-content-loaded.window'](event) { 4146 const data = event.detail.data; 4147 if ( 4148 data.messages && 4149 data.messages.messages && 4150 data.messages.messages.length 4151 ) { 4152 this.addMessages(data.messages.messages); 4153 } 4154 }, 4155 ['@clear-messages.window']() { 4156 this.messages = []; 4157 }, 4158 ['@pageshow.window'](event) { 4159 if (event.persisted) { 4160 this.messages = []; 4161 }; 4162 } 4163 }, 4164 getMessageUiId() { 4165 return 'message-' + this.message.type; 4166 } 4167 } 4168 } 4169 4170 window.addEventListener('alpine:init', () => Alpine.data('initMessages', initMessages), {once: true}) 4171</script>
4171 4172<section id="messages" 4173 x-data="initMessages" 4174 x-bind="eventListeners" 4175 role="alert" 4176> 4177 <template x-if="hasMessages"> 4178 <div class="w-full"> 4179 <div class="messages container mx-auto py-3"> 4180 <template x-for="(message, index) in messages" :key="index"> 4181 <div> 4182 <template x-if="hasMessage"> 4183 <div class="message" 4184 :class="message.type" 4185 :ui-id="getMessageUiId" 4186 > 4187 <span x-html="message.text"></span> 4188 <button 4189 type="button" 4190 class="text-gray-600 hover:text-black" 4191 aria-label="Close message" 4192 @click.prevent="removeMessage" 4193 > 4194 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="stroke-current" width="18" height="18" aria-hidden="true"> 4195 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 4196</svg> 4197 </button> 4198 </div> 4199 </template> 4200 </div> 4201 </template> 4202 </div> 4203 </div> 4204 </template> 4205</section> 4206</div> <div class="container flex flex-col md:flex-row flex-wrap"> 4207 <h1 class="page-title text-3xl font-bold mb-6 lg:text-4xl" 4208 data-ui-id="page-title-wrapper" 4209 > 4210 Featured Products </h1> 4211 </div> 4212<div class="columns"><aside class="sidebar sidebar-main"> 4213 <div 4214 role="region" 4215 aria-label="Product filters" 4216 class="block border border-container bg-container-darker p-4 md:border-0 md:bg-transparent md:py-0 md:px-0 my-6" 4217 x-data="initLayeredNavigation()" 4218 x-init="checkIsMobileResolution()" 4219 @resize.window.debounce="checkIsMobileResolution()" 4220 @visibilitychange.window.debounce="checkIsMobileResolution()" 4221 > 4222 <h2> 4223 <div 4224 class="block-title h-10 flex items-center justify-between" 4225 :class="{ 'cursor-pointer' : isMobile }" 4226 :role="isMobile ? 'button' : 'presentation'" 4227 :aria-expanded="isMobile ? blockOpen : undefined" 4228 :aria-controls="isMobile ? 'filters-content' : undefined" 4229 :tabindex="isMobile ? 0 : undefined" 4230 @click="blockOpen = !blockOpen" 4231 @keydown.enter="blockOpen = !blockOpen" 4232 @keydown.space="blockOpen = !blockOpen" 4233 > 4234 <span class="text-primary text-md md:text-3xl font-medium uppercase"> 4235 Shop By </span> 4236 <span class="py-1 px-1 bg-container-lighter rounded border border-container-darker hidden" 4237 :class="{ 'block' : isMobile, 'hidden': !isMobile }"> 4238 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" 4239 xmlns="http://www.w3.org/2000/svg" 4240 class="transition-transform transform duration-300 ease-in-out" 4241 :class="blockOpen ? 'rotate-180' : ''"> 4242 <path d="M19 9L12 16L5 9" stroke="#4A5568" stroke-width="2" stroke-linecap="round" 4243 stroke-linejoin="round"/> 4244 </svg> 4245 </span> 4246 </div> 4247 </h2> 4248 <div 4249 id="filters-content" 4250 class="block-content filter-content pt-3" 4251 x-show="isMobile && blockOpen || !isMobile" 4252 > 4253 <a 4254 href="#products-list" 4255 class="sr-only focus:not-sr-only bg-blue-600 text-white px-12 py-4 text-center block rounded-sm" 4256 > 4257 Skip to product list </a> 4258 <div 4259 role="group" 4260 aria-labelledby="filter-option-0-title" 4261 class="filter-option card my-4" 4262 x-data="{ open: true }" 4263 > 4264 <h3 4265 id="filter-option-0-title" 4266 class="filter-options-title" 4267 > 4268 <button 4269 class="flex justify-between items-center cursor-pointer hover:text-secondary-darker border-container w-full" 4270 :class="{ 'border-b pb-4': open }" 4271 @click="open = !open" 4272 aria-controls="filter-option-0-content" 4273 :aria-expanded="open" 4274 >
4275 <span class="title text-md md:text-lg font-semibold"> 4276 Price <span class="sr-only"> filter</span> 4277 </span> 4278 <span class="py-1 px-1 rounded border border-container"> 4279 <svg 4280 width="24" 4281 height="24" 4282 viewBox="0 0 24 24" 4283 fill="none" 4284 xmlns="http://www.w3.org/2000/svg" 4285 class="transition-transform transform duration-300 ease-in-out" 4286 :class="open ? 'rotate-180' : ''" 4287 aria-hidden="true" 4288 > 4289 <path 4290 d="M19 9L12 16L5 9" 4291 stroke="#4A5568" 4292 stroke-width="2" 4293 stroke-linecap="round" 4294 stroke-linejoin="round" 4295 /> 4296 </svg> 4297 </span> 4298 </button> 4299 </h3> 4300 <div 4301 id="filter-option-0-content" 4302 class="filter-options-content pt-3" 4303 x-show="open" 4304 > 4305 <style> 4306 .es-range-slider input[type=range] { 4307 pointer-events: none; 4308 } 4309 4310 .es-range-slider .thumb { 4311 margin-top: -0.5rem; 4312 width: 1.5rem; 4313 height: 1.5rem; 4314 } 4315 4316 .es-range-slider input[type=range] { 4317 margin-top: -0.5rem; 4318 height: 1.5rem; 4319 } 4320 4321 .es-range-slider input[type=range]::-webkit-slider-thumb { 4322 pointer-events: all; 4323 width: 1.5rem; 4324 height: 1.5rem; 4325 border-radius: 0px; 4326 border: 0 none; 4327 -webkit-appearance: none; 4328 } 4329 4330 .es-range-slider input[type=range]::-moz-range-thumb { 4331 pointer-events: all; 4332 width: 1.5rem; 4333 height: 1.5rem; 4334 border-radius: 0px; 4335 border: 0 none; 4336 -webkit-appearance: none; 4337 } 4338 4339 .es-range-slider input[type=range]::-ms-thumb { 4340 pointer-events: all; 4341 width: 1.5rem; 4342 height: 1.5rem; 4343 border-radius: 0px; 4344 border: 0 none; 4345 -webkit-appearance: none; 4346 } 4347</style> 4348<div class="smile-es-range-slider" data-role="range-price-slider-price"> 4349 <div x-data="rangeSlider({"minValue":16,"maxValue":46,"currentValue":{"from":16,"to":46},"fieldFormat":{"pattern":"\u00a3%s","precision":2,"requiredPrecision":2,"decimalSymbol":".","groupSymbol":",","groupLength":3,"integerRequired":false},"intervals":[{"value":16,"count":1},{"value":24,"count":1},{"value":44,"count":1},{"value":45,"count":1}],"adaptiveIntervals":[],"showAdaptiveSlider":false,"urlTemplate":"https:\/\/www.healthcare4all.co.uk\/featured-products?price=<%- from %>-<%- to %>","messageTemplates":{"displayOne":"1 product","displayCount":"<%- count %> products","displayEmpty":"No products in the selected range."},"rate":1}, true)" x-init="initialize()" class="relative max-w-xl w-full"> 4350 <div class="flex justify-between items-center mb-8"> 4351 <div>
4352 <span class="sr-only">Minimum value</span> 4353 <span x-model="minprice" x-text="fromLabel" class="px-3 py-2 border border-gray-200 rounded w-24 text-center"></span> 4354 </div> 4355 <div> 4356 <span class="sr-only">Maximum value</span> 4357 <span x-model="maxprice" x-text="toLabel" class="px-3 py-2 border border-gray-200 rounded w-24 text-center"></span> 4358 </div> 4359 </div> 4360 4361 4362 <div class="es-range-slider relative rounded-md bg-gray-200" 4363 role="group" 4364 aria-label="Range slider" 4365 aria-describedby="range-handler" 4366 > 4367 <input 4368 type="range" 4369 step="1" x-bind:min="min" 4370 x-bind:max="max" 4371 x-on:input="mintrigger" 4372 @focus="() => updateFocusState('min', true)" 4373 @blur="() => updateFocusState('min', false)" 4374 x-bind:style="'z-index: ' + minZindex" 4375 x-model="minprice" 4376 class="absolute pointer-events-none appearance-none h-2 w-full opacity-0 cursor-pointer" 4377 aria-label="Minimum price value, use left and right arrows to adjust." 4378 /> 4379 <input 4380 type="range" 4381 step="1" 4382 x-bind:min="min" 4383 x-bind:max="max" 4384 x-on:input="maxtrigger" 4385 @focus="() => updateFocusState('max', true)" 4386 @blur="() => updateFocusState('max', false)" 4387 x-bind:style="'z-index: ' + maxZindex" 4388 x-model="maxprice" 4389 class="absolute pointer-events-none appearance-none h-2 w-full opacity-0 cursor-pointer" 4390 aria-label="Maximum price value, use left and right arrows to adjust." 4391 /> 4392 4393 <div class="relative z-10 h-2" style="height: 0.5rem; margin-right: 1.5rem;"> 4394 <div class="absolute z-10 left-0 right-0 bottom-0 top-0"></div> 4395 <div class="absolute z-20 top-0 bottom-0 rounded-md bg-primary" x-bind:style="'right:'+ (100 - 1 - maxthumb)+'%; left:'+ minthumb+'%'"></div> 4396 <div :class="{ 'ring': minfocused }" class="absolute z-30 w-6 h-6 top-0 left-0 bg-primary rounded-full -mt-2 thumb" x-bind:style="'left: '+minthumb+'%'"></div> 4397 <div :class="{ 'ring': maxfocused }" class="absolute z-30 w-6 h-6 top-0 right-0 bg-primary rounded-full -mt-2 thumb" x-bind:style="'left: '+maxthumb+'%'"></div> 4398 </div> 4399 </div> 4400 4401 <div class="mt-8 mb-8 h-6 flex justify-between items-center"> 4402 <div x-html="message"></div> 4403 <div class=""> 4404 <a 4405 class="w-auto mr-auto btn btn-primary justify-center text-sm px-4 md:px-2 lg:px-4" 4406 x-model="url" 4407 :href="url" 4408 :aria-label=" 4409 hyva.str('Apply\u0020pricing\u0020filtering,\u0020minimum\u0020price\u0020\u00251,\u0020maximum\u0020price\u0020\u00252', minprice, maxprice) + ', ' + 4410 hyva.str('\u00251\u0020products\u0020available', count) 4411 " 4412 > 4413 <span>OK</span> 4414 </a> 4415 </div> 4416 </div> 4417 </div> 4418</div> 4419 4420 4421 </div> 4422 </div> 4423 <div 4424 role="group" 4425 aria-labelledby="filter-option-1-title" 4426 class="filter-option card my-4" 4427 x-data="{ open: true }" 4428 > 4429 <h3 4430 id="filter-option-1-title" 4431 class="filter-options-title" 4432 > 4433 <button 4434 class="flex justify-between items-center cursor-pointer hover:text-secondary-darker border-container w-full" 4435 :class="{ 'border-b pb-4': open }" 4436 @click="open = !open" 4437 aria-controls="filter-option-1-content" 4438 :aria-expanded="open" 4439 >
4440 <span class="title text-md md:text-lg font-semibold"> 4441 Manufacturer <span class="sr-only"> filter</span> 4442 </span> 4443 <span class="py-1 px-1 rounded border border-container"> 4444 <svg 4445 width="24" 4446 height="24" 4447 viewBox="0 0 24 24" 4448 fill="none" 4449 xmlns="http://www.w3.org/2000/svg" 4450 class="transition-transform transform duration-300 ease-in-out" 4451 :class="open ? 'rotate-180' : ''" 4452 aria-hidden="true" 4453 > 4454 <path 4455 d="M19 9L12 16L5 9" 4456 stroke="#4A5568" 4457 stroke-width="2" 4458 stroke-linecap="round" 4459 stroke-linejoin="round" 4460 /> 4461 </svg> 4462 </span> 4463 </button> 4464 </h3> 4465 <div 4466 id="filter-option-1-content" 4467 class="filter-options-content pt-3" 4468 x-show="open" 4469 > 4470 <div 4471 class="manufacturerFilter" 4472 x-data="initSmileAttribute({"component":"Smile_ElasticsuiteCatalog\/js\/attribute-filter","maxSize":10,"displayProductCount":true,"hasMoreItems":false,"displayRelNofollow":"","ajaxLoadUrl":"https:\/\/www.healthcare4all.co.uk\/catalog\/navigation_filter\/ajax\/id\/222\/?cat=222&filterName=manufacturer","items":[{"label":"Beurer","count":2,"url":"https:\/\/www.healthcare4all.co.uk\/featured-products?manufacturer=Beurer","is_selected":false},{"label":"Heal Force","count":1,"url":"https:\/\/www.healthcare4all.co.uk\/featured-products?manufacturer=Heal+Force","is_selected":false},{"label":"Jumper Medical","count":1,"url":"https:\/\/www.healthcare4all.co.uk\/featured-products?manufacturer=Jumper+Medical","is_selected":false}]})" 4473 x-init="initialize();" 4474 > 4475 <div class="field search" x-show="displaySearch"> 4476 <div class="control"> 4477 <input class="filter-search w-full mb-2" 4478 type="text" 4479 aria-label="Search Manufacturer filter" 4480 autocomplete="off" 4481 :placeholder="searchPlaceholder" 4482 @keyup="onSearchChange" 4483 @focusout="onSearchFocusOut" /> 4484 </div> 4485 </div> 4486 <ol class="items" 4487 aria-label="Manufacturer filter options" 4488 tabindex="-1" 4489 x-ref="closestItems_6ac3ddb3c3efd" 4490 > 4491 <template x-for="attribute in displayedItems" hidden> 4492 <li class="item my-1"> 4493 <a 4494 class="flex items-center" 4495 :href="attribute.url" 4496 x-show="attribute.count >= 1" 4497 :rel="options.displayRelNofollow" 4498 >
4499 <span 4500 class="rounded-sm border border-gray-400" 4501 :class="attribute.is_selected && 'bg-blue-600 border-blue-600'" 4502 > 4503 <svg 4504 fill="none" 4505 class="stroke-2 stroke-white" 4506 :class="{ 4507 'opacity-100': attribute.is_selected, 4508 'opacity-0': !attribute.is_selected, 4509 }" 4510 width="16" 4511 height="16" 4512 viewBox="0 0 24 24" 4513 xmlns="http://www.w3.org/2000/svg" 4514 aria-hidden="true" 4515 > 4516 <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path> 4517 </svg> 4518 </span> 4519 <div class="ml-2"> 4520 <span x-html="attribute.label"></span> 4521 <span class="count" x-show="options.displayProductCount"> 4522 (<span x-text="attribute.count"></span><span class="sr-only">products available</span>) 4523 </span> 4524 <span class="sr-only" x-show="attribute.is_selected"> 4525 filter selected </span> 4526 </div> 4527 </a> 4528 4529 <div x-show="attribute.count < 1"> 4530 <span x-html="attribute.label"></span> 4531 <span class="count" x-text="attribute.count"></span> 4532 </div> 4533 </li> 4534 </template> 4535 </ol> 4536 4537 <div class="no-results-message" x-model="result" x-show="getFulltextSearch() && !hasSearchResult()" class="empty"> 4538 <p x-html="getSearchResultMessage()"></p> 4539 </div> 4540 4541 <div class="actions" x-show="enableExpansion()"> 4542 <div class="secondary text-right"> 4543 <button class="action show-more underline text-secondary cursor-pointer" @click="onShowMore(); $refs.closestItems_6ac3ddb3c3efd.focus()" x-show="displayShowMore()"><span x-text="showMoreLabel + '+'"></span></button> 4544 <button class="action show-less underline text-secondary cursor-pointer" @click="onShowLess(); $refs.closestItems_6ac3ddb3c3efd.focus()" x-show="displayShowLess()"><span x-text="showLessLabel + '-'"></span></button> 4545 </div> 4546 </div> 4547 </div> 4548 4549 </div> 4550 </div> 4551 </div> 4552 </div> 4553
4553<script> 4554 function initLayeredNavigation() { 4555 return { 4556 isMobile: false, 4557 blockOpen: false, 4558 checkIsMobileResolution: function () { 4559 this.isMobile = window.outerWidth < 768 4560 } 4561 } 4562 } 4563 </script>
4563 4564 </aside><div class="column main"> 4565
4565<script> 4566 /* e.g. hyva theme */ 4567 document.addEventListener('DOMContentLoaded', function(){ 4568 var items = document.getElementsByClassName('mfblogunveil'); 4569 var el, url; 4570 if (items.length) { 4571 for (var i=0; i<items.length;i++) { 4572 el = items[i]; 4573 url = el.getAttribute('data-original'); 4574 if (!url) { 4575 continue; 4576 }; 4577 if ('IMG' == el.tagName) { 4578 el.src = url; 4579 } else { 4580 el.style.backgroundImage = "url('" + url + "')"; 4581 } 4582 } 4583 } 4584 }); 4585 </script>
4585 4586 <section class="py-8" id="product-list" aria-label="Product list" tabindex="-1"> 4587
4587<script> 4588 function initToolbar_6ac3ddb3cb106() { 4589 return { 4590 options: {"productListToolbarForm":{"mode":"product_list_mode","direction":"product_list_dir","order":"product_list_order","limit":"product_list_limit","modeDefault":"grid","directionDefault":"asc","orderDefault":"name","limitDefault":36,"url":"https:\/\/www.healthcare4all.co.uk\/featured-products","formKey":"0TWtmpCcpZOzi078","post":false,"page":"p"}}.productListToolbarForm || {}, 4591 getUrlParams: function () { 4592 let decode = window.decodeURIComponent, 4593 urlPaths = this.options.url.split('?'), 4594 urlParams = urlPaths[1] ? urlPaths[1].split('&') : [], 4595 params = {}, 4596 parameters, i; 4597 4598 for (i = 0; i < urlParams.length; i++) { 4599 parameters = urlParams[i].split('='); 4600 params[decode(parameters[0])] = parameters[1] !== undefined ? 4601 decode(parameters[1].replace(/\+/g, '%20')) : 4602 ''; 4603 } 4604 4605 return params; 4606 }, 4607 getCurrentLimit: function () { 4608 return this.getUrlParams()[this.options.limit] || this.options.limitDefault; 4609 }, 4610 getCurrentPage: function () { 4611 return this.getUrlParams()[this.options.page] || 1; 4612 }, 4613 changeUrl(paramName, paramValue, defaultValue) { 4614 let urlPaths = this.options.url.split('?'), 4615 baseUrl = urlPaths[0], 4616 paramData = this.getUrlParams(), 4617 currentPage = this.getCurrentPage(), 4618 newPage; 4619 4620 /** 4621 * calculates the page on which the first item of the current page will 4622 * be with the new limit and sets that number as the new page 4623 */ 4624 if (currentPage > 1 && paramName === this.options.limit) { 4625 newPage = Math.floor(this.getCurrentLimit() * (currentPage - 1) / paramValue) + 1; 4626 4627 if (newPage > 1) { 4628 paramData[this.options.page] = newPage; 4629 } else { 4630 delete paramData[this.options.page]; 4631 } 4632 } 4633 4634 paramData[paramName] = paramValue; 4635 4636 if (this.options.post) { 4637 hyva.postForm({action: baseUrl, data: paramData, skipUenc: true}); 4638 } else { 4639 if (paramValue === defaultValue.toString()) { 4640 delete paramData[paramName]; 4641 } 4642 paramData = Object.keys(paramData).length === 0 4643 ? '' 4644 : '?' + (new URLSearchParams(paramData)); 4645 location.href = baseUrl + paramData 4646 } 4647 } 4648 } 4649 } 4650</script>
4650 4651 <div x-data="initToolbar_6ac3ddb3cb106()" 4652 class="toolbar toolbar-products grid grid-cols-4 sm:grid-cols-8 md:grid-cols-4 4653 lg:grid-cols-8 grid-flow-row gap-2 items-center"> 4654 4655 <nav 4656 class="modes invisible md:visible flex justify-center gap-1 mr-2 items-center px-2 py-2 rounded-md border border-gray-300 bg-white text-sm leading-5 4657 w-20 order-1 col-span-1 sm:col-span-2 md:col-span-1 lg:col-span-2" 4658 aria-label="Products view mode" 4659 > 4660 <style> 4661 .modes-mode.mode-grid { 4662 background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" /></svg>'); 4663 } 4664 4665 .modes-mode.mode-list { 4666 background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /></svg>'); 4667 } 4668 </style> 4669 <button 4670 type="button" 4671 class="modes-mode w-6 h-6 mode-grid active" 4672 title="Grid" 4673 disabled 4674 data-role="mode-switcher" 4675 data-value="grid" 4676 aria-label="Products view mode - Grid" 4677 ></button> 4678 <button 4679 type="button" 4680 class="modes-mode w-6 h-6 mode-list opacity-50 hover:opacity-100" 4681 title="List" 4682 @click.prevent="changeUrl( 4683 'product_list_mode', 4684 'list', 4685 options.modeDefault 4686 )" 4687 data-role="mode-switcher" 4688 data-value="list" 4689 aria-label="Products view mode - List" 4690 ></button> 4691 </nav> 4692 <div class="toolbar-sorter sorter flex items-center order-1 col-span-3 sm:col-span-6 4693 md:col-span-3 lg:col-span-6 justify-end"> 4694 <label class="inline-block mr-3"> 4695 <select data-role="sorter" 4696 name="sorter" 4697 class="form-select sorter-options" 4698 aria-label="Sort By" 4699 @change="changeUrl( 4700 'product_list_order', 4701 $event.currentTarget.options[$event.currentTarget.selectedIndex].value, 4702 options.orderDefault 4703 )"> 4704 <option value="position" 4705 > 4706 Position </option> 4707 <option value="name" 4708 selected="selected" 4709 > 4710 Product Name </option> 4711 <option value="price" 4712 > 4713 Price </option> 4714 </select> 4715 </label> 4716 <button 4717 type="button" 4718 title="Set Descending Direction" 4719 class="action sorter-action sort-asc" 4720 @click.prevent="changeUrl('product_list_dir', 'desc', options.directionDefault)" 4721 > 4722 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 4723 <path stroke-linecap="round" stroke-linejoin="round" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"/> 4724</svg> 4725 </button> 4726 </div> 4727 </div> 4728 <div class="products wrapper mode-grid products-grid"> 4729 <ul 4730 role="list" 4731 class="mx-auto pt-4 pb-12 grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3" 4732 > 4733 <li class="flex flex-col"> 4734 4735<form method="post" 4736 action="https://www.healthcare4all.co.uk/checkout/cart/add/uenc/%25uenc%25/product/1410/" 4737 class="item product product-item product_addtocart_form card card-interactive grow flex flex-col w-full " 4738 data-sku="BEU-FT78" 4739 >
4740 <input name="form_key" type="hidden" value="0TWtmpCcpZOzi078" /> <input type="hidden" name="product" value="1410"/> 4741 <a href="https://www.healthcare4all.co.uk/beurer-ft78-ear-thermometer-with-temperature-alarm-uses-protective-cap" 4742 title="Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap" 4743 class="product photo product-item-photo block mx-auto mb-3 " 4744 tabindex="-1" 4745 > 4746 <img 4747 src="https://www.healthcare4all.co.uk/media/catalog/product/cache/cfaac077d0b00d7a2b6146a7db3be980/f/t/ft_78_product_image__.jpg" 4748 width="360" 4749 height="360" 4750 alt="Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap" 4751 class="product-image-photo" 4752 x-data="initProductItemImage" 4753 @update-gallery-1410.window="updateImage" 4754 loading="eager" 4755 fetchpriority="high" 4756 > 4757 </a> 4758 <div class="product-info flex flex-col grow "> 4759 <div class="mt-2 mb-1 items-center justify-center font-semibold text-lg text-center "> 4760 <a 4761 class="product-item-link line-clamp-3" 4762 href="https://www.healthcare4all.co.uk/beurer-ft78-ear-thermometer-with-temperature-alarm-uses-protective-cap" 4763 title="Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap" 4764 > 4765 Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap </a> 4766 </div> 4767 4768 <div class="py-1 mx-auto "> 4769 <div 4770 role="img" 4771 class="rating-summary" 4772 aria-label="Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap rating. 0 out of 5 stars" 4773 > 4774 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4775 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4776 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4777 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4778 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewB
4778ox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4779 </div> 4780 </div> 4781 4782 4783 4784 4785 <div class="pt-1 text-gray-900" 4786 x-data="initPriceBox()" 4787 x-defer="intersect" 4788 @update-prices-1410.window="updatePrice($event.detail);" 4789 > 4790 <div class="price-box price-final_price" data-role="priceBox" data-product-id="1410" data-price-box="product-id-1410"> 4791 <span 4792 x-data x-id="['price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1410']" class="price-container price-final_price tax weee" 4793 > 4794 <span :id="$id('price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1410')" data-label="Incl. Tax" data-price-amount="55.188001" 4795 data-price-type="finalPrice" 4796 class="price-wrapper price-including-tax" 4797 ><span class="price">£55.19</span></span> 4798 4799 4800 <span id="price-excluding-tax-product-price-1410" 4801 data-label="Excl. Tax" 4802 data-price-amount="45.99" 4803 data-price-type="basePrice" 4804 class="price-wrapper price-excluding-tax"> 4805 <span class="price">£45.99</span></span> 4806 </span> 4807 4808</div> </div> 4809 4810 <div class="pt-3 flex flex-wrap items-center gap-y-4 gap-x-2 4811 "> 4812 <button 4813 class="cart-button w-auto btn btn-primary justify-center text-sm mx-auto mr-auto" 4814 title="Add to Cart Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap" 4815 aria-label="Add to Cart Beurer FT78 Ear Thermometer with Temperature Alarm - Uses Protective Cap" 4816 data-addto="cart" 4817 > 4818 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 4819 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/> 4820</svg> 4821 <span class="inline md:hidden lg:inline"> 4822 Add to Cart </span> 4823 </button> 4824 4825 </div> 4826 </div> 4827</form> 4828 </li> 4829 <li class="flex flex-col"> 4830 4831<form method="post" 4832 action="https://www.healthcare4all.co.uk/checkout/cart/add/uenc/%25uenc%25/product/1119/" 4833 class="item product product-item product_addtocart_form card card-interactive grow flex flex-col w-full " 4834 data-sku="BEU-TL30" 4835 > 4836 <input name="form_key" type="hidden" value="0TWtmpCcpZOzi078" /> <input type="hidden" name="product" value="1119"/> 4837 <a href="https://www.healthcare4all.co.uk/beurer-tl30-ultra-portable-daylight-sad-sunlight-lamp" 4838 title="Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp" 4839 class="product photo product-item-photo block mx-auto mb-3 " 4840 tabindex="-1" 4841 > 4842 <img 4843 src="https://www.healthcare4all.co.uk/media/catalog/product/cache/cfaac077d0b00d7a2b6146a7db3be980/b/e/beurer_tl30_lamp_landscape.jpg" 4844 width="360" 4845 height="360" 4846 alt="Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp" 4847 class="product-image-photo" 4848 x-data="initProductItemImage" 4849 @update-gallery-1119.window="updateImage" 4850 loading="eager" 4851 fetchpriority="high" 4852 > 4853 </a> 4854 <div class="product-info flex flex-col grow "> 4855 <div class="mt-2 mb-1 items-center justify-center font-semibold text-lg text-center "> 4856 <a 4857 class="product-item-link line-clamp-3" 4858 href="https://www.healthcare4all.co.uk/beurer-tl30-ultra-portable-daylight-sad-sunlight-lamp" 4859 title="Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp" 4860 > 4861 Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp </a> 4862 </div> 4863 4864 <div class="py-1 mx-auto "> 4865 <div 4866 role="img" 4867 class="rating-summary" 4868 aria-label="Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp rating. 5 out of 5 stars" 4869 > 4870 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewB
4870ox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4871 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4872 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4873 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4874 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4875 </div> 4876 </div> 4877 4878 4879 4880 4881 <div class="pt-1 text-gray-900" 4882 x-data="initPriceBox()" 4883 x-defer="intersect" 4884 @update-prices-1119.window="updatePrice($event.detail);" 4885 > 4886 <div class="price-box price-final_price" data-role="priceBox" data-product-id="1119" data-price-box="product-id-1119"> 4887 <span 4888 x-data x-id="['price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1119']" class="price-container price-final_price tax weee" 4889 > 4890 <span :id="$id('price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1119')" data-label="Incl. Tax" data-price-amount="52.992001" 4891 data-price-type="finalPrice" 4892 class="price-wrapper price-including-tax" 4893 ><span class="price">£52.99</span></span> 4894 4895 4896 <span id="price-excluding-tax-product-price-1119" 4897 data-label="Excl. Tax" 4898 data-price-amount="44.16" 4899 data-price-type="basePrice" 4900 class="price-wrapper price-excluding-tax">
4901 <span class="price">£44.16</span></span> 4902 </span> 4903 4904</div> </div> 4905 4906 <div class="pt-3 flex flex-wrap items-center gap-y-4 gap-x-2 4907 "> 4908 <button 4909 class="cart-button w-auto btn btn-primary justify-center text-sm mx-auto mr-auto" 4910 title="Add to Cart Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp" 4911 aria-label="Add to Cart Beurer TL30 Ultra Portable Daylight SAD Sunlight Lamp" 4912 data-addto="cart" 4913 > 4914 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 4915 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/> 4916</svg> 4917 <span class="inline md:hidden lg:inline"> 4918 Add to Cart </span> 4919 </button> 4920 4921 </div> 4922 </div> 4923</form> 4924 </li> 4925 <li class="flex flex-col"> 4926 4927<form method="post" 4928 action="https://www.healthcare4all.co.uk/checkout/cart/add/uenc/%25uenc%25/product/1448/" 4929 class="item product product-item product_addtocart_form card card-interactive grow flex flex-col w-full " 4930 data-sku="HF-100A" 4931 > 4932 <input name="form_key" type="hidden" value="X51fLJXsn1FK619w" /> <input type="hidden" name="product" value="1448"/> 4933 <a href="https://www.healthcare4all.co.uk/heal-force-prince-100a-led-fingertip-pulse-oximeter-with-auto-power-on" 4934 title="Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On" 4935 class="product photo product-item-photo block mx-auto mb-3 " 4936 tabindex="-1" 4937 > 4938 <img 4939 src="https://www.healthcare4all.co.uk/media/catalog/product/cache/cfaac077d0b00d7a2b6146a7db3be980/h/e/heal_force_100a_updated.png" 4940 width="360" 4941 height="360" 4942 alt="Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On" 4943 class="product-image-photo" 4944 x-data="initProductItemImage" 4945 @update-gallery-1448.window="updateImage" 4946 loading="eager" 4947 fetchpriority="high" 4948 > 4949 </a> 4950 <div class="product-info flex flex-col grow "> 4951 <div class="mt-2 mb-1 items-center justify-center font-semibold text-lg text-center "> 4952 <a 4953 class="product-item-link line-clamp-3" 4954 href="https://www.healthcare4all.co.uk/heal-force-prince-100a-led-fingertip-pulse-oximeter-with-auto-power-on" 4955 title="Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On" 4956 > 4957 Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On </a> 4958 </div> 4959 4960 <div class="py-1 mx-auto "> 4961 <div 4962 role="img" 4963 class="rating-summary" 4964 aria-label="Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On rating. 0 out of 5 stars" 4965 > 4966 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4967 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewB
4967ox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4968 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4969 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4970 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 4971 </div> 4972 </div> 4973 4974 4975 4976 4977 <div class="pt-1 text-gray-900" 4978 x-data="initPriceBox()" 4979 x-defer="intersect" 4980 @update-prices-1448.window="updatePrice($event.detail);" 4981 > 4982 <div class="price-box price-final_price" data-role="priceBox" data-product-id="1448" data-price-box="product-id-1448"> 4983 <span 4984 x-data x-id="['price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1448']" class="price-container price-final_price tax weee" 4985 > 4986 <span :id="$id('price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1448')" data-label="Incl. Tax" data-price-amount="29.988001" 4987 data-price-type="finalPrice" 4988 class="price-wrapper price-including-tax" 4989 ><span class="price">£29.99</span></span> 4990 4991 4992 <span id="price-excluding-tax-product-price-1448" 4993 data-label="Excl. Tax" 4994 data-price-amount="24.99" 4995 data-price-type="basePrice" 4996 class="price-wrapper price-excluding-tax"> 4997 <span class="price">£24.99</span></span> 4998 </span> 4999 5000</div> </div> 5001 5002 <div class="pt-3 flex flex-wrap items-center gap-y-4 gap-x-2 5003 "> 5004 <button 5005 class="cart-button w-auto btn btn-primary justify-center text-sm mx-auto mr-auto" 5006 title="Add to Cart Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On" 5007 aria-label="Add to Cart Heal Force Prince 100A LED Fingertip Pulse Oximeter With Auto Power On" 5008 data-addto="cart" 5009 > 5010 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 5011 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2
50110 014 0z"/> 5012</svg> 5013 <span class="inline md:hidden lg:inline"> 5014 Add to Cart </span> 5015 </button> 5016 5017 </div> 5018 </div> 5019</form> 5020 </li> 5021 <li class="flex flex-col"> 5022 5023<form method="post" 5024 action="https://www.healthcare4all.co.uk/checkout/cart/add/uenc/%25uenc%25/product/1429/in_cart/1/" 5025 class="item product product-item product_addtocart_form card card-interactive grow flex flex-col w-full " 5026 data-sku="JPD-500E" 5027 > 5028 <input name="form_key" type="hidden" value="epjP2l7fzdzQf4Oc" /> <input type="hidden" name="product" value="1429"/> 5029 <a href="https://www.healthcare4all.co.uk/jumper-medical-jpd-500e-led-fingertip-pulse-oximeter-for-oxygen-level-pulse-rate" 5030 title="Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level & Pulse Rate" 5031 class="product photo product-item-photo block mx-auto mb-3 " 5032 tabindex="-1" 5033 > 5034 <img 5035 src="https://www.healthcare4all.co.uk/media/catalog/product/cache/cfaac077d0b00d7a2b6146a7db3be980/t/u/tumbnail_57b3cce4-0d3e-459c-8dfb-f5b1c6461292.jpg" 5036 width="360" 5037 height="360" 5038 alt="Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level & Pulse Rate" 5039 class="product-image-photo" 5040 loading="lazy" 5041 x-data="initProductItemImage" 5042 @update-gallery-1429.window="updateImage" 5043 > 5044 </a> 5045 <div class="product-info flex flex-col grow "> 5046 <div class="mt-2 mb-1 items-center justify-center font-semibold text-lg text-center "> 5047 <a 5048 class="product-item-link line-clamp-3" 5049 href="https://www.healthcare4all.co.uk/jumper-medical-jpd-500e-led-fingertip-pulse-oximeter-for-oxygen-level-pulse-rate" 5050 title="Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level & Pulse Rate" 5051 > 5052 Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level & Pulse Rate </a> 5053 </div> 5054 5055 <div class="py-1 mx-auto "> 5056 <div 5057 role="img" 5058 class="rating-summary" 5059 aria-label="Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level & Pulse Rate rating. 5 out of 5 stars" 5060 > 5061 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 5062 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 5063 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewB
5063ox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 5064 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 5065 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" class="fill-current" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z"/></svg> 5066 </div> 5067 </div> 5068 5069 5070 5071 5072 <div class="pt-1 text-gray-900" 5073 x-data="initPriceBox()" 5074 x-defer="intersect" 5075 @update-prices-1429.window="updatePrice($event.detail);" 5076 > 5077 <div class="price-box price-final_price" data-role="priceBox" data-product-id="1429" data-price-box="product-id-1429"> 5078 <span 5079 x-data x-id="['price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1429']" class="price-container price-final_price tax weee" 5080 > 5081 <span :id="$id('price\u002Dincluding\u002Dtax\u002Dproduct\u002Dprice\u002D1429')" data-label="Incl. Tax" data-price-amount="19.980001" 5082 data-price-type="finalPrice" 5083 class="price-wrapper price-including-tax" 5084 ><span class="price">£19.98</span></span> 5085 5086 5087 <span id="price-excluding-tax-product-price-1429" 5088 data-label="Excl. Tax" 5089 data-price-amount="16.65" 5090 data-price-type="basePrice" 5091 class="price-wrapper price-excluding-tax"> 5092 <span class="price">£16.65</span></span> 5093 </span> 5094 5095</div> </div> 5096 5097 <div class="pt-3 flex flex-wrap items-center gap-y-4 gap-x-2 5098 "> 5099 <button 5100 class="cart-button w-auto btn btn-primary justify-center text-sm mx-auto mr-auto" 5101 title="Add to Cart Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level &amp; Pulse Rate" 5102 aria-label="Add to Cart Jumper Medical JPD-500E LED Fingertip Pulse Oximeter for Oxygen Level &amp; Pulse Rate" 5103 data-addto="cart" 5104 > 5105 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 5106 <path stroke-linecap="round" stroke-linejoin="round" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/> 5107</svg>
5108 <span class="inline md:hidden lg:inline"> 5109 Add to Cart </span> 5110 </button> 5111 5112 </div> 5113 </div> 5114</form> 5115 </li> 5116 </ul> 5117 </div> 5118
5118<script> 5119 function initToolbar_6ac3ddb3d2cb9() { 5120 return { 5121 options: {"productListToolbarForm":{"mode":"product_list_mode","direction":"product_list_dir","order":"product_list_order","limit":"product_list_limit","modeDefault":"grid","directionDefault":"asc","orderDefault":"name","limitDefault":36,"url":"https:\/\/www.healthcare4all.co.uk\/featured-products","formKey":"0TWtmpCcpZOzi078","post":false,"page":"p"}}.productListToolbarForm || {}, 5122 getUrlParams: function () { 5123 let decode = window.decodeURIComponent, 5124 urlPaths = this.options.url.split('?'), 5125 urlParams = urlPaths[1] ? urlPaths[1].split('&') : [], 5126 params = {}, 5127 parameters, i; 5128 5129 for (i = 0; i < urlParams.length; i++) { 5130 parameters = urlParams[i].split('='); 5131 params[decode(parameters[0])] = parameters[1] !== undefined ? 5132 decode(parameters[1].replace(/\+/g, '%20')) : 5133 ''; 5134 } 5135 5136 return params; 5137 }, 5138 getCurrentLimit: function () { 5139 return this.getUrlParams()[this.options.limit] || this.options.limitDefault; 5140 }, 5141 getCurrentPage: function () { 5142 return this.getUrlParams()[this.options.page] || 1; 5143 }, 5144 changeUrl(paramName, paramValue, defaultValue) { 5145 let urlPaths = this.options.url.split('?'), 5146 baseUrl = urlPaths[0], 5147 paramData = this.getUrlParams(), 5148 currentPage = this.getCurrentPage(), 5149 newPage; 5150 5151 /** 5152 * calculates the page on which the first item of the current page will 5153 * be with the new limit and sets that number as the new page 5154 */ 5155 if (currentPage > 1 && paramName === this.options.limit) { 5156 newPage = Math.floor(this.getCurrentLimit() * (currentPage - 1) / paramValue) + 1; 5157 5158 if (newPage > 1) { 5159 paramData[this.options.page] = newPage; 5160 } else { 5161 delete paramData[this.options.page]; 5162 } 5163 } 5164 5165 paramData[paramName] = paramValue; 5166 5167 if (this.options.post) { 5168 hyva.postForm({action: baseUrl, data: paramData, skipUenc: true}); 5169 } else { 5170 if (paramValue === defaultValue.toString()) { 5171 delete paramData[paramName]; 5172 } 5173 paramData = Object.keys(paramData).length === 0 5174 ? '' 5175 : '?' + (new URLSearchParams(paramData)); 5176 location.href = baseUrl + paramData 5177 } 5178 } 5179 } 5180 } 5181</script>
5181 5182 <div x-data="initToolbar_6ac3ddb3d2cb9()" 5183 class="toolbar toolbar-products grid grid-cols-4 sm:grid-cols-8 md:grid-cols-4 5184 lg:grid-cols-8 grid-flow-row gap-2 items-center"> 5185 <p class="toolbar-amount text-sm leading-5 text-gray-700 order-3 sm:order-2 md:order-3 5186 lg:order-2 col-span-2 gap-x-1" id="toolbar-amount"> 5187 <span class="toolbar-number">4</span> Items </p> 5188 5189 5190 5191 <div class="flex justify-center order-2 col-span-4"> 5192 </div> 5193 5194 5195 5196 5197 <div class="field limiter flex items-center order-3 sm:order-2 md:order-3 lg:order-2 col-span-2 justify-end"> 5198 <div class="control"> 5199 <label class="text-sm label"> 5200 <span class="mr-2" aria-label="Show items per page"> 5201 Show </span> 5202 <select 5203 class="form-select limiter-options" 5204 @change="changeUrl( 5205 'product_list_limit', 5206 $event.currentTarget.options[$event.currentTarget.selectedIndex].value, 5207 options.limitDefault 5208 )" 5209 > 5210 <option value="12" 5211 > 5212 12 </option> 5213 <option value="24" 5214 > 5215 24 </option> 5216 <option value="36" 5217 selected="selected" 5218 > 5219 36 </option> 5220 <option value="all" 5221 > 5222 All </option> 5223 </select> 5224 </label> 5225 </div> 5226 </div> 5227 </div> 5228 </section> 5229</div><aside class="sidebar sidebar-additional">
5230<script> 5231function compareSidebarFetchHandler(postUrl, postHeaders, isSingleItem = true) { 5232 const messages = { 5233 "success": isSingleItem 5234 ? "You removed product Product from the comparison list" 5235 : "You removed all products from the comparison list", 5236 "warning": isSingleItem 5237 ? "Could not remove item from compare." 5238 : "Could not remove all item from compare.", 5239 } 5240 5241 return fetch(postUrl, postHeaders).then(function (response) { 5242 if (response.redirected) { 5243 window.location.href = response.url; 5244 } else if (response.ok) { 5245 return response.json(); 5246 } else { 5247 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 5248 [{ type: "warning", text: messages.warning }], 5000 5249 ); 5250 } 5251 }).then(function (response) { 5252 if (!response) return; 5253 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 5254 [{ 5255 type: (response.success) ? "success" : "error", 5256 text: (response.success) ? messages.success : response.error_message 5257 }], 5000 5258 ); 5259 let reloadCustomerDataEvent = new CustomEvent("reload-customer-section-data"); 5260 window.dispatchEvent(reloadCustomerDataEvent); 5261 }).catch(function (error) { 5262 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 5263 [{ type: "error", text: error }], 5000 5264 ); 5265 }); 5266} 5267 5268function initCompareOnCompareSidebar() { 5269 return { 5270 compareProducts: null, 5271 itemCount: 0, 5272 compareItems: {}, 5273 receiveCompareData: function (data) { 5274 if (data['compare-products']) { 5275 this.compareProducts = data['compare-products']; 5276 this.itemCount = this.compareProducts.count; 5277 this.compareItems = this.compareProducts.items; 5278 } 5279 }, 5280 removeFromCompare: function(productId) { 5281 const formKey = hyva.getFormKey(); 5282 const postUrl = BASE_URL + 'catalog/product_compare/remove/'; 5283 const confirmMessage = "Are you sure you want to remove this item from your Compare Products list?"; 5284 if (!window.confirm(confirmMessage)) return; 5285 const postHeaders = { 5286 "headers": { 5287 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 5288 }, 5289 "body": "form_key=" + formKey + "&product=" + productId + "&uenc="
5289+ hyva.getUenc(), 5290 "method": "POST", 5291 "mode": "cors", 5292 "credentials": "include" 5293 }; 5294 5295 compareSidebarFetchHandler(postUrl, postHeaders); 5296 } 5297 } 5298} 5299 5300function initCompareSidebarClear() { 5301 return { 5302 clearCompare: function() { 5303 const formKey = hyva.getFormKey(); 5304 const postUrl = BASE_URL + 'catalog/product_compare/clear/'; 5305 const confirmMessage = "Are you sure you want to remove all items from your Compare Products list?"; 5306 if (!window.confirm(confirmMessage)) return; 5307 const postHeaders = { 5308 "headers": { 5309 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 5310 }, 5311 "body": "form_key=" + formKey + "&uenc=" + hyva.getUenc(), 5312 "method": "POST", 5313 "mode": "cors", 5314 "credentials": "include" 5315 }; 5316 5317 compareSidebarFetchHandler(postUrl, postHeaders, isSingleItem = false); 5318 } 5319 } 5320} 5321</script>
5321 5322 5323<div x-data="initCompareOnCompareSidebar()" 5324 @private-content-loaded.window="receiveCompareData($event.detail.data)" 5325 class="compare-widget" 5326> 5327 <template x-if="itemCount"> 5328 <div class="mt-8"> 5329 <h2 class="border-t border-gray-300 mb-6 pt-5 font-semibold text-lg" 5330 id="compare-sidebar" 5331 > 5332 Compare Products </h2> 5333 <ul role="list" class="my-4" aria-labelledby="compare-sidebar"> 5334 <template x-for="product in compareItems"> 5335 <li class="flex items-start mb-4"> 5336 <a 5337 :href="product.product_url" 5338 class="block mb-3 w-10 h-10 shrink-0 mr-4" 5339 aria-hidden="true" 5340 tabindex="-1" 5341 > 5342 <img 5343 :src="product.image" 5344 alt="" 5345 loading="lazy" 5346 > 5347 </a> 5348 <strong class="mr-2 text-sm leading-6 font-normal"> 5349 <a :href="product.product_url" :title="product.name" x-html="product.name"></a> 5350 </strong> 5351 <button 5352 type="button" 5353 @click.prevent="removeFromCompare(product.id)" 5354 :aria-label="hyva.str('Remove\u0020product\u0020\u0022\u00251\u0022\u0020from\u0020the\u0020comparison', product.name)" 5355 class="p-1 inline-flex shrink-0 items-center justify-center text-slate-400 5356 hover:text-slate-800 ml-auto" 5357 > 5358 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24" height="24" aria-hidden="true"> 5359 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 5360</svg> 5361 </button> 5362 </li> 5363 </template> 5364 </ul> 5365 <div class="flex flex-wrap items-center md:mt-5 gap-2 text-sm"> 5366 <a href="https://www.healthcare4all.co.uk/catalog/product_compare/index/" 5367 title="Compare Products" 5368 class="btn btn-secondary text-sm"> 5369 <span>Compare</span> 5370 </a> 5371 <button x-data="initCompareSidebarClear()" 5372 @click.prevent="clearCompare()" 5373 aria-label="Remove all Products" 5374 class="btn text-sm shadow-none bg-transparent text-inherit"> 5375 <span>Remove All</span> 5376 </button> 5377 </div> 5378 </div> 5379 </template> 5380</div> 5381 5382</aside></div></main><footer class="page-footer"><div class="footer content">
5382<script> 5383 addEventListener('DOMContentLoaded', () => { 5384 for (const [selector, label] of Object.entries({"aside.sidebar-main":"Sidebar Main","aside.sidebar-additional":"Sidebar Additional"})) { 5385 const target = document.querySelector(selector); 5386 target && target.setAttribute('aria-label', label); 5387 } 5388 }, {once: true}) 5389</script>
5389 5390 5391<style> 5392 .newsletter-grid { 5393 display: grid; 5394 grid-template-columns: auto 1fr auto; 5395 grid-template-rows: auto auto; 5396 gap: 0.5rem 1.5rem; 5397 align-items: center; 5398 padding: 1rem 0; 5399 } 5400 .newsletter-grid .ng-title { grid-column: 1; grid-row: 1; text-align: center; } 5401 .newsletter-grid .ng-follow { grid-column: 3; grid-row: 1; text-align: center; } 5402 .newsletter-grid .ng-desc { grid-column: 1; grid-row: 2; text-align: center; } 5403 .newsletter-grid .ng-form { grid-column: 2; grid-row: 2; display: flex; gap: 0.5rem; align-items: center; justify-self: center; } 5404 .newsletter-grid .ng-icons { grid-column: 3; grid-row: 2; justify-self: center; } 5405 @media (max-width: 767px) { 5406 .newsletter-grid { 5407 display: flex; 5408 flex-direction: column; 5409 align-items: center; 5410 text-align: center; 5411 gap: 0.5rem; 5412 } 5413 .newsletter-grid .ng-title { order: 1; } 5414 .newsletter-grid .ng-desc { order: 2; } 5415 .newsletter-grid .ng-form { order: 3; flex-direction: column; width: 100%; max-width: 100% !important; } 5416 .newsletter-grid .ng-follow { order: 4; margin-top: 0.5rem; } 5417 .newsletter-grid .ng-icons { order: 5; justify-content: center; } 5418 } 5419</style> 5420 5421<div class="bg-zinc-50 newsletter-grid mx-auto px-4" style="max-width: 1060px;"> 5422 <!-- Row 1 left: heading --> 5423 <div class="ng-title"> 5424 <p class="text-lg text-slate-700 font-bold mb-0"> 5425 <strong>Be the first to know</strong> 5426 </p> 5427 </div> 5428 5429 <!-- Row 1 right: follow us --> 5430 <div class="ng-follow text-lg font-bold lg:text-base text-slate-700 uppercase"> 5431 Follow us </div> 5432 5433 <!-- Row 2 left: description --> 5434 <div class="ng-desc text-slate-600"> 5435 <p class="mb-0">Get all the latest information on Events,<br> 5436 Sales and Offers. Sign up for newsletter today.</p> 5437 </div> 5438 5439 <!-- Row 2 middle: form --> 5440 <form 5441 id="newsletter-validate-detail" 5442 class="ng-form" 5443 action="https://www.healthcare4all.co.uk/newsletter/subscriber/new/" 5444 method="post" 5445 x-data="initNewsletterForm" 5446 @submit.prevent="submitForm" 5447 aria-label="Subscribe to Newsletter" 5448 > 5449 <label class="grow m-0"> 5450 <span class="sr-only">Email Address</span> 5451 <input 5452 type="email" 5453 id="newsletter-subscribe" 5454 name="email" 5455 class="form-input w-full py-2.5 px-5" style="min-width: 260px;" 5456 required 5457 placeholder="Enter your email address" 5458 > 5459 <input name="form_key" type="hidden" value="0TWtmpCcpZOzi078" /> <div class="control"> 5460 <input type="hidden" 5461 value="" 5462 name="g-recaptcha-response" 5463 > 5464</div> 5465 </label> 5466 <button class="newsletter-button shrink-0 btn btn-primary h-11 font-bold uppercase"> 5467 Subscribe </button> 5468 <template x-if="displayErrorMessage"> 5469 <p class="flex items-center text-red mt-2"> 5470 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="inline-block mr-3" width="24" height="24" role="img"> 5471 <path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> 5472<title>exclamation-circle</title></svg> 5473 <template x-for="errorMessage in errorMessages"> 5474 <span x-html="errorMessage"></span> 5475 </template> 5476 </p> 5477 </template> 5478 <div><p class="prose my-4 text-sm"> 5479 <em>This form is protected by reCAPTCHA - the <a class="underline" href="https://policies.google.com/privacy" target="_blank" rel="noopener">Google Privacy Policy</a> and <a class="underline" href="https://policies.google.com/terms" target="_blank" rel="noopener">Terms of Service</a> apply.</em> 5480</p> 5481</div> 5482 </form> 5483 5484
5484<script> 5485 function initNewsletterForm() { 5486 return { 5487 errors: 0, 5488 hasCaptchaToken: 0, 5489 displayErrorMessage: false, 5490 errorMessages: [], 5491 setErrorMessages(messages) { 5492 this.errorMessages = [messages] 5493 this.displayErrorMessage = this.errorMessages.length 5494 }, 5495 submitForm() { 5496 // Do not rename $form, the variable is expected to be declared in the recaptcha output 5497 const $form = document.querySelector('#newsletter-validate-detail'); 5498 if (!this.hasCaptchaToken) { 5499 this.errors = 1; 5500 5501 5502 const executeGreCaptcha = () => { 5503 grecaptcha.ready(() => { 5504 grecaptcha.execute( 5505 '6Lc7_50sAAAAAG_oXG0fwI0gVEkpJtqxB2S2A2ce', 5506 {action: 'submit'} 5507 ).then((token) => { 5508 const tokenElement = $form['g\u002Drecaptcha\u002Dresponse']; 5509 5510 if (tokenElement && token && token.length > 0) { 5511 $form['g\u002Drecaptcha\u002Dresponse'].value = token; 5512 this.errors = 0; 5513 this.hasCaptchaToken = 1; 5514 (this.submitForm || $form.submit).call(this); 5515 } else { 5516 this.errors = 1; 5517 const error = tokenElement 5518 ? 'ReCaptcha\u0020validation\u0020failed,\u0020please\u0020try\u0020again' 5519 : 'ReCaptcha\u0020token\u0020element\u0020is\u0020missing.\u0020Please\u0020refresh\u0020the\u0020page\u0020and\u0020trying\u0020again.'; 5520 if (this.setErrorMessages) { 5521 this.setErrorMessages([error]) 5522 this.displayErrorMessage = true; 5523 } else { 5524 window.dispatchMessages && window.dispatchMessages([{type: "error", text: error}], 5000); 5525 } 5526 } 5527 }).catch(exception => { 5528 console.error(exception || `An unknown error occurred during ReCaptcha validation. Are the tokens and the domain correctly set up in the Google console?`) 5529 }); 5530 }) 5531 } 5532 5533 if (window.grecaptcha) { 5534 executeGreCaptcha(); 5535 } else { 5536 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?render=6Lc7_50sAAAAAG_oXG0fwI0gVEkpJtqxB2S2A2ce"; 5537 const script = document.createElement('script'); 5538 script.setAttribute('type', 'text/javascript'); 5539 script.setAttribute('src', recaptchaUrl); 5540 document.head.appendChild(script); 5541 5542 script.addEventListener("load", executeGreCaptcha, false); 5543 } 5544 } 5545 5546 if (this.errors === 0) { 5547 $form.submit(); 5548 } 5549 } 5550 } 5551 } 5552 window.addEventListener('alpine:init', () => Alpine.data('initNewsletterForm', initNewsletterForm), {once: true}) 5553 </script>
5553 5554 5555 <!-- Row 2 right: social icons --> 5556 <div class="ng-icons flex gap-2 justify-end"> 5557 <a href="https://www.facebook.com/Healthcare4all/" 5558 target="_blank" rel="noopener noreferrer" 5559 class="text-white transition-colors rounded-lg p-1.5" 5560 style="background-color: #089A8A;" 5561 onmouseover="this.style.backgroundColor='#067a6d'" 5562 onmouseout="this.style.backgroundColor='#089A8A'"> 5563 <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" viewBox="0 0 32 32" role="img"> 5564 <path d="M17.068 26.667v-9.732h3.267l.489-3.792h-3.756v-2.421c0-1.098.305-1.847 1.88-1.847h2.008V5.483c-.347-.046-1.54-.15-2.926-.15-2.896 0-4.878 1.768-4.878 5.013v2.797H9.877v3.793h3.275v9.73h3.916Z"/> 5565<title>Follow us on Facebook</title></svg> 5566 </a> 5567 <a href="https://www.instagram.com/healthcare4alluk/" 5568 target="_blank" rel="noopener noreferrer" 5569 class="text-white transition-colors rounded-lg p-1.5" 5570 style="background-color: #089A8A;" 5571 onmouseover="this.style.backgroundColor='#067a6d'" 5572 onmouseout="this.style.backgroundColor='#089A8A'"> 5573 <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" viewBox="0 0 32 32" role="img"> 5574 <path d="M12.668 16a3.333 3.333 0 1 1 6.666 0 3.333 3.333 0 0 1-6.666 0Zm-1.802 0a5.135 5.135 0 1 0 10.27 0 5.135 5.135 0 0 0-10.27 0Zm9.273-5.338a1.2 1.2 0 1 0 1.2-1.2 1.2 1.2 0 0 0-1.2 1.2ZM11.96 24.14c-.975-.045-1.505-.207-1.857-.344a3.109 3.109 0 0 1-1.15-.748 3.086 3.086 0 0 1-.748-1.15c-.137-.352-.3-.882-.344-1.857-.048-1.054-.058-1.37-.058-4.04 0-2.671.01-2.987.058-4.042.045-.975.208-1.504.344-1.857.182-.467.398-.8.748-1.15.35-.35.683-.567 1.15-.748.352-.138.882-.3 1.857-.344C13.014 7.81 13.331 7.8 16 7.8c2.67 0 2.987.01 4.042.059.975.044 1.504.208 1.857.344.466.18.8.398 1.15.748.35.35.566.683.748 1.15.137.352.3.882.344 1.857.048 1.055.058 1.37.058 4.041 0 2.67-.01 2.986-.058 4.041-.044.975-.208 1.505-.344 1.857a3.1 3.1 0 0 1-.748 1.15 3.11 3.11 0 0 1-1.15.748c-.352.137-.882.3-1.857.344-1.055.048-1.371.058-4.042.058-2.67 0-2.986-.01-4.04-.058Zm-.082-18.08c-1.065.049-1.792.218-2.428.465A4.905 4.905 0 0 0 7.68 7.678 4.886 4.886 0 0 0 6.525 9.45c-.247.636-.416 1.363-.464 2.427-.05 1.066-.06 1.407-.06 4.123s.01 3.057.06 4.123c.048 1.064.217 1.791.464 2.427a4.888 4.888 0 0 0 1.154 1.771 4.916 4.916 0 0 0 1.771 1.154c.637.247 1.363.416 2.428.464 1.066.049 1.407.061 4.122.061 2.716 0 3.057-.011 4.123-.06 1.065-.049 1.792-.218 2.427-.465a4.917 4.917 0 0 0 1.772-1.154 4.899 4.899 0 0 0 1.153-1.77c.248-.637.417-1.364.465-2.428.048-1.067.06-1.407.06-4.123s-.012-3.057-.06-4.123c-.049-1.064-.217-1.792-.465-2.427a4.918 4.918 0 0 0-1.153-1.772 4.893 4.893 0 0 0-1.77-1.153c-.637-.247-1.364-.417-2.428-.464C19.058 6.012 18.717 6 16.001 6s-3.057.011-4.123.06Z"/> 5575<title>Follow us on Instagram</title></svg> 5576 </a> 5577 <a href="https://x.com/healthcare4" 5578 target="_blank" rel="noopener noreferrer" 5579 class="text-white transition-colors rounded-lg p-1.5" 5580 style="background-color: #089A8A;" 5581 onmouseover="this.style.backgroundColor='#067a6d'" 5582 onmouseout="this.style.backgroundColor='#089A8A'"> 5583 <img src="https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/images/x.svg" alt="Icon" width="40" height="40"/> 5584 </a> 5585 </div> 5586</div> 5587 5588 5589 5590<div class="bg-zinc-100 border-t border-zinc-200 footer-bg pb-8 sm:pb-0"> 5591 <div class="container py-5 mx-auto"> 5592 <div class="grid grid-cols-1 lg:grid-cols-3 lg:gap-6 text-slate-600"> 5593 5594 <div 5595 x-data="mobileFooterCollpase" 5596 x-bind="eventListeners" 5597 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 5598 data-open="true" 5599 > 5600 <div 5601 class="group flex w-full items-center justify-between py-2.5 gap-2 font-bold text-sm uppercase tracking-wider text-slate-700 lg:pt-0" 5602 data-id="footer_column_1" 5603 x-bind="setToggleRoles" 5604 @click="toggle" 5605 @keyup.enter="toggle" 5606 @keyup.space="toggle" 5607 > 5608 <h3 class="title-footer_column_1">CONTACT INFORMATION</h3>
5609 <span 5610 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 5611 x-ref="toggleIcon" 5612 > 5613 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 5614 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 5615</svg> 5616 </span> 5617 </div> 5618 <div 5619 id="footer_column_1" 5620 class="aria-[hidden=true]:hidden" 5621 x-bind="setCollapseRoles" 5622 > 5623 <div class="pt-0.5 pb-1.5"> 5624 <p class="font-semibold mt-0">ADDRESS</p> 5625<p>Unit E, Oaktree Business Park, Limewood Court, Leeds, LS14 1NF</p> 5626<p class="font-semibold mt-3">PHONE</p> 5627<p>0113 350 5432</p> 5628<p class="font-semibold mt-3">EMAIL</p> 5629<p><a href="/cdn-cgi/l/email-protection#ceadbbbdbaa1a3abbcbdabbcb8a7adab8ea6abafa2baa6adafbcabfaafa2a2e0ada1e0bba5" class="underline"><span class="__cf_email__" data-cfemail="33504640475c5e5641405641455a5056735b56525f475b5052415607525f5f1d505c1d4658">[email protected]</span></a></p> </div> 5630 </div> 5631 </div> 5632 5633 <div 5634 x-data="mobileFooterCollpase" 5635 x-bind="eventListeners" 5636 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 5637 data-open="false" 5638 > 5639 <div 5640 class="group flex w-full items-center justify-between py-2.5 gap-2 font-bold text-sm uppercase tracking-wider text-slate-700 lg:pt-0" 5641 data-id="footer_column_2" 5642 x-bind="setToggleRoles" 5643 @click="toggle" 5644 @keyup.enter="toggle" 5645 @keyup.space="toggle" 5646 > 5647 <h3 class="title-footer_column_2">CUSTOMER SUPPORT</h3> 5648 <span 5649 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 5650 x-ref="toggleIcon" 5651 > 5652 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 5653 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 5654</svg> 5655 </span> 5656 </div> 5657 <div 5658 id="footer_column_2" 5659 class="aria-[hidden=true]:hidden" 5660 x-bind="setCollapseRoles" 5661 > 5662 <div class="pt-0.5 pb-1.5"> 5663 5664<nav class="sm:flex" aria-label="Customer Support"> 5665 <ul class="lg:w-1/2"> 5666 <li> 5667 <a 5668 href="https://www.healthcare4all.co.uk/sales/order/history/" 5669 class="block py-1 hover:underline" 5670 >Order History</a> 5671 </li> 5672 <li> 5673 <a 5674 href="https://www.healthcare4all.co.uk/returns_policy/" 5675 class="block py-1 hover:underline" 5676 >Returns</a> 5677 </li> 5678 <li> 5679 <a 5680 href="https://www.healthcare4all.co.uk/vat_exemption_explanation/" 5681 class="block py-1 hover:underline" 5682 >VAT Exemption</a> 5683 </li> 5684 <li> 5685 <a 5686 href="https://www.healthcare4all.co.uk/faq/" 5687 class="block py-1 hover:underline" 5688 >Help & FAQs</a> 5689 </li> 5690 <li> 5691 <a 5692 href="https://www.healthcare4all.co.uk/contact/" 5693 class="block py-1 hover:underline" 5694 >Contact Us</a> 5695 </li> 5696 </ul> 5697 <ul class="lg:w-1/2"> 5698 <li> 5699 <a 5700 href="https://www.healthcare4all.co.uk/about-us/" 5701 class="block py-1 hover:underline" 5702 >About Us</a> 5703 </li> 5704 <li> 5705 <a 5706 href="https://www.healthcare4all.co.uk/blog/" 5707 class="block py-1 hover:underline" 5708 >Blog</a> 5709 </li> 5710 </ul> 5711</nav> 5712 </div> 5713 </div> 5714 </div> 5715 5716 <div 5717 x-data="mobileFooterCollpase" 5718 x-bind="eventListeners" 5719 class="border-b border-zinc-200 lg:border-b-0 last:border-b-0" 5720 data-open="false" 5721 > 5722 <div 5723 class="group flex w-full items-center justify-between py-2.5 gap-2 font-bold text-sm uppercase tracking-wider text-slate-700 lg:pt-0" 5724 data-id="footer_column_3" 5725 x-bind="setToggleRoles" 5726 @click="toggle" 5727 @keyup.enter="toggle" 5728 @keyup.space="toggle" 5729 > 5730 <h3 class="title-footer_column_3">ABOUT US</h3>
5731 <span 5732 class="transition-transform group-aria-expanded:rotate-180 lg:hidden" 5733 x-ref="toggleIcon" 5734 > 5735 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20" height="20" aria-hidden="true"> 5736 <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/> 5737</svg> 5738 </span> 5739 </div> 5740 <div 5741 id="footer_column_3" 5742 class="aria-[hidden=true]:hidden" 5743 x-bind="setCollapseRoles" 5744 > 5745 <div class="pt-0.5 pb-1.5"> 5746 <p>Healthcare4all are medical equipment suppliers in the UK, specialising in respiratory products such as nebuliser machines and pulse oximeters, for conditions such as COPD and asthma. We also have a wide range of dental supplies such as irrigators and brushes, home ECG devices and equipment to help diabetics monitor their condition.</p> </div> 5747 </div> 5748 </div> 5749 <div class="pt-4 lg:pt-0"> 5750 </div> 5751 </div> 5752 </div> 5753 <div class="container pt-4 pb-4 border-t border-zinc-200 flex justify-between items-center flex-col sm:flex-row text-sm"> 5754 <small class="text-sm text-slate-700"> 5755 <span>© 2026 Healthcare4all Ltd. All Rights Reserved.</span> 5756</small> 5757 <div class="pay-prov flex gap-2 flex-wrap justify-center" aria-label="Payment Providers" > 5758 <img src="/media/wysiwyg/paypal.svg" alt="paypal" width="48" height="32"> 5759<img src="/media/wysiwyg/mastercard.svg" alt="mastercard" width="48" height="32" > 5760<img src="/media/wysiwyg/discover.svg" alt="discover" width="48" height="32" > 5761<img src="/media/wysiwyg/visa.svg" alt="visa" width="48" height="32"> 5762<img src="/media/wysiwyg/americanexpress.svg" alt="americanexpress" width="48" height="32" > </div> 5763 </div> 5764</div>
vendor: 109 bytes, lines 5764-5765
5764 5765<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
5765<script> 5766 function mobileFooterCollpase() { 5767 return { 5768 open: false, 5769 isMobile: false, 5770 init() { 5771 this.checkIsMobileResolution(); 5772 if (this.$root.dataset.open === "true") { 5773 this.open = true; 5774 } 5775 }, 5776 checkIsMobileResolution() { 5777 this.isMobile = getComputedStyle(this.$refs.toggleIcon).display !== 'none' 5778 }, 5779 isOpen() { 5780 return this.isMobile ? this.open : true; 5781 }, 5782 toggle() { 5783 return this.isMobile ? this.open = !this.open : true; 5784 }, 5785 eventListeners: { 5786 ['@resize.window.debounce'] () { 5787 this.checkIsMobileResolution(); 5788 }, 5789 ['@visibilitychange.window.debounce'] () { 5790 this.checkIsMobileResolution(); 5791 } 5792 }, 5793 setToggleRoles: { 5794 [':role'] () { 5795 return this.isMobile && 'button'; 5796 }, 5797 [':tabindex'] () { 5798 return this.isMobile && '0'; 5799 }, 5800 [':aria-expanded'] () { 5801 return this.isMobile ? this.open : null; 5802 }, 5803 [':aria-controls'] () { 5804 return this.isMobile ? this.$el.dataset.id : null; 5805 } 5806 }, 5807 setCollapseRoles: { 5808 [':aria-hidden'] () { 5809 return this.isMobile ? !this.open : null; 5810 }, 5811 [':aria-labelledby'] () { 5812 return this.isMobile ? this.$el.id : null; 5813 } 5814 } 5815 } 5816 } 5817 window.addEventListener('alpine:init', () => Alpine.data('mobileFooterCollpase', mobileFooterCollpase), {once: true}) 5818</script>
5818 5819 5820</div></footer> <small class="copyright"><span>Search engine powered by <a href="https://elasticsuite.io" rel="nofollow" style="color:inherit">ElasticSuite</a></span></small> 5821
5822<script>document.addEventListener("DOMContentLoaded", function() { 5823 if (document.querySelectorAll('.mf-ytw-wrapper').length 5824 || document.querySelectorAll('[data-mf-ytw-youtube-link]').length) { 5825 !function (f, b, e, v, t, s) { 5826 if(f.mfytwcss)return; 5827 f.mfytwcss=1; 5828 t = b.createElement(e); 5829 t.rel = 'stylesheet'; 5830 t.type = 'text/css'; 5831 t.href = v; 5832 s = b.getElementsByTagName('HEAD')[0]; 5833 s.appendChild(t) 5834 }(window, document, 'link', 'https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Magefan_YouTubeWidget/css/youtubewidget.css'); 5835 } 5836 if (document.querySelectorAll('.mf-ytw-wrapper').length) { 5837 !function (f, b, e, v, t, s) { 5838 if(f.mfytwjs)return; 5839 f.mfytwjs=1; 5840 t = b.createElement(e); 5841 t.type = 'text/javascript'; 5842 t.src = v; 5843 s = b.getElementsByTagName('HEAD')[0]; 5844 s.appendChild(t) 5845 }(window, document, 'script', 'https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Magefan_YouTubeWidget/js/iframe.js'); 5846 } 5847 if (document.querySelectorAll('[data-mf-ytw-youtube-link]').length) { 5848 !function (f, b, e, v, t) { 5849 if(f.mflinkjs)return; 5850 f.mflinkjs=1; 5851 t = b.createElement(e); 5852 t.type = 'text/javascript'; 5853 t.src = v; 5854 s = b.getElementsByTagName('HEAD')[0]; 5855 s.appendChild(t) 5856 }(window, document, 'script', 'https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Magefan_YouTubeWidget/js/link.js'); 5857 } 5858 });</script>
5858<script>try { 5859smileTracker.addPageVar('type.identifier', 'catalog_category_view'); 5860smileTracker.addPageVar('type.label', 'Catalog Category'); 5861smileTracker.addPageVar('locale', 'en_GB'); 5862} catch (err) { ; }</script>
5862<script>try { 5863smileTracker.addPageVar('category.id', '222'); 5864smileTracker.addPageVar('category.label', 'Featured Products'); 5865smileTracker.addPageVar('category.path', '1/124/222'); 5866smileTracker.addPageVar('category.breadcrumb', ''); 5867smileTracker.addPageVar('product_list.page_count', '1'); 5868smileTracker.addPageVar('product_list.product_count', '4'); 5869smileTracker.addPageVar('product_list.current_page', '1'); 5870smileTracker.addPageVar('product_list.sort_order', 'name'); 5871smileTracker.addPageVar('product_list.sort_direction', 'asc'); 5872smileTracker.addPageVar('product_list.display_mode', 'grid'); 5873} catch (err) { ; }</script>
vendor: 1 bytes, line 5873
5873
5874<script type="text/x-magento-init"> 5875{ 5876 "*": { 5877 "tawk-embed" : { 5878 "embedUrl" : "https://embed.tawk.to/5d19ee677a48df6da2425e54/default" 5879 } 5880 } 5881} 5882</script>
vendor: 1 bytes, line 5882
5882
5883<script type="text/javascript" async> 5884 var w = document.createElement("script"); 5885 w.type = "text/javascript"; 5886 w.src = "//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js"; 5887 w.async = true; 5888 document.head.appendChild(w); 5889</script>
vendor: 1 bytes, line 5889
5889
5890<script type="text/javascript"> 5891 (function(w,d,s,r,n){w.TrustpilotObject=n;w[n]=w[n]||function(){(w[n].q=w[n].q||[]).push(arguments)}; 5892 a=d.createElement(s);a.async=1;a.src=r;a.type='text/java'+s;f=d.getElementsByTagName(s)[0]; 5893 f.parentNode.insertBefore(a,f)})(window,document,'script', 'https://invitejs.trustpilot.com/tp.min.js', 'tp'); 5894 tp('register','yZn8o9dhyzg6D6Ik'); 5895</script>
vendor: 1 bytes, line 5895
5895
5896<script type="text/javascript"> 5897 function inIframe () { 5898 try { 5899 return window.self !== window.top; 5900 } catch (e) { 5901 return false; 5902 } 5903 } 5904 5905 function tryParseJson(str) { 5906 if (typeof str === 'string') { 5907 try { 5908 return JSON.parse(str); 5909 } catch (e) { 5910 return false; 5911 } 5912 } 5913 return false; 5914 } 5915 5916 if (inIframe()) { 5917 window.addEventListener('message', function(e) { 5918 var adminOrign = new URL(window.location).hostname; 5919 var eventOriginHostname = new URL(e.origin).hostname; 5920 if (!e.data || adminOrign !== eventOriginHostname) { 5921 return; 5922 } 5923 if (typeof TrustpilotPreview !== 'undefined') { 5924 if (typeof e.data === 'string' && e.data === 'submit') { 5925 TrustpilotPreview.sendTrustboxes(); 5926 } else { 5927 jsonData = tryParseJson(e.data); 5928 if (jsonData.trustbox) { 5929 TrustpilotPreview.setSettings(jsonData.trustbox); 5930 } else if (jsonData.customised) { 5931 TrustpilotPreview.updateActive(jsonData.customised); 5932 } 5933 } 5934 } else { 5935 var settings = tryParseJson(e.data); 5936 if (settings) { 5937 var p = document.createElement("script"); 5938 p.type = "text/javascript"; 5939 p.onload = function () { 5940 const iFrame = e.source.parent.document.getElementById('configuration_iframe').contentWindow; 5941 TrustpilotPreview.init(['//ecommplugins-scripts.trustpilot.com/v2.1/css/preview.min.css'], settings, iFrame, e.source); 5942 }; 5943 p.src = '//ecommplugins-scripts.trustpilot.com/v2.1/js/preview.min.js'; 5944 document.head.appendChild(p); 5945 } 5946 } 5947 }); 5948 } 5949</script>
vendor: 1 bytes, line 5949
5949
5950<script> 5951 (() => { 5952 function alpineSnapSlider(Alpine) { 5953 function roundUpIfGreaterThan(number, min = 8) { 5954 const decimalPart = number - Math.floor(number); 5955 return decimalPart >= min ? Math.ceil(number) : Math.floor(number); 5956 } 5957 Alpine.directive("snap-slider", (el, { modifiers }, { cleanup }) => { 5958 const track = el.querySelector("[data-track]"); 5959 if (!track) { 5960 console.warn( 5961 "No Slider track defined, reverting back to CSS slider.\nPlease create a wrapper element for your slides with the attribute data-track" 5962 ); 5963 return; 5964 } 5965 let initialLoad = true; 5966 let pager = el.querySelector("[data-pager]"); 5967 let slides = []; 5968 let inViewObserver, mutationObserver, resizeObserver; 5969 const navBtns = Array.from( 5970 el.querySelectorAll("[data-next], [data-prev]") 5971 ); 5972 const slideLabelSepparator = el.dataset.slideLabelSepparator || "of"; 5973 const useAutoPager = modifiers.includes("auto-pager"); 5974 const useGroupPager = modifiers.includes("group-pager"); 5975 const sliderLabel = el.hasAttribute("aria-label") && el.getAttribute("aria-label").toLowerCase().trim().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, ""); 5976 const sliderId = el.id || sliderLabel || "slider"; 5977 const markerIdName = "data-target-id"; 5978 const pagerClasses = el.dataset.pagerClass || "pager"; 5979 const markerClasses = el.dataset.markerClass || "pager-item"; 5980 function getInViewItems() { 5981 const inViewSlides = track.querySelectorAll("[data-in-view]"); 5982 const firstInViewSlide = inViewSlides[0] || null; 5983 const lastInViewSlide = inViewSlides[inViewSlides.length - 1] || null; 5984 const isAtStart = firstInViewSlide === slides[0]; 5985 const isAtEnd = lastInViewSlide === slides[slides.length - 1]; 5986 return { 5987 inViewSlides, 5988 totalInViewSlides: inViewSlides.length, 5989 firstInViewSlide, 5990 lastInViewSlide, 5991 isAtStart, 5992 isAtEnd, 5993 hasNoOverflow: isAtStart && isAtEnd 5994 }; 5995 } 5996 function groupPagerMarkers() { 5997 if (!pager || !useGroupPager) return; 5998 const totalVisibleSlides = roundUpIfGreaterThan( 5999 track.offsetWidth / slides[0].offsetWidth 6000 ); 6001 const markers = Array.from(pager.querySelectorAll("a, button")); 6002 markers.forEach((marker, index) => { 6003 marker.style.display = index % totalVisibleSlides === 0 ? null : "none"; 6004 }); 6005 } 6006 function handleInView(entries) { 6007 entries.forEach((entry) => { 6008 const marker = pager && (pager.querySelector(`[href="#${entry.target.id}"]`) || pager.querySelector( 6009 `[${markerIdName}="${entry.target.id}"]` 6010 )); 6011 entry.target.toggleAttribute( 6012 "data-in-view", 6013 entry.isIntersecting 6014 ); 6015 entry.target.toggleAttribute("inert", !entry.isIntersecting); 6016 marker?.setAttribute("aria-current", entry.isIntersecting); 6017 marker?.setAttribute( 6018 "tabindex", 6019 entry.isIntersecting ? "0" : "-1" 6020 ); 6021 }); 6022 const { isAtStart, isAtEnd, hasNoOverflow } = getInViewItems(); 6023 navBtns.forEach((btn) => { 6024 if (btn.hasAttribute("data-next")) { 6025 btn.style.visibility = hasNoOverflow ? "hidden" : null; 6026 isAtEnd ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled"); 6027 } 6028 if (btn.hasAttribute("data-prev")) { 6029 btn.style.visibility = hasNoOverflow ? "hidden" : null; 6030 isAtStart ? btn.setAttribute("disabled", "") : btn.removeAttribute("disabled"); 6031 } 6032 }); 6033 if (pager) { 6034 pager.style.visibility = hasNoOverflow ? "hidden" : null; 6035 } 6036 if (!initialLoad) { 6037 el.dispatchEvent( 6038 new CustomEvent("slideChange", { detail: getInViewItems() }) 6039 ); 6040 } else { 6041 initialLoad = false;
6042 } 6043 if (document.activeElement.parentElement.hasAttribute("data-pager")) { 6044 const activeItems = pager.querySelectorAll('[tabindex="0"]'); 6045 if (activeItems.length) { 6046 activeItems[0].focus(); 6047 } 6048 } 6049 } 6050 function getSlides() { 6051 if (!track) return []; 6052 return Array.from(track.children).filter( 6053 (child) => child.tagName.toLowerCase() !== "template" && child.tagName.toLowerCase() !== "script" 6054 ); 6055 } 6056 function refreshSlides() { 6057 initialLoad = true; 6058 slides = getSlides(); 6059 setupSlides(); 6060 if (useAutoPager) { 6061 createPager(); 6062 } else { 6063 setupPager(); 6064 } 6065 groupPagerMarkers(); 6066 setupObservers(); 6067 } 6068 function setupSlides() { 6069 slides = getSlides(); 6070 slides.forEach((slide, index) => { 6071 const totalSlides = slides.length; 6072 const currentSlide = index + 1; 6073 const existingLabel = slide.getAttribute("aria-label") || ""; 6074 const isImage = slide.tagName.toLowerCase() === "img" || slide.tagName.toLowerCase() === "picture"; 6075 const slideLabelTag = isImage ? "alt" : "aria-label"; 6076 const hasAutoLabel = existingLabel.startsWith(`${currentSlide} ${slideLabelSepparator} `); 6077 if (!slide.hasAttribute("id")) { 6078 slide.setAttribute("id", `${sliderId}-item-${currentSlide}`); 6079 } 6080 6081 if ((!slide.hasAttribute(slideLabelTag) || slide.getAttribute(slideLabelTag) === "") || hasAutoLabel) { 6082 slide.setAttribute(slideLabelTag, `${currentSlide} ${slideLabelSepparator} ${totalSlides}`); 6083 } 6084 6085 if (slide.tagName.toLowerCase() === "div" && !slide.hasAttribute("role")) { 6086 slide.setAttribute("role", "group"); 6087 } 6088 6089 if (pager && !isImage) { 6090 slide.setAttribute("role", "tabpanel"); 6091 } 6092 6093 if (slide.getAttribute('role') === "group") { 6094 slide.setAttribute("aria-roledescription", "item"); 6095 } 6096 }); 6097 if (!el.hasAttribute("role")) { 6098 el.setAttribute("role", "region"); 6099 } 6100 if (!el.hasAttribute("aria-roledescription")) { 6101 el.setAttribute("aria-roledescription", "carousel"); 6102 } 6103 track.setAttribute("tabindex", 0); 6104 track.setAttribute("aria-live", "polite"); 6105 } 6106 function setupNav() { 6107 navBtns.forEach((btn) => { 6108 btn.setAttribute("disabled", ""); 6109 btn.removeAttribute("hidden"); 6110 btn.classList.remove("invisible"); 6111 btn.style.visibility = null; 6112 }); 6113 } 6114 function createPager() { 6115 const newPager = document.createElement("nav"); 6116 newPager.setAttribute("data-pager", ""); 6117 newPager.setAttribute("role", "tablist"); 6118 newPager.classList.add(...pagerClasses.split(" ")); 6119 6120 slides.forEach((slide, index) => { 6121 const marker = document.createElement("button"); 6122 const slideId = slide.id || `${sliderId}-item-${index + 1}`; 6123 marker.setAttribute(markerIdName, slideId); 6124 marker.classList.add(...markerClasses.split(" ")); 6125 setupPagerMarker(marker, index); 6126 newPager.appendChild(marker); 6127 6128 if (slide.tagName.toLowerCase() !== "img" && slide.tagName.toLowerCase() !== "picture") { 6129 slide.removeAttribute("aria-roledescription"); 6130 slide.setAttribute("role", "tabpanel"); 6131 } 6132 }); 6133 6134 if (pager) { 6135 pager.setAttribute("role", "tablist"); 6136 pager.replaceChildren(...newPager.children); 6137 } else { 6138 track.after(newPager); 6139 pager = el.querySelector("[data-pager]"); 6140 } 6141 } 6142 function setupPager() { 6143 if (!pager) return; 6144 pager.setAttribute("role", "tablist"); 6145 const items = Array.from(pager.querySelectorAll("a, button"));
6146 items.forEach((marker, index) => setupPagerMarker(marker, index)); 6147 } 6148 function setupPagerMarker(marker, index) { 6149 const markerId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(markerIdName); 6150 const slideId = markerId || `${sliderId}-item-${index + 1}`; 6151 if (!markerId) { 6152 marker.setAttribute(markerIdName, slideId); 6153 } 6154 marker.setAttribute("role", "tab"); 6155 marker.setAttribute("aria-controls", slideId); 6156 marker.setAttribute("aria-posinset", index + 1); 6157 marker.setAttribute("aria-setsize", slides.length); 6158 marker.setAttribute("tabindex", "-1"); 6159 if (!marker.hasAttribute("aria-label")) { 6160 marker.setAttribute("aria-label", `Slide ${index + 1}`); 6161 } 6162 } 6163 function setupObservers() { 6164 if (inViewObserver) { 6165 inViewObserver.disconnect(); 6166 } 6167 inViewObserver = new IntersectionObserver( 6168 handleInView.bind(track), 6169 { root: track, threshold: 0.8 } 6170 ); 6171 slides.forEach((slide) => inViewObserver.observe(slide)); 6172 } 6173 function setupMutationObserver() { 6174 mutationObserver = new MutationObserver(refreshSlides.bind(track)); 6175 mutationObserver.observe(track, { 6176 childList: true, 6177 subtree: false 6178 }); 6179 } 6180 function setupResizeObserver() { 6181 resizeObserver = new ResizeObserver(groupPagerMarkers.bind(el)); 6182 resizeObserver.observe(el); 6183 } 6184 function goToSlideDir(dir = "next") { 6185 const { firstInViewSlide, lastInViewSlide } = getInViewItems(); 6186 const isPrev = dir === "prev"; 6187 let targetSlide = isPrev ? firstInViewSlide?.previousElementSibling : lastInViewSlide?.nextElementSibling; 6188 if (!targetSlide) return; 6189 if (targetSlide.tagName.toLowerCase() === "template") { 6190 targetSlide = isPrev ? targetSlide?.previousElementSibling : targetSlide?.nextElementSibling; 6191 } 6192 targetSlide.scrollIntoView({ 6193 block: "nearest", 6194 inline: isPrev ? "end" : "start", 6195 behavior: "smooth" 6196 }); 6197 } 6198 function pagerToSlide(event) { 6199 if (!event.target.closest("[data-pager]")) return; 6200 const marker = event.target.closest("a, button"); 6201 if (!marker) return; 6202 event.preventDefault(); 6203 const slideId = marker.getAttribute("href")?.slice(1) || marker.getAttribute(markerIdName); 6204 const targetSlide = track.querySelector(`#${slideId}`); 6205 targetSlide?.scrollIntoView({ 6206 block: "nearest", 6207 inline: "start", 6208 behavior: "smooth" 6209 }); 6210 } 6211 setupSlides(); 6212 setupNav(); 6213 if (useAutoPager) { 6214 createPager(); 6215 } else { 6216 setupPager(); 6217 } 6218 setupObservers(); 6219 setupMutationObserver(); 6220 setupResizeObserver(); 6221 function eventHandler(event) { 6222 const target = event.target.closest( 6223 "[data-next], [data-prev], [data-pager]" 6224 ); 6225 if (!target) return; 6226 if (event.type === "click") { 6227 if (target.hasAttribute("data-next")) { 6228 goToSlideDir("next"); 6229 } else if (target.hasAttribute("data-prev")) { 6230 goToSlideDir("prev"); 6231 } else if (target.closest("[data-pager]")) { 6232 pagerToSlide(event); 6233 } 6234 } 6235 if (event.type === "keydown" && target.closest("[data-pager]")) { 6236 if (event.key === "ArrowRight") { 6237 goToSlideDir("next"); 6238 } else if (event.key === "ArrowLeft") { 6239 goToSlideDir("prev"); 6240 } 6241 } 6242 } 6243 el.addEventListener("click", eventHandler); 6244 el.addEventListener("keydown", eventHandler); 6245 cleanup(() => { 6246 inViewObserver?.disconnect(); 6247 mutationObserver?.disconnect(); 6248 resizeObserver?.disconnect(); 6249 el.removeEventListener("click", eventHandler); 6250 el.removeEventListener("keydown", eventHandler); 6251 }); 6252 }); 6253 } 6254 6255 document.addEventListener("alpine:init", () => { 6256 window.Alpine.plugin(alpineSnapSlider); 6257 }); 6258 })(); 6259</script>
vendor: 1 bytes, line 6259
6259
6260<script> 6261 (() => { 6262 // src/dialog.js 6263 function dialog_default(Alpine) { 6264 Alpine.directive("htmldialog", fylgjaAlpineDialog); 6265 function fylgjaAlpineDialog(el, { expression, modifiers }, { evaluateLater, cleanup }) { 6266 const evaluate = expression.length ? evaluateLater(expression) : () => {}; 6267 const canEvaluate = expression.length > 0; 6268 const lockPageScroll = modifiers.includes("noscroll"); 6269 const closeBy = el.getAttribute("closeby") || modifierValue(modifiers, "closeby", "closerequest"); 6270 el.style.display = null; 6271 el.style.length === 0 && el.removeAttribute("style"); 6272 if (el._x_isShown) { 6273 open(); 6274 } 6275 const closeBySupported = (() => { 6276 return "closedBy" in HTMLDialogElement.prototype; 6277 })(); 6278 function scrollLock(use = true) { 6279 document.body.style.overflow = use ? "hidden" : ""; 6280 } 6281 function dialogSubmit(event) { 6282 if (event.target.getAttribute("method") === "dialog" || event.submitter?.getAttribute("formmethod") === "dialog") { 6283 event.preventDefault(); 6284 evaluate(); 6285 } 6286 } 6287 function escapeDialog(event) { 6288 if (event.key !== "Escape") return; 6289 event.preventDefault(); 6290 if (closeBy === "none") return; 6291 evaluate(); 6292 } 6293 function handleCloseByEvent(event) { 6294 if (event.target !== el) return; 6295 const rect = el.getBoundingClientRect(); 6296 const isInDialog = rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width; 6297 if (!isInDialog) { 6298 if (closeBy === "any") { 6299 if (closeBySupported) { 6300 event.preventDefault(); 6301 } 6302 evaluate(); 6303 } 6304 } 6305 } 6306 function handleCloseEvent() { 6307 evaluate(); 6308 } 6309 function open() { 6310 if (el.hasAttribute("open")) return; 6311 el.showModal(); 6312 scrollLock(lockPageScroll); 6313 } 6314 function close() { 6315 if (!el.hasAttribute("open")) return; 6316 el.close(); 6317 scrollLock(false); 6318 } 6319 el._x_doShow = () => open(); 6320 el._x_doHide = () => close(); 6321 el.addEventListener("keydown", escapeDialog); 6322 el.addEventListener("submit", dialogSubmit); 6323 el.addEventListener("click", handleCloseByEvent); 6324 el.addEventListener("cancel", handleCloseEvent); 6325 cleanup(() => { 6326 el.removeEventListener("keydown", escapeDialog); 6327 el.removeEventListener("submit", dialogSubmit); 6328 el.removeEventListener("click", handleCloseByEvent); 6329 el.removeEventListener("cancel", handleCloseEvent); 6330 scrollLock(false); 6331 }); 6332 } 6333 } 6334 function modifierValue(modifiers, key, fallback) { 6335 if (modifiers.indexOf(key) === -1) return fallback; 6336 const rawValue = modifiers[modifiers.indexOf(key) + 1]; 6337 if (!rawValue) return fallback; 6338 if (key === "closeby") { 6339 const allowedValues = ["auto", "none", "closerequest", "any"]; 6340 const options = allowedValues.join(", "); 6341 if (!allowedValues.includes(rawValue)) { 6342 console.warn( 6343 `"${rawValue}" is not one of the allowed values for closeby: ${options}` 6344 ); 6345 return fallback; 6346 } 6347 } 6348 return rawValue; 6349 } 6350 6351 // src/cdn.js 6352 document.addEventListener("alpine:init", () => { 6353 window.Alpine.plugin(dialog_default); 6354 }); 6355 })(); 6356 //# sourceURL=alpine-htmldialog.js 6357</script>
vendor: 1 bytes, line 6357
6357
6358<script> 6359 (() => { 6360 function src_default(Alpine) { 6361 Alpine.directive("intersect", Alpine.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { 6362 let evaluate = evaluateLater(expression); 6363 let options = { 6364 rootMargin: getRootMargin(modifiers), 6365 threshold: getThreshold(modifiers) 6366 }; 6367 let observer = new IntersectionObserver((entries) => { 6368 entries.forEach((entry) => { 6369 if (entry.isIntersecting === (value === "leave")) 6370 return; 6371 evaluate(); 6372 modifiers.includes("once") && observer.disconnect(); 6373 }); 6374 }, options); 6375 observer.observe(el); 6376 cleanup(() => { 6377 observer.disconnect(); 6378 }); 6379 })); 6380 } 6381 function getThreshold(modifiers) { 6382 if (modifiers.includes("full")) 6383 return 0.99; 6384 if (modifiers.includes("half")) 6385 return 0.5; 6386 if (!modifiers.includes("threshold")) 6387 return 0; 6388 let threshold = modifiers[modifiers.indexOf("threshold") + 1]; 6389 if (threshold === "100") 6390 return 1; 6391 if (threshold === "0") 6392 return 0; 6393 return Number(`.${threshold}`); 6394 } 6395 function getLengthValue(rawValue) { 6396 let match = rawValue.match(/^(-?[0-9]+)(px|%)?$/); 6397 return match ? match[1] + (match[2] || "px") : void 0; 6398 } 6399 function getRootMargin(modifiers) { 6400 const key = "margin"; 6401 const fallback = "0px 0px 0px 0px"; 6402 const index = modifiers.indexOf(key); 6403 if (index === -1) 6404 return fallback; 6405 let values = []; 6406 for (let i = 1; i < 5; i++) { 6407 values.push(getLengthValue(modifiers[index + i] || "")); 6408 } 6409 values = values.filter((v) => v !== void 0); 6410 return values.length ? values.join(" ").trim() : fallback; 6411 } 6412 6413 document.addEventListener("alpine:init", () => { 6414 window.Alpine.plugin(src_default); 6415 }); 6416 })(); 6417 //# sourceURL=alpine-intersect.js 6418</script>
vendor: 1 bytes, line 6418
6418
6419<script> 6420 for (const [selector, deferUntil] of Object.entries({".product-slider section[x-data]:not([x-data] [x-data])":"intersect",".product-info [x-data]:not([x-data] [x-data])":"intersect","#filters-content [x-data]:not([x-data] [x-data])":"intersect","#review_form":"intersect","section[x-data^=initRecentlyViewedProductsComponent]":"intersect","div[x-data^=initBundleOptions]":"intersect","#product_addtocart_form [x-data]:not([x-data] [x-data])":"intersect","#notice-cookie-block":"idle"})) { 6421 document.querySelectorAll(selector).forEach(el => el.setAttribute('x-defer', `${deferUntil}`)); 6422 } 6423 //# sourceURL=alpine-defer-rules.js 6424</script>
vendor: 1 bytes, line 6424
6424
6425<script> 6426 (() => { 6427 const hasAlpine = new Promise(resolve => { 6428 window.addEventListener('alpine:initialized', resolve, {once: true, passive: true}); 6429 }); 6430 6431 const hasInteract = new Promise(resolve => { 6432 (events => { 6433 const onInteract = () => { 6434 resolve(); 6435 events.forEach(type => window.removeEventListener(type, onInteract)); 6436 } 6437 events.forEach(type => window.addEventListener(type, onInteract, {once: true, passive: true})) 6438 })(['touchstart', 'mouseover', 'wheel', 'scroll', 'keydown']) 6439 }); 6440 6441 const onIntersect = (el) => { 6442 return new Promise(resolve => { 6443 const observer = new IntersectionObserver(entries => { 6444 for (const entry of entries) { 6445 if (entry.isIntersecting) { 6446 observer.disconnect() 6447 resolve(); 6448 } 6449 } 6450 }, {}); 6451 observer.observe(el); 6452 }); 6453 } 6454 6455 function runComponent(el) { 6456 hasAlpine.then(() => { 6457 el.removeAttribute('x-ignore'); 6458 queueMicrotask(() => Alpine.initTree(el)); 6459 }); 6460 } 6461 6462 function initDeferredComponents() { 6463 document.querySelectorAll('[x-data][x-defer]').forEach(el => { 6464 el.setAttribute('x-ignore', ''); 6465 const deferUntil = (el.getAttribute('x-defer') || '').trim(); 6466 switch (deferUntil) { 6467 case 'interact': 6468 hasInteract.then(() => runComponent(el)); 6469 break; 6470 case 'intersect': 6471 onIntersect(el).then(() => runComponent(el)) 6472 break; 6473 case 'idle': 6474 window.requestIdleCallback 6475 ? window.requestIdleCallback(() => runComponent(el), {timeout: 4000}) 6476 : setTimeout(() => runComponent(el), 4000); 6477 break; 6478 case 'eager': 6479 runComponent(el); 6480 break; 6481 default: 6482 if (deferUntil.startsWith('event:') && deferUntil.length > 6) { 6483 window.addEventListener(deferUntil.substring(6), () => runComponent(el), {once: true, passive: true}); 6484 } 6485 } 6486 }); 6487 } 6488 6489 window.addEventListener('alpine:init', initDeferredComponents, {once: true, passive: true}); 6490 })(); 6491 //# sourceURL=alpine-defer.js 6492</script>
6492 6493
6494<script type="module" 6495 src="https://www.healthcare4all.co.uk/static/version1788769602/frontend/HC4ALL/Hyva/en_GB/Hyva_Theme/js/alpine3.min.js" 6496 defer 6497 crossorigin 6498></script>
vendor: 1 bytes, line 6498
6498
6499<script> 6500 function dispatchMessages(messages, hideAfter) { 6501 const messagesEvent = new CustomEvent("messages-loaded", { 6502 detail: { 6503 messages: messages, 6504 hideAfter: hideAfter 6505 } 6506 }); 6507 window.dispatchEvent(messagesEvent); 6508 } 6509 6510 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) { 6511 console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script"); 6512 } 6513 6514 (function( hyva, undefined ) { 6515 6516 hyva.initFormKey = () => { 6517 const inputSelector = 'input[name="form_key"]', 6518 formKey = hyva.getFormKey(); 6519 6520 Array.from(document.querySelectorAll(inputSelector)).map(function (input) { 6521 input.value = formKey 6522 }); 6523 } 6524 6525 hyva.initMessages = () => { 6526 try { 6527 const messages = hyva.getCookie('mage-messages'); 6528 window.mageMessages = messages ? JSON.parse(decodeURIComponent(messages).replace(/\+/g, ' ')) : []; 6529 6530 dispatchMessages(window.mageMessages); 6531 6532 // empty `mage-messages` cookie 6533 const skipSetDomain = true; 6534 hyva.setCookie('mage-messages','', -1, skipSetDomain); 6535 6536 } catch (error) { 6537 console.warn('Error parsing Cookie Messages:', error); 6538 } 6539 } 6540 6541 window.addEventListener('DOMContentLoaded', hyva.initFormKey); 6542 hyva.alpineInitialized(hyva.initMessages) 6543 6544 }( window.hyva = window.hyva || {} )); 6545 //# sourceURL=hyva-cookies.js 6546</script>
vendor: 1 bytes, line 6546
6546
6547<script> 6548 { 6549 const private_content_key = 'mage-cache-storage'; 6550 const private_content_expire_key = 'mage-cache-timeout'; 6551 const private_content_version_key = 'private_content_version'; 6552 const section_data_ids_key = 'section_data_ids'; 6553 const mage_cache_session_id_key = 'mage-cache-sessid'; 6554 const last_visited_store_key = 'last_visited_store'; 6555 6556 const ttl = 3600; 6557 6558 if (typeof hyva === 'undefined' || (!hyva.getBrowserStorage || !hyva.getCookie || !hyva.setCookie)) { 6559 console.warn("Hyvä helpers are not loaded yet. Make sure they are included before this script"); 6560 } 6561 6562 function loadSectionData () { 6563 const browserStorage = hyva.getBrowserStorage(); 6564 if (!browserStorage) { 6565 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 6566 [{ 6567 type: "warning", 6568 text: "Please enable LocalStorage in your browser." 6569 }] 6570 ); 6571 return; 6572 } 6573 try { 6574 let isInvalid = false; 6575 6576 if (hyva.getCookie(last_visited_store_key) !== CURRENT_STORE_CODE) { 6577 isInvalid = true; 6578 } 6579 hyva.setCookie(last_visited_store_key, CURRENT_STORE_CODE, false, false); 6580 6581 if (!hyva.getCookie(mage_cache_session_id_key)) { 6582 isInvalid = true; 6583 browserStorage.removeItem(private_content_key); 6584 const skipSetDomain = true; 6585 const days = false; 6586 hyva.setCookie(mage_cache_session_id_key, true, days, skipSetDomain) 6587 } 6588 6589 const cookieVersion = hyva.getCookie(private_content_version_key); 6590 const storageVersion = browserStorage.getItem(private_content_version_key); 6591 6592 if (cookieVersion && !storageVersion || cookieVersion !== storageVersion) { 6593 isInvalid = true; 6594 } 6595 6596 const privateContentExpires = browserStorage.getItem(private_content_expire_key); 6597 if (privateContentExpires && new Date(privateContentExpires) < new Date()) { 6598 browserStorage.removeItem(private_content_key); 6599 } 6600 6601 if (isInvalid && cookieVersion) { 6602 fetchPrivateContent([]); 6603 } else if (cookieVersion && storageVersion && cookieVersion === storageVersion) { 6604 const privateContent = JSON.parse(browserStorage.getItem(private_content_key)); 6605 if ( 6606 privateContent && 6607 privateContentExpires && 6608 privateContent.cart && 6609 privateContent.customer 6610 ) { 6611 dispatchPrivateContent(privateContent); 6612 } else { 6613 fetchPrivateContent([]); 6614 } 6615 } else { 6616 if (document.getElementById('default-section-data')) { 6617 const privateContent = JSON.parse(document.getElementById('default-section-data').innerText.trim()); 6618 dispatchPrivateContent(privateContent); 6619 } else { 6620 dispatchPrivateContent({}); 6621 } 6622 } 6623 6624 } catch (error) { 6625 console.warn('Error retrieving Private Content:', error); 6626 } 6627 } 6628 6629 hyva.alpineInitialized(loadSectionData) 6630 window.addEventListener('reload-customer-section-data', loadSectionData); 6631 6632 window.processSectionDataBeforeDispatch = window.processSectionDataBeforeDispatch || (data => data); 6633 6634 function dispatchPrivateContent(data) { 6635 6636 const privateContentEvent = new CustomEvent("private-content-loaded", { 6637 detail: { 6638 data: window.processSectionDataBeforeDispatch(data) 6639 } 6640 }); 6641 window.dispatchEvent(privateContentEvent); 6642 } 6643 6644 function fetchPrivateContent(sections) { 6645 fetch(`${BASE_URL}customer/section/load/?sections=${encodeURIComponent(sections.join(','))}`, { 6646 method: 'GET', 6647 headers: { 6648 'Content-Type': 'application/json', 6649 'X-Requested-With': 'XMLHttpRequest' 6650 } 6651 }) 6652 .then(response => response.ok && response.json()) 6653 .then( 6654 data => { 6655 if (data) { 6656 try { 6657 const browserStorage = hyva.getBrowserStorage(); 6658 6659 // merge new data preserving non-invalidated sections 6660 const oldSectionData = JSON.parse(browserStorage.getItem(private_content_key) || '{}') || {}; 6661 6662 if ((! data.cart || ! data.cart.cartId) && oldSectionData['checkout-data']) { 6663 delete oldSectionData['checkout-data']; 6664 } 6665 const newSectionData = Object.assign(oldSectionData, data); 6666 6667 dispatchPrivateContent(newSectionData); 6668 6669 // don't persist messages, they've been dispatched already 6670 if (newSectionData.messages && newSectionData.messages.messages ) { 6671 newSectionData.messages.messages = []; 6672 } 6673 6674 browserStorage.setItem(private_content_key, JSON.stringify(newSectionData)); 6675 6676 const expiresAt = new Date(Date.now() + (ttl * 1000)).toISOString(); 6677 browserStorage.setItem(private_content_expire_key, expiresAt); 6678 6679 const newCookieVersion = hyva.getCookie(private_content_version_key); 6680 browserStorage.setItem(private_content_version_key, newCookieVersion); 6681 6682 // We don't need the section_data_ids in Hyvä, but we store them for compatibility 6683 // with Luma Fallback. Otherwise, not all sections are loaded in Luma Checkout 6684 hyva.setCookie( 6685 section_data_ids_key, 6686 JSON.stringify( 6687 Object.keys(data).reduce((sectionDataIds, sectionKey) => { 6688 sectionDataIds[sectionKey] = data[sectionKey]['data_id']; 6689 return sectionDataIds; 6690 }, {}) 6691 ), 6692 false, 6693 true 6694 ); 6695 } catch (error) { 6696 console.warn("Couldn't store privateContent", error); 6697 } 6698 } 6699 } 6700 ); 6701 } 6702 } 6703 //# sourceURL=hyva-private-content.js 6704</script>
vendor: 1 bytes, line 6704
6704
6705<script> 6706 (() => { 6707 document.addEventListener('submit', event => event.target.action = event.target.action.replace('%25uenc%25', hyva.getUenc())); 6708 })() 6709</script>
vendor: 1 bytes, line 6709
6709
6710<script> 6711 (events => { 6712 const dispatchUserInteractionEvent = () => { 6713 events.forEach(type => window.removeEventListener(type, dispatchUserInteractionEvent)) 6714 window.dispatchEvent(new Event('init-external-scripts')) 6715 }; 6716 events.forEach(type => window.addEventListener(type, dispatchUserInteractionEvent, {once: true, passive: true})) 6717 })(['touchstart', 'mousemove', 'wheel', 'scroll', 'keydown']); 6718 //# sourceURL=hyva-init-external-scripts.js 6719</script>
vendor: 1 bytes, line 6719
6719
6720<script> 6721 function initProductItemImage() { 6722 return { 6723 updateImage() { 6724 const image = this.$event.detail.medium; 6725 if (!image) return; 6726 this.$el.src = image; 6727 } 6728 } 6729 } 6730 window.addEventListener('alpine:init', () => { 6731 Alpine.data('initProductItemImage', initProductItemImage); 6732 }, { once: true }); 6733</script>
vendor: 1 bytes, line 6733
6733
6734<script> 6735 function initCompareOnProductList() { 6736 return { 6737 addToCompare(productId) { 6738 const formKey = hyva.getFormKey(); 6739 const postUrl = BASE_URL + 'catalog/product_compare/add/'; 6740 6741 fetch(postUrl, { 6742 "headers": { 6743 "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 6744 }, 6745 "body": "form_key=" + formKey + "&product=" + productId + "&uenc=" + hyva.getUenc(), 6746 "method": "POST", 6747 "mode": "cors", 6748 "credentials": "include" 6749 }).then(function (response) { 6750 if (response.redirected) { 6751 window.location.href = response.url; 6752 } 6753 }).catch(function (error) { 6754 typeof window.dispatchMessages !== "undefined" && window.dispatchMessages( 6755 [{ 6756 type: "error", 6757 text: error 6758 }], 5000 6759 ); 6760 }); 6761 } 6762 }; 6763 } 6764</script>
vendor: 1 bytes, line 6764
6764
6765<script> 6766 function initPriceBox() 6767 { 6768 return { 6769 updatePrice(priceData) { 6770 const regularPriceLabel = this.$root.querySelector('.normal-price .price-label'); 6771 const regularPriceElement = this.$root.querySelector('.normal-price [data-price-type=finalPrice].price-wrapper .price'); 6772 const basePriceElement = this.$root.querySelector('.normal-price [data-price-type=basePrice].price-wrapper .price'); 6773 if (priceData.finalPrice.amount < priceData.oldPrice.amount) { 6774 regularPriceLabel && regularPriceLabel.classList.add('hidden'); 6775 } else { 6776 regularPriceLabel && regularPriceLabel.classList.remove('hidden'); 6777 } 6778 regularPriceElement && (regularPriceElement.innerText = hyva.formatPrice(priceData.finalPrice.amount)); 6779 basePriceElement && (basePriceElement.innerText = hyva.formatPrice(priceData.basePrice.amount)); 6780 } 6781 } 6782 } 6783</script>
vendor: 1 bytes, line 6783
6783
6784<script> 6785 function initConfigurableOptions(productId, optionConfig) { 6786 6787 function findPathParam(key) { 6788 const baseUrl = (BASE_URL.substring(0, 2) === '//' ? 'http:' : '') + BASE_URL; 6789 const baseUrlParts = (new URL(baseUrl)).pathname.replace(/\/$/, '').split('/'); 6790 const pathParts = window.location.pathname.split('/').slice(baseUrlParts.length + 3); 6791 for (let i = 0; i < pathParts.length; i += 2) { 6792 if (pathParts[i] === key && pathParts.length > i) { 6793 return pathParts[i + 1]; 6794 } 6795 } 6796 } 6797 6798 return { 6799 optionConfig, 6800 productId, 6801 itemId: (new URLSearchParams(window.location.search)).get('id') || findPathParam('id'), 6802 allowedAttributeOptions: [], 6803 selectedValues: [], 6804 init() { 6805 this.buildLookupMap(); 6806 this.findAllowedAttributeOptions(); 6807 this.$nextTick(() => { 6808 if (typeof this.optionConfig.defaultValues === 'object') { 6809 for (const [attributeId, value] of Object.entries(this.optionConfig.defaultValues)) { 6810 this.changeOption(attributeId, value + ''); 6811 } 6812 } 6813 this.preselectQuerystringItems(); 6814 this.preselectLocationHashItems(); 6815 }); 6816 }, 6817 productIndex: 0, 6818 productIndexForPrice: 0, 6819 productIndexesMap: null, 6820 productIndexesKeys: null, 6821 attributeCount: 0, 6822 optionIsActive(attributeId, optionId) { 6823 return !!this.getAllowedAttributeOptions(attributeId).find( 6824 option => option.id === optionId 6825 ) 6826 }, 6827 optionIsEnabled(attributeId, optionId) { 6828 for (const productId in this.optionConfig.index) { 6829 if (this.optionConfig.index[productId][attributeId] === optionId) { 6830 return true; 6831 } 6832 } 6833 return false; 6834 }, 6835 findSimpleIndex() { 6836 this.productIndex = this.calculateSimpleIndexForPartialSelection(this.selectedValues); 6837 this.productIndexForPrice = this.findCheapestProductForPartialSelection(this.selectedValues); 6838 }, 6839 calculateSimpleIndexForPartialSelection(selectedValues) { 6840 if (selectedValues.length === 0) return 0; 6841 return this.findProductIdsForPartialSelection(selectedValues)[0]; 6842 }, 6843 buildLookupMap() { 6844 this.productIndexesMap = new Map(); 6845 this.attributeCount = Object.keys(this.optionConfig.attributes).length; 6846 for (const id in this.optionConfig.index) { 6847 const options = this.optionConfig.index[id]; 6848 if (! this.productIndexesKeys) { 6849 this.productIndexesKeys = Object.keys(options).sort(); 6850 } 6851 const key = JSON.stringify(options, this.productIndexesKeys); 6852 this.productIndexesMap.set(key, id); 6853 } 6854 }, 6855 calculateSimpleIndexForFullSelection(selectedValues) { 6856 if (! this.isFullSelection(selectedValues)) return false; 6857 6858 const attrKeys = this.productIndexesKeys || []; 6859 const normalised = {}; 6860 for (let i = 0; i < attrKeys.length; i++) { 6861 normalised[attrKeys[i]] = selectedValues[attrKeys[i]]; 6862 } 6863 const queryKey = JSON.stringify(normalised, attrKeys); 6864 return this.productIndexesMap.get(queryKey); 6865 }, 6866 findAllowedAttributeOptions() { 6867 this.allowedAttributeOptions = this.calculateAllowedAttributeOptions(this.selectedValues); 6868 }, 6869 calculateAllowedAttributeOptions(selectedValues) { 6870 const allAttributes = this.optionConfig.attributes; 6871 const allAttributesSorted = Object.values(allAttributes).sort((a,b) => { 6872 return a.position - b.position 6873 }); 6874 6875 const newAllowedAttributeOptions = []; 6876 6877 allAttributesSorted.forEach(attribute => { 6878 const selectionWithoutAttr = Object.assign({}, this.removeAttrFromSelection(selectedValues, attribute.id)); 6879 const availableIndexes = this.calculateAvailableProductIndexes(selectionWithoutAttr); 6880 newAllowedAttributeOptions[attribute.id] = allAttributes[attribute.id].options.filter(option => { 6881 return !!option.products.find(product => { 6882 return availableIndexes.includes(product); 6883 }) 6884 }); 6885 }); 6886 return newAllowedAttributeOptions; 6887 }, 6888 calculateAvailableProductIndexes(selectedOptions) { 6889 if (Object.keys(selectedOptions).length === 0) { 6890 if (Object.values(this.optionConfig.salable || {}).length) { 6891 return [].concat.apply([], [].concat.apply([], Object.values(this.optionConfig.salable).map(Object.values))).filter((x, i, a) => a.indexOf(x) === i) 6892 } 6893 return Object.keys(this.optionConfig.index); 6894 } 6895 6896 const selectedIds = Object.keys(selectedOptions); 6897 if (Object.values(this.optionConfig.salable || {}).length) { 6898 const selectedOptionIndexes = selectedIds.map(attrId => { 6899 const optionValue = selectedOptions[attrId]; 6900 return this.optionConfig.salable[attrId] && this.optionConfig.salable[attrId][optionValue] || [] 6901 }) 6902 return selectedOptionIndexes.reduce((acc, optionIndexes) => { 6903 return acc.filter(index => optionIndexes.includes(index)); 6904 }); 6905 } else { 6906 const productIndexes = this.optionConfig.index; 6907 return Object.keys(productIndexes).filter(index => { 6908 for (const attrId of selectedIds) { 6909 if (productIndexes[index][attrId] !== `${selectedOptions[attrId]}`) return false 6910 } 6911 return true 6912 }); 6913 } 6914 }, 6915 findAttributeByOptionId(optionId) { 6916 for (const attributeId in this.optionConfig.attributes) { 6917 const attributeOptions = this.optionConfig.attributes[attributeId].options || []; 6918 if (attributeOptions.find(option => option.id === optionId)) { 6919 return attributeId; 6920 } 6921 } 6922 }, 6923 getAllowedAttributeOptions(attributeId) { 6924 return this.allowedAttributeOptions[attributeId] || [] 6925 }, 6926 getAllAttributeOptions(attributeId) { 6927 return ( 6928 this.optionConfig.attributes[attributeId] && 6929 this.optionConfig.attributes[attributeId].options 6930 ) || [] 6931 }, 6932 getProductIdsForOption(option) { 6933 const attributeId = this.findAttributeByOptionId(option.id); 6934 const allOptions = this.optionConfig.attributes[attributeId]; 6935 const opt = (allOptions && allOptions.options || []).find(o => o.id === option.id); 6936 return opt && opt.products 6937 ? opt.products 6938 : []; 6939 }, 6940 findProductIdsForPartialSelection(optionSelection) { 6941 const candidateProducts = Object.values(optionSelection).reduce((candidates, optionId) => { 6942 const newCandidates = this.getProductIdsForOption({id: optionId}); 6943 return candidates === null 6944 ? newCandidates 6945 : candidates.filter(productId => newCandidates.includes(productId)); 6946 }, null); 6947 return candidateProducts || []; 6948 },
6949 findCheapestProductForPartialSelection(optionSelection) { 6950 const candidateProducts = this.findProductIdsForPartialSelection(optionSelection); 6951 return candidateProducts.reduce((cheapest, simpleIdx) => { 6952 // in the first iteration we start with simpleIdx as the currently cheapest product 6953 if (! this.optionConfig.optionPrices[cheapest]) return simpleIdx; 6954 const knownCheapestPrice = this.optionConfig.optionPrices[cheapest].finalPrice.amount; 6955 return knownCheapestPrice > this.optionConfig.optionPrices[simpleIdx].finalPrice.amount 6956 ? simpleIdx 6957 : cheapest; 6958 }, 0) 6959 }, 6960 findProductIdToUseForOptionPrice(option) { 6961 // try to find a product for a complete selection 6962 const attributeId = this.findAttributeByOptionId(option.id); 6963 const optionSelection = Object.assign({}, this.selectedValues, {[attributeId]: option.id}); 6964 const matchingSimpleIndex = this.calculateSimpleIndexForFullSelection(optionSelection); 6965 // if there is no complete selection, use the cheapest product for the option 6966 return matchingSimpleIndex || this.findCheapestProductForPartialSelection(optionSelection); 6967 }, 6968 getAttributeOptionLabel(option) { 6969 const optionProduct = this.findProductIdToUseForOptionPrice(option); 6970 6971 if ((! optionProduct) || (optionProduct === this.productIndexForPrice)) { 6972 return option.label; 6973 } 6974 6975 const currentPrice = this.getOptionPriceAdjustmentBasePrice(); 6976 6977 if (this.optionConfig.optionPrices[optionProduct]) { 6978 const optionPrice = this.optionConfig.optionPrices[optionProduct].finalPrice.amount; 6979 if (optionPrice !== currentPrice){ 6980 return option.label + ' ' + hyva.formatPrice(optionPrice - currentPrice, true); 6981 } 6982 } 6983 return option.label; 6984 }, 6985 getOptionPriceAdjustmentBasePrice() { 6986 if (this.optionConfig.optionPrices[this.productIndexForPrice]) { 6987 return this.optionConfig.optionPrices[this.productIndexForPrice].finalPrice.amount 6988 } 6989 return this.optionConfig.prices.finalPrice.amount; // default price if no option selection 6990 }, 6991 clearOptionIfActive(optionId, value) { 6992 if (this.selectedValues[optionId] === value) { 6993 this.blurLabel() 6994 this.changeOption(optionId, '') 6995 } 6996 }, 6997 removeAttrFromSelection(selectedValues, attributeId) { 6998 attributeId = parseInt(attributeId); 6999 return selectedValues.reduce((newSelection, val, attr) => { 7000 if (attr !== attributeId) { 7001 newSelection[attr] = val; 7002 } 7003 return newSelection; 7004 }, []); 7005 }, 7006 changeOption(attributeId, value) { 7007 if (value === '') { 7008 this.selectedValues = this.removeAttrFromSelection(this.selectedValues, attributeId) 7009 } else if (value && this.getAllowedAttributeOptions(attributeId).find(option => option.id === value)) { 7010 this.selectedValues[attributeId] = value; 7011 } 7012 this.findSimpleIndex(); 7013 this.findAllowedAttributeOptions(); 7014 this.updatePrices(); 7015 this.updateGallery(); 7016 7017 const candidates = this.findProductIdsForPartialSelection(this.selectedValues); 7018 7019 window.dispatchEvent( 7020 new CustomEvent( 7021 'configurable-selection-changed', 7022 { 7023 detail: { 7024 productId: this.productId, 7025 optionId: attributeId, 7026 value: value, 7027 productIndex: this.productIndex, 7028 selectedValues: this.selectedValues, 7029 candidates: candidates, 7030 skuCandidates: Object.values(candidates).map(id =>
7030 this.optionConfig.sku?.[id] ?? null).filter(Boolean), 7031 } 7032 } 7033 ) 7034 ); 7035 }, 7036 calculateIsMinimalPrice() { 7037 return ! this.isFullSelection(this.selectedValues); 7038 }, 7039 isFullSelection(selectedValues) { 7040 return Object.keys(selectedValues).length === this.attributeCount; 7041 }, 7042 updatePrices() { 7043 const value = this.optionConfig.optionPrices[this.productIndexForPrice] || this.optionConfig.prices; 7044 window.dispatchEvent( 7045 new CustomEvent( 7046 "update-prices-" + this.productId, 7047 { 7048 detail: Object.assign( 7049 value, 7050 { isMinimalPrice: this.calculateIsMinimalPrice() } 7051 ) 7052 } 7053 ) 7054 ); 7055 }, 7056 updateGallery () { 7057 if (this.productIndex) { 7058 const images = this.optionConfig.images[this.productIndex]; 7059 images && window.dispatchEvent(new CustomEvent( 7060 "update-gallery", 7061 { detail: this.sortImagesByPosition(images) } 7062 )); 7063 } else { 7064 window.dispatchEvent(new Event("reset-gallery")); 7065 } 7066 }, 7067 sortImagesByPosition(images) { 7068 return images.sort((x, y) => { 7069 return x.position === y.position ? 0 : (parseInt(x.position) > parseInt(y.position) ? 1 : -1) 7070 }); 7071 }, 7072 onGetCartData(data) { 7073 }, 7074 preselectCartItems(data) { 7075 // pre-select options based on cart data for current (quote) itemId 7076 const cart = data && data.cart; 7077 if (cart && cart.items) { 7078 const cartItem = cart.items.find((item) => { 7079 return ( 7080 item.item_id === this.itemId 7081 && item.product_id === this.productId 7082 ) 7083 }); 7084 if (cartItem && cartItem.options && cartItem.options.length) { 7085 cartItem.options.map(option => { 7086 this.changeOption(option.option_id, option.option_value); 7087 }) 7088 } 7089 } 7090 }, 7091 preselectQuerystringItems() { 7092 // pre-select option like ?size=167 7093 const urlQueryParams = new URLSearchParams(window.location.search.replace('?','')); 7094 this.preselectItemsBasedOnLocation(attribute => urlQueryParams.get(attribute.code)); 7095 }, 7096 preselectLocationHashItems() { 7097 // pre-select option like #144=167 7098 const urlHashParams = new URLSearchParams(window.location.hash.replace('#','')); 7099 this.preselectItemsBasedOnLocation(attribute => urlHashParams.get(attribute.id)); 7100 }, 7101 preselectItemsBasedOnLocation(getLocationValue) { 7102 Object.values(this.optionConfig.attributes).map(attribute => { 7103 const v = getLocationValue(attribute); 7104 v && this.changeOption(attribute.id, v) 7105 }); 7106 } 7107 } 7108 } 7109</script>
vendor: 1 bytes, line 7109
7109
7110<script> 7111 function initSwatchOptions(swatchConfig) { 7112 return { 7113 swatchConfig, 7114 getAttributeSwatchData(attributeId) { 7115 const swatchConfig = Object.assign({}, this.swatchConfig[attributeId]); 7116 swatchConfig['details'] = JSON.parse(swatchConfig['additional_data']); 7117 7118 return swatchConfig; 7119 }, 7120 mapSwatchTypeNumberToTypeCode(typeNumber) { 7121 switch ("" + typeNumber) { 7122 case "1": 7123 return "color" 7124 case "2": 7125 return "image" 7126 case "3": 7127 return "empty" 7128 case "0": 7129 default: 7130 return "text" 7131 } 7132 }, 7133 getTypeOfFirstOption(attributeId) { 7134 for (const optionId in this.swatchConfig[attributeId]) { 7135 const option = this.swatchConfig[attributeId][optionId]; 7136 if (typeof option.type !== 'undefined') { 7137 return this.mapSwatchTypeNumberToTypeCode(option.type); 7138 } 7139 } 7140 }, 7141 getVisualSwatchType(attributeId, targetOptionId) { 7142 // If a type configuration is present for the given option id, use it 7143 const config = this.swatchConfig[attributeId]; 7144 if (config[targetOptionId] && typeof config[targetOptionId].type !== 'undefined') { 7145 return this.mapSwatchTypeNumberToTypeCode(config[targetOptionId].type); 7146 } 7147 7148 // Otherwise - if no config is present for the target option - use the type of the first option 7149 // with a type property from the attribute, thus assuming its the same type as the target option. 7150 // (This edge case condition can occur on single swatch products if some options are not salable) 7151 return this.getTypeOfFirstOption(attributeId); 7152 }, 7153 getSwatchType(attributeId, optionId) { 7154 // Deserialize the attribute details the first time they are used 7155 if (this.swatchConfig[attributeId] && ! this.swatchConfig[attributeId].details) { 7156 this.swatchConfig[attributeId] = this.getAttributeSwatchData(attributeId); 7157 } 7158 const type = this.swatchConfig[attributeId] && 7159 this.swatchConfig[attributeId].details && 7160 this.swatchConfig[attributeId].details.swatch_input_type || 7161 "empty"; 7162 return type === 'visual' ? this.getVisualSwatchType(attributeId, optionId) : type; 7163 }, 7164 isTextSwatch(attributeId, optionId) { 7165 return this.getSwatchType(attributeId, optionId) === 'text'; 7166 }, 7167 isVisualSwatch(attributeId, optionId) { 7168 const type = this.getSwatchType(attributeId, optionId); 7169 7170 return ['image', 'color'].includes(type); 7171 }, 7172 getSwatchBackgroundStyle(attributeId, optionId) { 7173 const config = this.getSwatchConfig(attributeId, optionId); 7174 const type = this.getSwatchType(attributeId, optionId); 7175 7176 if (type === "color") { 7177 return 'background-color:' + config.value; 7178 } else if (type === "image") { 7179 return "background: #fff url('" + config.value + "') no-repeat center"; 7180 } else { 7181 return ''; 7182 } 7183 }, 7184 getSwatchText(attributeId, optionId) { 7185 const config = this.getSwatchConfig(attributeId, optionId); 7186 return config.label || config.value || this.getOptionLabelFromOptionConfig(attributeId, optionId); 7187 }, 7188 getOptionLabelFromOptionConfig(attributeId, optionId) { 7189 // Fallback if no value is present in swatchConfig data 7190 // Reference issue https://gitlab.hyva.io/hyva-themes/magento2-default-theme/-/issues/190 7191 const option = this.getAllAttributeOptions(attributeId).filter(option => option.id === optionId); 7192 return option && option[0] && option[0].label ||''; 7193 }, 7194 getSwatchConfig(attributeId, optionId) { 7195 return this.swatchConfig[attributeId] && this.swatchConfig[attributeId][optionId] 7196 ? this.swatchConfig[attributeId][optionId] 7197 : false;
7198 }, 7199 activeTooltipItem: false, 7200 tooltipPositionElement: false, 7201 isTooltipVisible() { 7202 return this.activeTooltipItem && 7203 this.getSwatchConfig( 7204 this.activeTooltipItem.attribute, 7205 this.activeTooltipItem.item 7206 ); 7207 }, 7208 isFirstItemCol() { 7209 return this.activeTooltipItem.index === 0; 7210 }, 7211 getTooltipImageStyle(attributeId, optionId) { 7212 const config = this.getSwatchConfig(attributeId, optionId); 7213 const type = this.getSwatchType(attributeId, optionId); 7214 7215 if (type === "color") { 7216 return 'background-color:' + config.value + '; width: 110px; height: 90px;'; 7217 } else if (type === "image") { 7218 return "background: #ffffff url('" + config.thumb + 7219 "') center center no-repeat; width: 110px; height: 90px;"; 7220 } else { 7221 return 'display:none'; 7222 } 7223 }, 7224 getTooltipPosition() { 7225 return this.tooltipPositionElement ? 7226 `top: ${this.tooltipPositionElement.offsetTop}px;` + 7227 `left: ${ 7228 this.tooltipPositionElement.offsetLeft - ( 7229 this.tooltipPositionElement.closest('.snap') && 7230 this.tooltipPositionElement.closest('.snap').scrollLeft || 7231 0 7232 ) 7233 }px;` : '' 7234 }, 7235 getTooltipLabel() { 7236 return this.getSwatchConfig(this.activeTooltipItem.attribute, this.activeTooltipItem.item).label 7237 }, 7238 focusedLabel: false, 7239 focusLabel(optionId) { 7240 this.focusedLabel = optionId; 7241 }, 7242 blurLabel() { 7243 this.focusedLabel = false; 7244 } 7245 } 7246 } 7247</script>
vendor: 1 bytes, line 7247
7247
7248<script> 7249 'use strict'; 7250 7251 const grecaptchaV2LoadCallbacks = []; 7252 7253 function executeRecaptchaLoadCallbacks () { 7254 while (window.grecaptcha && grecaptchaV2LoadCallbacks.length > 0) { 7255 const callback = grecaptchaV2LoadCallbacks.pop(); 7256 typeof callback === 'string' ? window[callback]() : callback(); 7257 } 7258 } 7259 7260 (function() { 7261 const loadRecaptchaScript = (event) => { 7262 7263 if (window.grecaptcha || !event.target.form) { 7264 return; 7265 } 7266 7267 const url = 'https://www.google.com/recaptcha/api.js?onload=executeRecaptchaLoadCallbacks'; 7268 const siteKey = '6Lc7_50sAAAAAG_oXG0fwI0gVEkpJtqxB2S2A2ce'; 7269 const script = document.createElement('script'); 7270 script.type = 'text/javascript'; 7271 script.src = siteKey ? `${url}&render=${siteKey}` : `${url}&render=explicit`; 7272 script.async = true; 7273 document.head.appendChild(script); 7274 7275 script.addEventListener('load', () => { 7276 Array.from(document.querySelectorAll('button[data-recaptcha-btn]:disabled')).forEach(btn => btn.removeAttribute('disabled')); 7277 }); 7278 } 7279 7280 window.forceLoadRecaptchaScript = (form) => { 7281 loadRecaptchaScript({target: {form: form || 'dummy'}}); 7282 executeRecaptchaLoadCallbacks(); 7283 }; 7284 7285 document.body.addEventListener('input', loadRecaptchaScript, { once: true }); 7286 document.body.addEventListener('focus', loadRecaptchaScript, { once: true }); 7287 7288 }()); 7289 7290</script>
7290 7291
7292<script> 7293 function initSmileAttribute(options) { 7294 "use strict"; 7295 7296 return { 7297 options : options, 7298 searchLabel : 'Search (%s)', 7299 showMoreLabel : 'Show more', 7300 showLessLabel : 'Show less', 7301 noSearchResultLabel : 'No value matching the search <b>%s</b>.', 7302 expanded: false, 7303 items: [], 7304 lastSelectIndex: 0, 7305 maxSize: 0, 7306 displaySearch: false, 7307 displayedItems: [], 7308 fulltextSearch: null, 7309 searchPlaceholder: '', 7310 result: 0, 7311 7312 /** 7313 * Component initialization 7314 */ 7315 initialize: function () { 7316 7317 this.items = this.options.items.map(this.addItemId.bind(this)); 7318 7319 var lastSelectedIndex = Math.max.apply(null, (this.items.map( 7320 function (v, k) {return v['is_selected'] ? k : 0;})) 7321 ); 7322 this.maxSize = Math.max(this.options.maxSize, lastSelectedIndex + 1); 7323 7324 this.$nextTick(() => { 7325 this.initSearchPlaceholder(); 7326 this.onShowLess(); 7327 this.displaySearch = this.displayShowMore(); 7328 this.displayedItems = this.getDisplayedItems(); 7329 }); 7330 }, 7331 7332 /** 7333 * Init the place holder 7334 */ 7335 initSearchPlaceholder: function () { 7336 var examples = this.items.slice(0, 2).map(function (item) {return item.label}); 7337 7338 if (this.items.length > 2) { 7339 examples.push('...'); 7340 } 7341 7342 // Tip to make html chars interpretable by the browser when the value is get from JS. 7343 let placeholder = document.createElement('div'); 7344 placeholder.innerHTML = this.searchLabel.replace('%s', examples.join(', ')); 7345 7346 this.searchPlaceholder = placeholder.textContent; 7347 }, 7348 7349 /** 7350 * Triggered when typing on the search input 7351 */ 7352 onSearchChange: function (event) { 7353 var text = event.target.value; 7354 if (text.trim() === "") { 7355 this.fulltextSearch = null; 7356 this.onShowLess(); 7357 } else { 7358 this.fulltextSearch = text; 7359 this.onShowMore(); 7360 } 7361 7362 return true; 7363 }, 7364 7365 /** 7366 * Triggered when leaving the search field. 7367 */ 7368 onSearchFocusOut: function(event) { 7369 var text = event.target.value; 7370 if (text.trim() === "") { 7371 this.fulltextSearch = null; 7372 } 7373 }, 7374 7375 /** 7376 * Retrieve additional Results 7377 * 7378 * @param callback 7379 */ 7380 loadAdditionalItems: function (callback) { 7381 fetch(this.options.ajaxLoadUrl, { 7382 method: 'GET', 7383 headers: { 7384 'X-Requested-With': 'XMLHttpRequest', 7385 }, 7386 }) 7387 .then((response) => response.json()) 7388 .then((data) => { 7389 this.items = data.map(this.addItemId.bind(this)); 7390 this.options.hasMoreItems = false; 7391 7392 if (callback) { 7393 return callback(); 7394 } 7395 } 7396 ); 7397 }, 7398 7399 /** 7400 * Retrieve items to display 7401 * 7402 * @returns {*} 7403 */ 7404 getDisplayedItems: function () { 7405 var items = this.items; 7406 7407 if (this.expanded === false) { 7408 items = this.items.slice(0, this.maxSize); 7409 } 7410 7411 if (this.getFulltextSearch()) { 7412 var searchTokens = this.slugify(this.getFulltextSearch()).split('-'); 7413 var lastSearchToken = searchTokens.splice(-1, 1)[0]; 7414 7415 items = items.filter(function(item) { 7416 var isValidItem = true; 7417 var itemTokens = this.slugify(item.label).split('-'); 7418 searchTokens.forEach(function(currentToken) { 7419 if (itemTokens.indexOf(currentToken) === -1) { 7420 isValidItem = false;
7421 } 7422 }) 7423 if (isValidItem && lastSearchToken) { 7424 var ngrams = itemTokens.map(function(token) {return token.substring(0, lastSearchToken.length)}); 7425 isValidItem = ngrams.indexOf(lastSearchToken) !== -1; 7426 } 7427 return isValidItem; 7428 }.bind(this)) 7429 } 7430 this.result = items.length; 7431 return items; 7432 }, 7433 7434 /** 7435 * Does the search have a result 7436 */ 7437 hasSearchResult: function () { 7438 return this.getDisplayedItems().length > 0 7439 }, 7440 7441 /** 7442 * Search result message 7443 */ 7444 getSearchResultMessage : function() { 7445 return this.noSearchResultLabel.replace("%s", '"' + this.getFulltextSearch() + '"') 7446 }, 7447 7448 getFulltextSearch : function() { 7449 return this.fulltextSearch; 7450 }, 7451 7452 /** 7453 * Callback for the "Show more" button 7454 */ 7455 onShowMore: function () { 7456 if (this.options.hasMoreItems) { 7457 this.loadAdditionalItems(this.onShowMore.bind(this)); 7458 } else { 7459 this.expanded = true; 7460 } 7461 7462 this.displayedItems = this.getDisplayedItems(); 7463 }, 7464 7465 /** 7466 * Index the text to be searched. 7467 */ 7468 slugify: function(text) { 7469 return text.toString().toLowerCase() 7470 .replace(/\s+/g, '-') // Replace spaces with - 7471 .replace(/[^\w\u0400-\u052F\u2DE0-\u2DFF\uA640-\uA69F'\-]+/g, '') // Remove all non-word chars 7472 .replace(/\-\-+/g, '-') // Replace multiple - with single - 7473 .replace(/^-+/, '') // Trim - from start of text 7474 }, 7475 7476 /** 7477 * Callback for the "Show less" button 7478 */ 7479 onShowLess: function () { 7480 this.expanded = false; 7481 this.displayedItems = this.getDisplayedItems(); 7482 }, 7483 7484 /** 7485 * Check if the filter can be expanded 7486 * 7487 * @returns {boolean} 7488 */ 7489 enableExpansion : function () { 7490 return this.options.hasMoreItems || this.items.length > this.maxSize; 7491 }, 7492 7493 /** 7494 * Displays the "Show More" link 7495 * 7496 * @returns {*|boolean} 7497 */ 7498 displayShowMore: function () { 7499 return this.enableExpansion() && this.expanded === false && !this.getFulltextSearch(); 7500 }, 7501 7502 /** 7503 * Displays the "Show Less" link 7504 * 7505 * @returns {*|boolean} 7506 */ 7507 displayShowLess: function () { 7508 return this.enableExpansion() && this.expanded === true && !this.getFulltextSearch(); 7509 }, 7510 7511 /** 7512 * Add an id to items. 7513 */ 7514 addItemId: function (item) { 7515 item.id = Math.floor(Math.random() * 1000000) + "_option_"; 7516 item.displayProductCount = this.options.displayProductCount && (item.count >= 1); 7517 7518 return item; 7519 }, 7520 }; 7521 }; 7522</script>
vendor: 1 bytes, line 7522
7522
7523<script> 7524 function rangeSlider(options, isPriceSlider) { 7525 "use strict"; 7526 7527 return { 7528 options: options, 7529 priceSlider: isPriceSlider, 7530 lastThumbUpdatedMax: true, 7531 minfocused: false, 7532 maxfocused: false, 7533 sliderZindex: 20, 7534 messageTemplates: { 7535 "displayOne": '<span class="msg">1 item</span>', 7536 "displayCount": '<span class="msg"><%- count %> items</span>', 7537 "displayEmpty": '<span class="msg-error">No items in the current range.</span>' 7538 }, 7539 minprice: 0, 7540 maxprice: 0, 7541 fromLabel: '', 7542 toLabel: '', 7543 min: 0, 7544 max: 0, 7545 minZindex: 0, 7546 maxZindex: 0, 7547 minthumb: 0, 7548 maxthumb: 0, 7549 message: '', 7550 url: '', 7551 showAdaptiveSlider: false, 7552 intervals: [], 7553 7554 initialize: function () { 7555 this.options = Object.assign({}, this.options, options); 7556 this.url = this.options.urlTemplate; 7557 7558 if (this.options.sliderZindex !== undefined) { 7559 this.sliderZindex = this.options.sliderZindex; 7560 } 7561 7562 this.showAdaptiveSlider = false; 7563 if (this.options.showAdaptiveSlider !== undefined) { 7564 this.showAdaptiveSlider = this.options.showAdaptiveSlider; 7565 } 7566 7567 if (this.options.maxLabelOffset === undefined) { 7568 this.options.maxLabelOffset = 0.01; 7569 } 7570 7571 if (this.options.rate === undefined) { 7572 this.options.rate = 1.0000; 7573 } 7574 7575 if (this.showAdaptiveSlider) { 7576 this._initAdaptiveSliderValues(); 7577 } else { 7578 this._initSliderValues(); 7579 } 7580 7581 this.mintrigger(); 7582 this.maxtrigger(); 7583 }, 7584 _initSliderValues: function () { 7585 this.rate = parseFloat(this.options.rate); 7586 this.minprice = Math.floor(this.options.currentValue.from * this.rate); 7587 this.maxprice = Math.round(this.options.currentValue.to * this.rate); 7588 this.intervals = this.options.intervals.map( 7589 function(item) { item.value = Math.round(item.value * this.rate); return item}.bind(this) 7590 ); 7591 this.min = Math.floor(this.options.minValue * this.rate); 7592 this.max = Math.round(this.options.maxValue * this.rate); 7593 }, 7594 7595 _initAdaptiveSliderValues: function () { 7596 this.intervals = this.options.adaptiveIntervals; 7597 this.options.adaptiveIntervals[0].value = Math.floor(this.options.adaptiveIntervals[0].value); 7598 this.minprice = this._getAdaptiveValue(Number(this.options.currentValue.from)); 7599 this.maxprice = this._getAdaptiveValue(Number(this.options.currentValue.to)); 7600 this.rate = parseFloat(this.options.rate); 7601 this.intervals = this.intervals.map( 7602 function(item) { item.originalValue = Math.ceil(item.originalValue * this.rate); return item}.bind(this) 7603 ); 7604 this.min = this.intervals[0].value; 7605 this.max = this.intervals[this.intervals.length - 1].value; 7606 }, 7607 mintrigger: function () { 7608 this.lastThumbUpdatedMax = false; 7609 this.validation(); 7610 this.minprice = this._getClosestAdaptiveValue(Math.min(this.minprice, this.maxprice)); 7611 this.minthumb = ((this.minprice - this.min) / (this.max - this.min)) * 100; 7612 this._onChangeAfter(); 7613 }, 7614 maxtrigger: function () { 7615 this.lastThumbUpdatedMax = true; 7616 this.validation(); 7617 this.maxprice = this._getClosestAdaptiveValue(Math.max(this.maxprice, this.minprice)); 7618 this.maxthumb = ((this.maxprice - this.min) / (this.max - this.min)) * 100; 7619 this._onChangeAfter(); 7620 }, 7621 updateFocusState: function (targetName, stateValue) { 7622 this[`${targetName}focused`] = stateValue 7623 }, 7624 _onChangeAfter: function () {
7625 this._updateSliderZindexes(); 7626 this._applyRange(); 7627 this._refreshDisplay(); 7628 }, 7629 validation: function () { 7630 if (/^[\d.]*$/.test(this.minprice)) { 7631 if (this.minprice > this.max) { 7632 this.minprice = this._getAdaptiveValue(Number(this.options.currentValue.from)); 7633 } 7634 if (this.minprice < this.min) { 7635 this.minprice = this.min; 7636 } 7637 } else { 7638 this.minprice = this._getAdaptiveValue(Number(this.options.currentValue.from)); 7639 } 7640 if (/^[\d.]*$/.test(this.maxprice)) { 7641 if (this.maxprice > this.max) { 7642 this.maxprice = this.max; 7643 } 7644 if (this.maxprice < this.min) { 7645 this.maxprice = this._getAdaptiveValue(Number(this.options.currentValue.to)); 7646 } 7647 } else { 7648 this.maxprice = this._getAdaptiveValue(Number(this.options.currentValue.to)) 7649 } 7650 }, 7651 getItemCount: function () { 7652 var from = this.minprice, to = this.maxprice, intervals = this.intervals; 7653 return intervals.map(function (item) { 7654 return item.value >= from && item.value < to ? item.count : 0; 7655 }) 7656 .reduce(function (a, b) { 7657 return a + b; 7658 }); 7659 }, 7660 _refreshDisplay: function () { 7661 this.count = this.getItemCount(); 7662 let minprice = this._getOriginalValue(this.minprice); 7663 if (minprice >= this._getOriginalValue(this.max) ) { 7664 minprice = this._getOriginalValue(this.max) - this.options.maxLabelOffset; 7665 } 7666 this.fromLabel = this._formatLabel(minprice); 7667 7668 let maxprice = this._getOriginalValue(this.maxprice) - this.options.maxLabelOffset; 7669 if (maxprice < this._getOriginalValue(this.min)) { 7670 maxprice = this._getOriginalValue(this.maxprice); 7671 } 7672 this.toLabel = this._formatLabel(maxprice); 7673 7674 var messageTemplate = this.messageTemplates[this.count > 0 ? (this.count > 1 ? 'displayCount' : 'displayOne') : 'displayEmpty']; 7675 this.message = this._unescape(messageTemplate.replace('<%- count %>', this.count)); 7676 }, 7677 _formatLabel: function (value) { 7678 var formattedValue = value; 7679 7680 if (this.priceSlider && this.options.fieldFormat) { 7681 formattedValue = this._formatPrice(value); 7682 } else if (this.options.fieldFormat) { 7683 var pattern = this.options.fieldFormat.pattern || '%s'; 7684 formattedValue = pattern.replace( 7685 '%s', 7686 Number.parseFloat(formattedValue).toFixed(this.options.fieldFormat.precision) 7687 ); 7688 } 7689 7690 return formattedValue; 7691 }, 7692 _formatPrice: function (value) { 7693 var formatter = new Intl.NumberFormat( 7694 document.documentElement.lang, 7695 { 7696 style: 'currency', 7697 currency: 'GBP', 7698 } 7699 ); 7700 7701 return formatter.format(value); 7702 }, 7703 _applyRange: function () { 7704 var range = { 7705 from : this._getOriginalValue(this.minprice) * (1 / this.rate), 7706 to : this._getOriginalValue(this.maxprice) * (1 / this.rate), 7707 }; 7708 7709 this.url = this._unescape(this.options.urlTemplate.replace('<%- from %>', range.from).replace('<%- to %>', range.to)); 7710 }, 7711 _updateSliderZindexes: function () { 7712 this.minZindex = this.sliderZindex; 7713 this.maxZindex = this.sliderZindex; 7714 if (this.minprice == this.maxprice) { 7715 if (this.minprice === this.min || (this.minprice !== this.min && this.lastThumbUpdatedMax)) { 7716 this.maxZindex = this.sliderZindex + 1; 7717 } 7718 7719 if (this.maxprice === this.max || (this.maxprice !== this.max && !this.lastThumbUpdatedMax)) { 7720 this.minZindex = this.sliderZindex + 1; 7721 } 7722 7723 } 7724 }, 7725 _getAdaptiveValue : function (value) { 7726 if (!this.showAdaptiveSlider) { 7727 return value; 7728 } 7729 7730 var adaptiveValue = this.intervals[0].value; 7731 var found = false;
7732 this.intervals.forEach(function (item) { 7733 if (found === false && item.originalValue === value) { 7734 adaptiveValue = item.value; 7735 found = true; 7736 } 7737 7738 if (found === false && item.originalValue < value) { 7739 adaptiveValue = item.value; 7740 } 7741 }); 7742 7743 return adaptiveValue; 7744 }, 7745 7746 _getClosestAdaptiveValue : function (value) { 7747 if (!this.showAdaptiveSlider) { 7748 return value; 7749 } 7750 7751 var closestValue = this.intervals[0].value; 7752 var found = false; 7753 this.intervals.forEach(function (item) { 7754 if (item.value === value) { 7755 closestValue = value; 7756 found = true; 7757 } 7758 7759 if (found === false && item.value < value) { 7760 closestValue = item.value; 7761 } 7762 }); 7763 7764 return closestValue; 7765 }, 7766 7767 _getOriginalValue : function (value) { 7768 if (!this.showAdaptiveSlider) { 7769 return value; 7770 } 7771 7772 var originalValue = null; 7773 this.intervals.forEach(function (item) { 7774 if (item.value === value) { 7775 originalValue = item.originalValue; 7776 } 7777 }); 7778 7779 return originalValue; 7780 }, 7781 7782 _unescape: function (str) { 7783 return str.replace(/<%|%3C%/g, '<%').replace(/%>|%%3E/g, '%>'); 7784 }, 7785 } 7786 } 7787</script>
vendor: 1 bytes, line 7787
7787
7788<script type="text/json" id="default-section-data"> 7789 {"messages":[],"customer":[],"compare-products":[],"last-ordered-items":[],"cart":[],"directory-data":{"AD":{"name":"Andorra"},"AE":{"name":"United Arab Emirates"},"AF":{"name":"Afghanistan"},"AG":{"name":"Antigua & Barbuda"},"AI":{"name":"Anguilla"},"AL":{"name":"Albania","regions":{"728":{"code":"AL-01","name":"Berat"},"729":{"code":"AL-09","name":"Dib\u00ebr"},"730":{"code":"AL-02","name":"Durr\u00ebs"},"731":{"code":"AL-03","name":"Elbasan"},"732":{"code":"AL-04","name":"Fier"},"733":{"code":"AL-05","name":"Gjirokast\u00ebr"},"734":{"code":"AL-06","name":"Kor\u00e7\u00eb"},"735":{"code":"AL-07","name":"Kuk\u00ebs"},"736":{"code":"AL-08","name":"Lezh\u00eb"},"737":{"code":"AL-10","name":"Shkod\u00ebr"},"738":{"code":"AL-11","name":"Tiran\u00eb"},"739":{"code":"AL-12","name":"Vlor\u00eb"}}},"AM":{"name":"Armenia"},"AO":{"name":"Angola"},"AQ":{"name":"Antarctica"},"AR":{"name":"Argentina","regions":{"741":{"code":"AR-B","name":"Buenos Aires"},"742":{"code":"AR-K","name":"Catamarca"},"743":{"code":"AR-H","name":"Chaco"},"744":{"code":"AR-U","name":"Chubut"},"740":{"code":"AR-C","name":"Ciudad Aut\u00f3noma de Buenos Aires"},"745":{"code":"AR-X","name":"C\u00f3rdoba"},"746":{"code":"AR-W","name":"Corrientes"},"747":{"code":"AR-E","name":"Entre R\u00edos"},"748":{"code":"AR-P","name":"Formosa"},"749":{"code":"AR-Y","name":"Jujuy"},"750":{"code":"AR-L","name":"La Pampa"},"751":{"code":"AR-F","name":"La Rioja"},"752":{"code":"AR-M","name":"Mendoza"},"753":{"code":"AR-N","name":"Misiones"},"754":{"code":"AR-Q","name":"Neuqu\u00e9n"},"755":{"code":"AR-R","name":"R\u00edo Negro"},"756":{"code":"AR-A","name":"Salta"},"757":{"code":"AR-J","name":"San Juan"},"758":{"code":"AR-D","name":"San Luis"},"759":{"code":"AR-Z","name":"Santa Cruz"},"760":{"code":"AR-S","name":"Santa Fe"},"761":{"code":"AR-G","name":"Santiago del Estero"},"762":{"code":"AR-V","name":"Tierra del Fuego"},"763":{"code":"AR-T","name":"Tucum\u00e1n"}}},"AS":{"name":"American Samoa"},"AT":{"name":"Austria","regions":{"102":{"code":"BL","name":"Burgenland"},"99":{"code":"KN","name":"K\u00e4rnten"},"96":{"code":"NO","name":"Nieder\u00f6sterreich"},"97":{"code":"OO","name":"Ober\u00f6sterreich"},"98":{"code":"SB","name":"Salzburg"},"100":{"code":"ST","name":"Steiermark"},"101":{"code":"TI","name":"Tirol"},"103":{"code":"VB","name":"Vorarlberg"},"95":{"code":"WI","name":"Wien"}}},"AU":{"name":"Australia","regions":{"485":{"code":"ACT","name":"Australian Capital Territory"},"486":{"code":"NSW","name":"New South Wales"},"492":{"code":"NT","name":"Northern Territory"},"488":{"code":"QLD","name":"Queensland"},"489":{"code":"SA","name":"South Australia"},"490":{"code":"TAS","name":"Tasmania"},"487":{"code":"VIC","name":"Victoria"},"491":{"code":"WA","name":"Western Australia"}}},"AW":{"name":"Aruba"},"AX":{"name":"\u00c5land Islands"},"AZ":{"name":"Azerbaijan"},"BA":{"name":"Bosnia & Herzegovina"},"BB":{"name":"Barbados"},"BD":{"name":"Bangladesh"},"BE":{"name":"Belgium","regions":{"525":{"code":"VAN","name":"Antwerpen"},"526":{"code":"WBR","name":"Brabant wallon"},"527":{"code":"BRU","name":"Brussels-Capital Region"},"528":{"code":"WHT","name":"Hainaut"},"530":{"code":"WLG","name":"Li\u00e8ge"},"529":{"code":"VLI","name":"Limburg"},"531":{"code":"WLX","name":"Luxembourg"},"532":{"code":"WNA","name":"Namur"},"533":{"code":"VOV","name":"Oost-Vlaanderen"},"534":{"code":"VBR","name":"Vlaams-Brabant"},"535":{"code":"VWV","name":"West-Vlaanderen"}}},"BF":{"name":"Burkina Faso"},"BG":{"name":"Bulgaria","regions":{"780":{"code":"BG-01","name":"Blagoevgrad"},"781":{"code":"BG-02","name":"Burgas"},"787":{"code":"BG-08","name":"Dobrich"},"786":{"code":"BG-07","name":"Gabrovo"},"805":{"code":"BG-26","name":"Haskovo"},"788":{"code":"BG-09","name":"Kardzhali"},"789":{"code":"BG-10","name":"Kyustendil"},"790":{"code":"BG-11","name":"Lovech"},"791":{"code":"BG-12","name":"Montana"},"792":{"code":"BG-13","name":"Pazardzhik"},"793":{"code":"BG-14","name":"Pernik"},"794":{"code":"BG-15","name":"Pleven"},"795":{"code":"BG-16","name":"Plovdiv"},"796":{"code":"BG-17","name":"Razgrad"},"797":{"code":"BG-18","name":"Ruse"},"806":{"code":"BG-27","name":"Shumen"},"798":{"code":"BG-19","name":"Silistra"},"799":{"code":"BG-20","name":"Sliven"},"800":{"code":"BG-21","name":"Smolyan"},"801":{"code":"BG-22","name":"Sofia City"},"802":{"code":"BG-23","name":"Sofia Province"},"803":{"code":"BG-24","name":"Stara Zagora"},"804":{"code":"BG-25","name":"Targovishte"},"782":{"code":"BG-03","name":"Varna"},"783":{"code":"BG-04","name":"Veliko Tarnovo"},"784":{"code":"BG-05","name":"Vidin"},"785":{"code":"BG-06","name":"Vratsa"},"807":{"code":"BG-28","name":"Yambol"}}},"BH":{"name":"Bahrain"},"BI":{"name":"Burundi"},"BJ":{"name":"Benin"},"BL":{"name":"St. Barth\u00e9lemy"},"BM":{"name":"Bermuda"},"BN":{"name":"Brunei"}
7789,"BO":{"name":"Bolivia","regions":{"772":{"code":"BO-H","name":"Chuquisaca"},"771":{"code":"BO-C","name":"Cochabamba"},"773":{"code":"BO-B","name":"El Beni"},"774":{"code":"BO-L","name":"La Paz"},"775":{"code":"BO-O","name":"Oruro"},"776":{"code":"BO-N","name":"Pando"},"777":{"code":"BO-P","name":"Potos\u00ed"},"778":{"code":"BO-S","name":"Santa Cruz"},"779":{"code":"BO-T","name":"Tarija"}}},"BR":{"name":"Brazil"},"BS":{"name":"Bahamas"},"BT":{"name":"Bhutan"},"BV":{"name":"Bouvet Island"},"BW":{"name":"Botswana"},"BY":{"name":"Belarus","regions":{"764":{"code":"BY-BR","name":"Bresckaja voblas\u0107"},"765":{"code":"BY-HO","name":"Homie\u013askaja voblas\u0107"},"766":{"code":"BY-HM","name":"Horad Minsk"},"767":{"code":"BY-HR","name":"Hrodzienskaja voblas\u0107"},"768":{"code":"BY-MA","name":"Mahilio\u016dskaja voblas\u0107"},"769":{"code":"BY-MI","name":"Minskaja voblas\u0107"},"770":{"code":"BY-VI","name":"Viciebskaja voblas\u0107"}}},"BZ":{"name":"Belize"},"CA":{"name":"Canada","regions":{"66":{"code":"AB","name":"Alberta"},"67":{"code":"BC","name":"British Columbia"},"68":{"code":"MB","name":"Manitoba"},"70":{"code":"NB","name":"New Brunswick"},"69":{"code":"NL","name":"Newfoundland and Labrador"},"72":{"code":"NT","name":"Northwest Territories"},"71":{"code":"NS","name":"Nova Scotia"},"73":{"code":"NU","name":"Nunavut"},"74":{"code":"ON","name":"Ontario"},"75":{"code":"PE","name":"Prince Edward Island"},"76":{"code":"QC","name":"Quebec"},"77":{"code":"SK","name":"Saskatchewan"},"78":{"code":"YT","name":"Yukon Territory"}}},"CC":{"name":"Cocos (Keeling) Islands"},"CD":{"name":"Congo - Kinshasa"},"CF":{"name":"Central African Republic"},"CG":{"name":"Congo - Brazzaville"},"CH":{"name":"Switzerland","regions":{"104":{"code":"AG","name":"Aargau"},"106":{"code":"AR","name":"Appenzell Ausserrhoden"},"105":{"code":"AI","name":"Appenzell Innerrhoden"},"108":{"code":"BL","name":"Basel-Landschaft"},"109":{"code":"BS","name":"Basel-Stadt"},"107":{"code":"BE","name":"Bern"},"110":{"code":"FR","name":"Friburg"},"111":{"code":"GE","name":"Geneva"},"112":{"code":"GL","name":"Glarus"},"113":{"code":"GR","name":"Graub\u00fcnden"},"114":{"code":"JU","name":"Jura"},"115":{"code":"LU","name":"Lucerne"},"116":{"code":"NE","name":"Neuch\u00e2tel"},"117":{"code":"NW","name":"Nidwalden"},"118":{"code":"OW","name":"Obwalden"},"120":{"code":"SH","name":"Schaffhausen"},"122":{"code":"SZ","name":"Schwyz"},"121":{"code":"SO","name":"Solothurn"},"119":{"code":"SG","name":"St. Gallen"},"123":{"code":"TG","name":"Thurgau"},"124":{"code":"TI","name":"Ticino"},"125":{"code":"UR","name":"Uri"},"126":{"code":"VD","name":"Vaud"},"127":{"code":"VS","name":"Wallis"},"128":{"code":"ZG","name":"Zug"},"129":{"code":"ZH","name":"Z\u00fcrich"}}},"CI":{"name":"C\u00f4te d\u2019Ivoire"},"CK":{"name":"Cook Islands"},"CL":{"name":"Chile","regions":{"808":{"code":"CL-AI","name":"Ais\u00e9n del General Carlos Iba\u00f1ez del Campo"},"809":{"code":"CL-AN","name":"Antofagasta"},"810":{"code":"CL-AP","name":"Arica y Parinacota"},"812":{"code":"CL-AT","name":"Atacama"},"813":{"code":"CL-BI","name":"Biob\u00edo"},"814":{"code":"CL-CO","name":"Coquimbo"},"811":{"code":"CL-AR","name":"La Araucan\u00eda"},"815":{"code":"CL-LI","name":"Libertador General Bernardo O'Higgins"},"816":{"code":"CL-LL","name":"Los Lagos"},"817":{"code":"CL-LR","name":"Los R\u00edos"},"818":{"code":"CL-MA","name":"Magallanes"},"819":{"code":"CL-ML","name":"Maule"},"820":{"code":"CL-NB","name":"\u00d1uble"},"821":{"code":"CL-RM","name":"Regi\u00f3n Metropolitana de Santiago"},"822":{"code":"CL-TA","name":"Tarapac\u00e1"},"823":{"code":"CL-VS","name":"Valpara\u00edso"}}},"CM":{"name":"Cameroon"},"CN":{"name":"China","regions":{"536":{"code":"CN-AH","name":"Anhui Sheng"},"537":{"code":"CN-BJ","name":"Beijing Shi"},"538":{"code":"CN-CQ","name":"Chongqing Shi"},"539":{"code":"CN-FJ","name":"Fujian Sheng"},"540":{"code":"CN-GS","name":"Gansu Sheng"},"541":{"code":"CN-GD","name":"Guangdong Sheng"},"542":{"code":"CN-GX","name":"Guangxi Zhuangzu Zizhiqu"},"543":{"code":"CN-GZ","name":"Guizhou Sheng"},"544":{"code":"CN-HI","name":"Hainan Sheng"},"545":{"code":"CN-HE","name":"Hebei Sheng"},"546":{"code":"CN-HL","name":"Heilongjiang Sheng"},"547":{"code":"CN-HA","name":"Henan Sheng"},"548":{"code":"CN-HK","name":"Hong Kong SAR"},"549":{"code":"CN-HB","name":"Hubei Sheng"},"550":{"code":"CN-HN","name":"Hunan Sheng"},"551":{"code":"CN-JS","name":"Jiangsu Sheng"},"552":{"code":"CN-JX","name":"Jiangxi Sheng"},"553":{"code":"CN-JL","name":"Jilin Sheng"},"554":{"code":"CN-LN","name":"Liaoning Sheng"},"555":{"code":"CN-MO","name":"Macao SAR"},"556":{"code":"CN-NM","name":"Nei Mongol Zizhiqu"},"557":{"code":"CN-NX","name":"Ningxia Huizi Zizhiqu"},"558":{"code":"CN-QH","name":"Qinghai Sheng"},"559":{"code":"CN-SN","name":"Shaanxi Sheng"},"560":{"code":"CN-SD","name":"Shandong Sheng"},"561":{"code":"CN-SH","name":"Shanghai Shi"},"562":{"code":"CN-SX","name":"Shanxi Sheng"},"563":{"code":"CN-SC","name":"Sichuan Sheng"},"564":{"code":"CN-TW","name":"Taiwan Sheng"},"565":{"code":"CN-TJ","name":"Tianjin Shi"},"566":{"code":"CN-XJ","name":"Xinjiang Uygur Zizhiqu"},"567":{"code":"CN-XZ","name":"Xizang Zizhiqu"},"568":{"code":"CN-YN","name":"Yunnan Sheng"},"569":{"code":"CN-ZJ","name":"Zhejiang Sheng"}}},"CO":{"name":"Colombia","regions":{"570":{"code":"CO-AMA","name":"Amazonas"},"571":{"code":"CO-ANT","name":"Antioquia"},"572":{"code":"CO-ARA","name":"Arauca"},"573":{"code":"CO-ATL","name":"Atl\u00e1ntico"},"574":{"code":"CO-BOL","name":"Bol\u00edvar"},"575":{"code":"CO-BOY","name":"Boyac\u00e1"},"576":{"code":"CO-CAL","name":"Caldas"},"577":{"code":"CO-CAQ","name":"Caquet\u00e1"},"578":{"code":"CO-CAS","name":"Casanare"},"579":{"code":"CO-CAU","name":"Cauca"},"580":{"code":"CO-CES","name":"Cesar"},"581":{"code":"CO-CHO","name":"Choc\u00f3"},"582":{"code":"CO-COR","name":"C\u00f3rdoba"},"583":{"code":"CO-CUN","name":"Cundinamarca"},"584":{"code":"CO-GUA","name":"Guain\u00eda"},"585":{"code":"CO-GUV","name":"Guaviare"},"586":{"code":"CO-HUL","name":"Huila"},"587":{"code":"CO-LAG","name":"La Guajira"},"588":{"code":"CO-MAG","name":"Magdalena"},"589":{"code":"CO-MET","name":"Meta"}
7789,"590":{"code":"CO-NAR","name":"Nari\u00f1o"},"591":{"code":"CO-NSA","name":"Norte de Santander"},"592":{"code":"CO-PUT","name":"Putumayo"},"593":{"code":"CO-QUI","name":"Quind\u00edo"},"594":{"code":"CO-RIS","name":"Risaralda"},"595":{"code":"CO-SAP","name":"San Andr\u00e9s y Providencia"},"596":{"code":"CO-SAN","name":"Santander"},"597":{"code":"CO-SUC","name":"Sucre"},"598":{"code":"CO-TOL","name":"Tolima"},"599":{"code":"CO-VAC","name":"Valle del Cauca"},"600":{"code":"CO-VAU","name":"Vaup\u00e9s"},"601":{"code":"CO-VID","name":"Vichada"}}},"CR":{"name":"Costa Rica","regions":{"825":{"code":"CR-AL","name":"Alajuela"},"826":{"code":"CR-CA","name":"Cartago"},"828":{"code":"CR-GU","name":"Guanacaste"},"827":{"code":"CR-HE","name":"Heredia"},"830":{"code":"CR-LI","name":"Lim\u00f3n"},"829":{"code":"CR-PU","name":"Puntarenas"},"824":{"code":"CR-SJ","name":"San Jos\u00e9"}}},"CU":{"name":"Cuba"},"CV":{"name":"Cape Verde"},"CX":{"name":"Christmas Island"},"CY":{"name":"Cyprus"},"CZ":{"name":"Czechia","regions":{"833":{"code":"CZ-31","name":"Jiho\u010desk\u00fd kraj"},"841":{"code":"CZ-64","name":"Jihomoravsk\u00fd kraj"},"835":{"code":"CZ-41","name":"Karlovarsk\u00fd kraj"},"840":{"code":"CZ-63","name":"Kraj Vyso\u010dina"},"838":{"code":"CZ-52","name":"Kr\u00e1lov\u00e9hradeck\u00fd kraj"},"837":{"code":"CZ-51","name":"Libereck\u00fd kraj"},"844":{"code":"CZ-80","name":"Moravskoslezsk\u00fd kraj"},"842":{"code":"CZ-71","name":"Olomouck\u00fd kraj"},"839":{"code":"CZ-53","name":"Pardubick\u00fd kraj"},"834":{"code":"CZ-32","name":"Plze\u0148sk\u00fd kraj"},"831":{"code":"CZ-10","name":"Praha, Hlavn\u00ed m\u011bsto"},"832":{"code":"CZ-20","name":"St\u0159edo\u010desk\u00fd kraj"},"836":{"code":"CZ-42","name":"\u00dasteck\u00fd kraj"},"843":{"code":"CZ-72","name":"Zl\u00ednsk\u00fd kraj"}}},"DE":{"name":"Germany","regions":{"80":{"code":"BAW","name":"Baden-W\u00fcrttemberg"},"81":{"code":"BAY","name":"Bayern"},"82":{"code":"BER","name":"Berlin"},"83":{"code":"BRG","name":"Brandenburg"},"84":{"code":"BRE","name":"Bremen"},"85":{"code":"HAM","name":"Hamburg"},"86":{"code":"HES","name":"Hessen"},"87":{"code":"MEC","name":"Mecklenburg-Vorpommern"},"79":{"code":"NDS","name":"Niedersachsen"},"88":{"code":"NRW","name":"Nordrhein-Westfalen"},"89":{"code":"RHE","name":"Rheinland-Pfalz"},"90":{"code":"SAR","name":"Saarland"},"91":{"code":"SAS","name":"Sachsen"},"92":{"code":"SAC","name":"Sachsen-Anhalt"},"93":{"code":"SCN","name":"Schleswig-Holstein"},"94":{"code":"THE","name":"Th\u00fcringen"}}},"DJ":{"name":"Djibouti"},"DK":{"name":"Denmark","regions":{"845":{"code":"DK-84","name":"Hovedstaden"},"846":{"code":"DK-82","name":"Midtjylland"},"847":{"code":"DK-81","name":"Nordjylland"},"848":{"code":"DK-85","name":"Sj\u00e6lland"},"849":{"code":"DK-83","name":"Syddanmark"}}},"DM":{"name":"Dominica"},"DO":{"name":"Dominican Republic"},"DZ":{"name":"Algeria"},"EC":{"name":"Ecuador","regions":{"850":{"code":"EC-A","name":"Azuay"},"851":{"code":"EC-B","name":"Bol\u00edvar"},"852":{"code":"EC-F","name":"Ca\u00f1ar"},"853":{"code":"EC-C","name":"Carchi"},"854":{"code":"EC-H","name":"Chimborazo"},"855":{"code":"EC-X","name":"Cotopaxi"},"856":{"code":"EC-O","name":"El Oro"},"857":{"code":"EC-E","name":"Esmeraldas"},"858":{"code":"EC-W","name":"Gal\u00e1pagos"},"859":{"code":"EC-G","name":"Guayas"},"860":{"code":"EC-I","name":"Imbabura"},"861":{"code":"EC-L","name":"Loja"},"862":{"code":"EC-R","name":"Los R\u00edos"},"863":{"code":"EC-M","name":"Manab\u00ed"},"864":{"code":"EC-S","name":"Morona Santiago"},"865":{"code":"EC-N","name":"Napo"},"866":{"code":"EC-D","name":"Orellana"},"867":{"code":"EC-Y","name":"Pastaza"},"868":{"code":"EC-P","name":"Pichincha"},"869":{"code":"EC-SE","name":"Santa Elena"},"870":{"code":"EC-SD","name":"Santo Domingo de los Ts\u00e1chilas"},"871":{"code":"EC-U","name":"Sucumb\u00edos"},"872":{"code":"EC-T","name":"Tungurahua"},"873":{"code":"EC-Z","name":"Zamora Chinchipe"}}},"EE":{"name":"Estonia","regions":{"340":{"code":"EE-37","name":"Harjumaa"},"341":{"code":"EE-39","name":"Hiiumaa"},"342":{"code":"EE-44","name":"Ida-Virumaa"}
7789,"344":{"code":"EE-51","name":"J\u00e4rvamaa"},"343":{"code":"EE-49","name":"J\u00f5gevamaa"},"346":{"code":"EE-59","name":"L\u00e4\u00e4ne-Virumaa"},"345":{"code":"EE-57","name":"L\u00e4\u00e4nemaa"},"348":{"code":"EE-67","name":"P\u00e4rnumaa"},"347":{"code":"EE-65","name":"P\u00f5lvamaa"},"349":{"code":"EE-70","name":"Raplamaa"},"350":{"code":"EE-74","name":"Saaremaa"},"351":{"code":"EE-78","name":"Tartumaa"},"352":{"code":"EE-82","name":"Valgamaa"},"353":{"code":"EE-84","name":"Viljandimaa"},"354":{"code":"EE-86","name":"V\u00f5rumaa"}}},"EG":{"name":"Egypt"},"EH":{"name":"Western Sahara"},"ER":{"name":"Eritrea"},"ES":{"name":"Spain","regions":{"130":{"code":"A Coru\u0441a","name":"A Coru\u00f1a"},"131":{"code":"Alava","name":"Alava"},"132":{"code":"Albacete","name":"Albacete"},"133":{"code":"Alicante","name":"Alicante"},"134":{"code":"Almeria","name":"Almeria"},"135":{"code":"Asturias","name":"Asturias"},"136":{"code":"Avila","name":"Avila"},"137":{"code":"Badajoz","name":"Badajoz"},"138":{"code":"Baleares","name":"Baleares"},"139":{"code":"Barcelona","name":"Barcelona"},"140":{"code":"Burgos","name":"Burgos"},"141":{"code":"Caceres","name":"Caceres"},"142":{"code":"Cadiz","name":"Cadiz"},"143":{"code":"Cantabria","name":"Cantabria"},"144":{"code":"Castellon","name":"Castellon"},"145":{"code":"Ceuta","name":"Ceuta"},"146":{"code":"Ciudad Real","name":"Ciudad Real"},"147":{"code":"Cordoba","name":"Cordoba"},"148":{"code":"Cuenca","name":"Cuenca"},"149":{"code":"Girona","name":"Girona"},"150":{"code":"Granada","name":"Granada"},"151":{"code":"Guadalajara","name":"Guadalajara"},"152":{"code":"Guipuzcoa","name":"Guipuzcoa"},"153":{"code":"Huelva","name":"Huelva"},"154":{"code":"Huesca","name":"Huesca"},"155":{"code":"Jaen","name":"Jaen"},"156":{"code":"La Rioja","name":"La Rioja"},"157":{"code":"Las Palmas","name":"Las Palmas"},"158":{"code":"Leon","name":"Leon"},"159":{"code":"Lleida","name":"Lleida"},"160":{"code":"Lugo","name":"Lugo"},"161":{"code":"Madrid","name":"Madrid"},"162":{"code":"Malaga","name":"Malaga"},"163":{"code":"Melilla","name":"Melilla"},"164":{"code":"Murcia","name":"Murcia"},"165":{"code":"Navarra","name":"Navarra"},"166":{"code":"Ourense","name":"Ourense"},"167":{"code":"Palencia","name":"Palencia"},"168":{"code":"Pontevedra","name":"Pontevedra"},"169":{"code":"Salamanca","name":"Salamanca"},"170":{"code":"Santa Cruz de Tenerife","name":"Santa Cruz de Tenerife"},"171":{"code":"Segovia","name":"Segovia"},"172":{"code":"Sevilla","name":"Sevilla"},"173":{"code":"Soria","name":"Soria"},"174":{"code":"Tarragona","name":"Tarragona"},"175":{"code":"Teruel","name":"Teruel"},"176":{"code":"Toledo","name":"Toledo"},"177":{"code":"Valencia","name":"Valencia"},"178":{"code":"Valladolid","name":"Valladolid"},"179":{"code":"Vizcaya","name":"Vizcaya"},"180":{"code":"Zamora","name":"Zamora"},"181":{"code":"Zaragoza","name":"Zaragoza"}}},"ET":{"name":"Ethiopia"},"FI":{"name":"Finland","regions":{"339":{"code":"Ahvenanmaa","name":"Ahvenanmaa"},"333":{"code":"Etel\u00e4-Karjala","name":"Etel\u00e4-Karjala"},"326":{"code":"Etel\u00e4-Pohjanmaa","name":"Etel\u00e4-Pohjanmaa"},"325":{"code":"Etel\u00e4-Savo","name":"Etel\u00e4-Savo"},"337":{"code":"It\u00e4-Uusimaa","name":"It\u00e4-Uusimaa"},"322":{"code":"Kainuu","name":"Kainuu"},"335":{"code":"Kanta-H\u00e4me","name":"Kanta-H\u00e4me"},"330":{"code":"Keski-Pohjanmaa","name":"Keski-Pohjanmaa"},"331":{"code":"Keski-Suomi","name":"Keski-Suomi"},"338":{"code":"Kymenlaakso","name":"Kymenlaakso"},"320":{"code":"Lappi","name":"Lappi"},"334":{"code":"P\u00e4ij\u00e4t-H\u00e4me","name":"P\u00e4ij\u00e4t-H\u00e4me"},"328":{"code":"Pirkanmaa","name":"Pirkanmaa"},"327":{"code":"Pohjanmaa","name":"Pohjanmaa"},"323":{"code":"Pohjois-Karjala","name":"Pohjois-Karjala"},"321":{"code":"Pohjois-Pohjanmaa","name":"Pohjois-Pohjanmaa"},"324":{"code":"Pohjois-Savo","name":"Pohjois-Savo"},"329":{"code":"Satakunta","name":"Satakunta"},"336":{"code":"Uusimaa","name":"Uusimaa"},"332":{"code":"Varsinais-Suomi","name":"Varsinais-Suomi"}}},"FJ":{"name":"Fiji"},"FK":{"name":"Falkland Islands"},"FM":{"name":"Micronesia"},"FO":{"name":"Faroe Islands"},"FR":{"name":"France","regions":{"182":{"code":"1","name":"Ain"},"183":{"code":"2","name":"Aisne"},"184":{"code":"3","name":"Allier"}
7789,"185":{"code":"4","name":"Alpes-de-Haute-Provence"},"187":{"code":"6","name":"Alpes-Maritimes"},"188":{"code":"7","name":"Ard\u00e8che"},"189":{"code":"8","name":"Ardennes"},"190":{"code":"9","name":"Ari\u00e8ge"},"191":{"code":"10","name":"Aube"},"192":{"code":"11","name":"Aude"},"193":{"code":"12","name":"Aveyron"},"249":{"code":"67","name":"Bas-Rhin"},"194":{"code":"13","name":"Bouches-du-Rh\u00f4ne"},"195":{"code":"14","name":"Calvados"},"196":{"code":"15","name":"Cantal"},"197":{"code":"16","name":"Charente"},"198":{"code":"17","name":"Charente-Maritime"},"199":{"code":"18","name":"Cher"},"200":{"code":"19","name":"Corr\u00e8ze"},"201":{"code":"2A","name":"Corse-du-Sud"},"203":{"code":"21","name":"C\u00f4te-d'Or"},"204":{"code":"22","name":"C\u00f4tes-d'Armor"},"205":{"code":"23","name":"Creuse"},"261":{"code":"79","name":"Deux-S\u00e8vres"},"206":{"code":"24","name":"Dordogne"},"207":{"code":"25","name":"Doubs"},"208":{"code":"26","name":"Dr\u00f4me"},"273":{"code":"91","name":"Essonne"},"209":{"code":"27","name":"Eure"},"210":{"code":"28","name":"Eure-et-Loir"},"211":{"code":"29","name":"Finist\u00e8re"},"212":{"code":"30","name":"Gard"},"214":{"code":"32","name":"Gers"},"215":{"code":"33","name":"Gironde"},"250":{"code":"68","name":"Haut-Rhin"},"202":{"code":"2B","name":"Haute-Corse"},"213":{"code":"31","name":"Haute-Garonne"},"225":{"code":"43","name":"Haute-Loire"},"234":{"code":"52","name":"Haute-Marne"},"252":{"code":"70","name":"Haute-Sa\u00f4ne"},"256":{"code":"74","name":"Haute-Savoie"},"269":{"code":"87","name":"Haute-Vienne"},"186":{"code":"5","name":"Hautes-Alpes"},"247":{"code":"65","name":"Hautes-Pyr\u00e9n\u00e9es"},"274":{"code":"92","name":"Hauts-de-Seine"},"216":{"code":"34","name":"H\u00e9rault"},"217":{"code":"35","name":"Ille-et-Vilaine"},"218":{"code":"36","name":"Indre"},"219":{"code":"37","name":"Indre-et-Loire"},"220":{"code":"38","name":"Is\u00e8re"},"221":{"code":"39","name":"Jura"},"222":{"code":"40","name":"Landes"},"223":{"code":"41","name":"Loir-et-Cher"},"224":{"code":"42","name":"Loire"},"226":{"code":"44","name":"Loire-Atlantique"},"227":{"code":"45","name":"Loiret"},"228":{"code":"46","name":"Lot"},"229":{"code":"47","name":"Lot-et-Garonne"},"230":{"code":"48","name":"Loz\u00e8re"},"231":{"code":"49","name":"Maine-et-Loire"},"232":{"code":"50","name":"Manche"},"233":{"code":"51","name":"Marne"},"235":{"code":"53","name":"Mayenne"},"236":{"code":"54","name":"Meurthe-et-Moselle"},"237":{"code":"55","name":"Meuse"},"238":{"code":"56","name":"Morbihan"},"239":{"code":"57","name":"Moselle"},"240":{"code":"58","name":"Ni\u00e8vre"},"241":{"code":"59","name":"Nord"},"242":{"code":"60","name":"Oise"},"243":{"code":"61","name":"Orne"},"257":{"code":"75","name":"Paris"},"244":{"code":"62","name":"Pas-de-Calais"},"245":{"code":"63","name":"Puy-de-D\u00f4me"},"246":{"code":"64","name":"Pyr\u00e9n\u00e9es-Atlantiques"},"248":{"code":"66","name":"Pyr\u00e9n\u00e9es-Orientales"},"251":{"code":"69","name":"Rh\u00f4ne"},"253":{"code":"71","name":"Sa\u00f4ne-et-Loire"},"254":{"code":"72","name":"Sarthe"},"255":{"code":"73","name":"Savoie"},"259":{"code":"77","name":"Seine-et-Marne"},"258":{"code":"76","name":"Seine-Maritime"},"275":{"code":"93","name":"Seine-Saint-Denis"},"262":{"code":"80","name":"Somme"},"263":{"code":"81","name":"Tarn"},"264":{"code":"82","name":"Tarn-et-Garonne"},"272":{"code":"90","name":"Territoire-de-Belfort"},"277":{"code":"95","name":"Val-d'Oise"},"276":{"code":"94","name":"Val-de-Marne"},"265":{"code":"83","name":"Var"},"266":{"code":"84","name":"Vaucluse"},"267":{"code":"85","name":"Vend\u00e9e"},"268":{"code":"86","name":"Vienne"},"270":{"code":"88","name":"Vosges"},"271":{"code":"89","name":"Yonne"},"260":{"code":"78","name":"Yvelines"}}},"GA":{"name":"Gabon"},"GB":{"name":"United Kingdom"},"GD":{"name":"Grenada"},"GE":{"name":"Georgia"},"GF":{"name":"French Guiana"},"GG":{"name":"Guernsey"},"GH":{"name":"Ghana"},"GI":{"name":"Gibraltar"},"GL":{"name":"Greenland"},"GM":{"name":"Gambia"},"GN":{"name":"Guinea"},"GP":{"name":"Guadeloupe"},"GQ":{"name":"Equatorial Guinea"},"GR":{"name":"Greece","regions":{"887":{"code":"GR-69","name":"\u00c1gion \u00d3ros"},"874":{"code":"GR-A","name":"Anatolik\u00ed Makedon\u00eda kai Thr\u00e1ki"},"875":{"code":"GR-I","name":"Attik\u00ed"},"876":{"code":"GR-G","name":"Dytik\u00ed Ell\u00e1da"},"877":{"code":"GR-C","name":"Dytik\u00ed Makedon\u00eda"},"878":{"code":"GR-F","name":"Ion\u00eda N\u00edsia"},"879":{"code":"GR-D","name":"\u00cdpeiros"},"880":{"code":"GR-B","name":"Kentrik\u00ed Makedon\u00eda"},"881":{"code":"GR-M","name":"Kr\u00edti"},"882":{"code":"GR-L","name":"N\u00f3tio Aiga\u00edo"},"883":{"code":"GR-J","name":"Pelop\u00f3nnisos"},"884":{"code":"GR-H","name":"Stere\u00e1 Ell\u00e1da"}
7789,"885":{"code":"GR-E","name":"Thessal\u00eda"},"886":{"code":"GR-K","name":"V\u00f3reio Aiga\u00edo"}}},"GS":{"name":"South Georgia & South Sandwich Islands"},"GT":{"name":"Guatemala"},"GU":{"name":"Guam"},"GW":{"name":"Guinea-Bissau"},"GY":{"name":"Guyana","regions":{"888":{"code":"GY-BA","name":"Barima-Waini"},"889":{"code":"GY-CU","name":"Cuyuni-Mazaruni"},"890":{"code":"GY-DE","name":"Demerara-Mahaica"},"891":{"code":"GY-EB","name":"East Berbice-Corentyne"},"892":{"code":"GY-ES","name":"Essequibo Islands-West Demerara"},"893":{"code":"GY-MA","name":"Mahaica-Berbice"},"894":{"code":"GY-PM","name":"Pomeroon-Supenaam"},"895":{"code":"GY-PT","name":"Potaro-Siparuni"},"896":{"code":"GY-UD","name":"Upper Demerara-Berbice"},"897":{"code":"GY-UT","name":"Upper Takutu-Upper Essequibo"}}},"HK":{"name":"Hong Kong SAR China"},"HM":{"name":"Heard & McDonald Islands"},"HN":{"name":"Honduras"},"HR":{"name":"Croatia"},"HT":{"name":"Haiti"},"HU":{"name":"Hungary"},"ID":{"name":"Indonesia"},"IE":{"name":"Ireland"},"IL":{"name":"Israel"},"IM":{"name":"Isle of Man"},"IN":{"name":"India","regions":{"1072":{"code":"LA","name":"Ladakh"}}},"IO":{"name":"British Indian Ocean Territory"},"IQ":{"name":"Iraq"},"IR":{"name":"Iran"},"IS":{"name":"Iceland","regions":{"904":{"code":"IS-07","name":"Austurland"},"898":{"code":"IS-01","name":"H\u00f6fu\u00f0borgarsv\u00e6\u00f0i"},"903":{"code":"IS-06","name":"Nor\u00f0urland eystra"},"902":{"code":"IS-05","name":"Nor\u00f0urland vestra"},"905":{"code":"IS-08","name":"Su\u00f0urland"},"899":{"code":"IS-02","name":"Su\u00f0urnes"},"901":{"code":"IS-04","name":"Vestfir\u00f0ir"},"900":{"code":"IS-03","name":"Vesturland"}}},"IT":{"name":"Italy","regions":{"602":{"code":"AG","name":"Agrigento"},"603":{"code":"AL","name":"Alessandria"},"604":{"code":"AN","name":"Ancona"},"605":{"code":"AO","name":"Aosta"},"607":{"code":"AR","name":"Arezzo"},"608":{"code":"AP","name":"Ascoli-Piceno"},"609":{"code":"AT","name":"Asti"},"610":{"code":"AV","name":"Avellino"},"611":{"code":"BA","name":"Bari"},"612":{"code":"BT","name":"Barletta-Andria-Trani"},"613":{"code":"BL","name":"Belluno"},"614":{"code":"BN","name":"Benevento"},"615":{"code":"BG","name":"Bergamo"},"616":{"code":"BI","name":"Biella"},"617":{"code":"BO","name":"Bologna"},"618":{"code":"BZ","name":"Bolzano"},"619":{"code":"BS","name":"Brescia"},"620":{"code":"BR","name":"Brindisi"},"621":{"code":"CA","name":"Cagliari"},"622":{"code":"CL","name":"Caltanissetta"},"623":{"code":"CB","name":"Campobasso"},"624":{"code":"CI","name":"Carbonia Iglesias"},"625":{"code":"CE","name":"Caserta"},"626":{"code":"CT","name":"Catania"},"627":{"code":"CZ","name":"Catanzaro"},"628":{"code":"CH","name":"Chieti"},"629":{"code":"CO","name":"Como"},"630":{"code":"CS","name":"Cosenza"},"631":{"code":"CR","name":"Cremona"},"632":{"code":"KR","name":"Crotone"},"633":{"code":"CN","name":"Cuneo"},"634":{"code":"EN","name":"Enna"},"635":{"code":"FM","name":"Fermo"},"636":{"code":"FE","name":"Ferrara"},"637":{"code":"FI","name":"Firenze"},"638":{"code":"FG","name":"Foggia"},"639":{"code":"FC","name":"Forli-Cesena"},"640":{"code":"FR","name":"Frosinone"},"641":{"code":"GE","name":"Genova"},"642":{"code":"GO","name":"Gorizia"},"643":{"code":"GR","name":"Grosseto"},"644":{"code":"IM","name":"Imperia"},"645":{"code":"IS","name":"Isernia"},"606":{"code":"AQ","name":"L'Aquila"},"646":{"code":"SP","name":"La-Spezia"},"647":{"code":"LT","name":"Latina"},"648":{"code":"LE","name":"Lecce"},"649":{"code":"LC","name":"Lecco"},"650":{"code":"LI","name":"Livorno"},"651":{"code":"LO","name":"Lodi"},"652":{"code":"LU","name":"Lucca"},"653":{"code":"MC","name":"Macerata"},"654":{"code":"MN","name":"Mantova"},"655":{"code":"MS","name":"Massa-Carrara"},"656":{"code":"MT","name":"Matera"},"657":{"code":"VS","name":"Medio Campidano"},"658":{"code":"ME","name":"Messina"},"659":{"code":"MI","name":"Milano"},"660":{"code":"MO","name":"Modena"},"661":{"code":"MB","name":"Monza-Brianza"},"662":{"code":"NA","name":"Napoli"},"663":{"code":"NO","name":"Novara"},"664":{"code":"NU","name":"Nuoro"},"665":{"code":"OG","name":"Ogliastra"},"666":{"code":"OT","name":"Olbia Tempio"},"667":{"code":"OR","name":"Oristano"},"668":{"code":"PD","name":"Padova"},"669":{"code":"PA","name":"Palermo"},"670":{"code":"PR","name":"Parma"},"671":{"code":"PV","name":"Pavia"},"672":{"code":"PG","name":"Perugia"},"673":{"code":"PU","name":"Pesaro-Urbino"},"674":{"code":"PE","name":"Pescara"},"675":{"code":"PC","name":"Piacenza"},"676":{"code":"PI","name":"Pisa"},"677":{"code":"PT","name":"Pistoia"},"678":{"code":"PN","name":"Pordenone"},"679":{"code":"PZ","name":"Potenza"},"680":{"code":"PO","name":"Prato"},"681":{"code":"RG","name":"Ragusa"},"682":{"code":"RA","name":"Ravenna"},"683":{"code":"RC","name":"Reggio-Calabria"},"684":{"code":"RE","name":"Reggio-Emilia"},"685":{"code":"RI","name":"Rieti"},"686":{"code":"RN","name":"Rimini"},"687":{"code":"RM","name":"Roma"},"688":{"code":"RO","name":"Rovigo"},"689":{"code":"SA","name":"Salerno"},"690":{"code":"SS","name":"Sassari"},"691":{"code":"SV","name":"Savona"},"692":{"code":"SI","name":"Siena"},"693":{"code":"SR","name":"Siracusa"},"694":{"code":"SO","name":"Sondrio"},"695":{"code":"TA","name":"Taranto"},"696":{"code":"TE","name":"Teramo"},"697":{"code":"TR","name":"Terni"},"698":{"code":"TO","name":"Torino"},"699":{"code":"TP","name":"Trapani"},"700":{"code":"TN","name":"Trento"},"701":{"code":"TV","name":"Treviso"},"702":{"code":"TS","name":"Trieste"},"703":{"code":"UD","name":"Udine"},"704":{"code":"VA","name":"Varese"},"705":{"code":"VE","name":"Venezia"},"706":{"code":"VB","name":"Verbania"},"707":{"code":"VC","name":"Vercelli"},"708":{"code":"VR","name":"Verona"}
7789,"709":{"code":"VV","name":"Vibo-Valentia"},"710":{"code":"VI","name":"Vicenza"},"711":{"code":"VT","name":"Viterbo"}}},"JE":{"name":"Jersey"},"JM":{"name":"Jamaica"},"JO":{"name":"Jordan"},"JP":{"name":"Japan"},"KE":{"name":"Kenya"},"KG":{"name":"Kyrgyzstan"},"KH":{"name":"Cambodia"},"KI":{"name":"Kiribati"},"KM":{"name":"Comoros"},"KN":{"name":"St. Kitts & Nevis"},"KP":{"name":"North Korea"},"KR":{"name":"South Korea"},"KW":{"name":"Kuwait"},"KY":{"name":"Cayman Islands"},"KZ":{"name":"Kazakhstan"},"LA":{"name":"Laos"},"LB":{"name":"Lebanon"},"LC":{"name":"St. Lucia"},"LI":{"name":"Liechtenstein"},"LK":{"name":"Sri Lanka"},"LR":{"name":"Liberia"},"LS":{"name":"Lesotho"},"LT":{"name":"Lithuania","regions":{"475":{"code":"LT-AL","name":"Alytaus Apskritis"},"476":{"code":"LT-KU","name":"Kauno Apskritis"},"477":{"code":"LT-KL","name":"Klaip\u0117dos Apskritis"},"478":{"code":"LT-MR","name":"Marijampol\u0117s Apskritis"},"479":{"code":"LT-PN","name":"Panev\u0117\u017eio Apskritis"},"480":{"code":"LT-SA","name":"\u0160iauli\u0173 Apskritis"},"481":{"code":"LT-TA","name":"Taurag\u0117s Apskritis"},"482":{"code":"LT-TE","name":"Tel\u0161i\u0173 Apskritis"},"483":{"code":"LT-UT","name":"Utenos Apskritis"},"484":{"code":"LT-VL","name":"Vilniaus Apskritis"}}},"LU":{"name":"Luxembourg"},"LV":{"name":"Latvia","regions":{"471":{"code":"\u0100da\u017eu novads","name":"\u0100da\u017eu novads"},"366":{"code":"Aglonas novads","name":"Aglonas novads"},"367":{"code":"LV-AI","name":"Aizkraukles novads"},"368":{"code":"Aizputes novads","name":"Aizputes novads"},"369":{"code":"Akn\u012bstes novads","name":"Akn\u012bstes novads"},"370":{"code":"Alojas novads","name":"Alojas novads"},"371":{"code":"Alsungas novads","name":"Alsungas novads"},"372":{"code":"LV-AL","name":"Al\u016bksnes novads"},"373":{"code":"Amatas novads","name":"Amatas novads"},"374":{"code":"Apes novads","name":"Apes novads"},"375":{"code":"Auces novads","name":"Auces novads"},"376":{"code":"Bab\u012btes novads","name":"Bab\u012btes novads"},"377":{"code":"Baldones novads","name":"Baldones novads"},"378":{"code":"Baltinavas novads","name":"Baltinavas novads"},"379":{"code":"LV-BL","name":"Balvu novads"},"380":{"code":"LV-BU","name":"Bauskas novads"},"381":{"code":"Bever\u012bnas novads","name":"Bever\u012bnas novads"},"382":{"code":"Broc\u0113nu novads","name":"Broc\u0113nu novads"},"383":{"code":"Burtnieku novads","name":"Burtnieku novads"},"384":{"code":"Carnikavas novads","name":"Carnikavas novads"},"387":{"code":"LV-CE","name":"C\u0113su novads"},"385":{"code":"Cesvaines novads","name":"Cesvaines novads"},"386":{"code":"Ciblas novads","name":"Ciblas novads"},"388":{"code":"Dagdas novads","name":"Dagdas novads"},"355":{"code":"LV-DGV","name":"Daugavpils"},"389":{"code":"LV-DA","name":"Daugavpils novads"},"390":{"code":"LV-DO","name":"Dobeles novads"},"391":{"code":"Dundagas novads","name":"Dundagas novads"},"392":{"code":"Durbes novads","name":"Durbes novads"},"393":{"code":"Engures novads","name":"Engures novads"},"472":{"code":"\u0112rg\u013cu novads","name":"\u0112rg\u013cu novads"},"394":{"code":"Garkalnes novads","name":"Garkalnes novads"},"395":{"code":"Grobi\u0146as novads","name":"Grobi\u0146as novads"},"396":{"code":"LV-GU","name":"Gulbenes novads"},"397":{"code":"Iecavas novads","name":"Iecavas novads"},"398":{"code":"Ik\u0161\u0137iles novads","name":"Ik\u0161\u0137iles novads"},"399":{"code":"Il\u016bkstes novads","name":"Il\u016bkstes novads"},"400":{"code":"In\u010dukalna novads","name":"In\u010dukalna novads"},"401":{"code":"Jaunjelgavas novads","name":"Jaunjelgavas novads"},"402":{"code":"Jaunpiebalgas novads","name":"Jaunpiebalgas novads"},"403":{"code":"Jaunpils novads","name":"Jaunpils novads"},"357":{"code":"J\u0113kabpils","name":"J\u0113kabpils"},"405":{"code":"LV-JK","name":"J\u0113kabpils novads"},"356":{"code":"LV-JEL","name":"Jelgava"},"404":{"code":"LV-JL","name":"Jelgavas novads"},"358":{"code":"LV-JUR","name":"J\u016brmala"},"406":{"code":"Kandavas novads","name":"Kandavas novads"},"412":{"code":"K\u0101rsavas novads","name":"K\u0101rsavas novads"},"473":{"code":"\u0136eguma novads","name":"\u0136eguma novads"},"474":{"code":"\u0136ekavas novads","name":"\u0136ekavas novads"},"407":{"code":"Kokneses novads","name":"Kokneses novads"},"410":{"code":"LV-KR","name":"Kr\u0101slavas novads"},"408":{"code":"Krimuldas novads","name":"Krimuldas novads"},"409":{"code":"Krustpils novads","name":"Krustpils novads"},"411":{"code":"LV-KU","name":"Kuld\u012bgas novads"},"413":{"code":"Lielv\u0101rdes novads","name":"Lielv\u0101rdes novads"},"359":{"code":"LV-LPX","name":"Liep\u0101ja"},"360":{"code":"LV-LE","name":"Liep\u0101jas novads"},"417":{"code":"L\u012bgatnes novads","name":"L\u012bgatnes novads"},"414":{"code":"LV-LM","name":"Limba\u017eu novads"},"418":{"code":"L\u012bv\u0101nu novads","name":"L\u012bv\u0101nu novads"},"415":{"code":"Lub\u0101nas novads","name":"Lub\u0101nas novads"},"416":{"code":"LV-LU","name":"Ludzas novads"},"419":{"code":"LV-MA","name":"Madonas novads"},"421":{"code":"M\u0101lpils novads","name":"M\u0101lpils novads"},"422":{"code":"M\u0101rupes novads","name":"M\u0101rupes novads"},"420":{"code":"Mazsalacas novads","name":"Mazsalacas novads"},"423":{"code":"Nauk\u0161\u0113nu novads","name":"Nauk\u0161\u0113nu novads"},"424":{"code":"Neretas novads","name":"Neretas novads"},"425":{"code":"N\u012bcas novads","name":"N\u012bcas novads"},"426":{"code":"LV-OG","name":"Ogres novads"},"427":{"code":"Olaines novads","name":"Olaines novads"},"428":{"code":"Ozolnieku novads","name":"Ozolnieku novads"},"432":{"code":"P\u0101rgaujas novads","name":"P\u0101rgaujas novads"},"433":{"code":"P\u0101vilostas novads","name":"P\u0101vilostas novads"},"434":{"code":"P\u013cavi\u0146u novads","name":"P\u013cavi\u0146u novads"},"429":{"code":"LV-PR","name":"Prei\u013cu novads"},"430":{"code":"Priekules novads","name":"Priekules novads"},"431":{"code":"Prieku\u013cu novads","name":"Prieku\u013cu novads"},"435":{"code":"Raunas novads","name":"Raunas novads"},"361":{"code":"LV-REZ","name":"R\u0113zekne"},"442":{"code":"LV-RE","name":"R\u0113zeknes novads"},"436":{"code":"Riebi\u0146u novads","name":"Riebi\u0146u novads"},"362":{"code":"LV-RIX","name":"R\u012bga"},"363":{"code":"LV-RI","name":"R\u012bgas novads"},"437":{"code":"Rojas novads","name":"Rojas novads"},"438":{"code":"Ropa\u017eu novads","name":"Ropa\u017eu novads"},"439":{"code":"Rucavas novads","name":"Rucavas novads"},"440":{"code":"Rug\u0101ju novads","name":"Rug\u0101ju novads"},"443":{"code":"R\u016bjienas novads","name":"R\u016bjienas novads"},"441":{"code":"Rund\u0101les novads","name":"Rund\u0101les novads"},"444":{"code":"Salacgr\u012bvas novads","name":"Salacgr\u012bvas novads"},"445":{"code":"Salas novads","name":"Salas novads"},"446":{"code":"Salaspils novads","name":"Salaspils novads"},"447":{"code":"LV-SA","name":"Saldus novads"},"448":{"code":"Saulkrastu novads","name":"Saulkrastu novads"},"455":{"code":"S\u0113jas novads","name":"S\u0113jas novads"},"449":{"code":"Siguldas novads","name":"Siguldas novads"}
7789,"451":{"code":"Skr\u012bveru novads","name":"Skr\u012bveru novads"},"450":{"code":"Skrundas novads","name":"Skrundas novads"},"452":{"code":"Smiltenes novads","name":"Smiltenes novads"},"453":{"code":"Stopi\u0146u novads","name":"Stopi\u0146u novads"},"454":{"code":"Stren\u010du novads","name":"Stren\u010du novads"},"456":{"code":"LV-TA","name":"Talsu novads"},"458":{"code":"T\u0113rvetes novads","name":"T\u0113rvetes novads"},"457":{"code":"LV-TU","name":"Tukuma novads"},"459":{"code":"Vai\u0146odes novads","name":"Vai\u0146odes novads"},"460":{"code":"LV-VK","name":"Valkas novads"},"364":{"code":"Valmiera","name":"Valmiera"},"461":{"code":"LV-VM","name":"Valmieras novads"},"462":{"code":"Varak\u013c\u0101nu novads","name":"Varak\u013c\u0101nu novads"},"469":{"code":"V\u0101rkavas novads","name":"V\u0101rkavas novads"},"463":{"code":"Vecpiebalgas novads","name":"Vecpiebalgas novads"},"464":{"code":"Vecumnieku novads","name":"Vecumnieku novads"},"365":{"code":"LV-VEN","name":"Ventspils"},"465":{"code":"LV-VE","name":"Ventspils novads"},"466":{"code":"Vies\u012btes novads","name":"Vies\u012btes novads"},"467":{"code":"Vi\u013cakas novads","name":"Vi\u013cakas novads"},"468":{"code":"Vi\u013c\u0101nu novads","name":"Vi\u013c\u0101nu novads"},"470":{"code":"Zilupes novads","name":"Zilupes novads"}}},"LY":{"name":"Libya"},"MA":{"name":"Morocco"},"MC":{"name":"Monaco"},"MD":{"name":"Moldova"},"ME":{"name":"Montenegro"},"MF":{"name":"St. Martin"},"MG":{"name":"Madagascar"},"MH":{"name":"Marshall Islands"},"MK":{"name":"North Macedonia"},"ML":{"name":"Mali"},"MM":{"name":"Myanmar (Burma)"},"MN":{"name":"Mongolia"},"MO":{"name":"Macao SAR China"},"MP":{"name":"Northern Mariana Islands"},"MQ":{"name":"Martinique"},"MR":{"name":"Mauritania"},"MS":{"name":"Montserrat"},"MT":{"name":"Malta"},"MU":{"name":"Mauritius"},"MV":{"name":"Maldives"},"MW":{"name":"Malawi"},"MX":{"name":"Mexico","regions":{"493":{"code":"AGU","name":"Aguascalientes"},"494":{"code":"BCN","name":"Baja California"},"495":{"code":"BCS","name":"Baja California Sur"},"496":{"code":"CAM","name":"Campeche"},"497":{"code":"CHP","name":"Chiapas"},"498":{"code":"CHH","name":"Chihuahua"},"499":{"code":"CMX","name":"Ciudad de M\u00e9xico"},"500":{"code":"COA","name":"Coahuila"},"501":{"code":"COL","name":"Colima"},"502":{"code":"DUR","name":"Durango"},"503":{"code":"MEX","name":"Estado de M\u00e9xico"},"504":{"code":"GUA","name":"Guanajuato"},"505":{"code":"GRO","name":"Guerrero"},"506":{"code":"HID","name":"Hidalgo"},"507":{"code":"JAL","name":"Jalisco"},"508":{"code":"MIC","name":"Michoac\u00e1n"},"509":{"code":"MOR","name":"Morelos"},"510":{"code":"NAY","name":"Nayarit"},"511":{"code":"NLE","name":"Nuevo Le\u00f3n"},"512":{"code":"OAX","name":"Oaxaca"},"513":{"code":"PUE","name":"Puebla"},"514":{"code":"QUE","name":"Quer\u00e9taro"},"515":{"code":"ROO","name":"Quintana Roo"},"516":{"code":"SLP","name":"San Luis Potos\u00ed"},"517":{"code":"SIN","name":"Sinaloa"},"518":{"code":"SON","name":"Sonora"},"519":{"code":"TAB","name":"Tabasco"},"520":{"code":"TAM","name":"Tamaulipas"},"521":{"code":"TLA","name":"Tlaxcala"},"522":{"code":"VER","name":"Veracruz"},"523":{"code":"YUC","name":"Yucat\u00e1n"},"524":{"code":"ZAC","name":"Zacatecas"}}},"MY":{"name":"Malaysia"},"MZ":{"name":"Mozambique"},"NA":{"name":"Namibia"},"NC":{"name":"New Caledonia"},"NE":{"name":"Niger"},"NF":{"name":"Norfolk Island"},"NG":{"name":"Nigeria"},"NI":{"name":"Nicaragua"},"NL":{"name":"Netherlands"},"NO":{"name":"Norway"},"NP":{"name":"Nepal"},"NR":{"name":"Nauru"},"NU":{"name":"Niue"},"NZ":{"name":"New Zealand"},"OM":{"name":"Oman"},"PA":{"name":"Panama"},"PE":{"name":"Peru","regions":{"925":{"code":"PE-AMA","name":"Amazonas"},"926":{"code":"PE-ANC","name":"Ancash"},"927":{"code":"PE-APU","name":"Apur\u00edmac"},"928":{"code":"PE-ARE","name":"Arequipa"},"929":{"code":"PE-AYA","name":"Ayacucho"},"930":{"code":"PE-CAJ","name":"Cajamarca"},"931":{"code":"PE-CUS","name":"Cusco"},"932":{"code":"PE-CAL","name":"El Callao"},"933":{"code":"PE-HUV","name":"Huancavelica"},"934":{"code":"PE-HUC","name":"Hu\u00e1nuco"},"935":{"code":"PE-ICA","name":"Ica"},"936":{"code":"PE-JUN","name":"Jun\u00edn"},"937":{"code":"PE-LAL","name":"La Libertad"},"938":{"code":"PE-LAM","name":"Lambayeque"},"939":{"code":"PE-LIM","name":"Lima"},"940":{"code":"PE-LOR","name":"Loreto"},"941":{"code":"PE-MDD","name":"Madre de Dios"},"942":{"code":"PE-MOQ","name":"Moquegua"}
7789,"924":{"code":"PE-LMA","name":"Municipalidad Metropolitana de Lima"},"943":{"code":"PE-PAS","name":"Pasco"},"944":{"code":"PE-PIU","name":"Piura"},"945":{"code":"PE-PUN","name":"Puno"},"946":{"code":"PE-SAM","name":"San Mart\u00edn"},"947":{"code":"PE-TAC","name":"Tacna"},"948":{"code":"PE-TUM","name":"Tumbes"},"949":{"code":"PE-UCA","name":"Ucayali"}}},"PF":{"name":"French Polynesia"},"PG":{"name":"Papua New Guinea"},"PH":{"name":"Philippines"},"PK":{"name":"Pakistan"},"PL":{"name":"Poland","regions":{"712":{"code":"PL-02","name":"dolno\u015bl\u0105skie"},"713":{"code":"PL-04","name":"kujawsko-pomorskie"},"714":{"code":"PL-06","name":"lubelskie"},"715":{"code":"PL-08","name":"lubuskie"},"718":{"code":"PL-14","name":"mazowieckie"},"717":{"code":"PL-12","name":"ma\u0142opolskie"},"719":{"code":"PL-16","name":"opolskie"},"720":{"code":"PL-18","name":"podkarpackie"},"721":{"code":"PL-20","name":"podlaskie"},"722":{"code":"PL-22","name":"pomorskie"},"723":{"code":"PL-24","name":"\u015bl\u0105skie"},"724":{"code":"PL-26","name":"\u015bwi\u0119tokrzyskie"},"725":{"code":"PL-28","name":"warmi\u0144sko-mazurskie"},"726":{"code":"PL-30","name":"wielkopolskie"},"727":{"code":"PL-32","name":"zachodniopomorskie"},"716":{"code":"PL-10","name":"\u0142\u00f3dzkie"}}},"PM":{"name":"St. Pierre & Miquelon"},"PN":{"name":"Pitcairn Islands"},"PR":{"name":"Puerto Rico"},"PS":{"name":"Palestinian Territories"},"PT":{"name":"Portugal","regions":{"950":{"code":"PT-01","name":"Aveiro"},"951":{"code":"PT-02","name":"Beja"},"952":{"code":"PT-03","name":"Braga"},"953":{"code":"PT-04","name":"Bragan\u00e7a"},"954":{"code":"PT-05","name":"Castelo Branco"},"955":{"code":"PT-06","name":"Coimbra"},"956":{"code":"PT-07","name":"\u00c9vora"},"957":{"code":"PT-08","name":"Faro"},"958":{"code":"PT-09","name":"Guarda"},"959":{"code":"PT-10","name":"Leiria"},"960":{"code":"PT-11","name":"Lisboa"},"961":{"code":"PT-12","name":"Portalegre"},"962":{"code":"PT-13","name":"Porto"},"969":{"code":"PT-30","name":"Regi\u00e3o Aut\u00f3noma da Madeira"},"968":{"code":"PT-20","name":"Regi\u00e3o Aut\u00f3noma dos A\u00e7ores"},"963":{"code":"PT-14","name":"Santar\u00e9m"},"964":{"code":"PT-15","name":"Set\u00fabal"},"965":{"code":"PT-16","name":"Viana do Castelo"},"966":{"code":"PT-17","name":"Vila Real"},"967":{"code":"PT-18","name":"Viseu"}}},"PW":{"name":"Palau"},"PY":{"name":"Paraguay","regions":{"907":{"code":"PY-16","name":"Alto Paraguay"},"908":{"code":"PY-10","name":"Alto Paran\u00e1"},"909":{"code":"PY-13","name":"Amambay"},"906":{"code":"PY-ASU","name":"Asunci\u00f3n"},"910":{"code":"PY-19","name":"Boquer\u00f3n"},"911":{"code":"PY-5","name":"Caaguaz\u00fa"},"912":{"code":"PY-6","name":"Caazap\u00e1"},"913":{"code":"PY-14","name":"Canindey\u00fa"},"914":{"code":"PY-11","name":"Central"},"915":{"code":"PY-1","name":"Concepci\u00f3n"},"916":{"code":"PY-3","name":"Cordillera"},"917":{"code":"PY-4","name":"Guair\u00e1"},"918":{"code":"PY-7","name":"Itap\u00faa"},"919":{"code":"PY-8","name":"Misiones"},"920":{"code":"PY-12","name":"\u00d1eembuc\u00fa"},"921":{"code":"PY-9","name":"Paraguar\u00ed"},"922":{"code":"PY-15","name":"Presidente Hayes"},"923":{"code":"PY-2","name":"San Pedro"}}},"QA":{"name":"Qatar"},"RE":{"name":"R\u00e9union"},"RO":{"name":"Romania","regions":{"278":{"code":"AB","name":"Alba"},"279":{"code":"AR","name":"Arad"},"280":{"code":"AG","name":"Arge\u015f"},"281":{"code":"BC","name":"Bac\u0103u"},"282":{"code":"BH","name":"Bihor"},"283":{"code":"BN","name":"Bistri\u0163a-N\u0103s\u0103ud"},"284":{"code":"BT","name":"Boto\u015fani"},"286":{"code":"BR","name":"Br\u0103ila"},"285":{"code":"BV","name":"Bra\u015fov"},"287":{"code":"B","name":"Bucure\u015fti"},"288":{"code":"BZ","name":"Buz\u0103u"},"290":{"code":"CL","name":"C\u0103l\u0103ra\u015fi"},"289":{"code":"CS","name":"Cara\u015f-Severin"},"291":{"code":"CJ","name":"Cluj"},"292":{"code":"CT","name":"Constan\u0163a"},"293":{"code":"CV","name":"Covasna"},"294":{"code":"DB","name":"D\u00e2mbovi\u0163a"},"295":{"code":"DJ","name":"Dolj"},"296":{"code":"GL","name":"Gala\u0163i"},"297":{"code":"GR","name":"Giurgiu"},"298":{"code":"GJ","name":"Gorj"},"299":{"code":"HR","name":"Harghita"},"300":{"code":"HD","name":"Hunedoara"},"301":{"code":"IL","name":"Ialomi\u0163a"},"302":{"code":"IS","name":"Ia\u015fi"},"303":{"code":"IF","name":"Ilfov"},"304":{"code":"MM","name":"Maramure\u015f"},"305":{"code":"MH","name":"Mehedin\u0163i"},"306":{"code":"MS","name":"Mure\u015f"},"307":{"code":"NT","name":"Neam\u0163"},"308":{"code":"OT","name":"Olt"},"309":{"code":"PH","name":"Prahova"},"311":{"code":"SJ","name":"S\u0103laj"},"310":{"code":"SM","name":"Satu-Mare"},"312":{"code":"SB","name":"Sibiu"},"313":{"code":"SV","name":"Suceava"},"314":{"code":"TR","name":"Teleorman"},"315":{"code":"TM","name":"Timi\u015f"},"316":{"code":"TL","name":"Tulcea"},"318":{"code":"VL","name":"V\u00e2lcea"},"317":{"code":"VS","name":"Vaslui"},"319":{"code":"VN","name":"Vrancea"}}},"RS":{"name":"Serbia"},"RU":{"name":"Russia"},"RW":{"name":"Rwanda"},"SA":{"name":"Saudi Arabia"},"SB":{"name":"Solomon Islands"},"SC":{"name":"Seychelles"},"SD":{"name":"Sudan"},"SE":{"name":"Sweden","regions":{"980":{"code":"SE-K","name":"Blekinge l\u00e4n"}
7789,"981":{"code":"SE-W","name":"Dalarnas l\u00e4n"},"983":{"code":"SE-X","name":"G\u00e4vleborgs l\u00e4n"},"982":{"code":"SE-I","name":"Gotlands l\u00e4n"},"984":{"code":"SE-N","name":"Hallands l\u00e4n"},"985":{"code":"SE-Z","name":"J\u00e4mtlands l\u00e4n"},"986":{"code":"SE-F","name":"J\u00f6nk\u00f6pings l\u00e4n"},"987":{"code":"SE-H","name":"Kalmar l\u00e4n"},"988":{"code":"SE-G","name":"Kronobergs l\u00e4n"},"989":{"code":"SE-BD","name":"Norrbottens l\u00e4n"},"999":{"code":"SE-T","name":"\u00d6rebro l\u00e4n"},"1000":{"code":"SE-E","name":"\u00d6sterg\u00f6tlands l\u00e4n"},"990":{"code":"SE-M","name":"Sk\u00e5ne l\u00e4n"},"992":{"code":"SE-D","name":"S\u00f6dermanlands l\u00e4n"},"991":{"code":"SE-AB","name":"Stockholms l\u00e4n"},"993":{"code":"SE-C","name":"Uppsala l\u00e4n"},"994":{"code":"SE-S","name":"V\u00e4rmlands l\u00e4n"},"995":{"code":"SE-AC","name":"V\u00e4sterbottens l\u00e4n"},"996":{"code":"SE-Y","name":"V\u00e4sternorrlands l\u00e4n"},"997":{"code":"SE-U","name":"V\u00e4stmanlands l\u00e4n"},"998":{"code":"SE-O","name":"V\u00e4stra G\u00f6talands l\u00e4n"}}},"SG":{"name":"Singapore"},"SH":{"name":"St. Helena"},"SI":{"name":"Slovenia"},"SJ":{"name":"Svalbard & Jan Mayen"},"SK":{"name":"Slovakia"},"SL":{"name":"Sierra Leone"},"SM":{"name":"San Marino"},"SN":{"name":"Senegal"},"SO":{"name":"Somalia"},"SR":{"name":"Suriname","regions":{"970":{"code":"SR-BR","name":"Brokopondo"},"971":{"code":"SR-CM","name":"Commewijne"},"972":{"code":"SR-CR","name":"Coronie"},"973":{"code":"SR-MA","name":"Marowijne"},"974":{"code":"SR-NI","name":"Nickerie"},"975":{"code":"SR-PR","name":"Para"},"976":{"code":"SR-PM","name":"Paramaribo"},"977":{"code":"SR-SA","name":"Saramacca"},"978":{"code":"SR-SI","name":"Sipaliwini"},"979":{"code":"SR-WA","name":"Wanica"}}},"ST":{"name":"S\u00e3o Tom\u00e9 & Pr\u00edncipe"},"SV":{"name":"El Salvador"},"SY":{"name":"Syria"},"SZ":{"name":"Eswatini"},"TC":{"name":"Turks & Caicos Islands"},"TD":{"name":"Chad"},"TF":{"name":"French Southern Territories"},"TG":{"name":"Togo"},"TH":{"name":"Thailand"},"TJ":{"name":"Tajikistan"},"TK":{"name":"Tokelau"},"TL":{"name":"Timor-Leste"},"TM":{"name":"Turkmenistan"},"TN":{"name":"Tunisia"},"TO":{"name":"Tonga"},"TR":{"name":"Turkey"},"TT":{"name":"Trinidad & Tobago"},"TV":{"name":"Tuvalu"},"TW":{"name":"Taiwan"},"TZ":{"name":"Tanzania"},"UA":{"name":"Ukraine","regions":{"1025":{"code":"UA-43","name":"Avtonomna Respublika Krym"},"1001":{"code":"UA-71","name":"Cherkaska oblast"},"1002":{"code":"UA-74","name":"Chernihivska oblast"},"1003":{"code":"UA-77","name":"Chernivetska oblast"},"1004":{"code":"UA-12","name":"Dnipropetrovska oblast"},"1005":{"code":"UA-14","name":"Donetska oblast"},"1006":{"code":"UA-26","name":"Ivano-Frankivska oblast"},"1007":{"code":"UA-63","name":"Kharkivska oblast"},"1008":{"code":"UA-65","name":"Khersonska oblast"},"1009":{"code":"UA-68","name":"Khmelnytska oblast"},"1010":{"code":"UA-35","name":"Kirovohradska oblast"},"1026":{"code":"UA-30","name":"Kyiv"},"1011":{"code":"UA-32","name":"Kyivska oblast"},"1012":{"code":"UA-09","name":"Luhanska oblast"},"1013":{"code":"UA-46","name":"Lvivska oblast"},"1014":{"code":"UA-48","name":"Mykolaivska oblast"},"1015":{"code":"UA-51","name":"Odeska oblast"},"1016":{"code":"UA-53","name":"Poltavska oblast"},"1017":{"code":"UA-56","name":"Rivnenska oblast"},"1027":{"code":"UA-40","name":"Sevastopol"},"1018":{"code":"UA-59","name":"Sumska oblast"},"1019":{"code":"UA-61","name":"Ternopilska oblast"},"1020":{"code":"UA-05","name":"Vinnytska oblast"},"1021":{"code":"UA-07","name":"Volynska oblast"},"1022":{"code":"UA-21","name":"Zakarpatska oblast"},"1023":{"code":"UA-23","name":"Zaporizka oblast"},"1024":{"code":"UA-18","name":"Zhytomyrska oblast"}}},"UG":{"name":"Uganda"},"UM":{"name":"U.S. Outlying Islands"},"US":{"name":"United States","regions":{"1":{"code":"AL","name":"Alabama"},"2":{"code":"AK","name":"Alaska"},"3":{"code":"AS","name":"American Samoa"},"4":{"code":"AZ","name":"Arizona"},"5":{"code":"AR","name":"Arkansas"},"6":{"code":"AF","name":"Armed Forces Africa"},"7":{"code":"AA","name":"Armed Forces Americas"},"8":{"code":"AC","name":"Armed Forces Canada"},"9":{"code":"AE","name":"Armed Forces Europe"},"10":{"code":"AM","name":"Armed Forces Middle East"},"11":{"code":"AP","name":"Armed Forces Pacific"},"12":{"code":"CA","name":"California"},"13":{"code":"CO","name":"Colorado"},"14":{"code":"CT","name":"Connecticut"},"15":{"code":"DE","name":"Delaware"},"16":{"code":"DC","name":"District of Columbia"},"17":{"code":"FM","name":"Federated States Of Micronesia"}
7789,"18":{"code":"FL","name":"Florida"},"19":{"code":"GA","name":"Georgia"},"20":{"code":"GU","name":"Guam"},"21":{"code":"HI","name":"Hawaii"},"22":{"code":"ID","name":"Idaho"},"23":{"code":"IL","name":"Illinois"},"24":{"code":"IN","name":"Indiana"},"25":{"code":"IA","name":"Iowa"},"26":{"code":"KS","name":"Kansas"},"27":{"code":"KY","name":"Kentucky"},"28":{"code":"LA","name":"Louisiana"},"29":{"code":"ME","name":"Maine"},"30":{"code":"MH","name":"Marshall Islands"},"31":{"code":"MD","name":"Maryland"},"32":{"code":"MA","name":"Massachusetts"},"33":{"code":"MI","name":"Michigan"},"34":{"code":"MN","name":"Minnesota"},"35":{"code":"MS","name":"Mississippi"},"36":{"code":"MO","name":"Missouri"},"37":{"code":"MT","name":"Montana"},"38":{"code":"NE","name":"Nebraska"},"39":{"code":"NV","name":"Nevada"},"40":{"code":"NH","name":"New Hampshire"},"41":{"code":"NJ","name":"New Jersey"},"42":{"code":"NM","name":"New Mexico"},"43":{"code":"NY","name":"New York"},"44":{"code":"NC","name":"North Carolina"},"45":{"code":"ND","name":"North Dakota"},"46":{"code":"MP","name":"Northern Mariana Islands"},"47":{"code":"OH","name":"Ohio"},"48":{"code":"OK","name":"Oklahoma"},"49":{"code":"OR","name":"Oregon"},"50":{"code":"PW","name":"Palau"},"51":{"code":"PA","name":"Pennsylvania"},"52":{"code":"PR","name":"Puerto Rico"},"53":{"code":"RI","name":"Rhode Island"},"54":{"code":"SC","name":"South Carolina"},"55":{"code":"SD","name":"South Dakota"},"56":{"code":"TN","name":"Tennessee"},"57":{"code":"TX","name":"Texas"},"58":{"code":"UT","name":"Utah"},"59":{"code":"VT","name":"Vermont"},"60":{"code":"VI","name":"Virgin Islands"},"61":{"code":"VA","name":"Virginia"},"62":{"code":"WA","name":"Washington"},"63":{"code":"WV","name":"West Virginia"},"64":{"code":"WI","name":"Wisconsin"},"65":{"code":"WY","name":"Wyoming"}}},"UY":{"name":"Uruguay","regions":{"1028":{"code":"UY-AR","name":"Artigas"},"1029":{"code":"UY-CA","name":"Canelones"},"1030":{"code":"UY-CL","name":"Cerro Largo"},"1031":{"code":"UY-CO","name":"Colonia"},"1032":{"code":"UY-DU","name":"Durazno"},"1033":{"code":"UY-FS","name":"Flores"},"1034":{"code":"UY-FD","name":"Florida"},"1035":{"code":"UY-LA","name":"Lavalleja"},"1036":{"code":"UY-MA","name":"Maldonado"},"1037":{"code":"UY-MO","name":"Montevideo"},"1038":{"code":"UY-PA","name":"Paysandu"},"1039":{"code":"UY-RN","name":"R\u00edo Negro"},"1040":{"code":"UY-RV","name":"Rivera"},"1041":{"code":"UY-RO","name":"Rocha"},"1042":{"code":"UY-SA","name":"Salto"},"1043":{"code":"UY-SJ","name":"San Jos\u00e9"},"1044":{"code":"UY-SO","name":"Soriano"},"1045":{"code":"UY-TA","name":"Tacuaremb\u00f3"},"1046":{"code":"UY-TT","name":"Treinta y Tres"}}},"UZ":{"name":"Uzbekistan"},"VA":{"name":"Vatican City"},"VC":{"name":"St. Vincent & Grenadines"},"VE":{"name":"Venezuela","regions":{"1049":{"code":"VE-Z","name":"Amazonas"},"1050":{"code":"VE-B","name":"Anzo\u00e1tegui"},"1051":{"code":"VE-C","name":"Apure"},"1052":{"code":"VE-D","name":"Aragua"},"1053":{"code":"VE-E","name":"Barinas"},"1054":{"code":"VE-F","name":"Bol\u00edvar"},"1055":{"code":"VE-G","name":"Carabobo"},"1056":{"code":"VE-H","name":"Cojedes"},"1057":{"code":"VE-Y","name":"Delta Amacuro"},"1047":{"code":"VE-W","name":"Dependencias Federales"},"1048":{"code":"VE-A","name":"Distrito Capital"},"1058":{"code":"VE-I","name":"Falc\u00f3n"},"1059":{"code":"VE-J","name":"Gu\u00e1rico"},"1060":{"code":"VE-K","name":"Lara"},"1061":{"code":"VE-L","name":"M\u00e9rida"},"1062":{"code":"VE-M","name":"Miranda"},"1063":{"code":"VE-N","name":"Monagas"},"1064":{"code":"VE-O","name":"Nueva Esparta"},"1065":{"code":"VE-P","name":"Portuguesa"},"1066":{"code":"VE-R","name":"Sucre"},"1067":{"code":"VE-S","name":"T\u00e1chira"},"1068":{"code":"VE-T","name":"Trujillo"},"1069":{"code":"VE-X","name":"Vargas"},"1070":{"code":"VE-U","name":"Yaracuy"},"1071":{"code":"VE-V","name":"Zulia"}}},"VG":{"name":"British Virgin Islands"},"VI":{"name":"U.S. Virgin Islands"},"VN":{"name":"Vietnam"},"VU":{"name":"Vanuatu"},"WF":{"name":"Wallis & Futuna"},"WS":{"name":"Samoa"},"YE":{"name":"Yemen"},"YT":{"name":"Mayotte"},"ZA":{"name":"South Africa"},"ZM":{"name":"Zambia"},"ZW":{"name":"Zimbabwe"},"data_id":1791221171},"captcha":[],"instant-purchase":[],"loggedAsCustomer":[],"persistent":[],"review":[],"payments":[],"wishlist":{"items":[]},"recently_viewed_product":[],"recently_compared_product":[],"product_data_storage":[],"paypal-billing-agreement":[]}</script>
7789 7790</div>
7790<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"0d839bd02fea43dbbaf4faa0b06ba72a","r":1,"spa":2}' crossorigin="anonymous"></script>
7790 7791</body> 7792</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.