PageSourceSearch

https://www.brewerairporttoyota.com/app/themes/dv-framework/media/js/da-modal.js?v=1.790.314

js brewerairporttoyota.com collected 2026-09-26 11:03:49 UTC 5,568 bytes, 140 lines download raw bytes

1/**
2 * @DealerAlchemist Modal — DAPopUp
3 *
4 * Config-driven modal for Nexus studio srpConfig actions. DVPopUp (dv-modal-disclaimer.js)
5 * stays exactly as-is for its ~20 existing callers; this is a separate entry point so the
6 * two never fight.
7 *
8 * Why not extend DVPopUp: its contract is disclaimer-first and positional
9 * (obj, id, isDisclaimer, modalType, dataObj, customClass), it branches on modalType for
10 * 360/video/shareVDP/shareSpecial, and — the blocker — it discards data-modal-content the
11 * moment a form id is present, swapping in a spinner and then replacing the whole text
12 * container with the form. A studio modal needs title + description + message +
13 * customContent + a form to coexist.
14 *
15 * Deliberately reuses the .dv-global-modal-* class names so all existing modal CSS applies
16 * and no new stylesheet is needed.
17 *
18 * @param {Object} options
19 * @param {string} [options.title]            Header label
20 * @param {string} [options.description]      Muted line under the title
21 * @param {string} [options.message]          Body copy
22 * @param {string} [options.customContent]    Raw HTML, rendered after the message
23 * @param {string} [options.size]             sm | md | lg | xl
24 * @param {string|number} [options.formId]    Numeric Gravity Form id, loaded over AJAX
25 * @param {Object} [options.vehicle]          { title, vin, stockNumber } for showVehicleInfo
26 * @param {boolean} [options.showVehicleInfo]
27 * @param {string} [options.customClass]
28 * @param {Function} [options.onOpen]         Called with the modal element once rendered
29 * @returns {HTMLElement|null} the modal element
30 */
31(function (window, document) {
32	"use strict";
33
34	var MAX_WIDTHS = { sm: "420px", md: "600px", lg: "800px", xl: "1040px" };
35
36	function escapeHtml(value) {
37		return String(value == null ? "" : value)
38			.replace(/&/g, "&")
39			.replace(/</g, "&lt;")
40			.replace(/>/g, "&gt;")
41			.replace(/"/g, "&quot;");
42	}
43
44	function closeModal(modal) {
45		if (!modal || !modal.parentNode) return;
46
47		modal.parentNode.removeChild(modal);
48
49		// Only release the scroll lock once the last modal is gone
50		if (!document.querySelector(".dv-global-modal")) {
51			document.body.classList.remove("dv-global-modal-open");
52		}
53	}
54
55	window.DAPopUp = function (options) {
56		var opts = options || {};
57		var vehicle = opts.vehicle || {};
58
59		var modal = document.createElement("div");
60		modal.className = "dv-global-modal da-modal" + (opts.customClass ? " " + opts.customClass : "");
61
62		var header = "";
63		if (opts.title) {
64			header = '<div class="dv-global-modal-header">'
65				+ '<p class="dv-global-modal-header-label">' + escapeHtml(opts.title) + "</p>"
66				+ "</div>";
67		}
68
69		var intro = "";
70
71		if (opts.showVehicleInfo && (vehicle.title || vehicle.vin || vehicle.stockNumber)) {
72			var details = [];
73			if (vehicle.stockNumber) details.push("Stock # " + escapeHtml(vehicle.stockNumber));
74			if (vehicle.vin) details.push("VIN " + escapeHtml(vehicle.vin));
75
76			// Each detail is nowrap so a narrow modal wraps between Stock and VIN, never inside one
77			intro += '<div class="da-modal-vehicle">'
78				+ (vehicle.title ? '<p class="da-modal-vehicle-title">' + escapeHtml(vehicle.title) + "</p>" : "")
79				+ (details.length
80					? '<p class="da-modal-vehicle-details"><span class="da-modal-vehicle-detail">'
81						+ details.join('</span> · <span class="da-modal-vehicle-detail">')
82						+ "</span></p>"
83					: "")
84				+ "</div>";
85		}
86
87		if (opts.description) intro += '<p class="da-modal-description">' + escapeHtml(opts.description) + "</p>";
88		if (opts.message) intro += '<p class="da-modal-message">' + escapeHtml(opts.message) + "</p>";
89		// Raw HTML by design — dealer-authored through the studio, same as custom containers
90		if (opts.customContent) intro += '<div class="da-modal-custom">' + opts.customContent + "</div>";
91
92		var formBlock = opts.formId
93			? '<div class="dv-global-modal-text da-modal-form">'
94				+ '<div class="dv-form-loading" style="text-align:center;padding:20px;">'
95				+ '<i class="fas fa-spinner fa-spin"></i> Loading Form...</div></div>'
96			: "";
97
98		modal.innerHTML =
99			'<div class="dv-global-modal-mask"></div>'
100			+ '<div class="dv-global-modal-dialog">'
101			+ '<span id="dv-close-modal" class="da-modal-close"><i class="fal fa-times"></i></span>'
102			+ '<div class="dv-global-modal-inner">'
103			+ header
104			+ '<div class="dv-global-modal-body">'
105			+ (intro ? '<div class="da-modal-intro">' + intro + "</div>" : "")
106			+ formBlock
107			+ "</div></div></div>";
108
109		if (opts.size && MAX_WIDTHS[opts.size]) {
110			modal.querySelector(".dv-global-modal-dialog").style.maxWidth = MAX_WIDTHS[opts.size];
111		}
112
113		document.body.appendChild(modal);
114		document.body.classList.add("dv-global-modal-open");
115
116		modal.querySelector(".da-modal-close").addEventListener("click", function () { closeModal(modal); });
117		modal.querySelector(".dv-global-modal-mask").addEventListener("click", function () { closeModal(modal); });
118
119		function onKeydown(event) {
120			if (event.key !== "Escape") return;
121			closeModal(modal);
122			document.removeEventListener("keydown", onKeydown);
123		}
124		document.addEventListener("keydown", onKeydown);
125
126		if (opts.formId) {
127			// Shared loader (da-gform-loader.js): get_gform fetch, honeypot re-init,
128			// gform_post_render — the hooks anti-spam and conditional logic depend on.
129			window.daGformLoad(modal.querySelector(".da-modal-form"), opts.formId, { vin: vehicle.vin });
130		}
131
132		if (typeof opts.onOpen === "function") {
133			opts.onOpen(modal);
134		}
135
136		return modal;
137	};
138
139	window.DAPopUpClose = closeModal;
140})(window, document);

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.