Help
RSS
API
Feed
Maltego
Contact
Domain > shop.widmann-stone.com
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2022-12-19
172.67.75.215
(
ClassC
)
2026-02-13
104.26.3.155
(
ClassC
)
Port 443
HTTP/1.1 200 OKDate: Fri, 13 Feb 2026 17:26:52 GMTContent-Type: text/html; charsetUTF-8Transfer-Encoding: chunkedConnection: keep-aliveServer: cloudflareexpires: Thu, 19 Nov 1981 08:52:00 GMTCache-Control: no-store, no-cache, must-revalidatepragma: no-cacheSet-Cookie: PHPSESSIDkuc80mqrej3d2ptrijloqee4fr; expiresFri, 20 Feb 2026 17:26:52 GMT; Max-Age604800; path/; domainshop.widmann-stone.com; secure; HttpOnly; SameSiteLaxvary: Accept-Encoding,User-AgentReport-To: {group:cf-nel,max_age:604800,endpoints:{url:https://a.nel.cloudflare.com/report/v4?s0LaaF%2BDkdh8hPlrXKebw354JodzSatgt1IF2VdXk31%2Fb%2FyAOMg07%2BJS4r34ngS%2B8J9mUXlB56g%2BLaGDhjJbbVe%2FHU4DDldfrAD%2FozzrXw8c7FGnk3A%3D%3D}}strict-transport-security: max-age0x-powered-by: PleskLinx-frame-options: sameorigincf-cache-status: DYNAMICNel: {report_to:cf-nel,success_fraction:0.0,max_age:604800}CF-RAY: 9cd6087e5b771319-PDXalt-svc: h3:443; ma86400 !DOCTYPE html>html langen>head> meta charsetUTF-8> meta nameviewport contentwidthdevice-width, initial-scale1.0> title>Natural Stone Online Gallery - Widmann Stone Snc./title>meta namedescription contentBuy natural stone online: Hard Rock, Limestone, Marble and more for home, garden and terrace. Find high-quality Blocks and Slabs from Widmann Stone Snc. in our live warehouse and request directly online.>meta namekeywords contentBuy natural stone online, Hard Rock, Limestone, Marble, Onyx, Quartzite, Resin-Bound Agglomerate, Travertine, Blocks, Slabs, Natural stone slabs, Natural stones for home and garden, Request natural stone slabs, Natural stone warehouse, affordable natural stones, Natural stone suppliers>meta propertyog:title contentNatural Stone Online Shop - Widmann Stone Snc.>meta propertyog:description contentBuy natural stone online: Hard Rock, Limestone, Marble and more for home, garden and terrace. Find high-quality Blocks and Slabs from Widmann Stone Snc. in our live warehouse and request directly online.>meta propertyog:type contentwebsite>meta propertyog:url contenthttps://shop.widmann-stone.com/>meta nametwitter:card contentsummary_large_image>meta nametwitter:title contentNatural Stone Online Shop - Widmann Stone Snc.>meta nametwitter:description contentBuy natural stone online: Hard Rock, Limestone, Marble and more for home, garden and terrace. Find high-quality Blocks and Slabs from Widmann Stone Snc. in our live warehouse and request directly online.>script typeapplication/ld+json>{ @context: https://schema.org, @type: Organization, name: Widmann Stone Snc., description: Buy natural stone online: Hard Rock, Limestone, Marble and more for home, garden and terrace. Find high-quality Blocks and Slabs from Widmann Stone Snc. in our live warehouse and request directly online., address: { @type: PostalAddress, streetAddress: Alte Landstrasse 29, addressLocality: I-39022 Algund, addressCountry: Italy }, url: https://shop.widmann-stone.com/, productSupplied: { @type: Product, name: Hard Rock, category: Blocks }, { @type: Product, name: Hard Rock, category: Slabs }, { @type: Product, name: Limestone, category: Slabs }, { @type: Product, name: Marble, category: Blocks }, { @type: Product, name: Marble, category: Slabs }, { @type: Product, name: Onyx, category: Slabs }, { @type: Product, name: Quartzite, category: Blocks }, { @type: Product, name: Quartzite, category: Slabs }, { @type: Product, name: Resin-Bound Agglomerate, category: Slabs }, { @type: Product, name: Travertine, category: Blocks }, { @type: Product, name: Travertine, category: Slabs } }/script> link relmodulepreload hrefhttps://unpkg.com/hyperapp@2.0.22/index.js> script srchttps://code.jquery.com/jquery-3.6.0.slim.min.js integritysha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI crossoriginanonymous>/script> link relstylesheet typetext/css href/assets/css/basic.css?v1769104539> link relstylesheet href/assets/fonts/fontawesome/css/all.min.css> style> #app { min-height: calc(100vh - 210px); } a.more { position: relative; padding-right: 15px; } a.more::after { content: ; position: absolute; top: 55%; right: 0; transform: translateY(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid var(--text); } a.more:hover::after { border-top: 5px solid var(--color); } .row.gap5 { gap: 5px; } .product-item { background: var(--slabdark); padding: 10px; border-radius: var(--radius); position: relative; border: 1px solid #7c7c7c40; display: grid; gap: 3px; align-content: space-between; } .product-item a{ cursor: pointer; } .product-item .usage_icon { width: 20px; height: 20px; display: flex; align-items: center; padding: 0 5px; justify-content: center; } .product-item .usage_icon i { color: var(--color); } .product-item .ellipsis { padding-bottom: 8px; } .product-item .usage_icon.wide { width: auto; height: 20px; font-weight: bold; font-size: 10px; line-height: 20px; border-radius: 5px; padding: 5px; } button.selected { background: #ffc98a; } img.product-image { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; cursor: pointer; } img.table-image { width: 100px; aspect-ratio: 3 / 2; object-fit: contain; } table { border-collapse: collapse; min-width: 100%; position: relative; } thead th { border: 1px solid #7c7c7c40; } tbody tr:last-child td{ border-bottom: 1px solid #7c7c7c40; } tr.item th { background: var(--table); } tr.item:nth-child(even) td, tbody tr.item:nth-child(even) th { background: color-mix(in srgb, #7c7c7c 2%, var(--table) 100%); } tr.item:nth-child(odd) td, tbody tr.item:nth-child(odd) th { background: color-mix(in srgb, #7c7c7c 10%, var(--table) 100%); } tr.item:hover td, tbody tr.item:hover th { background: color-mix(in srgb, #7c7c7c 15%, var(--table) 100%); } tr.item td, tr.item th { height: 46px; border-left: 1px solid #7c7c7c40; border-right: 1px solid #7c7c7c40; padding: 0 10px; text-align: left; white-space: nowrap; } td input:not(typecheckbox):not(typeradio) { /* background: transparent; */ /* border: 0; */ width: 50px; height: 28px; margin-top: 7px; } tr.item th.filter { cursor: pointer; position: relative; padding-right: 20px; } tr.item th.filter::after { content: ; position: absolute; top: 50%; right: 5px; transform: translateY(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid var(--button); } .sticky-end { position: -webkit-sticky; position: sticky; right: 0; } .table_container { max-width: 100%; overflow-x: scroll; position: relative; } .setinfo { width: 100%; height: auto; aspect-ratio: 4/1; background-size: contain; background-repeat: no-repeat; background-image: url(/assets/images/shop/setinfo.svg?v2); display: block; position: relative; background-position: center; } .blocks .setinfo { background-image: url(/assets/images/shop/setinfo_block.svg); } .setinfo .height, .setinfo .width, .setinfo .thickness, .setinfo .area, .setinfo .amount { position: absolute; font-size: 9px; } .setinfo svg { fill: var(--text); font-size: revert !important; } .setinfo .height { writing-mode: unset; transform: rotate(-90deg); left: -3.5%; bottom: 45%; top: auto; width: 13%; } .setinfo .width { top: 65%; left: 6%; width: 13%; } .setinfo .thickness { top: 37%; left: 29%; width: 15%; } .setinfo .area { top: 39%; left: 55.6%; width: 15%; } .setinfo .amount { top: 47%; left: 80.5%; width: 14%; } .setinfo .volume { position: absolute; top: 49%; left: 54.9%; width: 13%; } .setinfo .weight { position: absolute; top: 54%; left: 83.2%; width: 13%; } .dropdown_area { width: 100%; display: flex; gap: 10px; padding-bottom: 5px; padding-left: 0 !important; justify-content: flex-end; } .row.title.filter h2.mwfc { min-width: fit-content; } .dropdown { position: relative; text-transform: none; font-weight: normal; display: inline-block; width: 100%; max-width: min(calc((100vw - 540px) / 6), 200px); } .dropdown-header { background: url(data:image/svg+xml;utf8,svg xmlnshttp://www.w3.org/2000/svg fill%23F0F0F0 width50px height50px>polyline points46.139,15.518 25.166,36.49 4.193,15.519/>/svg>); background-repeat: no-repeat; background-position: right 9px top 5px; background-size: 17px 18px; padding: 5px 10px; padding-right: 35px; width: 100%; max-width: 200px; background-color: var(--input); cursor: pointer; display: flex; justify-content: space-between; align-items: center; border-radius: var(--radius) var(--radius) 0 0; } .dropdown.open .dropdown-header { /*border: 1px solid #7c7c7c60; border-bottom: 0;*/ } .cover_16_10{ aspect-ratio: 16 / 10; object-fit: cover; } .dropdown .dropdown-header { border: 1px solid transparent; border-bottom: 0; border-radius: var(--radius); } .dropdown-header span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--normal); } .dropdown-list { display: none; position: absolute; width: 100%; max-height: 200px; background-color: var(--input); z-index: 1; /* border: 1px solid #7c7c7c60; */ border-top: 0; border-radius: 5px; margin-top: -5px; } .dropdown-list input { width: 20px; padding-left: 5px; } .dropdown-list label { width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--normal); } .options-container { max-height: 200px; overflow-y: auto; overflow-x: hidden; padding-top: 13px; } .option { padding: 8px; padding-left: 13px; display: flex; align-items: flex-end; /* background: var(--chart_back); */ } .option input, .option label{ cursor: pointer; } .option label:hover { color: var(--color); } .option:nth-child(odd) { /*background: var(--input);*/ } .title.filter { gap: 20px; } .title.filter .dropdown_toggle { display: none; } .blink { animation: blinker 0.8s linear infinite; } @keyframes blinker { 50% { opacity: 0.5; } } a.ico { position: absolute; right: 0; top: 0; bottom: 0; background: #7c7c7c75; padding: 7px; display: flex; align-items: center; } a.ico i { font-size: 18px; top: 11px; color: var(--textdark); right: 10px; } .tag.type { position: relative; overflow: hidden; padding-right: 28px; font-weight: bold; } .mw25{ min-width: 25%; } .nowrap{ white-space: nowrap; } h3 { line-height: 1.5em; } .fixed_sidebar { position: fixed; top: 73px; bottom: 0; overflow-y: auto; padding-right: 10px; width: 250px; min-width: fit-content; min-height: calc(100vh - 210px); } .flex_spacer.w66_on_medium { max-width: calc(100vw - 250px); } .fixed_sidebar::-webkit-scrollbar { display: none; } .fixed_sidebar { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } @media only screen and (max-width: 820px) { .sidebar_ref{ display: none; } #app{ min-height: 200px; } .fixed_sidebar { position: relative; top: 0; bottom: auto; overflow-y: visible; padding-right: 0; width: 100%; min-height: 0; } .flex_spacer.w66_on_medium, .dropdown { max-width: none; } .sidebar-list-title{ cursor: pointer; padding: 8px 8px; } .sidebar-list-title::after { font-family: Font Awesome 6 Free; font-weight: 900; -webkit-font-smoothing: antialiased; content: \f107; right: 10px; position: absolute; padding-top: 2px; } .sidebar-list.open .sidebar-list-title::after { content: \f106; } .sidebar-list{ height: 37px; overflow: hidden; } .sidebar-list.open{ height: auto; overflow: auto; } } tr.item:nth-child(odd) td input:not(typecheckbox):not(typeradio), tbody tr.item:hover th input:not(typecheckbox):not(typeradio) { background: color-mix(in srgb, var(--text) 10%, var(--table) 100%); } tr.item:nth-child(odd) td button:not(:hover,.button_orange), tbody tr.item:hover th button:not(:hover){ background: color-mix(in srgb, var(--text) 10%, var(--table) 100%); } tr.item:hover td button:not(:hover), tr.item:hover td input:not(typecheckbox):not(typeradio){ background: color-mix(in srgb, var(--text) 20%, var(--table) 100%); } @media only screen and (max-width: 1000px) { .grid.slab_view { grid-template-columns: repeat(auto-fill, calc(50% - 5px)); } .w33_on_medium { width: 33%; } .w66_on_medium { width: 67%; } } @media only screen and (max-width: 820px) { .grid.slab_view.grid_100_on_mobile { /*grid-template-columns: repeat(auto-fill, calc(50% - 5px));*/ grid-template-columns: repeat(auto-fill, calc(100%)); overflow: hidden; } .title.filter { display: grid; grid-template-columns: 1fr 40px; grid-column-gap: 0px; grid-row-gap: 0px; } .title.filter .dropdown_toggle { grid-area: 1 / 2 / 2 / 3; display: grid; justify-content: end; align-items: center; } .title.filter .dropdown_toggle i { cursor: pointer; } .title.filter .dropdown_area { grid-area: 2 / 1 / 3 / 3; display: none; gap: 5px; flex-direction: column; } .dropdown-header { max-width: 100%; } .flex_spacer.w66_on_medium.table { padding-left: 10px; padding-right: 10px; } } /style> link relapple-touch-icon sizes180x180 href/assets/images/icons/0/apple-touch-icon.png>link relicon typeimage/png sizes32x32 href/assets/images/icons/0/favicon-32x32.png>link relicon typeimage/png sizes16x16 href/assets/images/icons/0/favicon-16x16.png>link relmanifest href/assets/images/icons/0/site.webmanifest>link relmask-icon href/assets/images/icons/0/safari-pinned-tab.svg color#2e2e2e>link relshortcut icon href/assets/images/icons/0/favicon.ico>meta namemsapplication-TileColor content#2e2e2e>meta namemsapplication-config content/assets/images/icons/0/browserconfig.xml>meta nametheme-color content#2e2e2e>/head>body> div classheader header_outer> div classwrap> div classheader_inner> div styledisplay: flex; align-items: center;> a href/> img classlogo src/assets/images/logos/17_light.png?1769104539 altLogo> /a> /div> div styledisplay: flex;justify-content: flex-end;align-items: center;> div classheader_icon open_match hide color data-blinktrue titleMatch stylemargin: -1px 20px 0px -10px;>i classfas fa-star>/i>/div> div classmatch_content reset head_dropdown empty hide> div classrow> div classflex_spacer bold style line-height: 19px; padding: 8px;>Favorites/div> div classw12_5 w50_on_mobile>button data-actiongallery_match_discard data-blinktrue>Clear Favorites/button>/div> /div> div classmatch_target grid slab_view pt0 grid_50_on_mobile mt5>/div> /div> div classcart_icon hide onclickwindow.location.href/cart data-blinktrue titleCart>i classfas fa-truck-moving color stylepadding: 10px 13px 10px 10px;>/i> div classnumber data-targetcart_amount>/div> /div> !--span classnotification_arrow styledisplay: none;>/span>--> !--div classlanguage_content hide reset head_dropdown menuli> ul> a href# classdropdown-item data-langen>li>i classfas fa-language>/i>English/li>/a> a href# classdropdown-item data-langde>li>i classfas fa-language>/i>German/li>/a> a href# classdropdown-item data-langit>li>i classfas fa-language>/i>Italian/li>/a> /ul> /div>--> button classbutton_orange onclickwindow.open(/login, _self) stylefont-weight: bold;padding: 5px;text-transform: uppercase;>Login/button> a classlarge_icon idmenu titleMenu >i classfas fa-bars styletransform: scaleX(1.5);padding: 10px 15px 10px 15px;>/i>/a> div classmenu menuli styledisplay: none;> ul> a href/shop>li>i classfas fa-th>/i>Stone Gallery/li>/a> a classlanguage_trigger>li>i classfas fa-language>/i>English/li>/a> div classlanguage_content reset hide> a href# classdropdown-item data-langen>li>i classfas fa-circle color>/i>English/li>/a> a href# classdropdown-item data-langde>li>i classfas fa-circle >/i>German/li>/a> a href# classdropdown-item data-langit>li>i classfas fa-circle >/i>Italian/li>/a> a href# classdropdown-item data-langfr>li>i classfas fa-circle >/i>French/li>/a> a href# classdropdown-item data-langpt>li>i classfas fa-circle >/i>Portuguese/li>/a> /div> a href/login stylefont-weight: normal;>li>i classfas fa-sign-in-alt>/i>Login/li>/a> /ul> /div> /div> /div> /div>/div>script typetext/javascript> $(function(){ $(document).on(click, .open_match, function(e){ e.stopPropagation(); e.preventDefault(); $(.notification_content).hide(); $(.notification_icon, #menu, .open_share).removeClass(active); if($(this).is(.active)){ $(.notification_content, .notification_arrow, .menu, .notification_arrow, .header .link_content, .match_content, .header .language_content).hide(); $(this).removeClass(active); $(.wrap).removeClass(notifications_open); var inital_padding parseInt($(body > .wrap).css(paddingTop)); $(body > .wrap).removeAttr(style); if(window.scrollY ! 0) window.scrollBy(0, (parseInt($(body > .wrap).css(paddingTop))-inital_padding)); }else{ $(.notification_arrow, .match_content).show(); $(.menu, .header .link_content).hide(); var wrap $(.header .wrap); var icon $(.open_match).first(); var arrow $(.notification_arrow).first(); var pos (icon.offset().left-wrap.offset().left+icon.width()/2)-arrow.width()/2; $(.menu).css({minWidth: (pos-wrap.width()+$(.notification_arrow).first().width()+20)+px, top: 70px}); $(.notification_arrow).css(left, pos+px); $(this).addClass(active); setTimeout(function(){ var inital_padding parseInt($(body > .wrap).removeAttr(style).css(paddingTop)); $(body > .wrap).css(paddingTop, (inital_padding+$(.match_content).outerHeight()-($(.branding:visible).length0?0:$(.branding).height()))+px); if(window.scrollY ! 0){ window.scrollBy(0, -(inital_padding-parseInt($(body > .wrap).css(paddingTop)))); } },25); } }); $(body).on(click, .language_content a, function(e){ e.preventDefault(); var lang $(this).attr(data-lang); if (lang) { var url window.location.href; url url.replace(/&?lang^&*/, ); if (url.slice(-1) ?) { url url.slice(0, -1); } url + (url.indexOf(?) -1 ? ? : &) + `lang${lang}`; window.location.href url; } }) $(document).on(click, .open_share, function(e){ e.stopPropagation(); e.preventDefault(); if($(.open_match).is(.active)){ $(.open_match).trigger(click); } $(.notification_content, .header .language_content).hide(); $(.notification_icon, #menu, .language_trigger).removeClass(active); if($(this).is(.active)){ $(.notification_content, .notification_arrow, .menu, .notification_arrow, .header .link_content, .header .language_content).hide(); $(this).removeClass(active); $(.wrap).removeClass(notifications_open); }else{ $(.notification_arrow, .header .link_content).show(); $(.notification_arrow, .header .link_content).css({top: 60px}); $(.menu).hide(); var wrap $(.header .wrap); var icon $(.open_share).first(); var arrow $(.notification_arrow).first(); var pos (icon.offset().left-wrap.offset().left+icon.width()/2)-arrow.width()/2; $(.menu).css({minWidth: (pos-wrap.width()+$(.notification_arrow).first().width()+20)+px, top: 60px}); $(.notification_arrow).css(left, pos+px); $(this).addClass(active); $(.wrap).addClass(notifications_open); } }); $(document).on(click, .language_trigger, function(e){ $(.notification_arrowX, .header .language_content).show(); e.stopPropagation(); }); $(body).on(click, .share, function(){ var type $(this).attr(data-type); var link_box $(input.copy_link); var link link_box.val(); if(link ){ link window.location.href; link_box.val(link) } if(type link){ link_box0.select(); link_box0.setSelectionRange(0, 99999); document.execCommand(copy); $(.copy_message).show(); $(.copy_message .text).text(Link copied to the clipboard.); }else if(type newsletter){ window.location.href /newsletter?from+encodeURIComponent(link); }else{ var template $(this).attr(data-href).replace(LINK, encodeURIComponent(link)); window.open(template, _blank); $(.copy_message .text).text(Thank you!); } setTimeout(function(){ $(.copy_message).hide(); if($(.open_share.active).length>0){ $(.notification_arrow, .header .link_content).hide(); $(.open_share).removeClass(active); $(.wrap).removeClass(notifications_open); } }, 3000) }) $(body).on(click, .share_newsletter, function(){ }) $(body).on(change, select#workspace, function(){ if($(this).val() ! Menu) window.location.href $(this).val(); }); $(document).on(click, .notification_trigger, body, function(e){ if($(this).is(body) || $(.notification_icon).is(.active) || $(.language_trigger).is(.active)){ if($(e.target).parents(.head_dropdown).length 0 && !$(.open_match).is(.active)){ $(.notification_content, .notification_arrow, .menu, .header .link_content, .header .language_content).hide(); $(.notification_icon, a#menu, .open_share, .language_trigger).removeClass(active); $(.wrap).removeClass(notifications_open); } $(.notification_icon, .language_trigger).removeClass(active); }else{ e.stopPropagation(); e.preventDefault(); if($(.open_match).is(.active)){ $(.open_match).trigger(click); } $(.open_share, #menu, .language_trigger).removeClass(active); $(.menu).hide(); $(.link_content).hide(); $(.notification_content, .notification_arrow).show(); var wrap $(.header .wrap); var icon $(.notification_icon).first(); var arrow $(.notification_arrow).first(); var pos (icon.offset().left-wrap.offset().left+icon.width()/2)-arrow.width()/2; $(.notification_content).css({minWidth: (pos-wrap.width()+$(.notification_arrow).first().width()+20)+px, top: $(.header_inner).height()+px}); $(.notification_arrow).css(left, pos+px); $(.notification_icon).addClass(active); $(.wrap).addClass(notifications_open); } }); $(body).on(click, .notification_content adata-n-action, function(e){ e.stopPropagation(); var id $(this).attr(data-id); var action $(this).attr(data-n-action); if(action seen){ $(this).parents(.single_notification).removeClass(new); var num_new_notifications $(.single_notification.new).length; $(.num_new_notifications).text(num_new_notifications); if(num_new_notifications 0){ $(.notification_trigger).removeClass(new); } } if(action delete){ if($(this).parents(.notification_content).find(.single_notification).length 1){ $(.empty_notifications).show(); } $(this).parents(.single_notification).remove(); } $.post( async/notifications, { action: action, id: id }); }); $(body).on(click, .notification_content .single_notification, function(){ if($(this).is(.new)){ $.post( async/notifications, { action: seen, id: $(this).attr(data-id) }); } window.location.href $(this).attr(data-href); }) // dropdown menu $(document).on(click, a#menu, function(e){ e.stopPropagation(); e.preventDefault(); if($(.open_match).is(.active)){ $(.open_match).trigger(click); } $(.notification_content, .language_content).hide(); $(.notification_icon, .open_share, .language_trigger).removeClass(active); if($(this).is(.active)){ $(.menu, .notification_arrow, .header .link_content, .header .language_content).hide(); $(this).removeClass(active); $(.wrap).removeClass(notifications_open); }else{ $(.menu, .notification_arrow).show(); $(.link_content).hide(); var wrap $(.header .wrap); var icon $(a#menu).first(); var arrow $(.notification_arrow).first(); var pos (icon.offset().left-wrap.offset().left+icon.width()/2)-arrow.width()/2; $(.menu).css({minWidth: (pos-wrap.width()+$(.notification_arrow).first().width()+200)+px, top: $(.header_inner).height()+px}); $(.notification_arrow).css(left, pos+px); $(this).addClass(active); $(.wrap).addClass(notifications_open); } }); });/script> div classwrap> div idapp>/div> /div> script typemodule> import { h, text, app, memo } from https://unpkg.com/hyperapp@2.0.22/index.js // Permission flags from PHP const HAS_SALES_PERMISSION false; const HAS_OPERATIONS_PERMISSION false; function getFiltersFromURL() { let filters ; let urlParams new URLSearchParams(window.location.search); urlParams.forEach((value, key) > { let filterItems value.split(,).map(v > ({ value: v, selected: true })); filters.push({ id: key, items: filterItems }); }); return filters; } // State var initialState { hero: , materials: , products: , filters: getFiltersFromURL(), actions: , search: , mode: , permissions: { sales: HAS_SALES_PERMISSION, operations: HAS_OPERATIONS_PERMISSION } } window.suffix ; let trade_name_shown false; let init true; window.addEventListener(beforeunload, () > { let caches JSON.parse(sessionStorage.getItem(shopCaches) ?? {}); if (cacheswindow.location.search) { cacheswindow.location.search.scroll window.scrollY; sessionStorage.setItem(shopCaches, JSON.stringify(caches)); } }); // Actions const SetHero (state, hero) > ({ ...state, hero }) const SetMaterials (state, materials) > ({ ...state, materials }) const SetProducts (state, products) > ({ ...state, products }) const SetProductsPartial (state, products, partial_id) > { var newState { ...state }; const productMap new Map(newState.products.map((sproduct, index) > sproduct.id, index)); for (let product of products) { if (productMap.has(product.id) && product.id partial_id) { const index productMap.get(product.id); newState.productsindex { ...newState.productsindex, ...product }; } } return newState; }; const SetFiltes (state, filters, partial_id) > { if (partial_id) { for (let f of state.filters) { if (f.id.startsWith(g_) && !f.id.startsWith(`g_${partial_id}`)) filters.push(f); } } return { ...state, filters }; } const SetUrl (state, filters, search, mode) > { var newState { ...state, mode: mode }; var url MakeUrl(state, filters, search, mode); window.cache.state { ...state, filters }; if(url ! window.location.href.replace(/\?$/, )){ if (window.history && window.history.pushState) { window.history.pushState(window.cache.state, document.title, url); } else { window.location.href url; } } return { ...newState, filters }; } const MakeUrl (state, filters false, search false, mode false) > { if (!filters) filters state.filters; if (!search) search state.search; let params ; let suffix {}; let tags ; let thicknesses ; for (let it of filters) { let fs it.items && Array.isArray(it.items) ? it.items.filter(v > v.selected).map(v > v.value).sort().join(,) : it.value; if (fs ! ) { params.push(it.id + + fs); } // Handle projects filter if (it.id projects) { if (fs 1) { suffix.usage projects; } } // Handle project_id filter Handle module_id filter if (it.id project_id || it.id module_id || it.id overlay || it.id offer_instance) { if (fs) { suffixit.id fs; } } // Collect tags from surface filters if (it.id.includes(surface) && Array.isArray(it.items)) { for (let item of it.items) { if (item.selected) { tags.push(item.value); } } } // Collect thicknesses from thickness filters if (it.id.includes(z) && Array.isArray(it.items)) { for (let item of it.items) { if (item.selected) { thicknesses.push(item.value); } } } } // Add tags to suffix if there are any if (tags.length > 0) { suffix.tags tags.join(,); } // Add thicknesses to suffix if there are any if (thicknesses.length > 0) { suffix.thickness thicknesses.join(,); } // Build the suffix string window.suffix &+(new URLSearchParams(suffix).toString()); if (search ! ) { params.push(search + encodeURIComponent(search)); } if (mode ! ) { params.push(mode + encodeURIComponent(mode)); } let url window.location.href.split(?)0 + (params.length > 0 ? (? + params.sort().join(&)) : ); return url; } const SetActions (state, actions) > ({ ...state, actions }) // Effects let currentAbortController null; const LoadEffect ({ filters, actions, search, mode }) > (dispatch) > { // Abort the previous request if it exists if (actions && actions.length 0 && currentAbortController) { currentAbortController.abort(); } // Create a new AbortController for the current request currentAbortController new AbortController(); const { signal } currentAbortController; const url new URL(/async/shop, window.location.origin); if (filters) url.searchParams.append(filters, JSON.stringify(filters)); let prev_actions false; if (actions) { prev_actions actions; url.searchParams.append(actions, JSON.stringify(actions)); dispatch(SetActions, ); } // Query Cache for Page dispatch(CacheState, false); if (search) url.searchParams.append(search, search); if (mode) url.searchParams.append(mode, mode); fetch(url, { signal }) .then(response > response.json()) .then(data > { ProcessState(data)(dispatch); // Set Cache for Page dispatch(CacheState, true); init false; }) .catch(error > { if (error.name ! AbortError) { console.error(Failed to load products:, error); setTimeout(function () { prev_actions ? dispatch(SetActions, prev_actions) : 0; LoadEffect({ filters: filters, actions: actions, search: search })(dispatch); }, 500); } }) }; const CacheState (state, set false) > (dispatch) > { if (set) { window.cache.scroll window.scrollY; window.cache.state state; // Store the current state let caches JSON.parse(sessionStorage.getItem(shopCaches) ?? {}); cacheswindow.location.search window.cache; sessionStorage.setItem(shopCaches, JSON.stringify(caches)); console.log(SET STATE CACHE); return state; // Return state directly, not in an array } else { let newState { ...state }; let url encodeURI(MakeUrl(state).split(window.location.host+window.location.pathname)1); let caches JSON.parse(sessionStorage.getItem(shopCaches) ?? {}); window.cache {}; if (cachesurl) { window.cache cachesurl; if (init) { window.programmaticScroll true; window.scrollTo(0, window.cache.scroll); // Use window.cache.scroll instead of cache.scroll } if (window.cache.state) newState window.cache.state; } return newState; // Return newState directly, not in an array } } const ProcessState (data) > (dispatch) > { dispatch(SetMaterials, data.materials); dispatch(SetHero, data.hero || ); if (data.partial) { dispatch(SetProductsPartial, data.products, data.partial); } if (!data.partial) { dispatch(SetProducts, data.products); } if (data.notification) { alert(data.notification); } dispatch(SetFiltes, data.filters, data.partial); dispatch(SetUrl, data.filters, data.search, data.mode); // Scroll to top after data loads if flag is set if (window.scrollToTopAfterLoad) { window.scrollToTopAfterLoad false; requestAnimationFrame(() > { window.programmaticScroll true; window.scrollTo(0, 0); }); } if (data.redirect) { window.location.href data.redirect.replace({src-url}, encodeURIComponent(window.location.pathname+window.location.search)); } } // Custom debounce function let timeoutId; const debounce (fn, ms) > { return (...args) > { clearTimeout(timeoutId); return (dispatch, props) > { timeoutId setTimeout(() > { const result fn(...args); if (typeof result function) { result(dispatch, props); } else { dispatch(result); } }, ms); }; }; }; // Modified SetSearchTerm function const SetSearchTerm (state, event) > { const newState { ...state, search: event.target.value }; return newState, debounce(LoadEffect, 250)(newState) ; }; // Views const SlabItem ({ id, block_name, slab_name, amount, area, height, width, thickness, image, currency, usage, price, unit, type }, group_id) > { if (thickness.includes(,)) { thickness thickness.split(,); let min Math.min(...thickness); let max Math.max(...thickness); thickness (parseInt(min) / 10) + - + (parseInt(max) / 10) } else { thickness parseInt(thickness) / 10 } return h(div, { class: product-item }, !trade_name_shown&&type?h(div, {class: row gap5}, h(h4, { class: ellipsis flex_spacer }, text(type)) ):null, h(div, {class: row gap5}, h(h3, { class: pb5 flex_spacer }, text(block_name)), ...UsageIcons(usage, price, currency, unit, image) ), h(a, { href: `/item?id${id}${window.suffix??}`, onclick: (state, event) > { event.target.classList.add(blink); return state; } }, h(img, { src: image, class: product-image }), ), h(div, { class: setinfo }, SvgText(`${parseInt(height / 10)}cm`, height), SvgText(`${parseInt(width / 10)}cm`, width), SvgText(`${thickness}cm`, thickness), SvgText(`${parseInt(area / 1000000)}m²`, area), SvgText(parseFloat(amount).toFixed(0), amount), ), ) } const UsageIcons (usage, price, currency, unit, image) > { let icons ; if(price){ icons.push(h(span, {class: right flex_spacer}, text(`${parseFloat(price).toFixed(2)} ${currency}/${unit}`))); return icons; } for (var i usage.length - 1; i > 0; i--) { if(usagei cart){ icons.push(h(div, {class: usage_icon, title: View Cart}, h(a, {href: /cart}, h(i, {class: fas fa-truck-moving})) )); }else if(usagei reserved){ icons.push(h(div, {class: usage_icon, title: Reserved}, h(i, {class: fas fa-registered}))); }else if(usagei prio){ icons.push(h(div, {class: usage_icon, title: Prioritized}, h(i, {class: fas fa-angle-double-up}))); }else if(usagei hidden){ icons.push(h(div, {class: usage_icon, title: Hidden}, h(i, {class: fas fa-eye-slash}))); }else if(usagei time){ icons.push(h(div, {class: usage_icon, title: Sale}, h(i, {class: fas fa-clock}))); }else if(usagei.startsWith(/project)){ icons.push(h(div, {class: usage_icon, title: Used in project}, h(a, {href: usagei}, h(i, {class: fas fa-building active})) )); }else if(usagei.startsWith(/offers)){ icons.push(h(div, {class: usage_icon, title: Offer requested}, h(a, {href: usagei}, h(i, {class: fas fa-box-open active})) )); }else if(usagei.startsWith(S)){ icons.push(h(div, {class: usage_icon wide}, text(usagei))); } } if (image) { if (image.includes(typeslab)) { icons.push(h(div, { class: usage_icon, title: Slab photo }, h(i, { class: fas fa-vector-square }) // Slab )); } else if (image.includes(typeblock)) { icons.push(h(div, { class: usage_icon, title: Block photo }, h(i, { class: fas fa-cube }) // Block )); } else if (image.includes(typetype)) { icons.push(h(div, { class: usage_icon, title: Example image }, h(i, { class: fas fa-image }) // Symbolic material image )); } } return icons; } const SvgText (content, name) > h(svg, { viewBox: 0 0 50 17, class: name }, h(text, { text-anchor: middle, x: 50%, y: 75% }, text(content)) ) const BlockItem ({ id, block_name, amount, area, height, width, thickness, image, currency, usage, price, unit, type }, group_id) > h(div, { class: product-item gap5 }, !trade_name_shown&&type?h(div, {class: row gap5}, h(h4, { class: ellipsis flex_spacer }, text(type)) ):null, h(div, {class: row}, h(h3, { class: pb5 flex_spacer }, text(block_name)), ...UsageIcons(usage, price, currency, unit, image) ), h(a, { href: `/item?id${id}${window.suffix??}&blocks1`, onclick: (state, event) > { event.target.classList.add(blink); return state; } }, h(img, { src: image, class: product-image }), ), h(div, { class: setinfo }, SvgText(`${parseInt(height / 10)}cm`, height), SvgText(`${parseInt(width / 10)}cm`, width), SvgText(`${thickness / 10}cm`, thickness), SvgText(`${parseInt(amount / 100000000) / 10}m³`, volume), SvgText(`${parseInt(area / 1000000000)}t`, weight), ), ) const TableItem ({ block_name, amount, height, width, thickness, image }, group_id) > h(tr, { class: item }, h(td, {}, h(img, { src: image, class: table-image }) ), h(td, {}, text(block_name)), h(td, {}, text(amount)), h(td, {}, text(`${parseInt(width / 10)}cm`)), h(td, {}, text(`${parseInt(height / 10)}cm`)), h(td, {}, text(`${parseInt(thickness / 10)}cm`)), ) const TableBoardsItem ({ id, block_name, amount, currency, unit, height, width, thickness, price, surface, warehouse, image, selected, type }, group_id, show_image false) > h(tr, { class: item }, show_image ? h(td, {}, h(img, { src: image, class: table-image }) ) : null, h(td, {}, text(`${parseInt(amount * 100) / 100} ${unit}`)), h(td, {}, text(`${isNaN(width) ? width : parseInt(width / 10)} x ${parseInt(height / 10)} cm`)), h(td, {}, text(`${parseInt(thickness) / 10} cm`)), h(td, {}, text(surface)), !trade_name_shown&&type?h(td, {}, text(type)):null, h(td, {}, text(block_name)), h(td, {}, text(warehouse||)), price?h(td, {}, text(`${parseFloat(price).toFixed(2)} ${currency}/${unit}`)):null, h(td, { class: sticky-end }, h(div, { class: row }, (() > { const isSelected selected; // Only allow offer mode if user has sales permission const isOfferInstance HAS_SALES_PERMISSION && window.location.search.includes(offer_instance); if(isSelected){ return h(button, { class: mt5 mb5 button_orange, onclick: (_, event) > { window.location.href isOfferInstance ? `/offers?instance${new URLSearchParams(window.location.search).get(offer_instance)}` : `/cart` } }, text(isOfferInstance ? Back to Offer : View Cart) ) ; }else{ return h(input, { type: number, placeholder: 0, max: amount, class: right, id: `amount_${id}` }), h(div, { class: mr10 pt12 }, text(unit)), h(button, { class: mt5 mb5, onclick: (_, event) > AddCart, id, event }, text(isOfferInstance ? Add to offer : Add to Cart)) ; } })()) ), ) const AddCart (state, id) > { const inputElement document.getElementById(`amount_${id}`); const inputAmount parseFloat(inputElement.value) || 0; inputElement.value ; event.target.classList.add(blink); const newState { ...state }; newState.actions.push({ job: AddCart, id: id, amount: inputAmount }); return newState, LoadEffect(newState) ; }; const Sort (state, group_id, column) > { const newState { ...state }; const filter newState.filters.find(f > f.id `g_${group_id}_order`); if (column recommended) { // Remove the filter if column is recommended if (filter) { newState.filters newState.filters.filter(f > f.id ! `g_${group_id}_order`); } } else if (filter) { let _, dir filter.value.split(,); filter.value column + , + (dir asc ? desc : asc); } else { newState.filters.push({ id: `g_${group_id}_order`, value: column }); } return newState, LoadEffect(newState) ; }; const ProductList ({ group_id, items }) > { if (group_id 1) { return h(div, { class: grid slab_view pt0 grid_100_on_mobile }, ...items.map(item > SlabItem(item, group_id)) ) } else if (group_id 2) { return h(div, { class: grid slab_view pt0 grid_100_on_mobile blocks }, ...items.map(item > BlockItem(item, group_id)) ) } else if (group_id 3) { return h(div, { class: table_container mini_scroll }, h(table, { class: results }, h(thead, {}, h(tr, { class: item }, h(th, { class: filter, onclick: Sort, group_id, amount }, text(Amount)), h(th, { class: filter, onclick: Sort, group_id, width }, text(Dimensions)), h(th, { class: filter, onclick: Sort, group_id, thickness }, text(Thickness)), h(th, { class: filter, onclick: Sort, group_id, surface }, text(Surface)), !trade_name_shown&&items0&&items0?.type?h(th, {}, text(Trade name)):null, h(th, { class: filter, onclick: Sort, group_id, block_name }, text(Block)), h(th, { class: filter, onclick: Sort, group_id, warehouse }, text(Location)), items0&&items0.price?h(th, { class: filter, onclick: Sort, group_id, price }, text(Price)):null, h(th, { class: sticky-end }) ) ), h(tbody, {}, ...items.map(item > TableBoardsItem(item, group_id)) ) ) ) } else if (group_id 5 || group_id 6 || group_id 4 || group_id 7 || group_id 8) { return h(div, { class: table_container mini_scroll }, h(table, { class: results }, h(thead, {}, h(tr, { class: item }, h(th, {}, text(Bild)), h(th, { class: filter, onclick: Sort, group_id, amount }, text(Amount)), h(th, { class: filter, onclick: Sort, group_id, width }, text(Dimensions)), h(th, { class: filter, onclick: Sort, group_id, thickness }, text(Thickness)), h(th, { class: filter, onclick: Sort, group_id, surface }, text(Surface)), !trade_name_shown&&items0&&items0?.type?h(th, {}, text(Trade name)):null, h(th, { class: filter, onclick: Sort, group_id, block_name }, text(Block)), h(th, { class: filter, onclick: Sort, group_id, warehouse }, text(Location)), items0&&items0.price?h(th, { class: filter, onclick: Sort, group_id, price }, text(Price)):null, h(th, { class: sticky-end }) ) ), h(tbody, {}, ...items.map(item > TableBoardsItem(item, group_id, true)) ) ) ) } else { return h(table, { class: results }, h(tbody, {}, ...items.map(item > TableItem(item, group_id)) ) ) } } const LoadMore (state, group_id, more) > { const newState { ...state }; const add 16; const filter newState.filters.find(f > f.id `g_${group_id}_limit`); if (filter) { filter.items0.value filter.items0.value + add; } else { newState.filters.push({ id: `g_${group_id}_limit`, items: { value: more+add, selected: true } }); } if (group_id 0) { newState.materials.clicked true; } else { const productIndex newState.products.findIndex(f > f.id group_id); if (productIndex ! -1) newState.productsproductIndex.clicked true; } return newState, LoadEffect(newState) ; }; // Infinite Scroll Subscriber Function const infiniteScrollSubscriber (dispatch, props) > { console.log(InfiniteScroll Subscription initialized); let lastScrollY window.scrollY; let userHasScrolled true; // Start as true to allow initial check let autoLoadInProgress false; // Global flag to ignore programmatic scrolls window.programmaticScroll false; const checkScroll (forceCheck false) > { console.log(InfiniteScroll Checking scroll position); // Prevent consecutive automatic loads without user scroll if (autoLoadInProgress && !forceCheck) { console.log(InfiniteScroll Auto-load in progress, skipping check); return; } if (!userHasScrolled && !forceCheck) { console.log(InfiniteScroll User has not scrolled since last auto-load, skipping); return; } // Find all more buttons that have a data-more attribute const moreButtons document.querySelectorAll(data-more); console.log(InfiniteScroll Found more buttons:, moreButtons.length); moreButtons.forEach(button > { const groupId parseInt(button.dataset.groupId); const more parseInt(button.dataset.more); const alreadyTriggered button.dataset.triggered true; if (alreadyTriggered) { console.log(InfiniteScroll Button already triggered, skipping:, groupId); return; } const rect button.getBoundingClientRect(); const windowHeight window.innerHeight; // Check if element is within 500px of viewport if (rect.top windowHeight + 500 && rect.bottom > 0) { console.log(InfiniteScroll Triggering LoadMore for group:, groupId); button.dataset.triggered true; autoLoadInProgress true; userHasScrolled false; // Reset scroll flag // Reset trigger after a delay to allow re-triggering when new content loads setTimeout(() > { // Check if button still exists and reset const currentButtons document.querySelectorAll(data-more); currentButtons.forEach(btn > { if (btn.dataset.triggered true) { btn.dataset.triggered false; console.log(InfiniteScroll Reset trigger for group:, btn.dataset.groupId); } }); autoLoadInProgress false; // Only check again if user has scrolled in the meantime if (userHasScrolled) { console.log(InfiniteScroll User scrolled during load, checking again); checkScroll(); } }, 2000); // Reset after 2 seconds to allow for backend response dispatch(LoadMore, groupId, more); } }); }; const onScroll () > { // Ignore programmatic scrolls (e.g., from cache restoration) if (window.programmaticScroll) { console.log(InfiniteScroll Programmatic scroll detected, ignoring); window.programmaticScroll false; lastScrollY window.scrollY; return; } const currentScrollY window.scrollY; if (Math.abs(currentScrollY - lastScrollY) > 10) { // Threshold to ignore tiny scroll events userHasScrolled true; lastScrollY currentScrollY; console.log(InfiniteScroll User scrolled, flag set); } checkScroll(); }; // MutationObserver to detect DOM changes (new content loaded) const observer new MutationObserver((mutations) > { // Check if any mutations added nodes with data-more attribute let hasNewMoreButtons false; mutations.forEach(mutation > { mutation.addedNodes.forEach(node > { if (node.nodeType 1) { // Element node if (node.hasAttribute && node.hasAttribute(data-more)) { hasNewMoreButtons true; } else if (node.querySelector) { const moreBtn node.querySelector(data-more); if (moreBtn) hasNewMoreButtons true; } } }); }); if (hasNewMoreButtons) { console.log(InfiniteScroll New content detected, checking scroll); // Wait a bit for rendering to complete setTimeout(checkScroll, 100); } }); // Observe the app container for changes const appContainer document.getElementById(app); if (appContainer) { observer.observe(appContainer, { childList: true, subtree: true }); console.log(InfiniteScroll MutationObserver attached); } // Check on scroll window.addEventListener(scroll, onScroll, { passive: true }); // Check initially and after short delay (for DOM updates) - force check to allow initial load setTimeout(() > checkScroll(true), 100); setTimeout(() > checkScroll(true), 500); setTimeout(() > checkScroll(true), 1000); console.log(InfiniteScroll Scroll listener attached); return () > { console.log(InfiniteScroll Cleaning up scroll listener); window.removeEventListener(scroll, onScroll); observer.disconnect(); }; }; // Subscription definition const onInfiniteScroll () > infiniteScrollSubscriber; const ProductCategory ({ id, name, items, filters, more, clicked }, global_filters) > h(div, { class: row table mb5 }, h(div, { class: w100 }, h(div, { class: row title filter }, h(h2, { class: flex_spacer mw25 nowrap }, text(name)), h(div, { class: dropdown_toggle, onclick: toggleDropdownArea, `da${id}` }, h(i, { class: fas fa-filter }) ), h(div, { class: dropdown_area mini_scroll, id: `da${id}` }, filters ! undefined ? ...filters.map(filter > GroupFilter(filter, id)), GroupOrder(id, global_filters) : GroupOrder(id, global_filters)), ), ProductList({ group_id: id, items: items }), more ? h(div, { class: row center mt20, id: `more-btn-${id}`, data-more: more, data-group-id: id }, h(a, { class: { more: true, blink: clicked }, onclick: LoadMore, id, more }, text(Show more {type} .replace({type}, name))) ) : null ) ) const toggleDropdownArea (state, areaId, group_id 0) > { const dropdownArea document.getElementById(areaId); dropdownArea.style.display !dropdownArea.style.display || dropdownArea.style.display none ? flex : none; return state; } const GroupOrder (group_id, global_filters) > { const dropdownId `dropdown-list-${group_id}-order`; // Find the current order filter for this group const filter global_filters.find(f > f.id `g_${group_id}_order`); let currentColumn ; let currentDir asc; if (filter && filter.value) { const parts filter.value.split(,); currentColumn parts0; currentDir parts.length > 1 ? parts1 : asc; } // Get column translations based on group_id const getColumnTranslations (group_id) > { const baseColumns { recommended: Recommended, block_name: Block name, ...(global_filters.find(f > f.id type && f.items && f.items.length > 0 && f.items.some(item > item.selected && item.value ! *)) ? {} : {type: Trade name}) }; // Group-specific column translations switch(parseInt(group_id)) { case 1: // Slabs return { ...baseColumns, thickness: Thickness, width: Width, height: Height, amount: Amount, //surface: Surface }; case 2: // Blocks return { ...baseColumns, thickness: Thickness, width: Width, height: Height, area: Weight }; case 3: // Skirting boards return { ...baseColumns, thickness: Thickness, width: Width, amount: Amount, surface: Surface, warehouse: Location, }; case 4: // Terrace slabs case 5: // Tiles and floor case 7: // Polygonal panels case 8: // Treads and risers return { ...baseColumns, thickness: Thickness, amount: Amount, surface: Surface, warehouse: Location, }; case 6: // Crust plates return { ...baseColumns, thickness: Thickness, width: Width, height: Height, area: Area, warehouse: Location, }; default: return baseColumns; } }; // Get column translations for current group const columnTranslations getColumnTranslations(group_id); // Create sort options from the column translations const sortOptions Object.entries(columnTranslations).map((column, label) > h(div, { class: option, onclick: (state, event) > { const newState Sort(state, group_id, column); toggleDropdown(newState, dropdownId); return newState; }}, currentColumn column ? h(i, { class: `pointer fas fa-sort-amount-${currentDir asc ? up-alt : down}` }) : h(span, { class: checkbox-placeholder }), h(label, {}, text(label)) ) ); return h(div, { class: dropdown }, h(div, { class: dropdown-header, onclick: toggleDropdown, dropdownId }, h(span, {}, h(i, { class: `fas fa-sort-amount-${currentDir asc ? up-alt : down}` }), text(currentColumn ? (columnTranslationscurrentColumn || Order by) : Order by) ), h(span, { id: dropdown-values }) ), h(div, { id: dropdownId, class: dropdown-list }, h(div, { class: options-container mini_scroll }, sortOptions) ) ); } const GroupFilter ({ id, name, items, value, unit, clicked }, group_id) > { const dropdownId `dropdown-list-${group_id}-${id}`; if (items ! undefined) { let selected items.filter(i > i.selected).map(i > i.name).join(,); selected ! ? selected : + selected : 0; return h(div, { class: dropdown }, h(div, { class: { dropdown-header: true, blink: clicked }, onclick: toggleDropdown, dropdownId }, h(span, {}, text(`${name}${selected}`)), h(span, { id: dropdown-values }) ), h(div, { id: dropdownId, class: dropdown-list }, h(div, { class: options-container mini_scroll }, items.map(item > h(div, { class: option }, h(input, { id: `option-${group_id}-${item.value}`, type: checkbox, checked: item.selected, onchange: toggleOption, id, group_id, item.value, dropdownId }), h(label, { for: `option-${group_id}-${item.value}`, title: item.name}, text(item.name)) ) )) ) ) } else if (value ! undefined){ return h(div, { class: dropdown }, h(div, { class: dropdown-header, onclick: toggleDropdown, dropdownId }, h(span, {}, text(`${name}${value ! ? : + value + unit : }`)), h(span, { id: dropdown-values }) ), h(div, { id: dropdownId, class: dropdown-list }, h(div, { class: options-container mini_scroll }, h(div, { class: row pl5 pr5 pb5 }, h(input, { id: `option-${group_id}-${id}`, type: number, value: value, oninput: (_, event) > toggleOption, id, group_id, value, dropdownId, event }), h(span, { class: pt5 }, text(unit)) ) ) ) ) } } const toggleDropdown (state, dropdownId, group_id 0) > { document.querySelectorAll(.dropdown.open).forEach(dropdown > { let list dropdown.querySelector(.dropdown-list); if (list.id ! dropdownId) { dropdown.classList.remove(open); list.style.display none; } }); const dropdownList document.getElementById(dropdownId); if(!dropdownList.style.display || dropdownList.style.display none){ dropdownList.style.display block; dropdownList.parentElement.classList.add(open); dropdownList.querySelector(inputtypenumber)?.focus(); }else{ dropdownList.style.display none; dropdownList.parentElement.classList.remove(open); } if (group_id 0) { return state; } const newState { ...state }; newState.actions.push({ job: UpdateGroup, id: group_id }); return newState, LoadEffect(newState) ; } const toggleOption (state, id, group_id, value, dropdownId, event) > { const newState { ...state }; const filter newState.filters.find(f > f.id `g_${group_id}_${id}`); const pi newState.products.findIndex(i > i.id group_id); const fi newState.productspi.filters.findIndex(i > i.id id); if (filter.items) { const itemIndex filter.items.findIndex(i > i.value value); if (itemIndex > -1) { filter.itemsitemIndex.selected !filter.itemsitemIndex.selected; } else { filter.items.push({ value: value, selected: true }); } const ii newState.productspi.filtersfi.items.findIndex(i > i.value value); newState.productspi.filtersfi.clicked true; newState.productspi.filtersfi.itemsii.selected !newState.productspi.filtersfi.itemsii.selected; return toggleDropdown(newState, dropdownId, group_id); } else { filter.value event.target.value; newState.productspi.filtersfi.value event.target.value; return newState, debounce(LoadEffect, 400)(newState) ; } } const CategoryLists ({ products, filters, hero }) > h(div, { class: w80 w66_on_medium }, (() > { let productTypes new Set(); for (let product of products) { for (let item of product.items) { if (item.type) { productTypes.add(item.type); } } } trade_name_shown productTypes.size 1; return hero.type ? h(div, { class: row table mb5 }, h(div, { class: w100 }, h(div, {class: row bt_on_mobile}, h(div, { class: w50 }, h(div, { class: row p10 }, h(div, { class: w100 }, h(span, {}, text(Trade name)), h(h2, { class: flex_spacer }, text(...productTypes0)) ) ), h(div, { class: row mb10 p10 }, h(div, { class: w100 }, text(hero.description) ) ), h(div, { class: row tabledark m10 }, h(div, { class: w30 mwfc }, text(Material) ), h(div, { class: w70 }, text(hero.material) ) ), h(div, { class: row tabledark m10 }, h(div, { class: w30 mwfc }, text(Color) ), h(div, { class: w70 }, text(hero.color) ) ), h(div, { class: row tabledark m10 }, h(div, { class: w30 mwfc }, text(Character) ), h(div, { class: w70 }, text(hero.character) ) ), ), h(div, { class: w50, style: {background: `url(${hero.image})`, backgroundSize: cover, minHeight: 30vh} }), ) ) ) : (productTypes.size 1 ? h(div, { class: row table mb5 pl20 }, h(div, { class: w100 }, h(span, {}, text(Trade name)), h(h2, { class: flex_spacer }, text(...productTypes0)) ) ) : null); })(), ...products.map(product > ProductCategory(product, filters)) ) const MaterialList ({ items, more, clicked }, selected) > h(div, { class: flex_spacer w66_on_medium table }, h(div, { class: row pl10 pb10 }, h(div, {class: w100}, h(div, { class: row }, h(h2, { class: flex_spacer w75 }, text(Materials)), h(button, { class: btn fit mr10, onclick: (state) > { const newState { ...state }; for (var i state.filters.length - 1; i > 0; i--) { if (state.filtersi.id type) { newState.filtersi.items { value: *, name: *, selected: true }; break; } } return newState, LoadEffect(newState), (dispatch) > { // Restore scroll position after content loads const savedScrollY sessionStorage.getItem(materialGridScrollY); if (savedScrollY) { setTimeout(() > { console.log(RECOVER); window.programmaticScroll true; window.scrollTo(0, parseInt(savedScrollY)); sessionStorage.removeItem(materialGridScrollY); }, 100); } } ; } }, text(Show all)), ), selected.length>0?h(span, {}, text(Available as + (selected.length > 1 ? selected.slice(0,-1).join(, ) + or + selected.slice(-1) : selected.slice(-1)))):null ) ), h(div, { class: grid slab_view pt0 grid_100_on_mobile }, ...items.map(item > MaterialItem(item)) ), more ? h(div, { class: row center mt20, id: more-btn-0, data-more: more, data-group-id: 0 }, h(a, { class: { more: true, blink: clicked }, onclick: LoadMore, 0, more }, text(Show more materials)) ) : null ) const MaterialItem ({ name, image, group_ids }) > h(div, { class: product-item, onclick: (_, event) > SelectMaterial, name, event }, h(h3, { }, text(name)), h(p, {}, text(group_ids)), h(img, { src: image, class: product-image }) ) const SelectMaterial (state, name, event) > { const newState { ...state }; event.target.classList.add(blink); // Save scroll position before selecting material sessionStorage.setItem(materialGridScrollY, window.scrollY); // Set flag to scroll to top after data loads window.scrollToTopAfterLoad true; for (var i state.filters.length - 1; i > 0; i--) { if (state.filtersi.id type) { newState.filtersi.items { name: name, id: name, value: name, selected: true } break; } } return newState, LoadEffect(newState) ; }; const SearchInput ({ search }) > h(div, { class: row }, h(input, { class: search color, type: text, placeholder: Search, value: search, oninput: SetSearchTerm }) ) const GlobalFilters ({ filters }) > h(span, {}, filters.map((filter, idx0) > { if (filter.name && filter.items.length > 0 && !filter.private) return GlobalFilter(filter, idx0); }) ) const GlobalFilter ({ name, id, items }, idx0) > h(div, { class: `w100 sidebar-list ${id type || (window.sidebar_state && window.sidebar_stateid) ? open : }`, id: `sb_${id}`, onclick: (state, event) > { if (event.target.classList.contains(sidebar-list-title)) { const sidebarList document.getElementById(`sb_${id}`); const isOpen sidebarList.classList.toggle(open); // Initialize sidebar state if not exists window.sidebar_state window.sidebar_state || {}; window.sidebar_stateid isOpen; return state; } return state; } }, h(div, { class: row bold pt7 sidebar-list-title }, text(name), window.innerWidth 820 && id ! type && items.some(item > item.selected) ? text(: + items.filter(item > item.selected).map(item > item.name).join(, )) : null ), ...items.map((item, idx1) > FilterTag(item, idx0, idx1, id)) ) const SelectFilter (state, selected, idx0, idx1) > { const newState { ...state }; newState.filtersidx0.itemsidx1.selected !selected; newState.filtersidx0.itemsidx1.clicked true; // Check if this is the type filter being deselected const isTypeFilter newState.filtersidx0.id type; const isDeselecting selected; // If selected was true, were now deselecting if (isTypeFilter && isDeselecting) { return newState, LoadEffect(newState), (dispatch) > { // Restore scroll position after content loads const savedScrollY sessionStorage.getItem(materialGridScrollY); if (savedScrollY) { setTimeout(() > { console.log(RECOVER from FilterTag); window.programmaticScroll true; window.scrollTo(0, parseInt(savedScrollY)); sessionStorage.removeItem(materialGridScrollY); }, 100); } } ; } return newState, LoadEffect(newState) ; }; const FilterTag ({ name, selected, clicked, value }, idx0, idx1, id) > h(div, { class: { tag: true, mr0: true, orange: selected, blink: clicked, type: idtype }, onclick: SelectFilter, selected, idx0, idx1 }, text(name*?Show all:name), idtype?h(a, {class: ico}, h(i, {class: fas fa-times})):null ) const view state > { const projectId new URLSearchParams(window.location.search).get(project_id); const offerInstance new URLSearchParams(window.location.search).get(offer_instance); let backLink /, backText Gallery; if (projectId) { backLink `/project?id${projectId}`; backText Project; } else if (offerInstance) { backLink `/offers?instance${offerInstance}`; backText Offer; } else if(document.referrer.includes(/warehouse)) { backLink document.referrer; backText Warehouse; } else if(document.referrer || !document.referrer || history.length 1) { backLink false; backText ; }else{ backLink javascript:history.back(); backText Back; } return h(div, { class: boxstyle }, h(div, { class: row tb_on_mobile }, h(div, { class: w20 w33_on_medium mb20 sidebar_ref }, ), h(div, { class: w20 w33_on_medium mb20 fixed_sidebar }, backLink!false?h(div, { class: row title nobb mb0 pt5 }, h(a, { href: backLink }, h(i, { class: fas fa-arrow-left }), text(backText) ) ) : null, SearchInput(state), GlobalFilters(state) ), state.materials.items ? MaterialList(state.materials, state?.filters.find(filter > filter.id group_id)?.items.filter(item > item.selected).map(item > item.name) || ) : CategoryLists(state) ) ) } // Initialize the app var hyperapp app({ init: initialState, LoadEffect(initialState), view, subscriptions: state > onInfiniteScroll() , node: document.getElementById(app) }) // Function to handle popstate event window.addEventListener(popstate, (event) > { hyperapp(SetURLState, window.location.search); }); // Function to set state from URL const SetURLState (state, newUrl) > { let caches JSON.parse(sessionStorage.getItem(shopCaches) || {}); let cachedState cachesnewUrl; if (cachedState) { console.log(Loading state from cache for URL:, newUrl); return { ...cachedState.state }, (dispatch) > { window.programmaticScroll true; window.scrollTo(0, cachedState.scroll || 0); dispatch(CacheState, false); } ; } else { console.log(No cached state found for URL:, newUrl); // If no cached state, parse the URL and update filters let params new URLSearchParams(newUrl); let newState { ...state }; newState.filters getFiltersFromURL(); newState.search params.get(search) || ; return newState, LoadEffect(newState) ; } }; // FIXED SIDEBAR function syncSidebarWidth() { const ref document.querySelector(.sidebar_ref); const fixed document.querySelector(.fixed_sidebar); if (ref && fixed) { if (window.innerWidth 820) { fixed.style.width unset; return; } const width ref.getBoundingClientRect().width; fixed.style.width `${width}px`; } } function checkSidebarBoundaries() { const sidebar document.querySelector(.fixed_sidebar); const app document.querySelector(#app); if (!sidebar || !app) return; const appRect app.getBoundingClientRect(); const bottom Math.max((appRect.bottom - window.innerHeight) * -1, 0); if (bottom ! lastBottom) { if (window.innerWidth 820) { sidebar.style.bottom auto; lastBottom 0; return; } sidebar.style.bottom `${bottom}px`; lastBottom bottom; } } function syncSidebarWidthWhenReady(attempts 20) { if (attempts 0) return; syncSidebarWidth(); checkSidebarBoundaries(); requestAnimationFrame(() > syncSidebarWidthWhenReady(attempts - 1)); } let lastBottom null; window.addEventListener(DOMContentLoaded, () > syncSidebarWidthWhenReady()); window.addEventListener(resize, syncSidebarWidth); window.addEventListener(scroll, checkSidebarBoundaries, { passive: true }); window.addEventListener(resize, checkSidebarBoundaries); /script> script src/assets/js/core.js defer>/script> div classfooter meta> a href/articles/tos>Terms of Use/a> - a href/articles/privacy-policy>Privacy/a> - a href/articles/imprint>Imprint/a>/div>script typetext/javascript> $(body).on(click, .sharelink, function(){ navigator.clipboard.writeText($(this).text()); var tmp $(this).html(); $(this).html(copied); setTimeout(() > { $(this).html(tmp); }, 500); }); $(body).on(click, .nofold, .title a, .title input, .title button, function(e){ e.stopPropagation(); }) $(body).on(click, .foldable, function(e){ if(!$(this).hasClass(nofold)){ $(this).parents(.boxstyle).toggleClass(folded); var folded ; $(.boxstyle > .foldable).each(function(){ if($(this).parents(.folded).length>0 && $(this).attr(id) ! undefined) folded.push($(this).attr(id)); }); $.post( /async/dashboard, { jobs: JSON.stringify({folded: {data: {page: window.location.pathname, folded: folded}}})}); } })/script>script> function decryptEmail(encoded) { var address atob(encoded); window.location.href mailto: + address; }/script>/body>/html>
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]