PageSourceSearch

https://artandbeyond.gallery/lib/g/2.0/scripts/artlogic_modules/plugins/jquery.augmented_reality.1.0.js

js artandbeyond.gallery collected 2026-10-03 02:49:34 UTC 27,304 bytes, 548 lines download raw bytes

1/**
2 * Plugin based on template https://css-tricks.com/lodge/learn-jquery/28-building-complex-plugin/
3 */
4
5export default (function($) {
6    $.ar_slider = function (el, options) {
7        
8        var base = this;
9        
10        // Access to jQuery and DOM versions of element
11        base.$el = $(el);
12        base.el = el;
13        
14        // Find out the current browser
15        if ($.browser.name) {
16            var browserVersion = parseInt($.browser.version);
17            var browserName = $.browser.name;
18            if (browserVersion) {
19                $('body').addClass('browser-' + browserName);
20                $('body').addClass('browser-' + browserName + '-' + browserVersion);
21            }
22        };
23        
24        // Find out if device is handheld or desktop
25        var handheld_ios = false
26        var handheld_android = false
27        var handheld_device = false
28        
29        base.handheld_ios_devices = function() {
30            return (
31                //Detect iPhone
32                (navigator.platform.indexOf("iPhone") != -1) ||
33                //Detect iPod
34                (navigator.platform.indexOf("iPod") != -1) ||
35                //Detect iPad
36                (navigator.platform.indexOf("iPad") != -1) ||
37                //Detect iPad ios 13+
38                (navigator.platform.indexOf("MacIntel") != -1 && navigator.maxTouchPoints > 1)
39            );
40        };
41        
42        //Detect Android
43        base.handheld_android_devices = function() {
44            return (
45                (navigator.userAgent.toLowerCase().indexOf("android") != -1)
46            );
47        };
48        
49        if (base.handheld_android_devices()) {
50            handheld_android = true
51            handheld_device = true
52            $('body').addClass('handheld_android');
53        } else if (base.handheld_ios_devices()) {
54            handheld_ios = true
55            handheld_device = true
56            $('body').addClass('handheld_ios');
57        };
58        
59        
60        
61        // Detect support for AR Quick Looks (ios only)
62        var ios_ar_supported_device = false
63        var test_anchor = document.createElement("a");
64        
65        if (typeof(test_anchor.relList) != 'undefined' && typeof(test_anchor.relList.supports("ar")) != 'undefined') {
66            ios_ar_supported_device = true
67            $('body').addClass('ar-supported');
68        };
69
70        // Detect support for AR on Android
71        var android_ar_supported_device = false;
72        if (handheld_android) {
73            var testCanvas = document.createElement('canvas');
74            var testGl = testCanvas.getContext('webgl2')
75
76            if (testGl.getExtension('EXT_color_buffer_float')) {
77                android_ar_supported_device = true;
78            }
79        }
80        
81        // Retrieve element AR_model_data
82        var AR_model_data = base.$el.attr('data-ar_model');
83        var AR_model_data_edit = AR_model_data.replace(/'/g, '"');
84        var AR_model_data_parse = JSON.parse(AR_model_data_edit);
85        
86        var qrcode_for_artwork_page_on_mobile = AR_model_data_parse['qrcode_for_artwork_page_on_mobile']
87        var AR_model_usdz_url = AR_model_data_parse['ar_model_usdz_url']
88        var AR_model_gltf_url = AR_model_data_parse['ar_model_gltf_url']
89        var AR_model_placement = AR_model_data_parse['ar_placement']
90        
91        base.init = function() {
92            base.options = $.extend({}, $.ar_slider.defaultOptions, options);
93            
94            if (!$("#popup_slider_container.qr_code").length && handheld_device == false) {
95                base.setup_qr_code_html();
96                base.respond_to_qr_code_entry();
97                // base.setup_slide_html();
98            } else if (!$("#popup_slider_container").length && handheld_device == true) {
99                if ((ios_ar_supported_device == true && handheld_ios) || (handheld_android && android_ar_supported_device)) {
100                    // console.log("===passed ios and ios ar tests===")
101                    try {
102                        // Artlogic.import("galleries_js/model_viewer.js").then(() => {
103                            const body = document.body;
104                            const modelViewer = document.createElement('script'); 
105                            modelViewer.type = 'module';
106                            modelViewer.src = '/lib/g/2.0/scripts/artlogic_modules/galleries_js/model_viewer.js'; 
107                            body.appendChild(modelViewer);
108                            var ar_guidance_dismissed = base.get_local_storage_boolean();
109                            if (ar_guidance_dismissed == false) {
110                                base.setup_slide_html();
111                            };
112                            base.respond_to_qr_code_entry();
113                        // });
114                    } catch (err) {
115                        console.error(err);
116                    }
117                } else {
118                    // console.log("===failed ios and ios ar tests===")
119                    base.respond_to_qr_code_entry();
120                    $(base.$el).ar_slider_destroy();
121                }
122            };
123            base.on_element_click();
124            base.close_popup();
125            base.set_button_loader();
126        };
127        
128        // HTML INJECTION
129        base.setup_slide_html = function() {
130            
131            var slide_html = ' <div id="popup_slider_container">\
132                                    <div id="popup_slider_overlay"></div>\
133                                    <div id="popup_slider_inner">\
134                                    <div id="popup_slider_box" role="dialog" aria-modal="true" aria-label="AR popup slider" class="esc-key-listener-added focustrap-wrapper" data-popup-layer="1">\
135                                    <div id="popup_slider_close_popup" class="close focustrap-focusable focustrap-item focustrap-first" role="button" tabindex="0" aria-label="Close" data-tabindex="0">\
136                                        <a href="#" aria-hidden="true" tabindex="-1">Close</a>\
137                                    </div>\
138                                    <div id="popup_slider_slides">\
139                                          <ul>\
140                                            <li class="slide_1">\
141                                                 <div class="content_wrapper">\
142                                                    <ul>\
143                                                        <li>\
144                                                            <h2 class="popup_slider_main_header">AR viewer</h2>\
145                                                         </li>\
146                                                         <li>\
147                                                            <h3 class="popup_slider_subtitle">Preview artworks in your own home.</h3>\
148                                                        </li>\
149                                                        <li>\
150                                                             <div class="popup_slider_gif_container large ">\
151                                                                <span class="ar-slide-gif main_image"></span>\
152                                                             </div>\
153                                                        </li>\
154                                                        <li>\
155                                                             <div class="popup_slider_description">\
156                                                                <p>Opens your mobile device\'s built-in AR viewer. Results will depend greatly on the capabilities of your device.</p>\
157                                                            </div>\
158                                                        </li>\
159                                                        <li class="popup_slider_buttons_container">\
160                                                            <div class="button">\
161                                                                 <a class="control_exit" role="button" href="#" tabindex="0"><span>Skip help and don\'t show again</span></a>\
162                                                            </div>\
163                                                             <div class="button">\
164                                                                 <a class="control_next" role="button" href="#" tabindex="0">Next</a>\
165                                                            </div>\
166                                                        </li>\
167                                                    </ul>\
168                                                </div>\
169                                            </li>\
170                                            <li class="slide_2">\
171                                                 <div class="content_wrapper">\
172                                                     <ul>\
173                                                         <li>\
174                                                            <h2 class="popup_slider_main_header">Tips</h2>\
175                                                         </li>\
176                                                         <li>\
177                                                            <div class="popup_slider_gif_container small">\
178                                                                <sp
178an class="ar-slide-gif gif_animate light_bulb"></span>\
179                                                            </div>\
180                                                             <div class="popup_slider_description top">\
181                                                                <p>Augmented reality works best in a <strong>well-lit</strong> room.</p>\
182                                                            </div>\
183                                                         </li>\
184                                                         <li>\
185                                                             <div class="popup_slider_gif_container large">\
186                                                                <span class="ar-slide-gif gif_animate wall_template"></span>\
187                                                            </div>\
188                                                            <div class="popup_slider_description">\
189                                                                <p>Use <strong>clear wall</strong>, with a view of where the wall meets the <strong>floor</strong>.</p>\
190                                                            </div>\
191                                                        </li>\
192                                                        <li>\
193                                                            <div class="popup_slider_gif_container large">\
194                                                                <span class="ar-slide-gif gif_animate wall_scan"></span>\
195                                                            </div>\
196                                                            <div class="popup_slider_description bottom">\
197                                                                <p>When asked to initially move your phone, <strong>scan the target wall and floor</strong>.</p>\
198                                                            </div>\
199                                                        </li>\
200                                                        <li class="popup_slider_buttons_container">\
201                                                            <div class="button">\
202                                                                 <a class="control_open" role="button" tabindex="0"><span>Open AR Viewer</span></a>\
203                                                            </div>\
204                                                        </li>\
205                                                    </ul>\
206                                                </div>\
207                                            </li>\
208                                          </ul>\
209                                    </div>\
210                                    </div>\
211                                    </div>\
212                                </div>';
213                                
214            $('body').append(slide_html);               
215        };
216        
217        base.setup_qr_code_html = function() {
218            
219            var qr_code_html = ' <div id="popup_slider_container" class="qr_code">\
220                                    <div id="popup_slider_overlay"></div>\
221                                    <div id="popup_slider_inner">\
222                                    <div id="popup_slider_box" role="dialog" aria-modal="true" aria_label="QR code popup for viewing artworks in AR on a mobile device"  class="esc-key-listener-added focustrap-wrapper" data-popup-layer="1">\
223                                    <div id="popup_slider_close_popup" class="close focustrap-focusable focustrap-item focustrap-first" role="button" tabindex="0" aria-label="Close" data-tabindex="0">\
224                                        <a href="#" aria-hidden="true" tabindex="-1">Close</a>\
225                                    </div>\
226                                        <div class="qr_code_wrapper">\
227                                            <div class="qr_code_image">\
228                                                <span class="ar-qr_code-label">QR Code</span>\
229                                                <span class="ar-qr_code-icon">\
230                                                    <a class="nopopup" rel="ar">\
231                                                        <img src="' + qrcode_for_artwork_page_on_mobile + '">\
232                                                    </a>\
233                                                </span>\
234                                            </div>\
235                                            <div class="qr_code_description">\
236                                                <div class="description">\
237                                                    Scan the QR code to open this work using your mobile device\'s built-in Augmented Reality (AR) viewer.\
238                                                    <div class="note">\
239                                                        This is only available on Android and iOS devices that support AR.\
240                                                    </div>\
241                                                </div>\
242                                            </div>\
243                                        </div>\
244                                    </div>\
245                                    </div>\
246                                </div>';
247                                
248            $('body').append(qr_code_html);          
249        };
250        
251        base.inject_button_link_html = function() {
252            
253            if (!$('#view-in-ar-link').length && handheld_ios && ios_ar_supported_device) {
254                if (AR_model_usdz_url && typeof(AR_model_usdz_url) != 'undefined') {
255                    var button_link_html = '<div id="view-in-ar-link">\
256                                                <a class="nopopup" rel="ar" href="' + AR_model_usdz_url + '">\
257                                                    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">\
258                                                </a>\
259                                            </div>'
260                    base.$el.before(button_link_html)          
261                }
262            }
263        };
264
265        base.inject_model_viewer_html = function() {
266            if (!$('#ar-model-viewer-container').length && ((handheld_ios && ios_ar_supported_device) || (handheld_android && android_ar_supported_device))) {
267                if ((handheld_ios && AR_model_usdz_url && typeof(AR_model_usdz_url) != 'undefined') || (handheld_android && AR_model_gltf_url && typeof(AR_model_gltf_url) != 'undefined')) {
268                    // TODO Set ar-placement based on artwork settings
269                    var model_viewer_html = '<div id="ar-model-viewer-container"><model-viewer id="ar-model-viewer" src="' + AR_model_gltf_url + '" ios-src="' + AR_model_usdz_url + '" ar ar-placement="' + AR_model_placement + '" ar-modes="scene-viewer quick-look"></model-viewer></div>'
270                    base.$el.before(model_viewer_html) 
271                }
272            }
273        };
274        
275        // Inject button-loader html
276        base.set_button_loader = function () {
277            $('.button a.control_open').each(function() {
278                if (!$('.button_loader', this).length) {
279                    $(this).append('<div class="button_loader"></div>');
280                }
281            });
282            $('.button_loader').each(function() {
283                if (!$('svg', this).length) {
284                    $(this).append('<svg class="loader" viewBox="25 25 50 50"><circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="3" stroke-miterlimit="10"/></svg>');
285                }
286            });
287        };
288        
289        // Click event for plugin element  
290        base.on_element_click = function() {
291            base.$el.off().click(function() {
292                    if ($('li.slide_1').length) {
293                        $('li.slide_1').css('display', 'block');
294                    };
295                    var ar_guidance_dismissed = base.get_local_storage_boolean();
296                    
297                    if (ar_guidance_dismissed == true) {
298                        base.view_AR_model();
299                    } else {
300                        base.open_slides_popup();
301                    };
302            })
303        };
304        
305        base.view_AR_model = function() {
306            // if ($("#view-in-ar-link a").length) {
307            //     $("#view-in-ar-link a").get(0).click();
308            // };
309
310            base.inject_model_viewer_html();
311
312            var modelViewer = document.getElementById('ar-model-viewer');
313            modelViewer.addEventListener('error', function (e) {
314                console.error(e);
315            });
316
317            if (modelViewer.canActivateAR) {
318                try {
319                    modelViewer.activateAR();
320                } catch (err) {
321                    console.error(err);
322                }
323            } else {
324                modelViewer.addEventListener('load', function (e) {
325                    modelViewer.activateAR(); 
326                });
327
328                if (handheld_ios) {
329                    modelViewer.addEventListener('error', function (e) {
330                        console.log(e);
331                        modelViewer.activateAR(); 
332                    });
333                }
334            }
335        };
336        
337        // QR code handling 
338        base.respond_to_qr_code_entry = function() {
339            if (window.location.hash) {
340                if (window.location.hash == "#AR") {
341                    if ((ios_ar_supported_device == true && handheld_ios)) {
342                        setTimeout(function() {
343                            base.view_AR_model();
344                        }, base.options.splash_screen_timeout)
345                    } else if (handheld_android && android_ar_supported_device) {
346                        setTimeout(function () {
347                            if (!$('#popup_slider_container').length) {
348                                base.setup_slide_html();
349                            }
350                            base.open_slides_popup();
351                        }, base.options.splash_screen_timeout)
352                    } else {
353                        setTimeout(function() {
354                            h.prompt('<div class="ar_mobile_prompt">\
355                                              <h3>Feature not supported on this device</h3>\
356                                              <p>The Augmented Reality (AR) feature is currently only available on selected Android and iOS devices.</p>\
357                                          </div>', {
358                                buttons: {
359                                    'Ok': true,
360                                },
361                            });
362                        }, base.options.splash_screen_timeout)
363                    }
364                }
365            }
366        };
367
368        base.open_qr_code_popup = function() {
369            base.body.addClass('popup_slider_active');
370            
371            setTimeout(function() {
372                base.body.addClass('popup_slider_visble');
373                h.accessibility.on_popup_opening('#popup_slider_box', '#popup_slider_close_popup a', '#popup_slider_close_popup a');
374            }, 50);
375            
376        };
377        
378        // Popup and slider actions
379        base.open_slides_popup = function() {
380            
381            $('body').addClass('popup_slider_active');
382            $('li.slide_2').css('display', 'none');
383            
384            setTimeout(function() {
385                $('body').addClass('popup_slider_visble');
386                $('li.slide_1 .popup_slider_main_header').focus();
387                $('#popup_slider_slides ul li.slide_1 .content_wrapper').addClass('visible');
388                //trap_element, first_focusable_element_override, close_button_element
389                h.accessibility.on_popup_opening('#popup_slider_box', '#popup_slider_close_popup a', '#popup_slider_close_popup a');
390            }, 50);
391        
392            
393            $('.control_open').off().click(function() {
394                $('#popup_slider_slides ul li.slide_2 .popup_slider_buttons_container .button').addClass('loading');
395                
396                setTimeout(function() {
397                    $('#popup_slider_close_popup a').trigger('click');
398                    $('#popup_slider_slides ul li.slide_2 .popup_slider_buttons_container .button').removeClass('loading');
399                }, 3500);
400                base.view_AR_model();
401            });
402            
403            $('.control_exit').off().click(function() {
404                base.set_local_storage_boolean();
405                
406                setTimeout(function() {
407                    base.view_AR_model();
408                    $('#popup_slider_container').ar_slider_destroy();
409                },50)
410            });
411            
412            $('.control_next').off().click(function () {
413                base.next_slide();
414            });
415        };
416        
417        base.next_slide = function() {
418            $('li.slide_2').css('display', 'block');
419            $('li.slide_1').css('display', 'none');
420
421            $('#popup_slider_slides ul li.slide_1 .content_wrapper').removeClass('visible');
422
423            setTimeout(function() {
424                $('#popup_slider_slides ul li.slide_2 .content_wrapper').addClass('visible');
425                $('#popup_slider_close_popup').focus();
426                $('#popup_slider_slides ul li.slide_2 .content_wrapper')
427                    .delay(300)
428                    .queue(function() {
429                        $('#popup_slider_slides ul li .content_wrapper.visible ul li:first-child').addClass('animate_in');
430                        $(this).dequeue();
431                    })
432                    .delay(500)
433                    .queue(function() {
434                        $('#popup_slider_slides ul li .content_wrapper.visible ul li:nth-child(2)').addClass('animate_in');
435                        $(this).dequeue();
436                    })
437                    .delay(900)
438                    .queue(function() {
439                        $('#popup_slider_slides ul li .content_wrapper.visible ul li:nth-child(3)').addClass('animate_in');
440                        $(this).dequeue();
441                    })
442                    .delay(1650)
443                    .queue(function() {
444                        $('#popup_slider_slides ul li .content_wrapper.visible ul li:nth-child(4)').addClass('animate_in');
445                        $(this).dequeue();
446                    })
447                    .delay(250)
448                    .queue(function() {
449                        $('#popup_slider_slides ul li .content_wrapper.visible ul li:nth-child(5)').addClass('animate_in');
450                        $(this).dequeue();
451                    })
452                ;
453            }, 400);
454        };
455        
456        base.exit_slider = function() {
457            base.set_local_storage_boolean();
458            base.view_AR_model();
459        };
460
461        base.close_popup = function() {
462            
463             $('#popup_slider_close_popup a').off().click(function() {
464                 
465                $('body').removeClass('popup_slider_visble');
466                setTimeout(function() {
467                    $('body').removeClass('popup_slider_active');
468                    $('#popup_slider_slides ul li.slide_2 .content_wrapper').removeClass('visible');
469                    $('#popup_slider_slides ul li .content_wrapper ul li.animate_in').each(function() {
470                        $(this).removeClass('animate_in')
471                    })
472                }, 400);
473                
474                try {
475                    h.accessibility.on_popup_closing();
476                }
477                catch(error) {
478                    console.log(error);
479                }
480             })
481        };
482
483        // Local storage GET and SET
484        base.set_local_storage_boolean = function() {
485            var ar_guidance_dismissed = true;
486            localStorage.setItem("ar_guidance_dismissed", JSON.stringify(ar_guidance_dismissed)); 
487        };
488        
489        base.get_local_storage_boolean = function() {
490            
491            var browser_supports_local_storage = base.run_local_storage_test();
492            
493            if (browser_supports_local_storage == true) {
494                var ar_guidance_dismissed = JSON.parse(localStorage.getItem("ar_guidance_dismissed"));
495                
496                if (ar_guidance_dismissed == true) {
497                    return true
498                } else {
499                    return false
500                }
501            } else {
502                console.log('local_storage not supported by browser')
503            }
504        };
505        
506        // Check browser supports local storage
507        base.run_local_storage_test = function() {
508            var test = 'test';
509            try {
510                localStorage.setItem(test, test);
511                localStorage.removeItem(test);
512                return true;
513            } catch(e) {
514                return false;
515            }
516        };
517        
518        // Run initialise
519        base.init();
520    };
521    
522    // Destroy slider method
523    $.ar_slider_destroy = function(el) {
524        if ($(el).length) {
525            $(el).each(function() {
526                $(this).remove();
527            })
528        }
529    };
530    
531    $.fn.ar_slider_destroy = function() {
532        return this.each(function() {
533            (new $.ar_slider_destroy(this))
534        })
535    };
536    
537    // Run plugin
538    $.ar_slider.defaultOptions = {
539        'splash_screen_timeout': 0
540    };
541    
542    $.fn.ar_slider = function(options) {
543        return this.each(function() {
544            (new $.ar_slider(this, options))
545        })
546    };
547    
548})(jQuery);

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.