1(function () { 2 "use strict"; 3 4 /* --- 1. dead frames ------------------------------------------------------- 5 The inline handler (wDrop, declared in <head>) does the work: first failure 6 swaps the Photon url for the origin one, second failure removes the frame. 7 This sweep only catches what the handler cannot: a frame that answered 200 8 with a 1x1 pixel, and frames that die after the last error event. The 9 viewer's own <img> starts as a 1x1 gif, so it is NOT in this selector. */ 10 function sweep() { 11 var imgs = document.querySelectorAll(".frame img, [data-set] img, .story img"); 12 for (var n = 0; n < imgs.length; n++) { 13 var im = imgs[n]; 14 if (im.complete && im.naturalWidth <= 1 && window.wDrop) window.wDrop(im); 15 } 16 } 17 18 /* --- 2. no ragged last row ------------------------------------------------ 19 Tiles remove themselves when they die, so a grid that was flush in the 20 markup ends in a half-empty strip of bare ground. Rows are grouped by 21 offsetTop, which works at every breakpoint and with a banner tile that 22 spans the whole width; only a SHORT last row is dropped. */ 23 function trimTail(wall) { 24 var kids = Array.prototype.slice.call(wall.children); 25 if (kids.length < 4) return; 26 var rows = {}, i, t; 27 for (i = 0; i < kids.length; i++) { 28 t = Math.round(kids[i].offsetTop); 29 (rows[t] = rows[t] || []).push(kids[i]); 30 } 31 var tops = Object.keys(rows).map(Number).sort(function (a, b) { return a - b; }); 32 if (tops.length < 2) return; 33 var full = 0; 34 for (i = 0; i < tops.length; i++) full = Math.max(full, rows[tops[i]].length); 35 var last = rows[tops[tops.length - 1]]; 36 if (last.length < full) for (i = 0; i < last.length; i++) last[i].remove(); 37 } 38 39 /* A record whose FIRST frame is dead would open with no lead at all â about one 40 record in twelve. Promote the first surviving strip frame instead, so the 41 scale hierarchy holds on every record and not merely on most. */ 42 function keepLead() { 43 var set = document.querySelector("[data-set]"); 44 if (!set || set.querySelector(".lead")) return; 45 var first = set.querySelector(".strip__track figure"); 46 if (!first) return; 47 first.className = "lead"; 48 set.insertBefore(first, set.firstChild); 49 } 50 51 /* The ledger counts what is ON THE PAGE, not what the server sent: frames drop 52 out, and a count that keeps claiming twenty is simply untrue. */ 53 function count() { 54 var box = document.querySelector("[data-set], .story"); 55 var el = document.querySelector("[data-frames]"); 56 if (box && el) el.textContent = box.querySelectorAll("img").length; 57 Array.prototype.forEach.call(document.querySelectorAll("[data-trim]"), function (wall) { 58 var led = wall.previousElementSibling; 59 var slot = led && led.querySelector("[data-count]"); 60 if (slot) slot.textContent = wall.children.length + " sets"; 61 }); 62 } 63 64 function pass() { 65 sweep(); 66 keepLead(); 67 var walls = document.querySelectorAll("[data-trim]"); 68 for (var n = 0; n < walls.length; n++) trimTail(walls[n]); 69 count(); 70 } 71 /* a frame that dies after the last scheduled pass re-opens the ragged row, and 72 lazy tiles below the fold die only once the reader scrolls to them â so every 73 removal asks for one more pass instead of hoping the timers covered it */ 74 window.wAfterDrop = function () { 75 clearTimeout(window.__wardTr); 76 window.__wardTr = setTimeout(pass, 700); 77 }; 78 [700, 1800, 4000, 9000].forEach(function (ms) { setTimeout(pass, ms); }); 79 window.addEventListener("pageshow", pass); 80 window.addEventListener("resize", function () { 81 clearTimeout(window.__wardRz); 82 window.__wardRz = setTimeout(pass, 400); 83 }); 84 85 /* --- 3. the viewer: same frame, own code, no CDN -------------------------- */ 86 var box = document.getElementById("ward-viewer"); 87 var stage = box ? box.querySelector(".viewer__stage > img") : null; 88 var tally = box ? box.querySelector(".viewer__count") : null; 89 var reel = [], at = -1; 90 91 function place(k) { 92 if (!reel.length) return; 93 at = (k + reel.length) % reel.length; 94 var from = reel[at]; 95 stage.src = from.currentSrc || from.src; 96 stage.alt = from.alt || ""; 97 if (tally) tally.textContent = (at + 1) + " / " + reel.length; 98 } 99 function ahead() { place(at + 1); } 100 function back() { place(at - 1); } 101 102 function raise(scope, hit) { 103 if (!box || typeof box.showModal !== "function") return; 104 reel = Array.prototype.slice.call(scope.querySelectorAll("img")).filter(function (im) { 105 return im.isConnected; 106 }); 107 var k = reel.indexOf(hit); 108 place(k < 0 ? 0 : k); 109 box.showModal(); 110 } 111 112 Array.prototype.forEach.call(document.querySelectorAll("[data-viewer]"), function (scope) { 113 scope.addEventListener("click", function (e) { 114 var hit = e.target; 115 if (hit && hit.tagName === "IMG" && hit.isConnected) { 116 e.preventDefault(); 117 raise(scope, hit); 118 } 119 }); 120 }); 121 122 if (box) { 123 box.querySelector(".viewer__next").addEventListener("click", ahead); 124 box.querySelector(".viewer__prev").addEventListener("click", back); 125 box.querySelector(".viewer__x").addEventListener("click", function () { box.close(); }); 126 box.addEventListener("click", function (e) { if (e.target === box) box.close(); }); 127 box.addEventListener("keydown", function (e) { 128 if (e.key === "ArrowRight") ahead(); 129 else if (e.key === "ArrowLeft") back(); 130 }); 131 } 132 133 /* --- 4. film strip -------------------------------------------------------- */ 134 Array.prototype.forEach.call(document.querySelectorAll(".strip"), function (strip) { 135 var track = strip.querySelector(".strip__track"); 136 if (!track) return; 137 function nudge(way) { 138 var one = track.querySelector("figure"); 139 var w = one ? one.getBoundingClientRect().width + 6 : 300; 140 track.scrollBy({ left: way * w, behavior: "smooth" }); 141 } 142 var p = strip.querySelector('[data-strip="prev"]'), n = strip.querySelector('[data-strip="next"]'); 143 if (p) p.addEventListener("click", function () { nudge(-1); }); 144 if (n) n.addEventListener("click", function () { nudge(1); }); 145 }); 146 147 /* --- 5. role-6 pages carry no page-type IF, so the layout can only give them 148 the bare brand. Each legal page names itself here. ----------------------- */ 149 var slip = document.querySelector("[data-title]"); 150 if (slip) { 151 document.title = slip.getAttribute("data-title"); 152 var d = slip.getAttribute("data-desc"); 153 var m = document.querySelector('meta[name="description"]'); 154 if (d && m) m.setAttribute("content", d); 155 } 156})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.