adminlte.js 28 KB

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