UNPKG

dom-minimap

Version:
220 lines (172 loc) 6.95 kB
'use strict'; function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } function _templateObject5() { var data = _taggedTemplateLiteral(["<div style='position:relative;", "'>", "</div>"]); _templateObject5 = function _templateObject5() { return data; }; return data; } function _templateObject4() { var data = _taggedTemplateLiteral(["<div class=\"dom-minimap-scroll dom-minimap-scroll-bottom\" style=\"top:", "\"></div>"]); _templateObject4 = function _templateObject4() { return data; }; return data; } function _templateObject3() { var data = _taggedTemplateLiteral(["<div class=\"dom-minimap-scroll dom-minimap-scroll-top\" style=\"bottom:", "\"></div>"]); _templateObject3 = function _templateObject3() { return data; }; return data; } function _templateObject2() { var data = _taggedTemplateLiteral(["\n <div class=\"dom-minimap-section unselectable\"\n title=", " onclick=", "\n style=\"top:", ";bottom:", ";", "\">\n ", "\n </div>\n "]); _templateObject2 = function _templateObject2() { return data; }; return data; } function _templateObject() { var data = _taggedTemplateLiteral(["<div style=\"margin-top:20px;text-align:center\">loading</div>"]); _templateObject = function _templateObject() { return data; }; return data; } var yo = require('yo-yo'); var onload = require('on-load'); var nanoraf = require('nanoraf'); var insertCss = require('insert-css'); var debounce = require('lodash.debounce'); insertCss("\n .dom-minimap-section {\n position: absolute;\n background-color: lightgrey;\n overflow: hidden;\n color: grey;\n font-size: 11px;\n padding-left: 2px;\n border-radius: 2px;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n cursor: pointer;\n left: 5px; right: 5px;\n }\n\n .dom-minimap-section:hover {\n background-color: #e6e6e6;\n }\n\n .dom-minimap-scroll {\n pointer-events: none;\n position: absolute;\n background-color: rgba(0,0,0,0.15);\n top: 0; left: 0; right: 0; bottom: 0;\n }\n"); module.exports = minimap; function minimap(opts) { opts = opts || {}; opts.sections = opts.sections || 'minimap-section'; if (typeof opts.sections !== 'function') { var sectionName = opts.sections; opts.sections = function (container) { return Array.prototype.slice.call(container.getElementsByClassName(sectionName)); }; } opts.title = opts.title || 'data-section-title'; if (typeof opts.title !== 'function') { var titleName = opts.title; opts.title = function (section) { return section.getAttribute(titleName); }; } opts.tooltip = opts.tooltip || 'data-section-tooltip'; if (typeof opts.hover !== 'function') { var tooltipName = opts.tooltip; opts.tooltip = function (section) { return section.getAttribute(tooltipName); }; } opts.content = opts.content || 'minimap-content'; opts.mapStyle = typeof opts.mapStyle !== 'undefined' ? opts.mapStyle : 'height: 100%;'; opts.sectionStyle = opts.sectionStyle || ''; opts.clickOffset = opts.clickOffset || 0; var lastContainerHeight; var container; var element = document.createElement('div'); element.style.flex = '1'; var render = nanoraf(renderMap); var state = { opts: opts }; onload(element, function load() { container = typeof opts.content === 'string' ? document.getElementById(opts.content) : opts.content; lastContainerHeight = container.scrollHeight; // update on scroll event container.addEventListener('scroll', scrollUpdate); // update on window resize event window.addEventListener('resize', debounce(update), 100); // update on element loaded update(); }, null, minimap); element.addEventListener('wheel', function (event) { if (container) container.scrollTop = container.scrollTop + event.deltaY; }); function scrollUpdate() { state.scroll = getScroll(container); var top = element.querySelector('.dom-minimap-scroll-top'); var bottom = element.querySelector('.dom-minimap-scroll-bottom'); if (!top || !bottom) return; top.style.bottom = state.scroll.topFromBottom; bottom.style.top = state.scroll.bottomFromTop; } function update() { var sections = getSections(container, element, opts); if (!sections) return; var newState = Object.assign({}, state, { sections: sections, scroll: getScroll(container) }); render(newState, state); state = newState; } return function () { if (container) { setTimeout(function () { if (lastContainerHeight !== container.scrollHeight) { update(); } }, 1); } return element; }; function scrollTo() { var top = this.style.top.slice(0, -1); if (top) container.scrollTop = Math.round(container.scrollHeight * top / 100) + opts.clickOffset; } function renderMap(state) { var content = yo(_templateObject()); if (state.sections) { content = state.sections.map(function (section) { return yo(_templateObject2(), section.tooltip, scrollTo, section.top, section.bottom, typeof opts.sectionStyle === 'function' ? opts.sectionStyle(section) : opts.sectionStyle, section.title); }).concat([yo(_templateObject3(), state.scroll.topFromBottom), yo(_templateObject4(), state.scroll.bottomFromTop)]); } yo.update(element, yo(_templateObject5(), opts.mapStyle, content)); } } function getScroll(container) { var top = container.scrollTop; var cHeight = container.clientHeight; var height = container.scrollHeight; return { topFromBottom: (height - top) / height * 100 + '%', bottomFromTop: (1 - (height - top - cHeight) / height) * 100 + '%' }; } function getSections(content, map, opts) { if (!map.parentElement) return false; var cHeight = content.scrollHeight; var mHeight = map.parentElement.clientHeight; var cBounds = content.getBoundingClientRect(); var scrollTop = content.scrollTop; return opts.sections(content).map(function (section) { var bounds = section.getBoundingClientRect(); var top = (bounds.top - cBounds.top + scrollTop) / cHeight; var bottom = (bounds.bottom - cBounds.top + scrollTop) / cHeight; return { top: top * 100 + '%', bottom: applyPadding((1 - bottom) * 100 + '%', opts.paddingBottom), title: opts.title(section, mHeight * bottom - mHeight * top), tooltip: opts.tooltip(section), element: section }; }); } function applyPadding(value, padding) { if (!padding) return value; return "calc(".concat(value, " + ").concat(padding, ")"); }