PageSourceSearch

https://jeanschmitt.net/release/locke/production/v0.0.141/js/large.js

js jeanschmitt.net collected 2026-10-07 19:53:51 UTC 13,821 bytes, 441 lines download raw bytes

1// OPP
2window.OPP = window.OPP || {};
3
4// Modernizr Tests
5(function (w, d) {
6    if (!w.Modernizr) { return; }
7
8    // Detect support for media queries and layouts for use by js and css
9    Modernizr.addTest('mediaquery', Modernizr.mq( OPP.modernMQ ));
10
11    // Detect stickyhover using a crude regex to detect known ios devices
12    Modernizr.addTest('stickyhover', Modernizr.touch && !!navigator.userAgent.match(/\biP(ad|hone|od)\b/i));
13
14    // Detect flexbox layout bug in Safari (See #520)
15    Modernizr.testStyles('#modernizr{display:flex;flex-wrap:wrap;width:2px;}#modernizr1,#modernizr2{flex:none;min-width:2px;width:1px;height:1px}', function (elem) {
16        var fixed = elem.firstChild.offsetTop !== elem.lastChild.offsetTop;
17        Modernizr.addTest('webkit-bug-136041', !fixed);
18    }, 2);
19
20})(window, window.document);
21
22// OPP.ajax (also used in contact.js)
23(function (w) {
24    var OPP = w.OPP;
25
26    function noop() {}
27
28    function xhrSettings(options) {
29        // default settings
30        var settings = {
31            async: true,
32            data: null, // no data
33            error: noop,
34            method: 'GET',
35            timeout: 0, // no timeout
36            success: noop
37        };
38
39        // shallow copy
40        for (prop in options) {
41            if( options.hasOwnProperty(prop) ) {
42                settings[prop] = options[prop];
43            }
44        }
45
46        // normalize method name
47        settings.method = settings.method.toUpperCase();
48
49        return settings;
50    }
51
52    OPP.ajax = function (options) {
53        var xhr = new XMLHttpRequest();
54        var settings = xhrSettings(options);
55        var context = settings.context || settings;
56        xhr.onreadystatechange = function (e) {
57            if (xhr.readyState === 4) {
58                if (xhr.status === 200) {
59                    settings.success.call(context, e);
60                }
61                else {
62                    settings.error.call(context, e);
63                }
64            }
65        }
66        xhr.open(settings.method, settings.uri, settings.async);
67        xhr.timeout = settings.timeout;
68        xhr.send(settings.data);
69    };
70}(window));
71
72// OPP.{has,add,remove,toggle}Class
73(function (w) {
74    var OPP = w.OPP;
75
76    // copied from lazySizes v1.1.3, thanks :)
77    var hasClass = OPP.hasClass = function(ele, cls) {
78        var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
79        return ele.className.match(reg) && reg;
80    };
81
82    // copied from lazySizes v1.1.3, thanks :)
83    OPP.addClass = function(ele, cls) {
84        if (!hasClass(ele, cls)){
85            ele.className += ' '+cls;
86        }
87    };
88
89    // copied from lazySizes v1.1.3, thanks :)
90    OPP.removeClass = function(ele, cls) {
91        var reg;
92        if ((reg = hasClass(ele,cls))) {
93            ele.className = ele.className.replace(reg, ' ');
94        }
95    };
96
97    OPP.toggleClass = function(ele, cls) {
98        var reg;
99        if ((reg = hasClass(ele,cls))) {
100            ele.className = ele.className.replace(reg, ' ');
101        } else {
102            ele.className += ' '+cls;
103        }
104    };
105})(window);
106
107// OPP Modal
108(function (w, d) {
109    var OPP = w.OPP;
110
111    var hasClass = OPP.hasClass;
112    var addClass = OPP.addClass;
113    var removeClass = OPP.removeClass;
114    if (!hasClass || !addClass || !removeClass) { return; }
115    if (!'getElementsByClassName' in d) { return; }
116    (function () {
117        var Modal = OPP.Modal = OPP.Modal || {};
118
119        var Class = {
120            BODY: 'modal-open',
121            MODAL: 'modal',
122            SHOW: 'show',
123        };
124
125        function isOpen() {
126            return hasClass(d.body, Class.BODY);
127        }
128
129        Modal.elems = d.getElementsByClassName(Class.MODAL);
130
131        function hideAll() {
132            var i = 0, elems = Modal.elems, len = elems.length;
133            for (; i < len; i++) { removeClass(elems[i], Class.SHOW); }
134        }
135
136        function show(elem) {
137            if ( !elem || !hasClass(elem, Class.MODAL) ) { return; }
138            hideAll();
139            addClass(elem, Class.SHOW);
140            addClass(d.body, Class.BODY);
141        };
142
143        function hide() {
144            removeClass(d.body, Class.BODY);
145            hideAll();
146        };
147
148        OPP.isModalOpen = Modal.isOpen = isOpen;
149        OPP.showModal = Modal.show = show;
150        OPP.hideModal = Modal.hide = hide;
151
152        addClass(d.documentElement, 'can-use-modal');
153    })();
154})(window, document);
155
156// NOTE: This is intended to run on every page load for large AND small
157// layouts. Do not be confused by the name of the file. It is loaded regardles
158// of the device classification.
159
160// handle redirect cookie used to trigger welcome page
161(function (w, d) {
162    var OPP = w.OPP;
163
164    function hasCookie(name) {
165        return d.cookie.match(new RegExp('\\b'+name+'='));
166    }
167
168    function killCookie(name) {
169	    d.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/"
170    }
171
172    var addClass = OPP.addClass;
173
174    if (!addClass) { return; }
175
176    (function () {
177        var rootRedirectCookie = '_opp-root-redirect';
178
179        if (w.location.pathname == "/home.html" && hasCookie(rootRedirectCookie)) {
180            killCookie(rootRedirectCookie);
181            addClass(d.documentElement, 'is-root-redirect');
182        }
183    }());
184
185}(window, window.document));
186
187// NOTE: This is intended to run on every page load for large AND small
188// layouts. Do not be confused by the name of the file. It is loaded regardles
189// of the device classification.
190
191// check .down and .grace_period
192(function (w, d) {
193    var OPP = w.OPP;
194
195    var ajax = OPP.ajax;
196    var addClass = OPP.addClass;
197    var downURI = OPP.downURI;
198    var gracePeriodURI = OPP.gracePeriodURI;
199
200    if (!ajax || !addClass || !downURI || !gracePeriodURI) { return; }
201
202    (function () {
203        function takeDown() {
204            window.scrollTo(0, 0); // required by offline css.
205            addClass(d.documentElement, 'is-down');
206        }
207
208        function checkGracePeriod() {
209            ajax({
210                uri: gracePeriodURI,
211                timeout: 1000,
212                error: takeDown
213            });
214        }
215
216        function checkDown() {
217            ajax({
218                uri: downURI,
219                timeout: 1000,
220                success: checkGracePeriod
221            });
222        }
223
224        // autorun
225        checkDown();
226    }());
227}(window, window.document));
228
229// OPP.{on,}refreshLayout
230(function (w) {
231    var OPP = w.OPP;
232
233    var queue = [];
234    var length = queue.length;
235
236    OPP.onRefreshLayout = function (f) {
237        length = queue.push(f);
238    };
239
240    OPP.refreshLayout = function () {
241        for(var i = 0; i < length; i++) {
242            queue[i]();
243        }
244    };
245})(window);
246
247// OPP.masonryInit
248// TODO: split this module for clarity
249(function (w, d) {
250    var OPP = w.OPP;
251    var docElem = d.documentElement;
252    var transEndEventNames = {
253        'WebkitTransition' : 'webkitTransitionEnd',// Saf 6, Android Browser
254        'MozTransition'    : 'transitionend',      // only for FF < 15
255        'transition'       : 'transitionend'       // IE10, Opera, Chrome, FF 15+, Saf 7+
256    };
257    var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
258
259    var hasClass = OPP.hasClass;
260    var addClass = OPP.addClass;
261    var removeClass = OPP.removeClass;
262    var refreshLayout = OPP.refreshLayout;
263    var onRefreshLayout = OPP.onRefreshLayout;
264
265    // do nothing if Masonry or required DOM features are missing
266    if (!w.Masonry || !w.addEventListener || !w.getComputedStyle || !d.querySelector || !d.getElementsByTagName) {
267        return;
268    }
269
270    function debounce(f, delay) {
271        var timer, run = function (context, args) {
272            f.apply(context, args);
273        };
274
275        return function () {
276            w.clearTimeout(timer);
277            timer = w.setTimeout(run, delay, this, arguments);
278        };
279    }
280
281    function masonryAddZIndex(items) {
282        var colXs = {}, i = this.cols - 1;
283        while (i >= 0) {
284            colXs[Math.floor(i * this.columnWidth)] = i;
285            i--;
286        }
287
288        // add z-index to each item to prevent staggered overlap.
289        items.forEach(function(item) {
290            var x = item.position.x;
291            item.element.style.zIndex = colXs[x];
292        });
293    }
294
295    var getScrollbarWidth = (function () {
296        var width;
297        return function () {
298            if (width === undefined) {
299                var outerDiv = d.createElement('div');
300                var innerDiv = d.createElement('div');
301                outerDiv.style.cssText = 'overflow:auto;' +
302                    'position:absolute;top:-9999px;width:100px;height:100px';
303                innerDiv.style.cssText = 'width:100%;height:200px';
304                outerDiv.appendChild(innerDiv);
305                d.body.appendChild(outerDiv);
306                width = outerDiv.offsetWidth - outerDiv.clientWidth;
307                d.body.removeChild(outerDiv);
308            }
309            return width;
310        };
311    })();
312
313    // Returns a function that will toggle the vertical scrollbar on and off
314    // for `el` based on the difference between it's `offsetHeight` and
315    // `scrollHeight` properties. By design, the returned function does
316    // nothing unless the result of this comparison has changed.
317    function toggleScrollYFn(el) {
318        var scrollbarWidth = getScrollbarWidth();
319        var computedStyle = w.getComputedStyle(el);
320        // parse computed value of paddingRight
321        var paddingRightBase = Math.max(
322            parseInt(computedStyle.paddingRight, 10),
323            scrollbarWidth
324        );
325        // pre-compute the value that will be used for `paddingRight`
326        var paddingRightNoScrollY = paddingRightBase + 'px';
327        var paddingRightScrollY = (paddingRightBase - scrollbarWidth) + 'px';
328        // Use `overflow-y` if supported, otherwise fallback to `overflow`
329        var overflowProp = ('overflowY' in computedStyle) ? 'overflowY' : 'overflow';
330        // track scrollbar state internally
331        var hasScrollY;
332
333        return function () {
334            var init = (hasScrollY === undefined);
335            var shouldScrollY = (el.scrollHeight - el.offsetHeight) > 0;
336            if ( (init || !hasScrollY) && shouldScrollY ) {
337                el.style[overflowProp] = 'scroll';
338                el.style.paddingRight = paddingRightScrollY;
339                hasScrollY = true;
340            } else if ( (init || hasScrollY) && !shouldScrollY ) {
341                el.style[overflowProp] = 'hidden';
342                el.style.paddingRight = paddingRightNoScrollY;
343                hasScrollY = false;
344            }
345            return hasScrollY;
346        };
347    }
348
349    function masonryScrollbarFix(msnry) {
350        var scrollParent = d.getElementsByTagName('main')[0];
351        var toggleScrollY = debounce( toggleScrollYFn(scrollParent), 250 );
352
353        // listen for resize events which may or may not trigger a masonry layout
354        w.addEventListener('resize', toggleScrollY);
355
356        // listen for `transitionend` events affecting on the masonry element's height
357        msnry.element.addEventListener(transEndEventName, function (evt) {
358            if (evt.target === msnry.element && evt.propertyName === "height") {
359                toggleScrollY(evt);
360            }
361        });
362
363        // init
364        toggleScrollY();
365    }
366
367    function masonryInit() {
368        var msnry;
369
370        addClass(docElem, 'scrollbarfix');
371        d.addEventListener("DOMContentLoaded", function() {
372            var small = d.querySelector('.previews');
373            var large = small.cloneNode(true);
374            // hide when large layout is active
375            small.className += ' hidden--large';
376            // hide when small layout is active
377            large.className += ' hidden--small';
378            small.parentNode.insertBefore(large, small);
379
380            msnry = new Masonry(large, { // options
381                itemSelector: '.preview',
382                transitionDuration: 0 // disable transitions
383            });
384
385            msnry.on('layoutComplete', masonryAddZIndex);
386
387            // do nothing if scrollbar width is zero when present
388            if (getScrollbarWidth() > 0) {
389                masonryScrollbarFix(msnry);
390            } else {
391                removeClass(docElem, 'scrollbarfix');
392            }
393
394            // trigger masonry layout on refresh
395            onRefreshLayout(function () {
396                msnry.layout();
397            });
398
399            // refresh layout in case of changes
400            refreshLayout();
401        });
402    }
403
404    OPP.masonryInit = masonryInit;
405})(window, window.document);
406
407// main
408(function (w, d) {
409    var OPP = w.OPP;
410
411    // lookup common functions
412    var hasClass = OPP.hasClass;
413    var masonryInit = OPP.masonryInit;
414    var refreshLayout = OPP.refreshLayout;
415    var onRefreshLayout = OPP.onRefreshLayout;
416
417    // for repeated calls to `hasClass`
418    var docElem = d.documentElement;
419
420    // process ratios and update sizes attribute on refresh
421    onRefreshLayout(function () {
422        !!w.imageRatio && imageRatio.processImages();
423        !!w.lazySizes && lazySizes.autoSizer.checkElems();
424    });
425
426    // make sure the aspect ratio is set before being unveiled (good for FF)
427    !!w.imageRatio && d.addEventListener('lazybeforeunveil', function (e) {
428        imageRatio.processImages([e.target]);
429    });
430
431    // run layout and page specific js only if media queries are supported,
432    // since we will be using `minimal.css` otherwise.
433    if ( Modernizr.mediaquery ) {
434        if ( hasClass(docElem, 'l-detailed') && hasClass(docElem, 'p-gallery') ) {
435            !!masonryInit && masonryInit();
436        }
437    }
438
439    // ensure sizes attribute is accurate
440    w.addEventListener("load", refreshLayout);
441})(window, window.document);

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.