PageSourceSearch

https://play.date/static/js/cart.0bb3b6626166.js

js play.date collected 2026-10-02 02:21:56 UTC 18,983 bytes, 518 lines download raw bytes

1function getCSRFToken() {
2    const cookieName = "csrftoken";
3    let cookieValue = null;
4    if (document.cookie && document.cookie !== "") {
5        var cookies = document.cookie.split(";");
6        for (var i = 0; i < cookies.length; i++) {
7            let cookie = cookies[i].trim();
8            if (
9                cookie.substring(0, cookieName.length + 1) ===
10                cookieName + "="
11            ) {
12                cookieValue = decodeURIComponent(
13                    cookie.substring(cookieName.length + 1)
14                );
15                break;
16            }
17        }
18    }
19    return cookieValue;
20}
21
22document.addEventListener("DOMContentLoaded", function () {
23    Array.from(
24        document.querySelectorAll('button[id$="cart-increment"]')
25    ).forEach((button) => {
26        initializeIncrementButton(button, true);
27    });
28    Array.from(
29        document.querySelectorAll('button[id$="cart-decrement"]')
30    ).forEach((button) => {
31        initializeIncrementButton(button, false);
32    });
33    Array.from(document.querySelectorAll('a[id$="add"]')).forEach((button) => {
34        initializeAddButton(button);
35    });
36    Array.from(document.querySelectorAll('button[id$="cart-add"]')).forEach(
37        (button) => {
38            initializeAddButton(button);
39        }
40    );
41
42    initializeRefreshButton();
43    initializeClearButton();
44});
45
46function initializeAddButton(addButton) {
47    if (addButton) {
48        let addInProgress = false;
49        let states = {
50            ADD: 0,
51            ADDING: 1,
52            UNAVAILABLE: 2,
53            ERROR: 3,
54            ADDED: 4,
55        };
56        let classes = {
57            addButton: {
58                [states.ADDING]: ["adding"],
59            },
60            errorModal: {
61                [states.ADD]: ["hidden"],
62                [states.ADDING]: ["hidden"],
63                [states.ADDED]: ["hidden"],
64                [states.ERROR]: [],
65                [states.UNAVAILABLE]: ["hidden"],
66            },
67        };
68        let html = {
69            addButton: {
70                [states.ADD]: "Add to Cart",
71                [states.ADDING]: "Adding...",
72                [states.ADDED]: "In Cart",
73                [states.ERROR]: "Unavailable",
74            },
75            errorModal: {},
76        };
77        let state = states.ADD;
78        function transitionState(next, effects) {
79            effects = effects || [];
80            const previous = state;
81            const elements = {
82                addButton,
83            };
84            Object.entries(elements).forEach(function ([name, element]) {
85                if (!element) {
86                    return;
87                }
88                element.classList.remove(...(classes[name][previous] || []));
89                element.classList.add(...(classes[name][next] || []));
90
91                const innerHTML = html[name][next];
92                if (innerHTML) {
93                    element.innerHTML = innerHTML;
94                }
95            });
96            state = next;
97        }
98        addButton.addEventListener("click", function (event) {
99            console.log(addButton.dataset);
100            if (addButton.dataset.disabled) {
101                return;
102            }
103            event.preventDefault();
104            event.stopPropagation();
105            const addToCartURL = addButton.dataset.href;
106            if (state === states.ADD || state === states.ERROR) {
107                transitionState(states.ADDING);
108                ajaxAddToCart(addToCartURL, addButton.dataset.pk);
109            } else if (state === states.ADDED) {
110                window.location.href = addButton.dataset.cartHref;
111            }
112        });
113
114        let variantSelector = addButton.parentNode.parentNode.querySelector(
115            ".shop-item-variant > select"
116        );
117        if (variantSelector) {
118            variantSelector.addEventListener("change", function (event) {
119                if (state === states.ADDED || state === states.ERROR) {
120                    transitionState(states.ADD);
121                }
122            });
123        }
124
125        function ajaxAddToCart(addToCartURL, pk) {
126            let clickTime = Date.now();
127            if (addInProgress) {
128                return;
129            }
130            addInProgress = true;
131            let timeSinceClick = Date.now() - clickTime;
132            let delay = Math.max(600 - timeSinceClick, 0);
133
134            const cartContents = document.querySelector("p#cart-contents");
135            const cartCountLabel = document.querySelector("span#cart-count");
136            setTimeout(function () {
137                new Promise(function (resolve, reject) {
138                    const httpRequest = new XMLHttpRequest();
139                    httpRequest.open("POST", addToCartURL, true);
140                    httpRequest.setRequestHeader("X-CSRFToken", getCSRFToken());
141                    httpRequest.setRequestHeader(
142                        "Content-Type",
143                        "application/x-www-form-urlencoded"
144                    );
145                    httpRequest.onreadystatechange = function () {
146                        if (httpRequest.readyState === XMLHttpRequest.DONE) {
147                            if (httpRequest.status === 200) {
148                                resolve(httpRequest.responseText);
149                            } else {
150                                console.log(httpRequest.responseText);
151                                reject(
152                                    "There was an error adding this item to the cart."
153                                );
154                            }
155                        }
156                    };
157                    httpRequest.send("item=" + pk + "&quantity=1");
158                })
159                    .then(function (data) {
160                        setTimeout(function () {
161                            transitionState(states.ADDED);
162                            if (cartContents) {
163                                cartContents.innerHTML = data;
164                            }
165                            let cartData = JSON.parse(data);
166                            cartCountLabel.innerHTML =
167                                cartData["cart"]["item_count"];
168                        }, delay);
169                    })
170                    .catch(function (error) {
171                        html.errorModal[states.ERROR] = error;
172                        transitionState(states.ERROR);
173                        if (cartContents) {
174                            cartContents.innerHTML = error;
175                        }
176                    })
177                    .finally(function () {
178                        addInProgress = false;
179                    });
180            }, delay);
181        }
182
183        document.body.addEventListener(
184            "click",
185            function (ev) {
186                if (state === states.ADDING) {
187                    transitionState(states.ADDED);
188                }
189            },
190            false
191        );
192    }
193}
194
195function initializeRefreshButton() {
196    const refreshButton = document.querySelector("a#refresh-cart");
197    const cartContents = document.querySelector("p#cart-contents");
198    if (!refreshButton) {
199        return;
200    }
201    refreshButton.addEventListener("click", function (event) {
202        event.preventDefault();
203        event.stopPropagation();
204
205        const refreshURL = event.target.href;
206
207        new Promise(function (resolve, reject) {
208            const httpRequest = new XMLHttpRequest();
209            httpRequest.open("GET", refreshURL, true);
210            httpRequest.onreadystatechange = function () {
211                if (httpRequest.readyState === XMLHttpRequest.DONE) {
212                    if (httpRequest.status === 200) {
213                        resolve(httpRequest.responseText);
214                    } else {
215                        console.log(httpRequest.responseText);
216                        reject("There was an error refreshing the cart.");
217                    }
218                }
219            };
220            httpRequest.send();
221        })
222            .then(function (content) {
223                cartContents.innerHTML = content;
224            })
225            .catch(function (error) {
226                console.log(error);
227            });
228    });
229}
230
231function initializeClearButton() {
232    const clearButton = document.querySelector("a#clear-cart");
233    const cartContents = document.querySelector("p#cart-contents");
234    if (!clearButton) {
235        return;
236    }
237    clearButton.addEventListener("click", function (event) {
238        event.preventDefault();
239        event.stopPropagation();
240
241        const refreshURL = event.target.href;
242
243        new Promise(function (resolve, reject) {
244            const httpRequest = new XMLHttpRequest();
245            httpRequest.open("POST", refreshURL, true);
246            httpRequest.setRequestHeader("X-CSRFToken", getCSRFToken());
247            httpRequest.onreadystatechange = function () {
248                if (httpRequest.readyState === XMLHttpRequest.DONE) {
249                    if (httpRequest.status === 200) {
250                        resolve(httpRequest.responseText);
251                    } else {
252                        console.log(httpRequest.responseText);
253                        reject("There was an error clearing the cart.");
254                    }
255                }
256            };
257            httpRequest.send();
258        })
259            .then(function (content) {
260                cartContents.innerHTML = content;
261            })
262            .catch(function (error) {
263                console.log(error);
264            });
265    });
266}
267
268function updateHTMLFromCartData(cartData) {
269    const cartCountLabel = document.querySelector("span#cart-count");
270    const cartContents = document.querySelector("p#cart-contents");
271    // cartData: {
272    //     cart: {
273    //         item_count: int,
274    //         items: [
275    //             {
276    //                 bundle_discount: {
277    //                     discount_dollars: "5.00",
278    //                     discount_percentage: 0,
279    //                     discount_type: "FLAT",
280    //                     quantity: 1,
281    //                 },
282    //                 metadata: null
283    //                 promo_code_discount: null
284    //                 quantity: 1,
285    //                 price: "199.00",
286    //                 sku_identifier: "PDU-Y-01"
287    //                 sku_title: "Playdate"
288    //                 subtotal: "199.00"
289    //                 pre_discount_total: "199.00"
290    //             }
291    //         ],
292    //         metadata: null,
293    //         promo_code_discount: {
294    //             code: ":)",
295    //             discount_dollars: "0",
296    //             discount_percentage: 50,
297    //             discount_type: "PERCENTAGE",
298    //         },
299    //         total: str
300    //         pre_discount_total: str
301    //     }
302    // }
303    if (cartContents) {
304        cartContents.innerHTML = cartData;
305    }
306    let emptyCartMessage = document.querySelector("#empty-cart-message");
307    if (emptyCartMessage) {
308        if (cartData["cart"]["item_count"] == 0) {
309            emptyCartMessage.classList.remove("hidden");
310        } else {
311            emptyCartMessage.classList.add("hidden");
312        }
313    }
314    cartCountLabel.innerHTML = cartData["cart"]["item_count"];
315    // update the pre-discount total
316    if (cartData.cart.promo_code_discount) {
317        document.querySelectorAll(".cart-discount-element").forEach((node) => {
318            node.classList.remove("hidden");
319        });
320        document.querySelector(".cart-discounts").classList.remove("hidden");
321        document.querySelector(
322            ".cart-compare-price"
323        ).innerHTML = `$${cartData.cart.pre_discount_total}`;
324        document.querySelector(
325            ".cart-discount-title .title"
326        ).innerHTML = `${cartData.cart.promo_code_discount.display}`;
327    } else {
328        document.querySelectorAll(".cart-discount-element").forEach((node) => {
329            node.classList.add("hidden");
330        });
331    }
332    // update the cart total
333    document.querySelector(
334        ".cart-items dd.cart-subtotal .cart-total"
335    ).innerHTML = `$${cartData.cart.total}`;
336    // update the item
337    const presentRows = Array.from(
338        document.querySelectorAll(".item-row")
339    ).reduce((acc, row) => {
340        acc[row.id] = row;
341        return acc;
342    }, {});
343    cartData.cart.items.forEach((item) => {
344        const sku = item.sku_identifier;
345        const row = document.querySelector(`div#${sku.replaceAll('.', '\\.')}`);
346        const quantityValue = row.querySelector("dd.cart-item-quantity .quantity")
347        quantityValue && (quantityValue.innerHTML = item.quantity);
348        if (item.bundle_discount) {
349            row.querySelector(
350                "s.cart-item-compare-price"
351            ).innerHTML = `$${item.pre_discount_total}`;
352            row.querySelector(".cart-item-discount-title").innerHTML =
353                item.bundle_discount.display;
354            row.querySelector(".cart-item-discount-title")?.classList.remove(
355                "hidden"
356            );
357            row.querySelector(".cart-item-compare-price")?.classList.remove(
358                "hidden"
359            );
360        } else if (item.ghost) {
361            // make sure we show "Included in your bundle"
362            row.querySelector(".cart-item-discount-title")?.classList.remove(
363                "hidden"
364            );
365        } else {
366            row.querySelector(".cart-item-discount-title")?.classList.add(
367                "hidden"
368            );
369            row.querySelector(".cart-item-compare-price")?.classList.add(
370                "hidden"
371            );
372        }
373        row.querySelector(
374            "dd.cart-item-price > .cart-item-total"
375        ).innerHTML = `$${item.subtotal}`;
376        presentRows[row.id] = null;
377    });
378    Object.entries(presentRows).forEach(([k, v]) => {
379        if (v) {
380            v.remove();
381        }
382    });
383    if (cartData.cart.items.length === 0) {
384        // hide the promo code element and subtotal.
385        const selectorsToHide = [
386            ".checkout-button",
387            ".cart-items",
388            ".cart-promocode",
389        ];
390        selectorsToHide.forEach((selector) => {
391            document.querySelector(selector).classList.add("hidden");
392        });
393    }
394}
395
396function initializeIncrementButton(incrementButton, increment) {
397    if (incrementButton) {
398        let addInProgress = false;
399        let states = {
400            ADD: 0,
401            ADDING: 1,
402            UNAVAILABLE: 2,
403            ERROR: 3,
404        };
405        let html = {
406            incrementButton: {
407                [states.ADD]: increment ? "+" : "-",
408                [states.ADDING]: "◕",
409                [states.ERROR]: "X",
410            },
411        };
412        let classes = {
413            incrementButton: {},
414        };
415        let state = states.ADD;
416        function transitionState(next, effects) {
417            const elements = {
418                incrementButton,
419            };
420            const previous = state;
421            Object.entries(elements).forEach(function ([name, element]) {
422                if (!element) {
423                    return;
424                }
425                element.classList.remove(...(classes[name][previous] || []));
426                element.classList.add(...(classes[name][next] || []));
427
428                const innerHTML = html[name][next];
429                if (innerHTML) {
430                    element.innerHTML = innerHTML;
431                }
432            });
433            state = next;
434        }
435        incrementButton.addEventListener("click", function (event) {
436            if (incrementButton.dataset.disabled) {
437                return;
438            }
439            event.preventDefault();
440            event.stopPropagation();
441            const addToCartURL = incrementButton.dataset.href;
442            if (state === states.ADD || state === states.ERROR) {
443                transitionState(states.ADDING);
444                ajaxAddToCart(addToCartURL, incrementButton.dataset.pk);
445            }
446        });
447
448        function ajaxAddToCart(addToCartURL, pk) {
449            let clickTime = Date.now();
450            if (addInProgress) {
451                return;
452            }
453            addInProgress = true;
454            let timeSinceClick = Date.now() - clickTime;
455            let delay = Math.max(600 - timeSinceClick, 0);
456
457            setTimeout(function () {
458                new Promise(function (resolve, reject) {
459                    const httpRequest = new XMLHttpRequest();
460                    httpRequest.open("POST", addToCartURL, true);
461                    httpRequest.setRequestHeader("X-CSRFToken", getCSRFToken());
462                    httpRequest.setRequestHeader(
463                        "Content-Type",
464                        "application/x-www-form-urlencoded"
465                    );
466                    httpRequest.onreadystatechange = function () {
467                        if (httpRequest.readyState === XMLHttpRequest.DONE) {
468                            if (httpRequest.status === 200) {
469                                resolve(httpRequest.responseText);
470                            } else {
471                                console.log(httpRequest.responseText);
472                                reject(
473                                    `There was an error ${
474                                        increment
475                                            ? "adding this item to the cart."
476                                            : "removing this item from the cart."
477                                    }`
478                                );
479                            }
480                        }
481                    };
482                    httpRequest.send(`item=${pk}&quantity=1`);
483                })
484                    .then(function (data) {
485                        let cartData = JSON.parse(data);
486                        if (cartData["reload"]) {
487                            window.location.reload();
488                        } else {
489                            setTimeout(function () {
490                                updateHTMLFromCartData(cartData);
491                            }, delay);
492                        }
493                    })
494                    .catch(function (error) {
495                        html.errorModal[states.ERROR] = error;
496                        transitionState(states.ERROR);
497                        if (cartContents) {
498                            cartContents.innerHTML = error;
499                        }
500                    })
501                    .finally(function () {
502                        addInProgress = false;
503                        transitionState(states.ADD);
504                    });
505            }, delay);
506        }
507
508        document.body.addEventListener(
509            "click",
510            function (ev) {
511                if (state === states.ADDING) {
512                    transitionState(states.ADDED);
513                }
514            },
515            false
516        );
517    }
518}

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.