annotate sites/all/modules/admin_menu/admin_menu.js @ 11:b0ee71395280

deleted .DS_Store files
author danieleb <danielebarchiesi@me.com>
date Mon, 28 Oct 2013 16:12:13 +0000
parents ce11bbd8f642
children
rev   line source
danielebarchiesi@4 1 (function($) {
danielebarchiesi@4 2
danielebarchiesi@4 3 Drupal.admin = Drupal.admin || {};
danielebarchiesi@4 4 Drupal.admin.behaviors = Drupal.admin.behaviors || {};
danielebarchiesi@4 5 Drupal.admin.hashes = Drupal.admin.hashes || {};
danielebarchiesi@4 6
danielebarchiesi@4 7 /**
danielebarchiesi@4 8 * Core behavior for Administration menu.
danielebarchiesi@4 9 *
danielebarchiesi@4 10 * Test whether there is an administration menu is in the output and execute all
danielebarchiesi@4 11 * registered behaviors.
danielebarchiesi@4 12 */
danielebarchiesi@4 13 Drupal.behaviors.adminMenu = {
danielebarchiesi@4 14 attach: function (context, settings) {
danielebarchiesi@4 15 // Initialize settings.
danielebarchiesi@4 16 settings.admin_menu = $.extend({
danielebarchiesi@4 17 suppress: false,
danielebarchiesi@4 18 margin_top: false,
danielebarchiesi@4 19 position_fixed: false,
danielebarchiesi@4 20 tweak_modules: false,
danielebarchiesi@4 21 tweak_permissions: false,
danielebarchiesi@4 22 tweak_tabs: false,
danielebarchiesi@4 23 destination: '',
danielebarchiesi@4 24 basePath: settings.basePath,
danielebarchiesi@4 25 hash: 0,
danielebarchiesi@4 26 replacements: {}
danielebarchiesi@4 27 }, settings.admin_menu || {});
danielebarchiesi@4 28 // Check whether administration menu should be suppressed.
danielebarchiesi@4 29 if (settings.admin_menu.suppress) {
danielebarchiesi@4 30 return;
danielebarchiesi@4 31 }
danielebarchiesi@4 32 var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
danielebarchiesi@4 33 // Client-side caching; if administration menu is not in the output, it is
danielebarchiesi@4 34 // fetched from the server and cached in the browser.
danielebarchiesi@4 35 if (!$adminMenu.length && settings.admin_menu.hash) {
danielebarchiesi@4 36 Drupal.admin.getCache(settings.admin_menu.hash, function (response) {
danielebarchiesi@4 37 if (typeof response == 'string' && response.length > 0) {
danielebarchiesi@4 38 $('body', context).append(response);
danielebarchiesi@4 39 }
danielebarchiesi@4 40 var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
danielebarchiesi@4 41 // Apply our behaviors.
danielebarchiesi@4 42 Drupal.admin.attachBehaviors(context, settings, $adminMenu);
danielebarchiesi@4 43 // Allow resize event handlers to recalculate sizes/positions.
danielebarchiesi@4 44 $(window).triggerHandler('resize');
danielebarchiesi@4 45 });
danielebarchiesi@4 46 }
danielebarchiesi@4 47 // If the menu is in the output already, this means there is a new version.
danielebarchiesi@4 48 else {
danielebarchiesi@4 49 // Apply our behaviors.
danielebarchiesi@4 50 Drupal.admin.attachBehaviors(context, settings, $adminMenu);
danielebarchiesi@4 51 }
danielebarchiesi@4 52 }
danielebarchiesi@4 53 };
danielebarchiesi@4 54
danielebarchiesi@4 55 /**
danielebarchiesi@4 56 * Collapse fieldsets on Modules page.
danielebarchiesi@4 57 */
danielebarchiesi@4 58 Drupal.behaviors.adminMenuCollapseModules = {
danielebarchiesi@4 59 attach: function (context, settings) {
danielebarchiesi@4 60 if (settings.admin_menu.tweak_modules) {
danielebarchiesi@4 61 $('#system-modules fieldset:not(.collapsed)', context).addClass('collapsed');
danielebarchiesi@4 62 }
danielebarchiesi@4 63 }
danielebarchiesi@4 64 };
danielebarchiesi@4 65
danielebarchiesi@4 66 /**
danielebarchiesi@4 67 * Collapse modules on Permissions page.
danielebarchiesi@4 68 */
danielebarchiesi@4 69 Drupal.behaviors.adminMenuCollapsePermissions = {
danielebarchiesi@4 70 attach: function (context, settings) {
danielebarchiesi@4 71 if (settings.admin_menu.tweak_permissions) {
danielebarchiesi@4 72 // Freeze width of first column to prevent jumping.
danielebarchiesi@4 73 $('#permissions th:first', context).css({ width: $('#permissions th:first', context).width() });
danielebarchiesi@4 74 // Attach click handler.
danielebarchiesi@4 75 $modules = $('#permissions tr:has(td.module)', context).once('admin-menu-tweak-permissions', function () {
danielebarchiesi@4 76 var $module = $(this);
danielebarchiesi@4 77 $module.bind('click.admin-menu', function () {
danielebarchiesi@4 78 // @todo Replace with .nextUntil() in jQuery 1.4.
danielebarchiesi@4 79 $module.nextAll().each(function () {
danielebarchiesi@4 80 var $row = $(this);
danielebarchiesi@4 81 if ($row.is(':has(td.module)')) {
danielebarchiesi@4 82 return false;
danielebarchiesi@4 83 }
danielebarchiesi@4 84 $row.toggleClass('element-hidden');
danielebarchiesi@4 85 });
danielebarchiesi@4 86 });
danielebarchiesi@4 87 });
danielebarchiesi@4 88 // Collapse all but the targeted permission rows set.
danielebarchiesi@4 89 if (window.location.hash.length) {
danielebarchiesi@4 90 $modules = $modules.not(':has(' + window.location.hash + ')');
danielebarchiesi@4 91 }
danielebarchiesi@4 92 $modules.trigger('click.admin-menu');
danielebarchiesi@4 93 }
danielebarchiesi@4 94 }
danielebarchiesi@4 95 };
danielebarchiesi@4 96
danielebarchiesi@4 97 /**
danielebarchiesi@4 98 * Apply margin to page.
danielebarchiesi@4 99 *
danielebarchiesi@4 100 * Note that directly applying marginTop does not work in IE. To prevent
danielebarchiesi@4 101 * flickering/jumping page content with client-side caching, this is a regular
danielebarchiesi@4 102 * Drupal behavior.
danielebarchiesi@4 103 */
danielebarchiesi@4 104 Drupal.behaviors.adminMenuMarginTop = {
danielebarchiesi@4 105 attach: function (context, settings) {
danielebarchiesi@4 106 if (!settings.admin_menu.suppress && settings.admin_menu.margin_top) {
danielebarchiesi@4 107 $('body:not(.admin-menu)', context).addClass('admin-menu');
danielebarchiesi@4 108 }
danielebarchiesi@4 109 }
danielebarchiesi@4 110 };
danielebarchiesi@4 111
danielebarchiesi@4 112 /**
danielebarchiesi@4 113 * Retrieve content from client-side cache.
danielebarchiesi@4 114 *
danielebarchiesi@4 115 * @param hash
danielebarchiesi@4 116 * The md5 hash of the content to retrieve.
danielebarchiesi@4 117 * @param onSuccess
danielebarchiesi@4 118 * A callback function invoked when the cache request was successful.
danielebarchiesi@4 119 */
danielebarchiesi@4 120 Drupal.admin.getCache = function (hash, onSuccess) {
danielebarchiesi@4 121 if (Drupal.admin.hashes.hash !== undefined) {
danielebarchiesi@4 122 return Drupal.admin.hashes.hash;
danielebarchiesi@4 123 }
danielebarchiesi@4 124 $.ajax({
danielebarchiesi@4 125 cache: true,
danielebarchiesi@4 126 type: 'GET',
danielebarchiesi@4 127 dataType: 'text', // Prevent auto-evaluation of response.
danielebarchiesi@4 128 global: false, // Do not trigger global AJAX events.
danielebarchiesi@4 129 url: Drupal.settings.admin_menu.basePath.replace(/admin_menu/, 'js/admin_menu/cache/' + hash),
danielebarchiesi@4 130 success: onSuccess,
danielebarchiesi@4 131 complete: function (XMLHttpRequest, status) {
danielebarchiesi@4 132 Drupal.admin.hashes.hash = status;
danielebarchiesi@4 133 }
danielebarchiesi@4 134 });
danielebarchiesi@4 135 };
danielebarchiesi@4 136
danielebarchiesi@4 137 /**
danielebarchiesi@4 138 * TableHeader callback to determine top viewport offset.
danielebarchiesi@4 139 *
danielebarchiesi@4 140 * @see toolbar.js
danielebarchiesi@4 141 */
danielebarchiesi@4 142 Drupal.admin.height = function() {
danielebarchiesi@4 143 var $adminMenu = $('#admin-menu');
danielebarchiesi@4 144 var height = $adminMenu.outerHeight();
danielebarchiesi@4 145 // In IE, Shadow filter adds some extra height, so we need to remove it from
danielebarchiesi@4 146 // the returned height.
danielebarchiesi@4 147 if ($adminMenu.css('filter') && $adminMenu.css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) {
danielebarchiesi@4 148 height -= $adminMenu.get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength;
danielebarchiesi@4 149 }
danielebarchiesi@4 150 return height;
danielebarchiesi@4 151 };
danielebarchiesi@4 152
danielebarchiesi@4 153 /**
danielebarchiesi@4 154 * @defgroup admin_behaviors Administration behaviors.
danielebarchiesi@4 155 * @{
danielebarchiesi@4 156 */
danielebarchiesi@4 157
danielebarchiesi@4 158 /**
danielebarchiesi@4 159 * Attach administrative behaviors.
danielebarchiesi@4 160 */
danielebarchiesi@4 161 Drupal.admin.attachBehaviors = function (context, settings, $adminMenu) {
danielebarchiesi@4 162 if ($adminMenu.length) {
danielebarchiesi@4 163 $adminMenu.addClass('admin-menu-processed');
danielebarchiesi@4 164 $.each(Drupal.admin.behaviors, function() {
danielebarchiesi@4 165 this(context, settings, $adminMenu);
danielebarchiesi@4 166 });
danielebarchiesi@4 167 }
danielebarchiesi@4 168 };
danielebarchiesi@4 169
danielebarchiesi@4 170 /**
danielebarchiesi@4 171 * Apply 'position: fixed'.
danielebarchiesi@4 172 */
danielebarchiesi@4 173 Drupal.admin.behaviors.positionFixed = function (context, settings, $adminMenu) {
danielebarchiesi@4 174 if (settings.admin_menu.position_fixed) {
danielebarchiesi@4 175 $adminMenu.addClass('admin-menu-position-fixed');
danielebarchiesi@4 176 $adminMenu.css('position', 'fixed');
danielebarchiesi@4 177 }
danielebarchiesi@4 178 };
danielebarchiesi@4 179
danielebarchiesi@4 180 /**
danielebarchiesi@4 181 * Move page tabs into administration menu.
danielebarchiesi@4 182 */
danielebarchiesi@4 183 Drupal.admin.behaviors.pageTabs = function (context, settings, $adminMenu) {
danielebarchiesi@4 184 if (settings.admin_menu.tweak_tabs) {
danielebarchiesi@4 185 var $tabs = $(context).find('ul.tabs.primary');
danielebarchiesi@4 186 $adminMenu.find('#admin-menu-wrapper > ul').eq(1)
danielebarchiesi@4 187 .append($tabs.find('li').addClass('admin-menu-tab'));
danielebarchiesi@4 188 $(context).find('ul.tabs.secondary')
danielebarchiesi@4 189 .appendTo('#admin-menu-wrapper > ul > li.admin-menu-tab.active')
danielebarchiesi@4 190 .removeClass('secondary');
danielebarchiesi@4 191 $tabs.remove();
danielebarchiesi@4 192 }
danielebarchiesi@4 193 };
danielebarchiesi@4 194
danielebarchiesi@4 195 /**
danielebarchiesi@4 196 * Perform dynamic replacements in cached menu.
danielebarchiesi@4 197 */
danielebarchiesi@4 198 Drupal.admin.behaviors.replacements = function (context, settings, $adminMenu) {
danielebarchiesi@4 199 for (var item in settings.admin_menu.replacements) {
danielebarchiesi@4 200 $(item, $adminMenu).html(settings.admin_menu.replacements[item]);
danielebarchiesi@4 201 }
danielebarchiesi@4 202 };
danielebarchiesi@4 203
danielebarchiesi@4 204 /**
danielebarchiesi@4 205 * Inject destination query strings for current page.
danielebarchiesi@4 206 */
danielebarchiesi@4 207 Drupal.admin.behaviors.destination = function (context, settings, $adminMenu) {
danielebarchiesi@4 208 if (settings.admin_menu.destination) {
danielebarchiesi@4 209 $('a.admin-menu-destination', $adminMenu).each(function() {
danielebarchiesi@4 210 this.search += (!this.search.length ? '?' : '&') + Drupal.settings.admin_menu.destination;
danielebarchiesi@4 211 });
danielebarchiesi@4 212 }
danielebarchiesi@4 213 };
danielebarchiesi@4 214
danielebarchiesi@4 215 /**
danielebarchiesi@4 216 * Apply JavaScript-based hovering behaviors.
danielebarchiesi@4 217 *
danielebarchiesi@4 218 * @todo This has to run last. If another script registers additional behaviors
danielebarchiesi@4 219 * it will not run last.
danielebarchiesi@4 220 */
danielebarchiesi@4 221 Drupal.admin.behaviors.hover = function (context, settings, $adminMenu) {
danielebarchiesi@4 222 // Hover emulation for IE 6.
danielebarchiesi@4 223 if ($.browser.msie && parseInt(jQuery.browser.version) == 6) {
danielebarchiesi@4 224 $('li', $adminMenu).hover(
danielebarchiesi@4 225 function () {
danielebarchiesi@4 226 $(this).addClass('iehover');
danielebarchiesi@4 227 },
danielebarchiesi@4 228 function () {
danielebarchiesi@4 229 $(this).removeClass('iehover');
danielebarchiesi@4 230 }
danielebarchiesi@4 231 );
danielebarchiesi@4 232 }
danielebarchiesi@4 233
danielebarchiesi@4 234 // Delayed mouseout.
danielebarchiesi@4 235 $('li.expandable', $adminMenu).hover(
danielebarchiesi@4 236 function () {
danielebarchiesi@4 237 // Stop the timer.
danielebarchiesi@4 238 clearTimeout(this.sfTimer);
danielebarchiesi@4 239 // Display child lists.
danielebarchiesi@4 240 $('> ul', this)
danielebarchiesi@4 241 .css({left: 'auto', display: 'block'})
danielebarchiesi@4 242 // Immediately hide nephew lists.
danielebarchiesi@4 243 .parent().siblings('li').children('ul').css({left: '-999em', display: 'none'});
danielebarchiesi@4 244 },
danielebarchiesi@4 245 function () {
danielebarchiesi@4 246 // Start the timer.
danielebarchiesi@4 247 var uls = $('> ul', this);
danielebarchiesi@4 248 this.sfTimer = setTimeout(function () {
danielebarchiesi@4 249 uls.css({left: '-999em', display: 'none'});
danielebarchiesi@4 250 }, 400);
danielebarchiesi@4 251 }
danielebarchiesi@4 252 );
danielebarchiesi@4 253 };
danielebarchiesi@4 254
danielebarchiesi@4 255 /**
danielebarchiesi@4 256 * Apply the search bar functionality.
danielebarchiesi@4 257 */
danielebarchiesi@4 258 Drupal.admin.behaviors.search = function (context, settings, $adminMenu) {
danielebarchiesi@4 259 // @todo Add a HTML ID.
danielebarchiesi@4 260 var $input = $('input.admin-menu-search', $adminMenu);
danielebarchiesi@4 261 // Initialize the current search needle.
danielebarchiesi@4 262 var needle = $input.val();
danielebarchiesi@4 263 // Cache of all links that can be matched in the menu.
danielebarchiesi@4 264 var links;
danielebarchiesi@4 265 // Minimum search needle length.
danielebarchiesi@4 266 var needleMinLength = 2;
danielebarchiesi@4 267 // Append the results container.
danielebarchiesi@4 268 var $results = $('<div />').insertAfter($input);
danielebarchiesi@4 269
danielebarchiesi@4 270 /**
danielebarchiesi@4 271 * Executes the search upon user input.
danielebarchiesi@4 272 */
danielebarchiesi@4 273 function keyupHandler() {
danielebarchiesi@4 274 var matches, $html, value = $(this).val();
danielebarchiesi@4 275 // Only proceed if the search needle has changed.
danielebarchiesi@4 276 if (value !== needle) {
danielebarchiesi@4 277 needle = value;
danielebarchiesi@4 278 // Initialize the cache of menu links upon first search.
danielebarchiesi@4 279 if (!links && needle.length >= needleMinLength) {
danielebarchiesi@4 280 // @todo Limit to links in dropdown menus; i.e., skip menu additions.
danielebarchiesi@4 281 links = buildSearchIndex($adminMenu.find('li:not(.admin-menu-action, .admin-menu-action li) > a'));
danielebarchiesi@4 282 }
danielebarchiesi@4 283 // Empty results container when deleting search text.
danielebarchiesi@4 284 if (needle.length < needleMinLength) {
danielebarchiesi@4 285 $results.empty();
danielebarchiesi@4 286 }
danielebarchiesi@4 287 // Only search if the needle is long enough.
danielebarchiesi@4 288 if (needle.length >= needleMinLength && links) {
danielebarchiesi@4 289 matches = findMatches(needle, links);
danielebarchiesi@4 290 // Build the list in a detached DOM node.
danielebarchiesi@4 291 $html = buildResultsList(matches);
danielebarchiesi@4 292 // Display results.
danielebarchiesi@4 293 $results.empty().append($html);
danielebarchiesi@4 294 }
danielebarchiesi@4 295 }
danielebarchiesi@4 296 }
danielebarchiesi@4 297
danielebarchiesi@4 298 /**
danielebarchiesi@4 299 * Builds the search index.
danielebarchiesi@4 300 */
danielebarchiesi@4 301 function buildSearchIndex($links) {
danielebarchiesi@4 302 return $links
danielebarchiesi@4 303 .map(function () {
danielebarchiesi@4 304 var text = (this.textContent || this.innerText);
danielebarchiesi@4 305 // Skip menu entries that do not contain any text (e.g., the icon).
danielebarchiesi@4 306 if (typeof text === 'undefined') {
danielebarchiesi@4 307 return;
danielebarchiesi@4 308 }
danielebarchiesi@4 309 return {
danielebarchiesi@4 310 text: text,
danielebarchiesi@4 311 textMatch: text.toLowerCase(),
danielebarchiesi@4 312 element: this
danielebarchiesi@4 313 };
danielebarchiesi@4 314 });
danielebarchiesi@4 315 }
danielebarchiesi@4 316
danielebarchiesi@4 317 /**
danielebarchiesi@4 318 * Searches the index for a given needle and returns matching entries.
danielebarchiesi@4 319 */
danielebarchiesi@4 320 function findMatches(needle, links) {
danielebarchiesi@4 321 var needleMatch = needle.toLowerCase();
danielebarchiesi@4 322 // Select matching links from the cache.
danielebarchiesi@4 323 return $.grep(links, function (link) {
danielebarchiesi@4 324 return link.textMatch.indexOf(needleMatch) !== -1;
danielebarchiesi@4 325 });
danielebarchiesi@4 326 }
danielebarchiesi@4 327
danielebarchiesi@4 328 /**
danielebarchiesi@4 329 * Builds the search result list in a detached DOM node.
danielebarchiesi@4 330 */
danielebarchiesi@4 331 function buildResultsList(matches) {
danielebarchiesi@4 332 var $html = $('<ul class="dropdown admin-menu-search-results" />');
danielebarchiesi@4 333 $.each(matches, function () {
danielebarchiesi@4 334 var result = this.text;
danielebarchiesi@4 335 var $element = $(this.element);
danielebarchiesi@4 336
danielebarchiesi@4 337 // Check whether there is a top-level category that can be prepended.
danielebarchiesi@4 338 var $category = $element.closest('#admin-menu-wrapper > ul > li');
danielebarchiesi@4 339 var categoryText = $category.find('> a').text()
danielebarchiesi@4 340 if ($category.length && categoryText) {
danielebarchiesi@4 341 result = categoryText + ': ' + result;
danielebarchiesi@4 342 }
danielebarchiesi@4 343
danielebarchiesi@4 344 var $result = $('<li><a href="' + $element.attr('href') + '">' + result + '</a></li>');
danielebarchiesi@4 345 $result.data('original-link', $(this.element).parent());
danielebarchiesi@4 346 $html.append($result);
danielebarchiesi@4 347 });
danielebarchiesi@4 348 return $html;
danielebarchiesi@4 349 }
danielebarchiesi@4 350
danielebarchiesi@4 351 /**
danielebarchiesi@4 352 * Highlights selected result.
danielebarchiesi@4 353 */
danielebarchiesi@4 354 function resultsHandler(e) {
danielebarchiesi@4 355 var $this = $(this);
danielebarchiesi@4 356 var show = e.type === 'mouseenter' || e.type === 'focusin';
danielebarchiesi@4 357 $this.trigger(show ? 'showPath' : 'hidePath', [this]);
danielebarchiesi@4 358 }
danielebarchiesi@4 359
danielebarchiesi@4 360 /**
danielebarchiesi@4 361 * Closes the search results and clears the search input.
danielebarchiesi@4 362 */
danielebarchiesi@4 363 function resultsClickHandler(e, link) {
danielebarchiesi@4 364 var $original = $(this).data('original-link');
danielebarchiesi@4 365 $original.trigger('mouseleave');
danielebarchiesi@4 366 $input.val('').trigger('keyup');
danielebarchiesi@4 367 }
danielebarchiesi@4 368
danielebarchiesi@4 369 /**
danielebarchiesi@4 370 * Shows the link in the menu that corresponds to a search result.
danielebarchiesi@4 371 */
danielebarchiesi@4 372 function highlightPathHandler(e, link) {
danielebarchiesi@4 373 if (link) {
danielebarchiesi@4 374 var $original = $(link).data('original-link');
danielebarchiesi@4 375 var show = e.type === 'showPath';
danielebarchiesi@4 376 // Toggle an additional CSS class to visually highlight the matching link.
danielebarchiesi@4 377 // @todo Consider using same visual appearance as regular hover.
danielebarchiesi@4 378 $original.toggleClass('highlight', show);
danielebarchiesi@4 379 $original.trigger(show ? 'mouseenter' : 'mouseleave');
danielebarchiesi@4 380 }
danielebarchiesi@4 381 }
danielebarchiesi@4 382
danielebarchiesi@4 383 // Attach showPath/hidePath handler to search result entries.
danielebarchiesi@4 384 $results.delegate('li', 'mouseenter mouseleave focus blur', resultsHandler);
danielebarchiesi@4 385 // Hide the result list after a link has been clicked, useful for overlay.
danielebarchiesi@4 386 $results.delegate('li', 'click', resultsClickHandler);
danielebarchiesi@4 387 // Attach hover/active highlight behavior to search result entries.
danielebarchiesi@4 388 $adminMenu.delegate('.admin-menu-search-results li', 'showPath hidePath', highlightPathHandler);
danielebarchiesi@4 389 // Attach the search input event handler.
danielebarchiesi@4 390 $input.bind('keyup search', keyupHandler);
danielebarchiesi@4 391 };
danielebarchiesi@4 392
danielebarchiesi@4 393 /**
danielebarchiesi@4 394 * @} End of "defgroup admin_behaviors".
danielebarchiesi@4 395 */
danielebarchiesi@4 396
danielebarchiesi@4 397 })(jQuery);