From c11cb4ec24479e801076c094f043f2084b344d0c Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Sun, 1 Jul 2007 15:37:10 +0000 Subject: - Patch #120360 by nedjo: enable AJAX by making all behaviours reattachable. --- misc/autocomplete.js | 10 ++---- misc/batch.js | 61 +++++++++++++++++++---------------- misc/collapse.js | 34 +++++++++----------- misc/drupal.js | 41 ++++++++++++++++++++++- misc/tableheader.js | 91 +++++++++++++++++++++++++--------------------------- misc/tableselect.js | 12 +++---- misc/teaser.js | 10 ++---- misc/textarea.js | 10 ++---- misc/upload.js | 16 +++------ 9 files changed, 152 insertions(+), 133 deletions(-) (limited to 'misc') diff --git a/misc/autocomplete.js b/misc/autocomplete.js index 2431d37e4..844b628cc 100644 --- a/misc/autocomplete.js +++ b/misc/autocomplete.js @@ -3,9 +3,9 @@ /** * Attaches the autocomplete behaviour to all required fields */ -Drupal.autocompleteAutoAttach = function () { +Drupal.behaviors.autocomplete = function (context) { var acdb = []; - $('input.autocomplete').each(function () { + $('input.autocomplete:not(.autocomplete-processed)', context).each(function () { var uri = this.value; if (!acdb[uri]) { acdb[uri] = new Drupal.ACDB(uri); @@ -14,6 +14,7 @@ Drupal.autocompleteAutoAttach = function () { .attr('autocomplete', 'OFF')[0]; $(input.form).submit(Drupal.autocompleteSubmit); new Drupal.jsAC(input, acdb[uri]); + $(this).addClass('autocomplete-processed'); }); }; @@ -296,8 +297,3 @@ Drupal.ACDB.prototype.cancel = function() { if (this.timer) clearTimeout(this.timer); this.searchString = ''; }; - -// Global Killswitch -if (Drupal.jsEnabled) { - $(document).ready(Drupal.autocompleteAutoAttach); -} diff --git a/misc/batch.js b/misc/batch.js index 8cf1f910f..51b1e8b59 100644 --- a/misc/batch.js +++ b/misc/batch.js @@ -1,31 +1,38 @@ -if (Drupal.jsEnabled) { - $(document).ready(function() { - $('#progress').each(function () { - var holder = this; - var uri = Drupal.settings.batch.uri; - var initMessage = Drupal.settings.batch.initMessage; - var errorMessage = Drupal.settings.batch.errorMessage; +// $Id$ - // Success: redirect to the summary. - var updateCallback = function (progress, status, pb) { - if (progress == 100) { - pb.stopMonitoring(); - window.location = uri+'&op=finished'; - } - }; +/** + * Attaches the batch behaviour to progress bars. + */ +Drupal.behaviors.batch = function (context) { + // This behavior attaches by ID, so is only valid once on a page. + if ($('#progress.batch-processed').size()) { + return; + } + $('#progress', context).addClass('batch-processed').each(function () { + var holder = this; + var uri = Drupal.settings.batch.uri; + var initMessage = Drupal.settings.batch.initMessage; + var errorMessage = Drupal.settings.batch.errorMessage; - var errorCallback = function (pb) { - var div = document.createElement('p'); - div.className = 'error'; - $(div).html(errorMessage); - $(holder).prepend(div); - $('#wait').hide(); - }; + // Success: redirect to the summary. + var updateCallback = function (progress, status, pb) { + if (progress == 100) { + pb.stopMonitoring(); + window.location = uri+'&op=finished'; + } + }; - var progress = new Drupal.progressBar('updateprogress', updateCallback, "POST", errorCallback); - progress.setProgress(-1, initMessage); - $(holder).append(progress.element); - progress.startMonitoring(uri+'&op=do', 10); - }); + var errorCallback = function (pb) { + var div = document.createElement('p'); + div.className = 'error'; + $(div).html(errorMessage); + $(holder).prepend(div); + $('#wait').hide(); + }; + + var progress = new Drupal.progressBar('updateprogress', updateCallback, "POST", errorCallback); + progress.setProgress(-1, initMessage); + $(holder).append(progress.element); + progress.startMonitoring(uri+'&op=do', 10); }); -} +}; diff --git a/misc/collapse.js b/misc/collapse.js index c1fd3d4c3..7bff25397 100644 --- a/misc/collapse.js +++ b/misc/collapse.js @@ -20,10 +20,6 @@ Drupal.toggleFieldset = function(fieldset) { Drupal.collapseScrollIntoView(this.parentNode); } }); - if (typeof(Drupal.textareaAttach) != 'undefined') { - // Initialize resizable textareas that are now revealed - Drupal.textareaAttach(null, fieldset); - } } else { var content = $('> div', fieldset).slideUp('medium', function() { @@ -50,19 +46,17 @@ Drupal.collapseScrollIntoView = function (node) { } }; -// Global Killswitch -if (Drupal.jsEnabled) { - $(document).ready(function() { - $('fieldset.collapsible > legend').each(function() { - var fieldset = $(this.parentNode); - // Expand if there are errors inside - if ($('input.error, textarea.error, select.error', fieldset).size() > 0) { - fieldset.removeClass('collapsed'); - } +Drupal.behaviors.collapse = function (context) { + $('fieldset.collapsible > legend:not(.collapse-processed)', context).each(function() { + var fieldset = $(this.parentNode); + // Expand if there are errors inside + if ($('input.error, textarea.error, select.error', fieldset).size() > 0) { + fieldset.removeClass('collapsed'); + } - // Turn the legend into a clickable link and wrap the contents of the fieldset - // in a div for easier animation - var text = this.innerHTML; + // Turn the legend into a clickable link and wrap the contents of the fieldset + // in a div for easier animation + var text = this.innerHTML; $(this).empty().append($(''+ text +'').click(function() { var fieldset = $(this).parents('fieldset:first')[0]; // Don't animate multiple times @@ -71,7 +65,9 @@ if (Drupal.jsEnabled) { Drupal.toggleFieldset(fieldset); } return false; - })).after($('
').append(fieldset.children(':not(legend)'))); - }); + })) + .after($('
') + .append(fieldset.children(':not(legend)'))) + .addClass('collapse-processed'); }); -} +}; diff --git a/misc/drupal.js b/misc/drupal.js index 98441c7ec..0c155f7d6 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -1,6 +1,6 @@ // $Id$ -var Drupal = Drupal || { 'settings': {}, 'themes': {}, 'locale': {} }; +var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} }; /** * Set the variable that indicates if JavaScript behaviors should be applied @@ -21,6 +21,43 @@ Drupal.extend = function(obj) { } }; +/** + * Attach all registered behaviors to a page element. + * + * Behaviors are event-triggered actions that attach to page elements, enhancing + * default non-Javascript UIs. Behaviors are registered in the Drupal.behaviors + * object as follows: + * @code + * Drupal.behaviors.behaviorName = function () { + * ... + * }; + * @endcode + * + * Drupal.attachBehaviors is added below to the jQuery ready event and so + * runs on initial page load. Developers implementing AHAH/AJAX in their + * solutions should also call this function after new page content has been + * loaded, feeding in an element to be processed, in order to attach all + * behaviors to the new content. + * + * Behaviors should use a class in the form behaviorName-processed to ensure + * the behavior is attached only once to a given element. (Doing so enables + * the reprocessing of given elements, which may be needed on occasion despite + * the ability to limit behavior attachment to a particular element.) + * + * @param context + * An element to attach behaviors to. If none is given, the document element + * is used. + */ +Drupal.attachBehaviors = function(context) { + context = context || document; + if (Drupal.jsEnabled) { + // Execute all of them. + jQuery.each(Drupal.behaviors, function() { + this(context); + }); + } +}; + /** * Encode special characters in a plain-text string for display as HTML. */ @@ -362,6 +399,8 @@ if (Drupal.jsEnabled) { document.documentElement.className = 'js'; // 'js enabled' cookie document.cookie = 'has_js=1'; + // Attach all behaviors. + $(document).ready(Drupal.attachBehaviors); } /** diff --git a/misc/tableheader.js b/misc/tableheader.js index 5b84126ca..80d1fbdde 100644 --- a/misc/tableheader.js +++ b/misc/tableheader.js @@ -1,60 +1,57 @@ // $Id$ -// Global Killswitch -if (Drupal.jsEnabled) { +Drupal.behaviors.tableHeader = function (context) { // Keep track of all header cells. var cells = []; - // Attach to all headers. - $(document).ready(function() { - var z = 0; - $('table thead').each(function () { - // Find table height. - var table = $(this).parent('table')[0]; - var height = $(table).addClass('sticky-table').height(); - var i = 0; + var z = 0; + $('table thead:not(.tableHeader-processed)', context).each(function () { + // Find table height. + var table = $(this).parent('table')[0]; + var height = $(table).addClass('sticky-table').height(); + var i = 0; - // Find all header cells. - $('th', this).each(function () { + // Find all header cells. + $('th', this).each(function () { - // Ensure each cell has an element in it. - var html = $(this).html(); - if (html == ' ') { - html = ' '; - } - if ($(this).children().size() == 0) { - html = ''+ html +''; - } + // Ensure each cell has an element in it. + var html = $(this).html(); + if (html == ' ') { + html = ' '; + } + if ($(this).children().size() == 0) { + html = ''+ html +''; + } - // Clone and wrap cell contents in sticky wrapper that overlaps the cell's padding. - $('').prependTo(this); - var div = $('div.sticky-header', this).css({ - 'marginLeft': '-'+ $(this).css('paddingLeft'), - 'marginRight': '-'+ $(this).css('paddingRight'), - 'paddingLeft': $(this).css('paddingLeft'), - 'paddingTop': $(this).css('paddingTop'), - 'paddingBottom': $(this).css('paddingBottom'), - 'z-index': ++z - })[0]; - cells.push(div); + // Clone and wrap cell contents in sticky wrapper that overlaps the cell's padding. + $('').prependTo(this); + var div = $('div.sticky-header', this).css({ + 'marginLeft': '-'+ $(this).css('paddingLeft'), + 'marginRight': '-'+ $(this).css('paddingRight'), + 'paddingLeft': $(this).css('paddingLeft'), + 'paddingTop': $(this).css('paddingTop'), + 'paddingBottom': $(this).css('paddingBottom'), + 'z-index': ++z + })[0]; + cells.push(div); - // Adjust width to fit cell/table. - var ref = this; - if (!i++) { - // The first cell is as wide as the table to prevent gaps. - ref = table; - div.wide = true; - } - $(div).css('width', parseInt($(ref).width()) - - parseInt($(div).css('paddingLeft')) +'px'); + // Adjust width to fit cell/table. + var ref = this; + if (!i++) { + // The first cell is as wide as the table to prevent gaps. + ref = table; + div.wide = true; + } + $(div).css('width', parseInt($(ref).width()) + - parseInt($(div).css('paddingLeft')) +'px'); - // Get position and store. - div.cell = this; - div.table = table; - div.stickyMax = height; - div.stickyPosition = Drupal.absolutePosition(this).y; - }); + // Get position and store. + div.cell = this; + div.table = table; + div.stickyMax = height; + div.stickyPosition = Drupal.absolutePosition(this).y; }); + $(this).addClass('tableHeader-processed'); }); // Track scrolling. @@ -108,4 +105,4 @@ if (Drupal.jsEnabled) { }, 250); }; $(window).resize(resize); -} +}; diff --git a/misc/tableselect.js b/misc/tableselect.js index 5c0cfbb32..978cff7c2 100644 --- a/misc/tableselect.js +++ b/misc/tableselect.js @@ -1,5 +1,9 @@ // $Id$ +Drupal.behaviors.tableSelect = function (context) { + $('form table[th.select-all]:not(.tableSelect-processed)', context).each(Drupal.tableSelect); +} + Drupal.tableSelect = function() { // Keep track of the table, which checkbox is checked and alias the settings. var table = this, selectAll, checkboxes, lastChecked; @@ -41,6 +45,7 @@ Drupal.tableSelect = function() { // Keep track of the last checked checkbox. lastChecked = e.target; }); + $(this).addClass('tableSelect-processed'); }; Drupal.tableSelectRange = function(from, to, state) { @@ -67,10 +72,3 @@ Drupal.tableSelectRange = function(from, to, state) { } }; - -// Global Killswitch -if (Drupal.jsEnabled) { - $(document).ready(function() { - $('form table[th.select-all]').each(Drupal.tableSelect); - }); -} diff --git a/misc/teaser.js b/misc/teaser.js index c59a92e55..0aa512901 100644 --- a/misc/teaser.js +++ b/misc/teaser.js @@ -5,9 +5,9 @@ * * Note: depends on resizable textareas. */ -Drupal.teaserAttach = function() { - $('textarea.teaser:not(.joined)').each(function() { - var teaser = $(this).addClass('joined'); +Drupal.behaviors.teaser = function(context) { + $('textarea.teaser:not(.teaser-processed)', context).each(function() { + var teaser = $(this).addClass('teaser-processed'); // Move teaser textarea before body, and remove its form-item wrapper. var body = $('#'+ Drupal.settings.teaser[this.id]); @@ -75,7 +75,3 @@ Drupal.teaserAttach = function() { }); }; - -if (Drupal.jsEnabled) { - $(document).ready(Drupal.teaserAttach); -} diff --git a/misc/textarea.js b/misc/textarea.js index 9cd5a1c84..65b8d3cca 100644 --- a/misc/textarea.js +++ b/misc/textarea.js @@ -1,8 +1,8 @@ // $Id$ -Drupal.textareaAttach = function() { - $('textarea.resizable:not(.processed)').each(function() { - var textarea = $(this).addClass('processed'), staticOffset = null; +Drupal.behaviors.textarea = function(context) { + $('textarea.resizable:not(.textarea-processed)', context).each(function() { + var textarea = $(this).addClass('textarea-processed'), staticOffset = null; // When wrapping the text area, work around an IE margin bug. See: // http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout @@ -37,7 +37,3 @@ Drupal.textareaAttach = function() { } }); }; - -if (Drupal.jsEnabled) { - $(document).ready(Drupal.textareaAttach); -} diff --git a/misc/upload.js b/misc/upload.js index 900d979ec..d69f3b765 100644 --- a/misc/upload.js +++ b/misc/upload.js @@ -3,8 +3,8 @@ /** * Attaches the upload behaviour to the upload form. */ -Drupal.uploadAutoAttach = function() { - $('input.upload').each(function () { +Drupal.behaviors.upload = function(context) { + $('input.upload:not(.upload-processed)', context).addClass('upload-processed').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); @@ -12,6 +12,7 @@ Drupal.uploadAutoAttach = function() { var wrapper = base + '-wrapper'; var hide = base + '-hide'; var upload = new Drupal.jsUpload(uri, button, wrapper, hide); + $(this).addClass('upload-processed'); }); }; @@ -65,11 +66,10 @@ Drupal.jsUpload.prototype.oncomplete = function (data) { // If uploading the first attachment fade in everything if ($('tr', div).size() == 2) { - // Replace form and re-attach behaviour + // Replace form and re-attach behaviours $(div).hide(); $(this.wrapper).append(div); $(div).fadeIn('slow'); - Drupal.uploadAutoAttach(); } // Else fade in only the last table row else { @@ -89,8 +89,8 @@ Drupal.jsUpload.prototype.oncomplete = function (data) { $(this.wrapper).append(div); $('table tr:last-of-type td', div).fadeIn('slow'); $(this.hide, div).fadeIn('slow'); - Drupal.uploadAutoAttach(); } + Drupal.attachBehaviors(div); Drupal.unfreezeHeight(); }; @@ -108,9 +108,3 @@ Drupal.jsUpload.prototype.onerror = function (error) { left: '0px' }); }; - - -// Global killswitch -if (Drupal.jsEnabled) { - $(document).ready(Drupal.uploadAutoAttach); -} -- cgit v1.2.3