Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.549
diff -u -d -F^function -r1.549 common.inc
--- includes/common.inc 19 Jul 2006 07:45:35 -0000 1.549
+++ includes/common.inc 23 Jul 2006 15:58:10 -0000
@@ -1224,10 +1224,19 @@ function drupal_add_link($attributes) {
* Add a JavaScript file to the output.
*
* 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.
+ * it adds "misc/drupal.js" and "misc/jquery.js" to the output for other
+ * scripts to use.
*/
function drupal_add_js($file, $nocache = FALSE) {
+ _drupal_add_js('misc/jquery.js', FALSE);
+ _drupal_add_js('misc/drupal.js', FALSE);
+ _drupal_add_js($file, $nocache);
+}
+
+/**
+ * Helper function for drupal_add_js()
+ */
+function _drupal_add_js($file, $nocache) {
static $sent = array();
$postfix = $nocache ? '?'. time() : '';
Index: misc/autocomplete.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/autocomplete.js,v
retrieving revision 1.12
diff -u -d -F^function -r1.12 autocomplete.js
--- misc/autocomplete.js 20 May 2006 07:23:47 -0000 1.12
+++ misc/autocomplete.js 23 Jul 2006 15:58:10 -0000
@@ -2,7 +2,7 @@
// Global Killswitch
if (isJsEnabled()) {
- addLoadEvent(autocompleteAutoAttach);
+ $(document).ready(autocompleteAutoAttach);
}
/**
@@ -10,34 +10,29 @@
*/
function autocompleteAutoAttach() {
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 ACDB(uri);
}
- }
+ var input = $('#' + this.id.substr(0, this.id.length - 13))
+ .set('autocomplete', 'OFF')
+ .get(0);
+ $(input.form).submit(autocompleteSubmit);
+ new 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;
+ return $('#autocomplete').each(function () {
+ this.owner.hidePopup();
+ }).size() == 0;
}
-
/**
* An AutoComplete object
*/
@@ -45,27 +40,13 @@ function jsAC(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
@@ -138,9 +119,9 @@ function jsAC(input, db) {
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));
}
}
}
@@ -158,8 +139,10 @@ function jsAC(input, db) {
* Highlights a suggestion
*/
jsAC.prototype.highlight = function (node) {
- removeClass(this.selected, 'selected');
- addClass(node, 'selected');
+ if (this.selected) {
+ $(this.selected).removeClass('selected');
+ }
+ $(node).addClass('selected');
this.selected = node;
}
@@ -167,7 +150,24 @@ function jsAC(input, db) {
* Unhighlights a suggestion
*/
jsAC.prototype.unhighlight = function (node) {
- removeClass(node, 'selected');
+ $(node).removeClass('selected');
+ this.selected = false;
+}
+
+/**
+ * Hides the autocomplete suggestions
+ */
+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;
}
@@ -175,12 +175,24 @@ function jsAC(input, db) {
* Positions the suggestions popup and starts a search
*/
jsAC.prototype.populatePopup = function () {
- var ac = this;
+ // Show popup
+ if (this.popup) {
+ $(this.popup).remove();
+ }
var pos = 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);
}
@@ -189,29 +201,23 @@ 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);
- }
+ // 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.hidePopup();
@@ -221,12 +227,12 @@ function jsAC(input, db) {
jsAC.prototype.setStatus = function (status) {
switch (status) {
case 'begin':
- addClass(this.input, 'throbbing');
+ $(this.input).addClass('throbbing');
break;
case 'cancel':
case 'error':
case 'found':
- removeClass(this.input, 'throbbing');
+ $(this.input).removeClass('throbbing');
break;
}
}
@@ -244,36 +250,42 @@ function ACDB(uri) {
* Performs a cached and delayed search
*/
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() {
db.owner.setStatus('begin');
- db.transport = HTTPGet(db.uri +'/'+ encodeURIComponent(searchString), db.receive, db);
- }, this.delay);
-}
-/**
- * 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') {
- acdb.owner.setStatus('error');
- 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);
- acdb.owner.setStatus('found');
- }
+ // Ajax GET request for autocompletion
+ $.ajax({
+ type: "GET",
+ url: db.uri +'/'+ encodeURIComponent(searchString),
+ success: function (xmlhttp) {
+ // Parse back result
+ var matches = parseJson(xmlhttp.responseText);
+ 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);
}
/**
@@ -282,8 +294,5 @@ function ACDB(uri) {
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 = '';
}
Index: misc/collapse.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/collapse.js,v
retrieving revision 1.6
diff -u -d -F^function -r1.6 collapse.js
--- misc/collapse.js 14 Apr 2006 13:48:56 -0000 1.6
+++ misc/collapse.js 23 Jul 2006 15:58:11 -0000
@@ -1,59 +1,84 @@
// $Id: collapse.js,v 1.6 2006/04/14 13:48:56 killes Exp $
if (isJsEnabled()) {
- addLoadEvent(collapseAutoAttach);
+ $(document).ready(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];
+ $('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;
}
- }
- this.blur();
- return false;
- };
- a.innerHTML = legend.innerHTML;
- while (legend.hasChildNodes()) {
- removeNode(legend.childNodes[0]);
+ fieldset.animating = true;
+
+ if ($(fieldset).is('.collapsed')) {
+ // Open fieldset with animation
+ $(fieldset.contentWrapper).hide();
+ $(fieldset).removeClass('collapsed');
+ $(fieldset.contentWrapper).slideDown('medium',
+ {
+ // Make sure we open to height auto
+ complete: function() {
+ $(fieldset.contentWrapper).css('height', 'auto');
+ collapseScrollIntoView(fieldset);
+ fieldset.animating = false;
+ },
+ // Scroll the fieldset into view
+ step: function() {
+ collapseScrollIntoView(fieldset);
+ }
+ }
+ );
+ if (typeof textAreaAutoAttach != 'undefined') {
+ // Initialize resizable textareas that are now revealed
+ textAreaAutoAttach(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;
+ })
+ .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) {
+ $(fieldset).removeClass('collapsed');
}
- }
+ });
}
function collapseScrollIntoView(node) {
Index: misc/drupal.css
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.css,v
retrieving revision 1.151
diff -u -d -F^function -r1.151 drupal.css
--- misc/drupal.css 30 Jun 2006 00:13:32 -0000 1.151
+++ misc/drupal.css 23 Jul 2006 15:58:11 -0000
@@ -632,23 +632,27 @@
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.collapsed legend *,
+* html.js fieldset.collapsed table * {
+ display: inline;
+}
* html.js fieldset.collapsible legend a {
display: block;
}
Index: misc/drupal.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.js,v
retrieving revision 1.24
diff -u -d -F^function -r1.24 drupal.js
--- misc/drupal.js 7 Jun 2006 09:34:11 -0000 1.24
+++ misc/drupal.js 23 Jul 2006 15:58:12 -0000
@@ -22,99 +22,13 @@ function isJsEnabled() {
}
/**
- * Make IE's XMLHTTP object accessible through XMLHttpRequest()
- */
-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!");
- }
-}
-
-/**
- * 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().
- */
-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) {
- if (callbackFunction) {
- 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]);
- }
- }
- else {
- toSend = object;
- }
- xmlHttp.send(toSend);
-
- if (bAsync) {
- if (callbackFunction) {
- xmlHttp.onreadystatechange = function() {
- if (xmlHttp.readyState == 4) {
- callbackFunction(xmlHttp.responseText, xmlHttp, callbackParameter);
- }
- }
- }
- 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();
+ // Give any previous onsubmit time to complete
+ window.setTimeout(createIframe, 100);
// Trap the button
button.onmouseover = button.onfocus = function() {
@@ -124,7 +38,7 @@ function redirectFormButton(uri, button,
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';
@@ -132,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;
@@ -151,8 +65,7 @@ function redirectFormButton(uri, button,
response = null;
}
- $('redirect-target').onload = null;
- $('redirect-target').src = 'about:blank';
+ iframe.onload = null;
response = parseJson(response);
// Check response code
@@ -161,6 +74,8 @@ function redirectFormButton(uri, button,
return;
}
handler.oncomplete(response.data);
+
+ return true;
}
return true;
@@ -172,37 +87,6 @@ function redirectFormButton(uri, button,
}
/**
- * 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) {
@@ -228,75 +112,6 @@ function dimensions(el) {
}
/**
- * Returns true if an element has a specified class name
- */
-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;
- }
-}
-
-/**
* Prevents an event from propagating.
*/
function stopEvent(event) {
@@ -327,41 +142,48 @@ function parseJson(data) {
*/
function createIframe() {
// Delete any previous iframe
- deleteIframe();
+ $('#redirect-holder').remove();
// 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)
+ .set({
+ 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.
+ * Freeze the current body height (as minimum height). Used to prevent
+ * unnecessary upwards scrolling when doing DOM manipulations.
*/
-function deleteIframe() {
- var holder = $('redirect-holder');
- if (holder != null) {
- removeNode(holder);
- }
+function freezeHeight() {
+ unfreezeHeight();
+ var div = document.createElement('div');
+ $(div).css({
+ position: 'absolute',
+ top: '0px',
+ left: '0px',
+ width: '1px',
+ height: $('body').css('height') +'px'
+ }).set('id', 'freeze-height');
+ $('body').append(div);
}
/**
- * Wrapper around document.getElementById().
+ * Unfreeze the body height
*/
-function $(id) {
- return document.getElementById(id);
-}
+function unfreezeHeight() {
+ $('#freeze-height').remove();
+}
\ No newline at end of file
Index: misc/progress.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/progress.js,v
retrieving revision 1.10
diff -u -d -F^function -r1.10 progress.js
--- misc/progress.js 28 Mar 2006 09:29:23 -0000 1.10
+++ misc/progress.js 23 Jul 2006 15:58:12 -0000
@@ -5,7 +5,7 @@
* the DOM afterwards through progressBar.element.
*
* method is the function which will perform the HTTP request to get the
- * progress bar state. Either HTTPGet or HTTPPost.
+ * progress bar state. Either "GET" or "POST".
*
* e.g. pb = new progressBar('myProgressBar');
* some_element.appendChild(pb.element);
@@ -13,37 +13,27 @@
function progressBar(id, updateCallback, method, errorCallback) {
var pb = this;
this.id = id;
- this.method = method ? method : HTTPGet;
+ this.method = method || "GET";
this.updateCallback = updateCallback;
this.errorCallback = errorCallback;
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'progress';
- this.element.innerHTML = ''+
- '
'+
- '';
+ $(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;
- }
+ 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);
}
@@ -75,30 +65,28 @@ function progressBar(id, updateCallback,
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 (xmlhttp) {
+ // Parse response
+ var progress = parseJson(xmlhttp.responseText);
+ // 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);
}
/**
@@ -109,8 +97,7 @@ function progressBar(id, updateCallback,
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 -d -F^function -r1.9 textarea.js
--- misc/textarea.js 14 Apr 2006 13:48:56 -0000 1.9
+++ misc/textarea.js 23 Jul 2006 15:58:12 -0000
@@ -1,55 +1,48 @@
// $Id: textarea.js,v 1.9 2006/04/14 13:48:56 killes Exp $
if (isJsEnabled()) {
- addLoadEvent(textAreaAutoAttach);
+ $(document).ready(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);
- }
+ $('textarea.resizable', parent).each(function() {
+ if (!this.resizable
+ && typeof dimensions(this).width != 'undefined'
+ && dimensions(this).width != 0) {
+ new textArea(this);
}
- }
+ });
}
function textArea(element) {
var ta = this;
this.element = element;
- this.parent = this.element.parentNode;
+ this.element.resizable = true;
this.dimensions = dimensions(element);
// Prepare wrapper
this.wrapper = document.createElement('div');
this.wrapper.className = 'resizable-textarea';
- this.parent.insertBefore(this.wrapper, this.element);
+ $(this.element).before(this.wrapper);
// Add grippie and measure it
this.grippie = document.createElement('div');
this.grippie.className = 'grippie';
- this.wrapper.appendChild(this.grippie);
+ $(this.wrapper).append(this.grippie);
this.grippie.dimensions = dimensions(this.grippie);
- this.grippie.onmousedown = function (e) { ta.beginDrag(e); };
+ $(this.grippie).mousedown(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';
+ $(this.wrapper).css('height', this.dimensions.height + this.grippie.dimensions.height + 1 +'px');
+ $(this.element).css({
+ marginBottom: '0px',
+ width: '100%',
+ height: this.dimensions.height +'px'
+ });
// Wrap textarea
- removeNode(this.element);
- this.wrapper.insertBefore(this.element, this.grippie);
+ $(this.element).remove();
+ $(this.grippie).before(this.element);
// Measure difference between desired and actual textarea dimensions to account for padding/borders
this.widthOffset = dimensions(this.wrapper).width - this.dimensions.width;
@@ -57,15 +50,17 @@ function textArea(element) {
// Make the grippie line up in various browsers
if (window.opera) {
// Opera
- this.grippie.style.marginRight = '4px';
+ $(this.grippie).css('marginRight', '4px');
}
if (document.all && !window.opera) {
// IE
- this.grippie.style.width = '100%';
- this.grippie.style.paddingLeft = '2px';
+ $(this.grippie).css({
+ width: '100%',
+ paddingLeft: '2px'
+ });
}
// Mozilla
- this.element.style.MozBoxSizing = 'border-box';
+ $(this.element).css('MozBoxSizing', 'border-box');
this.heightOffset = absolutePosition(this.grippie).y - absolutePosition(this.element).y - this.dimensions.height;
}
@@ -89,7 +84,7 @@ function textArea(element) {
this.dragOffset = event.clientY - pos.y;
// Make transparent
- this.element.style.opacity = 0.5;
+ $(this.element).css('opacity', '0.5');
// Process
this.handleDrag(event);
@@ -116,7 +111,6 @@ function textArea(element) {
document.onmouseup = this.oldUpHandler;
// Restore opacity
- this.element.style.opacity = 1.0;
+ $(this.element).css('opacity', '1.0');
document.isDragging = false;
-}
-
+}
\ No newline at end of file
Index: misc/update.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/update.js,v
retrieving revision 1.8
diff -u -d -F^function -r1.8 update.js
--- misc/update.js 28 Mar 2006 09:29:23 -0000 1.8
+++ misc/update.js 23 Jul 2006 15:58:12 -0000
@@ -1,12 +1,11 @@
// $Id: update.js,v 1.8 2006/03/28 09:29:23 killes Exp $
if (isJsEnabled()) {
- addLoadEvent(function() {
- if ($('edit-has_js')) {
- $('edit-has_js').value = 1;
- }
+ $(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 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.9
diff -u -d -F^function -r1.9 upload.js
--- misc/upload.js 5 May 2006 10:47:20 -0000 1.9
+++ misc/upload.js 23 Jul 2006 15:58:12 -0000
@@ -2,63 +2,104 @@
// Global killswitch
if (isJsEnabled()) {
- addLoadEvent(uploadAutoAttach);
+ $(document).ready(uploadAutoAttach);
}
/**
* 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);
- }
- }
+ $('input.upload').each(function () {
+ var uri = this.value;
+ // Extract the button ID based on a substring of the input name: edit[foo][bar] -> foo-bar
+ var button = this.name.substr(5, this.name.length - 6).replace('][', '-');
+ var wrapper = button + '-wrapper';
+ var hide = button + '-hide';
+ var upload = new 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);
+ // 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;
+ redirectFormButton(uri, $(this.button).get(0), this);
}
/**
* Handler for the form redirection submission.
*/
jsUpload.prototype.onsubmit = function () {
- var hide = $(this.hide);
// Insert progressbar and stretch to take the same space.
this.progress = new 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';
+ $(this.progress.element).css({
+ width: '28em',
+ height: ($(this.hide).get(0).offsetHeight - 10) +'px',
+ marginBottom: -$(this.hide).get(0).offsetHeight +'px',
+ paddingTop: '10px',
+ display: 'none'
+ });
+
+ // Hide file form and replace by progress bar (cannot use display: none,
+ // this mysteriously aborts form submission in Konqueror)
+/* $(this.hide)
+ .css({
+ position: 'absolute',
+ left: '-2000px'
+ })
+ .before(this.progress.element);
+*/
+ $(this.hide).before(this.progress.element).fadeOut('slow');
+ $(this.progress.element).fadeIn('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();
+ // Remove old form
+ 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');
+ 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');
+ uploadAutoAttach();
+ }
+ unfreezeHeight();
}
/**
@@ -67,9 +108,11 @@ function jsUpload(uri, button, wrapper,
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'
+ });
}