/** * @package Joomla.Component.Builder * * @created 30th April, 2015 * @author Llewellyn van der Merwe * @git Joomla Component Builder * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE.txt */ // Initial Script document.addEventListener('DOMContentLoaded', function() { var add_php_view_vvvvvzg = jQuery("#jform_add_php_view input[type='radio']:checked").val(); vvvvvzg(add_php_view_vvvvvzg); }); // the vvvvvzg function function vvvvvzg(add_php_view_vvvvvzg) { // set the function logic if (add_php_view_vvvvvzg == 1) { jQuery('#jform_php_view-lbl').closest('.control-group').show(); } else { jQuery('#jform_php_view-lbl').closest('.control-group').hide(); } } // the isSet function function isSet(val) { if ((val != undefined) && (val != null) && 0 !== val.length){ return true; } return false; } document.addEventListener("DOMContentLoaded", function() { // check and load all the custom code edit buttons getEditCustomCodeButtons(); }); /** * Fetch data from the server with validated parameters. * * @param {number|string} id The record ID (integer > 0 or string > 30 chars) * @param {string} type The type value to send * @param {string} typeName The type parameter name (e.g. "type" or "context") * @param {string} callingName The AJAX task name (e.g. "getCode") * @global {string} token The CSRF token name or key * @global {string} vastDevMod The developer key or mode flag (optional) * * @return {Promise} Returns parsed JSON data or null on failure * @since 3.1.2 */ async function getCodeFrom_server(id, type, typeName, callingName) { try { // --- Validation --- if (!getCodeFrom_isValidId(id)) { console.debug('[getCodeFrom_server] Invalid ID provided:', id); return null; } if (typeof type !== 'string' || !type.trim()) { console.debug('[getCodeFrom_server] Invalid type provided:', type); return null; } if (typeof typeName !== 'string' || !typeName.trim()) { console.debug('[getCodeFrom_server] Invalid typeName provided:', typeName); return null; } if (typeof callingName !== 'string' || !callingName.trim()) { console.debug('[getCodeFrom_server] Invalid callingName provided:', callingName); return null; } if (typeof token !== 'string' || !token.trim()) { console.debug('[getCodeFrom_server] Missing security token.'); return null; } // --- Construct URL safely --- const baseUrl = 'index.php'; const params = new URLSearchParams({ option: 'com_componentbuilder', task: `ajax.${callingName}`, format: 'json', raw: 'true', [token]: '1', [typeName]: type, id: id }); if (vastDevMod) params.append('vdm', vastDevMod); const fullUrl = JRouter(`${baseUrl}?${params.toString()}`); // --- Execute request --- const response = await fetch(fullUrl, { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, cache: 'no-store', credentials: 'same-origin' }); // --- Validate HTTP response --- if (!response.ok) { console.error(`[getCodeFromServer] Server responded with status ${response.status}: ${response.statusText}`); return null; } // --- Parse JSON response --- const data = await response.json(); return data ?? null; } catch (error) { console.error('[getCodeFromServer] Fetch operation failed:', error); return null; } } /** * Validate if the given ID is acceptable. * * @param {number|string} id The ID value to validate. * @return {boolean} True if valid, false otherwise. * @since 3.1.2 */ function getCodeFrom_isValidId(id) { if (typeof id === 'number') { return Number.isInteger(id) && id > 0; } if (typeof id === 'string') { return id.trim().length > 30; } return false; } /** * Retrieve the Edit Custom Code buttons from the server. * * @param {number} id The record ID to load custom code buttons for. * * @return {Promise} Returns JSON object of buttons or null on failure. * @since 3.1.3 */ async function getEditCustomCodeButtons_server(id) { try { // --- Validation --- if (typeof token !== 'string' || !token.trim()) { console.error('[getEditCustomCodeButtons_server] Missing or invalid CSRF token.'); return null; } if (typeof id !== 'number' || id <= 0) { console.error('[getEditCustomCodeButtons_server] Invalid ID provided:', id); return null; } if (typeof return_here !== 'string' || !return_here.trim()) { console.warn('[getEditCustomCodeButtons_server] "return_here" not set; continuing without it.'); } // --- Build URL safely --- const baseUrl = 'index.php'; const params = new URLSearchParams({ option: 'com_componentbuilder', task: 'ajax.getEditCustomCodeButtons', format: 'json', raw: 'true', [token]: '1', id: id, return_here: return_here || '' }); if (typeof vastDevMod === 'string' && vastDevMod.length > 0) { params.append('vdm', vastDevMod); } const urlWithParams = JRouter(`${baseUrl}?${params.toString()}`); // --- Execute request --- const response = await fetch(urlWithParams, { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, cache: 'no-store', credentials: 'same-origin' }); // --- Handle network errors --- if (!response.ok) { console.error(`[getEditCustomCodeButtons_server] HTTP ${response.status}: ${response.statusText}`); return null; } // --- Parse JSON result --- const data = await response.json(); return data ?? null; } catch (error) { console.error('[getEditCustomCodeButtons_server] Fetch failed:', error); return null; } } /** * Load and inject Edit Custom Code buttons into the DOM. * * @return {Promise} * @since 3.1.3 */ async function getEditCustomCodeButtons() { try { // --- Get record ID from the form --- const idField = document.querySelector('#jform_id'); if (!idField) { console.error('[getEditCustomCodeButtons] #jform_id not found.'); return; } const idValue = parseInt(idField.value, 10); if (isNaN(idValue) || idValue <= 0) { console.warn('[getEditCustomCodeButtons] Invalid or empty ID; skipping button load.'); return; } // --- Request data from server --- const result = await getEditCustomCodeButtons_server(idValue); if (!result || typeof result !== 'object') { console.warn('[getEditCustomCodeButtons] No result returned or invalid format.'); return; } // --- Inject returned button groups --- Object.entries(result).forEach(([field, buttons]) => { // Create the container div const div = document.createElement('div'); div.className = 'control-group'; div.innerHTML = `
`; // Find where to insert (before .control-wrapper-{field}) const insertBeforeElement = document.querySelector(`.control-wrapper-${field}`); if (insertBeforeElement && insertBeforeElement.parentNode) { insertBeforeElement.parentNode.insertBefore(div, insertBeforeElement); } // Append buttons to the new container const controlsDiv = div.querySelector(`.control-customcode-buttons-${field}`); if (controlsDiv && typeof buttons === 'object') { Object.entries(buttons).forEach(([name, buttonHtml]) => { if (typeof buttonHtml === 'string') { const wrapper = document.createElement('div'); wrapper.innerHTML = buttonHtml.trim(); const buttonNode = wrapper.firstElementChild; if (buttonNode) { controlsDiv.appendChild(buttonNode); } } }); } }); } catch (error) { console.error('[getEditCustomCodeButtons] Error rendering buttons:', error); } } function getSnippetDetails(id){ getCodeFrom_server(id, '_type', '_type', 'snippetDetails').then(function(result) { if(result.snippet){ var description = ''; if (result.description.length > 0) { description = '

'+result.description+'

'; } var library = ''; if (result.library.length > 0) { library = ' ('+result.library+')'; } var code = '
'+result.name+' ('+result.type+') see more details'+library+'
'+result.heading+'
'; jQuery('#snippet-code').remove(); jQuery('.snippet-code').append(code); // make sure the code block is active jQuery("#snippet").focus(function() { var jQuerythis = jQuery(this); jQuerythis.select(); // Work around Chrome's little problem jQuerythis.mouseup(function() { // Prevent further mouseup intervention jQuerythis.unbind("mouseup"); return false; }); }); } if(result.usage){ var usage = '

'+result.usage+'

'; jQuery('#snippet-usage').remove(); jQuery('.snippet-usage').append(usage); } }) } function getDynamicValuesServer(dynamicId) { var getUrl = 'index.php?option=com_componentbuilder&task=ajax.getDynamicValues&raw=true&format=json'; if (token.length > 0 && (dynamicId > 0 || dynamicId.length > 0)) { var request = token + '=1&view=template&id=' + dynamicId; } return fetch(getUrl + '&' + request, { method: 'GET', headers: { 'Content-Type': 'application/json', } }) .then(response => response.json()); } function getDynamicValues(id) { getDynamicValuesServer(id).then(function(result) { if (result) { var dynamicValuesElement = document.getElementById('dynamic_values'); if (dynamicValuesElement) { dynamicValuesElement.remove(); } document.querySelector('.dynamic_values').insertAdjacentHTML('beforeend', '
' + result + '
'); // Event listener for code blocks document.querySelectorAll("code").forEach(function(codeBlock) { codeBlock.addEventListener("click", function() { codeBlock.selText(); // Call the custom selText function codeBlock.classList.add("selected"); // Add the "selected" class }); }); } }).catch(function(error) { console.error('Error fetching dynamic values:', error); }); } function getLayoutDetails_server(id) { var getUrl = JRouter("index.php?option=com_componentbuilder&task=ajax.getLayoutDetails&format=json&raw=true&vdm=" + vastDevMod); var request = ''; // Ensure token and id are present if (token.length > 0 && id > 0) { request = token + '=1&id=' + id; } // Return a fetch promise (fetch does not support JSONP, so I assume the server can return JSON) return fetch(getUrl + '&' + request, { method: 'GET' }) .then(function(response) { if (!response.ok) { throw new Error("Network response was not ok"); } return response.json(); // Assuming the server returns JSON }); } function getLayoutDetails(id) { getLayoutDetails_server(id) .then(function(result) { if (result) { document.querySelector('#details').insertAdjacentHTML('beforeend', result); // Re-enable code block text selection functionality document.querySelectorAll("code").forEach(function(codeBlock) { codeBlock.addEventListener("click", function() { codeBlock.selText(); codeBlock.classList.add("selected"); }); }); } }) .catch(function(error) { console.error('There was a problem with the fetch operation:', error); }); } function getTemplateDetails(id) { getCodeFrom_server(id, 'type', 'type', 'templateDetails').then(function(result) { if (result) { document.querySelector('#details').insertAdjacentHTML('beforeend', result); // Re-enable code block text selection functionality document.querySelectorAll("code").forEach(function(codeBlock) { codeBlock.addEventListener("click", function() { codeBlock.selText(); codeBlock.classList.add("selected"); }); }); } }); } // set snippets that are on the page var snippetIds = []; var snippets = {}; var snippet = 0; jQuery(document).ready(function($) { jQuery("#jform_snippet option").each(function() { var key = jQuery(this).val(); var text = jQuery(this).text(); snippets[key] = text; snippetIds.push(key); }); snippet = jQuery("#jform_snippet").val(); getSnippets(); }); function getSnippets(){ jQuery("#loading").show(); // clear the selection jQuery('#jform_snippet').find('option').remove().end(); jQuery('#jform_snippet').trigger('liszt:updated'); // get libraries value if set var libraries = jQuery("#jform_libraries").val(); if (libraries) { getCodeFrom_server(1, JSON.stringify(libraries), 'libraries', 'getSnippets').then(function(result) { setSnippets(result); jQuery("#loading").hide(); if (typeof snippetButton !== 'undefined') { // ensure button is correct var snippet = jQuery('#jform_snippet').val(); snippetButton(snippet); } }); } else { // load all snippets in none is selected setSnippets(snippetIds); jQuery("#loading").hide(); } } function setSnippets(array){ if (array) { jQuery('#jform_snippet').append(''); jQuery.each( array, function( i, id ) { if (id in snippets) { jQuery('#jform_snippet').append(''); } if (id == snippet) { jQuery('#jform_snippet').val(id); } }); } else { jQuery('#jform_snippet').append(''); } jQuery('#jform_snippet').trigger('liszt:updated'); }