PageSourceSearch

https://oxoliving.com/wp-content/plugins/wordpress-plugin-producti…/js/cloudstay-wishlist.js?ver=1.2.875

js oxoliving.com collected 2026-10-08 08:01:02 UTC 7,486 bytes, 261 lines download raw bytes

1/**
2 * Cloudstay Wishlist/Favorites
3 *
4 * Client-side wishlist functionality using localStorage
5 *
6 * @package Cloudstay
7 * @since 1.3.0
8 */
9
10(function() {
11    'use strict';
12
13    const STORAGE_KEY = 'cloudstay_wishlist';
14
15    /**
16     * Wishlist manager
17     */
18    const wishlist = {
19        items: [],
20
21        /**
22         * Initialize wishlist from localStorage
23         */
24        init() {
25            try {
26                const stored = localStorage.getItem(STORAGE_KEY);
27                this.items = stored ? JSON.parse(stored) : [];
28            } catch (e) {
29                console.error('Error loading wishlist:', e);
30                this.items = [];
31            }
32            this.updateAllButtons();
33            this.updateWishlistCount();
34        },
35
36        /**
37         * Save wishlist to localStorage
38         */
39        save() {
40            try {
41                localStorage.setItem(STORAGE_KEY, JSON.stringify(this.items));
42            } catch (e) {
43                console.error('Error saving wishlist:', e);
44            }
45        },
46
47        /**
48         * Add item to wishlist
49         */
50        add(id, data = {}) {
51            // Convert to string for consistent comparison
52            id = String(id);
53            if (this.has(id)) return false;
54
55            this.items.push({
56                id: id,
57                name: data.name || '',
58                image: data.image || '',
59                price: data.price || 0,
60                currency: data.currency || 'USD',
61                symbol: data.symbol || '$',
62                location: data.location || '',
63                url: data.url || '',
64                bedrooms: data.bedrooms || 0,
65                bathrooms: data.bathrooms || 0,
66                rating: data.rating || 0,
67                addedAt: new Date().toISOString()
68            });
69
70            this.save();
71            this.updateAllButtons();
72            this.updateWishlistCount();
73            this.showNotification('Added to wishlist');
74            return true;
75        },
76
77        /**
78         * Remove item from wishlist
79         */
80        remove(id) {
81            id = String(id);
82            const index = this.items.findIndex(item => String(item.id) === id);
83            if (index === -1) return false;
84
85            this.items.splice(index, 1);
86            this.save();
87            this.updateAllButtons();
88            this.updateWishlistCount();
89            this.showNotification('Removed from wishlist');
90            return true;
91        },
92
93        /**
94         * Toggle item in wishlist
95         */
96        toggle(id, data = {}) {
97            id = String(id);
98            if (this.has(id)) {
99                return this.remove(id);
100            } else {
101                return this.add(id, data);
102            }
103        },
104
105        /**
106         * Check if item is in wishlist
107         */
108        has(id) {
109            id = String(id);
110            return this.items.some(item => String(item.id) === id);
111        },
112
113        /**
114         * Get all wishlist items
115         */
116        getAll() {
117            return [...this.items];
118        },
119
120        /**
121         * Clear all wishlist items
122         */
123        clear() {
124            this.items = [];
125            this.save();
126            this.updateAllButtons();
127            this.updateWishlistCount();
128        },
129
130        /**
131         * Get wishlist count
132         */
133        count() {
134            return this.items.length;
135        },
136
137        /**
138         * Update all wishlist button states on page
139         */
140        updateAllButtons() {
141            document.querySelectorAll('[data-wishlist-id]').forEach(btn => {
142                const id = btn.dataset.wishlistId;
143                this.updateButtonState(btn, this.has(id));
144            });
145        },
146
147        /**
148         * Update single button state
149         */
150        updateButtonState(btn, isActive) {
151            if (isActive) {
152                btn.classList.add('active');
153                btn.setAttribute('aria-label', 'Remove from wishlist');
154            } else {
155                btn.classList.remove('active');
156                btn.setAttribute('aria-label', 'Add to wishlist');
157            }
158
159            // Update heart icon if present
160            const svg = btn.querySelector('svg');
161            if (svg) {
162                svg.setAttribute('fill', isActive ? '#ef4444' : 'none');
163            }
164        },
165
166        /**
167         * Update wishlist count badge in header
168         */
169        updateWishlistCount() {
170            const countElements = document.querySelectorAll('.wishlist-count');
171            const count = this.count();
172
173            countElements.forEach(el => {
174                el.textContent = count;
175                el.style.display = count > 0 ? 'inline-flex' : 'none';
176            });
177        },
178
179        /**
180         * Show notification
181         */
182        showNotification(message) {
183            // Remove existing notification
184            const existing = document.querySelector('.wishlist-notification');
185            if (existing) {
186                existing.remove();
187            }
188
189            // Create notification
190            const notification = document.createElement('div');
191            notification.className = 'wishlist-notification';
192            notification.innerHTML = `
193                <svg viewBox="0 0 24 24" fill="#ef4444" width="20" height="20">
194                    <path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/>
195                </svg>
196                <span>${message}</span>
197            `;
198
199            document.body.appendChild(notification);
200
201            // Animate in
202            requestAnimationFrame(() => {
203                notification.classList.add('show');
204            });
205
206            // Remove after delay
207            setTimeout(() => {
208                notification.classList.remove('show');
209                setTimeout(() => notification.remove(), 300);
210            }, 2000);
211        }
212    };
213
214    /**
215     * Bind wishlist button events
216     */
217    function bindWishlistButtons() {
218        document.addEventListener('click', (e) => {
219            const btn = e.target.closest('[data-wishlist-id]');
220            if (!btn) return;
221
222            e.preventDefault();
223            e.stopPropagation();
224
225            const id = btn.dataset.wishlistId;
226            const data = {
227                name: btn.dataset.wishlistName || '',
228                image: btn.dataset.wishlistImage || '',
229                price: parseFloat(btn.dataset.wishlistPrice) || 0,
230                currency: btn.dataset.wishlistCurrency || 'USD',
231                symbol: btn.dataset.wishlistSymbol || '$',
232                location: btn.dataset.wishlistLocation || '',
233                url: btn.dataset.wishlistUrl || window.location.href,
234                bedrooms: parseInt(btn.dataset.wishlistBedrooms) || 0,
235                bathrooms: parseFloat(btn.dataset.wishlistBathrooms) || 0,
236                rating: parseFloat(btn.dataset.wishlistRating) || 0
237            };
238
239            wishlist.toggle(id, data);
240        });
241    }
242
243    /**
244     * Initialize when DOM is ready
245     */
246    function init() {
247        wishlist.init();
248        bindWishlistButtons();
249    }
250
251    // Expose wishlist globally
252    window.cloudstayWishlist = wishlist;
253
254    // Initialize
255    if (document.readyState === 'loading') {
256        document.addEventListener('DOMContentLoaded', init);
257    } else {
258        init();
259    }
260
261})();

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.