diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-04-11 22:19:46 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-04-11 22:19:46 +0000 |
commit | e888f0061cb7ca2f07b38ad4ff09da99faa75580 (patch) | |
tree | b1ffa36ead61e0061e99fdb4c33a8ea823eb4af5 /misc | |
parent | f278da9e50815f279ce4c7bda993f5d21b43efa3 (diff) | |
download | brdo-e888f0061cb7ca2f07b38ad4ff09da99faa75580.tar.gz brdo-e888f0061cb7ca2f07b38ad4ff09da99faa75580.tar.bz2 |
#323112 by dmitrig01, kkaefer, quicksketch, frando and many many more: Now presenting... Vertical Tabs. Fantastic new UI improvement for node forms and hopefully more in the future.
Diffstat (limited to 'misc')
-rw-r--r-- | misc/collapse.js | 9 | ||||
-rw-r--r-- | misc/form.js | 57 | ||||
-rw-r--r-- | misc/vertical-tabs-rtl.css | 15 | ||||
-rw-r--r-- | misc/vertical-tabs.css | 68 | ||||
-rw-r--r-- | misc/vertical-tabs.js | 120 |
5 files changed, 269 insertions, 0 deletions
diff --git a/misc/collapse.js b/misc/collapse.js index 35ebe5287..11426a1de 100644 --- a/misc/collapse.js +++ b/misc/collapse.js @@ -60,6 +60,14 @@ Drupal.behaviors.collapse = { fieldset.removeClass('collapsed'); } + var summary = $('<span class="summary"></span>'); + fieldset. + bind('summaryUpdated', function() { + var text = $.trim(fieldset.getSummary()); + summary.html(text ? ' (' + text + ')' : ''); + }) + .trigger('summaryUpdated'); + // Turn the legend into a clickable link and wrap the contents of the fieldset // in a div for easier animation var text = this.innerHTML; @@ -72,6 +80,7 @@ Drupal.behaviors.collapse = { } return false; })) + .append(summary) .after($('<div class="fieldset-wrapper"></div>') .append(fieldset.children(':not(legend):not(.action)'))) .addClass('collapse-processed'); diff --git a/misc/form.js b/misc/form.js index 4451e40d9..b54582391 100644 --- a/misc/form.js +++ b/misc/form.js @@ -1,6 +1,63 @@ // $Id$ (function($) { +/** + * Retrieves the summary for the first element. + */ +$.fn.getSummary = function() { + var callback = this.data('summaryCallback'); + return (this[0] && callback) ? $.trim(callback(this[0])) : ''; +}; + +/** + * Sets the summary for all matched elements. + * + * @param callback + * Either a function that will be called each time the summary is + * retrieved or a string (which is returned each time). + */ +$.fn.setSummary = function(callback) { + var that = this; + + // To facilitate things, the callback should always be a function. If it's + // not, we wrap it into an anonymous function which just returns the value. + if (typeof callback != 'function') { + var val = callback; + callback = function() { return val; }; + } + + return this + .data('summaryCallback', callback) + // To prevent duplicate events, the handlers are first removed and then + // (re-)added. + .unbind('formUpdated.summary') + .bind('formUpdated.summary', function() { + that.trigger('summaryUpdated'); + }) + // The actual summaryUpdated handler doesn't fire when the callback is + // changed, so we have to do this manually. + .trigger('summaryUpdated'); +}; + +/** + * Sends a 'formUpdated' event each time a form element is modified. + */ +Drupal.behaviors.formUpdated = { + attach: function(context) { + // These events are namespaced so that we can remove them later. + var events = 'change.formUpdated click.formUpdated blur.formUpdated keyup.formUpdated'; + $(context) + // Since context could be an input element itself, it's added back to + // the jQuery object and filtered again. + .find(':input').andSelf().filter(':input') + // To prevent duplicate events, the handlers are first removed and then + // (re-)added. + .unbind(events).bind(events, function() { + $(this).trigger('formUpdated'); + }); + } +}; + Drupal.behaviors.multiselectSelector = { attach: function(context, settings) { // Automatically selects the right radio button in a multiselect control. diff --git a/misc/vertical-tabs-rtl.css b/misc/vertical-tabs-rtl.css new file mode 100644 index 000000000..fd1e62686 --- /dev/null +++ b/misc/vertical-tabs-rtl.css @@ -0,0 +1,15 @@ +/* $Id */ + +.vertical-tabs { + margin-left: 0; + margin-right: 15em; +} +.vertical-tabs-list { + margin-right: -15em; + right: 0; + float: right; +} +.vertical-tabs-list li.selected { + border-left-width: 0; + border-right-width: 1px; +} diff --git a/misc/vertical-tabs.css b/misc/vertical-tabs.css new file mode 100644 index 000000000..7a5887cad --- /dev/null +++ b/misc/vertical-tabs.css @@ -0,0 +1,68 @@ +/* $Id */ + +.vertical-tabs { + margin: 1em 0 1em 15em; + border: 1px solid #ccc; +} +.vertical-tabs-list { + width: 15em; + list-style: none; + list-style-image: none; /* IE6 */ + border-top: 1px solid #ccc; + padding: 0; + position: relative; /* IE6 */ + margin: -1px -100% -1px 0; + left: -15em; + float: left; +} +.vertical-tabs .vertical-tabs-panes fieldset.vertical-tabs-pane { + margin: 0 !important; + padding: 0 1em; + border: 0; +} +.vertical-tabs .vertical-tabs-panes fieldset.vertical-tabs-pane legend { + display: none; +} + +/* Layout of each tab */ +.vertical-tabs-list li { + background: #eee; + border: 1px solid #ccc; + border-top: 0; + padding: 0; + margin: 0; + height: 1%; +} +.vertical-tabs-list li a { + display: block; + text-decoration: none; + padding: 0.5em 0.6em; + line-height: 1.3em; + height: 1%; +} +.vertical-tabs-list li a:focus { + position: relative; + z-index: 5; +} +.vertical-tabs-list li a:hover { + text-decoration: none; +} +.vertical-tabs-list li.selected { + background: #fff; + border-right-width: 0; + position: relative; +} +.vertical-tabs-list li.selected a:focus { + outline: 0; +} +.vertical-tabs-list li.selected .title { + font-weight: bold; + color: #000; +} +.vertical-tabs-list .summary { + display: block; +} +.vertical-tabs ul.vertical-tabs-list .summary { + line-height: normal; + margin-bottom: 0; +} diff --git a/misc/vertical-tabs.js b/misc/vertical-tabs.js new file mode 100644 index 000000000..a27a3d3ec --- /dev/null +++ b/misc/vertical-tabs.js @@ -0,0 +1,120 @@ +// $Id$ + +(function($) { + +/** + * This script transforms a set of fieldsets into a stack of vertical + * tabs. Another tab pane can be selected by clicking on the respective + * tab. + * + * Each tab may have a summary which can be updated by another + * script. For that to work, each fieldset has an associated + * 'verticalTabCallback' (with jQuery.data() attached to the fieldset), + * which is called every time the user performs an update to a form + * element inside the tab pane. + */ +Drupal.behaviors.verticalTabs = { + attach: function(context) { + $('.vertical-tabs-panes:not(.vertical-tabs-processed)', context).each(function() { + var focusID = $(':hidden.vertical-tabs-active-tab', this).val(); + var focus; + // Create the tab column. + var list = $('<ul class="vertical-tabs-list"></ul>'); + $(this).wrap('<div class="vertical-tabs clearfix"></div>').before(list); + + // Transform each fieldset into a tab. + $('> fieldset', this).each(function() { + var tab = new Drupal.verticalTab({ title: $('> legend', this).text(), fieldset: $(this) }); + list.append(tab.item); + $(this) + .removeClass('collapsible collapsed') + .addClass('vertical-tabs-pane') + .data('verticalTab', tab); + if (this.id == focusID) { + focus = $(this); + } + }); + + $('> li:first', list).addClass('first'); + $('> li:last', list).addClass('last'); + + if (!focus) { + focus = $('> .vertical-tabs-pane:first', this); + } + focus.data('verticalTab').focus(); + }).addClass('vertical-tabs-processed'); + } +}; + +/** + * The vertical tab object represents a single tab within a tab group. + * + * @param settings + * An object with the following keys: + * - title: The name of the tab. + * - fieldset: The jQuery object of the fieldset that is the tab pane. + */ +Drupal.verticalTab = function(settings) { + var that = this; + $.extend(this, settings, Drupal.theme('verticalTab', settings)); + + this.link.click(function() { + that.focus(); + return false; + }); + + this.fieldset + .bind('summaryUpdated', function() { + that.updateSummary(); + }) + .trigger('summaryUpdated'); +}; + +Drupal.verticalTab.prototype = { + // Displays the tab's content pane. + focus: function() { + this.fieldset + .siblings('fieldset.vertical-tabs-pane') + .each(function() { + var tab = $(this).data('verticalTab'); + tab.fieldset.hide(); + tab.item.removeClass('selected'); + }) + .end() + .show() + .siblings(':hidden.vertical-tabs-active-tab') + .val(this.fieldset.attr('id')); + this.item.addClass('selected'); + }, + + // Updates the tab's summary. + updateSummary: function() { + this.summary.html(this.fieldset.getSummary()); + } +}; + +/** + * Theme function for a vertical tab. + * + * @param settings + * An object with the following keys: + * - title: The name of the tab. + * @return + * This function has to return an object with at least these keys: + * - item: The root tab jQuery element + * - link: The anchor tag that acts as the clickable area of the tab + * (jQuery version) + * - summary: The jQuery element that contains the tab summary + */ +Drupal.theme.prototype.verticalTab = function(settings) { + var tab = {}; + tab.item = $('<li class="vertical-tab-button"></li>') + .append(tab.link = $('<a href="#"></a>') + .append(tab.title = $('<span class="title"></span>').text(settings.title)) + .append(tab.summary = $('<span class="summary"></span>') + ) + ); + return tab; +}; + +})(jQuery); |