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