text: /*
   * jQuery Navgoco Menus Plugin v0.2.1 (2014-04-11)
   * https://github.com/tefra/navgoco
   *
   * Copyright (c) 2014 Chris T (@tefra)
   * BSD - https://github.com/tefra/navgoco/blob/master/LICENSE-BSD
   */
  (function($) {
  
  	"use strict";
  
  	/**
  	 * Plugin Constructor. Every menu must have a unique id which will either
  	 * be the actual id attribute or its index in the page.
  	 *
  	 * @param {Element} el
  	 * @param {Object} options
  	 * @param {Integer} idx
  	 * @returns {Object} Plugin Instance
  	 */
  	var Plugin = function(el, options, idx) {
  		this.el = el;
  		this.$el = $(el);
  		this.options = options;
  		this.uuid = this.$el.attr('id') ? this.$el.attr('id') : idx;
  		this.state = {};
  		this.init();
  		return this;
  	};
  
  	/**
  	 * Plugin methods
  	 */
  	Plugin.prototype = {
  		/**
  		 * Load cookie, assign a unique data-index attribute to
  		 * all sub-menus and show|hide them according to cookie
  		 * or based on the parent open class. Find all parent li > a
  		 * links add the carent if it's on and attach the event click
  		 * to them.
  		 */
  		init: function() {
  			var self = this;
  			self._load();
  			self.$el.find('ul').each(function(idx) {
  				var sub = $(this);
  				sub.attr('data-index', idx);
  				if (self.options.save && self.state.hasOwnProperty(idx)) {
  					sub.parent().addClass(self.options.openClass);
  					sub.show();
  				} else if (sub.parent().hasClass(self.options.openClass)) {
  					sub.show();
  					self.state[idx] = 1;
  				} else {
  					sub.hide();
  				}
  			});
  
  			var caret = $('<span></span>').prepend(self.options.caretHtml);
  			var links = self.$el.find("li > a");
  			self._trigger(caret, false);
  			self._trigger(links, true);
  			self.$el.find("li:has(ul) > a").prepend(caret);
  		},
  		/**
  		 * Add the main event trigger to toggle menu items to the given sources
  		 * @param {Element} sources
  		 * @param {Boolean} isLink
  		 */
  		_trigger: function(sources, isLink) {
  			var self = this;
  			sources.on('click', function(event) {
  				event.stopPropagation();
  				var sub = isLink ? $(this).next() : $(this).parent().next();
  				var isAnchor = false;
  				if (isLink) {
  					var href = $(this).attr('href');
  					isAnchor = href === undefined || href === '' || href === '#';
  				}
  				sub = sub.length > 0 ? sub : false;
  				self.options.onClickBefore.call(this, event, sub);
  
  				if (!isLink || sub && isAnchor) {
  					event.preventDefault();
  					self._toggle(sub, sub.is(":hidden"));
  					self._save();
  				} else if (self.options.accordion) {
  					var allowed = self.state = self._parents($(this));
  					self.$el.find('ul').filter(':visible').each(function() {
  						var sub = $(this),
  							idx = sub.attr('data-index');
  
  						if (!allowed.hasOwnProperty(idx)) {
  							self._toggle(sub, false);
  						}
  					});
  					self._save();
  				}
  				self.options.onClickAfter.call(this, event, sub);
  			});
  		},
  		/**
  		 * Accepts a JQuery Element and a boolean flag. If flag is false it removes the `open` css
  		 * class from the parent li and slides up the sub-menu. If flag is open it adds the `open`
  		 * css class to the parent li and slides down the menu. If accordion mode is on all
  		 * sub-menus except the direct parent tree will close. Internally an object with the menus
  		 * states is maintained for later save duty.
  		 *
  		 * @param {Element} sub
  		 * @param {Boolean} open
  		 */
  		_toggle: function(sub, open) {
  			var self = this,
  				idx = sub.attr('data-index'),
  				parent = sub.parent();
  
  			self.options.onToggleBefore.call(this, sub, open);
  			if (open) {
  				parent.addClass(self.options.openClass);
  				sub.slideDown(self.options.slide);
  				self.state[idx] = 1;
  
  				if (self.options.accordion) {
  					var allowed = self.state = self._parents(sub);
  					allowed[idx] = self.state[idx] = 1;
  
  					self.$el.find('ul').filter(':visible').each(function() {
  						var sub = $(this),
  							idx = sub.attr('data-index');
  
  						if (!allowed.hasOwnProperty(idx)) {
  							self._toggle(sub, false);
  						}
  					});
  				}
  			} else {
  				parent.removeClass(self.options.openClass);
  				sub.slideUp(self.options.slide);
  				self.state[idx] = 0;
  			}
  			self.options.onToggleAfter.call(this, sub, open);
  		},
  		/**
  		 * Returns all parents of a sub-menu. When obj is true It returns an object with indexes for
  		 * keys and the elements as values, if obj is false the object is filled with the value `1`.
  		 *
  		 * @since v0.1.2
  		 * @param {Element} sub
  		 * @param {Boolean} obj
  		 * @returns {Object}
  		 */
  		_parents: function(sub, obj) {
  			var result = {},
  				parent = sub.parent(),
  				parents = parent.parents('ul');
  
  			parents.each(function() {
  				var par = $(this),
  					idx = par.attr('data-index');
  
  				if (!idx) {
  					return false;
  				}
  				result[idx] = obj ? par : 1;
  			});
  			return result;
  		},
  		/**
  		 * If `save` option is on the internal object that keeps track of the sub-menus states is
  		 * saved with a cookie. For size reasons only the open sub-menus indexes are stored.		 *
  		 */
  		_save: function() {
  			if (this.options.save) {
  				var save = {};
  				for (var key in this.state) {
  					if (this.state[key] === 1) {
  						save[key] = 1;
  					}
  				}
  				cookie[this.uuid] = this.state = save;
  				$.cookie(this.options.cookie.name, JSON.stringify(cookie), this.options.cookie);
  			}
  		},
  		/**
  		 * If `save` option is on it reads the cookie data. The cookie contains data for all
  		 * navgoco menus so the read happens only once and stored in the global `cookie` var.
  		 */
  		_load: function() {
  			if (this.options.save) {
  				if (cookie === null) {
  					var data = $.cookie(this.options.cookie.name);
  					cookie = (data) ? JSON.parse(data) : {};
  				}
  				this.state = cookie.hasOwnProperty(this.uuid) ? cookie[this.uuid] : {};
  			}
  		},
  		/**
  		 * Public method toggle to manually show|hide sub-menus. If no indexes are provided all
  		 * items will be toggled. You can pass sub-menus indexes as regular params. eg:
  		 * navgoco('toggle', true, 1, 2, 3, 4, 5);
  		 *
  		 * Since v0.1.2 it will also open parents when providing sub-menu indexes.
  		 *
  		 * @param {Boolean} open
  		 */
  		toggle: function(open) {
  			var self = this,
  				length = arguments.length;
  
  			if (length <= 1) {
  				self.$el.find('ul').each(function() {
  					var sub = $(this);
  					self._toggle(sub, open);
  				});
  			} else {
  				var idx,
  					list = {},
  					args = Array.prototype.slice.call(arguments, 1);
  				length--;
  
  				for (var i = 0; i < length; i++) {
  					idx = args[i];
  					var sub = self.$el.find('ul[data-index="' + idx + '"]').first();
  					if (sub) {
  						list[idx] = sub;
  						if (open) {
  							var parents = self._parents(sub, true);
  							for (var pIdx in parents) {
  								if (!list.hasOwnProperty(pIdx)) {
  									list[pIdx] = parents[pIdx];
  								}
  							}
  						}
  					}
  				}
  
  				for (idx in list) {
  					self._toggle(list[idx], open);
  				}
  			}
  			self._save();
  		},
  		/**
  		 * Removes instance from JQuery data cache and unbinds events.
  		 */
  		destroy: function() {
  			$.removeData(this.$el);
  			this.$el.find("li:has(ul) > a").unbind('click');
  			this.$el.find("li:has(ul) > a > span").unbind('click');
  		}
  	};
  
  	/**
  	 * A JQuery plugin wrapper for navgoco. It prevents from multiple instances and also handles
  	 * public methods calls. If we attempt to call a public method on an element that doesn't have
  	 * a navgoco instance, one will be created for it with the default options.
  	 *
  	 * @param {Object|String} options
  	 */
  	$.fn.navgoco = function(options) {
  		if (typeof options === 'string' && options.charAt(0) !== '_' && options !== 'init') {
  			var callback = true,
  				args = Array.prototype.slice.call(arguments, 1);
  		} else {
  			options = $.extend({}, $.fn.navgoco.defaults, options || {});
  			if (!$.cookie) {
  				options.save = false;
  			}
  		}
  		return this.each(function(idx) {
  			var $this = $(this),
  				obj = $this.data('navgoco');
  
  			if (!obj) {
  				obj = new Plugin(this, callback ? $.fn.navgoco.defaults : options, idx);
  				$this.data('navgoco', obj);
  			}
  			if (callback) {
  				obj[options].apply(obj, args);
  			}
  		});
  	};
  	/**
  	 * Global var holding all navgoco menus open states
  	 *
  	 * @type {Object}
  	 */
  	var cookie = null;
  
  	/**
  	 * Default navgoco options
  	 *
  	 * @type {Object}
  	 */
  	$.fn.navgoco.defaults = {
  		caretHtml: '',
  		accordion: false,
  		openClass: 'open',
  		save: true,
  		cookie: {
  			name: 'navgoco',
  			expires: false,
  			path: '/'
  		},
  		slide: {
  			duration: 400,
  			easing: 'swing'
  		},
  		onClickBefore: $.noop,
  		onClickAfter: $.noop,
  		onToggleBefore: $.noop,
  		onToggleAfter: $.noop
  	};
  })(jQuery);