[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 (function () { 2 'use strict'; 3 4 /** 5 * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> 6 * @license GNU General Public License version 2 or later; see LICENSE.txt 7 */ 8 Joomla = window.Joomla || {}; 9 10 (function (Joomla, document) { 11 Joomla.submitbuttonUpload = function () { 12 var form = document.getElementById('uploadForm'); 13 var confirmBackup = document.getElementById('joomlaupdate-confirm-backup'); // do field validation 14 15 if (form.install_package.value === '') { 16 alert(Joomla.Text._('COM_INSTALLER_MSG_INSTALL_PLEASE_SELECT_A_PACKAGE'), true); 17 } else if (form.install_package.files[0].size > form.max_upload_size.value) { 18 alert(Joomla.Text._('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG'), true); 19 } else if (confirmBackup && confirmBackup.checked) { 20 form.submit(); 21 } 22 }; 23 24 Joomla.installpackageChange = function () { 25 var form = document.getElementById('uploadForm'); 26 var fileSize = form.install_package.files[0].size; 27 var fileSizeMB = fileSize * 1.0 / 1024.0 / 1024.0; 28 var fileSizeElement = document.getElementById('file_size'); 29 var warningElement = document.getElementById('max_upload_size_warn'); 30 31 if (form.install_package.value === '') { 32 fileSizeElement.classList.add('hidden'); 33 warningElement.classList.add('hidden'); 34 } else if (fileSize) { 35 fileSizeElement.classList.remove('hidden'); 36 fileSizeElement.innerHTML = Joomla.sanitizeHtml(Joomla.Text._('JGLOBAL_SELECTED_UPLOAD_FILE_SIZE').replace('%s', fileSizeMB.toFixed(2) + " MB")); 37 38 if (fileSize > form.max_upload_size.value) { 39 warningElement.classList.remove('hidden'); 40 } else { 41 warningElement.classList.add('hidden'); 42 } 43 } 44 }; 45 46 document.addEventListener('DOMContentLoaded', function () { 47 var confirmButton = document.getElementById('confirmButton'); 48 var uploadForm = document.getElementById('uploadForm'); 49 var uploadButton = document.getElementById('uploadButton'); 50 var uploadField = document.getElementById('install_package'); 51 var installButton = document.querySelector('.emptystate-btnadd', document.getElementById('joomlaupdate-wrapper')); 52 var updateCheck = document.getElementById('joomlaupdate-confirm-backup'); 53 var form = installButton ? installButton.closest('form') : null; 54 var task = form ? form.querySelector('[name=task]', form) : null; 55 56 if (uploadButton) { 57 uploadButton.addEventListener('click', Joomla.submitbuttonUpload); 58 uploadButton.disabled = updateCheck && !updateCheck.checked; 59 60 if (updateCheck) { 61 updateCheck.addEventListener('change', function () { 62 uploadButton.disabled = !updateCheck.checked; 63 }); 64 } 65 } 66 67 if (confirmButton && updateCheck && !updateCheck.checked) { 68 confirmButton.classList.add('disabled'); 69 } 70 71 if (confirmButton && updateCheck) { 72 updateCheck.addEventListener('change', function () { 73 if (updateCheck.checked) { 74 confirmButton.classList.remove('disabled'); 75 } else { 76 confirmButton.classList.add('disabled'); 77 } 78 }); 79 } 80 81 if (uploadField) { 82 uploadField.addEventListener('change', Joomla.installpackageChange); 83 84 if (updateCheck) { 85 uploadField.addEventListener('change', function () { 86 var fileSize = uploadForm.install_package.files[0].size; 87 var allowedSize = uploadForm.max_upload_size.value; 88 89 if (fileSize <= allowedSize && updateCheck.disabled) { 90 updateCheck.disabled = !updateCheck.disabled; 91 } else if (fileSize <= allowedSize && !updateCheck.disabled && !updateCheck.checked) { 92 updateCheck.disabled = false; 93 } else if (fileSize <= allowedSize && updateCheck.checked) { 94 updateCheck.checked = updateCheck.classList.contains('d-none'); 95 uploadButton.disabled = true; 96 } else if (fileSize > allowedSize && !updateCheck.disabled) { 97 updateCheck.disabled = !updateCheck.disabled; 98 updateCheck.checked = updateCheck.classList.contains('d-none'); 99 uploadButton.disabled = true; 100 } 101 }); 102 } 103 } // Trigger (re-) install (including checkbox confirm if we update) 104 105 106 if (installButton && installButton.getAttribute('href') === '#' && task) { 107 installButton.addEventListener('click', function (e) { 108 e.preventDefault(); 109 110 if (updateCheck && !updateCheck.checked) { 111 return; 112 } 113 114 task.value = 'update.download'; 115 form.submit(); 116 }); 117 } 118 }); 119 })(Joomla, document); 120 121 (function (Joomla, document) { 122 /** 123 * PreUpdateChecker 124 * 125 * @type {Object} 126 */ 127 var PreUpdateChecker = {}; 128 /** 129 * Config object 130 * 131 * @type {{serverUrl: string, selector: string}} 132 */ 133 134 PreUpdateChecker.config = { 135 serverUrl: 'index.php?option=com_joomlaupdate&task=update.fetchextensioncompatibility', 136 batchUrl: 'index.php?option=com_joomlaupdate&task=update.batchextensioncompatibility', 137 selector: '.extension-check' 138 }; 139 /** 140 * Extension compatibility states returned by the server. 141 * 142 * @type {{ 143 * INCOMPATIBLE: number, 144 * COMPATIBLE: number, 145 * MISSING_COMPATIBILITY_TAG: number, 146 * SERVER_ERROR: number}} 147 */ 148 149 PreUpdateChecker.STATE = { 150 INCOMPATIBLE: 0, 151 COMPATIBLE: 1, 152 MISSING_COMPATIBILITY_TAG: 2, 153 SERVER_ERROR: 3 154 }; 155 156 PreUpdateChecker.cleanup = function (status) { 157 // Set the icon in the nav-tab 158 var infoIcon = document.querySelector('#joomlaupdate-precheck-extensions-tab .fa-spinner'); 159 var iconColor = 'success'; 160 var iconClass = 'check'; 161 162 switch (status) { 163 case 'danger': 164 iconColor = 'danger'; 165 iconClass = 'times'; 166 break; 167 168 case 'warning': 169 iconColor = 'warning'; 170 iconClass = 'exclamation-triangle'; 171 break; 172 } 173 174 if (infoIcon) { 175 infoIcon.classList.remove('fa-spinner', 'fa-spin'); 176 infoIcon.classList.add("fa-" + iconClass, "text-" + iconColor, 'bg-white'); 177 } // Hide table of addons to load 178 179 180 var checkedExtensions = document.querySelector('#compatibilityTable0'); 181 var preupdateCheckWarning = document.querySelector('#preupdateCheckWarning'); 182 183 if (checkedExtensions) { 184 checkedExtensions.classList.add('hidden'); 185 } 186 187 if (preupdateCheckWarning) { 188 preupdateCheckWarning.classList.add('hidden'); 189 } 190 }; 191 /** 192 * Run the PreUpdateChecker. 193 * Called by document ready, setup below. 194 */ 195 196 197 PreUpdateChecker.run = function () { 198 // eslint-disable-next-line no-undef 199 PreUpdateChecker.nonCoreCriticalPlugins = Joomla.getOptions('nonCoreCriticalPlugins', []); // Grab all extensions based on the selector set in the config object 200 201 var extensions = document.querySelectorAll(PreUpdateChecker.config.selector); // If there are no extensions to be checked we can exit here 202 203 if (extensions.length === 0) { 204 if (document.getElementById('preupdatecheckbox') !== null) { 205 document.getElementById('preupdatecheckbox').style.display = 'none'; 206 } 207 208 if (document.getElementById('noncoreplugins') !== null) { 209 document.getElementById('noncoreplugins').checked = true; 210 } 211 212 [].slice.call(document.querySelectorAll('button.submitupdate')).forEach(function (el) { 213 el.classList.remove('disabled'); 214 el.removeAttribute('disabled'); 215 }); 216 PreUpdateChecker.cleanup(); 217 return; 218 } // Let the user make an update although there *could* be dangerous plugins in the wild 219 220 221 var onChangeEvent = function onChangeEvent() { 222 var nonCorePluginCheckbox = document.getElementById('noncoreplugins'); 223 224 if (nonCorePluginCheckbox.checked) { 225 if (window.confirm(Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_POTENTIALLY_DANGEROUS_PLUGIN_CONFIRM_MESSAGE'))) { 226 [].slice.call(document.querySelectorAll('button.submitupdate')).forEach(function (el) { 227 el.classList.remove('disabled'); 228 el.removeAttribute('disabled'); 229 }); 230 } else { 231 nonCorePluginCheckbox.checked = false; 232 } 233 } else { 234 [].slice.call(document.querySelectorAll('button.submitupdate')).forEach(function (el) { 235 el.classList.add('disabled'); 236 el.setAttribute('disabled', ''); 237 }); 238 } 239 }; 240 241 if (document.getElementById('noncoreplugins') !== null) { 242 document.getElementById('noncoreplugins').addEventListener('change', onChangeEvent); 243 } // Get version of the available joomla update 244 245 246 var joomlaUpdateWrapper = document.getElementById('joomlaupdate-wrapper'); 247 PreUpdateChecker.joomlaTargetVersion = joomlaUpdateWrapper.getAttribute('data-joomla-target-version'); 248 PreUpdateChecker.joomlaCurrentVersion = joomlaUpdateWrapper.getAttribute('data-joomla-current-version'); 249 [].slice.call(document.querySelectorAll('.compatibilitytoggle')).forEach(function (el) { 250 el.addEventListener('click', function () { 251 var compatibilityTable = el.closest('.compatibilityTable'); 252 253 if (el.dataset.state === 'closed') { 254 el.dataset.state = 'open'; 255 el.innerHTML = Joomla.sanitizeHtml(Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_SHOW_LESS_COMPATIBILITY_INFORMATION')); 256 [].slice.call(compatibilityTable.querySelectorAll('table .hidden')).forEach(function (elem) { 257 elem.classList.remove('hidden'); 258 }); 259 } else { 260 el.dataset.state = 'closed'; 261 el.innerHTML = Joomla.sanitizeHtml(Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_SHOW_MORE_COMPATIBILITY_INFORMATION')); 262 [].slice.call(compatibilityTable.querySelectorAll('table .instver, table .upcomp, table .currcomp')).forEach(function (elem) { 263 elem.classList.add('hidden'); 264 }); 265 } 266 }); 267 }); // Grab all extensions based on the selector set in the config object 268 269 var extensionsInformation = []; 270 [].slice.call(extensions).forEach(function (extension) { 271 var thisInfo = { 272 eid: extension.getAttribute('data-extension-id'), 273 version: extension.getAttribute('data-extension-current-version') 274 }; 275 extensionsInformation.push(thisInfo); 276 }); 277 PreUpdateChecker.checkNextChunk(extensionsInformation); 278 }; 279 /** 280 * Converts a simple object containing query string parameters to a single, escaped query string 281 * 282 * @param data {object|string} A plain object containing the query parameters to pass 283 * @param prefix {string} Prefix for array-type parameters 284 * 285 * @returns {string} 286 */ 287 288 289 PreUpdateChecker.interpolateParameters = function (data, prefix) { 290 var encodedString = ''; 291 292 if (typeof data !== 'object' || data === null || !data) { 293 return ''; 294 } 295 296 Object.keys(data).forEach(function (prop) { 297 var item = data[prop]; 298 299 if (encodedString.length > 0) { 300 encodedString += '&'; 301 } // Scalar values 302 303 304 if (typeof item === 'object') { 305 var newPrefix = prefix.length ? prefix + "[" + prop + "]" : prop; 306 encodedString += PreUpdateChecker.interpolateParameters(item, newPrefix); 307 return; 308 } 309 310 if (prefix === '') { 311 encodedString += encodeURIComponent(prop) + "=" + encodeURIComponent(item); 312 return; 313 } 314 315 encodedString += encodeURIComponent(prefix) + "[" + encodeURIComponent(prop) + "]=" + encodeURIComponent(item); 316 }); 317 return encodedString; 318 }; 319 /** 320 * Check the compatibility of several extensions. 321 * 322 * Asks the server to check the compatibility of as many extensions as possible. The server 323 * returns these results and the remainder of the extensions not already checked. 324 * 325 * @param {Array} extensionsArray 326 */ 327 328 329 PreUpdateChecker.checkNextChunk = function (extensionsArray) { 330 if (extensionsArray.length === 0) { 331 return; 332 } 333 334 Joomla.request({ 335 url: PreUpdateChecker.config.batchUrl, 336 method: 'POST', 337 data: PreUpdateChecker.interpolateParameters({ 338 'joomla-target-version': PreUpdateChecker.joomlaTargetVersion, 339 'joomla-current-version': PreUpdateChecker.joomlaCurrentVersion, 340 extensions: extensionsArray 341 }, ''), 342 onSuccess: function onSuccess(data) { 343 var response = JSON.parse(data); 344 345 if (response.messages) { 346 Joomla.renderMessages(response.messages); 347 } 348 349 var extensions = response.data.extensions || []; 350 response.data.compatibility.forEach(function (record) { 351 var node = document.getElementById("preUpdateCheck_" + record.id); 352 353 if (!node) { 354 return; 355 } 356 357 PreUpdateChecker.setResultView({ 358 element: node, 359 compatibleVersion: 0, 360 serverError: 0, 361 compatibilityData: record 362 }); 363 }); 364 PreUpdateChecker.checkNextChunk(extensions); 365 }, 366 onError: function onError(xhr) { 367 // Report the XHR error 368 Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr)); // Mark all pending extensions as errored out on the server side 369 370 extensionsArray.forEach(function (info) { 371 var node = document.getElementById("preUpdateCheck_" + info.eid); 372 373 if (!node) { 374 return; 375 } 376 377 PreUpdateChecker.setResultView({ 378 element: node, 379 compatibleVersion: 0, 380 serverError: 1 381 }); 382 }); 383 } 384 }); 385 }; 386 /** 387 * Check the compatibility for a single extension. 388 * Requests the server checking the compatibility based 389 * on the data set in the element's data attributes. 390 * 391 * @param {Object} extension 392 */ 393 394 395 PreUpdateChecker.checkCompatibility = function (node) { 396 // Result object passed to the callback 397 // Set to server error by default 398 var extension = { 399 element: node, 400 compatibleVersion: 0, 401 serverError: 1 402 }; // Request the server to check the compatibility for the passed extension and joomla version 403 404 Joomla.request({ 405 url: PreUpdateChecker.config.serverUrl + "&joomla-target-version=" + encodeURIComponent(PreUpdateChecker.joomlaTargetVersion) + "&joomla-current-version=" + PreUpdateChecker.joomlaCurrentVersion + "&extension-version=" + node.getAttribute('data-extension-current-version') + "&extension-id=" + encodeURIComponent(node.getAttribute('data-extension-id')), 406 onSuccess: function onSuccess(data) { 407 var response = JSON.parse(data); // Extract the data from the JResponseJson object 408 409 extension.serverError = 0; 410 extension.compatibilityData = response.data; // Pass the retrieved data to the callback 411 412 PreUpdateChecker.setResultView(extension); 413 }, 414 onError: function onError() { 415 extension.serverError = 1; // Pass the retrieved data to the callback 416 417 PreUpdateChecker.setResultView(extension); 418 } 419 }); 420 }; 421 /** 422 * Set the result for a passed extensionData object containing state compatible version 423 * 424 * @param {Object} extensionData 425 */ 426 427 428 PreUpdateChecker.setResultView = function (extensionData) { 429 var html = ''; // const direction = (document.dir !== undefined) ? document.dir : document.getElementsByTagName('html')[0].getAttribute('dir'); 430 // Process Target Version Extension Compatibility 431 432 if (extensionData.serverError) { 433 // An error occurred -> show unknown error note 434 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_SERVER_ERROR'); // Force result into group 4 = Pre update checks failed 435 436 extensionData.compatibilityData = { 437 resultGroup: 4 438 }; 439 } else { 440 // Switch the compatibility state 441 switch (extensionData.compatibilityData.upgradeCompatibilityStatus.state) { 442 case PreUpdateChecker.STATE.COMPATIBLE: 443 if (extensionData.compatibilityData.upgradeWarning) { 444 var compatibleVersion = Joomla.sanitizeHtml(extensionData.compatibilityData.upgradeCompatibilityStatus.compatibleVersion); 445 html = "<span class=\"label label-warning\">" + compatibleVersion + "</span>"; // @TODO activate when language strings are correct 446 447 /* if (compatibilitytypes.querySelector('#updateorangewarning')) { 448 compatibilitytypes.querySelector('#updateorangewarning').classList.remove('hidden'); 449 } */ 450 } else { 451 html = extensionData.compatibilityData.upgradeCompatibilityStatus.compatibleVersion === false ? Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION') : Joomla.sanitizeHtml(extensionData.compatibilityData.upgradeCompatibilityStatus.compatibleVersion); 452 } 453 454 break; 455 456 case PreUpdateChecker.STATE.INCOMPATIBLE: 457 // No compatible version found -> display error label 458 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION'); // @TODO activate when language strings are correct 459 460 /* if (document.querySelector('#updateyellowwarning')) { 461 document.querySelector('#updateyellowwarning').classList.remove('hidden'); 462 } */ 463 464 break; 465 466 case PreUpdateChecker.STATE.MISSING_COMPATIBILITY_TAG: 467 // Could not check compatibility state -> display warning 468 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION'); // @TODO activate when language strings are correct 469 470 /* if (document.querySelector('#updateyellowwarning')) { 471 document.querySelector('#updateyellowwarning').classList.remove('hidden'); 472 } */ 473 474 break; 475 476 default: 477 // An error occurred -> show unknown error note 478 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_WARNING_UNKNOWN'); 479 } 480 } // Insert the generated html 481 482 483 extensionData.element.innerHTML = html; // Process Current Version Extension Compatibility 484 485 html = ''; 486 487 if (extensionData.serverError) { 488 // An error occurred -> show unknown error note 489 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_SERVER_ERROR'); 490 } else { 491 // Switch the compatibility state 492 switch (extensionData.compatibilityData.currentCompatibilityStatus.state) { 493 case PreUpdateChecker.STATE.COMPATIBLE: 494 html = extensionData.compatibilityData.currentCompatibilityStatus.compatibleVersion === false ? Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION') : extensionData.compatibilityData.currentCompatibilityStatus.compatibleVersion; 495 break; 496 497 case PreUpdateChecker.STATE.INCOMPATIBLE: 498 // No compatible version found -> display error label 499 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION'); 500 break; 501 502 case PreUpdateChecker.STATE.MISSING_COMPATIBILITY_TAG: 503 // Could not check compatibility state -> display warning 504 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_NO_COMPATIBILITY_INFORMATION'); 505 break; 506 507 default: 508 // An error occurred -> show unknown error note 509 html = Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_WARNING_UNKNOWN'); 510 } 511 } // Insert the generated html 512 513 514 var extensionId = extensionData.element.getAttribute('data-extension-id'); 515 document.getElementById("available-version-" + extensionId).innerText = html; 516 var compatType = document.querySelector("#compatibilityTable" + extensionData.compatibilityData.resultGroup + " tbody"); 517 518 if (compatType) { 519 compatType.appendChild(extensionData.element.closest('tr')); 520 } // Show the table 521 522 523 document.getElementById("compatibilityTable" + extensionData.compatibilityData.resultGroup).classList.remove('hidden'); // Process the nonCoreCriticalPlugin list 524 525 if (extensionData.compatibilityData.resultGroup === 3) { 526 PreUpdateChecker.nonCoreCriticalPlugins = PreUpdateChecker.nonCoreCriticalPlugins // eslint-disable-next-line max-len 527 .filter(function (ext) { 528 return !(ext.package_id.toString() === extensionId || ext.extension_id.toString() === extensionId); 529 }); 530 } // Have we finished? 531 532 533 if (!document.querySelector('#compatibilityTable0 tbody td')) { 534 document.getElementById('compatibilityTable0').classList.add('hidden'); 535 var status = 'success'; 536 PreUpdateChecker.nonCoreCriticalPlugins.forEach(function (plugin) { 537 var problemPluginRow = document.querySelector("td[data-extension-id=\"" + plugin.extension_id + "\"]"); 538 539 if (!problemPluginRow) { 540 problemPluginRow = document.querySelector("td[data-extension-id=\"" + plugin.package_id + "\"]"); 541 } 542 543 if (problemPluginRow) { 544 var tableRow = problemPluginRow.closest('tr'); 545 tableRow.classList.add('error'); 546 var pluginTitleTableCell = tableRow.querySelector('.exname'); 547 pluginTitleTableCell.innerHTML = Joomla.sanitizeHtml(pluginTitleTableCell.innerHTML) + "\n <div class=\"small\">\n <span class=\"badge bg-warning\">\n <span class=\"icon-warning\"></span>\n " + Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_POTENTIALLY_DANGEROUS_PLUGIN') + "\n </span>\n\n <button type=\"button\" class=\"btn btn-sm btn-link hasPopover\"\n title=\"" + Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_POTENTIALLY_DANGEROUS_PLUGIN') + " \"\n data-bs-content=\"" + Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_POTENTIALLY_DANGEROUS_PLUGIN_DESC') + " \"\n >\n " + Joomla.Text._('COM_JOOMLAUPDATE_VIEW_DEFAULT_HELP') + "\n </button>\n </div>"; 548 var popoverElement = pluginTitleTableCell.querySelector('.hasPopover'); 549 550 if (popoverElement) { 551 popoverElement.style.cursor = 'pointer'; // eslint-disable-next-line no-new 552 553 new bootstrap.Popover(popoverElement, { 554 placement: 'top', 555 html: true, 556 trigger: 'focus' 557 }); 558 } 559 560 status = 'danger'; 561 } 562 }); // Updates required 563 564 if (document.querySelector('#compatibilityTable2 tbody td')) { 565 status = 'danger'; 566 } else if (status !== 'danger' && document.querySelector('#compatibilityTable1 tbody td')) { 567 status = 'warning'; 568 } 569 570 if (PreUpdateChecker.nonCoreCriticalPlugins.length === 0 && status === 'success') { 571 document.getElementById('preupdatecheckbox').style.display = 'none'; 572 document.getElementById('noncoreplugins').checked = true; 573 [].slice.call(document.querySelectorAll('button.submitupdate')).forEach(function (el) { 574 el.classList.remove('disabled'); 575 el.removeAttribute('disabled'); 576 }); 577 } else if (PreUpdateChecker.nonCoreCriticalPlugins.length > 0) { 578 document.getElementById('preupdateCheckCompleteProblems').classList.remove('hidden'); 579 } 580 581 PreUpdateChecker.cleanup(status); 582 } 583 }; 584 585 if (document.getElementById('preupdatecheck') !== null) { 586 // Run PreUpdateChecker on document ready 587 document.addEventListener('DOMContentLoaded', PreUpdateChecker.run, false); 588 } 589 })(Joomla, document); 590 591 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |