summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorAngie Byron <webchick@24967.no-reply.drupal.org>2009-04-11 22:19:46 +0000
committerAngie Byron <webchick@24967.no-reply.drupal.org>2009-04-11 22:19:46 +0000
commite888f0061cb7ca2f07b38ad4ff09da99faa75580 (patch)
treeb1ffa36ead61e0061e99fdb4c33a8ea823eb4af5 /misc
parentf278da9e50815f279ce4c7bda993f5d21b43efa3 (diff)
downloadbrdo-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.js9
-rw-r--r--misc/form.js57
-rw-r--r--misc/vertical-tabs-rtl.css15
-rw-r--r--misc/vertical-tabs.css68
-rw-r--r--misc/vertical-tabs.js120
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);