1/* 2 * jQuery Navgoco Menus Plugin v0.2.1 (2014-04-11) 3 * https://github.com/tefra/navgoco 4 * 5 * Copyright (c) 2014 Chris T (@tefra) 6 * BSD - https://github.com/tefra/navgoco/blob/master/LICENSE-BSD 7 */ 8(function($) { 9 10 "use strict"; 11 12 /** 13 * Plugin Constructor. Every menu must have a unique id which will either 14 * be the actual id attribute or its index in the page. 15 * 16 * @param {Element} el 17 * @param {Object} options 18 * @param {Integer} idx 19 * @returns {Object} Plugin Instance 20 */ 21 var Plugin = function(el, options, idx) { 22 this.el = el; 23 this.$el = $(el); 24 this.options = options; 25 this.uuid = this.$el.attr('id') ? this.$el.attr('id') : idx; 26 this.state = {}; 27 this.init(); 28 return this; 29 }; 30 31 /** 32 * Plugin methods 33 */ 34 Plugin.prototype = { 35 /** 36 * Load cookie, assign a unique data-index attribute to 37 * all sub-menus and show|hide them according to cookie 38 * or based on the parent open class. Find all parent li > a 39 * links add the carent if it's on and attach the event click 40 * to them. 41 */ 42 init: function() { 43 var self = this; 44 self._load(); 45 self.$el.find('ul').each(function(idx) { 46 var sub = $(this); 47 sub.attr('data-index', idx); 48 if (self.options.save && self.state.hasOwnProperty(idx)) { 49 sub.parent().addClass(self.options.openClass); 50 sub.show(); 51 } else if (sub.parent().hasClass(self.options.openClass)) { 52 sub.show(); 53 self.state[idx] = 1; 54 } else { 55 sub.hide(); 56 } 57 }); 58 59 var caret = $('<span class="wpb-submenu-indicator"></span>').prepend(self.options.caretHtml); 60 var links = self.$el.find("li > a"); 61 self._trigger(caret, false); 62 self._trigger(links, true); 63 self.$el.find("li:has(ul) > a").prepend(caret); 64 }, 65 /** 66 * Add the main event trigger to toggle menu items to the given sources 67 * @param {Element} sources 68 * @param {Boolean} isLink 69 */ 70 _trigger: function(sources, isLink) { 71 var self = this; 72 sources.on('click', function(event) { 73 event.stopPropagation(); 74 var sub = isLink ? $(this).next() : $(this).parent().next(); 75 var isAnchor = false; 76 if (isLink) { 77 var href = $(this).attr('href'); 78 isAnchor = href === undefined || href === '' || href === '#'; 79 } 80 sub = sub.length > 0 ? sub : false; 81 self.options.onClickBefore.call(this, event, sub); 82 83 if (!isLink || sub && isAnchor) { 84 event.preventDefault(); 85 self._toggle(sub, sub.is(":hidden")); 86 self._save(); 87 } else if (self.options.accordion) { 88 var allowed = self.state = self._parents($(this)); 89 self.$el.find('ul').filter(':visible').each(function() { 90 var sub = $(this), 91 idx = sub.attr('data-index'); 92 93 if (!allowed.hasOwnProperty(idx)) { 94 self._toggle(sub, false); 95 } 96 }); 97 self._save(); 98 } 99 self.options.onClickAfter.call(this, event, sub); 100 }); 101 }, 102 /** 103 * Accepts a JQuery Element and a boolean flag. If flag is false it removes the `open` css 104 * class from the parent li and slides up the sub-menu. If flag is open it adds the `open` 105 * css class to the parent li and slides down the menu. If accordion mode is on all 106 * sub-menus except the direct parent tree will close. Internally an object with the menus 107 * states is maintained for later save duty. 108 * 109 * @param {Element} sub 110 * @param {Boolean} open 111 */ 112 _toggle: function(sub, open) { 113 var self = this, 114 idx = sub.attr('data-index'), 115 parent = sub.parent(); 116 117 self.options.onToggleBefore.call(this, sub, open); 118 if (open) { 119 parent.addClass(self.options.openClass); 120 sub.slideDown(self.options.slide); 121 self.state[idx] = 1; 122 123 if (self.options.accordion) { 124 var allowed = self.state = self._parents(sub); 125 allowed[idx] = self.state[idx] = 1; 126 127 self.$el.find('ul').filter(':visible').each(function() { 128 var sub = $(this), 129 idx = sub.attr('data-index'); 130 131 if (!allowed.hasOwnProperty(idx)) { 132 self._toggle(sub, false); 133 } 134 }); 135 } 136 } else { 137 parent.removeClass(self.options.openClass); 138 sub.slideUp(self.options.slide); 139 self.state[idx] = 0; 140 } 141 self.options.onToggleAfter.call(this, sub, open); 142 }, 143 /** 144 * Returns all parents of a sub-menu. When obj is true It returns an object with indexes for 145 * keys and the elements as values, if obj is false the object is filled with the value `1`. 146 * 147 * @since v0.1.2 148 * @param {Element} sub 149 * @param {Boolean} obj 150 * @returns {Object} 151 */ 152 _parents: function(sub, obj) { 153 var result = {}, 154 parent = sub.parent(), 155 parents = parent.parents('ul'); 156 157 parents.each(function() { 158 var par = $(this), 159 idx = par.attr('data-index'); 160 161 if (!idx) { 162 return false;
163 } 164 result[idx] = obj ? par : 1; 165 }); 166 return result; 167 }, 168 /** 169 * If `save` option is on the internal object that keeps track of the sub-menus states is 170 * saved with a cookie. For size reasons only the open sub-menus indexes are stored. * 171 */ 172 _save: function() { 173 if (this.options.save) { 174 var save = {}; 175 for (var key in this.state) { 176 if (this.state[key] === 1) { 177 save[key] = 1; 178 } 179 } 180 cookie[this.uuid] = this.state = save; 181 $.cookie(this.options.cookie.name, JSON.stringify(cookie), this.options.cookie); 182 } 183 }, 184 /** 185 * If `save` option is on it reads the cookie data. The cookie contains data for all 186 * navgoco menus so the read happens only once and stored in the global `cookie` var. 187 */ 188 _load: function() { 189 if (this.options.save) { 190 if (cookie === null) { 191 var data = $.cookie(this.options.cookie.name); 192 cookie = (data) ? JSON.parse(data) : {}; 193 } 194 this.state = cookie.hasOwnProperty(this.uuid) ? cookie[this.uuid] : {}; 195 } 196 }, 197 /** 198 * Public method toggle to manually show|hide sub-menus. If no indexes are provided all 199 * items will be toggled. You can pass sub-menus indexes as regular params. eg: 200 * navgoco('toggle', true, 1, 2, 3, 4, 5); 201 * 202 * Since v0.1.2 it will also open parents when providing sub-menu indexes. 203 * 204 * @param {Boolean} open 205 */ 206 toggle: function(open) { 207 var self = this, 208 length = arguments.length; 209 210 if (length <= 1) { 211 self.$el.find('ul').each(function() { 212 var sub = $(this); 213 self._toggle(sub, open); 214 }); 215 } else { 216 var idx, 217 list = {}, 218 args = Array.prototype.slice.call(arguments, 1); 219 length--; 220 221 for (var i = 0; i < length; i++) { 222 idx = args[i]; 223 var sub = self.$el.find('ul[data-index="' + idx + '"]').first(); 224 if (sub) { 225 list[idx] = sub; 226 if (open) { 227 var parents = self._parents(sub, true); 228 for (var pIdx in parents) { 229 if (!list.hasOwnProperty(pIdx)) { 230 list[pIdx] = parents[pIdx]; 231 } 232 } 233 } 234 } 235 } 236 237 for (idx in list) { 238 self._toggle(list[idx], open); 239 } 240 } 241 self._save(); 242 }, 243 /** 244 * Removes instance from JQuery data cache and unbinds events. 245 */ 246 destroy: function() { 247 $.removeData(this.$el); 248 this.$el.find("li:has(ul) > a").unbind('click'); 249 this.$el.find("li:has(ul) > a > span").unbind('click'); 250 } 251 }; 252 253 /** 254 * A JQuery plugin wrapper for navgoco. It prevents from multiple instances and also handles 255 * public methods calls. If we attempt to call a public method on an element that doesn't have 256 * a navgoco instance, one will be created for it with the default options. 257 * 258 * @param {Object|String} options 259 */ 260 $.fn.navgoco = function(options) { 261 if (typeof options === 'string' && options.charAt(0) !== '_' && options !== 'init') { 262 var callback = true, 263 args = Array.prototype.slice.call(arguments, 1); 264 } else { 265 options = $.extend({}, $.fn.navgoco.defaults, options || {}); 266 if (!$.cookie) { 267 options.save = false; 268 } 269 } 270 return this.each(function(idx) { 271 var $this = $(this), 272 obj = $this.data('navgoco'); 273 274 if (!obj) { 275 obj = new Plugin(this, callback ? $.fn.navgoco.defaults : options, idx); 276 $this.data('navgoco', obj); 277 } 278 if (callback) { 279 obj[options].apply(obj, args); 280 } 281 }); 282 }; 283 /** 284 * Global var holding all navgoco menus open states 285 * 286 * @type {Object} 287 */ 288 var cookie = null; 289 290 /** 291 * Default navgoco options 292 * 293 * @type {Object} 294 */ 295 $.fn.navgoco.defaults = { 296 caretHtml: '', 297 accordion: false, 298 openClass: 'open', 299 save: true, 300 cookie: { 301 name: 'navgoco', 302 expires: false, 303 path: '/' 304 }, 305 slide: { 306 duration: 400, 307 easing: 'swing' 308 }, 309 onClickBefore: $.noop, 310 onClickAfter: $.noop, 311 onToggleBefore: $.noop, 312 onToggleAfter: $.noop 313 }; 314})(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.