]> git.mxchange.org Git - friendica.git/blob - view/theme/frio/frameworks/flexMenu/flexmenu.custom.js
restructuring for PR for friendica main repo
[friendica.git] / view / theme / frio / frameworks / flexMenu / flexmenu.custom.js
1 /*      jQuery.flexMenu 1.3
2         https://github.com/352Media/flexMenu
3         Description: If a list is too long for all items to fit on one line, display a popup menu instead.
4         Dependencies: jQuery, Modernizr (optional). Without Modernizr, the menu can only be shown on click (not hover). */
5
6 (function (factory) {
7         if (typeof define === 'function' && define.amd) {
8                 // AMD. Register as an anonymous module.
9                 define(['jquery'], factory);
10         } else {
11                 // Browser globals
12                 factory(jQuery);
13         }
14 }(function ($) {
15         var flexObjects = [], // Array of all flexMenu objects
16                 resizeTimeout;
17         // When the page is resized, adjust the flexMenus.
18         function adjustFlexMenu() {
19                 $(flexObjects).each(function () {
20                         $(this).flexMenu({
21                                 'undo' : true,
22                                 'target': this.options.target ? this.options.target : false
23                         }).flexMenu(this.options);
24                 });
25         }
26         function collapseAllExcept($menuToAvoid) {
27                 var $activeMenus,
28                         $menusToCollapse;
29                 $activeMenus = $('li.flexMenu-viewMore.active');
30                 $menusToCollapse = $activeMenus.not($menuToAvoid);
31                 $menusToCollapse.removeClass('active').find('> ul').hide();
32         }
33         $(window).resize(function () {
34                 clearTimeout(resizeTimeout);
35                 resizeTimeout = setTimeout(function () {
36                         adjustFlexMenu();
37                 }, 200);
38         });
39         $.fn.flexMenu = function (options) {
40                 var checkFlexObject,
41                         s = $.extend({
42                                 'threshold' : 2, // [integer] If there are this many items or fewer in the list, we will not display a "View More" link and will instead let the list break to the next line. This is useful in cases where adding a "view more" link would actually cause more things to break  to the next line.
43                                 'cutoff' : 2, // [integer] If there is space for this many or fewer items outside our "more" popup, just move everything into the more menu. In that case, also use linkTextAll and linkTitleAll instead of linkText and linkTitle. To disable this feature, just set this value to 0.
44                                 'linkText' : 'More', // [string] What text should we display on the "view more" link?
45                                 'linkTitle' : 'View More', // [string] What should the title of the "view more" button be?
46                                 'linkTextAll' : 'Menu', // [string] If we hit the cutoff, what text should we display on the "view more" link?
47                                 'linkTitleAll' : 'Open/Close Menu', // [string] If we hit the cutoff, what should the title of the "view more" button be?
48                                 'showOnHover' : true, // [boolean] Should we we show the menu on hover? If not, we'll require a click. If we're on a touch device - or if Modernizr is not available - we'll ignore this setting and only show the menu on click. The reason for this is that touch devices emulate hover events in unpredictable ways, causing some taps to do nothing.
49                                 'popupAbsolute' : true, // [boolean] Should we absolutely position the popup? Usually this is a good idea. That way, the popup can appear over other content and spill outside a parent that has overflow: hidden set. If you want to do something different from this in CSS, just set this option to false.
50                                 'popupClass' : '', // [string] If this is set, this class will be added to the popup
51                                 'undo' : false, // [boolean] Move the list items back to where they were before, and remove the "View More" link.
52                                 'target': false // Maybe add a target option to define where to place the removed nav items
53                         }, options);
54                 this.options = s; // Set options on object
55                 checkFlexObject = $.inArray(this, flexObjects); // Checks if this object is already in the flexObjects array
56                 if (checkFlexObject >= 0) {
57                         flexObjects.splice(checkFlexObject, 1); // Remove this object if found
58                 } else {
59                         flexObjects.push(this); // Add this object to the flexObjects array
60                 }
61                 if(s.target)
62                         $(s.target).hide();
63                 return this.each(function () {
64                         var $this = $(this),
65                                 $items = $this.find('> li'),
66                                 $self = $this,
67                                 $firstItem = $items.first(),
68                                 $lastItem = $items.last(),
69                                 numItems = $this.find('li').length,
70                                 firstItemTop = Math.floor($firstItem.offset().top),
71                                 firstItemHeight = Math.floor($firstItem.outerHeight(true)),
72                                 $lastChild,
73                                 keepLooking,
74                                 $moreItem,
75                                 $moreLink,
76                                 numToRemove,
77                                 allInPopup = false,
78                                 $menu,
79                                 $target = s.target,
80                                 i;
81                         function needsMenu($itemOfInterest) {
82                                 var result = (Math.ceil($itemOfInterest.offset().top) >= (firstItemTop + firstItemHeight)) ? true : false;
83                                 // Values may be calculated from em and give us something other than round numbers. Browsers may round these inconsistently. So, let's round numbers to make it easier to trigger flexMenu.
84                                 return result;
85                         }
86                         if (needsMenu($lastItem) && numItems > s.threshold && !s.undo && $this.is(':visible')) {
87                                 var $popup = $('<ul class="flexMenu-popup" style="display:none;' + ((s.popupAbsolute) ? ' position: absolute;' : '') + '"></ul>'),
88                                 // Move all list items after the first to this new popup ul
89                                         firstItemOffset = $firstItem.offset().top;
90                                 // Add class if popupClass option is set
91                                 $popup.addClass(s.popupClass);
92
93                                 if($target){
94                                         $popup = $('<ul class="flexMenu-popup ' + s.popupClass + '"></ul>')
95                                                 $popup.appendTo($($target));
96                                                 $($target).show();
97                                 }
98
99                                 for (i = numItems; i > 1; i--) {
100                                                 // Find all of the list items that have been pushed below the first item. Put those items into the popup menu. Put one additional item into the popup menu to cover situations where the last item is shorter than the "more" text.
101                                                 $lastChild = $this.find('> li:last-child');
102                                                 keepLooking = (needsMenu($lastChild));
103                                                 $lastChild.appendTo($popup);
104                                                 // If there only a few items left in the navigation bar, move them all to the popup menu.
105                                                 if ((i - 1) <= s.cutoff) { // We've removed the ith item, so i - 1 gives us the number of items remaining.
106                                                         $($this.children().get().reverse()).appendTo($popup);
107                                                         allInPopup = true;
108                                                         break;
109                                                 }
110                                                 if (!keepLooking) {
111                                                         break;
112                                                 }
113                                 }
114
115                                 if(!$target){
116                                         if (allInPopup) {
117                                                 $this.append('<li class="flexMenu-viewMore flexMenu-allInPopup"><a href="#" title="' + s.linkTitleAll + '">' + s.linkTextAll + '</a></li>');
118                                         } else {
119                                                 $this.append('<li class="flexMenu-viewMore"><a href="#" title="' + s.linkTitle + '">' + s.linkText + '</a></li>');
120                                         }
121                                         $moreItem = $this.find('> li.flexMenu-viewMore');
122                                         /// Check to see whether the more link has been pushed down. This might happen if the link immediately before it is especially wide.
123                                         if (needsMenu($moreItem)) {
124                                                 $this.find('> li:nth-last-child(2)').appendTo($popup);
125                                         }
126                                         // Our popup menu is currently in reverse order. Let's fix that.
127                                         $popup.children().each(function (i, li) {
128                                                 $popup.prepend(li);
129                                         });
130                                         $moreItem.append($popup);
131                                         $moreLink = $this.find('> li.flexMenu-viewMore > a');
132                                         $moreLink.click(function (e) {
133                                                 // Collapsing any other open flexMenu
134                                                 collapseAllExcept($moreItem);
135                                                 //Open and Set active the one being interacted with.
136                                                 $popup.toggle();
137                                                 $moreItem.toggleClass('active');
138                                                 e.preventDefault();
139                                         });
140                                         if (s.showOnHover && (typeof Modernizr !== 'undefined') && !Modernizr.touch) { // If requireClick is false AND touch is unsupported, then show the menu on hover. If Modernizr is not available, assume that touch is unsupported. Through the magic of lazy evaluation, we can check for Modernizr and start using it in the same if statement. Reversing the order of these variables would produce an error.
141                                                 $moreItem.hover(
142                                                         function () {
143                                                                 $popup.show();
144                                                                 $(this).addClass('active');
145                                                         },
146                                                         function () {
147                                                                 $popup.hide();
148                                                                 $(this).removeClass('active');
149                                                         });
150                                         }
151                                 }
152                         } else if (s.undo) {
153                                 $menu = $target ? $($target).find('ul.flexMenu-popup') : $this.find('ul.flexMenu-popup');
154                                 if($menu.length){
155                                         numToRemove = $menu.find('li').length;
156                                         for (i = 1; i <= numToRemove; i++) {
157                                                 $menu.find('> li:first-child').appendTo($this);
158                                         }
159                                         $menu.remove();
160                                         $target ? $($target).find('> li.flexMenu-viewMore').remove() : $this.find('> li.flexMenu-viewMore').remove();
161                                 }
162                         }
163                 });
164         };
165 }));