PageSourceSearch

https://www.wemtoyota.com/wp-content/themes/magnetis-dealer/plugin…/js/PriceBuilder.js?ver=1790184938

js wemtoyota.com collected 2026-09-24 13:28:12 UTC 9,963 bytes, 266 lines download raw bytes

1/*jshint esversion: 11 */
2
3jQuery(function($) {
4
5  $.fn.priceBuilder = JQueryPlugin({
6    options: {
7      // WP ajax url
8      ajaxUrl: '',
9
10      builderUrl: 'http://pricebuilder.magnetisdealer.com/builder?model_id=36766',
11
12      // form or stripe
13      reservationMode: 'form',
14
15      vehicleId: 0,
16      lang: 'fr'
17    },
18    methods: {
19      init: function () {
20        const parser = document.createElement('a');
21        parser.href = this.options.builderUrl;
22        const url = parser.protocol + '//' + parser.host ;
23
24        const gtmEventMap = {
25          Open:            { event: 'magnetis.started' },
26          Close:           { event: 'magnetis.close', reason: 'unload' },
27          BackToSite:      { event: 'magnetis.close', reason: 'back_to_site' },
28          Inventory:       { event: 'magnetis.close', reason: 'inventory' },
29          StyleChange:     { event: 'magnetis.configuration_change', type: 'build_model' },
30          KeyOptionChange: { event: 'magnetis.configuration_change', type: 'build_model' },
31          OptionChange:    { event: 'magnetis.configuration_change', type: 'build_option' },
32          PaymentOption:   { event: 'magnetis.interaction', action: 'payment_options' },
33          Legal:           { event: 'magnetis.interaction', action: 'legal' },
34          Reserve:         { event: 'magnetis.form_started', mode: 'reserve' },
35          RequestInfo:     { event: 'magnetis.form_started', mode: 'lead' },
36        };
37
38        const buildVehicleContext = (data) => {
39          const model   = data?.vehicle?.model || {};
40          const style   = data?.vehicle?.style || {};
41          const summary = data?.summary       || {};
42          return {
43            vehicle_make:     model.divisionName,
44            vehicle_model:    model.modelName,
45            vehicle_year:     model.modelYear,
46            vehicle_trim:     style.consumerFriendlyStyleName,
47            vehicle_style_id: style.styleId,
48            vehicle_color:    data?.vehicle?.color,
49            vehicle_price:    summary.price,
50            session_id:       data?.session?.actual,
51          };
52        };
53
54        window.addEventListener("message", (message) => {
55          if (message.origin != url) {
56            return;
57          }
58
59          //console.log('PriceBuilder', message, url);
60
61          const gtmPayload = gtmEventMap[message.data.event];
62          if (gtmPayload && typeof window.gtmPushNewEvent === 'function') {
63            window.gtmPushNewEvent({
64              Component: 'plateforme.priceBuilder',
65              ...gtmPayload,
66              ...buildVehicleContext(message.data),
67            });
68          }
69
70          this.element.trigger(message.data.event, message.data);
71        });
72
73        this.element.on('Reserve', this.onReserve.bind(this));
74
75        this.element.on('RequestInfo', this.onRequestInfo.bind(this));
76
77        // On builder ready ('Open'), forward the open-time context (fresh fees + per-trim incentives)
78        this.element.on('Open', () => {
79          Promise.resolve(this.openDataPromise).then((data) => this.postContextToIframe(data));
80        });
81
82        if (window.location.hash === '#' + this.element.attr('id')) {
83          // Open the UI if the anchor related to current id is present
84          this.open();
85        }
86      },
87
88      onReserve: function(event, messagePayload) {
89        console.log('---------------------');
90        console.log(messagePayload);
91
92        $.ajax({
93          contentType: "application/json",
94          url: this.options.ajaxUrl + "?action=reservation_pricebuilder",
95          method: 'POST',
96          data: JSON.stringify(messagePayload),
97        })
98        .done(function (response) {
99          document.location.href = response.redirect;
100          console.log(response);
101        });
102
103      },
104
105      onRequestInfo: function(event, messagePayload) {
106        console.log('---------------------');
107        console.log(messagePayload);
108
109        const commentString = this.buildOptionsMessage(messagePayload);
110        $('.js-price-builder-modal textarea[name="comments"]').val(commentString);
111        $('.js-price-builder-modal').modal('show');
112      },
113
114      open: function() {
115        const priceBuilderUrl = new URL(this.options.builderUrl);
116        const priceBuilderUrlParams = new URLSearchParams(priceBuilderUrl.search);
117
118        const fromUrl = new URL(document.location);
119        priceBuilderUrlParams.set('url', fromUrl.protocol + '//' + fromUrl.host);
120
121        // Pre-select the trim + color the user picked on the VDP so the builder opens on the same configuration
122        const chromeStyleId = $('#native_trim_selector option:selected').attr('data-sid');
123        const chromeColorCode = $('.trim_color_picker span.active').attr('data-color-chrome-code');
124        if (chromeStyleId) {
125          priceBuilderUrlParams.set('style_id', chromeStyleId);
126        }
127        if (chromeColorCode) {
128          priceBuilderUrlParams.set('color', chromeColorCode);
129        }
130
131        priceBuilderUrl.search = priceBuilderUrlParams;
132
133        // Kick off the open-time data fetch; forwarded to the iframe on 'Open'.
134        this.openDataPromise = this.fetchOpenData();
135
136        jQuery('body').addClass('no-scroll');
137
138        this.element.find('iframe').attr('src', priceBuilderUrl);
139        this.element.removeClass('d-none');
140
141        setTimeout(() => {
142          this.element.addClass('open');
143        }, 50);
144
145        this.element.trigger('open');
146
147        //Sending Optimy widget to the back
148        let launcher = $('optimy-launcher');
149        if (launcher.length) {
150            let shadowRoot = launcher[0].shadowRoot;
151            $(shadowRoot).find('.optimy').css('z-index', '45');
152        }
153
154        //check if iframe #podium is present if yes set it's z-index to 50 using jquery
155        let podium = $('iframe#podium-bubble');
156        if (podium.length) {
157            podium.css('z-index', '44');
158        }
159      },
160
161      close: function() {
162        this.element.removeClass('open');
163        // Wait for the transition to complete
164        this.element.on('transitionend', () => {
165          this.element.find('iframe').attr('src', 'about:blank');
166          jQuery('body').removeClass('no-scroll');
167          this.element.addClass('d-none');
168          this.element.off('transitionend');
169
170          this.element.trigger('close');
171
172          // Reset z-index of the Optimy widget
173          let launcher = $('optimy-launcher');
174          if (launcher.length) {
175            let shadowRoot = launcher[0].shadowRoot;
176            $(shadowRoot).find('.optimy').css('z-index', '');
177          }
178          let podium = $('iframe#podium-bubble');
179          if (podium.length) {
180              podium.css('z-index', '1000');
181          }
182
183          if (window.location.hash === '#' + this.element.attr('id')) {
184            const newUrl = window.location.href.split('#')[0];
185            history.replaceState({}, document.title, newUrl);
186          }
187        });
188      },
189
190      /* Fetch fresh fees + per-trim incentives for this VDP from the host. */
191      fetchOpenData: function () {
192        const ajaxUrl = this.options.ajaxUrl;
193        const vehicleId = this.options.vehicleId;
194        const lang = this.options.lang || 'fr';
195
196        if (!ajaxUrl || !vehicleId) {
197          return Promise.resolve(null);
198        }
199
200        const url = ajaxUrl + '?action=pricebuilder_pricing_context'
201          + '&vehicle_id=' + encodeURIComponent(vehicleId)
202          + '&lang=' + encodeURIComponent(lang);
203
204        return fetch(url, {method: 'GET'})
205          .then((response) => (response.ok ? response.json() : null))
206          .catch(() => null);
207      },
208
209      /* Forward the open-time context (fees + incentives) into the iframe. */
210      postContextToIframe: function (data) {
211        if (!data) {
212          return;
213        }
214
215        const iframe = this.element.find('iframe')[0];
216        if (!iframe || !iframe.contentWindow) {
217          return;
218        }
219
220        const parser = document.createElement('a');
221        parser.href = this.options.builderUrl;
222        const builderOrigin = parser.protocol + '//' + parser.host;
223
224        iframe.contentWindow.postMessage(
225          {
226            type: 'magnetis:context',
227            fees: data.fees || [],
228            inPriceAdditionalFees: data.inPriceAdditionalFees || 0,
229            incentives: data.incentives || {},
230          },
231          builderOrigin
232        );
233      },
234
235      /**
236       * Convert PriceBuilder reservation into a human-readable string
237       * @param messagePayload
238       * @return {string}
239       */
240      buildOptionsMessage: function (messagePayload) {
241        const optionsInfo = messagePayload.summary.categories
242          .filter(category => category.options && category.options.length > 0) // filter out empty or non-existing options
243          .map(category => {
244            const optionsString = category.options.map(option => `${option.name}: ${option.value}$`).join(', ');
245            return `${category.name}: [${optionsString}]`;
246          })
247          .join('\n');
248
249        // Format the information into a string
250        const message = [
251          `Model: ${messagePayload.vehicle.model.divisionName} ${messagePayload.vehicle.model.modelName} ${messagePayload.vehicle.model.modelYear}`,
252          `Style: ${messagePayload.vehicle.style.consumerFriendlyStyleName}`,
253          `Color Code: ${messagePayload.vehicle.color}`,
254          `Options:\n${optionsInfo}`
255        ].join("\n");
256
257        if (messagePayload.reservation && messagePayload.reservation.url) {
258          message += `\nBuild URL: ${messagePayload.reservation.url}`;
259        }
260        return message;
261      }
262    },
263  });
264
265  $('.js-price-builder').priceBuilder();
266});

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.