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