diff options
Diffstat (limited to 'public/bower_components/admin-lte/dist/js/adminlte.js')
-rw-r--r-- | public/bower_components/admin-lte/dist/js/adminlte.js | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/public/bower_components/admin-lte/dist/js/adminlte.js b/public/bower_components/admin-lte/dist/js/adminlte.js new file mode 100644 index 0000000..c413316 --- /dev/null +++ b/public/bower_components/admin-lte/dist/js/adminlte.js @@ -0,0 +1,1129 @@ +/*! AdminLTE app.js +* ================ +* Main JS application file for AdminLTE v2. This file +* should be included in all pages. It controls some layout +* options and implements exclusive AdminLTE plugins. +* +* @Author Almsaeed Studio +* @Support <https://www.almsaeedstudio.com> +* @Email <abdullah@almsaeedstudio.com> +* @version 2.4.2 +* @repository git://github.com/almasaeed2010/AdminLTE.git +* @license MIT <http://opensource.org/licenses/MIT> +*/ + +// Make sure jQuery has been loaded +if (typeof jQuery === 'undefined') { +throw new Error('AdminLTE requires jQuery') +} + +/* BoxRefresh() + * ========= + * Adds AJAX content control to a box. + * + * @Usage: $('#my-box').boxRefresh(options) + * or add [data-widget="box-refresh"] to the box element + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.boxrefresh'; + + var Default = { + source : '', + params : {}, + trigger : '.refresh-btn', + content : '.box-body', + loadInContent : true, + responseType : '', + overlayTemplate: '<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>', + onLoadStart : function () { + }, + onLoadDone : function (response) { + return response; + } + }; + + var Selector = { + data: '[data-widget="box-refresh"]' + }; + + // BoxRefresh Class Definition + // ========================= + var BoxRefresh = function (element, options) { + this.element = element; + this.options = options; + this.$overlay = $(options.overlay); + + if (options.source === '') { + throw new Error('Source url was not defined. Please specify a url in your BoxRefresh source option.'); + } + + this._setUpListeners(); + this.load(); + }; + + BoxRefresh.prototype.load = function () { + this._addOverlay(); + this.options.onLoadStart.call($(this)); + + $.get(this.options.source, this.options.params, function (response) { + if (this.options.loadInContent) { + $(this.options.content).html(response); + } + this.options.onLoadDone.call($(this), response); + this._removeOverlay(); + }.bind(this), this.options.responseType !== '' && this.options.responseType); + }; + + // Private + + BoxRefresh.prototype._setUpListeners = function () { + $(this.element).on('click', Selector.trigger, function (event) { + if (event) event.preventDefault(); + this.load(); + }.bind(this)); + }; + + BoxRefresh.prototype._addOverlay = function () { + $(this.element).append(this.$overlay); + }; + + BoxRefresh.prototype._removeOverlay = function () { + $(this.element).remove(this.$overlay); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new BoxRefresh($this, options))); + } + + if (typeof data == 'string') { + if (typeof data[option] == 'undefined') { + throw new Error('No method named ' + option); + } + data[option](); + } + }); + } + + var old = $.fn.boxRefresh; + + $.fn.boxRefresh = Plugin; + $.fn.boxRefresh.Constructor = BoxRefresh; + + // No Conflict Mode + // ================ + $.fn.boxRefresh.noConflict = function () { + $.fn.boxRefresh = old; + return this; + }; + + // BoxRefresh Data API + // ================= + $(window).on('load', function () { + $(Selector.data).each(function () { + Plugin.call($(this)); + }); + }); + +}(jQuery); + + +/* BoxWidget() + * ====== + * Adds box widget functions to boxes. + * + * @Usage: $('.my-box').boxWidget(options) + * This plugin auto activates on any element using the `.box` class + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.boxwidget'; + + var Default = { + animationSpeed : 500, + collapseTrigger: '[data-widget="collapse"]', + removeTrigger : '[data-widget="remove"]', + collapseIcon : 'fa-minus', + expandIcon : 'fa-plus', + removeIcon : 'fa-times' + }; + + var Selector = { + data : '.box', + collapsed: '.collapsed-box', + header : '.box-header', + body : '.box-body', + footer : '.box-footer', + tools : '.box-tools' + }; + + var ClassName = { + collapsed: 'collapsed-box' + }; + + var Event = { + collapsed: 'collapsed.boxwidget', + expanded : 'expanded.boxwidget', + removed : 'removed.boxwidget' + }; + + // BoxWidget Class Definition + // ===================== + var BoxWidget = function (element, options) { + this.element = element; + this.options = options; + + this._setUpListeners(); + }; + + BoxWidget.prototype.toggle = function () { + var isOpen = !$(this.element).is(Selector.collapsed); + + if (isOpen) { + this.collapse(); + } else { + this.expand(); + } + }; + + BoxWidget.prototype.expand = function () { + var expandedEvent = $.Event(Event.expanded); + var collapseIcon = this.options.collapseIcon; + var expandIcon = this.options.expandIcon; + + $(this.element).removeClass(ClassName.collapsed); + + $(this.element) + .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer) + .children(Selector.tools) + .find('.' + expandIcon) + .removeClass(expandIcon) + .addClass(collapseIcon); + + $(this.element).children(Selector.body + ', ' + Selector.footer) + .slideDown(this.options.animationSpeed, function () { + $(this.element).trigger(expandedEvent); + }.bind(this)); + }; + + BoxWidget.prototype.collapse = function () { + var collapsedEvent = $.Event(Event.collapsed); + var collapseIcon = this.options.collapseIcon; + var expandIcon = this.options.expandIcon; + + $(this.element) + .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer) + .children(Selector.tools) + .find('.' + collapseIcon) + .removeClass(collapseIcon) + .addClass(expandIcon); + + $(this.element).children(Selector.body + ', ' + Selector.footer) + .slideUp(this.options.animationSpeed, function () { + $(this.element).addClass(ClassName.collapsed); + $(this.element).trigger(collapsedEvent); + }.bind(this)); + }; + + BoxWidget.prototype.remove = function () { + var removedEvent = $.Event(Event.removed); + + $(this.element).slideUp(this.options.animationSpeed, function () { + $(this.element).trigger(removedEvent); + $(this.element).remove(); + }.bind(this)); + }; + + // Private + + BoxWidget.prototype._setUpListeners = function () { + var that = this; + + $(this.element).on('click', this.options.collapseTrigger, function (event) { + if (event) event.preventDefault(); + that.toggle($(this)); + return false; + }); + + $(this.element).on('click', this.options.removeTrigger, function (event) { + if (event) event.preventDefault(); + that.remove($(this)); + return false; + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new BoxWidget($this, options))); + } + + if (typeof option == 'string') { + if (typeof data[option] == 'undefined') { + throw new Error('No method named ' + option); + } + data[option](); + } + }); + } + + var old = $.fn.boxWidget; + + $.fn.boxWidget = Plugin; + $.fn.boxWidget.Constructor = BoxWidget; + + // No Conflict Mode + // ================ + $.fn.boxWidget.noConflict = function () { + $.fn.boxWidget = old; + return this; + }; + + // BoxWidget Data API + // ================== + $(window).on('load', function () { + $(Selector.data).each(function () { + Plugin.call($(this)); + }); + }); +}(jQuery); + + +/* ControlSidebar() + * =============== + * Toggles the state of the control sidebar + * + * @Usage: $('#control-sidebar-trigger').controlSidebar(options) + * or add [data-toggle="control-sidebar"] to the trigger + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.controlsidebar'; + + var Default = { + slide: true + }; + + var Selector = { + sidebar: '.control-sidebar', + data : '[data-toggle="control-sidebar"]', + open : '.control-sidebar-open', + bg : '.control-sidebar-bg', + wrapper: '.wrapper', + content: '.content-wrapper', + boxed : '.layout-boxed' + }; + + var ClassName = { + open : 'control-sidebar-open', + fixed: 'fixed' + }; + + var Event = { + collapsed: 'collapsed.controlsidebar', + expanded : 'expanded.controlsidebar' + }; + + // ControlSidebar Class Definition + // =============================== + var ControlSidebar = function (element, options) { + this.element = element; + this.options = options; + this.hasBindedResize = false; + + this.init(); + }; + + ControlSidebar.prototype.init = function () { + // Add click listener if the element hasn't been + // initialized using the data API + if (!$(this.element).is(Selector.data)) { + $(this).on('click', this.toggle); + } + + this.fix(); + $(window).resize(function () { + this.fix(); + }.bind(this)); + }; + + ControlSidebar.prototype.toggle = function (event) { + if (event) event.preventDefault(); + + this.fix(); + + if (!$(Selector.sidebar).is(Selector.open) && !$('body').is(Selector.open)) { + this.expand(); + } else { + this.collapse(); + } + }; + + ControlSidebar.prototype.expand = function () { + if (!this.options.slide) { + $('body').addClass(ClassName.open); + } else { + $(Selector.sidebar).addClass(ClassName.open); + } + + $(this.element).trigger($.Event(Event.expanded)); + }; + + ControlSidebar.prototype.collapse = function () { + $('body, ' + Selector.sidebar).removeClass(ClassName.open); + $(this.element).trigger($.Event(Event.collapsed)); + }; + + ControlSidebar.prototype.fix = function () { + if ($('body').is(Selector.boxed)) { + this._fixForBoxed($(Selector.bg)); + } + }; + + // Private + + ControlSidebar.prototype._fixForBoxed = function (bg) { + bg.css({ + position: 'absolute', + height : $(Selector.wrapper).height() + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new ControlSidebar($this, options))); + } + + if (typeof option == 'string') data.toggle(); + }); + } + + var old = $.fn.controlSidebar; + + $.fn.controlSidebar = Plugin; + $.fn.controlSidebar.Constructor = ControlSidebar; + + // No Conflict Mode + // ================ + $.fn.controlSidebar.noConflict = function () { + $.fn.controlSidebar = old; + return this; + }; + + // ControlSidebar Data API + // ======================= + $(document).on('click', Selector.data, function (event) { + if (event) event.preventDefault(); + Plugin.call($(this), 'toggle'); + }); + +}(jQuery); + + +/* DirectChat() + * =============== + * Toggles the state of the control sidebar + * + * @Usage: $('#my-chat-box').directChat() + * or add [data-widget="direct-chat"] to the trigger + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.directchat'; + + var Selector = { + data: '[data-widget="chat-pane-toggle"]', + box : '.direct-chat' + }; + + var ClassName = { + open: 'direct-chat-contacts-open' + }; + + // DirectChat Class Definition + // =========================== + var DirectChat = function (element) { + this.element = element; + }; + + DirectChat.prototype.toggle = function ($trigger) { + $trigger.parents(Selector.box).first().toggleClass(ClassName.open); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + $this.data(DataKey, (data = new DirectChat($this))); + } + + if (typeof option == 'string') data.toggle($this); + }); + } + + var old = $.fn.directChat; + + $.fn.directChat = Plugin; + $.fn.directChat.Constructor = DirectChat; + + // No Conflict Mode + // ================ + $.fn.directChat.noConflict = function () { + $.fn.directChat = old; + return this; + }; + + // DirectChat Data API + // =================== + $(document).on('click', Selector.data, function (event) { + if (event) event.preventDefault(); + Plugin.call($(this), 'toggle'); + }); + +}(jQuery); + + +/* Layout() + * ======== + * Implements AdminLTE layout. + * Fixes the layout height in case min-height fails. + * + * @usage activated automatically upon window load. + * Configure any options by passing data-option="value" + * to the body tag. + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.layout'; + + var Default = { + slimscroll : true, + resetHeight: true + }; + + var Selector = { + wrapper : '.wrapper', + contentWrapper: '.content-wrapper', + layoutBoxed : '.layout-boxed', + mainFooter : '.main-footer', + mainHeader : '.main-header', + sidebar : '.sidebar', + controlSidebar: '.control-sidebar', + fixed : '.fixed', + sidebarMenu : '.sidebar-menu', + logo : '.main-header .logo' + }; + + var ClassName = { + fixed : 'fixed', + holdTransition: 'hold-transition' + }; + + var Layout = function (options) { + this.options = options; + this.bindedResize = false; + this.activate(); + }; + + Layout.prototype.activate = function () { + this.fix(); + this.fixSidebar(); + + $('body').removeClass(ClassName.holdTransition); + + if (this.options.resetHeight) { + $('body, html, ' + Selector.wrapper).css({ + 'height' : 'auto', + 'min-height': '100%' + }); + } + + if (!this.bindedResize) { + $(window).resize(function () { + this.fix(); + this.fixSidebar(); + + $(Selector.logo + ', ' + Selector.sidebar).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + }.bind(this)); + + this.bindedResize = true; + } + + $(Selector.sidebarMenu).on('expanded.tree', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + + $(Selector.sidebarMenu).on('collapsed.tree', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + }; + + Layout.prototype.fix = function () { + // Remove overflow from .wrapper if layout-boxed exists + $(Selector.layoutBoxed + ' > ' + Selector.wrapper).css('overflow', 'hidden'); + + // Get window height and the wrapper height + var footerHeight = $(Selector.mainFooter).outerHeight() || 0; + var neg = $(Selector.mainHeader).outerHeight() + footerHeight; + var windowHeight = $(window).height(); + var sidebarHeight = $(Selector.sidebar).height() || 0; + + // Set the min-height of the content and sidebar based on + // the height of the document. + if ($('body').hasClass(ClassName.fixed)) { + $(Selector.contentWrapper).css('min-height', windowHeight - footerHeight); + } else { + var postSetHeight; + + if (windowHeight >= sidebarHeight) { + $(Selector.contentWrapper).css('min-height', windowHeight - neg); + postSetHeight = windowHeight - neg; + } else { + $(Selector.contentWrapper).css('min-height', sidebarHeight); + postSetHeight = sidebarHeight; + } + + // Fix for the control sidebar height + var $controlSidebar = $(Selector.controlSidebar); + if (typeof $controlSidebar !== 'undefined') { + if ($controlSidebar.height() > postSetHeight) + $(Selector.contentWrapper).css('min-height', $controlSidebar.height()); + } + } + }; + + Layout.prototype.fixSidebar = function () { + // Make sure the body tag has the .fixed class + if (!$('body').hasClass(ClassName.fixed)) { + if (typeof $.fn.slimScroll !== 'undefined') { + $(Selector.sidebar).slimScroll({ destroy: true }).height('auto'); + } + return; + } + + // Enable slimscroll for fixed layout + if (this.options.slimscroll) { + if (typeof $.fn.slimScroll !== 'undefined') { + // Destroy if it exists + // $(Selector.sidebar).slimScroll({ destroy: true }).height('auto') + + // Add slimscroll + $(Selector.sidebar).slimScroll({ + height: ($(window).height() - $(Selector.mainHeader).height()) + 'px' + }); + } + } + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option === 'object' && option); + $this.data(DataKey, (data = new Layout(options))); + } + + if (typeof option === 'string') { + if (typeof data[option] === 'undefined') { + throw new Error('No method named ' + option); + } + data[option](); + } + }); + } + + var old = $.fn.layout; + + $.fn.layout = Plugin; + $.fn.layout.Constuctor = Layout; + + // No conflict mode + // ================ + $.fn.layout.noConflict = function () { + $.fn.layout = old; + return this; + }; + + // Layout DATA-API + // =============== + $(window).on('load', function () { + Plugin.call($('body')); + }); +}(jQuery); + + +/* PushMenu() + * ========== + * Adds the push menu functionality to the sidebar. + * + * @usage: $('.btn').pushMenu(options) + * or add [data-toggle="push-menu"] to any button + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.pushmenu'; + + var Default = { + collapseScreenSize : 767, + expandOnHover : false, + expandTransitionDelay: 200 + }; + + var Selector = { + collapsed : '.sidebar-collapse', + open : '.sidebar-open', + mainSidebar : '.main-sidebar', + contentWrapper: '.content-wrapper', + searchInput : '.sidebar-form .form-control', + button : '[data-toggle="push-menu"]', + mini : '.sidebar-mini', + expanded : '.sidebar-expanded-on-hover', + layoutFixed : '.fixed' + }; + + var ClassName = { + collapsed : 'sidebar-collapse', + open : 'sidebar-open', + mini : 'sidebar-mini', + expanded : 'sidebar-expanded-on-hover', + expandFeature: 'sidebar-mini-expand-feature', + layoutFixed : 'fixed' + }; + + var Event = { + expanded : 'expanded.pushMenu', + collapsed: 'collapsed.pushMenu' + }; + + // PushMenu Class Definition + // ========================= + var PushMenu = function (options) { + this.options = options; + this.init(); + }; + + PushMenu.prototype.init = function () { + if (this.options.expandOnHover + || ($('body').is(Selector.mini + Selector.layoutFixed))) { + this.expandOnHover(); + $('body').addClass(ClassName.expandFeature); + } + + $(Selector.contentWrapper).click(function () { + // Enable hide menu when clicking on the content-wrapper on small screens + if ($(window).width() <= this.options.collapseScreenSize && $('body').hasClass(ClassName.open)) { + this.close(); + } + }.bind(this)); + + // __Fix for android devices + $(Selector.searchInput).click(function (e) { + e.stopPropagation(); + }); + }; + + PushMenu.prototype.toggle = function () { + var windowWidth = $(window).width(); + var isOpen = !$('body').hasClass(ClassName.collapsed); + + if (windowWidth <= this.options.collapseScreenSize) { + isOpen = $('body').hasClass(ClassName.open); + } + + if (!isOpen) { + this.open(); + } else { + this.close(); + } + }; + + PushMenu.prototype.open = function () { + var windowWidth = $(window).width(); + + if (windowWidth > this.options.collapseScreenSize) { + $('body').removeClass(ClassName.collapsed) + .trigger($.Event(Event.expanded)); + } + else { + $('body').addClass(ClassName.open) + .trigger($.Event(Event.expanded)); + } + }; + + PushMenu.prototype.close = function () { + var windowWidth = $(window).width(); + if (windowWidth > this.options.collapseScreenSize) { + $('body').addClass(ClassName.collapsed) + .trigger($.Event(Event.collapsed)); + } else { + $('body').removeClass(ClassName.open + ' ' + ClassName.collapsed) + .trigger($.Event(Event.collapsed)); + } + }; + + PushMenu.prototype.expandOnHover = function () { + $(Selector.mainSidebar).hover(function () { + if ($('body').is(Selector.mini + Selector.collapsed) + && $(window).width() > this.options.collapseScreenSize) { + this.expand(); + } + }.bind(this), function () { + if ($('body').is(Selector.expanded)) { + this.collapse(); + } + }.bind(this)); + }; + + PushMenu.prototype.expand = function () { + setTimeout(function () { + $('body').removeClass(ClassName.collapsed) + .addClass(ClassName.expanded); + }, this.options.expandTransitionDelay); + }; + + PushMenu.prototype.collapse = function () { + setTimeout(function () { + $('body').removeClass(ClassName.expanded) + .addClass(ClassName.collapsed); + }, this.options.expandTransitionDelay); + }; + + // PushMenu Plugin Definition + // ========================== + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new PushMenu(options))); + } + + if (option === 'toggle') data.toggle(); + }); + } + + var old = $.fn.pushMenu; + + $.fn.pushMenu = Plugin; + $.fn.pushMenu.Constructor = PushMenu; + + // No Conflict Mode + // ================ + $.fn.pushMenu.noConflict = function () { + $.fn.pushMenu = old; + return this; + }; + + // Data API + // ======== + $(document).on('click', Selector.button, function (e) { + e.preventDefault(); + Plugin.call($(this), 'toggle'); + }); + $(window).on('load', function () { + Plugin.call($(Selector.button)); + }); +}(jQuery); + + +/* TodoList() + * ========= + * Converts a list into a todoList. + * + * @Usage: $('.my-list').todoList(options) + * or add [data-widget="todo-list"] to the ul element + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.todolist'; + + var Default = { + onCheck : function (item) { + return item; + }, + onUnCheck: function (item) { + return item; + } + }; + + var Selector = { + data: '[data-widget="todo-list"]' + }; + + var ClassName = { + done: 'done' + }; + + // TodoList Class Definition + // ========================= + var TodoList = function (element, options) { + this.element = element; + this.options = options; + + this._setUpListeners(); + }; + + TodoList.prototype.toggle = function (item) { + item.parents(Selector.li).first().toggleClass(ClassName.done); + if (!item.prop('checked')) { + this.unCheck(item); + return; + } + + this.check(item); + }; + + TodoList.prototype.check = function (item) { + this.options.onCheck.call(item); + }; + + TodoList.prototype.unCheck = function (item) { + this.options.onUnCheck.call(item); + }; + + // Private + + TodoList.prototype._setUpListeners = function () { + var that = this; + $(this.element).on('change ifChanged', 'input:checkbox', function () { + that.toggle($(this)); + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new TodoList($this, options))); + } + + if (typeof data == 'string') { + if (typeof data[option] == 'undefined') { + throw new Error('No method named ' + option); + } + data[option](); + } + }); + } + + var old = $.fn.todoList; + + $.fn.todoList = Plugin; + $.fn.todoList.Constructor = TodoList; + + // No Conflict Mode + // ================ + $.fn.todoList.noConflict = function () { + $.fn.todoList = old; + return this; + }; + + // TodoList Data API + // ================= + $(window).on('load', function () { + $(Selector.data).each(function () { + Plugin.call($(this)); + }); + }); + +}(jQuery); + + +/* Tree() + * ====== + * Converts a nested list into a multilevel + * tree view menu. + * + * @Usage: $('.my-menu').tree(options) + * or add [data-widget="tree"] to the ul element + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.tree'; + + var Default = { + animationSpeed: 500, + accordion : true, + followLink : false, + trigger : '.treeview a' + }; + + var Selector = { + tree : '.tree', + treeview : '.treeview', + treeviewMenu: '.treeview-menu', + open : '.menu-open, .active', + li : 'li', + data : '[data-widget="tree"]', + active : '.active' + }; + + var ClassName = { + open: 'menu-open', + tree: 'tree' + }; + + var Event = { + collapsed: 'collapsed.tree', + expanded : 'expanded.tree' + }; + + // Tree Class Definition + // ===================== + var Tree = function (element, options) { + this.element = element; + this.options = options; + + $(this.element).addClass(ClassName.tree); + + $(Selector.treeview + Selector.active, this.element).addClass(ClassName.open); + + this._setUpListeners(); + }; + + Tree.prototype.toggle = function (link, event) { + var treeviewMenu = link.next(Selector.treeviewMenu); + var parentLi = link.parent(); + var isOpen = parentLi.hasClass(ClassName.open); + + if (!parentLi.is(Selector.treeview)) { + return; + } + + if (!this.options.followLink || link.attr('href') === '#') { + event.preventDefault(); + } + + if (isOpen) { + this.collapse(treeviewMenu, parentLi); + } else { + this.expand(treeviewMenu, parentLi); + } + }; + + Tree.prototype.expand = function (tree, parent) { + var expandedEvent = $.Event(Event.expanded); + + if (this.options.accordion) { + var openMenuLi = parent.siblings(Selector.open); + var openTree = openMenuLi.children(Selector.treeviewMenu); + this.collapse(openTree, openMenuLi); + } + + parent.addClass(ClassName.open); + tree.slideDown(this.options.animationSpeed, function () { + $(this.element).trigger(expandedEvent); + }.bind(this)); + }; + + Tree.prototype.collapse = function (tree, parentLi) { + var collapsedEvent = $.Event(Event.collapsed); + + tree.find(Selector.open).removeClass(ClassName.open); + parentLi.removeClass(ClassName.open); + tree.slideUp(this.options.animationSpeed, function () { + tree.find(Selector.open + ' > ' + Selector.treeview).slideUp(); + $(this.element).trigger(collapsedEvent); + }.bind(this)); + }; + + // Private + + Tree.prototype._setUpListeners = function () { + var that = this; + + $(this.element).on('click', this.options.trigger, function (event) { + that.toggle($(this), event); + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, new Tree($this, options)); + } + }); + } + + var old = $.fn.tree; + + $.fn.tree = Plugin; + $.fn.tree.Constructor = Tree; + + // No Conflict Mode + // ================ + $.fn.tree.noConflict = function () { + $.fn.tree = old; + return this; + }; + + // Tree Data API + // ============= + $(window).on('load', function () { + $(Selector.data).each(function () { + Plugin.call($(this)); + }); + }); + +}(jQuery); |