Mercurial > hg > rr-repo
diff sites/all/modules/admin_menu/admin_menu.js @ 4:ce11bbd8f642
added modules
author | danieleb <danielebarchiesi@me.com> |
---|---|
date | Thu, 19 Sep 2013 10:38:44 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sites/all/modules/admin_menu/admin_menu.js Thu Sep 19 10:38:44 2013 +0100 @@ -0,0 +1,397 @@ +(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 = { + attach: function (context, settings) { + // Initialize settings. + settings.admin_menu = $.extend({ + suppress: false, + margin_top: false, + position_fixed: false, + tweak_modules: false, + tweak_permissions: false, + tweak_tabs: false, + destination: '', + basePath: settings.basePath, + hash: 0, + replacements: {} + }, settings.admin_menu || {}); + // Check whether administration menu should be suppressed. + if (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 && settings.admin_menu.hash) { + Drupal.admin.getCache(settings.admin_menu.hash, function (response) { + if (typeof response == 'string' && response.length > 0) { + $('body', context).append(response); + } + var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context); + // Apply our behaviors. + Drupal.admin.attachBehaviors(context, settings, $adminMenu); + // Allow resize event handlers to recalculate sizes/positions. + $(window).triggerHandler('resize'); + }); + } + // If the menu is in the output already, this means there is a new version. + else { + // Apply our behaviors. + Drupal.admin.attachBehaviors(context, settings, $adminMenu); + } + } +}; + +/** + * Collapse fieldsets on Modules page. + */ +Drupal.behaviors.adminMenuCollapseModules = { + attach: function (context, settings) { + if (settings.admin_menu.tweak_modules) { + $('#system-modules fieldset:not(.collapsed)', context).addClass('collapsed'); + } + } +}; + +/** + * Collapse modules on Permissions page. + */ +Drupal.behaviors.adminMenuCollapsePermissions = { + attach: function (context, settings) { + if (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. + $modules = $('#permissions tr:has(td.module)', context).once('admin-menu-tweak-permissions', function () { + var $module = $(this); + $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'); + }); + }); + }); + // Collapse all but the targeted permission rows set. + if (window.location.hash.length) { + $modules = $modules.not(':has(' + window.location.hash + ')'); + } + $modules.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 = { + attach: function (context, settings) { + if (!settings.admin_menu.suppress && 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; + } + }); +}; + +/** + * TableHeader callback to determine top viewport offset. + * + * @see toolbar.js + */ +Drupal.admin.height = function() { + var $adminMenu = $('#admin-menu'); + var height = $adminMenu.outerHeight(); + // In IE, Shadow filter adds some extra height, so we need to remove it from + // the returned height. + if ($adminMenu.css('filter') && $adminMenu.css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) { + height -= $adminMenu.get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength; + } + return height; +}; + +/** + * @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.addClass('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) { + var $tabs = $(context).find('ul.tabs.primary'); + $adminMenu.find('#admin-menu-wrapper > ul').eq(1) + .append($tabs.find('li').addClass('admin-menu-tab')); + $(context).find('ul.tabs.secondary') + .appendTo('#admin-menu-wrapper > ul > li.admin-menu-tab.active') + .removeClass('secondary'); + $tabs.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); + } + ); +}; + +/** + * Apply the search bar functionality. + */ +Drupal.admin.behaviors.search = function (context, settings, $adminMenu) { + // @todo Add a HTML ID. + var $input = $('input.admin-menu-search', $adminMenu); + // Initialize the current search needle. + var needle = $input.val(); + // Cache of all links that can be matched in the menu. + var links; + // Minimum search needle length. + var needleMinLength = 2; + // Append the results container. + var $results = $('<div />').insertAfter($input); + + /** + * Executes the search upon user input. + */ + function keyupHandler() { + var matches, $html, value = $(this).val(); + // Only proceed if the search needle has changed. + if (value !== needle) { + needle = value; + // Initialize the cache of menu links upon first search. + if (!links && needle.length >= needleMinLength) { + // @todo Limit to links in dropdown menus; i.e., skip menu additions. + links = buildSearchIndex($adminMenu.find('li:not(.admin-menu-action, .admin-menu-action li) > a')); + } + // Empty results container when deleting search text. + if (needle.length < needleMinLength) { + $results.empty(); + } + // Only search if the needle is long enough. + if (needle.length >= needleMinLength && links) { + matches = findMatches(needle, links); + // Build the list in a detached DOM node. + $html = buildResultsList(matches); + // Display results. + $results.empty().append($html); + } + } + } + + /** + * Builds the search index. + */ + function buildSearchIndex($links) { + return $links + .map(function () { + var text = (this.textContent || this.innerText); + // Skip menu entries that do not contain any text (e.g., the icon). + if (typeof text === 'undefined') { + return; + } + return { + text: text, + textMatch: text.toLowerCase(), + element: this + }; + }); + } + + /** + * Searches the index for a given needle and returns matching entries. + */ + function findMatches(needle, links) { + var needleMatch = needle.toLowerCase(); + // Select matching links from the cache. + return $.grep(links, function (link) { + return link.textMatch.indexOf(needleMatch) !== -1; + }); + } + + /** + * Builds the search result list in a detached DOM node. + */ + function buildResultsList(matches) { + var $html = $('<ul class="dropdown admin-menu-search-results" />'); + $.each(matches, function () { + var result = this.text; + var $element = $(this.element); + + // Check whether there is a top-level category that can be prepended. + var $category = $element.closest('#admin-menu-wrapper > ul > li'); + var categoryText = $category.find('> a').text() + if ($category.length && categoryText) { + result = categoryText + ': ' + result; + } + + var $result = $('<li><a href="' + $element.attr('href') + '">' + result + '</a></li>'); + $result.data('original-link', $(this.element).parent()); + $html.append($result); + }); + return $html; + } + + /** + * Highlights selected result. + */ + function resultsHandler(e) { + var $this = $(this); + var show = e.type === 'mouseenter' || e.type === 'focusin'; + $this.trigger(show ? 'showPath' : 'hidePath', [this]); + } + + /** + * Closes the search results and clears the search input. + */ + function resultsClickHandler(e, link) { + var $original = $(this).data('original-link'); + $original.trigger('mouseleave'); + $input.val('').trigger('keyup'); + } + + /** + * Shows the link in the menu that corresponds to a search result. + */ + function highlightPathHandler(e, link) { + if (link) { + var $original = $(link).data('original-link'); + var show = e.type === 'showPath'; + // Toggle an additional CSS class to visually highlight the matching link. + // @todo Consider using same visual appearance as regular hover. + $original.toggleClass('highlight', show); + $original.trigger(show ? 'mouseenter' : 'mouseleave'); + } + } + + // Attach showPath/hidePath handler to search result entries. + $results.delegate('li', 'mouseenter mouseleave focus blur', resultsHandler); + // Hide the result list after a link has been clicked, useful for overlay. + $results.delegate('li', 'click', resultsClickHandler); + // Attach hover/active highlight behavior to search result entries. + $adminMenu.delegate('.admin-menu-search-results li', 'showPath hidePath', highlightPathHandler); + // Attach the search input event handler. + $input.bind('keyup search', keyupHandler); +}; + +/** + * @} End of "defgroup admin_behaviors". + */ + +})(jQuery);