PageSourceSearch

https://escacs.cat/plugins/system/t3/base-bs3/js/menu.js

js escacs.cat collected 2026-10-02 08:09:15 UTC 12,037 bytes, 452 lines download raw bytes

1/** 
2 *------------------------------------------------------------------------------
3 * @package       T3 Framework for Joomla!
4 *------------------------------------------------------------------------------
5 * @copyright     Copyright (C) 2004-2013 JoomlArt.com. All Rights Reserved.
6 * @license       GNU General Public License version 2 or later; see LICENSE.txt
7 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github 
8 *                & Google group to become co-author)
9 * @Google group: https://groups.google.com/forum/#!forum/t3fw
10 * @Link:         http://t3-framework.org 
11 *------------------------------------------------------------------------------
12 */
13	
14;(function($){
15
16
17	var T3Menu = function(elm, options){
18		this.$menu = $(elm);
19		if (!this.$menu.length){
20			return;
21		}
22
23		this.options = $.extend({}, $.fn.t3menu.defaults, options);
24		this.child_open = [];
25		this.loaded = false;
26		
27		this.start();
28	};
29
30	T3Menu.prototype = {
31		constructor: T3Menu,
32
33		start: function () {
34			//init once
35			if (this.loaded){
36				return;
37			}
38			this.loaded = true;
39
40			//start
41			var self = this,
42				options = this.options,
43				$menu = this.$menu;
44			
45			this.$items = $menu.find('li');
46			this.$items.each(function (idx, li) {
47				
48				var $item = $(this),
49					$child = $item.children('.dropdown-menu'),
50					$link = $item.children('a'),
51					item = {
52						$item: $item,
53						child: $child.length,
54						link: $link.length,
55						clickable: !($link.length && $child.length),
56						mega: $item.hasClass('mega'),
57						status: 'close',
58						timer: null,
59						atimer: null
60					};
61
62				//store
63				$item.data('t3menu.item', item);
64
65				//click action
66				if ($child.length && !options.hover) {
67					$item.on('click', function (e) {
68						e.stopPropagation();
69
70						if ($item.hasClass('group')) {
71							return;
72						}
73
74						if (item.status == 'close') {
75							e.preventDefault();
76							self.show(item);
77						}
78					});
79				} else {
80
81					//stop if click on menu item - prevent bubble event
82					$item.on('click', function (e) {
83						e.stopPropagation()
84					});
85				}
86
87				if (options.hover) {
88					$item.on('mouseover', function (e) {
89						if ($item.hasClass('group')) {
90							return;
91						}
92
93						e.stopPropagation();
94						self.show(item);
95
96					}).on('mouseleave', function (e) {
97						if ($item.hasClass('group')) {
98							return;
99						}
100						
101						e.stopPropagation();
102						self.hide(item);
103					});
104
105					//if has child, don't goto link before open child - fix for touch screen
106					if ($link.length && $child.length) {
107						$link.on('click', function (e) {
108							return item.clickable;
109						});
110					}
111				}
112
113			});
114
115			$(document.body).on('tap hideall.t3menu', function(e){
116				clearTimeout(self.timer);
117				self.timer = setTimeout($.proxy(self.hide_alls, self), e.type == 'tap' ? 500 : self.options.hidedelay);
118			});
119		},
120
121		show: function (item) {
122			// hide all others menu of this instance
123			if($.inArray(item, this.child_open) < this.child_open.length -1){
124				this.hide_others(item);
125			}
126
127			// hide all for other instances as well
128			$(document.body).trigger('hideall.t3menu', [this]);
129			
130			clearTimeout(this.timer);		//hide alls
131			clearTimeout(item.timer);		//hide this item
132			clearTimeout(item.ftimer);	//on hidden
133			clearTimeout(item.ctimer);	//on hidden
134
135			if(item.status != 'open' || !item.$item.hasClass('open') || !this.child_open.length){
136				if(item.mega){
137					//remove timer
138					clearTimeout(item.astimer);	//animate
139					clearTimeout(item.atimer);	//animate
140
141					//place menu
142					this.position(item.$item);
143
144					// add class animate
145					item.astimer = setTimeout(function(){item.$item.addClass('animating')}, 10);
146					item.atimer = setTimeout(function(){item.$item.removeClass('animating')}, this.options.duration + 50);
147					item.timer = setTimeout(function(){item.$item.addClass('open')}, 100);
148
149				} else {
150					item.$item.addClass('open');
151				}
152
153				item.status = 'open';
154				if (item.child && $.inArray(item, this.child_open) == -1) {
155					this.child_open.push(item);
156				}
157			}
158
159			item.ctimer = setTimeout($.proxy(this.clickable, this, item), 300);
160		},
161
162		hide: function (item) {
163			clearTimeout(this.timer);		//hide alls
164			clearTimeout(item.timer);		//hide this item
165			clearTimeout(item.astimer);	//animate timer
166			clearTimeout(item.atimer);	//animate timer
167			clearTimeout(item.ftimer);	//on hidden
168
169			if(item.mega){
170				//animate out
171				item.$item.addClass('animating');
172				item.atimer = setTimeout(function(){item.$item.removeClass('animating')}, this.options.duration);
173				item.timer = setTimeout(function(){item.$item.removeClass('open')}, 100);
174			} else {
175				item.$item.removeClass('open');
176			}
177
178			item.status = 'close';
179			for (var i = this.child_open.length; i--;){
180				if (this.child_open[i] === item){
181					this.child_open.splice(i, 1);
182				}
183			}
184
185			item.ftimer = setTimeout($.proxy(this.hidden, this, item), this.options.duration);
186			this.timer = setTimeout($.proxy(this.hide_alls, this), this.options.hidedelay);
187		},
188
189		hidden: function (item) {
190			//hide done
191			if (item.status == 'close') {
192				item.clickable = false;
193			}
194		},
195
196		hide_others: function (item) {
197			var self = this;
198			$.each(this.child_open.slice(), function (idx, open) {
199				if (!item || (open != item && !open.$item.has(item.$item).length)) {
200					self.hide(open);
201				}
202			});
203		},
204
205		hide_alls: function (e, inst) {
206			if(!e || e.type == 'tap' || (e.type == 'hideall' && this != inst)){
207				var self = this;
208				$.each(this.child_open.slice(), function (idx, item) {
209					item && self.hide(item);
210				});
211			}
212		},
213
214		clickable: function (item) {
215			item.clickable = true;
216		},
217
218		position: function ($item) {
219			var sub = $item.children('.mega-dropdown-menu'),
220				is_show = sub.is(':visible');
221
222			if(!is_show){
223				sub.show();
224			}
225
226			var offset = $item.offset(),
227				width = $item.outerWidth(),
228				screen_width = $(window).width() - this.options.sb_width,
229				sub_width = sub.outerWidth(),
230				level = $item.data('level');
231
232			if(!is_show){
233				sub.css('display', '');
234			}
235
236			//reset custom align
237			sub.css({left : '', right : ''});
238
239			if(level == 1){
240
241				var align = $item.data('alignsub'),
242					align_offset = 0,
243					align_delta = 0,
244					align_trans = 0;
245
246				if(align == 'justify'){
247					return;	//do nothing
248				}
249
250				if(!align){
251					align = 'left';
252				}
253
254				if(align == 'center'){
255					align_offset = offset.left + (width /2);
256
257					if(!$.support.t3transform){
258						align_trans = -sub_width /2;
259						sub.css(this.options.rtl ? 'right' : 'left', align_trans + width /2);
260					}
261
262				} else {
263					align_offset = offset.left + ((align == 'left' && this.options.rtl || align == 'right' && !this.options.rtl) ? width : 0);
264				}
265		
266				if (this.options.rtl) {
267
268					if(align == 'right'){
269						if(align_offset + sub_width > screen_width){
270							align_delta = screen_width - align_offset - sub_width;
271							sub.css('left', align_delta);
272
273							if(screen_width < sub_width){
274								sub.css('left', align_delta + sub_width - screen_width);
275							}
276						}
277					} else {
278						if(align_offset < (align == 'center' ? sub_width /2 : sub_width)){
279							align_delta = align_offset - (align == 'center' ? sub_width /2 : sub_width);
280							sub.css('right', align_delta + align_trans);
281						}
282
283						if(align_offset + (align == 'center' ? sub_width /2 : 0) - align_delta > screen_width){
284							sub.css('right', align_offset + (align == 'center' ? (sub_width + width) /2 : 0) + align_trans - screen_width);
285						}
286					}
287
288				} else {
289
290					if(align == 'right'){
291						if(align_offset < sub_width){
292							align_delta = align_offset - sub_width;
293							sub.css('right', align_delta);
294
295							if(sub_width > screen_width){
296								sub.css('right', sub_width - screen_width + align_delta);
297							}
298						}
299					} else {
300
301						if(align_offset + (align == 'center' ? sub_width /2 : sub_width) > screen_width){
302							align_delta = screen_width - align_offset -(align == 'center' ? sub_width /2 : sub_width);
303							sub.css('left', align_delta + align_trans);
304						}
305
306						if(align_offset - (align == 'center' ? sub_width /2 : 0) + align_delta < 0){
307							sub.css('left', (align == 'center' ? (sub_width + width) /2 : 0) + align_trans - align_offset);
308						}
309					}
310				}
311			} else {
312
313				if (this.options.rtl) {
314					if ($item.closest('.mega-dropdown-menu').parent().hasClass('mega-align-right')) {
315
316						//should be align to the right as parent
317						// $item.removeClass('mega-align-left').addClass('mega-align-right');
318
319						// check if not able => revert the direction
320						if (offset.left + width + sub_width > screen_width) {
321							$item.removeClass('mega-align-right'); //should we add align left ? it is th default now
322
323							if(offset.left - sub_width < 0){
324								sub.css('right', offset.left + width - sub_width);
325							}
326						}
327					} else {
328						if (offset.left - sub_width < 0) {
329							$item.removeClass('mega-align-left').addClass('mega-align-right');
330
331							if(offset.left + width + sub_width > screen_width){
332								sub.css('left', screen_width - offset.left - sub_width);
333							}
334						}
335					}
336				} else {
337
338					if ($item.closest('.mega-dropdown-menu').parent().hasClass('mega-align-right')) {
339						//should be align to the right as parent
340						// $item.removeClass('mega-align-left').addClass('mega-align-right');
341
342						// check if not able => revert the direction
343						if (offset.left - sub_width < 0) {
344							$item.removeClass('mega-align-right'); //should we add align left ? it is th default now
345
346							if(offset.left + width + sub_width > screen_width){
347								sub.css('left', screen_width - offset.left - sub_width);
348							}
349						}
350					} else {
351
352						if (offset.left + width + sub_width > screen_width) {
353							$item.removeClass('mega-align-left').addClass('mega-align-right');
354
355							if(offset.left - sub_width < 0){
356								sub.css('right', offset.left + width - sub_width);
357							}
358						}
359					}
360				}
361			}
362		}
363	};
364
365	$.fn.t3menu = function (option) {
366		return this.each(function () {
367			var $this = $(this),
368				data = $this.data('megamenu'),
369				options = typeof option == 'object' && option;
370			
371			if (!data) {
372				$this.data('megamenu', (data = new T3Menu(this, options)));
373				
374			} else {
375				if (typeof option == 'string' && data[option]){
376					data[option]()
377				}
378			}
379		})
380	};
381
382	$.fn.t3menu.defaults = {
383		duration: 400,
384		timeout: 100,
385		hidedelay: 200,
386		hover: true,
387		sb_width: 20
388	};
389
390
391	//apply script
392	$(document).ready(function(){
393
394		//detect settings
395		var mm_duration = $('.t3-megamenu').data('duration') || 0;
396		if (mm_duration) {
397
398			$('<style type="text/css">' +
399					'.t3-megamenu.animate .animating > .mega-dropdown-menu,' +
400					'.t3-megamenu.animate.slide .animating > .mega-dropdown-menu > div {' +
401						'transition-duration: ' + mm_duration + 'ms !important;' +
402						'-webkit-transition-duration: ' + mm_duration + 'ms !important;' +
403					'}
403' +
404				'</style>').appendTo ('head');
405		}
406
407		var mm_timeout = mm_duration ? 100 + mm_duration : 500,
408			mm_rtl = $(document.documentElement).attr('dir') == 'rtl',
409			mm_trigger = $(document.documentElement).hasClass('mm-hover'),
410			sb_width = (function () { 
411			var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
412				child = parent.children(),
413				width = child.innerWidth() - child.height(100).innerWidth();
414
415			parent.remove();
416
417			return width;
418		})();
419
420		//lt IE 10
421		if(!$.support.transition){
422			//it is not support animate
423			$('.t3-megamenu').removeClass('animate');
424			
425			mm_timeout = 100;
426		}
427
428		//get ready
429		$('.nav').has('.dropdown-menu').t3menu({
430			duration: mm_duration,
431			timeout: mm_timeout,
432			rtl: mm_rtl,
433			sb_width: sb_width,
434			hover: mm_trigger
435		});
436
437
438		$(window).load(function(){
439			
440			//check we miss any nav
441			$('.nav').has('.dropdown-menu').t3menu({
442				duration: mm_duration,
443				timeout: mm_timeout,
444				rtl: mm_rtl,
445				sb_width: sb_width,
446				hover: mm_trigger
447			});
448
449		});
450	});
451
452})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.