From a36f058e53e204883e2c97c31fb62a3707e55a69 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Thu, 13 Jul 2006 09:48:56 +0000 Subject: [PATCH] Bug 6101 - Automatically scroll to any errors when upgrading the database. JavaScript thanks to Andrew Walker. PHP changes are my fault. --- admin/index.php | 6 +- backup/lib.php | 8 +- lib/adminlib.php | 12 ++- lib/blocklib.php | 17 +++-- lib/datalib.php | 2 +- lib/locallib.php | 3 +- lib/scroll_to_errors.js | 160 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 lib/scroll_to_errors.js diff --git a/admin/index.php b/admin/index.php index 01a7f01c9c..b9358f1a03 100644 --- a/admin/index.php +++ b/admin/index.php @@ -93,6 +93,7 @@ } } + $linktoscrolltoerrors = ''; if (! $maintables) { if (empty($agreelicence)) { $strlicense = get_string("license"); @@ -110,7 +111,8 @@ $strdatabasesetup = get_string("databasesetup"); $strdatabasesuccess = get_string("databasesuccess"); - print_header($strdatabasesetup, $strdatabasesetup, $strdatabasesetup, "", "", false, " ", " "); + print_header($strdatabasesetup, $strdatabasesetup, $strdatabasesetup, + "", $linktoscrolltoerrors, false, " ", " "); if (file_exists("$CFG->libdir/db/$CFG->dbtype.sql")) { $db->debug = true; if (modify_database("$CFG->libdir/db/$CFG->dbtype.sql")) { @@ -152,7 +154,7 @@ } else { $strdatabasesuccess = get_string("databasesuccess"); print_header($strdatabasechecking, $stradministration, $strdatabasechecking, - "", "", false, " ", " "); + "", $linktoscrolltoerrors, false, " ", " "); print_heading($strdatabasechecking); $db->debug=true; if (main_upgrade($CFG->version)) { diff --git a/backup/lib.php b/backup/lib.php index c7947e0cce..6bcee82997 100644 --- a/backup/lib.php +++ b/backup/lib.php @@ -323,8 +323,9 @@ if (empty($CFG->backup_version)) { // Backup has never been installed. $strdatabaseupgrades = get_string("databaseupgrades"); - print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, - "", "", false, " ", " "); + print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, "", + '', + false, " ", " "); $db->debug=true; if (modify_database("$CFG->dirroot/backup/db/$CFG->dbtype.sql")) { @@ -345,7 +346,8 @@ if ($backup_version > $CFG->backup_version) { // Upgrade tables $strdatabaseupgrades = get_string("databaseupgrades"); - print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades); + print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, '', + ''); require_once ("$CFG->dirroot/backup/db/$CFG->dbtype.php"); diff --git a/lib/adminlib.php b/lib/adminlib.php index e3c7bcbd4f..a7f814498d 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -73,7 +73,9 @@ function upgrade_plugins($type, $dir, $return) { } else if ($CFG->$pluginversion < $plugin->version) { if (empty($updated_plugins)) { $strpluginsetup = get_string('pluginsetup'); - print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '', '', false, ' ', ' '); + print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '', + '', + false, ' ', ' '); } print_heading($plugin->name .' plugin needs upgrading'); @@ -186,7 +188,9 @@ function upgrade_activity_modules($return) { } else if ($currmodule->version < $module->version) { if (empty($updated_modules)) { $strmodulesetup = get_string('modulesetup'); - print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', '', false, ' ', ' '); + print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', + '', + false, ' ', ' '); } print_heading($module->name .' module needs upgrading'); $upgrade_function = $module->name.'_upgrade'; @@ -215,7 +219,9 @@ function upgrade_activity_modules($return) { } else { // module not installed yet, so install it if (empty($updated_modules)) { $strmodulesetup = get_string('modulesetup'); - print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', '', false, ' ', ' '); + print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', + '', + false, ' ', ' '); } print_heading($module->name); $updated_modules = true; diff --git a/lib/blocklib.php b/lib/blocklib.php index 6196d01427..2b0cf5927f 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -908,8 +908,9 @@ function upgrade_blocks_db($continueto) { if (empty($CFG->blocks_version)) { // Blocks have never been installed. $strdatabaseupgrades = get_string('databaseupgrades'); - print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, - '', '', false, ' ', ' '); + print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, '', + '', + false, ' ', ' '); $db->debug=true; if (modify_database($CFG->dirroot .'/blocks/db/'. $CFG->dbtype .'.sql')) { @@ -930,8 +931,8 @@ function upgrade_blocks_db($continueto) { if ($blocks_version > $CFG->blocks_version) { // Upgrade tables $strdatabaseupgrades = get_string('databaseupgrades'); - print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades); - + print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, '', + ''); require_once ($CFG->dirroot .'/blocks/db/'. $CFG->dbtype .'.php'); $db->debug=true; @@ -1064,7 +1065,9 @@ function upgrade_blocks_plugins($continueto) { } else if ($currblock->version < $block->version) { if (empty($updated_blocks)) { $strblocksetup = get_string('blocksetup'); - print_header($strblocksetup, $strblocksetup, $strblocksetup, '', '', false, ' ', ' '); + print_header($strblocksetup, $strblocksetup, $strblocksetup, '', + '', + false, ' ', ' '); } print_heading('New version of '.$blocktitle.' ('.$block->name.') exists'); $upgrade_function = $block->name.'_upgrade'; @@ -1116,7 +1119,9 @@ function upgrade_blocks_plugins($continueto) { } if (empty($updated_blocks)) { $strblocksetup = get_string('blocksetup'); - print_header($strblocksetup, $strblocksetup, $strblocksetup, '', '', false, ' ', ' '); + print_header($strblocksetup, $strblocksetup, $strblocksetup, '', + '', + false, ' ', ' '); } print_heading($block->name); $updated_blocks = true; diff --git a/lib/datalib.php b/lib/datalib.php index 93f3ee039c..a8f1012a5a 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -57,7 +57,7 @@ function execute_sql($command, $feedback=true) { return true; } else { if ($feedback) { - echo '

'. get_string('error') .'

'; + notify('' . get_string('error') . ''); } if (!empty($CFG->dblogerror)) { $debug=array_shift(debug_backtrace()); diff --git a/lib/locallib.php b/lib/locallib.php index ba8de57d24..01a2db0ea1 100644 --- a/lib/locallib.php +++ b/lib/locallib.php @@ -90,7 +90,8 @@ function upgrade_local_db($continueto) { if ($local_version > $CFG->local_version) { // upgrade! $strdatabaseupgrades = get_string('databaseupgrades'); - print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades); + print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades, '', + ''); require_once ($CFG->dirroot .'/local/db/'. $CFG->dbtype .'.php'); diff --git a/lib/scroll_to_errors.js b/lib/scroll_to_errors.js new file mode 100644 index 0000000000..741f1815ff --- /dev/null +++ b/lib/scroll_to_errors.js @@ -0,0 +1,160 @@ +// keep the global scope clean +(function() { + + var id = null; + var warnings = null; + var continueBtn = null; + + var getElementPosY = function(obj) { + var y = 0; + while (obj.offsetParent) { + y += obj.offsetTop; + obj = obj.offsetParent; + } + return y; + }; + + // ugh, find scroll position in 3 possible ways + var getScrollY = function() { + return self.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; + }; + + var initScroll = function(obj) { + // if we scroll to the warning div itself the sql that caused the warning will be off the top of the page + // so we can look through the page for a preceeding div and base the scroll position on that + var prevDiv = findPreviousSibling(obj, 'div'); + // if the warning div doesn't have a previous sibling div scroll to the top of the page instead + var y = (prevDiv) ? getElementPosY(prevDiv) + prevDiv.offsetHeight : 0; + + if (id) { + clearInterval(id); + } + + // scroll with a little bit of easing, I guess it's a matter of personal taste whether it would be + // better to scroll the page directly to the point using window.scrollTo(0, y). But I think easing + // makes it a little clearer to the user that they're scrolling through the page :-) + id = setInterval(function() { + var ys = getScrollY(); + // the stuff on arguments.callee is a check to stop scrolling if we've reached the end of the page + // and can't scroll any further + if ((arguments.callee.oldPos && arguments.callee.oldPos == ys) || Math.abs(y - ys) < 5) { + arguments.callee.oldPos = null; + window.scrollTo(0, y); + clearInterval(id); + id = null; + } else { + window.scrollTo(0, Math.round(ys + ((y - ys) / 2))); + } + arguments.callee.oldPos = ys; + }, 60); + }; + + // return nodes with a class name that matches regexp - if individual is set we're only looking + // for a single node + var filterNodesByClassName = function(nodes, regexp, individual) { + var filtered = []; + var n = nodes.length; + for (var i = 0; i < n; ++i) { + if (nodes[i].className && nodes[i].className.match(regexp)) { + if (individual) { + return nodes[i]; + } + filtered.push(nodes[i]); + } + } + return filtered; + }; + + // look through the previous siblings of an element and find the first one with a given node name + var findPreviousSibling = function(obj, nodeName) { + while (obj = obj.previousSibling) { + if (obj.nodeName.toLowerCase() == nodeName) { + return obj; + } + } + return false; + }; + + // create the links to scroll around the page. warningIndex is used to look up the element in the + // warnings array that should be scrolled to + var createWarningSkipLink = function(linkText, warningIndex, style) { + var link = document.createElement('a'); + link.href = 'javascript:;'; + link.warningIndex = warningIndex; + link.appendChild(document.createTextNode(linkText)); + link.onclick = function() { + initScroll(warnings[this.warningIndex]); + }; + + if (style) { + for (var x in style) { + link.style[x] = style[x]; + } + } + return link; + }; + + + var checkWarnings = function() { + // look for div tags with the class name notifyproblem + warnings = filterNodesByClassName(document.getElementsByTagName('div'), /(^|\b)notifyproblem(\b|$)/); + // and find the continue button + continueBtn = filterNodesByClassName(document.getElementsByTagName('div'), /(^|\b)continuebutton(\b|$)/, true); + + var n = warnings.length; // find how many warnings + warnings[warnings.length] = continueBtn; // then add the continue button to the array + + var link; + for (var i = 0; i < n; ++i) { + // add a "next" link to all warnings except the last one on the page + if (i < n - 1) { + link = createWarningSkipLink('Scroll to next warning', i + 1, {paddingLeft: '1em'}); + } else { + // on the last link add a link to go to the continue button + link = createWarningSkipLink('Scroll to continue button', i + 1, {paddingLeft: '1em'}); + } + warnings[i].appendChild(link); + // and add a "previous" link to all except the first + if (i > 0) { + link = createWarningSkipLink('Scroll to previous warning', i - 1, {paddingRight: '1em'}); + warnings[i].insertBefore(link, warnings[i].firstChild); + } + } + + + var contentDiv = document.getElementById('content'); + if (contentDiv) { + // create a message to display at the top of the page, with a link to the first warning + // or to the continue button if there were no warnings on the page + var p = document.createElement('p'); + if (n > 0) { + var warningText = (n == 1) ? 'warning' : 'warnings'; + link = createWarningSkipLink('Scroll to the first warning', 0); + p.appendChild(document.createTextNode('This script generated ' + n + ' ' + warningText + ' - ')); + p.className = 'notifyproblem'; + } else { + link = createWarningSkipLink('Scroll to the continue button', 0); + p.appendChild(document.createTextNode('No warnings - ')); + p.className = 'notifysuccess'; + } + p.appendChild(link); + contentDiv.insertBefore(p, contentDiv.firstChild); + } + + // automatically scroll to the first warning or continue button + initScroll(warnings[0]); + }; + + // load should be a document event, but most browsers use window + if (window.addEventListener) { + window.addEventListener('load', checkWarnings, false); + } else if (document.addEventListener) { + document.addEventListener('load', checkWarnings, false); + } else if (window.attachEvent) { + // sometimes IE doesn't report scrollTop correctly (it might be a quirk of this specific page, I don't know) + // but using scrollTo once to begin makes sure things work + window.scrollTo(0, 1); + window.attachEvent('onload', checkWarnings); + } + +})(); \ No newline at end of file -- 2.39.5