AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/edit-json-plugin.js

/* eslint-disable */
/* Genius config editor — Monaco + auto-detected component sidebar.
 * Falls back to a plain <textarea> if Monaco cannot be loaded, so the
 * page is always usable. */
jQuery(document).ready(function ($) {
	var cfg = window.editJsonPlugin || {};
	var vsPath = cfg.monaco_vs || "";
	var baseUrl = vsPath.replace(/\/vs$/, "") + "/";

	var state = {
		mode: "monaco", // or "fallback"
		editor: null,
		_fallbackArea: null,
		components: [],
		schema: null,
		filter: "all",
		search: "",
	};

	var $ta = $("#json-content");
	var $list = $("#componentList");
	var $status = $("#genius-status");

	/* ---------- value abstraction (works for Monaco and fallback) ---------- */
	function getValue() {
		if (state.mode === "monaco" && state.editor) return state.editor.getValue();
		if (state._fallbackArea) return state._fallbackArea.val();
		return $ta.val();
	}
	function setValue(v) {
		if (state.mode === "monaco" && state.editor) {
			state.editor.setValue(v);
			return;
		}
		if (state._fallbackArea) {
			state._fallbackArea.val(v);
			return;
		}
		$ta.val(v);
	}

	/* ---------- feedback ---------- */
	function showToast(message, type) {
		if (typeof Toastify !== "function") {
			if (type === "error") console.error(message);
			else console.log(message);
			return;
		}
		Toastify({
			text: message,
			duration: 6000,
			newWindow: true,
			close: true,
			gravity: "bottom",
			position: "right",
			stopOnFocus: true,
			style: {
				background: type === "success" ? "green" : type === "error" ? "red" : "#2271b1",
				fontSize: "16px",
				borderRadius: "5px",
			},
		}).showToast();
	}

	function setStatus(text, kind) {
		$status.removeClass("is-error is-ok");
		if (kind) $status.addClass(kind === "error" ? "is-error" : "is-ok");
		$status.text(text || "");
	}

	function esc(s) {
		return String(s).replace(/[&<>"']/g, function (ch) {
			return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[ch];
		});
	}

	/* ---------- modal (kept from the original) ---------- */
	var modal = $("#myModal");
	$(".close").on("click", function () {
		modal.hide();
	});
	$("#close-modal-button").on("click", function () {
		modal.hide();
	});
	$(window).on("click", function (event) {
		if ($(event.target).is(modal)) modal.hide();
	});
	function openModal(message) {
		$("#modal-body").text(message);
		modal.show();
	}

	/* ---------- save ---------- */
	function saveJson() {
		var jsonContent = getValue();
		try {
			JSON.parse(jsonContent);
		} catch (e) {
			showToast("Invalid JSON format. Please fix the JSON syntax.", "error");
			setStatus("Invalid JSON — not saved", "error");
			return;
		}

		$("#saving-backdrop").show();
		$.ajax({
			url: cfg.ajax_url,
			method: "POST",
			data: {
				action: "save_json_file",
				json_content: jsonContent,
				page: "leadbox-settings-genius",
				nonce: cfg.nonce,
			},
			success: function (response) {
				$("#saving-backdrop").hide();
				if (response && response.success) {
					saveOption(jsonContent);
					showToast(response.data || "Saved", "success");
					setStatus("Saved", "ok");
				} else {
					showToast((response && response.data) || "Error saving file", "error");
					setStatus("Save failed", "error");
				}
			},
			error: function (xhr, status, error) {
				$("#saving-backdrop").hide();
				showToast(error || "Network error", "error");
				setStatus("Save failed", "error");
			},
		});
	}

	function saveOption(json) {
		if (!json) return;
		$.ajax({
			url: cfg.ajax_url,
			method: "POST",
			data: {
				action: "save_json_option",
				json_content: json,
				page: "leadbox-settings-genius",
				nonce: cfg.nonce,
			},
		});
	}

	/* ---------- format ---------- */
	function formatJson() {
		if (state.mode === "monaco" && state.editor) {
			var action = state.editor.getAction("editor.action.formatDocument");
			if (action) {
				action.run();
				return;
			}
		}
		var content = getValue();
		try {
			setValue(JSON.stringify(JSON.parse(content), null, 4));
		} catch (e) {
			openModal("Invalid JSON format. Please fix the JSON syntax.");
		}
	}

	/* ---------- jump to a top-level key in the editor ---------- */
	function jumpToKey(key) {
		if (state.mode !== "monaco" || !state.editor || !window.monaco) return;
		var model = state.editor.getModel();
		if (!model) return;
		var matches = model.findMatches('"' + key + '"', true, false, true, null, false);
		if (!matches || !matches.length) return;
		// Prefer the least-indented match that begins a key (the top-level one).
		var target = null;
		var bestIndent = Infinity;
		for (var i = 0; i < matches.length; i++) {
			var line = model.getLineContent(matches[i].range.startLineNumber);
			var trimmed = line.replace(/^\s+/, "");
			if (trimmed.indexOf('"' + key + '"') !== 0) continue;
			var indent = line.length - trimmed.length;
			if (indent < bestIndent) {
				bestIndent = indent;
				target = matches[i];
			}
		}
		if (!target) target = matches[0];
		state.editor.revealLineInCenter(target.range.startLineNumber);
		state.editor.setSelection(target.range);
		state.editor.focus();
	}

	/* ---------- patch a component version directly into the JSON ---------- */
	function patchVersion(key, version) {
		var obj;
		try {
			obj = JSON.parse(getValue());
		} catch (e) {
			showToast("Fix JSON syntax before changing versions.", "error");
			return;
		}
		var num = parseInt(version, 10);
		if (isNaN(num)) return;

		if (!obj[key] || typeof obj[key] !== "object" || Array.isArray(obj[key])) {
			obj[key] = { version: num, data: {} };
		} else {
			obj[key].version = num;
		}
		setValue(JSON.stringify(obj, null, 4));

		for (var i = 0; i < state.components.length; i++) {
			var c = state.components[i];
			if (c.key === key) {
				c.current = num;
				c.missingInJson = false;
				break;
			}
		}
		updateCounts();
		renderList();
		jumpToKey(key);
		showToast(key + " set to v" + num + " — remember to Save", "info");
	}

	/* ---------- sidebar render ---------- */
	function matchesFilter(c) {
		if (state.filter === "custom") return !!c.custom;
		if (state.filter === "missing") return !!c.missingInJson;
		return true;
	}
	function matchesSearch(c) {
		if (!state.search) return true;
		return (
			c.label.toLowerCase().indexOf(state.search) !== -1 ||
			c.key.toLowerCase().indexOf(state.search) !== -1
		);
	}

	function updateCounts() {
		var all = state.components.length;
		var custom = 0;
		var missing = 0;
		state.components.forEach(function (c) {
			if (c.custom) custom++;
			if (c.missingInJson) missing++;
		});
		$('.genius-count[data-count="all"]').text(all);
		$('.genius-count[data-count="custom"]').text(custom);
		$('.genius-count[data-count="missing"]').text(missing);
	}

	function renderList() {
		var visible = state.components.filter(function (c) {
			return matchesFilter(c) && matchesSearch(c);
		});
		if (!visible.length) {
			$list.html('<p class="genius-empty">No components match.</p>');
			return;
		}
		var html = visible
			.map(function (c) {
				var badges = "";
				if (c.custom) badges += '<span class="genius-badge custom">Custom</span>';
				if (c.missingInJson) badges += '<span class="genius-badge missing">Not in JSON</span>';

				var count = c.available.length;
				var curTxt = c.missingInJson ? "Not set" : "Using v" + c.current;
				var countTxt = count + (count === 1 ? " version" : " versions");

				var opts = c.available
					.map(function (v) {
						var sel = !c.missingInJson && v === c.current ? " selected" : "";
						return '<option value="' + v + '"' + sel + ">v" + v + "</option>";
					})
					.join("");
				if (c.missingInJson) {
					opts = '<option value="" selected>&mdash;</option>' + opts;
				}

				return (
					'<div class="genius-card" data-key="' + esc(c.key) + '">' +
					'<div class="genius-card-main">' +
					'<div class="genius-card-name" title="' + esc(c.key) + '">' + esc(c.label) + "</div>" +
					'<div class="genius-card-ver">' +
					'<span class="using">' + curTxt + "</span>" +
					'<span class="dot">&middot;</span>' +
					'<span class="count">' + countTxt + "</span>" +
					"</div>" +
					"</div>" +
					'<div class="genius-card-right">' +
					'<div class="genius-badges">' + badges + "</div>" +
					'<select class="genius-version-select" data-key="' + esc(c.key) + '">' + opts + "</select>" +
					"</div>" +
					"</div>"
				);
			})
			.join("");
		$list.html(html);
	}

	/* delegated sidebar events */
	$list.on("click", ".genius-card", function (event) {
		if ($(event.target).closest(".genius-version-select").length) return;
		jumpToKey($(this).data("key"));
	});
	$list.on("click", ".genius-version-select", function (event) {
		event.stopPropagation();
	});
	$list.on("change", ".genius-version-select", function (event) {
		event.stopPropagation();
		var val = $(this).val();
		if (val === "") return;
		patchVersion($(this).data("key"), val);
	});

	/* search + filter chips */
	$("#searchInput").on("input", function () {
		state.search = this.value.toLowerCase();
		renderList();
	});
	$(".genius-chip").on("click", function () {
		$(".genius-chip").removeClass("is-active");
		$(this).addClass("is-active");
		state.filter = $(this).data("filter");
		renderList();
	});

	/* buttons + shortcut */
	$("#save-json").on("click", saveJson);
	$("#format-json").on("click", formatJson);
	document.addEventListener("keydown", function (event) {
		if ((event.key === "s" || event.key === "S") && (event.ctrlKey || event.metaKey)) {
			event.preventDefault();
			saveJson();
		}
	});

	/* ---------- data loading ---------- */
	function loadComponents(done) {
		$.ajax({
			url: cfg.ajax_url,
			method: "POST",
			data: { action: cfg.components_action || "get_genius_components", nonce: cfg.nonce },
			success: function (response) {
				if (response && response.success && response.data) {
					state.components = response.data.components || [];
					state.schema = response.data.schema || null;
					updateCounts();
					renderList();
				} else {
					$list.html('<p class="genius-empty">Could not load components.</p>');
				}
				if (done) done();
			},
			error: function () {
				$list.html('<p class="genius-empty">Could not load components.</p>');
				if (done) done();
			},
		});
	}

	function loadJsonContent() {
		var jsonUrl = cfg.json_file_url + "?t=" + new Date().getTime();
		$.get(jsonUrl, function (data) {
			var text = typeof data === "string" ? data : JSON.stringify(data, null, 4);
			try {
				text = JSON.stringify(JSON.parse(text), null, 4);
			} catch (e) {
				/* leave raw if not valid JSON */
			}
			setValue(text);
			$ta.val(getValue());

			if (state.mode === "monaco" && state.editor) {
				setTimeout(function () {
					// Keep the root expanded, fold its children to one line each.
					state.editor.setPosition({ lineNumber: 1, column: 1 });
					var fold = state.editor.getAction("editor.foldLevel1");
					if (fold) fold.run();
					state.editor.revealLine(1);
				}, 300);
			}
		}).fail(function () {
			showToast("Error loading JSON file", "error");
			setStatus("Could not load genius.json", "error");
		});
	}

	function applySchema() {
		if (!window.monaco || !state.schema) return;
		try {
			monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
				validate: true,
				allowComments: false,
				enableSchemaRequest: false,
				schemas: [
					{
						uri: "inmemory://leadbox/genius-schema.json",
						fileMatch: ["*"],
						schema: state.schema,
					},
				],
			});
		} catch (e) {
			/* schema is a nice-to-have; never block the editor */
		}
	}

	/* ---------- editors ---------- */
	function initMonaco() {
		try {
			state.editor = monaco.editor.create(document.getElementById("json-editor"), {
				value: "",
				language: "json",
				theme: "vs-dark",
				automaticLayout: true,
				fontSize: 13,
				tabSize: 4,
				insertSpaces: true,
				minimap: { enabled: true },
				scrollBeyondLastLine: false,
				formatOnPaste: true,
				fixedOverflowWidgets: true,
			});
			state.mode = "monaco";
		} catch (e) {
			console.error("Monaco init failed, using fallback editor", e);
			initFallback();
			return;
		}
		loadComponents(function () {
			applySchema();
			loadJsonContent();
		});
	}

	function initFallback() {
		state.mode = "fallback";
		var $editor = $("#json-editor");
		$editor.addClass("genius-fallback").empty();
		state._fallbackArea = $('<textarea class="genius-fallback-area" spellcheck="false"></textarea>');
		$editor.append(state._fallbackArea);
		loadComponents(function () {
			loadJsonContent();
		});
	}

	/* ---------- bootstrap ----------
	 * Monaco's AMD globals were stashed away (in PHP) right after loader.js so
	 * they don't clobber WordPress's underscore/backbone. We borrow them only
	 * for the duration of the load, then put the page's globals back. */
	function loadMonaco() {
		var amd = window.__leadboxMonacoAMD;
		if (!amd || typeof amd.require === "undefined" || !vsPath) {
			initFallback();
			return;
		}

		// Hand Monaco back its AMD globals. We KEEP them in place on success:
		// Monaco lazily loads language modes (jsonMode → syntax colors) and worker
		// glue via define/require AFTER the editor is created, so removing them too
		// early breaks coloring/validation. WordPress's UMD libs (underscore,
		// backbone) already ran during page parse while these globals were
		// neutralized, so keeping Monaco's loader now no longer affects them.
		// Only on failure do we neutralize again, to leave the page clean.
		var neutralRequire = window.require; // undefined (set by the inline shim)
		var neutralDefine = window.define; // undefined
		window.require = amd.require;
		window.define = amd.define;
		function neutralize() {
			window.require = neutralRequire;
			window.define = neutralDefine;
		}

		try {
			window.MonacoEnvironment = {
				getWorkerUrl: function () {
					return (
						"data:text/javascript;charset=utf-8," +
						encodeURIComponent(
							"self.MonacoEnvironment = { baseUrl: '" + baseUrl + "' };\n" +
								"importScripts('" + vsPath + "/base/worker/workerMain.js');"
						)
					);
				},
			};
			window.require.config({ paths: { vs: vsPath } });
			window.require(
				["vs/editor/editor.main"],
				function () {
					initMonaco();
				},
				function (err) {
					neutralize();
					console.error("Failed to load Monaco, using fallback editor", err);
					initFallback();
				}
			);
		} catch (e) {
			neutralize();
			console.error(e);
			initFallback();
		}
	}

	loadMonaco();
});