diff --git a/Makefile b/Makefile index ee7aae7..304b1cc 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ test-browser/tests.js: test/ examples: @./bin/styledocco -n StyleDocco -o ./examples/styledocco \ - --include share/previews.css --include share/docs.js share/docs.css + --include share/previews.css --include share/docs.ui.js share/docs.css @./bin/styledocco -n "Twitter Bootstrap" -o ./examples/bootstrap/docs \ examples/bootstrap/less diff --git a/cli.js b/cli.js index 892c85f..df5af62 100644 --- a/cli.js +++ b/cli.js @@ -20,7 +20,8 @@ marked.setOptions({ sanitize: false, gfm: true }); // Helper functions var mincss = function(css) { return cleancss.process(css); }; -var minjs = uglifyjs; +//var minjs = uglifyjs; +var minjs = function(str) { return str; }; var pluck = function(arr, prop) { return arr.map(function(item) { return item[prop]; }); }; @@ -148,7 +149,15 @@ var cli = function(options) { docs: function(cb) { async.parallel({ css: async.apply(fs.readFile, resourcesDir + 'docs.css', 'utf8'), - js: async.apply(fs.readFile, resourcesDir + 'docs.js', 'utf8') + js: function(cb) { + async.parallel([ + async.apply(fs.readFile, resourcesDir + 'docs.ui.js', 'utf8'), + async.apply(fs.readFile, resourcesDir + 'docs.previews.js', 'utf8') + ], function(err, res) { + if (err != null) return cb(err); + cb(null, res.join('')); + }); + } }, cb); }, // Extra JavaScript and CSS files to include in previews. diff --git a/share/docs.css b/share/docs.css index bca3a83..c4c12c6 100644 --- a/share/docs.css +++ b/share/docs.css @@ -253,7 +253,7 @@ Fixed to top with a small drop shadow. border-right-color: transparent; border-bottom-color: transparent; } -.search-results, +.nav-results, .dropdown { display: none; position: absolute; @@ -271,25 +271,26 @@ Fixed to top with a small drop shadow. border-radius: 3px; box-shadow: 0 0 3px hsla(207, 5%, 0%, .2); } -.search-results { +.nav-results { right: 0; left: auto; + padding: 5px 0; } -.search-results-filename { +.nav-results-filename { display: block; font-size: 10px; opacity: .75; } -.search-results a { +.nav-results a { display: block; line-height: 15px; padding: 5px 10px; } /* Match everything after the first non-hidden `li`. */ -.search-results li:not([hidden]) ~ li a { +.nav-results li:not([hidden]) ~ li a { border-top: 1px solid hsla(27, 10%, 90%, .1); } -.search-results.is-active, +.nav-results.is-active, .dropdown.is-active { display: block; } @@ -299,11 +300,11 @@ Fixed to top with a small drop shadow. .dropdown li:hover { background-color: hsl(207, 10%, 22%); } -.search { +.nav { float: right; position: relative; } -.search input[type="search"] { +.nav input[type="search"] { padding: 2px 4px; color: #fff; width: 150px; @@ -314,13 +315,13 @@ Fixed to top with a small drop shadow. border-radius: 10px; -webkit-appearance: textfield; } - input[type="search"]:focus { + .nav input[type="search"]:focus { outline: 0; background: hsla(207, 7%, 45%, .9); } -.ir.toc { +i.toc { width: 24px; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAVCAMAAABrN94UAAAACVBMVEX///8AAAD///9+749PAAAAAnRSTlMfALvJw6YAAAArSURBVHjazZCxCQAACMNs/j9acBWHgkOzZgkpQMVmhCyhA18EVymy6udVAxE6Av61mQeKAAAAAElFTkSuQmCC); + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAVCAYAAABc6S4mAAAAAXNSR0IArs4c6QAAAFZJREFUOMtjfH310H8GKBDRsmV8c+2wPAMDwwMGKgEmdAERLduHDFQETAw0Boz///+nqQU09wHNLWB5c+3waCoaTUVUTkUMDAwMyGKjQTSaikbLIsoBAOrOK0XRs05qAAAAAElFTkSuQmCC); } /* @@ -329,41 +330,45 @@ Fixed to top with a small drop shadow. .settings { text-align: center; } -.settings button { +.bar button { display: inline-block; vertical-align: middle; + margin: 0 7px; + background: transparent; +} +.bar i { + display: inline-block; opacity: .6; height: 30px; - margin: 0 7px; background-color: transparent; background-repeat: no-repeat; background-position: 50%; } -.settings button:first-child { +.bar button:first-child { margin-left: 0; } -.settings button:hover, -.settings button.is-active { +.bar button:hover i, +.bar button.is-active i { opacity: .9; } /* Glyphicons Free. http://glyphicons.com */ -.settings .desktop { +i.desktop { width: 28px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYBAMAAAAbsoCxAAAAAXNSR0IArs4c6QAAABJQTFRF////69XC69XC69XC69XC69XCsKjc1AAAAAV0Uk5TAD9Nz+9utsS9AAAANklEQVQYV2NwDUUCIQyhKIAhVAkJDA8umgeRQEAoA1poQABQGRJgDA0VQOIKh4YawjlwYzG4AElRPlfk7mo+AAAAAElFTkSuQmCC); } -.settings .laptop { +i.laptop { width: 28px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAPCAMAAADAkV+TAAAAElBMVEXr1cLm0L4AAADr1cLdyLbr1cK81tkGAAAABHRSTlMPswBNJIULqAAAAC5JREFUeNrtycENACAMw8A01PuvTCWeFMQAWP6dbCVN6ZKatoWGsfXxDbmkOFtMvhcFsfZOYKIAAAAASUVORK5CYII=); } -.settings .tablet { +i.tablet { width: 20px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAMAAABLAV/qAAAAG1BMVEXfyrjr1cLr1cLr1cLr1cLr1cIAAADr1cLr1cJ8BJOtAAAACHRSTlPbPxN/iY8ATT4ucloAAAA3SURBVHja7dFLCgAgDEPBfmPvf2JBiiCtBxCcVXjbkEdBFI1rHIcfn4mLiVi5mAHe0XMooDl9Ak7UD3akKiswAAAAAElFTkSuQmCC); } -.settings .smartphone { +i.smartphone { width: 14px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAYCAMAAAD9GTxlAAAAGFBMVEXr1cIAAADfyrjr1cLr1cLr1cLdyLbr1cLLd4FAAAAABnRSTlNvANsPP009vtSqAAAAOUlEQVR42t2QSQ4AIAgDi2D5/4+NG4H4A+fUSU8tjB7QsCwcXni1B5/qhGV+U21JIXICc8t7LPexA4RJB7GsUfWoAAAAAElFTkSuQmCC); } -.settings .featurephone { +i.featurephone { width: 15px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAZCAMAAADZh4T+AAAAJFBMVEXr1cLdyLbr1cLizbvr1cLr1cLfyrjr1cIAAADr1cLdyLbr1cLNhLPeAAAACnRSTlOP7qDHL0/bfwBNv2ECtwAAADpJREFUeNrNyjsKACAQQ8H4j+b+9xUL2UXsdSDFg4AsSFpqLCRylQkZQ96A1I30YTvXJrl39oN/k9cm7WsOQEZJiNEAAAAASUVORK5CYII=); } diff --git a/share/docs.js b/share/docs.js deleted file mode 100644 index 74c1a04..0000000 --- a/share/docs.js +++ /dev/null @@ -1,262 +0,0 @@ -// StyleDocco JavaScript for documentation -// ======================================= -/*global index:false*/ - -(function() { - -'use strict'; - -// Helper functions -// ================ -// Using `Array.prototype` to make them work on Array-like objects. -var filter = function(arr, it) { return Array.prototype.filter.call(arr, it); }; -var forEach = function(arr, it) { return Array.prototype.forEach.call(arr, it); }; -var map = function(arr, it) { return Array.prototype.map.call(arr, it); }; -var pluck = function(arr, prop) { return map(arr, function(item) { return item[prop]; } ); }; - -// Parse `key=value; key=value` strings (for cookies). -var keyvalParse = function(str) { - var obj = {}; - var pairs = str.split(';'); - for (var i = 0; pairs.length > i; i++) { - var kvs = pairs[i].trim().split('='); - obj[kvs[0]] = kvs[1]; - } - return obj; -}; -var postMessage = function(target, msg) { - target.contentDocument.defaultView.postMessage(msg, '*'); -}; - -var bodyEl = document.getElementsByTagName('body')[0]; -var headEl = document.getElementsByTagName('head')[0]; - - -// Iframe rendering and handling -// ============================= -(function() { - // Don't run this function if we're rendering a preview page. - if (location.hash === '#__preview__' || location.protocol === 'data:') return; - - var settingsEl = bodyEl.getElementsByClassName('settings')[0]; - var resizeableElOffset = 30; // `.resizeable` padding - var resizeableEls = bodyEl.getElementsByClassName('resizeable'); - var resizePreviews = function(width) { - document.cookie = 'preview-width=' + width; - forEach(resizeableEls, function(el) { - if (width === 'auto') width = el.parentNode.offsetWidth; - el.style.width = width + 'px'; - // TODO: Add CSS transitions and update height after `transitionend` event - postMessage(el.getElementsByTagName('iframe')[0], 'getHeight'); - }); - }; - - window.addEventListener('message', function (ev) { - if (ev.data == null || !ev.source) return; - var data = ev.data; - var sourceFrameEl = document.getElementsByName(ev.source.name)[0]; - // Set iframe height - if (data.height != null && sourceFrameEl) { - sourceFrameEl.parentNode.style.height = (data.height + resizeableElOffset) + 'px'; - } - }, false); - - // Get preview styles intended for preview iframes. - var styles = pluck(headEl.querySelectorAll('style[type="text/preview"]'), 'innerHTML').join(''); - // Get preview scripts intended for preview iframes. - var scripts = pluck(headEl.querySelectorAll('script[type="text/preview"]'), 'innerHTML').join(''); - - // Check if browser treats data uris as same origin. - // This will always display an error in WebKit. - var iframeEl = document.createElement('iframe'); - iframeEl.src = 'data:text/html,'; - bodyEl.appendChild(iframeEl); - iframeEl.addEventListener('load', function() { - var support = {}; - if (this.contentDocument) support.dataIframes = true; - else support.dataIframes = false; - this.parentNode.removeChild(this); - - // Loop through code textareas and render the code in iframes. - var previewUrl = location.href.split('#')[0] + '#__preview__'; - var iframeId = 0; - forEach(bodyEl.getElementsByTagName('textarea'), function(codeEl) { - var previewEl, resizeableEl, iframeEl; - previewEl = document.createElement('div'); - previewEl.appendChild(resizeableEl = document.createElement('div')); - resizeableEl.appendChild(iframeEl = document.createElement('iframe')); - previewEl.className = 'preview'; - resizeableEl.className = 'resizeable'; - iframeEl.setAttribute('scrolling', 'no'); - iframeEl.name = 'iframe' + iframeId++; - iframeEl.addEventListener('load', function(event) { - var htmlEl, bodyEl, scriptEl, styleEl; - var doc = this.contentDocument; - // Abort if we're loading a data uri in a browser without support. - if (!support.dataIframes && this.src !== previewUrl) { - return; - } else if (this.src === previewUrl) { - // Replace iframe content with the preview HTML. - htmlEl = doc.createElement('html'); - htmlEl.appendChild(doc.createElement('head')); - htmlEl.appendChild(bodyEl = doc.createElement('body')); - bodyEl.innerHTML = codeEl.textContent; - doc.replaceChild(htmlEl, doc.documentElement); - } - var win = doc.defaultView; - // Add scripts and styles. - var headEl = doc.createElement('head'); - headEl.appendChild(styleEl = doc.createElement('style')); - headEl.appendChild(scriptEl = doc.createElement('script')); - scriptEl.textContent = scripts; - styleEl.textContent = styles; - var oldHeadEl = doc.getElementsByTagName('head')[0]; - oldHeadEl.parentNode.replaceChild(headEl, oldHeadEl); - postMessage(iframeEl, 'getHeight'); - }); - var dataHtmlPrefix = 'data:text/html;charset=utf-8,' + encodeURIComponent(''); - if (!support.dataIframes) { - iframeEl.setAttribute('src', previewUrl); - } else { - iframeEl.setAttribute('src', dataHtmlPrefix + encodeURIComponent(codeEl.textContent)); - } - codeEl.parentNode.insertBefore(previewEl, codeEl); - resizeableEl.style.width = resizeableEl.offsetWidth + 'px'; - - var previewWidth = keyvalParse(document.cookie)['preview-width']; - if (previewWidth) { - resizePreviews(previewWidth); - forEach(settingsEl.getElementsByClassName('is-active'), function(el) { - el.classList.remove('is-active'); - }); - settingsEl.querySelector('button[data-width="' + previewWidth + '"]') - .classList.add('is-active'); - } - // An element with the same styles and content as the textarea to - // calculate the height of the textarea content. - var mirrorEl = document.createElement('div'); - mirrorEl.className = 'preview-code'; - mirrorEl.style.position = 'absolute'; - mirrorEl.style.left = '-99999px'; - bodyEl.appendChild(mirrorEl); - // Auto update iframe when `textarea` changes and auto-resize textarea - // to fit content. - var maxHeight = parseInt( - window.getComputedStyle(codeEl).getPropertyValue('max-height'), - 10); - var codeDidChange = function() { - iframeEl.contentDocument.body.innerHTML = codeEl.value; - mirrorEl.textContent = codeEl.value + '\n'; - var height = mirrorEl.offsetHeight + 2; - if (height >= maxHeight) { - codeEl.style.overflow = 'auto'; - } else { - codeEl.style.overflow = 'hidden'; - } - codeEl.style.height = (mirrorEl.offsetHeight + 2) + 'px'; - postMessage(iframeEl, 'getHeight'); - }; - codeEl.addEventListener('keypress', codeDidChange); - codeEl.addEventListener('keyup', codeDidChange); - codeDidChange(); - }); - }); - - // Resizing buttons - if (settingsEl) { - settingsEl.addEventListener('click', function(event) { - if (event.target.tagName.toLowerCase() !== 'button') return; - event.preventDefault(); - var btn = event.target; - forEach(btn.parentNode.getElementsByClassName('is-active'), function(el) { - el.classList.remove('is-active'); - }); - btn.classList.add('is-active'); - var width = btn.dataset.width; - resizePreviews(width); - }); - } -})(); - -// Dropdown menus -bodyEl.addEventListener('click', function(event) { - var el = event.target; - var activateDropdown = false; - if (el.classList.contains('dropdown-toggle')) { - event.preventDefault(); - // Click fired on an inactive dropdown toggle - if (!el.classList.contains('is-active')) activateDropdown = true; - } - // Deactivate *all* dropdowns - forEach(bodyEl.getElementsByClassName('dropdown-toggle'), function(el) { - el.classList.remove('is-active'); - el.parentNode.getElementsByClassName('dropdown')[0].classList.remove('is-active'); - }); - // Activate the clicked dropdown - if (activateDropdown) { - el.classList.add('is-active'); - el.parentNode.getElementsByClassName('dropdown')[0].classList.add('is-active'); - } -}); - - -(function() { - var navEl = bodyEl.getElementsByClassName('nav')[0]; - if (!navEl) return; - - // Generate HTML elements for each ToC item - var searchList = document.createElement('ul'); - searchList.className = 'search-results'; - forEach(searchIndex, function(item) { - var el = document.createElement('li'); - var a = document.createElement('a'); - el.appendChild(a); - a.href = item.url; - a.innerHTML = item.title; - if (item.filename) { - var filenameEl = document.createElement('span'); - filenameEl.innerHTML = item.filename; - filenameEl.className = 'search-results-filename'; - a.appendChild(filenameEl); - } - el._title = item.title.toLowerCase(); - el.hidden = true; - searchList.appendChild(el); - }); - - navEl.appendChild(searchList); - - var searchItems = searchList.children; - - var doSearch = function(ev) { - // Hide all items - forEach(searchItems, function(el) { el.hidden = true; }); - var val = this.value.toLowerCase(); - var filtered = []; - if (val !== '') { - filtered = filter(searchItems, function(el) { - return (el._title.indexOf(val) !== -1); - }); - } - if (filtered.length > 0) { - forEach(filtered, function(el) { el.hidden = false; }); - searchList.classList.add('is-active'); - } else { - searchList.classList.remove('is-active'); - } - }; - var searchEl = navEl.querySelector('input[type="search"]'); - searchEl.addEventListener('keyup', doSearch); - searchEl.addEventListener('focus', doSearch); - // Hide search results - bodyEl.addEventListener('click', function(event) { - if (event.target.parentNode.className === 'search') return; - searchList.classList.remove('is-active'); - }); - // Reset search box - searchList.addEventListener('click', function(event) { - searchEl.value = ''; - }); -})(); - -})(); diff --git a/share/docs.previews.js b/share/docs.previews.js new file mode 100644 index 0000000..9581354 --- /dev/null +++ b/share/docs.previews.js @@ -0,0 +1,130 @@ +// StyleDocco documentation code/preview rendering and handling +// ================================================================== +// Takes the HTML code from preview textareas and renders iframes with +// the specified preview CSS and JavaScript applied. + +(function() { + +'use strict'; + +// Abort if rendering a preview page (to avoid recursive iframe loading). +// This can happen in WebKit where we set the iframe src to `location.href`. +if (location.hash === '#__preview__' || location.protocol === 'data:') return; + +// Helper functions. Using `Array.prototype` to make them work on NodeLists. +var forEach = function(arr, it) { return Array.prototype.forEach.call(arr, it); }; +var map = function(arr, it) { return Array.prototype.map.call(arr, it); }; +var pluck = function(arr, prop) { return map(arr, function(item) { return item[prop]; } ); }; + +var postMessage = function(target, msg) { + target.contentDocument.defaultView.postMessage(msg, '*'); +}; + +var headEl = document.getElementsByTagName('head')[0]; +var bodyEl = document.getElementsByTagName('body')[0]; + +// Get preview styles intended for preview iframes. +var styles = pluck( + headEl.querySelectorAll('style[type="text/preview"]'), + 'innerHTML').join(''); +// Get preview scripts intended for preview iframes. +var scripts = pluck( + headEl.querySelectorAll('script[type="text/preview"]'), + 'innerHTML').join(''); + +var previewUrl = location.href.split('#')[0] + '#__preview__'; + +// Check if browser treats data uris as same origin. +// This will always display an error in WebKit :-( +var iframeEl = document.createElement('iframe'); +iframeEl.src = 'data:text/html,'; +bodyEl.appendChild(iframeEl); +iframeEl.addEventListener('load', function() { + var support = { sameOriginDataUri: false }; + if (this.contentDocument) support.sameOriginDataUri = true; + this.parentNode.removeChild(this); + // Loop through code textareas and render the code in iframes. + forEach(bodyEl.getElementsByTagName('textarea'), function(codeEl, idx) { + addIframe(codeEl, support, idx); + autoResizeTextArea(codeEl); + }); +}); + +var addIframe = function(codeEl, support, iframeId) { + var previewEl, resizeableEl, iframeEl; + previewEl = document.createElement('div'); + previewEl.appendChild(resizeableEl = document.createElement('div')); + resizeableEl.appendChild(iframeEl = document.createElement('iframe')); + previewEl.className = 'preview'; + resizeableEl.className = 'resizeable'; + iframeEl.setAttribute('scrolling', 'no'); + iframeEl.name = 'iframe' + iframeId++; + iframeEl.addEventListener('load', function(event) { + var htmlEl, bodyEl, scriptEl, styleEl, headEl, oldHeadEl, doc; + doc = this.contentDocument; + // Abort if we're loading a data uri in a browser without same + // origin data uri support. + if (!support.sameOriginDataUri && this.src !== previewUrl) { + return; + // Otherwise replace iframe content with the preview code. + } else if (this.src === previewUrl) { + htmlEl = doc.createElement('html'); + htmlEl.appendChild(doc.createElement('head')); + htmlEl.appendChild(bodyEl = doc.createElement('body')); + bodyEl.innerHTML = codeEl.textContent; + doc.replaceChild(htmlEl, doc.documentElement); + } + // Add scripts and styles. + headEl = doc.createElement('head'); + headEl.appendChild(styleEl = doc.createElement('style')); + headEl.appendChild(scriptEl = doc.createElement('script')); + scriptEl.textContent = scripts; + styleEl.textContent = styles; + oldHeadEl = doc.getElementsByTagName('head')[0]; + oldHeadEl.parentNode.replaceChild(headEl, oldHeadEl); + postMessage(iframeEl, 'getHeight'); + }); + if (!support.sameOriginDataUri) { + var iframeSrc = previewUrl; + } else { + var iframeSrc = 'data:text/html;charset=utf-8,' + encodeURIComponent( + '' + + codeEl.textContent); + } + iframeEl.setAttribute('src', iframeSrc); + var codeDidChange = function() { + iframeEl.contentDocument.body.innerHTML = this.value; + postMessage(iframeEl, 'getHeight'); + }; + codeEl.addEventListener('keypress', codeDidChange); + codeEl.addEventListener('keyup', codeDidChange); + codeEl.parentNode.insertBefore(previewEl, codeEl); +}; + +var autoResizeTextArea = function(el) { + // Add an element with the same styles and content as the textarea to + // calculate the height of the textarea content. + var mirrorEl = document.createElement('div'); + mirrorEl.className = 'preview-code'; + mirrorEl.style.position = 'absolute'; + mirrorEl.style.left = '-9999px'; + bodyEl.appendChild(mirrorEl); + var maxHeight = parseInt( + window.getComputedStyle(el).getPropertyValue('max-height'), + 10); + var codeDidChange = function(ev) { + mirrorEl.textContent = this.value + '\n'; + var height = mirrorEl.offsetHeight + 2; // Account for borders. + if (height >= maxHeight) { + this.style.overflow = 'auto'; + } else { + this.style.overflow = 'hidden'; + } + this.style.height = (mirrorEl.offsetHeight + 2) + 'px'; + }; + el.addEventListener('keypress', codeDidChange); + el.addEventListener('keyup', codeDidChange); + codeDidChange.call(el); +}; + +})(); diff --git a/share/docs.ui.js b/share/docs.ui.js new file mode 100644 index 0000000..f1af664 --- /dev/null +++ b/share/docs.ui.js @@ -0,0 +1,160 @@ +// StyleDocco documentation user interface elements +// ================================================================== +// Dropdown, search, display settings. + +(function() { + +'use strict'; + +/*global index:false*/ + +// Helper functions. Using `Array.prototype` to make them work on NodeLists. +var filter = function(arr, it) { return Array.prototype.filter.call(arr, it); }; +var forEach = function(arr, it) { return Array.prototype.forEach.call(arr, it); }; + +// Parse `key=value; key=value` strings (for cookies). +var keyvalParse = function(str) { + var obj = {}; + var pairs = str.split(';'); + for (var i = 0; pairs.length > i; i++) { + var kvs = pairs[i].trim().split('='); + obj[kvs[0]] = kvs[1]; + } + return obj; +}; +var postMessage = function(target, msg) { + target.contentDocument.defaultView.postMessage(msg, '*'); +}; + +var headEl = document.getElementsByTagName('head')[0]; +var bodyEl = document.getElementsByTagName('body')[0]; + +var settingsEl = bodyEl.getElementsByClassName('settings')[0]; +var resizeableElOffset = 30; // `.resizeable` padding +var resizeableEls = bodyEl.getElementsByClassName('resizeable'); +var resizePreviews = function(width) { + document.cookie = 'preview-width=' + width; + forEach(resizeableEls, function(el) { + if (width === 'auto') width = el.parentNode.offsetWidth; + el.style.width = width + 'px'; + // TODO: Add CSS transitions and update height after `transitionend` event + postMessage(el.getElementsByTagName('iframe')[0], 'getHeight'); + }); +}; + +window.addEventListener('message', function (ev) { + if (ev.data == null || !ev.source) return; + var data = ev.data; + var sourceFrameEl = document.getElementsByName(ev.source.name)[0]; + // Set iframe height + if (data.height != null && sourceFrameEl) { + sourceFrameEl.parentNode.style.height = (data.height + resizeableElOffset) + 'px'; + } +}, false); + +var previewWidth = keyvalParse(document.cookie)['preview-width']; +if (previewWidth) { + resizePreviews(previewWidth); + forEach(settingsEl.getElementsByClassName('is-active'), function(el) { + el.classList.remove('is-active'); + }); + settingsEl.querySelector('button[data-width="' + previewWidth + '"]') + .classList.add('is-active'); +} +// Resizing buttons +if (settingsEl) { + settingsEl.addEventListener('click', function(event) { + if (event.target.tagName.toLowerCase() !== 'button') return; + event.preventDefault(); + var btn = event.target; + forEach(btn.parentNode.getElementsByClassName('is-active'), function(el) { + el.classList.remove('is-active'); + }); + btn.classList.add('is-active'); + var width = btn.dataset.width; + resizePreviews(width); + }); +} + +// Dropdown menus +bodyEl.addEventListener('click', function(event) { + var el = event.target; + var activateDropdown = false; + if (el.classList.contains('dropdown-toggle')) { + event.preventDefault(); + // Click fired on an inactive dropdown toggle + if (!el.classList.contains('is-active')) activateDropdown = true; + } + // Deactivate *all* dropdowns + forEach(bodyEl.getElementsByClassName('dropdown-toggle'), function(el) { + el.classList.remove('is-active'); + el.parentNode.getElementsByClassName('dropdown')[0].classList.remove('is-active'); + }); + // Activate the clicked dropdown + if (activateDropdown) { + el.classList.add('is-active'); + el.parentNode.getElementsByClassName('dropdown')[0].classList.add('is-active'); + } +}); + + +(function() { + var navEl = bodyEl.getElementsByClassName('nav')[0]; + if (!navEl) return; + + // Generate HTML elements for each ToC item + var searchList = document.createElement('ul'); + searchList.className = 'nav-results'; + forEach(searchIndex, function(item) { + var el = document.createElement('li'); + var a = document.createElement('a'); + el.appendChild(a); + a.href = item.url; + a.innerHTML = item.title; + if (item.filename) { + var filenameEl = document.createElement('span'); + filenameEl.innerHTML = item.filename; + filenameEl.className = 'nav-results-filename'; + a.appendChild(filenameEl); + } + el._title = item.title.toLowerCase(); + el.hidden = true; + searchList.appendChild(el); + }); + + navEl.appendChild(searchList); + + var searchItems = searchList.children; + + var doSearch = function(ev) { + // Hide all items + forEach(searchItems, function(el) { el.hidden = true; }); + var val = this.value.toLowerCase(); + var filtered = []; + if (val !== '') { + filtered = filter(searchItems, function(el) { + return (el._title.indexOf(val) !== -1); + }); + } + if (filtered.length > 0) { + forEach(filtered, function(el) { el.hidden = false; }); + searchList.classList.add('is-active'); + } else { + searchList.classList.remove('is-active'); + } + }; + var searchEl = navEl.querySelector('input[type="search"]'); + searchEl.addEventListener('keyup', doSearch); + searchEl.addEventListener('focus', doSearch); + // Hide search results + bodyEl.addEventListener('click', function(event) { + if (event.target.parentNode.className === 'nav') return; + searchList.classList.remove('is-active'); + }); + // Reset search box + searchList.addEventListener('click', function(event) { + searchEl.value = ''; + }); +})(); + +})();