(function() { // Run callback when DOM is ready function DOMReady(fn) { // Run now if DOM has already loaded as we're loading async if(['interactive', 'complete'].indexOf(document.readyState) >= 0) { fn(); // Otherwise wait for DOM } else { document.addEventListener('DOMContentLoaded', fn); } } // Feature tester function FeatureTester(tests) { var self = this; self.tests = tests; self.test = function(features) { if(!features || !features.length) { return false; } return features.every(function(feature) { return self.tests[feature]; }); } } // Init once, don't re-detect features each time var supports = new FeatureTester({ localStorage: (function() { try { localStorage.setItem('test', 'test'); localStorage.removeItem('test'); return true; } catch (e) { return false; } })(), inlineSVG: (function() { var div = document.createElement('div'); div.innerHTML = ''; return ( typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI ) == 'http://www.w3.org/2000/svg'; })(), querySelector: typeof document.querySelector === 'function', classList: 'classList' in document.createElement('div') }); // Favourite nodes var favouriteNodes = { // Key used in localStorage storageKey: 'heartedNodes', // Url to heart SVG heartPath: '/assets/heart.svg', // Class added to heart SVG element when active activeClass: 'hearted', // Gets current node hash getCurrentNode: function() { var node = /^\/node\/([a-zA-Z0-9]+)/.exec(window.location.pathname); return node ? node[1] : node; }, // Gets hearted nodes getHeartedNodes: function() { return JSON.parse(localStorage.getItem(favouriteNodes.storageKey)) || []; }, // Saves hearted nodes saveHeartedNodes: function(heartedNodes) { return localStorage.setItem(favouriteNodes.storageKey, JSON.stringify(heartedNodes)); }, // Checks if node is hearted isHearted: function(node) { return favouriteNodes.getHeartedNodes().indexOf(node) > -1; }, // Heart node heart: function(node) { var heartedNodes = favouriteNodes.getHeartedNodes(); heartedNodes.push(node); return favouriteNodes.saveHeartedNodes(heartedNodes); }, // Unheart node unHeart: function(node) { var heartedNodes = favouriteNodes.getHeartedNodes(); var nodeIndex = heartedNodes.indexOf(node); heartedNodes.splice(nodeIndex, 1); return favouriteNodes.saveHeartedNodes(heartedNodes); }, // Load SVG, run callback when loaded loadSVG: function(cb) { // Get heart SVG var xhr = new XMLHttpRequest(); xhr.open('GET', favouriteNodes.heartPath); xhr.addEventListener('load', function() { // Create heart SVG elem var div = document.createElement('div'); div.innerHTML = xhr.responseText; favouriteNodes.heartEl = div.firstChild; // Show heart as active if we've already hearted this node var node = favouriteNodes.getCurrentNode(); if(favouriteNodes.isHearted(node)) { favouriteNodes.heartEl.classList.add(favouriteNodes.activeClass); } // Add click handler favouriteNodes.heartEl.addEventListener('click', function() { // Heart/unheart node var node = favouriteNodes.getCurrentNode(); if(favouriteNodes.isHearted(node)) { favouriteNodes.heartEl.classList.remove(favouriteNodes.activeClass); favouriteNodes.unHeart(node); } else { favouriteNodes.heartEl.classList.add(favouriteNodes.activeClass); favouriteNodes.heart(node); } }); // Run callback cb(favouriteNodes.heartEl); }); xhr.send(); } }; // Init favourite nodes if(supports.test(['localStorage', 'inlineSVG', 'querySelector', 'classList'])) { // Start loading heart SVG before DOM favouriteNodes.loadSVG(function(heartEl) { // Then inject into DOM when it's ready DOMReady(function() { var titleEl = document.querySelector('h2.node-title'); if(titleEl) { titleEl.insertBefore(heartEl, titleEl.firstChild); } }); }); } // Add ios class to body on iOS devices if(supports.test(['classList'])) { DOMReady(function() { if( /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream && document.body.classList ) { document.body.classList.add('ios'); } }); } })();