/* * The client side script that cgit serves with every page. Its main job is * to refresh the relative ages that cgit_print_age renders in * source/ui-shared.c, so the thresholds, suffixes and class names tabulated * below mirror the constants there and the two have to move together. One * smaller piece follows, the highlight laid over the source line a URL * fragment names. Each piece is wrapped in a function of its own so that * nothing is left behind in the global scope. */ (function () { // Written the way SECONDS_PER_* are derived in source/cgit.h, so that the // bucket a browser picks is the bucket cgit_print_age already picked on the // server. A month is a twelfth of a year rather than thirty days, which is // the definition the server uses. var MINUTE = 60; var HOUR = 60 * MINUTE; var DAY = 24 * HOUR; var WEEK = 7 * DAY; var YEAR = 365 * DAY; var MONTH = YEAR / 12; // The five arrays are indexed together by the bucket an age falls into. The // search in render_age can stop one place past the last class, so the arrays // it reads there repeat their final entry. Each limit is twice the next unit // up, matching the thresholds cgit_print_age compares against. var age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks", "age-months", "age-years" ]; var age_suffix = [ "min.", "hours", "days", "weeks", "months", "years", "years" ]; var age_unit = [ MINUTE, HOUR, DAY, WEEK, MONTH, YEAR, YEAR ]; var age_limit = [ 2 * HOUR, 2 * DAY, 2 * WEEK, 2 * MONTH, 2 * YEAR, 2 * YEAR ]; var update_delay = [ 10, 5 * MINUTE, 30 * MINUTE, DAY, DAY, DAY, DAY ]; function render_age(element, age) { var text, bucket; for (bucket = 0; bucket < age_classes.length; bucket++) if (age < age_limit[bucket]) break; text = Math.round(age / age_unit[bucket]) + " " + age_suffix[bucket]; // Every age on the page is measured again on each pass, so most of // them are already reading correctly and writing to them would cost a // repaint for nothing. if (element.textContent != text) { element.textContent = text; // An age past the last limit is still counted in years, but // there is no class beyond age-years to put on it. if (bucket == age_classes.length) bucket--; if (element.className != age_classes[bucket]) element.className = age_classes[bucket]; } } /* * Measures every age on the page against the clock and books the next pass. * There is no point coming back before the coarsest unit on the page could * change, so a page already counted in hours is left alone for minutes and * one counted in years for a day. */ function refresh_ages() { var bucket, elements, i, age; var delay = 24 * 3600; var now = Math.round(new Date().getTime() / 1000); for (bucket = 0; bucket < age_classes.length; bucket++) { elements = document.getElementsByClassName(age_classes[bucket]); if (elements.length && update_delay[bucket] < delay) delay = update_delay[bucket]; for (i = 0; i < elements.length; i++) { age = now - elements[i].getAttribute("data-ut"); // A commit dated ahead of the viewer's clock would // otherwise show a negative age, and ui-shared.c // clamps it the same way. if (age < 0) age = 0; render_age(elements[i], age); } } window.setTimeout(refresh_ages, delay * 1000); } document.addEventListener("DOMContentLoaded", function () { // Nothing here depends on layout, so the first pass can run as soon // as the document is parsed. refresh_ages(); }, false); })(); /* * Washes a faded highlight over the source line a URL fragment names, either * a single line as in #n231 or a range as in #n5-n12. The line anchors live * in the number gutter, so the anchor is measured and a bar of the same * height is laid across the full width of the code. Without scripting the * CSS target rule still tints the line number itself. */ (function () { var bar = null; function place_bar() { var match, first, last, table; var table_box, first_box, last_box, top, bottom; if (bar) { bar.remove(); bar = null; } match = /^#n(\d+)(?:-n?(\d+))?$/.exec(location.hash); if (!match) return; first = document.getElementById("n" + match[1]); if (!first) return; last = (match[2] && document.getElementById("n" + match[2])) || first; table = first.closest("table"); if (!table) return; table_box = table.getBoundingClientRect(); first_box = first.getBoundingClientRect(); last_box = last.getBoundingClientRect(); top = Math.min(first_box.top, last_box.top) - table_box.top; bottom = Math.max(first_box.bottom, last_box.bottom) - table_box.top; bar = document.createElement("div"); bar.className = "line-hl"; bar.style.top = top + "px"; bar.style.height = (bottom - top) + "px"; table.appendChild(bar); // A browser only scrolls to a fragment that names a real id, which a // range never does, so bring the start of one into view here. if (match[2]) first.scrollIntoView({ block: "center" }); } document.addEventListener("DOMContentLoaded", place_bar, false); window.addEventListener("hashchange", place_bar, false); })();