summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Wittens <steven@10.no-reply.drupal.org>2006-02-05 19:04:58 +0000
committerSteven Wittens <steven@10.no-reply.drupal.org>2006-02-05 19:04:58 +0000
commitd38429248ee2cbaa442e396f251b1781acbc0d66 (patch)
treefb04fcaf6c118752902bc8d4a18ec763e3d9c4da
parentafde65151c2e3807f8879fd0fe2ecd1cdda9f050 (diff)
downloadbrdo-d38429248ee2cbaa442e396f251b1781acbc0d66.tar.gz
brdo-d38429248ee2cbaa442e396f251b1781acbc0d66.tar.bz2
- #47510: Show JavaScript alert when PHP errors occur
-rw-r--r--includes/common.inc14
-rw-r--r--misc/drupal.js96
-rw-r--r--misc/progress.js26
-rw-r--r--misc/update.js2
-rw-r--r--misc/upload.js15
-rw-r--r--modules/upload.module2
-rw-r--r--modules/upload/upload.module2
-rw-r--r--update.php19
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(/&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;
@@ -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">&nbsp;</div>'+
+ '<div class="message">&nbsp;</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;