PageSourceSearch

https://duncohc.com/wp-content/plugins/scheduler-setup/assets/on_demand.js?ver=1.0.8

js duncohc.com collected 2026-10-07 18:53:39 UTC 7,847 bytes, 243 lines download raw bytes

1/**
2 * on_demand.js — Scheduler Setup Plugin
3 *
4 * window.SchedulerConfig is injected by PHP (wp_add_inline_script) BEFORE
5 * this file loads, so every value is available immediately.
6 *
7 * Usage anywhere on the site:
8 *
9 *   // Raw values
10 *   const key  = SchedulerSetup.apiKey;
11 *   const id   = SchedulerSetup.schedulerId;
12 *
13 *   // Trigger on-demand
14 *   SchedulerSetup.run();
15 *
16 *   // Listen for completion
17 *   document.addEventListener('schedulerSetup:done', (e) => {
18 *       console.log('Scheduler finished', e.detail);
19 *   });
20 */
21
22( function ( window ) {
23    'use strict';
24
25    /* ------------------------------------------------------------------ */
26    /* 1.  Read the config object injected by PHP                          */
27    /* ------------------------------------------------------------------ */
28    var cfg = window.SchedulerConfig || {};
29
30    var API_KEY      = cfg.apiKey      || '';
31    var SCHEDULER_ID = cfg.schedulerId || '';
32
33    /**
34     * Validate that required config values are present.
35     * @returns {boolean}
36     */
37    function isConfigValid() {
38        if ( ! API_KEY ) {
39            console.warn( '[SchedulerSetup] _api_key is empty. Check ACF site-settings.' );
40            return false;
41        }
42        if ( ! SCHEDULER_ID ) {
43            console.warn( '[SchedulerSetup] _scheduler_id is empty. Check ACF site-settings.' );
44            return false;
45        }
46        return true;
47    }
48
49
50    /* ------------------------------------------------------------------ */
51    /*2.  Public API — attached to window so every file can use it       */
52    /* ------------------------------------------------------------------ */
53
54    window.SchedulerSetup = {
55        /** The API key read from ACF site-settings._api_key */
56        apiKey:      API_KEY,
57
58        /** The scheduler ID read from ACF site-settings._scheduler_id */
59        schedulerId: SCHEDULER_ID,
60
61        /** True when both values are present */
62        isReady: isConfigValid(),
63
64    };
65
66
67/* On demand script to run scheduler on page based on click  */
68
69/* IM Banshi - 03-20-2026 Resolve
70 * button click and load   service
71 * titan script after click */
72document.addEventListener('touchstart', handleSchedulerClick, { passive: false });
73document.addEventListener('click', handleSchedulerClick);
74var schedulerListener = null;
75var fallbackTimer = null;
76var schedulerUsed = false;
77var loadInProgress = false; // true while a load is in flight but not yet resolved
78
79function handleSchedulerClick(e) {
80
81    // This is used when there is a mix of schedule-online hrefs
82    var target = e.target.closest('a[href="/schedule-online"], a[href="/schedule-online/"], a[href$="/schedule-online"], a[href$="/schedule-online/"]');
83
84    if (!target) return;
85
86    e.preventDefault();
87
88    console.log('Captured early interaction' + target.href);
89
90    // Now load your delayed scripts manually
91    loadSchedulerScript(target.href);
92}
93
94function loadSchedulerScript(targeLink) {
95    var link = targeLink;
96    var isLoaded = document.querySelector('#se-widget-embed');
97    console.log(isLoaded);
98
99    if (isLoaded === null) {
100        console.log('Script not loaded');
101        loadInProgress = true; // mark load as started
102
103        var script = document.createElement('script');
104        script.src = "https://embed.scheduler.servicetitan.com/scheduler-v1.js";
105        script.defer = true;
106        script.id = "se-widget-embed";
107
108        script.setAttribute('data-api-key', SchedulerSetup.apiKey);
109        script.setAttribute('data-schedulerid', SchedulerSetup.schedulerId);
110        var maxTime = 2500;
111        var intervalTime = 100;
112        var elapsed = 0;
113        var runCount = 0;
114
115        script.onerror = function () { // recover if the widget script fails to load at all
116            console.warn('Scheduler script failed to load');
117            loadInProgress = false;
118            if (link && link != '') {
119                window.location.href = link;
120            }
121        };
122
123        script.onload = function () {
124            console.log('Script loaded by plugin');
125
126            var checkInterval = setInterval(function () {
127                runCount++;
128                console.log('Interval run count:', runCount);
129
130                var iframeExists = document.querySelector('iframe[src*="scheduler"]') !== null;
131                var schedulerReady = (typeof _scheduler !== "undefined") && iframeExists;
132
133                if (schedulerReady) {
134                    clearInterval(checkInterval);
135                    console.log('Scheduler + iframe detected');
136
137                    function onReady(event) {
138                        if (event.origin !== "https://scheduler.servicetitan.com") return;
139
140                        if (event.data && event.data.type === "se-app-ready") {
141                            console.log("Scheduler ready");
142
143                            window.removeEventListener("message", onReady);
144
145                            _scheduler.show({
146                                schedulerId: SchedulerSetup.schedulerId
147                            });
148
149                            schedulerUsed = true;
150                            loadInProgress = false; // load resolved successfully
151                        }
152                    }
153
154                    window.addEventListener("message", onReady);
155                } else {
156                    elapsed += intervalTime;
157
158                    if (elapsed >= maxTime) {
159                        clearInterval(checkInterval);
160
161                        console.log('Max time reached');
162                        console.log('Total interval runs:', runCount);
163
164                        loadInProgress = false; // give up, unlock future clicks
165
166                        if (link && link != '') {
167                            window.location.href = link;
168                            return;
169                        }
170                    }
171                }
172
173            }, intervalTime);
174        };
175
176        document.head.appendChild(script);
177
178        return; // ✅ STOP further execution
179    }
180
181    console.log('Schedule script found on page')
182    var eventReceived = false;
183
184    // Block multiple listeners
185    if (schedulerListener) {
186        window.removeEventListener("message", schedulerListener);
187        schedulerListener = null;
188    }
189
190    if (fallbackTimer) {
191        clearTimeout(fallbackTimer);
192    }
193
194    // If scheduler already used once → assume success (reopen)
195    if (schedulerUsed) {
196        console.log("Scheduler already used, skipping listener");
197        _scheduler.show({ schedulerId: SchedulerSetup.schedulerId });
198        return;
199    }
200
201    // A load from an earlier click is still in flight — ignore this click instead
202    // of falling through to the strict checks below
203    if (loadInProgress) {
204        console.log('Load already in progress, ignoring extra click');
205        return;
206    }
207
208    // If scheduler not loaded → fallback
209    if (typeof _scheduler === "undefined") {
210        window.location.href = link;
211        return;
212    }
213
214    // Open widget
215    _scheduler.show({ schedulerId: SchedulerSetup.schedulerId });
216
217    schedulerListener = function (event) {
218
219        if (event.origin !== "https://scheduler.servicetitan.com") return;
220        if (!event.data || event.data.type !== "se-event") return;
221
222        console.log("Scheduler Event:", event.data.eventName);
223        eventReceived = true;
224        schedulerUsed = true;
225
226        clearTimeout(fallbackTimer);
227        window.removeEventListener("message", schedulerListener);
228        schedulerListener = null;
229    };
230
231    window.addEventListener("message", schedulerListener);
232
233    fallbackTimer = setTimeout(function () {
234        if (!eventReceived) {
235            console.warn("Scheduler silent — fallback triggered");
236            window.location.href = link;
237        }
238    }, 2000);
239}
240
241
242
243}( window ) );

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.