cms/drupal/misc/vertical-tabs.js
changeset 541 e756a8c72c3d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/drupal/misc/vertical-tabs.js	Fri Sep 08 12:04:06 2017 +0200
@@ -0,0 +1,201 @@
+
+(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', context).once('vertical-tabs', function () {
+      var focusID = $(':hidden.vertical-tabs-active-tab', this).val();
+      var tab_focus;
+
+      // Check if there are some fieldsets that can be converted to vertical-tabs
+      var $fieldsets = $('> fieldset', this);
+      if ($fieldsets.length == 0) {
+        return;
+      }
+
+      // Create the tab column.
+      var tab_list = $('<ul class="vertical-tabs-list"></ul>');
+      $(this).wrap('<div class="vertical-tabs clearfix"></div>').before(tab_list);
+
+      // Transform each fieldset into a tab.
+      $fieldsets.each(function () {
+        var vertical_tab = new Drupal.verticalTab({
+          title: $('> legend', this).text(),
+          fieldset: $(this)
+        });
+        tab_list.append(vertical_tab.item);
+        $(this)
+          .removeClass('collapsible collapsed')
+          .addClass('vertical-tabs-pane')
+          .data('verticalTab', vertical_tab);
+        if (this.id == focusID) {
+          tab_focus = $(this);
+        }
+      });
+
+      $('> li:first', tab_list).addClass('first');
+      $('> li:last', tab_list).addClass('last');
+
+      if (!tab_focus) {
+        // If the current URL has a fragment and one of the tabs contains an
+        // element that matches the URL fragment, activate that tab.
+        if (window.location.hash && $(this).find(window.location.hash).length) {
+          tab_focus = $(this).find(window.location.hash).closest('.vertical-tabs-pane');
+        }
+        else {
+          tab_focus = $('> .vertical-tabs-pane:first', this);
+        }
+      }
+      if (tab_focus.length) {
+        tab_focus.data('verticalTab').focus();
+      }
+    });
+  }
+};
+
+/**
+ * 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 self = this;
+  $.extend(this, settings, Drupal.theme('verticalTab', settings));
+
+  this.link.click(function () {
+    self.focus();
+    return false;
+  });
+
+  // Keyboard events added:
+  // Pressing the Enter key will open the tab pane.
+  this.link.keydown(function(event) {
+    if (event.keyCode == 13) {
+      self.focus();
+      // Set focus on the first input field of the visible fieldset/tab pane.
+      $("fieldset.vertical-tabs-pane :input:visible:enabled:first").focus();
+      return false;
+    }
+  });
+
+  this.fieldset
+    .bind('summaryUpdated', function () {
+      self.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');
+    // Mark the active tab for screen readers.
+    $('#active-vertical-tab').remove();
+    this.link.append('<span id="active-vertical-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
+  },
+
+  /**
+   * Updates the tab's summary.
+   */
+  updateSummary: function () {
+    this.summary.html(this.fieldset.drupalGetSummary());
+  },
+
+  /**
+   * Shows a vertical tab pane.
+   */
+  tabShow: function () {
+    // Display the tab.
+    this.item.show();
+    // Show the vertical tabs.
+    this.item.closest('.vertical-tabs').show();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.vertical-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Display the fieldset.
+    this.fieldset.removeClass('vertical-tab-hidden').show();
+    // Focus this tab.
+    this.focus();
+    return this;
+  },
+
+  /**
+   * Hides a vertical tab pane.
+   */
+  tabHide: function () {
+    // Hide this tab.
+    this.item.hide();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.vertical-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Hide the fieldset.
+    this.fieldset.addClass('vertical-tab-hidden').hide();
+    // Focus the first visible tab (if there is one).
+    var $firstTab = this.fieldset.siblings('.vertical-tabs-pane:not(.vertical-tab-hidden):first');
+    if ($firstTab.length) {
+      $firstTab.data('verticalTab').focus();
+    }
+    // Hide the vertical tabs (if no tabs remain).
+    else {
+      this.item.closest('.vertical-tabs').hide();
+    }
+    return this;
+  }
+};
+
+/**
+ * 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" tabindex="-1"></li>')
+    .append(tab.link = $('<a href="#"></a>')
+      .append(tab.title = $('<strong></strong>').text(settings.title))
+      .append(tab.summary = $('<span class="summary"></span>')
+    )
+  );
+  return tab;
+};
+
+})(jQuery);