/* $Id: admin_menu.js,v 1.7.2.7.2.18 2010/02/20 23:44:04 sun Exp $ */
(function($) {

Drupal.admin = Drupal.admin || {};
Drupal.admin.behaviors = Drupal.admin.behaviors || {};
Drupal.admin.hashes = Drupal.admin.hashes || {};

/**
 * Core behavior for Administration menu.
 *
 * Test whether there is an administration menu is in the output and execute all
 * registered behaviors.
 */
Drupal.behaviors.adminMenu = function (context) {
  // Initialize settings.
  Drupal.settings.admin_menu = $.extend({
    suppress: false,
    margin_top: false,
    position_fixed: false,
    tweak_modules: false,
    tweak_permissions: false,
    tweak_tabs: false,
    destination: '',
    basePath: Drupal.settings.basePath,
    hash: 0,
    replacements: {}
  }, Drupal.settings.admin_menu || {});
  // Check whether administration menu should be suppressed.
  if (Drupal.settings.admin_menu.suppress) {
    return;
  }
  var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
  // Client-side caching; if administration menu is not in the output, it is
  // fetched from the server and cached in the browser.
  if (!$adminMenu.length && Drupal.settings.admin_menu.hash) {
    Drupal.admin.getCache(Drupal.settings.admin_menu.hash, function (response) {
      if (typeof response == 'string' && response.length > 0) {
        $('body', context).prepend(response);
      }
      var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
      // Apply our behaviors.
      Drupal.admin.attachBehaviors(context, Drupal.settings, $adminMenu);
    });
  }
  // If the menu is in the output already, this means there is a new version.
  else {
    // Apply our behaviors.
    Drupal.admin.attachBehaviors(context, Drupal.settings, $adminMenu);
  }
};

/**
 * Collapse fieldsets on Modules page.
 *
 * For why multiple selectors see #111719.
 */
Drupal.behaviors.adminMenuCollapseModules = function (context) {
  if (Drupal.settings.admin_menu.tweak_modules) {
    $('#system-modules fieldset:not(.collapsed), #system-modules-1 fieldset:not(.collapsed)', context).addClass('collapsed');
  }
};

/**
 * Collapse modules on Permissions page.
 */
Drupal.behaviors.adminMenuCollapsePermissions = function (context) {
  if (Drupal.settings.admin_menu.tweak_permissions) {
    // Freeze width of first column to prevent jumping.
    $('#permissions th:first', context).css({ width: $('#permissions th:first', context).width() });
    // Attach click handler.
    $('#permissions tr:has(td.module)', context).each(function () {
      var $module = $(this).addClass('admin-menu-tweak-permissions-processed');
      $module.bind('click.admin-menu', function () {
        // @todo Replace with .nextUntil() in jQuery 1.4.
        $module.nextAll().each(function () {
          var $row = $(this);
          if ($row.is(':has(td.module)')) {
            return false;
          }
          $row.toggleClass('element-hidden');
        });
      });
    }).trigger('click.admin-menu');
  }
};

/**
 * Apply margin to page.
 *
 * Note that directly applying marginTop does not work in IE. To prevent
 * flickering/jumping page content with client-side caching, this is a regular
 * Drupal behavior.
 */
Drupal.behaviors.adminMenuMarginTop = function (context) {
  if (!Drupal.settings.admin_menu.suppress && Drupal.settings.admin_menu.margin_top) {
    $('body:not(.admin-menu)', context).addClass('admin-menu');
  }
};

/**
 * Retrieve content from client-side cache.
 *
 * @param hash
 *   The md5 hash of the content to retrieve.
 * @param onSuccess
 *   A callback function invoked when the cache request was successful.
 */
Drupal.admin.getCache = function (hash, onSuccess) {
  if (Drupal.admin.hashes.hash !== undefined) {
    return Drupal.admin.hashes.hash;
  }
  $.ajax({
    cache: true,
    type: 'GET',
    dataType: 'text', // Prevent auto-evaluation of response.
    global: false, // Do not trigger global AJAX events.
    url: Drupal.settings.admin_menu.basePath.replace(/admin_menu/, 'js/admin_menu/cache/' + hash),
    success: onSuccess,
    complete: function (XMLHttpRequest, status) {
      Drupal.admin.hashes.hash = status;
    }
  });
}

/**
 * @defgroup admin_behaviors Administration behaviors.
 * @{
 */

/**
 * Attach administrative behaviors.
 */
Drupal.admin.attachBehaviors = function (context, settings, $adminMenu) {
  if ($adminMenu.length) {
    $adminMenu.addClass('admin-menu-processed');
    $.each(Drupal.admin.behaviors, function() {
      this(context, settings, $adminMenu);
    });
  }
};

/**
 * Apply 'position: fixed'.
 */
Drupal.admin.behaviors.positionFixed = function (context, settings, $adminMenu) {
  if (settings.admin_menu.position_fixed) {
    $adminMenu.css('position', 'fixed');
  }
};

/**
 * Move page tabs into administration menu.
 */
Drupal.admin.behaviors.pageTabs = function (context, settings, $adminMenu) {
  if (settings.admin_menu.tweak_tabs) {
    $('ul.tabs.primary li', context).addClass('admin-menu-tab').appendTo('#admin-menu-wrapper > ul');
    $('ul.tabs.secondary', context).appendTo('#admin-menu-wrapper > ul > li.admin-menu-tab.active').removeClass('secondary');
    $('ul.tabs.primary', context).remove();
  }
};

/**
 * Perform dynamic replacements in cached menu.
 */
Drupal.admin.behaviors.replacements = function (context, settings, $adminMenu) {
  for (var item in settings.admin_menu.replacements) {
    $(item, $adminMenu).html(settings.admin_menu.replacements[item]);
  }
}

/**
 * Inject destination query strings for current page.
 */
Drupal.admin.behaviors.destination = function (context, settings, $adminMenu) {
  if (settings.admin_menu.destination) {
    $('a.admin-menu-destination', $adminMenu).each(function() {
      this.search += (!this.search.length ? '?' : '&') + Drupal.settings.admin_menu.destination;
    });
  }
}

/**
 * Apply JavaScript-based hovering behaviors.
 *
 * @todo This has to run last.  If another script registers additional behaviors
 *   it will not run last.
 */
Drupal.admin.behaviors.hover = function (context, settings, $adminMenu) {
  // Hover emulation for IE 6.
  if ($.browser.msie && parseInt(jQuery.browser.version) == 6) {
    $('li', $adminMenu).hover(
      function () {
        $(this).addClass('iehover');
      },
      function () {
        $(this).removeClass('iehover');
      }
    );
  }

  // Delayed mouseout.
  $('li.expandable', $adminMenu).hover(
    function () {
      // Stop the timer.
      clearTimeout(this.sfTimer);
      // Display child lists.
      $('> ul', this)
        .css({left: 'auto', display: 'block'})
        // Immediately hide nephew lists.
        .parent().siblings('li').children('ul').css({left: '-999em', display: 'none'});
    },
    function () {
      // Start the timer.
      var uls = $('> ul', this);
      this.sfTimer = setTimeout(function () {
        uls.css({left: '-999em', display: 'none'});
      }, 400);
    }
  );
};

/**
 * @} End of "defgroup admin_behaviors".
 */

})(jQuery);
