- #47510: Show JavaScript alert when PHP errors occur

4.7.x
Steven Wittens 2006-02-05 19:04:58 +00:00
parent afde65151c
commit d38429248e
8 changed files with 131 additions and 45 deletions

View File

@ -1171,6 +1171,8 @@ function drupal_call_js($function) {
/** /**
* Converts a PHP variable into its Javascript equivalent. * Converts a PHP variable into its Javascript equivalent.
*
* We use HTML-safe strings, i.e. with <, > and & escaped.
*/ */
function drupal_to_js($var) { function drupal_to_js($var) {
switch (gettype($var)) { switch (gettype($var)) {
@ -1180,8 +1182,18 @@ function drupal_to_js($var) {
return $var; return $var;
case 'resource': case 'resource':
case 'string': case 'string':
return '"'. str_replace(array("\r", "\n"), array('\r', '\n'), addslashes($var)) .'"'; return '"'. str_replace(array("\r", "\n", "<", ">", "&"),
array('\r', '\n', '\x3c', '\x3e', '\x26'),
addslashes($var)) .'"';
case 'array': case 'array':
if (array_keys($var) === range(0, sizeof($var) - 1)) {
$output = array();
foreach($var as $v) {
$output[] = drupal_to_js($v);
}
return '[ '. implode(', ', $output) .' ]';
}
// Fall through
case 'object': case 'object':
$output = array(); $output = array();
foreach ($var as $k => $v) { foreach ($var as $k => $v) {

View File

@ -113,24 +113,8 @@ function HTTPPost(uri, callbackFunction, callbackParameter, object) {
* window.parent.iframeHandler() after submission. * window.parent.iframeHandler() after submission.
*/ */
function redirectFormButton(uri, button, handler) { function redirectFormButton(uri, button, handler) {
// Insert the iframe // Make sure we have an iframe to target
// Note: some browsers require the literal name/id attributes on the tag, createIframe();
// some want them set through JS. We do both.
var div = document.createElement('div');
div.innerHTML = '<iframe name="redirect-target" id="redirect-target" class="redirect"></iframe>';
var iframe = div.firstChild;
with (iframe) {
name = 'redirect-target';
setAttribute('name', 'redirect-target');
id = 'redirect-target';
}
with (iframe.style) {
position = 'absolute';
height = '1px';
width = '1px';
visibility = 'hidden';
}
document.body.appendChild(iframe);
// Trap the button // Trap the button
button.onmouseover = button.onfocus = function() { button.onmouseover = button.onfocus = function() {
@ -147,11 +131,34 @@ function redirectFormButton(uri, button, handler) {
handler.onsubmit(); handler.onsubmit();
// Set iframe handler for later // Set iframe handler for later
window.iframeHandler = function (data) { window.iframeHandler = function () {
var iframe = $('redirect-target');
// Restore form submission // Restore form submission
button.form.action = action; button.form.action = action;
button.form.target = target; button.form.target = target;
handler.oncomplete(data);
// Get response from iframe body
try {
response = (iframe.contentWindow || iframe.contentDocument || iframe).document.body.innerHTML;
if (window.opera) {
// Opera-hack: it returns innerHTML sanitized.
response = response.replace(/&quot;/g, '"');
}
}
catch (e) {
response = null;
}
// Recreate the iframe: re-using an old iframe can sometimes cause browser bugs.
createIframe();
response = parseJson(response);
// Check response code
if (response.status == 0) {
handler.onerror(response.data);
return;
}
handler.oncomplete(response.data);
} }
return true; return true;
@ -300,6 +307,55 @@ function stopEvent(event) {
} }
} }
/**
* Parse a JSON response.
*
* The result is either the JSON object, or an object with 'status' 0 and 'data' an error message.
*/
function parseJson(data) {
if (data.substring(0,1) != '{') {
return { status: 0, data: data.length ? data : 'Unspecified error' };
}
return eval('(' + data + ');');
}
/**
* Create an invisible iframe for form submissions.
*/
function createIframe() {
// Delete any previous iframe
deleteIframe();
// Note: some browsers require the literal name/id attributes on the tag,
// some want them set through JS. We do both.
window.iframeHandler = function () {};
var div = document.createElement('div');
div.id = 'redirect-holder';
div.innerHTML = '<iframe name="redirect-target" id="redirect-target" class="redirect" onload="window.iframeHandler();"></iframe>';
var iframe = div.firstChild;
with (iframe) {
name = 'redirect-target';
setAttribute('name', 'redirect-target');
id = 'redirect-target';
}
with (iframe.style) {
position = 'absolute';
height = '1px';
width = '1px';
visibility = 'hidden';
}
document.body.appendChild(div);
}
/**
* Delete the invisible iframe for form submissions.
*/
function deleteIframe() {
var holder = $('redirect-holder');
if (typeof holder != 'undefined') {
removeNode(holder);
}
}
/** /**
* Wrapper around document.getElementById(). * Wrapper around document.getElementById().
*/ */

View File

@ -3,7 +3,7 @@
* the DOM afterwards through progressBar.element. * the DOM afterwards through progressBar.element.
* *
* method is the function which will perform the HTTP request to get the * method is the function which will perform the HTTP request to get the
* progress bar status. Either HTTPGet or HTTPPost. * progress bar state. Either HTTPGet or HTTPPost.
* *
* e.g. pb = new progressBar('myProgressBar'); * e.g. pb = new progressBar('myProgressBar');
* some_element.appendChild(pb.element); * some_element.appendChild(pb.element);
@ -18,14 +18,14 @@ function progressBar(id, callback, method) {
this.element.id = id; this.element.id = id;
this.element.className = 'progress'; this.element.className = 'progress';
this.element.innerHTML = '<div class="percentage"></div>'+ this.element.innerHTML = '<div class="percentage"></div>'+
'<div class="status">&nbsp;</div>'+ '<div class="message">&nbsp;</div>'+
'<div class="bar"><div class="filled"></div></div>'; '<div class="bar"><div class="filled"></div></div>';
} }
/** /**
* Set the percentage and status message for the progressbar. * Set the percentage and status message for the progressbar.
*/ */
progressBar.prototype.setProgress = function (percentage, status) { progressBar.prototype.setProgress = function (percentage, message) {
var divs = this.element.getElementsByTagName('div'); var divs = this.element.getElementsByTagName('div');
var div; var div;
for (var i = 0; div = divs[i]; ++i) { for (var i = 0; div = divs[i]; ++i) {
@ -37,12 +37,12 @@ progressBar.prototype.setProgress = function (percentage, status) {
divs[i].innerHTML = percentage + '%'; divs[i].innerHTML = percentage + '%';
} }
} }
if (hasClass(divs[i], 'status')) { if (hasClass(divs[i], 'message')) {
divs[i].innerHTML = status; divs[i].innerHTML = message;
} }
} }
if (this.callback) { if (this.callback) {
this.callback(percentage, status, this); this.callback(percentage, message, this);
} }
} }
@ -84,12 +84,16 @@ progressBar.prototype.receivePing = function (string, xmlhttp, pb) {
if (xmlhttp.status != 200) { if (xmlhttp.status != 200) {
return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri); return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
} }
// Split into values // Parse response
var matches = string.length > 0 ? string.split('|') : []; var progress = parseJson(string);
// Update progress // Display errors
if (matches.length >= 2) { if (progress.status == 0) {
pb.setProgress(matches[0], matches[1]); alert(progress.data);
return;
} }
// Update display
pb.setProgress(progress.percentage, progress.message);
// Schedule next timer // Schedule next timer
pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay); pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
} }

View File

@ -13,7 +13,7 @@ if (isJsEnabled()) {
} }
var progress = new progressBar('updateprogress', updateCallback, HTTPPost); var progress = new progressBar('updateprogress', updateCallback, HTTPPost);
progress.setProgress(-1, 'Starting updates...'); progress.setProgress(-1, 'Starting updates');
$('progress').appendChild(progress.element); $('progress').appendChild(progress.element);
progress.startMonitoring('update.php?op=do_update', 0); progress.startMonitoring('update.php?op=do_update', 0);
} }

View File

@ -54,9 +54,22 @@ jsUpload.prototype.onsubmit = function () {
*/ */
jsUpload.prototype.oncomplete = function (data) { jsUpload.prototype.oncomplete = function (data) {
// Remove progressbar // Remove progressbar
removeNode(this.progress); removeNode(this.progress.element);
this.progress = null; this.progress = null;
// Replace form and re-attach behaviour // Replace form and re-attach behaviour
$(this.wrapper).innerHTML = data; $(this.wrapper).innerHTML = data;
uploadAutoAttach(); uploadAutoAttach();
} }
/**
* Handler for the form redirection error.
*/
jsUpload.prototype.onerror = function (error) {
alert('An error occurred:\n\n'+ error);
// Remove progressbar
removeNode(this.progress.element);
this.progress = null;
// Undo hide
$(this.hide).style.position = 'static';
$(this.hide).style.left = '0px';
}

View File

@ -543,6 +543,6 @@ function upload_js() {
$output = theme('status_messages') . form_render($form); $output = theme('status_messages') . form_render($form);
// We send the updated file attachments form. // We send the updated file attachments form.
print drupal_call_js('window.parent.iframeHandler', $output); print drupal_to_js(array('status' => TRUE, 'data' => $output));
exit; exit;
} }

View File

@ -543,6 +543,6 @@ function upload_js() {
$output = theme('status_messages') . form_render($form); $output = theme('status_messages') . form_render($form);
// We send the updated file attachments form. // We send the updated file attachments form.
print drupal_call_js('window.parent.iframeHandler', $output); print drupal_to_js(array('status' => TRUE, 'data' => $output));
exit; exit;
} }

