function addClass(el,className){ if (el.classList) el.classList.add(className); else el.className += ' ' + className; } function removeClass(el,className){ if (el.classList) el.classList.remove(className); else el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); } function toggleClass(el,className) { if (el.classList) { el.classList.toggle(className); } else { var classes = el.className.split(' '); var existingIndex = classes.indexOf(className); if (existingIndex >= 0) classes.splice(existingIndex, 1); else classes.push(className); el.className = classes.join(' '); } } function hasClass(el,className) { return new RegExp('(\\s|^)'+className+'(\\s|$)').test(el.className); } function getScrollTop() { return window.scrollY || document.documentElement.scrollTop; } function scrollShouldAjaxLoad(el, offset, preset) { offset = offset || 100; preset = preset || false; if(!el) { return false; } try { var windowHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); var r = el.getBoundingClientRect(); if(el.offsetHeight + r.top - offset < windowHeight) { if(preset) { if(el.offsetHeight + r.top + preset > windowHeight) { return true; } return false; } return true; } return false; } catch(e) { return false; } } var smoothScroll = { documentVerticalScrollPosition: function(){ if(self.pageYOffset) return self.pageYOffset; if(document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; if(document.body.scrollTop) return document.body.scrollTop; return 0; }, viewportHeight: function(){ return (document.compatMode === "CSS1Compat") ? document.documentElement.clientHeight : document.body.clientHeight; }, documentHeight: function(){ return (document.height !== undefined) ? document.height : document.body.offsetHeight; }, documentMaximumScrollPosition: function(){ return this.documentHeight() - this.viewportHeight(); }, elementVerticalClientPosition: function(element){ var rectangle = element.getBoundingClientRect(); return rectangle.top; }, verticalTickToPosition: function(currentPosition, targetPosition){ var filter = 0.2; var fps = 60; var difference = parseFloat(targetPosition) - parseFloat(currentPosition); var arrived = (Math.abs(difference) <= 0.5); if(arrived){ scrollTo(0.0, targetPosition); return; } currentPosition = (parseFloat(currentPosition) * (1.0 - filter)) + (parseFloat(targetPosition) * filter); scrollTo(0.0, Math.round(currentPosition)); var self = this; setTimeout(function(){ self.verticalTickToPosition(currentPosition, targetPosition); }, (1000 / fps)); }, toElement: function(element, padding){ if(!element){ console.warn("Couldn't find target element."); return; } var targetPosition = this.documentVerticalScrollPosition() + this.elementVerticalClientPosition(element) - padding; var currentPosition = this.documentVerticalScrollPosition(); var maximumScrollPosition = this.documentMaximumScrollPosition(); if(targetPosition > maximumScrollPosition) targetPosition = maximumScrollPosition; this.verticalTickToPosition(currentPosition, targetPosition); } }; function Cookie(name, defaultValue, path) { this.name = name; this.value = null; this.path = path || "/"; var ca = document.cookie.split(';'); for(var i=0; i 120) { addClass(body, "shrink"); } else { removeClass(body, "shrink"); } } const NavbarSearchItem_Product = props => { const { data: p, active, highlightIndex, onMouseEnter, } = props; return {p.title}
{p.title}
{p.price} Kč
}; const NavbarSearchItem_Generic = props => { const { data: r, active, highlightIndex, onMouseEnter, } = props; return {r.title} }; const NavbarSearchItem_Post = props => { const { data: p, active, highlightIndex, onMouseEnter, } = props; return {p.title}
{p.title}
} class NavbarSearch extends React.Component { constructor(props) { super(props) this.state = { value: "", opened: false, nodes: [], highlighted: -1, preloading: false, used: false, }; this.loading = false; this.blurTimeout = undefined; this.searchTimeout = undefined; this.rowTypes = [ { type: "ranking", title: __navSearchLang.acZebricky, component: NavbarSearchItem_Post, }, { type: "review", title: __navSearchLang.acRecenze, component: NavbarSearchItem_Post, }, { type: "blogPost", title: __navSearchLang.acClanky, component: NavbarSearchItem_Post, }, { type: "product", title: __navSearchLang.acProdukty, component: NavbarSearchItem_Product, }, { type: "category", title: __navSearchLang.acKategorieProduktu, component: NavbarSearchItem_Generic, }, { type: "brand", title: __navSearchLang.acVyrobci, component: NavbarSearchItem_Generic, }, ]; this._open = this.open.bind(this); this._close = this.close.bind(this); this._toggleOpen = this.toggleOpen.bind(this); this._search = this.search.bind(this); this._onChange = this.onChange.bind(this); this._onBlur = this.onBlur.bind(this); this._onFocus = this.onFocus.bind(this); this._onMouseEnter = this.onMouseEnter.bind(this); this._onKeyDown = this.onKeyDown.bind(this); } componentDidUpdate(prevProps, prevState, snapshot) { if(!prevState.opened && this.state.opened) { const input = this.refs.input; input.focus() input.select() } } open() { this.setState({ opened: true, }) this.props.onToggle?.(true) } close() { this.setState({ opened: false, }) this.props.onToggle?.(false) } toggleOpen() { if(this.state.opened) { this.close() } else { this.open() } } async search() { if(this.loading) return; this.loading = true; const nextState = {}; try { const fd = new FormData(); fd.append("request", "index/search") fd.append("query", this.state.value) fd.append("all", "1") const r = await fetch(`${__httppath}/ajax/`, { method: "POST", body: fd, }); const e = await r.json(); if(e.status == "OK") { nextState.nodes = e.data.nodes; nextState.highlighted = -1; nextState.used = true; } else { console.error(e) } } catch(err) { console.error(err) } finally { nextState.preloading = false; this.setState(nextState) this.loading = false; } } onChange(ev) { const val = ev.currentTarget.value; const isSearchable = val.length >= 3; this.setState({ value: val, preloading: isSearchable, }, () => { if(isSearchable) { clearTimeout(this.searchTimeout) this.searchTimeout = setTimeout(this._search, 750); } }) } onBlur() { clearTimeout(this.blurTimeout) this.blurTimeout = setTimeout(this._close, 300); } onFocus() { clearTimeout(this.blurTimeout) } onMouseEnter(ev) { const hlindex = parseInt(ev.currentTarget.dataset.jsHlindex); this.setState({ highlighted: hlindex, }) } onKeyDown(ev) { switch(ev.key) { case "ArrowDown": { ev.preventDefault() const nodeCount = this.state.nodes.length; let next = this.state.highlighted + 1; if(next > nodeCount - 1) next = -1; this.setState({ highlighted: next, }) } break; case "ArrowUp": { ev.preventDefault() const nodeCount = this.state.nodes.length; let next = this.state.highlighted - 1; if(next < -1) next = nodeCount - 1; this.setState({ highlighted: next, }) } break; case "Enter": const hl = this.state.highlighted; if(hl > -1 && this.state.nodes[hl] !== undefined) { window.location.href = this.state.nodes[hl].link; } else { window.location.href = `${__httppath}/hledat/?q=${encodeURIComponent(this.state.value)}`; } break; case "Escape": this.refs.input.blur() break; } } render() { let hlIterator = -1; let results; const { nodes, highlighted, preloading, used, opened, value, } = this.state; if(used && opened) { const segments = []; for(const t of this.rowTypes) { const results = nodes.filter(e => e.type == t.type); if(results.length == 0) continue; segments.push(
{t.title}
{results.map(r => { hlIterator++; return React.createElement(t.component, { key: r.id, data: r, active: highlighted == hlIterator, highlightIndex: hlIterator, onMouseEnter: this._onMouseEnter, }) })}
) } results = (
{segments} {nodes.length > 0 ? __navSearchLang.acVsechnyVysledky : __navSearchLang.acZadneVysledky}
); } return
{preloading &&
} {results}
} } const onNavbarSearchToggle = opened => { if(opened) { $navbar.navbar.classList.add("search-active") } else { $navbar.navbar.classList.remove("search-active") } }; ReactDOM.render(, document.getElementById("navbar-search")) var siTriggers = document.querySelectorAll("[data-subitems-trigger]"); var siCloses = document.querySelectorAll("[data-subitems-close]"); for(var i=0; i { if(trigger.hasAttribute("href")) { trigger.addEventListener("click", (ev) => { if(window.innerWidth < 768) { ev.preventDefault() } }) } }) var trackedProducts = document.querySelectorAll("a[data-tr-product]"); for(var i=0; i
); } }); var $SHOWCOOKIECONFIRM = new Cookie("_ccf", "1"); if($SHOWCOOKIECONFIRM.value === "1") { ReactDOM.render(, document.getElementById("cookie-confirm")); } var serialiseObject = function(obj) { var pairs = []; for (var prop in obj) { if (!obj.hasOwnProperty(prop)) { continue; } if (Object.prototype.toString.call(obj[prop]) == '[object Object]') { pairs.push(serialiseObject(obj[prop])); continue; } pairs.push(prop + '=' + obj[prop]); } return pairs.join('&'); } function Ajax(obj){ if(typeof obj.processData == "undefined") obj.processData = true; var request = new XMLHttpRequest(); request.onreadystatechange = function(){ if(request.readyState == 1){ if(obj.contentType != false) if(typeof obj.contentType == "undefined"){ request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); }else{ if(obj.contentType)request.setRequestHeader('Content-Type', obj.contentType); } } if(request.readyState == 4){ if(request.status == 200){ try { if(obj.success){ var resp; switch(obj.dataType){ case "json": resp = JSON.parse(request.response); break; default: resp = request.response; break; } obj.success(resp); } } catch (e){ console.error("1MD::AJAX ERROR OCCURED!",e); if(obj.fail)obj.fail(e); } }else if(obj.fail)obj.fail(); } }; if(obj.progress){ request.upload.addEventListener('progress', obj.progress, false); } request.open(obj.type, obj.url); if(obj.processData){ obj.data = serialiseObject(obj.data); } request.send(obj.data); } function clone(obj) { if (obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj) return obj; if (obj instanceof Date) var temp = new obj.constructor(); else var temp = obj.constructor(); for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { obj['isActiveClone'] = null; temp[key] = clone(obj[key]); delete obj['isActiveClone']; } } return temp; } var NewSlider = React.createClass({ getInitialState() { return { elementCount: 0, totalWidth: 0, page: 1, maxPages: 0 }; }, html: "", rowClass: "", touch: { active: false, initialX: null, reactionLimit: 80 }, setTransform(px) { return { WebkitTransform: "translateX("+px+"px)", MozTransform: "translateX("+px+"px)", msTransform: "translateX("+px+"px)", OTransform: "translateX("+px+"px)", transform: "translateX("+px+"px)" }; }, getDimensions() { const el = document.querySelector("#"+this.props.elementID+" .row div[class^='col-']") var elw = el === null ? 1 : el.offsetWidth - 3; var elc = document.querySelectorAll("#"+this.props.elementID+" .row div[class^='col-']").length; var ttw = ReactDOM.findDOMNode(this.refs.overhaul).offsetWidth; this.setState({ elementCount: elc, totalWidth: ttw, page: 1, maxPages: Math.ceil(elc*elw/ttw), showArrows: Math.round(ttw/elw) < elc }); }, componentWillMount() { this.html = document.querySelector("#"+this.props.elementID+" .row").innerHTML; this.rowClass = document.querySelector("#"+this.props.elementID+" .row").className; }, componentDidMount() { var self = this; window.addEventListener("resize", function(){ self.getDimensions(); }); this.getDimensions(); }, handleAction(type, data) { switch(type) { case "prev": var a = this.state.page == 1 ? this.state.maxPages : this.state.page-1; this.setState({ page: a }); this.handleAction("refreshBLazy"); break; case "next": var a = this.state.page == this.state.maxPages ? 1 : this.state.page+1; this.setState({ page: a }); this.handleAction("refreshBLazy"); break; case "touch-start": this.touch.active = true; this.touch.initialX = data.touches[0].pageX; break; case "touch-move": if(this.touch.active) { var diff = this.touch.initialX - data.touches[0].pageX; if(diff > this.touch.reactionLimit) { this.handleAction("next"); } else if(diff < -this.touch.reactionLimit) { this.handleAction("prev"); } if(Math.abs(diff) > this.touch.reactionLimit) { this.touch.active = false; } } break; case "touch-end": this.touch.active = false; break; case "refreshBLazy": if(typeof blazy != "undefined") { setTimeout(function(){ blazy.revalidate(); }, 350); } break; } }, render() { var arrows = []; if(this.state.showArrows) { arrows.push(
); arrows.push(
); } return (
{arrows}
); } }); var ns = document.getElementById("new-slider"); if(ns) ReactDOM.render(, ns); var IndexAutocompleter = React.createClass({ getInitialState() { return { nodes: [], highlighted: -1, loading: false, preloading: false, open: false, used: false }; }, ajaxTimer: null, openTimer: null, value: "", handleAction(type, data) { switch(type) { case "key-up": switch(data.keyCode) { case 38: // nahoru var a; if(this.state.highlighted == -1 || this.state.highlighted == 0) a = this.state.nodes.length-1; else a = this.state.highlighted-1; this.setState({ highlighted: a }); break; case 40: // dolu var a; if(this.state.highlighted == this.state.nodes.length-1) a = 0; else a = this.state.highlighted+1; this.setState({ highlighted: a }); break; case 13: // enter if(this.state.highlighted > -1 && !this.state.loading && !this.state.preloading) { window.location.href = this.state.nodes[this.state.highlighted].link; } else { window.location.href = "hledat/?q="+this.value; } break; default: var q = data.currentTarget.value; this.value = q; clearTimeout(this.ajaxTimer); if(q.length >= 3) { var self = this; this.setState({ preloading: true }); this.ajaxTimer = setTimeout(function(){ self.handleAction("fetch", q); }, 750); } break; } break; case "fetch": var self = this; if(data.length < 3) return false; if(this.state.loading) return false; this.setState({ loading: true, preloading: false }); Ajax({ url: "/ajax/", type: "POST", dataType: "json", data: { request: "index/search", query: data }, success(e){ switch(e.status){ case "OK": self.setState({ nodes: e.data.nodes, loading: false, highlighted: -1, used: true }); break; } }, fail(e) { self.setState({ loading: false }); } }); break; case "manual-search": this.handleAction("fetch", this.value); ReactDOM.findDOMNode(this.refs.input).focus(); break; case "highlight": this.setState({ highlighted: parseInt(data) }); break; case "open": clearTimeout(this.openTimer); this.setState({ open: true }); break; case "close": clearTimeout(this.openTimer); var self = this; this.openTimer = setTimeout(function(){ self.setState({ open: false }); }, 300); break; } }, render() { var loading, categories = [], brands = [], products = [], ck = 0, bk = 0, pk = 0, ch, bh, ph, showMore; if(this.state.nodes.length > 0) { for(let i=0; i
{node.title}
{node.price} Kč
); pk++; break; case "category": var class_ = "node simple"; if(this.state.highlighted == index) class_ += " highlighted"; categories.push(
{node.title}
); ck++; break; case "brand": var class_ = "node simple"; if(this.state.highlighted == index) class_ += " highlighted"; brands.push(
{node.title}
); bk++; break; } } showMore = ( ); if(ck > 0) ch =
{__lang.acKategorieProduktu}
; if(bk > 0) bh =
{__lang.acZnacky}
; if(pk > 0) ph =
{__lang.acProdukty}
; } else if(this.state.used) { showMore = ( ); } var class_ = "results"; if(!this.state.open) class_ += " hide"; var results = (
{ph} {products} {ch} {categories} {bh} {brands} {showMore}
); if(this.state.loading || this.state.preloading) { loading =
; } return (
{loading}
{results}
); } }); ReactDOM.render(, document.getElementById("index-autocompleter"));