Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.537.2.11 diff -u -F^f -r1.537.2.11 common.inc --- includes/common.inc 12 Oct 2006 19:53:55 -0000 1.537.2.11 +++ includes/common.inc 14 Oct 2006 07:56:16 -0000 @@ -116,7 +116,7 @@ function drupal_set_html_head($data = NU function drupal_get_html_head() { $output = "\n"; $output .= theme('stylesheet_import', base_path() .'misc/drupal.css'); - return $output . drupal_set_html_head(); + return $output . drupal_get_js() . drupal_set_html_head(); } /** @@ -1217,24 +1217,145 @@ function drupal_add_link($attributes) { } /** - * Add a JavaScript file to the output. + * Add a JavaScript file, setting or inline code to the page. * - * The first time this function is invoked per page request, - * it adds "misc/drupal.js" to the output. Other scripts - * depends on the 'killswitch' inside it. - */ -function drupal_add_js($file, $nocache = FALSE) { - static $sent = array(); - - $postfix = $nocache ? '?'. time() : ''; - if (!isset($sent['misc/drupal.js'])) { - drupal_set_html_head(''); - $sent['misc/drupal.js'] = true; - } - if (!isset($sent[$file])) { - drupal_set_html_head(''); - $sent[$file] = true; + * The behavior of this function depends on the parameters it is called with. + * Generally, it handles the addition of JavaScript to the page, either as + * reference to an existing file or as inline code. The following actions can be + * performed using this function: + * + * - Add a file ('core', 'module' and 'theme'): + * Adds a reference to a JavaScript file to the page. JavaScript files + * are placed in a certain order, from 'core' first, to 'module' and finally + * 'theme' so that files, that are added later, can override previously added + * files with ease. + * + * - Add inline JavaScript code ('inline'): + * Executes a piece of JavaScript code on the current page by placing the code + * directly in the page. This can, for example, be useful to tell the user that + * a new message arrived, by opening a pop up, alert box etc. + * + * - Add settings ('setting'): + * Adds a setting to Drupal's global storage of JavaScript settings. Per-page + * settings are required by some modules to function properly. The settings + * will be accessible at Drupal.settings. + * + * @param $data + * (optional) If given, the value depends on the $type parameter: + * - 'core', 'module' or 'theme': Path to the file relative to base_path(). + * - 'inline': The JavaScript code that should be placed in the given scope. + * - 'setting': An array with configuration options as associative array. The + * array is directly placed in Drupal.settings. You might want to wrap your + * actual configuration settings in another variable to prevent the pollution + * of the Drupal.settings namespace. + * @param $type + * (optional) The type of JavaScript that should be added to the page. Allowed + * values are 'core', 'module', 'theme', 'inline' and 'setting'. You + * can, however, specify any value. It is treated as a reference to a JavaScript + * file. Defaults to 'module'. + * @param $scope + * (optional) The location in which you want to place the script. Possible + * values are 'header' and 'footer' by default. If your theme implements + * different locations, however, you can also use these. + * @param $defer + * (optional) If set to TRUE, the defer attribute is set on the \n"; + break; + case 'inline': + foreach ($data as $info) { + $output .= '\n"; + } + break; + default: + foreach ($data as $path => $info) { + $output .= '\n"; + } + } + } + + return $output; } /** Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.292.2.7 diff -u -F^f -r1.292.2.7 theme.inc --- includes/theme.inc 5 Sep 2006 10:22:24 -0000 1.292.2.7 +++ includes/theme.inc 14 Oct 2006 07:56:17 -0000 @@ -919,7 +919,7 @@ function theme_feed_icon($url) { */ function theme_closure($main = 0) { $footer = module_invoke_all('footer', $main); - return implode("\n", $footer); + return implode("\n", $footer) . drupal_get_js('footer'); } /** Index: misc/autocomplete.js =================================================================== RCS file: /cvs/drupal/drupal/misc/autocomplete.js,v retrieving revision 1.11 diff -u -F^f -r1.11 autocomplete.js --- misc/autocomplete.js 17 Apr 2006 20:48:25 -0000 1.11 +++ misc/autocomplete.js 14 Oct 2006 07:56:17 -0000 @@ -1,76 +1,51 @@ -// $Id: autocomplete.js,v 1.11 2006/04/17 20:48:25 dries Exp $ - -// Global Killswitch -if (isJsEnabled()) { - addLoadEvent(autocompleteAutoAttach); -} +// $Id: autocomplete.js,v 1.14 2006/10/14 02:39:48 unconed Exp $ /** * Attaches the autocomplete behaviour to all required fields */ -function autocompleteAutoAttach() { +Drupal.autocompleteAutoAttach = function () { var acdb = []; - var inputs = document.getElementsByTagName('input'); - for (i = 0; input = inputs[i]; i++) { - if (input && hasClass(input, 'autocomplete')) { - uri = input.value; - if (!acdb[uri]) { - acdb[uri] = new ACDB(uri); - } - input = $(input.id.substr(0, input.id.length - 13)); - input.setAttribute('autocomplete', 'OFF'); - addSubmitEvent(input.form, autocompleteSubmit); - new jsAC(input, acdb[uri]); + $('input.autocomplete').each(function () { + var uri = this.value; + if (!acdb[uri]) { + acdb[uri] = new Drupal.ACDB(uri); } - } + var input = $('#' + this.id.substr(0, this.id.length - 13)) + .attr('autocomplete', 'OFF')[0]; + $(input.form).submit(Drupal.autocompleteSubmit); + new Drupal.jsAC(input, acdb[uri]); + }); } /** * Prevents the form from submitting if the suggestions popup is open + * and closes the suggestions popup when doing so. */ -function autocompleteSubmit() { - var popup = document.getElementById('autocomplete'); - if (popup) { - popup.owner.hidePopup(); - return false; - } - return true; +Drupal.autocompleteSubmit = function () { + return $('#autocomplete').each(function () { + this.owner.hidePopup(); + }).size() == 0; } - /** * An AutoComplete object */ -function jsAC(input, db) { +Drupal.jsAC = function (input, db) { var ac = this; this.input = input; this.db = db; - this.input.onkeydown = function (event) { return ac.onkeydown(this, event); }; - this.input.onkeyup = function (event) { ac.onkeyup(this, event) }; - this.input.onblur = function () { ac.hidePopup(); ac.db.cancel(); }; - this.popup = document.createElement('div'); - this.popup.id = 'autocomplete'; - this.popup.owner = this; -}; -/** - * Hides the autocomplete suggestions - */ -jsAC.prototype.hidePopup = function (keycode) { - if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) { - this.input.value = this.selected.autocompleteValue; - } - if (this.popup.parentNode && this.popup.parentNode.tagName) { - removeNode(this.popup); - } - this.selected = false; -} + $(this.input) + .keydown(function (event) { return ac.onkeydown(this, event); }) + .keyup(function (event) { ac.onkeyup(this, event) }) + .blur(function () { ac.hidePopup(); ac.db.cancel(); }); +}; /** * Handler for the "keydown" event */ -jsAC.prototype.onkeydown = function (input, e) { +Drupal.jsAC.prototype.onkeydown = function (input, e) { if (!e) { e = window.event; } @@ -89,7 +64,7 @@ function jsAC(input, db) { /** * Handler for the "keyup" event */ -jsAC.prototype.onkeyup = function (input, e) { +Drupal.jsAC.prototype.onkeyup = function (input, e) { if (!e) { e = window.event; } @@ -126,21 +101,21 @@ function jsAC(input, db) { /** * Puts the currently highlighted suggestion into the autocomplete field */ -jsAC.prototype.select = function (node) { +Drupal.jsAC.prototype.select = function (node) { this.input.value = node.autocompleteValue; } /** * Highlights the next suggestion */ -jsAC.prototype.selectDown = function () { +Drupal.jsAC.prototype.selectDown = function () { if (this.selected && this.selected.nextSibling) { this.highlight(this.selected.nextSibling); } else { - var lis = this.popup.getElementsByTagName('li'); - if (lis.length > 0) { - this.highlight(lis[0]); + var lis = $('li', this.popup); + if (lis.size() > 0) { + this.highlight(lis.get(0)); } } } @@ -148,7 +123,7 @@ function jsAC(input, db) { /** * Highlights the previous suggestion */ -jsAC.prototype.selectUp = function () { +Drupal.jsAC.prototype.selectUp = function () { if (this.selected && this.selected.previousSibling) { this.highlight(this.selected.previousSibling); } @@ -157,30 +132,61 @@ function jsAC(input, db) { /** * Highlights a suggestion */ -jsAC.prototype.highlight = function (node) { - removeClass(this.selected, 'selected'); - addClass(node, 'selected'); +Drupal.jsAC.prototype.highlight = function (node) { + if (this.selected) { + $(this.selected).removeClass('selected'); + } + $(node).addClass('selected'); this.selected = node; } /** * Unhighlights a suggestion */ -jsAC.prototype.unhighlight = function (node) { - removeClass(node, 'selected'); +Drupal.jsAC.prototype.unhighlight = function (node) { + $(node).removeClass('selected'); + this.selected = false; +} + +/** + * Hides the autocomplete suggestions + */ +Drupal.jsAC.prototype.hidePopup = function (keycode) { + // Select item if the right key or mousebutton was pressed + if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) { + this.input.value = this.selected.autocompleteValue; + } + // Hide popup + var popup = this.popup; + if (popup) { + this.popup = null; + $(popup).fadeOut('fast', function() { $(popup).remove(); }); + } this.selected = false; } /** * Positions the suggestions popup and starts a search */ -jsAC.prototype.populatePopup = function () { - var ac = this; - var pos = absolutePosition(this.input); +Drupal.jsAC.prototype.populatePopup = function () { + // Show popup + if (this.popup) { + $(this.popup).remove(); + } + var pos = Drupal.absolutePosition(this.input); this.selected = false; - this.popup.style.top = (pos.y + this.input.offsetHeight) +'px'; - this.popup.style.left = pos.x +'px'; - this.popup.style.width = (this.input.offsetWidth - 4) +'px'; + this.popup = document.createElement('div'); + this.popup.id = 'autocomplete'; + this.popup.owner = this; + $(this.popup).css({ + top: (pos.y + this.input.offsetHeight) +'px', + left: pos.x +'px', + width: (this.input.offsetWidth - 4) +'px', + display: 'none' + }); + $('body').append(this.popup); + + // Do search this.db.owner = this; this.db.search(this.input.value); } @@ -188,41 +194,48 @@ function jsAC(input, db) { /** * Fills the suggestion popup with any matches received */ -jsAC.prototype.found = function (matches) { - while (this.popup.hasChildNodes()) { - this.popup.removeChild(this.popup.childNodes[0]); - } - if (!this.popup.parentNode || !this.popup.parentNode.tagName) { - document.getElementsByTagName('body')[0].appendChild(this.popup); - } +Drupal.jsAC.prototype.found = function (matches) { + // Prepare matches var ul = document.createElement('ul'); var ac = this; - for (key in matches) { var li = document.createElement('li'); - var div = document.createElement('div'); - div.innerHTML = matches[key]; - li.appendChild(div); + $(li) + .html('
'+ matches[key] +'
') + .mousedown(function () { ac.select(this); }) + .mouseover(function () { ac.highlight(this); }) + .mouseout(function () { ac.unhighlight(this); }); li.autocompleteValue = key; - li.onmousedown = function() { ac.select(this); }; - li.onmouseover = function() { ac.highlight(this); }; - li.onmouseout = function() { ac.unhighlight(this); }; - ul.appendChild(li); + $(ul).append(li); } + // Show popup with matches, if any if (ul.childNodes.length > 0) { - this.popup.appendChild(ul); + $(this.popup).empty().append(ul).show(); } else { + $(this.popup).css({visibility: 'hidden'}); this.hidePopup(); } - removeClass(this.input, 'throbbing'); +} + +Drupal.jsAC.prototype.setStatus = function (status) { + switch (status) { + case 'begin': + $(this.input).addClass('throbbing'); + break; + case 'cancel': + case 'error': + case 'found': + $(this.input).removeClass('throbbing'); + break; + } } /** * An AutoComplete DataBase object */ -function ACDB(uri) { +Drupal.ACDB = function (uri) { this.uri = uri; this.delay = 300; this.cache = {}; @@ -231,46 +244,55 @@ function ACDB(uri) { /** * Performs a cached and delayed search */ -ACDB.prototype.search = function(searchString) { +Drupal.ACDB.prototype.search = function (searchString) { + var db = this; this.searchString = searchString; + + // See if this key has been searched for before if (this.cache[searchString]) { return this.owner.found(this.cache[searchString]); } + + // Initiate delayed search if (this.timer) { clearTimeout(this.timer); } - var db = this; this.timer = setTimeout(function() { - addClass(db.owner.input, 'throbbing'); - db.transport = HTTPGet(db.uri +'/'+ encodeURIComponent(searchString), db.receive, db); - }, this.delay); -} + db.owner.setStatus('begin'); -/** - * HTTP callback function. Passes suggestions to the autocomplete object - */ -ACDB.prototype.receive = function(string, xmlhttp, acdb) { - // Note: Safari returns 'undefined' status if the request returns no data. - if (xmlhttp.status != 200 && typeof xmlhttp.status != 'undefined') { - removeClass(acdb.owner.input, 'throbbing'); - return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ acdb.uri); - } - // Parse back result - var matches = parseJson(string); - if (typeof matches['status'] == 'undefined' || matches['status'] != 0) { - acdb.cache[acdb.searchString] = matches; - acdb.owner.found(matches); - } + // Ajax GET request for autocompletion + $.ajax({ + type: "GET", + url: db.uri +'/'+ Drupal.encodeURIComponent(searchString), + success: function (data) { + // Parse back result + var matches = Drupal.parseJson(data); + if (typeof matches['status'] == 'undefined' || matches['status'] != 0) { + db.cache[searchString] = matches; + // Verify if these are still the matches the user wants to see + if (db.searchString == searchString) { + db.owner.found(matches); + } + db.owner.setStatus('found'); + } + }, + error: function (xmlhttp) { + alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri); + } + }); + }, this.delay); } /** * Cancels the current autocomplete request */ -ACDB.prototype.cancel = function() { - if (this.owner) removeClass(this.owner.input, 'throbbing'); +Drupal.ACDB.prototype.cancel = function() { + if (this.owner) this.owner.setStatus('cancel'); if (this.timer) clearTimeout(this.timer); - if (this.transport) { - this.transport.onreadystatechange = function() {}; - this.transport.abort(); - } + this.searchString = ''; +} + +// Global Killswitch +if (Drupal.jsEnabled) { + $(document).ready(Drupal.autocompleteAutoAttach); } Index: misc/collapse.js =================================================================== RCS file: /cvs/drupal/drupal/misc/collapse.js,v retrieving revision 1.6 diff -u -F^f -r1.6 collapse.js --- misc/collapse.js 14 Apr 2006 13:48:56 -0000 1.6 +++ misc/collapse.js 14 Oct 2006 07:56:18 -0000 @@ -1,70 +1,100 @@ -// $Id: collapse.js,v 1.6 2006/04/14 13:48:56 killes Exp $ +// $Id: collapse.js,v 1.7 2006/08/31 23:31:24 unconed Exp $ -if (isJsEnabled()) { - addLoadEvent(collapseAutoAttach); -} - -function collapseAutoAttach() { - var fieldsets = document.getElementsByTagName('fieldset'); - var legend, fieldset; - for (var i = 0; fieldset = fieldsets[i]; i++) { - if (!hasClass(fieldset, 'collapsible')) { - continue; - } - legend = fieldset.getElementsByTagName('legend'); - if (legend.length == 0) { - continue; - } - legend = legend[0]; +Drupal.collapseAutoAttach = function () { + $('fieldset.collapsible legend').each(function () { + // Turn the legend into clickable link var a = document.createElement('a'); a.href = '#'; - a.onclick = function() { - toggleClass(this.parentNode.parentNode, 'collapsed'); - if (!hasClass(this.parentNode.parentNode, 'collapsed')) { - collapseScrollIntoView(this.parentNode.parentNode); - if (typeof textAreaAutoAttach != 'undefined') { - // Add the grippie to a textarea in a collapsed fieldset. - textAreaAutoAttach(null, this.parentNode.parentNode); + $(a) + .click(function() { + var fieldset = this.parentNode.parentNode; + + // Prevent double animations + if (fieldset.animating) { + return false; + } + fieldset.animating = true; + + if ($(fieldset).is('.collapsed')) { + // Open fieldset with animation + $(fieldset.contentWrapper).hide(); + $(fieldset).removeClass('collapsed'); + $(fieldset.contentWrapper).slideDown(300, + { + // Make sure we open to height auto + complete: function() { + $(fieldset.contentWrapper).css('height', 'auto'); + Drupal.collapseScrollIntoView(fieldset); + fieldset.animating = false; + }, + // Scroll the fieldset into view + step: function() { + Drupal.collapseScrollIntoView(fieldset); + } + } + ); + if (typeof Drupal.textareaAttach != 'undefined') { + // Initialize resizable textareas that are now revealed + Drupal.textareaAttach(null, fieldset); + } + } + else { + // Collapse fieldset with animation (reverse of opening) + $(fieldset.contentWrapper) + .slideUp('medium', function () { $(fieldset).addClass('collapsed'); fieldset.animating = false; } ) + .show(); } - } - this.blur(); - return false; - }; - a.innerHTML = legend.innerHTML; - while (legend.hasChildNodes()) { - removeNode(legend.childNodes[0]); + this.blur(); + return false; + }) + .html(this.innerHTML); + $(this) + .empty() + .append(a); + + // Wrap fieldsets contents (except for the legend) into wrapper divs for animating. + // div1 is used to avoid margin problems inside fieldsets, + // div2 is the one that is actually animated. + var div1 = document.createElement('div'); + var div2 = document.createElement('div'); + this.parentNode.contentWrapper = div2; + $(this).after(div1); + $(div1).append(div2); + var el = div1.nextSibling; + while (el != null) { + var next = el.nextSibling; + $(el).remove(); + $(div2).append(el); + el = next; } - legend.appendChild(a); - collapseEnsureErrorsVisible(fieldset); - } -} + // Avoid jumping around due to margins collapsing into fieldset border + $(div1).css('overflow', 'hidden'); -function collapseEnsureErrorsVisible(fieldset) { - if (!hasClass(fieldset, 'collapsed')) { - return; - } - var inputs = []; - inputs = inputs.concat(fieldset.getElementsByTagName('input')); - inputs = inputs.concat(fieldset.getElementsByTagName('textarea')); - inputs = inputs.concat(fieldset.getElementsByTagName('select')); - for (var j = 0; j<3; j++) { - for (var i = 0; i < inputs[j].length; i++) { - if (hasClass(inputs[j][i], 'error')) { - return removeClass(fieldset, 'collapsed'); - } + // Expand if there are errors inside + if ($('input.error, textarea.error, select.error', this.parentNode).size() > 0) { + $(this.parentNode).removeClass('collapsed'); } - } + }); } -function collapseScrollIntoView(node) { +/** + * Scroll a given fieldset into view as much as possible. + */ +Drupal.collapseScrollIntoView = function (node) { var h = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0; var offset = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; - var pos = absolutePosition(node); - if (pos.y + node.scrollHeight > h + offset) { - if (node.scrollHeight > h) { + var pos = Drupal.absolutePosition(node); + var fudge = 55; + if (pos.y + node.offsetHeight + fudge > h + offset) { + if (node.offsetHeight > h) { window.scrollTo(0, pos.y); } else { - window.scrollTo(0, pos.y + node.scrollHeight - h); + window.scrollTo(0, pos.y + node.offsetHeight - h + fudge); } } } + +// Global Killswitch +if (Drupal.jsEnabled) { + $(document).ready(Drupal.collapseAutoAttach); +} Index: misc/drupal.css =================================================================== RCS file: /cvs/drupal/drupal/misc/Attic/drupal.css,v retrieving revision 1.147.2.3 diff -u -F^f -r1.147.2.3 drupal.css --- misc/drupal.css 30 Jun 2006 00:13:45 -0000 1.147.2.3 +++ misc/drupal.css 14 Oct 2006 07:56:18 -0000 @@ -594,7 +594,7 @@ form { } /* Animated throbber */ html.js input.form-autocomplete { - background-image: url(throbber.gif); + background-image: url(misc/throbber.gif); background-repeat: no-repeat; background-position: 100% 2px; } @@ -603,28 +603,6 @@ form { } /* -** Progressbar styles -*/ -.progress { - font-weight: bold; -} -.progress .bar { - background: #fff url(progress.gif); - border: 1px solid #00375a; - height: 1.5em; - margin-top: 0.2em; -} -.progress .filled { - background: #0072b9; - height: 1em; - border-bottom: 0.5em solid #004a73; - width: 0%; -} -.progress .percentage { - float: right; -} - -/* ** Collapsing fieldsets */ html.js fieldset.collapsed { @@ -632,24 +610,29 @@ form { border-left-width: 0; border-right-width: 0; margin-bottom: 0; + height: 1em; } html.js fieldset.collapsed * { display: none; } -html.js fieldset.collapsed table *, -html.js fieldset.collapsed legend, -html.js fieldset.collapsed legend * { - display: inline; +html.js fieldset.collapsed legend { + display: block; } html.js fieldset.collapsible legend a { padding-left: 15px; - background: url(menu-expanded.png) 5px 50% no-repeat; + background: url(menu-expanded.png) 5px 75% no-repeat; } html.js fieldset.collapsed legend a { background-image: url(menu-collapsed.png); + background-position: 5px 50%; } /* Note: IE-only fix due to '* html' (breaks Konqueror otherwise). */ -* html.js fieldset.collapsible legend a { +* html.js fieldset.collapsed legend, +* html.js fieldset.collapsed legend *, +* html.js fieldset.collapsed table * { + display: inline; +} +html.js fieldset.collapsible legend a { display: block; } @@ -666,6 +649,32 @@ form { border-top-width: 0; cursor: s-resize; } +html.js .resizable-textarea textarea { + margin-bottom: 0; + width: 100%; +} + +/* +** Progressbar styles +*/ +.progress { + font-weight: bold; +} +.progress .bar { + background: #fff url(progress.gif); + border: 1px solid #00375a; + height: 1.5em; + margin-top: 0.2em; +} +.progress .filled { + background: #0072b9; + height: 1em; + border-bottom: 0.5em solid #004a73; + width: 0%; +} +.progress .percentage { + float: right; +} /* ** Formatting for welcome page Index: misc/drupal.js =================================================================== RCS file: /cvs/drupal/drupal/misc/drupal.js,v retrieving revision 1.22.2.2 diff -u -F^f -r1.22.2.2 drupal.js --- misc/drupal.js 19 Aug 2006 19:55:20 -0000 1.22.2.2 +++ misc/drupal.js 14 Oct 2006 07:56:18 -0000 @@ -1,127 +1,44 @@ -// $Id: drupal.js,v 1.22.2.2 2006/08/19 19:55:20 killes Exp $ +// $Id: drupal.js,v 1.29 2006/10/14 02:39:48 unconed Exp $ -/** - * Only enable Javascript functionality if all required features are supported. - */ -function isJsEnabled() { - if (typeof document.jsEnabled == 'undefined') { - // Note: ! casts to boolean implicitly. - document.jsEnabled = !( - !document.getElementsByTagName || - !document.createElement || - !document.createTextNode || - !document.documentElement || - !document.getElementById); - } - return document.jsEnabled; -} - -// Global Killswitch on the element -if (isJsEnabled()) { - document.documentElement.className = 'js'; -} +var Drupal = Drupal || {}; /** - * Make IE's XMLHTTP object accessible through XMLHttpRequest() + * Set the variable that indicates if JavaScript behaviors should be applied */ -if (typeof XMLHttpRequest == 'undefined') { - XMLHttpRequest = function () { - var msxmls = ['MSXML3', 'MSXML2', 'Microsoft'] - for (var i=0; i < msxmls.length; i++) { - try { - return new ActiveXObject(msxmls[i]+'.XMLHTTP') - } - catch (e) { } - } - throw new Error("No XML component installed!"); - } -} +Drupal.jsEnabled = document.getElementsByTagName && document.createElement && document.createTextNode && document.documentElement && document.getElementById; /** - * Creates an HTTP GET request and sends the response to the callback function. - * - * Note that dynamic arguments in the URI should be escaped with encodeURIComponent(). + * Extends the current object with the parameter. Works recursively. */ -function HTTPGet(uri, callbackFunction, callbackParameter) { - var xmlHttp = new XMLHttpRequest(); - var bAsync = true; - if (!callbackFunction) { - bAsync = false; - } - - xmlHttp.open('GET', uri, bAsync); - xmlHttp.send(null); - - if (bAsync) { - xmlHttp.onreadystatechange = function() { - if (xmlHttp.readyState == 4) { - callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter); - } - } - return xmlHttp; - } - else { - return xmlHttp.responseText; - } -} - -/** - * Creates an HTTP POST request and sends the response to the callback function - * - * Note: passing null or undefined for 'object' makes the request fail in Opera 8. - * Pass an empty string instead. - */ -function HTTPPost(uri, callbackFunction, callbackParameter, object) { - var xmlHttp = new XMLHttpRequest(); - var bAsync = true; - if (!callbackFunction) { - bAsync = false; - } - xmlHttp.open('POST', uri, bAsync); - - var toSend = ''; - if (typeof object == 'object') { - xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - for (var i in object) { - toSend += (toSend ? '&' : '') + i + '=' + encodeURIComponent(object[i]); +Drupal.extend = function(obj) { + for (var i in obj) { + if (this[i]) { + Drupal.extend.apply(this[i], [obj[i]]); } - } - else { - toSend = object; - } - xmlHttp.send(toSend); - - if (bAsync) { - xmlHttp.onreadystatechange = function() { - if (xmlHttp.readyState == 4) { - callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter); - } + else { + this[i] = obj[i]; } - return xmlHttp; } - else { - return xmlHttp.responseText; - } -} +}; /** * Redirects a button's form submission to a hidden iframe and displays the result * in a given wrapper. The iframe should contain a call to * window.parent.iframeHandler() after submission. */ -function redirectFormButton(uri, button, handler) { - // (Re)create an iframe to target. - createIframe(); - +Drupal.redirectFormButton = function (uri, button, handler) { // Trap the button button.onmouseover = button.onfocus = function() { button.onclick = function() { + // Create target iframe + Drupal.createIframe(); + // Prepare variables for use in anonymous function. var button = this; var action = button.form.action; var target = button.form.target; - // Redirect form submission + // Redirect form submission to iframe this.form.action = uri; this.form.target = 'redirect-target'; @@ -129,7 +46,7 @@ function redirectFormButton(uri, button, // Set iframe handler for later window.iframeHandler = function () { - var iframe = $('redirect-target'); + var iframe = $('#redirect-target').get(0); // Restore form submission button.form.action = action; button.form.target = target; @@ -148,16 +65,15 @@ function redirectFormButton(uri, button, response = null; } - $('redirect-target').onload = null; - $('redirect-target').src = 'about:blank'; - - response = parseJson(response); + response = Drupal.parseJson(response); // Check response code if (response.status == 0) { handler.onerror(response.data); return; } handler.oncomplete(response.data); + + return true; } return true; @@ -166,43 +82,12 @@ function redirectFormButton(uri, button, button.onmouseout = button.onblur = function() { button.onclick = null; } -} - -/** - * Adds a function to the window onload event - */ -function addLoadEvent(func) { - var oldOnload = window.onload; - if (typeof window.onload != 'function') { - window.onload = func; - } - else { - window.onload = function() { - oldOnload(); - func(); - } - } -} - -/** - * Adds a function to a given form's submit event - */ -function addSubmitEvent(form, func) { - var oldSubmit = form.onsubmit; - if (typeof oldSubmit != 'function') { - form.onsubmit = func; - } - else { - form.onsubmit = function() { - return oldSubmit() && func(); - } - } -} +}; /** * Retrieves the absolute position of an element on the screen */ -function absolutePosition(el) { +Drupal.absolutePosition = function (el) { var sLeft = 0, sTop = 0; var isDiv = /^div$/i.test(el.tagName); if (isDiv && el.scrollLeft) { @@ -213,152 +98,109 @@ function absolutePosition(el) { } var r = { x: el.offsetLeft - sLeft, y: el.offsetTop - sTop }; if (el.offsetParent) { - var tmp = absolutePosition(el.offsetParent); + var tmp = Drupal.absolutePosition(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; -function dimensions(el) { - return { width: el.offsetWidth, height: el.offsetHeight }; -} - /** - * Returns true if an element has a specified class name + * Return the dimensions of an element on the screen */ -function hasClass(node, className) { - if (node.className == className) { - return true; - } - var reg = new RegExp('(^| )'+ className +'($| )') - if (reg.test(node.className)) { - return true; - } - return false; -} - -/** - * Adds a class name to an element - */ -function addClass(node, className) { - if (hasClass(node, className)) { - return false; - } - node.className += ' '+ className; - return true; -} - -/** - * Removes a class name from an element - */ -function removeClass(node, className) { - if (!hasClass(node, className)) { - return false; - } - // Replaces words surrounded with whitespace or at a string border with a space. Prevents multiple class names from being glued together. - node.className = eregReplace('(^|\\s+)'+ className +'($|\\s+)', ' ', node.className); - return true; -} - -/** - * Toggles a class name on or off for an element - */ -function toggleClass(node, className) { - if (!removeClass(node, className) && !addClass(node, className)) { - return false; - } - return true; -} - -/** - * Emulate PHP's ereg_replace function in javascript - */ -function eregReplace(search, replace, subject) { - return subject.replace(new RegExp(search,'g'), replace); -} - -/** - * Removes an element from the page - */ -function removeNode(node) { - if (typeof node == 'string') { - node = $(node); - } - if (node && node.parentNode) { - return node.parentNode.removeChild(node); - } - else { - return false; - } -} +Drupal.dimensions = function (el) { + return { width: el.offsetWidth, height: el.offsetHeight }; +}; /** - * Prevents an event from propagating. + * Returns the position of the mouse cursor based on the event object passed */ -function stopEvent(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } - else { - event.returnValue = false; - event.cancelBubble = true; - } -} +Drupal.mousePosition = function(e) { + return { x: e.clientX + document.documentElement.scrollLeft, y: e.clientY + document.documentElement.scrollTop }; +}; /** * 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) != '{') { +Drupal.parseJson = function (data) { + if ((data.substring(0, 1) != '{') && (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(); +Drupal.createIframe = function () { + if ($('#redirect-holder').size()) { + return; + } // 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 = ''; + $(div).html(''); 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); -} + $(iframe) + .attr({ + name: 'redirect-target', + id: 'redirect-target' + }) + .css({ + position: 'absolute', + height: '1px', + width: '1px', + visibility: 'hidden' + }); + $('body').append(div); +}; /** - * Delete the invisible iframe for form submissions. + * Delete the invisible iframe */ -function deleteIframe() { - var holder = $('redirect-holder'); - if (holder != null) { - removeNode(holder); - } -} +Drupal.deleteIframe = function () { + $('#redirect-holder').remove(); +}; + +/** + * Freeze the current body height (as minimum height). Used to prevent + * unnecessary upwards scrolling when doing DOM manipulations. + */ +Drupal.freezeHeight = function () { + Drupal.unfreezeHeight(); + var div = document.createElement('div'); + $(div).css({ + position: 'absolute', + top: '0px', + left: '0px', + width: '1px', + height: $('body').css('height') + }).attr('id', 'freeze-height'); + $('body').append(div); +}; + +/** + * Unfreeze the body height + */ +Drupal.unfreezeHeight = function () { + $('#freeze-height').remove(); +}; /** - * Wrapper around document.getElementById(). + * Wrapper to address the mod_rewrite url encoding bug + * (equivalent of drupal_urlencode() in PHP). */ -function $(id) { - return document.getElementById(id); +Drupal.encodeURIComponent = function (item, uri) { + uri = uri || location.href; + item = encodeURIComponent(item).replace('%2F', '/'); + return uri.indexOf('?q=') ? item : item.replace('%26', '%2526').replace('%23', '%2523'); +}; + +// Global Killswitch on the element +if (Drupal.jsEnabled) { + document.documentElement.className = 'js'; } Index: misc/jquery.js =================================================================== RCS file: misc/jquery.js diff -N misc/jquery.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ misc/jquery.js 14 Oct 2006 07:56:19 -0000 @@ -0,0 +1,2 @@ +// $Id: jquery.js,v 1.3 2006/10/14 02:39:48 unconed Exp $ +eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('l(1Y 1O.6=="P"){1O.P=1O.P;6=q(a,c){l(a&&1Y a=="q"&&6.C.1T)v 6(15).1T(a);a=a||6.1k||15;l(a.2J)v 6(6.1X(a,[]));l(c&&c.2J)v 6(c).2j(a);l(1O==7)v 1f 6(a,c);u m=/^[^<]*(<.+>)[^>]*$/.36(a);l(m)a=6.31([m[1]]);7.1o(a.N==2y||a.D&&!a.1S&&a[0]!=P&&a[0].1S?6.1X(a,[]):6.2j(a,c));u C=1d[1d.D-1];l(C&&1Y C=="q")7.U(C)};l(1Y $!="P")6.3W$=$;u $=6;6.C=6.89={2J:"1.0.2",4u:q(){v 7.D},1o:q(26){l(26&&26.N==2y){7.D=0;[].1l.17(7,26);v 7}F v 26==P?6.1X(7,[]):7[26]},U:q(C,1h){v 6.U(7,C,1h)},8b:q(16){u 2c=-1;7.U(q(i){l(7==16)2c=i});v 2c},1r:q(1P,W,B){v 1P.N!=1N||W!=P?7.U(q(){l(W==P)H(u I 1q 1P)6.1r(B?7.1a:7,I,1P[I]);F 6.1r(B?7.1a:7,1P,W)}):6[B||"1r"](7[0],1P)},1g:q(1P,W){v 7.1r(1P,W,"20")},2V:q(e){e=e||7;u t="";H(u j=0;j0:14},2K:q(1h,1p,2N,C){u 3G=7.4u()>1;u a=6.31(1h);v 7.U(q(){u 16=7;l(1p&&7.2x.2h()=="60"&&a[0].2x.2h()!="61"){u 25=7.4R("25");l(!25.D){16=15.4E("25");7.44(16)}F 16=25[0]}H(u i=(2N<0?a.D-1:0);i!=(2N<0?2N:a.D);i+=2N){C.17(16,[3G?a[i].3D(V):a[i]])}})},28:q(a,1h){u C=1h&&1h[1h.D-1];u 2i=1h&&1h[1h.D-2];l(C&&C.N!=1v)C=Q;l(2i&&2i.N!=1v)2i=Q;l(!C){l(!7.3d)7.3d=[];7.3d.1l(7.1o());7.1o(a)}F{u 1U=7.1o();7.1o(a);l(2i&&a.D||!2i)7.U(2i||C).1o(1U);F 7.1o(1U).U(C)}v 7}};6.1L=6.C.1L=q(16,I){l(!I){I=16;16=7}H(u i 1q I)16[i]=I[i];v 16};6.1L({5C:q(){6.63=V;6.U(6.2l.5u,q(i,n){6.C[i]=q(a){u K=6.2t(7,n);l(a&&a.N==1N)K=6.19(a,K).r;v 7.28(K,1d)}});6.U(6.2l.2q,q(i,n){6.C[i]=q(){u a=1d;v 7.U(q(){H(u j=0;j"}F l(!a[i].1c("<3v")){1p="3v";a[i]="<1p>"+a[i]+""}F l(!a[i].1c("<3M")||!a[i].1c("<6r")){1p="3M";a[i]="<1p><25><3v>"+a[i]+""}u 1F=15.4E("1F");1F.2u=a[i];l(1p){1F=1F.1M;l(1p!="4j")1F=1F.1M;l(1p=="3M")1F=1F.1M}H(u j=0;j<1F.2e.D;j++)r.1l(1F.2e[j])}F l(a[i].2J||a[i].D&&!a[i].1S)H(u k=0;km[3]-0",4J:"m[3]-0==i",5o:"m[3]-0==i",2f:"i==0",1R:"i==r.D-1",52:"i%2==0",53:"i%2","4J-32":"6.1x(a,m[3]).1m","2f-32":"6.1x(a,0).1m","1R-32":"6.1x(a,0).1R","6v-32":"6.1x(a).D==1",5v:"a.2e.D",5A:"!a.2e.D",5r:"(a.7L||a.2u).1c(m[3])>=0",6w:"a.B!=\'1V\'&&6.1g(a,\'1t\')!=\'21\'&&6.1g(a,\'4e\')!=\'1V\'",1V:"a.B==\'1V\'||6.1g(a,\'1t\')==\'21\'||6.1g(a,\'4e\')==\'1V\'",7I:"!a.2R",2R:"a.2R",34:"a.34",4f:"a.4f || 6.1r(a, \'4f\')",2V:"a.B==\'2V\'",5G:"a.B==\'5G\'",5H:"a.B==\'5H\'",4l:"a.B==\'4l\'",4L:"a.B==\'4L\'",4n:"a.B==\'4n\'",5I:"a.B==\'5I\'",4m:"a.B==\'4m\'",48:"a.B==\'48\'",5B:"a.2x.41().4U(/5B|5O|6C|48/)"},".":"6.1e.3l(a,m[2])","@":{"=":"z==m[4]","!=":"z!=m[4]","^=":"z && !z.1c(m[4])","$=":"z && z.2U(z.D - m[4].D,m[4].D)==m[4]","*=":"z && z.1c(m[4])>=0","":"z"},"[":"6.2j(m[2],a).D"},3j:["\\\\.\\\\.|/\\\\.\\\\.","a.1n",">|/","6.1x(a.1M)","\\\\+","6.1x(a).3p","~",q(a){u r=[];u s=6.1x(a);l(s.n>0)H(u i=s.n;i=1)t=t.2U(t.1c("/"),t.D)}u K=[1k];u 1J=[];u 1R=Q;2d(t.D>0&&1R!=t){u r=[];1R=t;t=6.2I(t).1A(/^\\/\\//i,"");u 3k=14;H(u i=0;i<6.3j.D;i+=2){l(3k)51;u 2o=1f 3T("^("+6.3j[i]+")");u m=2o.36(t);l(m){r=K=6.2t(K,6.3j[i+1]);t=6.2I(t.1A(2o,""));3k=V}}l(!3k){l(!t.1c(",")||!t.1c("|")){l(K[0]==1k)K.3O();1J=6.1X(1J,K);r=K=[1k];t=" "+t.2U(1,t.D)}F{u 3P=/^([#.]?)([a-4X-9\\\\*3W-]*)/i;u m=3P.36(t);l(m[1]=="#"){u 4q=15.5z(m[2]);r=K=4q?[4q]:[];t=t.1A(3P,"")}F{l(!m[2]||m[1]==".")m[2]="*";H(u i=0;i<\\/2b>");u 2b=15.5z("5V");2b.2A=q(){l(7.2Y!="1I")v;7.1n.3g(7);6.1T()};2b=Q}F l(6.18.3e){6.4r=3R(q(){l(15.2Y=="62"||15.2Y=="1I"){56(6.4r);6.4r=Q;6.1T()}},10)}6.L.1Z(1O,"2T",6.1T)};l(6.18.1y)6(1O).3J(q(){u L=6.L,1i=L.1i;H(u B 1q 1i){u 3H=1i[B],i=3H.D;l(i>0)68 l(B!=\'3J\')L.22(3H[i-1],B);2d(--i)}});6.C.1L({4z:6.C.1C,1C:q(11,G){v 11?7.1W({1z:"1C",27:"1C",1j:"1C"},11,G):7.4z()},5W:6.C.1s,1s:q(11,G){v 11?7.1W({1z:"1s",27:"1s",1j:"1s"},11,G):7.5W()},6h:q(11,G){v 7.1W({1z:"1C"},11,G)},6j:q(11,G){v 7.1W({1z:"1s"},11,G)},6k:q(11,G){v 7.U(q(){u 4B=6(7).4o(":1V")?"1C":"1s";6(7).1W({1z:4B},11,G)})},84:q(11,G){v 7.1W({1j:"1C"},11,G)},6n:q(11,G){v 7.1W({1j:"1s"},11,G)},6q:q(11,2q,G){v 7.1W({1j:2q},11,G)},1W:q(I,11,G){v 7.1w(q(){7.2P=I;H(u p 1q I){u e=1f 6.2O(7,6.11(11,G),p);l(I[p].N==4M)e.2M(e.1m(),I[p]);F e[I[p]](I)}})},1w:q(B,C){l(!C){C=B;B="2O"}v 7.U(q(){l(!7.1w)7.1w={};l(!7.1w[B])7.1w[B]=[];7.1w[B].1l(C);l(7.1w[B].D==1)C.17(7)})}});6.1L({5i:q(e,p){l(e.4K)v;l(p=="1z"&&e.4D!=3f(6.20(e,p)))v;l(p=="27"&&e.4F!=3f(6.20(e,p)))v;u a=e.1a[p];u o=6.20(e,p,1);l(p=="1z"&&e.4D!=o||p=="27"&&e.4F!=o)v;e.1a[p]=e.3t?"":"4I";u n=6.20(e,p,1);l(o!=n&&n!="4I"){e.1a[p]=a;e.4K=V}},11:q(s,o){o=o||{};l(o.N==1v)o={1I:o};u 4N={6x:6z,6A:4H};o.2F=(s&&s.N==4M?s:4N[s])||4S;o.3o=o.1I;o.1I=q(){6.4P(7,"2O");l(o.3o&&o.3o.N==1v)o.3o.17(7)};v o},1w:{},4P:q(E,B){B=B||"2O";l(E.1w&&E.1w[B]){E.1w[B].3O();u f=E.1w[B][0];l(f)f.17(E)}},2O:q(E,2m,I){u z=7;z.o={2F:2m.2F||4S,1I:2m.1I,2p:2m.2p};z.R=E;u y=z.R.1a;z.a=q(){l(2m.2p)2m.2p.17(E,[z.2a]);l(I=="1j")6.1r(y,"1j",z.2a);F l(3f(z.2a))y[I]=3f(z.2a)+"5f";y.1t="2Q"};z.57=q(){v 3Z(6.1g(z.R,I))};z.1m=q(){u r=3Z(6.20(z.R,I));v r&&r>-6R?r:z.57()};z.2M=q(4t,2q){z.42=(1f 54()).55();z.2a=4t;z.a();z.3Y=3R(q(){z.2p(4t,2q)},13)};z.1C=q(p){l(!z.R.1G)z.R.1G={};z.R.1G[I]=7.1m();l(I=="1j")z.2M(z.R.1G[I],1);F z.2M(0,z.R.1G[I]);l(I!="1j")y[I]="6Z"};z.1s=q(){l(!z.R.1G)z.R.1G={};z.R.1G[I]=7.1m();z.o.1s=V;z.2M(z.R.1G[I],0)};l(!z.R.71)z.R.59=6.1g(z.R,"39");y.39="1V";z.2p=q(47,46){u t=(1f 54()).55();l(t>z.o.2F+z.42){56(z.3Y);z.3Y=Q;z.2a=46;z.a();z.R.2P[I]=V;u 1J=V;H(u i 1q z.R.2P)l(z.R.2P[i]!==V)1J=14;l(1J){y.39=z.R.59;l(z.o.1s)y.1t=\'21\';l(z.o.1s){H(u p 1q z.R.2P){l(p=="1j"&&6.18.1y)6.1r(y,p,z.R.1G[p]);F y[p]=z.R.1G[p]+"5f";l(p==\'1z\'||p==\'27\')6.5i(z.R,p)}}}l(1J&&z.o.1I&&z.o.1I.N==1v)z.o.1I.17(z.R)}F{u p=(t-7.42)/z.o.2F;z.2a=((-5t.7m(p*5t.7q)/2)+0.5)*(46-47)+47;z.a()}}}});6.C.1L({7v:q(M,1K,G){7.2T(M,1K,G,1)},2T:q(M,1K,G,1E){l(M.N==1v)v 7.3B("2T",M);G=G||q(){};u B="4d";l(1K){l(1K.N==1v){G=1K;1K=Q}F{1K=6.2C(1K);B="4x"}}u 3q=7;6.3C(B,M,1K,q(3r,12){l(12=="2w"||!1E&&12=="5s"){3q.5y(3r.2Z).U(G,[3r.2Z,12]);6("2b",3q).U(q(){l(7.3m)6.4v(7.3m);F 37.4i(1O,7.2V||7.7A||7.2u||"")})}F G.17(3q,[3r.2Z,12])},1E);v 7},7F:q(){v 6.2C(7)}});l(6.18.1y&&1Y 3b=="P")3b=q(){v 1f 7K(5J.5K.1c("7R 5")>=0?"7U.5P":"7W.5P")};1f q(){u e="4G,5M,5F,5D,5x".3y(",");H(u i=0;i-1)?"&":"?")+6.2C(J);6.3C("4d",M,Q,q(r,12){l(G)G(6.3n(r,B),12)},1E)},5Z:q(M,J,G,B){6.1o(M,J,G,B,1)},4v:q(M,G){6.1o(M,G,"2b")},64:q(M,J,G){l(G)6.1o(M,J,G,"3S");F{6.1o(M,J,"3S")}},6b:q(M,J,G,B){6.3C("4x",M,6.2C(J),q(r,12){l(G)G(6.3n(r,B),12)})},1u:0,6i:q(1u){6.1u=1u},38:{},3C:q(B,M,J,K,1E){l(!M){K=B.1I;u 2w=B.2w;u 2k=B.2k;u 49=B.49;u 1i=1Y B.1i=="85"?B.1i:V;u 1u=1Y B.1u=="6s"?B.1u:6.1u;u 1E=B.1E||14;J=B.J;M=B.M;B=B.B}l(1i&&!6.3I++)6.L.1Q("4G");u 4p=14;u O=1f 3b();O.6y(B||"4d",M,V);l(J)O.30("6D-6E","6F/x-6J-6L-6O");l(1E)O.30("6S-40-6V",6.38[M]||"6W, 6Y 70 72 3V:3V:3V 73");O.30("X-74-75","3b");l(O.78)O.30("7c","7g");u 2A=q(43){l(O&&(O.2Y==4||43=="1u")){4p=V;u 12=6.4y(O)&&43!="1u"?1E&&6.4Q(O,M)?"5s":"2w":"2k";l(12!="2k"){u 3F;3x{3F=O.4b("4T-40")}3h(e){}l(1E&&3F)6.38[M]=3F;l(2w)2w(6.3n(O,49),12);l(1i)6.L.1Q("5x")}F{l(2k)2k(O,12);l(1i)6.L.1Q("5D")}l(1i)6.L.1Q("5F");l(1i&&!--6.3I)6.L.1Q("5M");l(K)K(O,12);O.2A=q(){};O=Q}};O.2A=2A;l(1u>0)7X(q(){l(O){O.82();l(!4p)2A("1u");O=Q}},1u);O.65(J)},3I:0,4y:q(r){3x{v!r.12&&6l.6m=="4l:"||(r.12>=4H&&r.12<6B)||r.12==4W||6.18.3e&&r.12==P}3h(e){}v 14},4Q:q(O,M){3x{u 50=O.4b("4T-40");v O.12==4W||50==6.38[M]||6.18.3e&&O.12==P}3h(e){}v 14},3n:q(r,B){u 4k=r.4b("7G-B");u J=!B&&4k&&4k.1c("O")>=0;J=B=="O"||J?r.8j:r.2Z;l(B=="2b")37.4i(1O,J);l(B=="3S")37("J = "+J);v J},2C:q(a){u s=[];l(a.N==2y||a.2J){H(u i=0;i '+ - '
'; + $(this.element).html('
'+ + '
 
'+ + '
'); } /** * Set the percentage and status message for the progressbar. */ -progressBar.prototype.setProgress = function (percentage, message) { - var divs = this.element.getElementsByTagName('div'); - var div; - for (var i = 0; div = divs[i]; ++i) { - if (percentage >= 0) { - if (hasClass(divs[i], 'filled')) { - divs[i].style.width = percentage + '%'; - } - if (hasClass(divs[i], 'percentage')) { - divs[i].innerHTML = percentage + '%'; - } - } - if (hasClass(divs[i], 'message')) { - divs[i].innerHTML = message; - } +Drupal.progressBar.prototype.setProgress = function (percentage, message) { + if (percentage >= 0 && percentage <= 100) { + $('div.filled', this.element).css('width', percentage +'%'); + $('div.percentage', this.element).html(percentage +'%'); } + $('div.message', this.element).html(message); if (this.updateCallback) { this.updateCallback(percentage, message, this); } @@ -52,7 +42,7 @@ function progressBar(id, updateCallback, /** * Start monitoring progress via Ajax. */ -progressBar.prototype.startMonitoring = function (uri, delay) { +Drupal.progressBar.prototype.startMonitoring = function (uri, delay) { this.delay = delay; this.uri = uri; this.sendPing(); @@ -61,7 +51,7 @@ function progressBar(id, updateCallback, /** * Stop monitoring progress via Ajax. */ -progressBar.prototype.stopMonitoring = function () { +Drupal.progressBar.prototype.stopMonitoring = function () { clearTimeout(this.timer); // This allows monitoring to be stopped from within the callback this.uri = null; @@ -70,47 +60,44 @@ function progressBar(id, updateCallback, /** * Request progress data from server. */ -progressBar.prototype.sendPing = function () { +Drupal.progressBar.prototype.sendPing = function () { if (this.timer) { clearTimeout(this.timer); } if (this.uri) { - this.method(this.uri, this.receivePing, this, ''); - } -} - -/** - * HTTP callback function. Passes data back to the progressbar and sets a new - * timer for the next ping. - */ -progressBar.prototype.receivePing = function (string, xmlhttp, pb) { - if (xmlhttp.status != 200) { - return pb.displayError('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri); - } - // Parse response - var progress = parseJson(string); - // Display errors - if (progress.status == 0) { - pb.displayError(progress.data); - return; + var pb = this; + $.ajax({ + type: this.method, + url: this.uri, + success: function (data) { + // Parse response + var progress = Drupal.parseJson(data); + // Display errors + if (progress.status == 0) { + pb.displayError(progress.data); + return; + } + // Update display + pb.setProgress(progress.percentage, progress.message); + // Schedule next timer + pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay); + }, + error: function (xmlhttp) { + pb.displayError('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri); + } + }); } - - // Update display - pb.setProgress(progress.percentage, progress.message); - // Schedule next timer - pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay); } /** * Display errors on the page. */ -progressBar.prototype.displayError = function (string) { +Drupal.progressBar.prototype.displayError = function (string) { var error = document.createElement('div'); error.className = 'error'; error.innerHTML = string; - this.element.style.display = 'none'; - this.element.parentNode.insertBefore(error, this.element); + $(this.element).before(error).hide(); if (this.errorCallback) { this.errorCallback(this); Index: misc/textarea.js =================================================================== RCS file: /cvs/drupal/drupal/misc/textarea.js,v retrieving revision 1.9 diff -u -F^f -r1.9 textarea.js --- misc/textarea.js 14 Apr 2006 13:48:56 -0000 1.9 +++ misc/textarea.js 14 Oct 2006 07:56:19 -0000 @@ -1,122 +1,34 @@ -// $Id: textarea.js,v 1.9 2006/04/14 13:48:56 killes Exp $ +// $Id: textarea.js,v 1.11 2006/09/07 08:05:31 dries Exp $ -if (isJsEnabled()) { - addLoadEvent(textAreaAutoAttach); -} - -function textAreaAutoAttach(event, parent) { - if (typeof parent == 'undefined') { - // Attach to all visible textareas. - textareas = document.getElementsByTagName('textarea'); - } - else { - // Attach to all visible textareas inside parent. - textareas = parent.getElementsByTagName('textarea'); - } - var textarea; - for (var i = 0; textarea = textareas[i]; ++i) { - if (hasClass(textarea, 'resizable') && !hasClass(textarea.nextSibling, 'grippie')) { - if (typeof dimensions(textarea).width != 'undefined' && dimensions(textarea).width != 0) { - new textArea(textarea); - } +Drupal.textareaAttach = function() { + $('textarea.resizable:not(.processed)').each(function() { + var textarea = $(this).addClass('processed'), staticOffset = null; + + $(this).wrap('
') + .parent().append($('
').mousedown(startDrag)); + + var grippie = $('div.grippie', $(this).parent())[0]; + grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px'; + + function startDrag(e) { + staticOffset = textarea.height() - Drupal.mousePosition(e).y; + textarea.css('opacity', 0.25); + $(document).mousemove(performDrag).mouseup(endDrag); + return false; } - } -} - -function textArea(element) { - var ta = this; - this.element = element; - this.parent = this.element.parentNode; - this.dimensions = dimensions(element); - - // Prepare wrapper - this.wrapper = document.createElement('div'); - this.wrapper.className = 'resizable-textarea'; - this.parent.insertBefore(this.wrapper, this.element); - - // Add grippie and measure it - this.grippie = document.createElement('div'); - this.grippie.className = 'grippie'; - this.wrapper.appendChild(this.grippie); - this.grippie.dimensions = dimensions(this.grippie); - this.grippie.onmousedown = function (e) { ta.beginDrag(e); }; - - // Set wrapper and textarea dimensions - this.wrapper.style.height = this.dimensions.height + this.grippie.dimensions.height + 1 +'px'; - this.element.style.marginBottom = '0px'; - this.element.style.width = '100%'; - this.element.style.height = this.dimensions.height +'px'; - - // Wrap textarea - removeNode(this.element); - this.wrapper.insertBefore(this.element, this.grippie); - - // Measure difference between desired and actual textarea dimensions to account for padding/borders - this.widthOffset = dimensions(this.wrapper).width - this.dimensions.width; - - // Make the grippie line up in various browsers - if (window.opera) { - // Opera - this.grippie.style.marginRight = '4px'; - } - if (document.all && !window.opera) { - // IE - this.grippie.style.width = '100%'; - this.grippie.style.paddingLeft = '2px'; - } - // Mozilla - this.element.style.MozBoxSizing = 'border-box'; - - this.heightOffset = absolutePosition(this.grippie).y - absolutePosition(this.element).y - this.dimensions.height; -} - -textArea.prototype.beginDrag = function (event) { - if (document.isDragging) { - return; - } - document.isDragging = true; - - event = event || window.event; - // Capture mouse - var cp = this; - this.oldMoveHandler = document.onmousemove; - document.onmousemove = function(e) { cp.handleDrag(e); }; - this.oldUpHandler = document.onmouseup; - document.onmouseup = function(e) { cp.endDrag(e); }; - - // Store drag offset from grippie top - var pos = absolutePosition(this.grippie); - this.dragOffset = event.clientY - pos.y; - // Make transparent - this.element.style.opacity = 0.5; - - // Process - this.handleDrag(event); -} - -textArea.prototype.handleDrag = function (event) { - event = event || window.event; - // Get coordinates relative to text area - var pos = absolutePosition(this.element); - var y = event.clientY - pos.y; - - // Set new height - var height = Math.max(32, y - this.dragOffset - this.heightOffset); - this.wrapper.style.height = height + this.grippie.dimensions.height + 1 + 'px'; - this.element.style.height = height + 'px'; + function performDrag(e) { + textarea.height(Math.max(32, staticOffset + Drupal.mousePosition(e).y) + 'px'); + return false; + } - // Avoid text selection - stopEvent(event); + function endDrag(e) { + $(document).unmousemove(performDrag).unmouseup(endDrag); + textarea.css('opacity', 1); + } + }); } -textArea.prototype.endDrag = function (event) { - // Uncapture mouse - document.onmousemove = this.oldMoveHandler; - document.onmouseup = this.oldUpHandler; - - // Restore opacity - this.element.style.opacity = 1.0; - document.isDragging = false; +if (Drupal.jsEnabled) { + $(document).ready(Drupal.textareaAttach); } - Index: misc/update.js =================================================================== RCS file: /cvs/drupal/drupal/misc/update.js,v retrieving revision 1.8 diff -u -F^f -r1.8 update.js --- misc/update.js 28 Mar 2006 09:29:23 -0000 1.8 +++ misc/update.js 14 Oct 2006 07:56:19 -0000 @@ -1,12 +1,11 @@ -// $Id: update.js,v 1.8 2006/03/28 09:29:23 killes Exp $ +// $Id: update.js,v 1.9 2006/08/31 23:31:25 unconed Exp $ -if (isJsEnabled()) { - addLoadEvent(function() { - if ($('edit-has_js')) { - $('edit-has_js').value = 1; - } +if (Drupal.jsEnabled) { + $(document).ready(function() { + $('#edit-has_js').each(function() { this.value = 1; }); + $('#progress').each(function () { + var holder = this; - if ($('progress')) { // Success: redirect to the summary. var updateCallback = function (progress, status, pb) { if (progress == 100) { @@ -19,15 +18,15 @@ var errorCallback = function (pb) { var div = document.createElement('p'); div.className = 'error'; - div.innerHTML = 'An unrecoverable error has occured. You can find the error message below. It is advised to copy it to the clipboard for reference. Please continue to the update summary'; - $('progress').insertBefore(div, $('progress').firstChild); - $('wait').style.display = 'none'; + $(div).html('An unrecoverable error has occured. You can find the error message below. It is advised to copy it to the clipboard for reference. Please continue to the update summary'); + $(holder).prepend(div); + $('#wait').hide(); } - var progress = new progressBar('updateprogress', updateCallback, HTTPPost, errorCallback); + var progress = new Drupal.progressBar('updateprogress', updateCallback, "POST", errorCallback); progress.setProgress(-1, 'Starting updates'); - $('progress').appendChild(progress.element); + $(holder).append(progress.element); progress.startMonitoring('update.php?op=do_update', 0); - } + }); }); } Index: misc/upload.js =================================================================== RCS file: /cvs/drupal/drupal/misc/upload.js,v retrieving revision 1.8.2.1 diff -u -F^f -r1.8.2.1 upload.js --- misc/upload.js 5 May 2006 11:57:19 -0000 1.8.2.1 +++ misc/upload.js 14 Oct 2006 07:56:19 -0000 @@ -1,75 +1,116 @@ -// $Id: upload.js,v 1.8.2.1 2006/05/05 11:57:19 killes Exp $ - -// Global killswitch -if (isJsEnabled()) { - addLoadEvent(uploadAutoAttach); -} +// $Id: upload.js,v 1.11 2006/08/31 23:31:25 unconed Exp $ /** * Attaches the upload behaviour to the upload form. */ -function uploadAutoAttach() { - var inputs = document.getElementsByTagName('input'); - for (i = 0; input = inputs[i]; i++) { - if (input && hasClass(input, 'upload')) { - var uri = input.value; - // Extract the button ID based on a substring of the input name: edit[foo][bar] -> foo-bar - var button = input.name.substr(5, input.name.length - 6).replace('][', '-'); - var wrapper = button + '-wrapper'; - var hide = button + '-hide'; - var upload = new jsUpload(uri, button, wrapper, hide); - } - } +Drupal.uploadAutoAttach = function() { + $('input.upload').each(function () { + var uri = this.value; + // Extract the base name from the id (edit-attach-url -> attach). + var base = this.id.substring(5, this.id.length - 4); + var button = base + '-button'; + var wrapper = base + '-wrapper'; + var hide = base + '-hide'; + var upload = new Drupal.jsUpload(uri, button, wrapper, hide); + }); } /** * JS upload object. */ -function jsUpload(uri, button, wrapper, hide) { - this.button = button; - this.wrapper = wrapper; - this.hide = hide; - redirectFormButton(uri, $(button), this); +Drupal.jsUpload = function(uri, button, wrapper, hide) { + // Note: these elements are replaced after an upload, so we re-select them + // everytime they are needed. + this.button = '#'+ button; + this.wrapper = '#'+ wrapper; + this.hide = '#'+ hide; + Drupal.redirectFormButton(uri, $(this.button).get(0), this); } /** * Handler for the form redirection submission. */ -jsUpload.prototype.onsubmit = function () { - var hide = $(this.hide); +Drupal.jsUpload.prototype.onsubmit = function () { // Insert progressbar and stretch to take the same space. - this.progress = new progressBar('uploadprogress'); + this.progress = new Drupal.progressBar('uploadprogress'); this.progress.setProgress(-1, 'Uploading file'); - this.progress.element.style.width = '28em'; - this.progress.element.style.height = hide.offsetHeight +'px'; - hide.parentNode.insertBefore(this.progress.element, hide); - // Hide file form (cannot use display: none, this mysteriously aborts form - // submission in Konqueror) - hide.style.position = 'absolute'; - hide.style.left = '-2000px'; + + var hide = this.hide; + var el = this.progress.element; + var offset = $(hide).get(0).offsetHeight; + $(el).css({ + width: '28em', + height: offset +'px', + paddingTop: '10px', + display: 'none' + }); + $(hide).css('position', 'absolute'); + + $(hide).after(el); + $(el).fadeIn('slow'); + $(hide).fadeOut('slow'); } /** * Handler for the form redirection completion. */ -jsUpload.prototype.oncomplete = function (data) { - // Remove progressbar - removeNode(this.progress.element); - this.progress = null; - // Replace form and re-attach behaviour - $(this.wrapper).innerHTML = data; - uploadAutoAttach(); +Drupal.jsUpload.prototype.oncomplete = function (data) { + // Remove old form + Drupal.freezeHeight(); // Avoid unnecessary scrolling + $(this.wrapper).html(''); + + // Place HTML into temporary div + var div = document.createElement('div'); + $(div).html(data); + + // If uploading the first attachment fade in everything + if ($('tr', div).size() == 2) { + // Replace form and re-attach behaviour + $(div).hide(); + $(this.wrapper).append(div); + $(div).fadeIn('slow'); + Drupal.uploadAutoAttach(); + } + // Else fade in only the last table row + else { + // Hide form and last table row + $('table tr:last-of-type td', div).hide(); + + // Note: workaround because jQuery's #id selector does not work outside of 'document' + // Should be: $(this.hide, div).hide(); + var hide = this.hide; + $('div', div).each(function() { + if (('#'+ this.id) == hide) { + this.style.display = 'none'; + } + }); + + // Replace form, fade in items and re-attach behaviour + $(this.wrapper).append(div); + $('table tr:last-of-type td', div).fadeIn('slow'); + $(this.hide, div).fadeIn('slow'); + Drupal.uploadAutoAttach(); + } + Drupal.unfreezeHeight(); } /** * Handler for the form redirection error. */ -jsUpload.prototype.onerror = function (error) { +Drupal.jsUpload.prototype.onerror = function (error) { alert('An error occurred:\n\n'+ error); // Remove progressbar - removeNode(this.progress.element); + $(this.progress.element).remove(); this.progress = null; // Undo hide - $(this.hide).style.position = 'static'; - $(this.hide).style.left = '0px'; + $(this.hide).css({ + position: 'static', + left: '0px' + }); +} + + +// Global killswitch +if (Drupal.jsEnabled) { + $(document).ready(Drupal.uploadAutoAttach); }