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; } function get_window_width() { return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; } function get_window_height() { return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; } function copyToClipboard(text) { var targetId = "_hiddenCopyText_"; var origSelectionStart, origSelectionEnd; var target = document.createElement("textarea"); target.style.position = "fixed"; target.style.left = "-9999px"; target.style.top = "0"; target.id = targetId; document.body.appendChild(target); var elem = document.getElementById(targetId); target.textContent = text; var currentFocus = document.activeElement; target.focus(); target.setSelectionRange(0, target.value.length); var succeed; try { succeed = document.execCommand("copy"); } catch(e) { succeed = false; } if (currentFocus && typeof currentFocus.focus === "function") { currentFocus.focus(); } document.body.removeChild(elem); return succeed; } 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")); } function remoteUnwrapper(uw) { var content = uw.querySelector(".content"); var inner = content.querySelector(".inner"); var isOpened = hasClass(uw, "opened"); if(!isOpened) { content.style.height = "0px"; setTimeout(function(){ content.style.height = inner.offsetHeight+"px"; addClass(uw, "opened"); }, 50) } else { content.style.height = inner.offsetHeight+"px"; setTimeout(function(){ content.style.height = "0px"; removeClass(uw, "opened"); }, 50) } } function getUnwrappersReady() { var unwrappers = document.getElementsByClassName("unwrapper"); for(var i=0; i { const sections = {}; const showCoupon = id => { sections[id]?.element?.classList.add("active") }; const closeCoupon = id => { sections[id]?.element?.classList.remove("active") }; const copyCoupon = id => { const s = sections[id]; if(s === undefined) return; copyToClipboard(s.code) clearTimeout(s.timeout) s.elCopy.classList.add("display-none") s.elCopied.classList.remove("display-none") s.timeout = setTimeout(() => { s.elCopy.classList.remove("display-none") s.elCopied.classList.add("display-none") }, 3000); }; document.querySelectorAll("[data-ctc-initialize]").forEach(el => { el.addEventListener("click", ev => { const isAnchor = el.tagName.toLowerCase() == "a" && el.hasAttribute("href"); const id = el.getAttribute("data-ctc-initialize"); if(isAnchor) { ev.preventDefault() window.open(`#coupon=${id}`) window.location.href = el.getAttribute("href"); } else { showCoupon(id) } }) }) document.querySelectorAll("[data-ctc-section]").forEach(el => { const id = el.getAttribute("data-ctc-section"); const elCopy = el.querySelector("[data-ctc-copy]"); sections[id] = { element: el, elCopy, elCopied: document.querySelector("[data-ctc-copied]"), timeout: undefined, code: el.querySelector("[data-ctc-code]").value, }; const closers = [ el.querySelector("[data-ctc-bg]"), el.querySelector("[data-ctc-close]"), el.querySelector("[data-ctc-close-too]"), ]; closers.forEach(cl => { cl.addEventListener("click", () => { closeCoupon(id) }) }) elCopy.addEventListener("click", () => { copyCoupon(id) }) }) const frMatch = window.location.hash.match(/^#coupon=([a-z0-9-]+)$/); if(frMatch !== null) { showCoupon(frMatch[1]) } }; initializeCoupons() var CommentAdder = React.createClass({ getInitialState() { return { window: 0, open: false, loading: false, respondTo: null, securityQuestion: { a: null, b: null, operant: null }, rnType: "none", }; }, getDefaultProps() { return { type: "kz", parent: 0, fund: 0, variant: "static" }; }, parent: 0, operants: ["+", "*"], operantsDisplay: [" + ", " × "], componentWillMount() { this.parent = this.props.parent; this.setState({ securityQuestion: this.handleAction("generate-security-question") }); }, handleAction(type, data) { switch(type) { case "get-random-int": return Math.floor(Math.random() * (data.max - data.min + 1)) + data.min; break; case "generate-security-question": return { a: this.handleAction("get-random-int", {min: 2, max: 10}), b: this.handleAction("get-random-int", {min: 2, max: 10}), operant: this.handleAction("get-random-int", {min: 0, max: this.operants.length-1}) }; break; case "get-security-result": switch(this.operants[this.state.securityQuestion.operant]) { case "+": return this.state.securityQuestion.a + this.state.securityQuestion.b; break; case "*": return this.state.securityQuestion.a * this.state.securityQuestion.b; break; } break; case "validate": data.preventDefault(); var sr = ReactDOM.findDOMNode(this.refs.securityResult); if(parseInt(sr.value) != this.handleAction("get-security-result")) { alert(this.props.lang.spatnaOdpoved); this.setState({ securityQuestion: this.handleAction("generate-security-question") }); sr.value = ""; sr.focus(); } else { this.handleAction("send"); } break; case "onRnTypeChange": this.setState({ rnType: data.currentTarget.value, }) break; case "send": var self = this; if(this.state.loading) return false; this.setState({ loading: true }); var iName = ReactDOM.findDOMNode(self.refs.name); var iText = ReactDOM.findDOMNode(self.refs.comment); const iRnEmail = ReactDOM.findDOMNode(self.refs.rnEmail); const rnEmail = iRnEmail === null ? "" : iRnEmail.value; Ajax({ url: "/ajax/", type: "POST", dataType: "json", data: { request: "comment/add", name: encodeURIComponent(iName.value), text: encodeURIComponent(iText.value), rnType: self.state.rnType, rnEmail: encodeURIComponent(rnEmail), recommends: self.refs.recommends ? self.refs.recommends.value : null, rating: self.refs.stars ? self.refs.stars.value : null, type: self.props.type, fund: self.props.fund, parent: self.parent, url: __comment.url, parentTitle: encodeURIComponent(__comment.parentTitle) }, success(e){ switch(e.status){ case "OK": switch(e.data.status) { case "OK": var recommends = "", rating = ""; if(self.props.ratable) { if(e.data.recommends != null) { recommends = "
" +"Thumbs "+(e.data.recommends ? "up" : "down")+"" +""+self.props.lang["recommends"+(e.data.recommends ? 1 : 0)+"_"+self.props.type]+"" +"
"; } if(e.data.rating != null) { rating = "
" +""+self.props.lang.hodnoceniCelkem+":" +"
" +"
" +"
" +"
" +"Star mask" +"
" +"
"; } } var appendedComment = document.createElement("div"); appendedComment.className = "comment"; appendedComment.innerHTML = "
" +"
" +"
" +"
" +"
"+e.data.name+(e.data.wa ? "" : "")+"
" +"
"+self.props.months["m"+e.data.month]+" "+e.data.day+", "+e.data.year+"
" +"
" +recommends +rating +"
" +"
" +"
"+e.data.text+"
" +"
" +"
" +"
" +"
" +"" +"
" +"
" +"
" +"
"; document.querySelector("[data-subcomments='"+self.parent+"']").appendChild(appendedComment); var v = document.querySelector("[data-dynamic-comment-voter='"+e.data.added+"']"); ReactDOM.render(, v); var t = document.getElementById("total-comment-count"); if(t) t.innerHTML = parseInt(t.innerHTML)+1; document.querySelector("[data-dynamic-comment-button='"+e.data.added+"']").addEventListener("click", function(){ if(typeof FloatingCommentAdder_ != "undefined") { FloatingCommentAdder_.handleAction("set-and-open", { parent: e.data.added, respondTo: e.data.name }); } }); iName.value = ""; iText.value = ""; if(iRnEmail !== null) iRnEmail.value = ""; ReactDOM.findDOMNode(self.refs.securityResult).value = ""; if(self.props.ratable) { self.refs.stars.handleAction("vote", 0); self.refs.recommends.handleAction("vote", 2); } var noComments = document.getElementById("comments-none"); if(noComments) { noComments.innerHTML = ""; noComments.className = "m-b-lg p-b-xs"; } if(self.props.ratable && e.data.rating != null) { var crCount = document.getElementById("comment-rating-count"); var crAverage = document.getElementById("comment-rating-average"); var crProgress = document.getElementById("comment-rating-progress"); var crStars = document.getElementById("comment-rating-stars"); if(crCount && crProgress && crAverage) { var count = parseInt(crCount.innerHTML); var average = parseFloat(crAverage.innerHTML); var newAverage = Math.round(((count*average+e.data.rating)/(count+1))*100)/100; crAverage.innerHTML = newAverage; crCount.innerHTML = count+1; crProgress.style.width = (newAverage*20)+"%"; crStars.className = "star-rating g-b rated-"+(Math.round(newAverage*2)*10); } } self.setState({ window: 1, open: true, loading: false, securityQuestion: self.handleAction("generate-security-question"), rnType: "none", }); Ajax({ url: "/ajax/", type: "POST", data: { request: "comment/rn", id: e.data.added, type: self.props.type, }, }) break; default: self.setState({ loading: false }); alert(self.props.lang.generalError); break; } break; } }, fail(e) { self.setState({ loading: false }); alert(self.props.lang.serverError); } }); break; case "close": this.setState({ open: false, window: 0 }); break; case "set-and-open": this.parent = data.parent; this.setState({ open: true, window: 0, respondTo: data.respondTo }); if(this.props.variant == "floating") ReactDOM.findDOMNode(this.refs.name).focus(); break; case "focus": ReactDOM.findDOMNode(this.refs.name).focus(); break; } }, render() { var finishWindow, heading = [], content; if(this.props.variant == "static") { heading.push(

{this.props.lang[this.props.ratable ? "pridatRecenzi" : (this.props.type == "kr" ? "pridatKomentar_kr" : "pridatKomentar")]}

); } else if(this.props.variant == "floating") { heading.push(

{this.props.lang.pridatReakci}

); heading.push({this.props.lang[this.props.ratable ? "naRecenziOd" : (this.props.type == "kr" ? "naKomentarOd_kr" : "naKomentarOd")]+" "+this.state.respondTo}); } if(this.state.window == 1 && this.state.open) { finishWindow = (
{heading} {this.props.lang.zavrit}
{this.props.lang.odeslano}
{this.props.lang.text1}
{this.props.lang.dekujeme}
{this.props.lang.odejit}
); } if(this.props.variant == "static" || (this.props.variant == "floating" && this.state.window == 0)) { var rating, radio; if(this.props.ratable) { rating = (
{this.props.lang["doporucujes_"+this.props.type]}
); radio = (
{this.props.lang.celkoveHodnoceni}
); } content = (