@gemboss/website-ui 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/website.js CHANGED
@@ -1,186 +1,240 @@
1
- /*! @gemboss/website-ui website.js | spec: docs/markup-contract.md | load with defer */
1
+ /*! @gemboss/website-ui 0.4.0 website.js | GENERATED by scripts/build.mjs from js/website.mjs (the source, with its comments): edit that file | spec: docs/markup-contract.md | load with defer */
2
2
  (function () {
3
- 'use strict';
4
- if (window.gwWebsite) return;
5
- window.gwWebsite = { version: '0.2.0' };
6
- var doc = document, root = doc.documentElement;
7
- function mq(q) { return window.matchMedia ? matchMedia(q) : { matches: false }; }
8
- function watch(m, fn) { if (m.addEventListener) m.addEventListener('change', fn); }
9
- function all(sel, ctx) { return [].slice.call((ctx || doc).querySelectorAll(sel)); }
10
- function on(el, type, fn, opt) { el.addEventListener(type, fn, opt || false); }
11
- function attr(el, name, dflt) { return el.getAttribute(name) || dflt; }
12
- function esc(e) { return e.key === 'Escape'; }
13
- function link(e) { return e.target.closest('a[href]'); }
3
+ 'use strict';
4
+ if (window.gwWebsite) return;
14
5
 
15
- // Mega menu. Opened by hover then clicked, a panel stays open: the click meant "open".
16
- function mega() {
17
- var fine = mq('(hover: hover) and (pointer: fine)'), open = null, timer = 0;
18
- var menus = all('[data-gw-mega]').map(function (t) {
19
- var p = doc.getElementById(attr(t, 'data-gw-mega', attr(t, 'aria-controls', '')));
20
- return p && { t: t, p: p, item: t.closest('.gw-nav__item') || t.parentNode };
21
- }).filter(Boolean);
22
- if (!menus.length) return;
23
- function set(m, show, mode) {
24
- m.p.hidden = !show;
25
- m.t.setAttribute('aria-expanded', String(show));
26
- m.item.classList.toggle('is-open', show);
27
- m.mode = mode;
28
- open = show ? m : open === m ? null : open;
29
- }
30
- function show(m, mode) {
31
- clearTimeout(timer);
32
- if (open === m) { if (mode === 'click') m.mode = mode; return; }
33
- if (open) set(open, false);
34
- set(m, true, mode);
35
- }
36
- function hide(focus) {
37
- var m = open;
38
- clearTimeout(timer);
39
- if (!m) return;
40
- set(m, false);
41
- if (focus === true) m.t.focus();
42
- }
43
- function inside(m, el) { return !!el && (m.item.contains(el) || m.p.contains(el)); }
44
- menus.forEach(function (m) {
45
- on(m.t, 'click', function () { if (open === m && m.mode !== 'hover') hide(); else show(m, 'click'); });
46
- (m.item.contains(m.p) ? [m.item] : [m.item, m.p]).forEach(function (el) {
47
- on(el, 'mouseenter', function () {
48
- if (fine.matches) { clearTimeout(timer); if (open !== m) timer = setTimeout(function () { show(m, 'hover'); }, 80); }
49
- });
50
- on(el, 'mouseleave', function () {
51
- if (fine.matches) { clearTimeout(timer); if (open === m && m.mode === 'hover') timer = setTimeout(hide, 160); }
52
- });
6
+ var version = '0.4.0';
7
+ var api = { version: version, init: init, destroy: destroy };
8
+ var doc, root, mine, fine, sys, live = [], megaOpen = null, megaTimer = 0, queued = false;
9
+ var READY = 'data-gw-ready';
10
+
11
+ function mq(q) { return window.matchMedia ? matchMedia(q) : { matches: false }; }
12
+ function watch(m, fn) { if (m.addEventListener) m.addEventListener('change', fn); }
13
+ function all(sel, ctx) { return [].slice.call((ctx || doc).querySelectorAll(sel)); }
14
+ function within(sel, ctx) { var l = all(sel, ctx); if (ctx.matches && ctx.matches(sel)) l.unshift(ctx); return l; }
15
+ function on(el, type, fn, opt) { el.addEventListener(type, fn, opt || false); }
16
+ function attr(el, name, dflt) { return el.getAttribute(name) || dflt; }
17
+ function esc(e) { return e.key === 'Escape'; }
18
+ function link(e) { return e.target.closest('a[href]'); }
19
+ function emit(el, type, detail) { if (window.CustomEvent) el.dispatchEvent(new CustomEvent(type, { bubbles: true, detail: detail })); }
20
+
21
+ function each(ctx, sel, kind, fn) {
22
+ within(sel, ctx).forEach(function (el) {
23
+ if (live.some(function (r) { return r.el === el && r.kind === kind; })) return;
24
+ var offs = [], r = fn(el, function (t, type, f, opt) {
25
+ on(t, type, f, opt);
26
+ offs.push(function () { t.removeEventListener(type, f, opt || false); });
27
+ });
28
+ if (!r) return offs.forEach(function (f) { f(); });
29
+ r.el = el; r.kind = kind; r.offs = offs;
30
+ mark(el, kind, true);
31
+ live.push(r);
32
+ });
33
+ }
34
+ function mark(el, kind, add) {
35
+ var l = attr(el, READY, '').split(' ').filter(function (k) { return k && k !== kind; });
36
+ if (add) l.push(kind);
37
+ if (l.length) el.setAttribute(READY, l.join(' ')); else el.removeAttribute(READY);
38
+ }
39
+ function drop(r) {
40
+ if (r.stop) r.stop();
41
+ r.offs.forEach(function (f) { f(); });
42
+ mark(r.el, r.kind);
43
+ live.splice(live.indexOf(r), 1);
44
+ }
45
+ function records(kind, fn) { live.slice().forEach(function (r) { if (r.kind === kind) fn(r); }); }
46
+
47
+ function setMega(m, show, mode) {
48
+ m.p.hidden = !show;
49
+ m.t.setAttribute('aria-expanded', String(show));
50
+ m.item.classList.toggle('is-open', show);
51
+ m.mode = mode;
52
+ megaOpen = show ? m : megaOpen === m ? null : megaOpen;
53
+ emit(m.t, 'gw:mega', { id: m.p.id, open: show });
54
+ }
55
+ function showMega(m, mode) {
56
+ clearTimeout(megaTimer);
57
+ if (megaOpen === m) { if (mode === 'click') m.mode = mode; return; }
58
+ if (megaOpen) setMega(megaOpen, false);
59
+ setMega(m, true, mode);
60
+ }
61
+ function hideMega(focus) {
62
+ var m = megaOpen;
63
+ clearTimeout(megaTimer);
64
+ if (!m) return;
65
+ setMega(m, false);
66
+ if (focus === true) m.t.focus();
67
+ }
68
+ function inside(m, el) { return !!el && (m.item.contains(el) || m.p.contains(el)); }
69
+ function mega(ctx) {
70
+ each(ctx, '[data-gw-mega]', 'mega', function (t, on) {
71
+ var p = doc.getElementById(attr(t, 'data-gw-mega', attr(t, 'aria-controls', '')));
72
+ if (!p) return;
73
+ var m = { t: t, p: p, item: t.closest('.gw-nav__item') || t.parentNode };
74
+ on(t, 'click', function () { if (megaOpen === m && m.mode !== 'hover') hideMega(); else showMega(m, 'click'); });
75
+ (m.item.contains(p) ? [m.item] : [m.item, p]).forEach(function (el) {
76
+ on(el, 'mouseenter', function () {
77
+ if (fine.matches) { clearTimeout(megaTimer); if (megaOpen !== m) megaTimer = setTimeout(function () { showMega(m, 'hover'); }, 80); }
78
+ });
79
+ on(el, 'mouseleave', function () {
80
+ if (fine.matches) { clearTimeout(megaTimer); if (megaOpen === m && m.mode === 'hover') megaTimer = setTimeout(hideMega, 160); }
53
81
  });
54
- on(m.item, 'focusout', function (e) { if (open === m && e.relatedTarget && !inside(m, e.relatedTarget)) hide(); });
55
- on(m.p, 'click', function (e) { if (link(e)) hide(); });
56
82
  });
57
- on(doc, 'click', function (e) { if (open && !inside(open, e.target)) hide(); });
58
- on(doc, 'keydown', function (e) { if (open && esc(e)) hide(inside(open, doc.activeElement) || open.mode === 'click'); });
59
- }
83
+ on(m.item, 'focusout', function (e) { if (megaOpen === m && e.relatedTarget && !inside(m, e.relatedTarget)) hideMega(); });
84
+ on(p, 'click', function (e) { if (link(e)) hideMega(); });
85
+ m.stop = function () { if (megaOpen === m) hideMega(); };
86
+ return m;
87
+ });
88
+ }
60
89
 
61
- // Mobile menu. Labels: data-gw-label-open/-close, else the markup's aria-label, else English.
62
- function mobile() {
63
- var btn = doc.querySelector('[data-gw-menu-toggle]');
64
- var menu = btn && doc.getElementById(attr(btn, 'aria-controls', 'gw-mobile-menu'));
90
+ function mobile(ctx) {
91
+ each(ctx, '[data-gw-menu-toggle]', 'menu', function (btn, on) {
92
+ var menu = doc.getElementById(attr(btn, 'aria-controls', 'gw-mobile-menu'));
65
93
  if (!menu) return;
66
94
  var label = [attr(btn, 'data-gw-label-open', attr(btn, 'aria-label', 'Open menu')), attr(btn, 'data-gw-label-close', 'Close menu')];
67
- var wide = mq('(min-width: 1080px)');
68
- function isOpen() { return !menu.hidden; }
69
- function set(o, focus) {
70
- menu.hidden = !o;
71
- btn.setAttribute('aria-expanded', String(o));
72
- btn.setAttribute('aria-label', label[+o]);
73
- root.classList.toggle('is-menu-open', o);
74
- if (focus) btn.focus();
75
- }
76
- on(btn, 'click', function () { set(!isOpen()); });
77
- on(doc, 'keydown', function (e) { if (esc(e) && isOpen()) set(false, true); });
78
- on(menu, 'click', function (e) { if (link(e)) set(false); }); // same-page anchors do not reload
79
- watch(wide, function () { if (wide.matches && isOpen()) set(false); });
80
- on(window, 'pageshow', function (e) { if (e.persisted && isOpen()) set(false); });
81
- }
95
+ var r = {
96
+ open: function () { return !menu.hidden; },
97
+ set: function (o, focus) {
98
+ menu.hidden = !o;
99
+ btn.setAttribute('aria-expanded', String(o));
100
+ btn.setAttribute('aria-label', label[+o]);
101
+ root.classList.toggle('is-menu-open', o);
102
+ if (focus) btn.focus();
103
+ },
104
+ stop: function () { if (r.open()) r.set(false); }
105
+ };
106
+ on(btn, 'click', function () { r.set(!r.open()); });
107
+ on(menu, 'click', function (e) { if (link(e)) r.set(false); });
108
+ return r;
109
+ });
110
+ }
111
+ function closeMenus(focus) { records('menu', function (r) { if (r.open()) r.set(false, focus); }); }
82
112
 
83
- // Theme toggle. Labels: data-gw-label-dark/-light, else the markup's aria-label, else English.
84
- function theme() {
85
- var sys = mq('(prefers-color-scheme: dark)'), stored = null;
86
- try { stored = localStorage.getItem('gw-theme'); } catch (e) { /* blocked */ }
87
- if (!root.hasAttribute('data-theme') && /^(light|dark)$/.test(stored)) root.setAttribute('data-theme', stored);
88
- var btns = all('[data-gw-theme-toggle]'), labels = btns.map(function (b) {
89
- return [attr(b, 'data-gw-label-dark', attr(b, 'aria-label', 'Switch to dark theme')), attr(b, 'data-gw-label-light', 'Switch to light theme')];
113
+ function dark() { var t = root.getAttribute('data-theme'); return t ? t === 'dark' : sys.matches; }
114
+ function relabel() { records('theme', function (r) { r.el.setAttribute('aria-label', r.labels[+dark()]); }); }
115
+ function theme(ctx) {
116
+ each(ctx, '[data-gw-theme-toggle]', 'theme', function (b, on) {
117
+ var r = { labels: [attr(b, 'data-gw-label-dark', attr(b, 'aria-label', 'Switch to dark theme')), attr(b, 'data-gw-label-light', 'Switch to light theme')] };
118
+ on(b, 'click', function () {
119
+ var next = dark() ? 'light' : 'dark';
120
+ root.setAttribute('data-theme', next);
121
+ try { localStorage.setItem('gw-theme', next); } catch (e) { /* blocked */ }
122
+ relabel();
123
+ emit(root, 'gw:theme', { theme: next });
90
124
  });
91
- function dark() { var t = root.getAttribute('data-theme'); return t ? t === 'dark' : sys.matches; }
92
- function relabel() { btns.forEach(function (b, i) { b.setAttribute('aria-label', labels[i][+dark()]); }); }
93
- btns.forEach(function (b) {
94
- on(b, 'click', function () {
95
- var next = dark() ? 'light' : 'dark';
96
- root.setAttribute('data-theme', next);
97
- try { localStorage.setItem('gw-theme', next); } catch (e) { /* blocked */ }
98
- relabel();
99
- });
100
- });
101
- watch(sys, relabel);
102
- relabel();
103
- }
125
+ r.stop = function () { b.setAttribute('aria-label', r.labels[0]); };
126
+ return r;
127
+ });
128
+ relabel();
129
+ }
104
130
 
105
- // Reveal at 15% visible, once. Failsafe: all shown after 2.5s, or at once without IntersectionObserver.
106
- function reveal() {
107
- var els = all('.gw-reveal'), io = null;
108
- function showAll() { els.forEach(function (el) { el.classList.add('is-in'); }); if (io) io.disconnect(); }
109
- if (!els.length) return;
110
- if (!window.IntersectionObserver || mq('(prefers-reduced-motion: reduce)').matches) return showAll();
111
- io = new IntersectionObserver(function (list) {
112
- list.forEach(function (en) { if (en.isIntersecting) { en.target.classList.add('is-in'); io.unobserve(en.target); } });
113
- }, { threshold: 0.15 });
114
- els.forEach(function (el) { io.observe(el); });
115
- setTimeout(showAll, 2500);
116
- }
131
+ function reveal(ctx) {
132
+ var els = [], io = null;
133
+ each(ctx, '.gw-reveal', 'reveal', function (el) { els.push(el); return { stop: function () { if (io) io.unobserve(el); } }; });
134
+ function showAll() { els.forEach(function (el) { el.classList.add('is-in'); }); if (io) io.disconnect(); }
135
+ if (!els.length) return;
136
+ if (!window.IntersectionObserver || mq('(prefers-reduced-motion: reduce)').matches) return showAll();
137
+ io = new IntersectionObserver(function (list) {
138
+ list.forEach(function (en) { if (en.isIntersecting) { en.target.classList.add('is-in'); io.unobserve(en.target); } });
139
+ }, { threshold: 0.15 });
140
+ els.forEach(function (el) { io.observe(el); });
141
+ setTimeout(showAll, 2500);
142
+ }
117
143
 
118
- // Header: .is-scrolled past 8px, read once per frame.
119
- function header() {
120
- var h = doc.querySelector('[data-gw-header]'), state = false, queued = false;
121
- if (!h) return;
122
- function update() {
123
- var s = window.scrollY > 8;
124
- queued = false;
125
- if (s !== state) h.classList.toggle('is-scrolled', (state = s));
126
- }
127
- on(window, 'scroll', function () { if (!queued) { queued = true; requestAnimationFrame(update); } }, { passive: true });
128
- update();
129
- }
144
+ function scrolled() {
145
+ var s = window.scrollY > 8;
146
+ queued = false;
147
+ records('header', function (r) { if (r.s !== s) r.el.classList.toggle('is-scrolled', (r.s = s)); });
148
+ }
149
+ function header(ctx) {
150
+ each(ctx, '[data-gw-header]', 'header', function (h) { return { s: false, stop: function () { h.classList.remove('is-scrolled'); } }; });
151
+ scrolled();
152
+ }
130
153
 
131
- // aria-current="page" on nav links to this path, unless the markup marked one.
132
- function current() {
133
- var menu = doc.getElementById('gw-mobile-menu');
134
- var links = all('.gw-nav__link[href], .gw-mega__link[href]').concat(menu ? all('a[href]', menu) : []);
135
- function norm(p) { return p.replace(/\/index\.html?$/, '/').replace(/\.html?$/, '').replace(/\/+$/, '') || '/'; }
136
- if (links.some(function (a) { return a.hasAttribute('aria-current'); })) return;
137
- links.forEach(function (a) {
138
- if (a.classList.contains('gw-btn') || a.hash || a.host !== location.host) return;
139
- if (norm(a.pathname) === norm(location.pathname)) a.setAttribute('aria-current', 'page');
140
- });
141
- }
154
+ function current(ctx) {
155
+ var links = within('.gw-nav__link[href], .gw-mega__link[href]', ctx);
156
+ within('#gw-mobile-menu, .gw-mobile-menu', ctx).forEach(function (m) { links = links.concat(all('a[href]', m)); });
157
+ function norm(p) { return p.replace(/\/index\.html?$/, '/').replace(/\.html?$/, '').replace(/\/+$/, '') || '/'; }
158
+ links.forEach(function (a) { if (mine.has(a)) { mine.delete(a); a.removeAttribute('aria-current'); } });
159
+ if (links.some(function (a) { return a.hasAttribute('aria-current'); })) return;
160
+ links.forEach(function (a) {
161
+ if (a.classList.contains('gw-btn') || a.hash || a.host !== location.host) return;
162
+ if (norm(a.pathname) === norm(location.pathname)) { a.setAttribute('aria-current', 'page'); mine.add(a); }
163
+ });
164
+ }
142
165
 
143
- // Segmented control: a radio group, one Tab stop; arrows (Home, End) move and choose. What one option shows carries
144
- // data-gw-show="group:value" and is hidden unless that option is chosen; without the script the markup's own choice shows.
145
- function segmented() {
146
- all('[data-gw-segmented]').forEach(function (g) {
147
- var name = attr(g, 'data-gw-segmented', ''), opts = all('[role="radio"]', g);
148
- if (!opts.length) return;
149
- function pick(o, focus, said) {
150
- var v = attr(o, 'value', '');
151
- opts.forEach(function (x) { x.setAttribute('aria-checked', String(x === o)); x.setAttribute('tabindex', x === o ? '0' : '-1'); });
152
- if (focus) o.focus();
153
- all('[data-gw-show]').forEach(function (el) {
154
- var mine = attr(el, 'data-gw-show', '').split(/\s+/).filter(function (t) { return t.split(':')[0] === name; });
155
- if (mine.length) el.hidden = mine.indexOf(name + ':' + v) < 0;
156
- });
157
- if (said && window.CustomEvent) g.dispatchEvent(new CustomEvent('gw:segmented', { bubbles: true, detail: { name: name, value: v } }));
158
- }
159
- opts.forEach(function (o, i) {
160
- on(o, 'click', function () { pick(o, false, true); });
161
- on(o, 'keydown', function (e) {
162
- var n = opts.length, k = { ArrowRight: i + 1, ArrowDown: i + 1, ArrowLeft: i - 1 + n, ArrowUp: i - 1 + n, Home: 0, End: n - 1 }[e.key];
163
- if (k === undefined || e.altKey || e.ctrlKey || e.metaKey) return;
164
- e.preventDefault();
165
- pick(opts[k % n], true, true);
166
- });
166
+ function segmented(ctx) {
167
+ each(ctx, '[data-gw-segmented]', 'segmented', function (g, on) {
168
+ var name = attr(g, 'data-gw-segmented', ''), opts = all('[role="radio"]', g);
169
+ if (!opts.length) return;
170
+ function pick(o, focus, said) {
171
+ var v = attr(o, 'value', '');
172
+ opts.forEach(function (x) { x.setAttribute('aria-checked', String(x === o)); x.setAttribute('tabindex', x === o ? '0' : '-1'); });
173
+ if (focus) o.focus();
174
+ all('[data-gw-show]').forEach(function (el) {
175
+ var own = attr(el, 'data-gw-show', '').split(/\s+/).filter(function (t) { return t.split(':')[0] === name; });
176
+ if (own.length) el.hidden = own.indexOf(name + ':' + v) < 0;
177
+ });
178
+ if (said) emit(g, 'gw:segmented', { name: name, value: v });
179
+ }
180
+ opts.forEach(function (o, i) {
181
+ on(o, 'click', function () { pick(o, false, true); });
182
+ on(o, 'keydown', function (e) {
183
+ var n = opts.length, k = { ArrowRight: i + 1, ArrowDown: i + 1, ArrowLeft: i - 1 + n, ArrowUp: i - 1 + n, Home: 0, End: n - 1 }[e.key];
184
+ if (k === undefined || e.altKey || e.ctrlKey || e.metaKey) return;
185
+ e.preventDefault();
186
+ pick(opts[k % n], true, true);
167
187
  });
168
- pick(opts.filter(function (o) { return attr(o, 'aria-checked', '') === 'true'; })[0] || opts[0]);
169
188
  });
170
- }
189
+ pick(opts.filter(function (o) { return attr(o, 'aria-checked', '') === 'true'; })[0] || opts[0]);
190
+ return {};
191
+ });
192
+ }
171
193
 
172
- // A busy button (aria-busy="true") ignores presses, by mouse or keyboard: no double submit. It keeps its focus and name.
173
- function busy() {
174
- on(doc, 'click', function (e) {
175
- var b = e.target.closest && e.target.closest('.gw-btn[aria-busy="true"]');
176
- if (b) { e.preventDefault(); e.stopPropagation(); }
177
- }, true);
178
- }
194
+ function install() {
195
+ doc = document; root = doc.documentElement; mine = new WeakSet();
196
+ fine = mq('(hover: hover) and (pointer: fine)'); sys = mq('(prefers-color-scheme: dark)');
197
+ var wide = mq('(min-width: 1080px)'), stored = null;
198
+ on(doc, 'click', function (e) { if (megaOpen && !inside(megaOpen, e.target)) hideMega(); });
199
+ on(doc, 'keydown', function (e) { if (megaOpen && esc(e)) hideMega(inside(megaOpen, doc.activeElement) || megaOpen.mode === 'click'); });
200
+ on(doc, 'keydown', function (e) { if (esc(e)) closeMenus(true); });
201
+ watch(wide, function () { if (wide.matches) closeMenus(); });
202
+ on(window, 'pageshow', function (e) { if (e.persisted) closeMenus(); });
203
+ try { stored = localStorage.getItem('gw-theme'); } catch (e) { /* blocked */ }
204
+ if (!root.hasAttribute('data-theme') && /^(light|dark)$/.test(stored)) root.setAttribute('data-theme', stored);
205
+ watch(sys, function () { relabel(); if (!root.hasAttribute('data-theme')) emit(root, 'gw:theme', { theme: dark() ? 'dark' : 'light' }); });
206
+ on(window, 'scroll', function () { if (!queued) { queued = true; requestAnimationFrame(scrolled); } }, { passive: true });
207
+ on(doc, 'click', function (e) {
208
+ var b = e.target.closest && e.target.closest('.gw-btn[aria-busy="true"]');
209
+ if (b) { e.preventDefault(); e.stopPropagation(); }
210
+ }, true);
211
+ }
179
212
 
180
- function init() {
181
- [mega, mobile, theme, reveal, header, current, segmented, busy].forEach(function (f) {
182
- try { f(); } catch (e) { console.error('[gw-website]', e); }
183
- });
184
- }
185
- if (doc.readyState === 'loading') on(doc, 'DOMContentLoaded', init); else init();
213
+ function run(fns, ctx) {
214
+ fns.forEach(function (f) { try { f(ctx); } catch (e) { console.error('[gw-website]', e); } });
215
+ }
216
+ function other() { var g = typeof window != 'undefined' && window.gwWebsite; return g && g !== api && g; }
217
+
218
+ /** Wires the kit's markup under root (default: the whole document). Safe to call again: wires only what is new. */
219
+ function init(ctx) {
220
+ if (typeof document == 'undefined') return;
221
+ var g = other();
222
+ if (g) return g.init && g.init(ctx);
223
+ window.gwWebsite = api;
224
+ if (!doc) run([install]);
225
+ live.slice().forEach(function (r) { if (r.el.isConnected === false) drop(r); });
226
+ run([mega, mobile, theme, reveal, header, current, segmented], ctx && ctx.querySelectorAll ? ctx : doc);
227
+ }
228
+
229
+ /** Takes back what init() wired under root (default: the whole document): listeners and data-gw-ready marks. */
230
+ function destroy(ctx) {
231
+ var g = other();
232
+ if (g) return g.destroy && g.destroy(ctx);
233
+ if (!doc) return;
234
+ ctx = ctx && ctx.querySelectorAll ? ctx : doc;
235
+ live.slice().forEach(function (r) { if (ctx === doc || ctx.contains(r.el)) drop(r); });
236
+ }
237
+
238
+ window.gwWebsite = api;
239
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function () { init(); }); else init();
186
240
  })();