diff options
author | Steven Wittens <steven@10.no-reply.drupal.org> | 2006-02-05 19:04:58 +0000 |
---|---|---|
committer | Steven Wittens <steven@10.no-reply.drupal.org> | 2006-02-05 19:04:58 +0000 |
commit | d38429248ee2cbaa442e396f251b1781acbc0d66 (patch) | |
tree | fb04fcaf6c118752902bc8d4a18ec763e3d9c4da | |
parent | afde65151c2e3807f8879fd0fe2ecd1cdda9f050 (diff) | |
download | brdo-d38429248ee2cbaa442e396f251b1781acbc0d66.tar.gz brdo-d38429248ee2cbaa442e396f251b1781acbc0d66.tar.bz2 |
- #47510: Show JavaScript alert when PHP errors occur
-rw-r--r-- | includes/common.inc | 14 | ||||
-rw-r--r-- | misc/drupal.js | 96 | ||||
-rw-r--r-- | misc/progress.js | 26 | ||||
-rw-r--r-- | misc/update.js | 2 | ||||
-rw-r--r-- | misc/upload.js | 15 | ||||
-rw-r--r-- | modules/upload.module | 2 | ||||
-rw-r--r-- | modules/upload/upload.module | 2 | ||||
-rw-r--r-- | update.php | 19 |
8 files changed, 131 insertions, 45 deletions
diff --git a/includes/common.inc b/includes/common.inc index 5548ae68b..aead0a2d7 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1171,6 +1171,8 @@ function drupal_call_js($function) { /** * Converts a PHP variable into its Javascript equivalent. + * + * We use HTML-safe strings, i.e. with <, > and & escaped. */ function drupal_to_js($var) { switch (gettype($var)) { @@ -1180,8 +1182,18 @@ function drupal_to_js($var) { return $var; case 'resource': 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': + 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': $output = array(); foreach ($var as $k => $v) { diff --git a/misc/drupal.js b/misc/drupal.js index b962c89f7..d633fa56e 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -113,24 +113,8 @@ function HTTPPost(uri, callbackFunction, callbackParameter, object) { * window.parent.iframeHandler() after submission. */ function redirectFormButton(uri, button, handler) { - // Insert the iframe - // Note: some browsers require the literal name/id attributes on the tag, - // 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); + // Make sure we have an iframe to target + createIframe(); // Trap the button button.onmouseover = button.onfocus = function() { @@ -147,11 +131,34 @@ function redirectFormButton(uri, button, handler) { handler.onsubmit(); // Set iframe handler for later - window.iframeHandler = function (data) { + window.iframeHandler = function () { + var iframe = $('redirect-target'); // Restore form submission button.form.action = action; 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(/"/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; @@ -301,6 +308,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(). */ function $(id) { diff --git a/misc/progress.js b/misc/progress.js index 940c32713..84979d68f 100644 --- a/misc/progress.js +++ b/misc/progress.js @@ -3,7 +3,7 @@ * the DOM afterwards through progressBar.element. * * 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'); * some_element.appendChild(pb.element); @@ -18,14 +18,14 @@ function progressBar(id, callback, method) { this.element.id = id; this.element.className = 'progress'; this.element.innerHTML = '<div class="percentage"></div>'+ - '<div class="status"> </div>'+ + '<div class="message"> </div>'+ '<div class="bar"><div class="filled"></div></div>'; } /** * 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 div; for (var i = 0; div = divs[i]; ++i) { @@ -37,12 +37,12 @@ progressBar.prototype.setProgress = function (percentage, status) { divs[i].innerHTML = percentage + '%'; } } - if (hasClass(divs[i], 'status')) { - divs[i].innerHTML = status; + if (hasClass(divs[i], 'message')) { + divs[i].innerHTML = message; } } 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) { return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri); } - // Split into values - var matches = string.length > 0 ? string.split('|') : []; - // Update progress - if (matches.length >= 2) { - pb.setProgress(matches[0], matches[1]); + // Parse response + var progress = parseJson(string); + // Display errors + if (progress.status == 0) { + alert(progress.data); + return; } + + // Update display + pb.setProgress(progress.percentage, progress.message); // Schedule next timer pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay); } diff --git a/misc/update.js b/misc/update.js index 117713b69..2586fbf50 100644 --- a/misc/update.js +++ b/misc/update.js @@ -13,7 +13,7 @@ if (isJsEnabled()) { } var progress = new progressBar('updateprogress', updateCallback, HTTPPost); - progress.setProgress(-1, 'Starting updates...'); + progress.setProgress(-1, 'Starting updates'); $('progress').appendChild(progress.element); progress.startMonitoring('update.php?op=do_update', 0); } diff --git a/misc/upload.js b/misc/upload.js index 9945803f6..dcf246dfb 100644 --- a/misc/upload.js +++ b/misc/upload.js @@ -54,9 +54,22 @@ jsUpload.prototype.onsubmit = function () { */ jsUpload.prototype.oncomplete = function (data) { // Remove progressbar - removeNode(this.progress); + removeNode(this.progress.element); this.progress = null; // Replace form and re-attach behaviour $(this.wrapper).innerHTML = data; 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'; +} diff --git a/modules/upload.module b/modules/upload.module index 201c455d4..e64f2a26d 100644 --- a/modules/upload.module +++ b/modules/upload.module @@ -543,6 +543,6 @@ function upload_js() { $output = theme('status_messages') . form_render($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; } diff --git a/modules/upload/upload.module b/modules/upload/upload.module index 201c455d4..e64f2a26d 100644 --- a/modules/upload/upload.module +++ b/modules/upload/upload.module @@ -543,6 +543,6 @@ function upload_js() { $output = theme('status_messages') . form_render($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; } diff --git a/update.php b/update.php index 55c345b1e..d6c9be87b 100644 --- a/update.php +++ b/update.php @@ -396,7 +396,7 @@ function update_progress_page() { * * @return * 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() { while (($update = reset($_SESSION['update_remaining']))) { @@ -412,12 +412,12 @@ function update_do_updates() { } 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 { - $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() { @@ -437,26 +437,27 @@ function update_do_update_page() { } 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() { $new_op = 'do_update_nojs'; if ($_SERVER['REQUEST_METHOD'] == 'GET') { - list($percent, $message) = update_do_updates(); - if ($percent == 100) { + list($percentage, $message) = update_do_updates(); + if ($percentage == 100) { $new_op = 'finished'; } } else { // This is the first page so return some output immediately. - $percent = 0; + $percentage = 0; $message = 'Starting updates'; } drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=update.php?op='. $new_op .'">'); 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>'; return $output; |