PageSourceSearch

https://www.groceryoutlet.com/wp-content/themes/digital_attic/js/custom.js?ver=1.4

js groceryoutlet.com collected 2026-10-02 03:52:45 UTC 12,154 bytes, 342 lines download raw bytes

1"use strict";
2
3(function() {  
4
5  if (window.location.search.includes('mode=app_webview')) {
6    // Function to hide elements with !important
7    const hideElement = (el) => {
8      if (el) el.style.setProperty("display", "none", "important");
9    };
10
11    // Immediately try hiding visible elements
12    hideElement(document.querySelector('header.header.header-mega'));
13    hideElement(document.querySelector('footer#footer.footer'));
14    const main = document.querySelector('main#main');
15    if (main) main.style.setProperty("padding-top", "0", "important");
16
17    // Now watch for the flipp-pdf link to appear dynamically
18    const observer = new MutationObserver(() => {
19      const flippPdf = document.querySelector('.flipp-pdf');
20      if (flippPdf) {
21        hideElement(flippPdf);
22        observer.disconnect(); // Stop watching once it's hidden
23      }
24    });
25
26    observer.observe(document.body, { childList: true, subtree: true });
27  }
28    // Remove focus from any focused element when the tab becomes visible
29    /*$(document).on('visibilitychange', function () {
30        if (document.visibilityState === 'visible') {
31            if ($(document.activeElement)) {
32                $(document.activeElement).blur();
33            }
34        }
35    });*/
36       
37    var originalCookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
38
39    Object.defineProperty(document, 'cookie', {
40        get: function() {
41            return originalCookieDescriptor.get.call(document);
42        },
43        set: function(cookie) {
44            // List of cookies to block
45            var blockedCookies = ['VISITOR_PRIVACY_METADATA', 'VISITOR_INFO1_LIVE', 'YSC','flipp-id', 'flipp-gid', 'flipp-merchant-id', 'flipp-sid', 'flipp-postal-code_2906', 'flipp-publication-run-id', 'flipp-store-code_2906'];
46
47            // Check if the cookie name is in the list of blocked cookies
48            for (var i = 0; i < blockedCookies.length; i++) {
49                if (cookie.indexOf(blockedCookies[i] + '=') !== -1) {
50                    return;
51                }
52            }
53
54            // If the cookie should not be blocked, set it as usual
55            originalCookieDescriptor.set.call(document, cookie);
56        }
57    });
58
59    function removeCookie(cookieName) {
60        document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
61    }
62
63    // List of cookies to check and remove if present
64    var cookiesToRemove = ['flipp-id', 'flipp-gid', 'flipp-merchant-id', 'flipp-sid'];
65
66    // Check if each cookie is already present and remove it
67    cookiesToRemove.forEach(function(cookieName) {
68        if (document.cookie.indexOf(cookieName + '=') !== -1) {
69            removeCookie(cookieName);
70        }
71    });
72})();
73
74
75// Helper function to handle preference updates
76function updatePreference(options) {
77    const {
78        toggleId,
79        fieldName,
80        errorMessage = 'Failed to update preferences',
81        additionalData = {}
82    } = options;
83
84    const $toggle = $(toggleId);
85    const $section = $toggle.closest('.form-section');
86    
87    // Get existing user data
88    const userData = getUser();
89
90    disablePage();
91    
92    var model = {
93        [fieldName]: $toggle.is(':checked') ? 'Yes' : 'No', // Set the toggle state
94        updatedField: fieldName,
95        Mail_Frequency: getWOWFrequencyData(),
96    };
97
98     
99   
100
101    const loginModal = $('#pref-center-email-settings');
102    const loader = $(`<div class="modal-loader"><div class="red-loader"></div></div>`).appendTo(loginModal.find('.tab-content'));
103    loginModal.find('form input, form button').prop('disabled', true);
104    // Remove existing messages and spinner
105    // $section.find('.success-message, .error-message, .pf-spinner').remove();
106    
107    // // Show loading spinner
108    // $section.append('<div class="d-inline-block pf-spinner text-center ml-2" role="status"><i class="fas fa-sync-alt fa-spin"></i> <span class="sr-only">Loading...</span></div>');
109
110    $.ajax({
111        url: site_url + '/api/subscribers/index.php',
112        type: 'put',
113        dataType: 'json',
114        data: { model: JSON.stringify(model),update:'alerts' },
115        
116        success: function(resp) {
117            if (resp) {
118                var user = JSON.parse(sessionStorage.getItem('user') || '{}');
119                user[fieldName] = model[fieldName];
120                
121                // Handle additional data in session storage
122                Object.keys(additionalData).forEach(key => {
123                    user[key] = additionalData[key];
124                });
125                
126                sessionStorage.setItem('user', JSON.stringify(user));
127                deps.user.changed();
128                loader.remove();
129
130                // Show success message
131                showToast({
132                    title: 'Success',
133                    message: 'Preference Updated',
134                    linkText: 'Just Now',
135                    showIcon : 'true',
136                    iconType : 'success'
137                  });                
138               
139            } else {
140                loader.remove();
141
142                $toggle.prop('checked', !$toggle.is(':checked'));
143                showToast({
144                    title: 'Error',
145                    message: errorMessage,
146                    linkText: 'Just Now',
147                    showIcon : 'true',
148                    iconType : 'error'
149                  }); 
150            }
151        },
152        error: function(xhr) {
153            loader.remove();
154
155            $toggle.prop('checked', !$toggle.is(':checked'));
156            const response = xhr.responseJSON || {};
157            const message = response.message || errorMessage;
158            showToast({
159                title: 'Error',
160                message: message,
161                linkText: 'Just Now',
162                showIcon : 'true',
163                iconType : 'error'
164              }); 
165        },
166        complete: function() {
167            loader.remove();
168            enablePage();
169        }
170    });
171}
172
173// Helper function for WOW Alerts frequency
174function getWOWFrequencyData() {
175    const isDaily = $('input[name="Mail_Frequency"][value="Daily"]').is(':checked');
176    return isDaily ? '0' : $('#Mail_Frequency_Day').val();
177}
178
179// Event Handlers for TextMessage
180$(document).on('change', '#TextMessage', function(e) {
181    updatePreference({
182        toggleId: '#TextMessage',
183        fieldName: 'TextMessage',
184        errorMessage: 'There was a problem updating your SMS preference. Please try again later.'
185    });
186});
187
188// Event Handlers for Weekly Ad
189$(document).on('change', '#General', function(e) {
190    updatePreference({
191        toggleId: '#General',
192        fieldName: 'WeeklyAd',  // matches backend case
193        additionalData: {
194            General: $(this).is(':checked') ? 'Yes' : 'No'  // backend expects 'General'
195        },
196        errorMessage: 'There was a problem updating your Weekly Ad preference. Please try again later.'
197    });
198});
199
200// Event Handlers for Latest Updates
201$(document).on('change', '#LastUpdates', function(e) {
202    updatePreference({
203        toggleId: '#LastUpdates',
204        fieldName: 'LatestUpdates',  // matches backend case
205        additionalData: {
206            LastUpdates: $(this).is(':checked') ? 'Yes' : 'No'  // backend expects 'LastUpdates'
207        },
208        errorMessage: 'There was a problem updating your Latest Updates preference. Please try again later.'
209    });
210});
211
212// WOW Alerts handlers
213$('#WOWPilot').on('change', function(e) {
214    if (!e.originalEvent) return;
215    
216    const additionalData = {
217        WOWPilot: $(this).is(':checked') ? 'Yes' : 'No'  // backend expects 'WOWPilot'
218    };
219    
220    if ($(this).is(':checked')) {
221        additionalData.Mail_Frequency = getWOWFrequencyData();
222    }
223
224    updatePreference({
225        toggleId: '#WOWPilot',
226        fieldName: 'WowAlerts',  // matches backend case
227        errorMessage: 'There was a problem updating your WOW Alerts preference. Please try again later.',
228        additionalData
229    });
230});
231
232// WOW Frequency handlers
233$('input[name="Mail_Frequency"], #Mail_Frequency_Day').on('change', function(e) {
234    if (!e.originalEvent) return;
235    
236    const $wowPilot = $('#WOWPilot');
237    if (!$wowPilot.is(':checked')) return;
238
239    if ($(this).attr('name') === 'Mail_Frequency') {
240        const isDaily = $(this).val() === 'Daily';
241        $('#Mail_Frequency_Day').prop('disabled', isDaily);
242    }
243
244    updatePreference({
245        toggleId: '#WOWPilot',
246        fieldName: 'WowAlerts',
247        errorMessage: 'There was a problem updating your WOW Alerts preference. Please try again later.',
248        additionalData: {
249            WOWPilot: 'Yes',
250            Mail_Frequency: getWOWFrequencyData()
251        }
252    });
253});
254
255function disablePage() {
256    // Add overlay if it doesn't exist
257    if ($('#page-overlay').length === 0) {
258        $('body').append('<div id="page-overlay"></div>');
259    }
260    $('body').addClass('page-disabled');
261}
262
263function enablePage() {
264    $('#page-overlay').remove();
265    $('body').removeClass('page-disabled modal-open');
266    $('.modal-backdrop').remove();
267}
268
269$(document).ready(function() {
270    const userData = getUser();
271    const PhoneNumber = userData ? userData.PhoneNumber : null;
272
273    if (!PhoneNumber || PhoneNumber === null) {
274        $('#TextMessage')
275            .prop('disabled', true)
276            .closest('.btn-toggle')
277            .addClass('disabled')
278            .attr('title', 'Phone number required for SMS alerts');
279    }
280});
281
282function showToast(options = {}) {
283    const {
284        title = 'Account Updated',
285        message = '',
286        linkText = 'Just Now',
287        linkUrl = '#',
288        duration = 12000,
289        showIcon = true,
290        iconType = 'success' // 'success', 'error', 'warning', 'info'
291    } = options;
292
293    // Icon mapping
294    const icons = {
295        success: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="#E31837"/></svg>',
296        error: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" fill="#E31837"/></svg>',
297        warning: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
297<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" fill="#E31837"/></svg>',
298        info: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" fill="#E31837"/></svg>'
299    };
300
301    const toast = `
302        <div class="account-toast">
303            ${showIcon ? `
304                <div class="toast-icon">
305                    ${icons[iconType] || icons.success}
306                </div>
307            ` : ''}
308            <div class="toast-content">
309                <div class="toast-title">${title}</div>
310                <div class="toast-message">${message}</div>
311            </div>
312            <button class="toast-close" onclick="this.parentElement.remove()">×</button> 
313        </div>
314    `;
315
316    // Remove existing toast if present
317    const existingToast = document.querySelector('.account-toast');
318    if (existingToast) {
319        existingToast.remove();
320    }
321
322    // Add new toast
323    document.body.insertAdjacentHTML('beforeend', toast);
324
325    // Add event listener to hide toast on outside click
326    document.addEventListener('click', function hideToast(event) {
327        const toastElement = document.querySelector('.account-toast');
328        if (toastElement && !toastElement.contains(event.target)) {
329            toastElement.remove();
330            document.removeEventListener('click', hideToast); // Remove the event listener after hiding
331        }
332    });
333
334    if (duration) {
335        setTimeout(() => {
336            const toastElement = document.querySelector('.account-toast');
337            if (toastElement) {
338                toastElement.remove();
339            }
340        }, duration);
341    }
342}

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.