View File

@ -396,7 +396,7 @@ function update_progress_page() {
* *
* @return * @return
* An array indicating the status after doing updates. The first element is * An array indicating the status after doing updates. The first element is
* the overall percent finished. The second element is a status message. * the overall percentage finished. The second element is a status message.
*/ */
function update_do_updates() { function update_do_updates() {
while (($update = reset($_SESSION['update_remaining']))) { while (($update = reset($_SESSION['update_remaining']))) {
@ -412,12 +412,12 @@ function update_do_updates() {
} }
if ($_SESSION['update_total']) { if ($_SESSION['update_total']) {
$percent = floor(($_SESSION['update_total'] - count($_SESSION['update_remaining']) + $update_finished) / $_SESSION['update_total'] * 100); $percentage = floor(($_SESSION['update_total'] - count($_SESSION['update_remaining']) + $update_finished) / $_SESSION['update_total'] * 100);
} }
else { else {
$percent = 100; $percentage = 100;
} }
return array($percent, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete'); return array($percentage, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete');
} }
function update_do_update_page() { function update_do_update_page() {
@ -437,26 +437,27 @@ function update_do_update_page() {
} }
ini_set('display_errors', FALSE); ini_set('display_errors', FALSE);
print implode('|', update_do_updates()); list($percentage, $message) = update_do_updates();
print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
} }
function update_progress_page_nojs() { function update_progress_page_nojs() {
$new_op = 'do_update_nojs'; $new_op = 'do_update_nojs';
if ($_SERVER['REQUEST_METHOD'] == 'GET') { if ($_SERVER['REQUEST_METHOD'] == 'GET') {
list($percent, $message) = update_do_updates(); list($percentage, $message) = update_do_updates();
if ($percent == 100) { if ($percentage == 100) {
$new_op = 'finished'; $new_op = 'finished';
} }
} }
else { else {
// This is the first page so return some output immediately. // This is the first page so return some output immediately.
$percent = 0; $percentage = 0;
$message = 'Starting updates'; $message = 'Starting updates';
} }
drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=update.php?op='. $new_op .'">'); drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=update.php?op='. $new_op .'">');
drupal_set_title('Updating'); drupal_set_title('Updating');
$output = theme('progress_bar', $percent, $message); $output = theme('progress_bar', $percentage, $message);
$output .= '<p>Updating your site will take a few seconds.</p>'; $output .= '<p>Updating your site will take a few seconds.</p>';
return $output; return $output;