You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1149 lines
29 KiB

  1. /*! AdminLTE app.js
  2. * ================
  3. * Main JS application file for AdminLTE v2. This file
  4. * should be included in all pages. It controls some layout
  5. * options and implements exclusive AdminLTE plugins.
  6. *
  7. * @author Colorlib
  8. * @support <https://github.com/ColorlibHQ/AdminLTE/issues>
  9. * @version 2.4.15
  10. * @repository git://github.com/ColorlibHQ/AdminLTE.git
  11. * @license MIT <http://opensource.org/licenses/MIT>
  12. */
  13. // Make sure jQuery has been loaded
  14. if (typeof jQuery === 'undefined') {
  15. throw new Error('AdminLTE requires jQuery')
  16. }
  17. /* BoxRefresh()
  18. * =========
  19. * Adds AJAX content control to a box.
  20. *
  21. * @Usage: $('#my-box').boxRefresh(options)
  22. * or add [data-widget="box-refresh"] to the box element
  23. * Pass any option as data-option="value"
  24. */
  25. +function ($) {
  26. 'use strict';
  27. var DataKey = 'lte.boxrefresh';
  28. var Default = {
  29. source : '',
  30. params : {},
  31. trigger : '.refresh-btn',
  32. content : '.box-body',
  33. loadInContent : true,
  34. responseType : '',
  35. overlayTemplate: '<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>',
  36. onLoadStart : function () {
  37. },
  38. onLoadDone : function (response) {
  39. return response;
  40. }
  41. };
  42. var Selector = {
  43. data: '[data-widget="box-refresh"]'
  44. };
  45. // BoxRefresh Class Definition
  46. // =========================
  47. var BoxRefresh = function (element, options) {
  48. this.element = element;
  49. this.options = options;
  50. this.$overlay = $(options.overlayTemplate);
  51. if (options.source === '') {
  52. throw new Error('Source url was not defined. Please specify a url in your BoxRefresh source option.');
  53. }
  54. this._setUpListeners();
  55. this.load();
  56. };
  57. BoxRefresh.prototype.load = function () {
  58. this._addOverlay();
  59. this.options.onLoadStart.call($(this));
  60. $.get(this.options.source, this.options.params, function (response) {
  61. if (this.options.loadInContent) {
  62. $(this.element).find(this.options.content).html(response);
  63. }
  64. this.options.onLoadDone.call($(this), response);
  65. this._removeOverlay();
  66. }.bind(this), this.options.responseType !== '' && this.options.responseType);
  67. };
  68. // Private
  69. BoxRefresh.prototype._setUpListeners = function () {
  70. $(this.element).on('click', this.options.trigger, function (event) {
  71. if (event) event.preventDefault();
  72. this.load();
  73. }.bind(this));
  74. };
  75. BoxRefresh.prototype._addOverlay = function () {
  76. $(this.element).append(this.$overlay);
  77. };
  78. BoxRefresh.prototype._removeOverlay = function () {
  79. $(this.$overlay).remove();
  80. };
  81. // Plugin Definition
  82. // =================
  83. function Plugin(option) {
  84. return this.each(function () {
  85. var $this = $(this);
  86. var data = $this.data(DataKey);
  87. if (!data) {
  88. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  89. $this.data(DataKey, (data = new BoxRefresh($this, options)));
  90. }
  91. if (typeof data == 'string') {
  92. if (typeof data[option] == 'undefined') {
  93. throw new Error('No method named ' + option);
  94. }
  95. data[option]();
  96. }
  97. });
  98. }
  99. var old = $.fn.boxRefresh;
  100. $.fn.boxRefresh = Plugin;
  101. $.fn.boxRefresh.Constructor = BoxRefresh;
  102. // No Conflict Mode
  103. // ================
  104. $.fn.boxRefresh.noConflict = function () {
  105. $.fn.boxRefresh = old;
  106. return this;
  107. };
  108. // BoxRefresh Data API
  109. // =================
  110. $(window).on('load', function () {
  111. $(Selector.data).each(function () {
  112. Plugin.call($(this));
  113. });
  114. });
  115. }(jQuery);
  116. /* BoxWidget()
  117. * ======
  118. * Adds box widget functions to boxes.
  119. *
  120. * @Usage: $('.my-box').boxWidget(options)
  121. * This plugin auto activates on any element using the `.box` class
  122. * Pass any option as data-option="value"
  123. */
  124. +function ($) {
  125. 'use strict';
  126. var DataKey = 'lte.boxwidget';
  127. var Default = {
  128. animationSpeed : 500,
  129. collapseTrigger: '[data-widget="collapse"]',
  130. removeTrigger : '[data-widget="remove"]',
  131. collapseIcon : 'fa-minus',
  132. expandIcon : 'fa-plus',
  133. removeIcon : 'fa-times'
  134. };
  135. var Selector = {
  136. data : '.box',
  137. collapsed: '.collapsed-box',
  138. header : '.box-header',
  139. body : '.box-body',
  140. footer : '.box-footer',
  141. tools : '.box-tools'
  142. };
  143. var ClassName = {
  144. collapsed: 'collapsed-box'
  145. };
  146. var Event = {
  147. collapsing: 'collapsing.boxwidget',
  148. collapsed: 'collapsed.boxwidget',
  149. expanding: 'expanding.boxwidget',
  150. expanded: 'expanded.boxwidget',
  151. removing: 'removing.boxwidget',
  152. removed: 'removed.boxwidget'
  153. };
  154. // BoxWidget Class Definition
  155. // =====================
  156. var BoxWidget = function (element, options) {
  157. this.element = element;
  158. this.options = options;
  159. this._setUpListeners();
  160. };
  161. BoxWidget.prototype.toggle = function () {
  162. var isOpen = !$(this.element).is(Selector.collapsed);
  163. if (isOpen) {
  164. this.collapse();
  165. } else {
  166. this.expand();
  167. }
  168. };
  169. BoxWidget.prototype.expand = function () {
  170. var expandedEvent = $.Event(Event.expanded);
  171. var expandingEvent = $.Event(Event.expanding);
  172. var collapseIcon = this.options.collapseIcon;
  173. var expandIcon = this.options.expandIcon;
  174. $(this.element).removeClass(ClassName.collapsed);
  175. $(this.element)
  176. .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer)
  177. .children(Selector.tools)
  178. .find('.' + expandIcon)
  179. .removeClass(expandIcon)
  180. .addClass(collapseIcon);
  181. $(this.element).children(Selector.body + ', ' + Selector.footer)
  182. .slideDown(this.options.animationSpeed, function () {
  183. $(this.element).trigger(expandedEvent);
  184. }.bind(this))
  185. .trigger(expandingEvent);
  186. };
  187. BoxWidget.prototype.collapse = function () {
  188. var collapsedEvent = $.Event(Event.collapsed);
  189. var collapsingEvent = $.Event(Event.collapsing);
  190. var collapseIcon = this.options.collapseIcon;
  191. var expandIcon = this.options.expandIcon;
  192. $(this.element)
  193. .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer)
  194. .children(Selector.tools)
  195. .find('.' + collapseIcon)
  196. .removeClass(collapseIcon)
  197. .addClass(expandIcon);
  198. $(this.element).children(Selector.body + ', ' + Selector.footer)
  199. .slideUp(this.options.animationSpeed, function () {
  200. $(this.element).addClass(ClassName.collapsed);
  201. $(this.element).trigger(collapsedEvent);
  202. }.bind(this))
  203. .trigger(collapsingEvent);
  204. };
  205. BoxWidget.prototype.remove = function () {
  206. var removedEvent = $.Event(Event.removed);
  207. var removingEvent = $.Event(Event.removing);
  208. $(this.element).slideUp(this.options.animationSpeed, function () {
  209. $(this.element).trigger(removedEvent);
  210. $(this.element).remove();
  211. }.bind(this))
  212. .trigger(removingEvent);
  213. };
  214. // Private
  215. BoxWidget.prototype._setUpListeners = function () {
  216. var that = this;
  217. $(this.element).on('click', this.options.collapseTrigger, function (event) {
  218. if (event) event.preventDefault();
  219. that.toggle($(this));
  220. return false;
  221. });
  222. $(this.element).on('click', this.options.removeTrigger, function (event) {
  223. if (event) event.preventDefault();
  224. that.remove($(this));
  225. return false;
  226. });
  227. };
  228. // Plugin Definition
  229. // =================
  230. function Plugin(option) {
  231. return this.each(function () {
  232. var $this = $(this);
  233. var data = $this.data(DataKey);
  234. if (!data) {
  235. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  236. $this.data(DataKey, (data = new BoxWidget($this, options)));
  237. }
  238. if (typeof option == 'string') {
  239. if (typeof data[option] == 'undefined') {
  240. throw new Error('No method named ' + option);
  241. }
  242. data[option]();
  243. }
  244. });
  245. }
  246. var old = $.fn.boxWidget;
  247. $.fn.boxWidget = Plugin;
  248. $.fn.boxWidget.Constructor = BoxWidget;
  249. // No Conflict Mode
  250. // ================
  251. $.fn.boxWidget.noConflict = function () {
  252. $.fn.boxWidget = old;
  253. return this;
  254. };
  255. // BoxWidget Data API
  256. // ==================
  257. $(window).on('load', function () {
  258. $(Selector.data).each(function () {
  259. Plugin.call($(this));
  260. });
  261. });
  262. }(jQuery);
  263. /* ControlSidebar()
  264. * ===============
  265. * Toggles the state of the control sidebar
  266. *
  267. * @Usage: $('#control-sidebar-trigger').controlSidebar(options)
  268. * or add [data-toggle="control-sidebar"] to the trigger
  269. * Pass any option as data-option="value"
  270. */
  271. +function ($) {
  272. 'use strict';
  273. var DataKey = 'lte.controlsidebar';
  274. var Default = {
  275. slide: true
  276. };
  277. var Selector = {
  278. sidebar: '.control-sidebar',
  279. data : '[data-toggle="control-sidebar"]',
  280. open : '.control-sidebar-open',
  281. bg : '.control-sidebar-bg',
  282. wrapper: '.wrapper',
  283. content: '.content-wrapper',
  284. boxed : '.layout-boxed'
  285. };
  286. var ClassName = {
  287. open : 'control-sidebar-open',
  288. fixed: 'fixed'
  289. };
  290. var Event = {
  291. collapsed: 'collapsed.controlsidebar',
  292. expanded : 'expanded.controlsidebar'
  293. };
  294. // ControlSidebar Class Definition
  295. // ===============================
  296. var ControlSidebar = function (element, options) {
  297. this.element = element;
  298. this.options = options;
  299. this.hasBindedResize = false;
  300. this.init();
  301. };
  302. ControlSidebar.prototype.init = function () {
  303. // Add click listener if the element hasn't been
  304. // initialized using the data API
  305. if (!$(this.element).is(Selector.data)) {
  306. $(this).on('click', this.toggle);
  307. }
  308. this.fix();
  309. $(window).resize(function () {
  310. this.fix();
  311. }.bind(this));
  312. };
  313. ControlSidebar.prototype.toggle = function (event) {
  314. if (event) event.preventDefault();
  315. this.fix();
  316. if (!$(Selector.sidebar).is(Selector.open) && !$('body').is(Selector.open)) {
  317. this.expand();
  318. } else {
  319. this.collapse();
  320. }
  321. };
  322. ControlSidebar.prototype.expand = function () {
  323. $(Selector.sidebar).show();
  324. if (!this.options.slide) {
  325. $('body').addClass(ClassName.open);
  326. } else {
  327. $(Selector.sidebar).addClass(ClassName.open);
  328. }
  329. $(this.element).trigger($.Event(Event.expanded));
  330. };
  331. ControlSidebar.prototype.collapse = function () {
  332. $('body, ' + Selector.sidebar).removeClass(ClassName.open);
  333. $(Selector.sidebar).fadeOut();
  334. $(this.element).trigger($.Event(Event.collapsed));
  335. };
  336. ControlSidebar.prototype.fix = function () {
  337. if ($('body').is(Selector.boxed)) {
  338. this._fixForBoxed($(Selector.bg));
  339. }
  340. };
  341. // Private
  342. ControlSidebar.prototype._fixForBoxed = function (bg) {
  343. bg.css({
  344. position: 'absolute',
  345. height : $(Selector.wrapper).height()
  346. });
  347. };
  348. // Plugin Definition
  349. // =================
  350. function Plugin(option) {
  351. return this.each(function () {
  352. var $this = $(this);
  353. var data = $this.data(DataKey);
  354. if (!data) {
  355. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  356. $this.data(DataKey, (data = new ControlSidebar($this, options)));
  357. }
  358. if (typeof option == 'string') data.toggle();
  359. });
  360. }
  361. var old = $.fn.controlSidebar;
  362. $.fn.controlSidebar = Plugin;
  363. $.fn.controlSidebar.Constructor = ControlSidebar;
  364. // No Conflict Mode
  365. // ================
  366. $.fn.controlSidebar.noConflict = function () {
  367. $.fn.controlSidebar = old;
  368. return this;
  369. };
  370. // ControlSidebar Data API
  371. // =======================
  372. $(document).on('click', Selector.data, function (event) {
  373. if (event) event.preventDefault();
  374. Plugin.call($(this), 'toggle');
  375. });
  376. }(jQuery);
  377. /* DirectChat()
  378. * ===============
  379. * Toggles the state of the control sidebar
  380. *
  381. * @Usage: $('#my-chat-box').directChat()
  382. * or add [data-widget="direct-chat"] to the trigger
  383. */
  384. +function ($) {
  385. 'use strict';
  386. var DataKey = 'lte.directchat';
  387. var Selector = {
  388. data: '[data-widget="chat-pane-toggle"]',
  389. box : '.direct-chat'
  390. };
  391. var ClassName = {
  392. open: 'direct-chat-contacts-open'
  393. };
  394. // DirectChat Class Definition
  395. // ===========================
  396. var DirectChat = function (element) {
  397. this.element = element;
  398. };
  399. DirectChat.prototype.toggle = function ($trigger) {
  400. $trigger.parents(Selector.box).first().toggleClass(ClassName.open);
  401. };
  402. // Plugin Definition
  403. // =================
  404. function Plugin(option) {
  405. return this.each(function () {
  406. var $this = $(this);
  407. var data = $this.data(DataKey);
  408. if (!data) {
  409. $this.data(DataKey, (data = new DirectChat($this)));
  410. }
  411. if (typeof option == 'string') data.toggle($this);
  412. });
  413. }
  414. var old = $.fn.directChat;
  415. $.fn.directChat = Plugin;
  416. $.fn.directChat.Constructor = DirectChat;
  417. // No Conflict Mode
  418. // ================
  419. $.fn.directChat.noConflict = function () {
  420. $.fn.directChat = old;
  421. return this;
  422. };
  423. // DirectChat Data API
  424. // ===================
  425. $(document).on('click', Selector.data, function (event) {
  426. if (event) event.preventDefault();
  427. Plugin.call($(this), 'toggle');
  428. });
  429. }(jQuery);
  430. /* PushMenu()
  431. * ==========
  432. * Adds the push menu functionality to the sidebar.
  433. *
  434. * @usage: $('.btn').pushMenu(options)
  435. * or add [data-toggle="push-menu"] to any button
  436. * Pass any option as data-option="value"
  437. */
  438. +function ($) {
  439. 'use strict';
  440. var DataKey = 'lte.pushmenu';
  441. var Default = {
  442. collapseScreenSize : 767,
  443. expandOnHover : false,
  444. expandTransitionDelay: 200
  445. };
  446. var Selector = {
  447. collapsed : '.sidebar-collapse',
  448. open : '.sidebar-open',
  449. mainSidebar : '.main-sidebar',
  450. contentWrapper: '.content-wrapper',
  451. searchInput : '.sidebar-form .form-control',
  452. button : '[data-toggle="push-menu"]',
  453. mini : '.sidebar-mini',
  454. expanded : '.sidebar-expanded-on-hover',
  455. layoutFixed : '.fixed'
  456. };
  457. var ClassName = {
  458. collapsed : 'sidebar-collapse',
  459. open : 'sidebar-open',
  460. mini : 'sidebar-mini',
  461. expanded : 'sidebar-expanded-on-hover',
  462. expandFeature: 'sidebar-mini-expand-feature',
  463. layoutFixed : 'fixed'
  464. };
  465. var Event = {
  466. expanded : 'expanded.pushMenu',
  467. collapsed: 'collapsed.pushMenu'
  468. };
  469. // PushMenu Class Definition
  470. // =========================
  471. var PushMenu = function (options) {
  472. this.options = options;
  473. this.init();
  474. };
  475. PushMenu.prototype.init = function () {
  476. if (this.options.expandOnHover
  477. || ($('body').is(Selector.mini + Selector.layoutFixed))) {
  478. this.expandOnHover();
  479. $('body').addClass(ClassName.expandFeature);
  480. }
  481. $(Selector.contentWrapper).click(function () {
  482. // Enable hide menu when clicking on the content-wrapper on small screens
  483. if ($(window).width() <= this.options.collapseScreenSize && $('body').hasClass(ClassName.open)) {
  484. this.close();
  485. }
  486. }.bind(this));
  487. // __Fix for android devices
  488. $(Selector.searchInput).click(function (e) {
  489. e.stopPropagation();
  490. });
  491. };
  492. PushMenu.prototype.toggle = function () {
  493. var windowWidth = $(window).width();
  494. var isOpen = !$('body').hasClass(ClassName.collapsed);
  495. if (windowWidth <= this.options.collapseScreenSize) {
  496. isOpen = $('body').hasClass(ClassName.open);
  497. }
  498. if (!isOpen) {
  499. this.open();
  500. } else {
  501. this.close();
  502. }
  503. };
  504. PushMenu.prototype.open = function () {
  505. var windowWidth = $(window).width();
  506. if (windowWidth > this.options.collapseScreenSize) {
  507. $('body').removeClass(ClassName.collapsed)
  508. .trigger($.Event(Event.expanded));
  509. }
  510. else {
  511. $('body').addClass(ClassName.open)
  512. .trigger($.Event(Event.expanded));
  513. }
  514. };
  515. PushMenu.prototype.close = function () {
  516. var windowWidth = $(window).width();
  517. if (windowWidth > this.options.collapseScreenSize) {
  518. $('body').addClass(ClassName.collapsed)
  519. .trigger($.Event(Event.collapsed));
  520. } else {
  521. $('body').removeClass(ClassName.open + ' ' + ClassName.collapsed)
  522. .trigger($.Event(Event.collapsed));
  523. }
  524. };
  525. PushMenu.prototype.expandOnHover = function () {
  526. $(Selector.mainSidebar).hover(function () {
  527. if ($('body').is(Selector.mini + Selector.collapsed)
  528. && $(window).width() > this.options.collapseScreenSize) {
  529. this.expand();
  530. }
  531. }.bind(this), function () {
  532. if ($('body').is(Selector.expanded)) {
  533. this.collapse();
  534. }
  535. }.bind(this));
  536. };
  537. PushMenu.prototype.expand = function () {
  538. setTimeout(function () {
  539. $('body').removeClass(ClassName.collapsed)
  540. .addClass(ClassName.expanded);
  541. }, this.options.expandTransitionDelay);
  542. };
  543. PushMenu.prototype.collapse = function () {
  544. setTimeout(function () {
  545. $('body').removeClass(ClassName.expanded)
  546. .addClass(ClassName.collapsed);
  547. }, this.options.expandTransitionDelay);
  548. };
  549. // PushMenu Plugin Definition
  550. // ==========================
  551. function Plugin(option) {
  552. return this.each(function () {
  553. var $this = $(this);
  554. var data = $this.data(DataKey);
  555. if (!data) {
  556. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  557. $this.data(DataKey, (data = new PushMenu(options)));
  558. }
  559. if (option === 'toggle') data.toggle();
  560. });
  561. }
  562. var old = $.fn.pushMenu;
  563. $.fn.pushMenu = Plugin;
  564. $.fn.pushMenu.Constructor = PushMenu;
  565. // No Conflict Mode
  566. // ================
  567. $.fn.pushMenu.noConflict = function () {
  568. $.fn.pushMenu = old;
  569. return this;
  570. };
  571. // Data API
  572. // ========
  573. $(document).on('click', Selector.button, function (e) {
  574. e.preventDefault();
  575. Plugin.call($(this), 'toggle');
  576. });
  577. $(window).on('load', function () {
  578. Plugin.call($(Selector.button));
  579. });
  580. }(jQuery);
  581. /* TodoList()
  582. * =========
  583. * Converts a list into a todoList.
  584. *
  585. * @Usage: $('.my-list').todoList(options)
  586. * or add [data-widget="todo-list"] to the ul element
  587. * Pass any option as data-option="value"
  588. */
  589. +function ($) {
  590. 'use strict';
  591. var DataKey = 'lte.todolist';
  592. var Default = {
  593. onCheck : function (item) {
  594. return item;
  595. },
  596. onUnCheck: function (item) {
  597. return item;
  598. }
  599. };
  600. var Selector = {
  601. data: '[data-widget="todo-list"]'
  602. };
  603. var ClassName = {
  604. done: 'done'
  605. };
  606. // TodoList Class Definition
  607. // =========================
  608. var TodoList = function (element, options) {
  609. this.element = element;
  610. this.options = options;
  611. this._setUpListeners();
  612. };
  613. TodoList.prototype.toggle = function (item) {
  614. item.parents(Selector.li).first().toggleClass(ClassName.done);
  615. if (!item.prop('checked')) {
  616. this.unCheck(item);
  617. return;
  618. }
  619. this.check(item);
  620. };
  621. TodoList.prototype.check = function (item) {
  622. this.options.onCheck.call(item);
  623. };
  624. TodoList.prototype.unCheck = function (item) {
  625. this.options.onUnCheck.call(item);
  626. };
  627. // Private
  628. TodoList.prototype._setUpListeners = function () {
  629. var that = this;
  630. $(this.element).on('change ifChanged', 'input:checkbox', function () {
  631. that.toggle($(this));
  632. });
  633. };
  634. // Plugin Definition
  635. // =================
  636. function Plugin(option) {
  637. return this.each(function () {
  638. var $this = $(this);
  639. var data = $this.data(DataKey);
  640. if (!data) {
  641. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  642. $this.data(DataKey, (data = new TodoList($this, options)));
  643. }
  644. if (typeof data == 'string') {
  645. if (typeof data[option] == 'undefined') {
  646. throw new Error('No method named ' + option);
  647. }
  648. data[option]();
  649. }
  650. });
  651. }
  652. var old = $.fn.todoList;
  653. $.fn.todoList = Plugin;
  654. $.fn.todoList.Constructor = TodoList;
  655. // No Conflict Mode
  656. // ================
  657. $.fn.todoList.noConflict = function () {
  658. $.fn.todoList = old;
  659. return this;
  660. };
  661. // TodoList Data API
  662. // =================
  663. $(window).on('load', function () {
  664. $(Selector.data).each(function () {
  665. Plugin.call($(this));
  666. });
  667. });
  668. }(jQuery);
  669. /* Tree()
  670. * ======
  671. * Converts a nested list into a multilevel
  672. * tree view menu.
  673. *
  674. * @Usage: $('.my-menu').tree(options)
  675. * or add [data-widget="tree"] to the ul element
  676. * Pass any option as data-option="value"
  677. */
  678. +function ($) {
  679. 'use strict';
  680. var DataKey = 'lte.tree';
  681. var Default = {
  682. animationSpeed: 500,
  683. accordion : true,
  684. followLink : false,
  685. trigger : '.treeview a'
  686. };
  687. var Selector = {
  688. tree : '.tree',
  689. treeview : '.treeview',
  690. treeviewMenu: '.treeview-menu',
  691. open : '.menu-open, .active',
  692. li : 'li',
  693. data : '[data-widget="tree"]',
  694. active : '.active'
  695. };
  696. var ClassName = {
  697. open: 'menu-open',
  698. tree: 'tree'
  699. };
  700. var Event = {
  701. collapsed: 'collapsed.tree',
  702. expanded : 'expanded.tree'
  703. };
  704. // Tree Class Definition
  705. // =====================
  706. var Tree = function (element, options) {
  707. this.element = element;
  708. this.options = options;
  709. $(this.element).addClass(ClassName.tree);
  710. $(Selector.treeview + Selector.active, this.element).addClass(ClassName.open);
  711. this._setUpListeners();
  712. };
  713. Tree.prototype.toggle = function (link, event) {
  714. var treeviewMenu = link.next(Selector.treeviewMenu);
  715. var parentLi = link.parent();
  716. var isOpen = parentLi.hasClass(ClassName.open);
  717. if (!parentLi.is(Selector.treeview)) {
  718. return;
  719. }
  720. if (!this.options.followLink || link.attr('href') === '#') {
  721. event.preventDefault();
  722. }
  723. if (isOpen) {
  724. this.collapse(treeviewMenu, parentLi);
  725. } else {
  726. this.expand(treeviewMenu, parentLi);
  727. }
  728. };
  729. Tree.prototype.expand = function (tree, parent) {
  730. var expandedEvent = $.Event(Event.expanded);
  731. if (this.options.accordion) {
  732. var openMenuLi = parent.siblings(Selector.open);
  733. var openTree = openMenuLi.children(Selector.treeviewMenu);
  734. this.collapse(openTree, openMenuLi);
  735. }
  736. parent.addClass(ClassName.open);
  737. tree.slideDown(this.options.animationSpeed, function () {
  738. $(this.element).trigger(expandedEvent);
  739. parent.height('auto');
  740. }.bind(this));
  741. };
  742. Tree.prototype.collapse = function (tree, parentLi) {
  743. var collapsedEvent = $.Event(Event.collapsed);
  744. //tree.find(Selector.open).removeClass(ClassName.open);
  745. parentLi.removeClass(ClassName.open);
  746. tree.slideUp(this.options.animationSpeed, function () {
  747. //tree.find(Selector.open + ' > ' + Selector.treeview).slideUp();
  748. $(this.element).trigger(collapsedEvent);
  749. // Collapse child items
  750. parentLi.find(Selector.treeview).removeClass(ClassName.open).find(Selector.treeviewMenu).hide();
  751. }.bind(this));
  752. };
  753. // Private
  754. Tree.prototype._setUpListeners = function () {
  755. var that = this;
  756. $(this.element).on('click', this.options.trigger, function (event) {
  757. that.toggle($(this), event);
  758. });
  759. };
  760. // Plugin Definition
  761. // =================
  762. function Plugin(option) {
  763. return this.each(function () {
  764. var $this = $(this);
  765. var data = $this.data(DataKey);
  766. if (!data) {
  767. var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
  768. $this.data(DataKey, new Tree($this, options));
  769. }
  770. });
  771. }
  772. var old = $.fn.tree;
  773. $.fn.tree = Plugin;
  774. $.fn.tree.Constructor = Tree;
  775. // No Conflict Mode
  776. // ================
  777. $.fn.tree.noConflict = function () {
  778. $.fn.tree = old;
  779. return this;
  780. };
  781. // Tree Data API
  782. // =============
  783. $(window).on('load', function () {
  784. $(Selector.data).each(function () {
  785. Plugin.call($(this));
  786. });
  787. });
  788. }(jQuery);
  789. /* Layout()
  790. * ========
  791. * Implements AdminLTE layout.
  792. * Fixes the layout height in case min-height fails.
  793. *
  794. * @usage activated automatically upon window load.
  795. * Configure any options by passing data-option="value"
  796. * to the body tag.
  797. */
  798. +function ($) {
  799. 'use strict';
  800. var DataKey = 'lte.layout';
  801. var Default = {
  802. slimscroll : true,
  803. resetHeight: true
  804. };
  805. var Selector = {
  806. wrapper : '.wrapper',
  807. contentWrapper: '.content-wrapper',
  808. layoutBoxed : '.layout-boxed',
  809. mainFooter : '.main-footer',
  810. mainHeader : '.main-header',
  811. mainSidebar : '.main-sidebar',
  812. slimScrollDiv : 'slimScrollDiv',
  813. sidebar : '.sidebar',
  814. controlSidebar: '.control-sidebar',
  815. fixed : '.fixed',
  816. sidebarMenu : '.sidebar-menu',
  817. logo : '.main-header .logo'
  818. };
  819. var ClassName = {
  820. fixed : 'fixed',
  821. holdTransition: 'hold-transition'
  822. };
  823. var Layout = function (options) {
  824. this.options = options;
  825. this.bindedResize = false;
  826. this.activate();
  827. };
  828. Layout.prototype.activate = function () {
  829. this.fix();
  830. this.fixSidebar();
  831. $('body').removeClass(ClassName.holdTransition);
  832. if (this.options.resetHeight) {
  833. $('body, html, ' + Selector.wrapper).css({
  834. 'height' : 'auto',
  835. 'min-height': '100%'
  836. });
  837. }
  838. if (!this.bindedResize) {
  839. $(window).resize(function () {
  840. this.fix();
  841. this.fixSidebar();
  842. $(Selector.logo + ', ' + Selector.sidebar).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
  843. this.fix();
  844. this.fixSidebar();
  845. }.bind(this));
  846. }.bind(this));
  847. this.bindedResize = true;
  848. }
  849. $(Selector.sidebarMenu).on('expanded.tree', function () {
  850. this.fix();
  851. this.fixSidebar();
  852. }.bind(this));
  853. $(Selector.sidebarMenu).on('collapsed.tree', function () {
  854. this.fix();
  855. this.fixSidebar();
  856. }.bind(this));
  857. };
  858. Layout.prototype.fix = function () {
  859. // Remove overflow from .wrapper if layout-boxed exists
  860. $(Selector.layoutBoxed + ' > ' + Selector.wrapper).css('overflow', 'hidden');
  861. // Get window height and the wrapper height
  862. var footerHeight = $(Selector.mainFooter).outerHeight() || 0;
  863. var headerHeight = $(Selector.mainHeader).outerHeight() || 0;
  864. var neg = headerHeight + footerHeight;
  865. var windowHeight = $(window).height();
  866. var sidebarHeight = $(Selector.sidebar).outerHeight() || 0;
  867. // Set the min-height of the content and sidebar based on
  868. // the height of the document.
  869. if ($('body').hasClass(ClassName.fixed)) {
  870. $(Selector.contentWrapper).css('min-height', windowHeight - footerHeight);
  871. } else {
  872. var postSetHeight;
  873. if (windowHeight >= sidebarHeight + headerHeight) {
  874. $(Selector.contentWrapper).css('min-height', windowHeight - neg);
  875. postSetHeight = windowHeight - neg;
  876. } else {
  877. $(Selector.contentWrapper).css('min-height', sidebarHeight);
  878. postSetHeight = sidebarHeight;
  879. }
  880. // Fix for the control sidebar height
  881. var $controlSidebar = $(Selector.controlSidebar);
  882. if (typeof $controlSidebar !== 'undefined') {
  883. if ($controlSidebar.height() > postSetHeight)
  884. $(Selector.contentWrapper).css('min-height', $controlSidebar.height());
  885. }
  886. }
  887. };
  888. Layout.prototype.fixSidebar = function () {
  889. // Make sure the body tag has the .fixed class
  890. if (!$('body').hasClass(ClassName.fixed)) {
  891. if (typeof $.fn.slimScroll !== 'undefined') {
  892. $(Selector.sidebar).slimScroll({ destroy: true }).height('auto');
  893. }
  894. return;
  895. }
  896. // Enable slimscroll for fixed layout
  897. if (this.options.slimscroll) {
  898. if (typeof $.fn.slimScroll !== 'undefined') {
  899. // Destroy if it exists
  900. // $(Selector.sidebar).slimScroll({ destroy: true }).height('auto')
  901. // Add slimscroll
  902. if ($(Selector.mainSidebar).find(Selector.slimScrollDiv).length === 0) {
  903. $(Selector.sidebar).slimScroll({
  904. height: ($(window).height() - $(Selector.mainHeader).height()) + 'px'
  905. });
  906. }
  907. }
  908. }
  909. };
  910. // Plugin Definition
  911. // =================
  912. function Plugin(option) {
  913. return this.each(function () {
  914. var $this = $(this);
  915. var data = $this.data(DataKey);
  916. if (!data) {
  917. var options = $.extend({}, Default, $this.data(), typeof option === 'object' && option);
  918. $this.data(DataKey, (data = new Layout(options)));
  919. }
  920. if (typeof option === 'string') {
  921. if (typeof data[option] === 'undefined') {
  922. throw new Error('No method named ' + option);
  923. }
  924. data[option]();
  925. }
  926. });
  927. }
  928. var old = $.fn.layout;
  929. $.fn.layout = Plugin;
  930. $.fn.layout.Constuctor = Layout;
  931. // No conflict mode
  932. // ================
  933. $.fn.layout.noConflict = function () {
  934. $.fn.layout = old;
  935. return this;
  936. };
  937. // Layout DATA-API
  938. // ===============
  939. $(window).on('load', function () {
  940. Plugin.call($('body'));
  941. });
  942. }(jQuery);