{"version":3,"sources":["STDIN"],"sourcesContent":["\"use strict\";\n\ndocument.addEventListener('DOMContentLoaded', function() {\n var current_index = -1,\n anchor_list = getProductAnchorList(),\n current_page = null,\n current_active = null;\n \n function hidePage() {\n if(current_page) {\n var rect = current_page.getBoundingClientRect();\n \n if(rect.top < 0) {\n window.scrollBy(0, -rect.height);\n }\n \n current_page.parentNode.removeChild(current_page);\n current_page = null;\n }\n }\n \n function pageLoaded(after, page) {\n hidePage();\n \n after.parentNode.insertBefore(page, after.nextSibling);\n current_page = page;\n }\n \n function getNavList(node) {\n while(node && !node.classList.contains('navlist')) {\n node = node.parentNode;\n }\n \n return node;\n }\n\n function loadOffsetPage(offset) {\n if(current_index !== -1) {\n var target = anchor_list[current_index+offset];\n\n if(target) {\n loadProductPage(target, true);\n }\n }\n }\n\n function loadPrevPage() {\n loadOffsetPage(-1);\n }\n\n function loadNextPage() {\n loadOffsetPage(1);\n }\n \n function getID(node) {\n while(node && !node.getAttribute('id')) {\n node = node.parentNode;\n }\n \n return node ? node.getAttribute('id') : null;\n }\n \n function makeButton(parent, classname, text, callback) {\n var item = document.createElement('li'),\n button = document.createElement('button');\n \n button.classList.add(classname);\n \n if(callback) {\n button.addEventListener('click', callback);\n } else {\n button.disabled = true;\n }\n \n if(text) {\n var span = document.createElement('span');\n span.appendChild(document.createTextNode(text));\n button.appendChild(span);\n button.title = text;\n }\n \n item.appendChild(button);\n parent.appendChild(item);\n }\n \n function makeSpacer(parent) {\n var spacer = document.createElement('li');\n spacer.classList.add('spacer');\n parent.appendChild(spacer);\n }\n \n function hideActive() {\n if(current_active) {\n current_active.classList.remove('active');\n current_active = null;\n current_index = -1;\n }\n }\n \n function closeCurrent() {\n hidePage();\n hideActive();\n }\n \n function getProductAnchorList() {\n var list = [];\n var lists = document.getElementsByClassName('navlist');\n \n for(var i=0; i < lists.length; i++) {\n var anchors=lists[i].getElementsByTagName('a');\n \n for(var j=0; j < anchors.length; j++) {\n list.push(anchors[j]);\n }\n }\n \n return list;\n }\n\n function textContent(anchor) {\n return anchor.textContent.trim().replace(/\\s+/g, ' ');\n }\n \n function home() {\n window.location = /^([^?#]*)/.exec(window.location)[1];\n }\n \n function loadProductPage(anchor, scroll) {\n var id = getID(anchor);\n \n if(id) {\n window.history.replaceState(null, '', '#'+id);\n }\n \n var navlist = getNavList(anchor);\n var old_scroll_offset = null;\n \n if(scroll && current_active) {\n old_scroll_offset = getNavList(current_active).getBoundingClientRect().top;\n }\n \n hideActive();\n \n current_active = anchor.parentNode;\n current_active.classList.add('active');\n current_index = anchor_list.findIndex((item) => item === anchor);\n \n var request = new XMLHttpRequest();\n request.addEventListener('load', function () {\n var page = document.createElement('div');\n var nav = document.createElement('ul');\n nav.classList.add('buttons');\n \n var prevProduct, nextProduct;\n \n if(current_index !== -1) {\n prevProduct = anchor_list[current_index-1];\n nextProduct = anchor_list[current_index+1];\n }\n\n if(prevProduct) {\n makeButton(nav, 'prev', textContent(prevProduct), loadPrevPage);\n } else {\n makeButton(nav, 'prev', 'Previous');\n }\n\n if(nextProduct) {\n makeButton(nav, 'next', textContent(nextProduct), loadNextPage);\n } else {\n makeButton(nav, 'next', 'Next');\n }\n\n makeSpacer(nav);\n makeButton(nav, 'home', 'Home', home);\n makeButton(nav, 'close', 'Close', closeCurrent);\n \n page.classList.add('page');\n page.appendChild(nav);\n page.appendChild(document.importNode(this.response.getElementsByClassName('product')[0], true));\n pageLoaded(navlist, page);\n \n if(old_scroll_offset) {\n window.scrollBy(0, navlist.getBoundingClientRect().top-old_scroll_offset);\n }\n });\n \n request.open('GET', anchor.href);\n request.responseType = 'document';\n request.send();\n }\n \n function loadPage(event) {\n event.preventDefault();\n loadProductPage(this, false);\n }\n \n var list = getProductAnchorList();\n \n for(var i=0; i < list.length; i++) {\n list[i].addEventListener('click', loadPage, true);\n }\n \n function hashChanged() {\n var foo = /^#(prod\\-.*)$/.exec(window.location.hash);\n \n if(!foo) {\n return;\n }\n \n foo = document.getElementById(foo[1]);\n \n if(!foo) {\n return;\n }\n \n foo = foo.getElementsByTagName('a')[0];\n \n if(foo) {\n loadProductPage(foo);\n }\n }\n\n document.addEventListener('keydown', (event) => {\n switch(event.code) {\n case 'ArrowLeft':\n loadPrevPage();\n break;\n\n case 'ArrowRight':\n loadNextPage();\n break;\n }\n })\n\n var touches = [];\n\n function swipeDirection(touch) {\n var data = touches[touch.identifier];\n if(!data) {\n return \"\";\n }\n\n if(!current_page || data.page !== current_page) {\n // there's nothing to swipe.\n return \"\";\n }\n\n if(performance.now()-data.startTime > 1000) {\n // a swipe taking more than 1 second isn't valid.\n return \"\";\n }\n \n var dX = touch.screenX-data.startX, dY = touch.screenY-data.startY;\n var angle = Math.atan2(dY, dX);\n var distance = Math.sqrt(dX*dX+dY+dY);\n\n if(distance < 80) {\n // a swipe shorter than 80 pixels isn't valid.\n return \"\";\n }\n\n var direction = \"\";\n var angleThreshold = Math.PI*.1666 // approx 30 degrees.\n\n if(angle < -Math.PI+angleThreshold || angle > Math.PI-angleThreshold) {\n direction = \"left\";\n }\n\n if(angle > -angleThreshold && angle < angleThreshold) {\n direction = \"right\";\n }\n\n // if there's already a swipe happening, and it isn't this one, it isn't valid.\n touches.forEach((data, i) => {\n if(data.dir != \"\" && i != touch.identifier) {\n direction = \"\";\n }\n })\n\n return direction;\n }\n\n function updateTouch(touch) {\n var data = touches[touch.identifier];\n\n if(!data) {\n return null;\n }\n\n var dir = swipeDirection(touch);\n\n if(data.dir != \"\" && data.dir != dir) {\n data.page.style.transition = 'translate 1s';\n data.page.style.translate = 'none';\n\n delete touches[touch.identifier];\n return null;\n }\n\n data.dir = dir;\n data.page.style.transition = 'translate 150ms';\n data.page.style.translate = `${touch.screenX-data.startX}px`;\n\n return data;\n }\n\n document.addEventListener('touchstart', (e) => {\n if(current_page && e.target.closest('.page')) {\n for(let i=0; i < e.changedTouches.length; i++) {\n var touch = e.changedTouches[i];\n touches[touch.identifier] = {\n startTime: performance.now(),\n startX: touch.screenX,\n startY: touch.screenY,\n dir: \"\",\n page: current_page,\n };\n }\n }\n })\n\n document.addEventListener('touchmove', (e) => {\n for(let i=0; i < e.changedTouches.length; i++) {\n updateTouch(e.changedTouches[i])\n }\n })\n\n document.addEventListener('touchend', (e) => {\n for(let i=0; i < e.changedTouches.length; i++) {\n var touch = e.changedTouches[i];\n var data = updateTouch(touch);\n\n if(data) {\n switch(data.dir) {\n case \"right\":\n touches = [];\n data.page.style.transition = 'translate 1s, opacity 1s';\n data.page.style.translate = '100%';\n data.page.style.opacity = '0';\n loadPrevPage();\n break;\n\n case \"left\":\n touches = [];\n data.page.style.transition = 'translate 1s, opacity 1s';\n data.page.style.translate = '-100%';\n data.page.style.opacity = '0';\n loadNextPage();\n break;\n }\n\n data.dir = \"cancel\";\n updateTouch(touch);\n }\n }\n })\n\n document.addEventListener('touchcancel', (e) => {\n for(let i=0; i