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.

1803 lines
58 KiB

9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 1.11.5 - Dropdown
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.dropdown = function(parameters) {
  14. var
  15. $allModules = $(this),
  16. $document = $(document),
  17. moduleSelector = $allModules.selector || '',
  18. hasTouch = ('ontouchstart' in document.documentElement),
  19. time = new Date().getTime(),
  20. performance = [],
  21. query = arguments[0],
  22. methodInvoked = (typeof query == 'string'),
  23. queryArguments = [].slice.call(arguments, 1),
  24. returnedValue
  25. ;
  26. $allModules
  27. .each(function() {
  28. var
  29. settings = ( $.isPlainObject(parameters) )
  30. ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
  31. : $.extend({}, $.fn.dropdown.settings),
  32. className = settings.className,
  33. metadata = settings.metadata,
  34. namespace = settings.namespace,
  35. selector = settings.selector,
  36. error = settings.error,
  37. eventNamespace = '.' + namespace,
  38. moduleNamespace = 'module-' + namespace,
  39. $module = $(this),
  40. $text = $module.find(selector.text),
  41. $search = $module.find(selector.search),
  42. $input = $module.find(selector.input),
  43. $combo = ($module.prev().find(selector.text).length > 0)
  44. ? $module.prev().find(selector.text)
  45. : $module.prev(),
  46. $menu = $module.children(selector.menu),
  47. $item = $menu.find(selector.item),
  48. activated = false,
  49. itemActivated = false,
  50. element = this,
  51. instance = $module.data(moduleNamespace),
  52. elementNamespace,
  53. id,
  54. observer,
  55. module
  56. ;
  57. module = {
  58. initialize: function() {
  59. module.debug('Initializing dropdown', settings);
  60. if( module.is.alreadySetup() ) {
  61. module.setup.reference();
  62. }
  63. else {
  64. module.setup.layout();
  65. module.save.defaults();
  66. module.set.selected();
  67. module.create.id();
  68. if(hasTouch) {
  69. module.bind.touchEvents();
  70. }
  71. module.bind.mouseEvents();
  72. module.bind.keyboardEvents();
  73. module.observeChanges();
  74. module.instantiate();
  75. }
  76. },
  77. instantiate: function() {
  78. module.verbose('Storing instance of dropdown', module);
  79. instance = module;
  80. $module
  81. .data(moduleNamespace, module)
  82. ;
  83. },
  84. destroy: function() {
  85. module.verbose('Destroying previous dropdown for', $module);
  86. module.remove.tabbable();
  87. $module
  88. .off(eventNamespace)
  89. .removeData(moduleNamespace)
  90. ;
  91. $menu
  92. .off(eventNamespace)
  93. ;
  94. $document
  95. .off(elementNamespace)
  96. ;
  97. },
  98. observeChanges: function() {
  99. if('MutationObserver' in window) {
  100. observer = new MutationObserver(function(mutations) {
  101. if( module.is.selectMutation(mutations) ) {
  102. module.debug('<select> modified, recreating menu');
  103. module.setup.select();
  104. }
  105. else {
  106. module.debug('DOM tree modified, updating selector cache');
  107. module.refresh();
  108. }
  109. });
  110. observer.observe(element, {
  111. childList : true,
  112. subtree : true
  113. });
  114. module.debug('Setting up mutation observer', observer);
  115. }
  116. },
  117. create: {
  118. id: function() {
  119. id = (Math.random().toString(16) + '000000000').substr(2,8);
  120. elementNamespace = '.' + id;
  121. module.verbose('Creating unique id for element', id);
  122. }
  123. },
  124. search: function() {
  125. var
  126. query
  127. ;
  128. query = $search.val();
  129. module.verbose('Searching for query', query);
  130. module.filter(query);
  131. if(module.is.searchSelection() && module.can.show() ) {
  132. module.show();
  133. }
  134. },
  135. setup: {
  136. layout: function() {
  137. if( $module.is('select') ) {
  138. module.setup.select();
  139. }
  140. if( module.is.search() && !module.is.searchable() ) {
  141. $search = $('<input />')
  142. .addClass(className.search)
  143. .insertBefore($text)
  144. ;
  145. }
  146. if(settings.allowTab) {
  147. module.set.tabbable();
  148. }
  149. },
  150. select: function() {
  151. var
  152. selectValues = module.get.selectValues()
  153. ;
  154. module.debug('Dropdown initialized on a select', selectValues);
  155. if( $module.is('select') ) {
  156. $input = $module;
  157. }
  158. // see if select is placed correctly already
  159. if($input.parent(selector.dropdown).length > 0) {
  160. module.debug('UI dropdown already exists. Creating dropdown menu only');
  161. $module = $input.closest(selector.dropdown);
  162. $menu = $module.children(selector.menu);
  163. if($menu.length === 0) {
  164. $menu = $('<div />')
  165. .addClass(className.menu)
  166. .appendTo($module)
  167. ;
  168. }
  169. $menu.html( settings.templates.menu( selectValues ));
  170. }
  171. else {
  172. module.debug('Creating entire dropdown from select');
  173. $module = $('<div />')
  174. .attr('class', $input.attr('class') )
  175. .addClass(className.selection)
  176. .addClass(className.dropdown)
  177. .html( settings.templates.dropdown(selectValues) )
  178. .insertBefore($input)
  179. ;
  180. $input
  181. .removeAttr('class')
  182. .prependTo($module)
  183. ;
  184. }
  185. module.refresh();
  186. },
  187. reference: function() {
  188. var
  189. index = $allModules.index($module),
  190. $firstModules,
  191. $lastModules
  192. ;
  193. module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
  194. // replace module reference
  195. $module = $module.parent(selector.dropdown);
  196. module.refresh();
  197. // adjust all modules
  198. $firstModules = $allModules.slice(0, index);
  199. $lastModules = $allModules.slice(index + 1);
  200. $allModules = $firstModules.add($module).add($lastModules);
  201. }
  202. },
  203. refresh: function() {
  204. module.verbose('Refreshing selector cache');
  205. $text = $module.find(selector.text);
  206. $search = $module.find(selector.search);
  207. $input = $module.find(selector.input);
  208. $combo = ($module.prev().find(selector.text).length > 0)
  209. ? $module.prev().find(selector.text)
  210. : $module.prev()
  211. ;
  212. $menu = $module.children(selector.menu);
  213. $item = $menu.find(selector.item);
  214. },
  215. toggle: function() {
  216. module.verbose('Toggling menu visibility');
  217. if( !module.is.active() ) {
  218. module.show();
  219. }
  220. else {
  221. module.hide();
  222. }
  223. },
  224. show: function(callback) {
  225. callback = $.isFunction(callback)
  226. ? callback
  227. : function(){}
  228. ;
  229. if( module.is.searchSelection() && module.is.allFiltered() ) {
  230. return;
  231. }
  232. if( module.can.show() && !module.is.active() ) {
  233. module.debug('Showing dropdown');
  234. module.animate.show(function() {
  235. if( module.can.click() ) {
  236. module.bind.intent();
  237. }
  238. module.set.visible();
  239. callback.call(element);
  240. });
  241. settings.onShow.call(element);
  242. }
  243. },
  244. hide: function(callback) {
  245. callback = $.isFunction(callback)
  246. ? callback
  247. : function(){}
  248. ;
  249. if( module.is.active() ) {
  250. module.debug('Hiding dropdown');
  251. module.animate.hide(function() {
  252. module.remove.visible();
  253. callback.call(element);
  254. });
  255. settings.onHide.call(element);
  256. }
  257. },
  258. hideOthers: function() {
  259. module.verbose('Finding other dropdowns to hide');
  260. $allModules
  261. .not($module)
  262. .has(selector.menu + ':visible:not(.' + className.animating + ')')
  263. .dropdown('hide')
  264. ;
  265. },
  266. hideSubMenus: function() {
  267. var
  268. $subMenus = $menu.find(selector.menu)
  269. ;
  270. $subMenus.transition('hide');
  271. },
  272. bind: {
  273. keyboardEvents: function() {
  274. module.debug('Binding keyboard events');
  275. $module
  276. .on('keydown' + eventNamespace, module.event.keydown)
  277. ;
  278. if( module.is.searchable() ) {
  279. $module
  280. .on(module.get.inputEvent(), selector.search, module.event.input)
  281. ;
  282. }
  283. },
  284. touchEvents: function() {
  285. module.debug('Touch device detected binding additional touch events');
  286. if( module.is.searchSelection() ) {
  287. // do nothing special yet
  288. }
  289. else {
  290. $module
  291. .on('touchstart' + eventNamespace, module.event.test.toggle)
  292. ;
  293. }
  294. $menu
  295. .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
  296. ;
  297. },
  298. mouseEvents: function() {
  299. module.verbose('Mouse detected binding mouse events');
  300. if( module.is.searchSelection() ) {
  301. $module
  302. .on('mousedown' + eventNamespace, selector.menu, module.event.menu.activate)
  303. .on('mouseup' + eventNamespace, selector.menu, module.event.menu.deactivate)
  304. .on('click' + eventNamespace, selector.search, module.show)
  305. .on('focus' + eventNamespace, selector.search, module.event.searchFocus)
  306. .on('blur' + eventNamespace, selector.search, module.event.searchBlur)
  307. .on('click' + eventNamespace, selector.text, module.event.searchTextFocus)
  308. ;
  309. }
  310. else {
  311. if(settings.on == 'click') {
  312. $module
  313. .on('click' + eventNamespace, module.event.test.toggle)
  314. ;
  315. }
  316. else if(settings.on == 'hover') {
  317. $module
  318. .on('mouseenter' + eventNamespace, module.delay.show)
  319. .on('mouseleave' + eventNamespace, module.delay.hide)
  320. ;
  321. }
  322. else {
  323. $module
  324. .on(settings.on + eventNamespace, module.toggle)
  325. ;
  326. }
  327. $module
  328. .on('mousedown' + eventNamespace, module.event.mousedown)
  329. .on('mouseup' + eventNamespace, module.event.mouseup)
  330. .on('focus' + eventNamespace, module.event.focus)
  331. .on('blur' + eventNamespace, module.event.blur)
  332. ;
  333. }
  334. $menu
  335. .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
  336. .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
  337. .on('click' + eventNamespace, selector.item, module.event.item.click)
  338. ;
  339. },
  340. intent: function() {
  341. module.verbose('Binding hide intent event to document');
  342. if(hasTouch) {
  343. $document
  344. .on('touchstart' + elementNamespace, module.event.test.touch)
  345. .on('touchmove' + elementNamespace, module.event.test.touch)
  346. ;
  347. }
  348. $document
  349. .on('click' + elementNamespace, module.event.test.hide)
  350. ;
  351. }
  352. },
  353. unbind: {
  354. intent: function() {
  355. module.verbose('Removing hide intent event from document');
  356. if(hasTouch) {
  357. $document
  358. .off('touchstart' + elementNamespace)
  359. .off('touchmove' + elementNamespace)
  360. ;
  361. }
  362. $document
  363. .off('click' + elementNamespace)
  364. ;
  365. }
  366. },
  367. filter: function(searchTerm) {
  368. var
  369. $results = $(),
  370. escapedTerm = module.escape.regExp(searchTerm),
  371. exactRegExp = new RegExp('^' + escapedTerm, 'igm'),
  372. fullTextRegExp = new RegExp(escapedTerm, 'ig'),
  373. allItemsFiltered
  374. ;
  375. module.verbose('Searching for matching values');
  376. $item
  377. .each(function(){
  378. var
  379. $choice = $(this),
  380. text = String(module.get.choiceText($choice, false)),
  381. value = String(module.get.choiceValue($choice, text))
  382. ;
  383. if( text.match(exactRegExp) || value.match(exactRegExp) ) {
  384. $results = $results.add($choice);
  385. }
  386. else if(settings.fullTextSearch) {
  387. if( text.match(fullTextRegExp) || value.match(fullTextRegExp) ) {
  388. $results = $results.add($choice);
  389. }
  390. }
  391. })
  392. ;
  393. module.debug('Setting filter', searchTerm);
  394. module.remove.filteredItem();
  395. $item
  396. .not($results)
  397. .addClass(className.filtered)
  398. ;
  399. module.verbose('Selecting first non-filtered element');
  400. module.remove.selectedItem();
  401. $item
  402. .not('.' + className.filtered)
  403. .eq(0)
  404. .addClass(className.selected)
  405. ;
  406. if( module.is.allFiltered() ) {
  407. module.debug('All items filtered, hiding dropdown', searchTerm);
  408. if(module.is.searchSelection()) {
  409. module.hide();
  410. }
  411. settings.onNoResults.call(element, searchTerm);
  412. }
  413. },
  414. focusSearch: function() {
  415. if( module.is.search() ) {
  416. $search
  417. .focus()
  418. ;
  419. }
  420. },
  421. forceSelection: function() {
  422. var
  423. $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
  424. $activeItem = $item.filter('.' + className.active).eq(0),
  425. $selectedItem = ($currentlySelected.length > 0)
  426. ? $currentlySelected
  427. : $activeItem,
  428. hasSelected = ($selectedItem.size() > 0)
  429. ;
  430. if(hasSelected) {
  431. module.event.item.click.call($selectedItem);
  432. module.remove.filteredItem();
  433. }
  434. else {
  435. module.hide();
  436. }
  437. },
  438. event: {
  439. // prevents focus callback from occuring on mousedown
  440. mousedown: function() {
  441. activated = true;
  442. },
  443. mouseup: function() {
  444. activated = false;
  445. },
  446. focus: function() {
  447. if(!activated && module.is.hidden()) {
  448. module.show();
  449. }
  450. },
  451. blur: function(event) {
  452. var
  453. pageLostFocus = (document.activeElement === this)
  454. ;
  455. if(!activated && !pageLostFocus) {
  456. module.hide();
  457. }
  458. },
  459. searchFocus: function() {
  460. activated = true;
  461. module.show();
  462. },
  463. searchBlur: function(event) {
  464. var
  465. pageLostFocus = (document.activeElement === this)
  466. ;
  467. if(!itemActivated && !pageLostFocus) {
  468. if(settings.forceSelection) {
  469. module.forceSelection();
  470. }
  471. else {
  472. module.hide();
  473. }
  474. }
  475. },
  476. searchTextFocus: function(event) {
  477. activated = true;
  478. $search.focus();
  479. },
  480. input: function(event) {
  481. if(module.is.searchSelection()) {
  482. module.set.filtered();
  483. }
  484. clearTimeout(module.timer);
  485. module.timer = setTimeout(module.search, settings.delay.search);
  486. },
  487. keydown: function(event) {
  488. var
  489. $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
  490. $activeItem = $menu.children('.' + className.active).eq(0),
  491. $selectedItem = ($currentlySelected.length > 0)
  492. ? $currentlySelected
  493. : $activeItem,
  494. $visibleItems = ($selectedItem.length > 0)
  495. ? $selectedItem.siblings(':not(.' + className.filtered +')').andSelf()
  496. : $menu.children(':not(.' + className.filtered +')'),
  497. $subMenu = $selectedItem.children(selector.menu),
  498. $parentMenu = $selectedItem.closest(selector.menu),
  499. isSubMenuItem = $parentMenu[0] !== $menu[0],
  500. inVisibleMenu = $parentMenu.is(':visible'),
  501. pressedKey = event.which,
  502. keys = {
  503. enter : 13,
  504. escape : 27,
  505. leftArrow : 37,
  506. upArrow : 38,
  507. rightArrow : 39,
  508. downArrow : 40
  509. },
  510. hasSubMenu = ($subMenu.length> 0),
  511. hasSelectedItem = ($selectedItem.length > 0),
  512. lastVisibleIndex = ($visibleItems.size() - 1),
  513. $nextItem,
  514. newIndex
  515. ;
  516. // visible menu keyboard shortcuts
  517. if(module.is.visible()) {
  518. // enter (select or sub-menu)
  519. if(pressedKey == keys.enter && hasSelectedItem) {
  520. if(hasSubMenu && !settings.allowCategorySelection) {
  521. module.verbose('Pressed enter on unselectable category, opening sub menu');
  522. pressedKey = keys.rightArrow;
  523. }
  524. else {
  525. module.verbose('Enter key pressed, choosing selected item');
  526. module.event.item.click.call($selectedItem, event);
  527. }
  528. }
  529. // left arrow (hide sub-menu)
  530. if(pressedKey == keys.leftArrow) {
  531. if(isSubMenuItem) {
  532. module.verbose('Left key pressed, closing sub-menu');
  533. module.animate.hide(false, $parentMenu);
  534. $selectedItem
  535. .removeClass(className.selected)
  536. ;
  537. $parentMenu
  538. .closest(selector.item)
  539. .addClass(className.selected)
  540. ;
  541. }
  542. event.preventDefault();
  543. }
  544. // right arrow (show sub-menu)
  545. if(pressedKey == keys.rightArrow) {
  546. if(hasSubMenu) {
  547. module.verbose('Right key pressed, opening sub-menu');
  548. module.animate.show(false, $subMenu);
  549. $selectedItem
  550. .removeClass(className.selected)
  551. ;
  552. $subMenu
  553. .find(selector.item).eq(0)
  554. .addClass(className.selected)
  555. ;
  556. }
  557. event.preventDefault();
  558. }
  559. // up arrow (traverse menu up)
  560. if(pressedKey == keys.upArrow) {
  561. $nextItem = (hasSelectedItem && inVisibleMenu)
  562. ? $selectedItem.prevAll(selector.item + ':not(.' + className.filtered + ')').eq(0)
  563. : $item.eq(0)
  564. ;
  565. if($visibleItems.index( $nextItem ) < 0) {
  566. module.verbose('Up key pressed but reached top of current menu');
  567. return;
  568. }
  569. else {
  570. module.verbose('Up key pressed, changing active item');
  571. $selectedItem
  572. .removeClass(className.selected)
  573. ;
  574. $nextItem
  575. .addClass(className.selected)
  576. ;
  577. module.set.scrollPosition($nextItem);
  578. }
  579. event.preventDefault();
  580. }
  581. // down arrow (traverse menu down)
  582. if(pressedKey == keys.downArrow) {
  583. $nextItem = (hasSelectedItem && inVisibleMenu)
  584. ? $nextItem = $selectedItem.nextAll(selector.item + ':not(.' + className.filtered + ')').eq(0)
  585. : $item.eq(0)
  586. ;
  587. if($nextItem.length === 0) {
  588. module.verbose('Down key pressed but reached bottom of current menu');
  589. return;
  590. }
  591. else {
  592. module.verbose('Down key pressed, changing active item');
  593. $item
  594. .removeClass(className.selected)
  595. ;
  596. $nextItem
  597. .addClass(className.selected)
  598. ;
  599. module.set.scrollPosition($nextItem);
  600. }
  601. event.preventDefault();
  602. }
  603. }
  604. else {
  605. // enter (open menu)
  606. if(pressedKey == keys.enter) {
  607. module.verbose('Enter key pressed, showing dropdown');
  608. module.show();
  609. }
  610. // escape (close menu)
  611. if(pressedKey == keys.escape) {
  612. module.verbose('Escape key pressed, closing dropdown');
  613. module.hide();
  614. }
  615. // down arrow (open menu)
  616. if(pressedKey == keys.downArrow) {
  617. module.verbose('Down key pressed, showing dropdown');
  618. module.show();
  619. }
  620. }
  621. },
  622. test: {
  623. toggle: function(event) {
  624. if( module.determine.eventInMenu(event, module.toggle) ) {
  625. event.preventDefault();
  626. }
  627. },
  628. touch: function(event) {
  629. module.determine.eventInMenu(event, function() {
  630. if(event.type == 'touchstart') {
  631. module.timer = setTimeout(module.hide, settings.delay.touch);
  632. }
  633. else if(event.type == 'touchmove') {
  634. clearTimeout(module.timer);
  635. }
  636. });
  637. event.stopPropagation();
  638. },
  639. hide: function(event) {
  640. module.determine.eventInModule(event, module.hide);
  641. }
  642. },
  643. menu: {
  644. activate: function() {
  645. itemActivated = true;
  646. },
  647. deactivate: function() {
  648. itemActivated = false;
  649. }
  650. },
  651. item: {
  652. mouseenter: function(event) {
  653. var
  654. $subMenu = $(this).children(selector.menu),
  655. $otherMenus = $(this).siblings(selector.item).children(selector.menu)
  656. ;
  657. if( $subMenu.length > 0 ) {
  658. clearTimeout(module.itemTimer);
  659. module.itemTimer = setTimeout(function() {
  660. module.verbose('Showing sub-menu', $subMenu);
  661. $.each($otherMenus, function() {
  662. module.animate.hide(false, $(this));
  663. });
  664. module.animate.show(false, $subMenu);
  665. }, settings.delay.show);
  666. event.preventDefault();
  667. }
  668. },
  669. mouseleave: function(event) {
  670. var
  671. $subMenu = $(this).children(selector.menu)
  672. ;
  673. if($subMenu.length > 0) {
  674. clearTimeout(module.itemTimer);
  675. module.itemTimer = setTimeout(function() {
  676. module.verbose('Hiding sub-menu', $subMenu);
  677. module.animate.hide(false, $subMenu);
  678. }, settings.delay.hide);
  679. }
  680. },
  681. click: function (event) {
  682. var
  683. $choice = $(this),
  684. $target = (event)
  685. ? $(event.target)
  686. : $(''),
  687. $subMenu = $choice.find(selector.menu),
  688. text = module.get.choiceText($choice),
  689. value = module.get.choiceValue($choice, text),
  690. callback = function() {
  691. module.remove.searchTerm();
  692. module.determine.selectAction(text, value);
  693. },
  694. hasSubMenu = ($subMenu.length > 0),
  695. isBubbledEvent = ($subMenu.find($target).length > 0)
  696. ;
  697. if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
  698. callback();
  699. }
  700. }
  701. },
  702. resetStyle: function() {
  703. $(this).removeAttr('style');
  704. }
  705. },
  706. determine: {
  707. selectAction: function(text, value) {
  708. module.verbose('Determining action', settings.action);
  709. if( $.isFunction( module.action[settings.action] ) ) {
  710. module.verbose('Triggering preset action', settings.action, text, value);
  711. module.action[ settings.action ](text, value);
  712. }
  713. else if( $.isFunction(settings.action) ) {
  714. module.verbose('Triggering user action', settings.action, text, value);
  715. settings.action(text, value);
  716. }
  717. else {
  718. module.error(error.action, settings.action);
  719. }
  720. },
  721. eventInModule: function(event, callback) {
  722. callback = $.isFunction(callback)
  723. ? callback
  724. : function(){}
  725. ;
  726. if( $(event.target).closest($module).length === 0 ) {
  727. module.verbose('Triggering event', callback);
  728. callback();
  729. return true;
  730. }
  731. else {
  732. module.verbose('Event occurred in dropdown, canceling callback');
  733. return false;
  734. }
  735. },
  736. eventInMenu: function(event, callback) {
  737. callback = $.isFunction(callback)
  738. ? callback
  739. : function(){}
  740. ;
  741. if( $(event.target).closest($menu).length === 0 ) {
  742. module.verbose('Triggering event', callback);
  743. callback();
  744. return true;
  745. }
  746. else {
  747. module.verbose('Event occurred in dropdown menu, canceling callback');
  748. return false;
  749. }
  750. }
  751. },
  752. action: {
  753. nothing: function() {},
  754. activate: function(text, value) {
  755. value = (value !== undefined)
  756. ? value
  757. : text
  758. ;
  759. module.set.selected(value);
  760. module.hide(function() {
  761. module.remove.filteredItem();
  762. });
  763. },
  764. select: function(text, value) {
  765. value = (value !== undefined)
  766. ? value
  767. : text
  768. ;
  769. module.set.selected(value);
  770. module.hide(function() {
  771. module.remove.filteredItem();
  772. });
  773. },
  774. combo: function(text, value) {
  775. value = (value !== undefined)
  776. ? value
  777. : text
  778. ;
  779. module.set.selected(value);
  780. module.hide(function() {
  781. module.remove.filteredItem();
  782. });
  783. },
  784. hide: function() {
  785. module.hide(function() {
  786. module.remove.filteredItem();
  787. });
  788. }
  789. },
  790. get: {
  791. id: function() {
  792. return id;
  793. },
  794. text: function() {
  795. return $text.text();
  796. },
  797. value: function() {
  798. return ($input.length > 0)
  799. ? $input.val()
  800. : $module.data(metadata.value)
  801. ;
  802. },
  803. choiceText: function($choice, preserveHTML) {
  804. preserveHTML = (preserveHTML !== undefined)
  805. ? preserveHTML
  806. : settings.preserveHTML
  807. ;
  808. if($choice !== undefined) {
  809. if($choice.find(selector.menu).length > 0) {
  810. module.verbose('Retreiving text of element with sub-menu');
  811. $choice = $choice.clone();
  812. $choice.find(selector.menu).remove();
  813. $choice.find(selector.menuIcon).remove();
  814. }
  815. return ($choice.data(metadata.text) !== undefined)
  816. ? $choice.data(metadata.text)
  817. : (preserveHTML)
  818. ? $choice.html().trim()
  819. : $choice.text().trim()
  820. ;
  821. }
  822. },
  823. choiceValue: function($choice, choiceText) {
  824. choiceText = choiceText || module.get.choiceText($choice);
  825. return ($choice.data(metadata.value) !== undefined)
  826. ? $choice.data(metadata.value)
  827. : (typeof choiceText === 'string')
  828. ? choiceText.toLowerCase().trim()
  829. : choiceText.trim()
  830. ;
  831. },
  832. inputEvent: function() {
  833. var
  834. input = $search[0]
  835. ;
  836. if(input) {
  837. return (input.oninput !== undefined)
  838. ? 'input'
  839. : (input.onpropertychange !== undefined)
  840. ? 'propertychange'
  841. : 'keyup'
  842. ;
  843. }
  844. return false;
  845. },
  846. selectValues: function() {
  847. var
  848. select = {}
  849. ;
  850. select.values = (settings.sortSelect)
  851. ? {} // properties will be sorted in object when re-accessed
  852. : [] // properties will keep original order in array
  853. ;
  854. $module
  855. .find('option')
  856. .each(function() {
  857. var
  858. name = $(this).html(),
  859. value = ( $(this).attr('value') !== undefined )
  860. ? $(this).attr('value')
  861. : name
  862. ;
  863. if(value === '') {
  864. select.placeholder = name;
  865. }
  866. else {
  867. if(settings.sortSelect) {
  868. select.values[value] = {
  869. name : name,
  870. value : value
  871. };
  872. }
  873. else {
  874. select.values.push({
  875. name: name,
  876. value: value
  877. });
  878. }
  879. }
  880. })
  881. ;
  882. if(settings.sortSelect) {
  883. module.debug('Retrieved and sorted values from select', select);
  884. }
  885. else {
  886. module.debug('Retreived values from select', select);
  887. }
  888. return select;
  889. },
  890. activeItem: function() {
  891. return $item.filter('.' + className.active);
  892. },
  893. item: function(value, strict) {
  894. var
  895. $selectedItem = false
  896. ;
  897. value = (value !== undefined)
  898. ? value
  899. : ( module.get.value() !== undefined)
  900. ? module.get.value()
  901. : module.get.text()
  902. ;
  903. strict = (value === '' || value === 0)
  904. ? true
  905. : strict || false
  906. ;
  907. if(value !== undefined) {
  908. $item
  909. .each(function() {
  910. var
  911. $choice = $(this),
  912. optionText = module.get.choiceText($choice),
  913. optionValue = module.get.choiceValue($choice, optionText)
  914. ;
  915. if(strict) {
  916. module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
  917. if( optionValue === value ) {
  918. $selectedItem = $(this);
  919. return true;
  920. }
  921. else if( !$selectedItem && optionText === value ) {
  922. $selectedItem = $(this);
  923. return true;
  924. }
  925. }
  926. else {
  927. if( optionValue == value ) {
  928. module.verbose('Found select item by value', optionValue, value);
  929. $selectedItem = $(this);
  930. return true;
  931. }
  932. else if( !$selectedItem && optionText == value ) {
  933. module.verbose('Found select item by text', optionText, value);
  934. $selectedItem = $(this);
  935. return true;
  936. }
  937. }
  938. })
  939. ;
  940. }
  941. else {
  942. value = module.get.text();
  943. }
  944. return $selectedItem || false;
  945. }
  946. },
  947. restore: {
  948. defaults: function() {
  949. module.restore.defaultText();
  950. module.restore.defaultValue();
  951. },
  952. defaultText: function() {
  953. var
  954. defaultText = $module.data(metadata.defaultText)
  955. ;
  956. module.debug('Restoring default text', defaultText);
  957. module.set.text(defaultText);
  958. $text.addClass(className.placeholder);
  959. },
  960. defaultValue: function() {
  961. var
  962. defaultValue = $module.data(metadata.defaultValue)
  963. ;
  964. if(defaultValue !== undefined) {
  965. module.debug('Restoring default value', defaultValue);
  966. if(defaultValue.length) {
  967. module.set.selected(defaultValue);
  968. }
  969. else {
  970. module.remove.activeItem();
  971. module.remove.selectedItem();
  972. }
  973. }
  974. }
  975. },
  976. save: {
  977. defaults: function() {
  978. module.save.defaultText();
  979. module.save.placeholderText();
  980. module.save.defaultValue();
  981. },
  982. defaultValue: function() {
  983. $module.data(metadata.defaultValue, module.get.value() );
  984. },
  985. defaultText: function() {
  986. $module.data(metadata.defaultText, $text.text() );
  987. },
  988. placeholderText: function() {
  989. if($text.hasClass(className.placeholder)) {
  990. $module.data(metadata.placeholderText, $text.text());
  991. }
  992. }
  993. },
  994. clear: function() {
  995. var
  996. placeholderText = $module.data(metadata.placeholderText)
  997. ;
  998. module.set.text(placeholderText);
  999. module.set.value('');
  1000. module.remove.activeItem();
  1001. module.remove.selectedItem();
  1002. $text.addClass(className.placeholder);
  1003. },
  1004. set: {
  1005. filtered: function() {
  1006. var
  1007. searchValue = $search.val(),
  1008. hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0)
  1009. ;
  1010. if(hasSearchValue) {
  1011. $text.addClass(className.filtered);
  1012. }
  1013. else {
  1014. $text.removeClass(className.filtered);
  1015. }
  1016. },
  1017. tabbable: function() {
  1018. if( module.is.searchable() ) {
  1019. module.debug('Searchable dropdown initialized');
  1020. $search
  1021. .val('')
  1022. .attr('tabindex', 0)
  1023. ;
  1024. $menu
  1025. .attr('tabindex', '-1')
  1026. ;
  1027. }
  1028. else {
  1029. module.debug('Simple selection dropdown initialized');
  1030. if(!$module.attr('tabindex') ) {
  1031. $module
  1032. .attr('tabindex', 0)
  1033. ;
  1034. $menu
  1035. .attr('tabindex', '-1')
  1036. ;
  1037. }
  1038. }
  1039. },
  1040. scrollPosition: function($item, forceScroll) {
  1041. var
  1042. edgeTolerance = 5,
  1043. hasActive,
  1044. offset,
  1045. itemHeight,
  1046. itemOffset,
  1047. menuOffset,
  1048. menuScroll,
  1049. menuHeight,
  1050. abovePage,
  1051. belowPage
  1052. ;
  1053. $item = $item || module.get.activeItem();
  1054. hasActive = ($item && $item.length > 0);
  1055. forceScroll = (forceScroll !== undefined)
  1056. ? forceScroll
  1057. : false
  1058. ;
  1059. if($item && hasActive) {
  1060. if(!$menu.hasClass(className.visible)) {
  1061. $menu.addClass(className.loading);
  1062. }
  1063. menuHeight = $menu.height();
  1064. itemHeight = $item.height();
  1065. menuScroll = $menu.scrollTop();
  1066. menuOffset = $menu.offset().top;
  1067. itemOffset = $item.offset().top;
  1068. offset = menuScroll - menuOffset + itemOffset;
  1069. belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
  1070. abovePage = ((offset - edgeTolerance) < menuScroll);
  1071. module.debug('Scrolling to active item', offset);
  1072. if(abovePage || belowPage || forceScroll) {
  1073. $menu
  1074. .scrollTop(offset)
  1075. .removeClass(className.loading)
  1076. ;
  1077. }
  1078. }
  1079. },
  1080. text: function(text) {
  1081. if(settings.action == 'combo') {
  1082. module.debug('Changing combo button text', text, $combo);
  1083. if(settings.preserveHTML) {
  1084. $combo.html(text);
  1085. }
  1086. else {
  1087. $combo.text(text);
  1088. }
  1089. }
  1090. else if(settings.action !== 'select') {
  1091. module.debug('Changing text', text, $text);
  1092. $text
  1093. .removeClass(className.filtered)
  1094. .removeClass(className.placeholder)
  1095. ;
  1096. if(settings.preserveHTML) {
  1097. $text.html(text);
  1098. }
  1099. else {
  1100. $text.text(text);
  1101. }
  1102. }
  1103. },
  1104. value: function(value) {
  1105. module.debug('Adding selected value to hidden input', value, $input);
  1106. if($input.length > 0) {
  1107. $input
  1108. .val(value)
  1109. .trigger('change')
  1110. ;
  1111. }
  1112. else {
  1113. $module.data(metadata.value, value);
  1114. }
  1115. },
  1116. active: function() {
  1117. $module
  1118. .addClass(className.active)
  1119. ;
  1120. },
  1121. visible: function() {
  1122. $module.addClass(className.visible);
  1123. },
  1124. selected: function(value) {
  1125. var
  1126. $selectedItem = module.get.item(value),
  1127. selectedText,
  1128. selectedValue
  1129. ;
  1130. if($selectedItem && !$selectedItem.hasClass(className.active) ) {
  1131. module.debug('Setting selected menu item to', $selectedItem);
  1132. module.remove.activeItem();
  1133. module.remove.selectedItem();
  1134. $selectedItem
  1135. .addClass(className.active)
  1136. .addClass(className.selected)
  1137. ;
  1138. selectedText = module.get.choiceText($selectedItem);
  1139. selectedValue = module.get.choiceValue($selectedItem, selectedText);
  1140. module.set.text(selectedText);
  1141. module.set.value(selectedValue);
  1142. settings.onChange.call(element, value, selectedText, $selectedItem);
  1143. }
  1144. }
  1145. },
  1146. remove: {
  1147. active: function() {
  1148. $module.removeClass(className.active);
  1149. },
  1150. visible: function() {
  1151. $module.removeClass(className.visible);
  1152. },
  1153. activeItem: function() {
  1154. $item.removeClass(className.active);
  1155. },
  1156. filteredItem: function() {
  1157. $item.removeClass(className.filtered);
  1158. },
  1159. searchTerm: function() {
  1160. $search.val('');
  1161. },
  1162. selectedItem: function() {
  1163. $item.removeClass(className.selected);
  1164. },
  1165. tabbable: function() {
  1166. if( module.is.searchable() ) {
  1167. module.debug('Searchable dropdown initialized');
  1168. $search
  1169. .attr('tabindex', '-1')
  1170. ;
  1171. $menu
  1172. .attr('tabindex', '-1')
  1173. ;
  1174. }
  1175. else {
  1176. module.debug('Simple selection dropdown initialized');
  1177. $module
  1178. .attr('tabindex', '-1')
  1179. ;
  1180. $menu
  1181. .attr('tabindex', '-1')
  1182. ;
  1183. }
  1184. }
  1185. },
  1186. is: {
  1187. active: function() {
  1188. return $module.hasClass(className.active);
  1189. },
  1190. alreadySetup: function() {
  1191. return ($module.is('select') && $module.parent(selector.dropdown).length > 0);
  1192. },
  1193. animating: function($subMenu) {
  1194. return ($subMenu)
  1195. ? $subMenu.is(':animated') || $subMenu.transition && $subMenu.transition('is animating')
  1196. : $menu.is(':animated') || $menu.transition && $menu.transition('is animating')
  1197. ;
  1198. },
  1199. allFiltered: function() {
  1200. return ($item.filter('.' + className.filtered).length === $item.length);
  1201. },
  1202. hidden: function($subMenu) {
  1203. return ($subMenu)
  1204. ? $subMenu.is(':hidden')
  1205. : $menu.is(':hidden')
  1206. ;
  1207. },
  1208. selectMutation: function(mutations) {
  1209. var
  1210. selectChanged = false
  1211. ;
  1212. $.each(mutations, function(index, mutation) {
  1213. if(mutation.target && $(mutation.target).is('select')) {
  1214. selectChanged = true;
  1215. return true;
  1216. }
  1217. });
  1218. return selectChanged;
  1219. },
  1220. search: function() {
  1221. return $module.hasClass(className.search);
  1222. },
  1223. searchable: function() {
  1224. return ($search.length > 0);
  1225. },
  1226. searchSelection: function() {
  1227. return ( module.is.searchable() && $search.parent().is($module) );
  1228. },
  1229. selection: function() {
  1230. return $module.hasClass(className.selection);
  1231. },
  1232. upward: function() {
  1233. return $module.hasClass(className.upward);
  1234. },
  1235. visible: function($subMenu) {
  1236. return ($subMenu)
  1237. ? $subMenu.is(':visible')
  1238. : $menu.is(':visible')
  1239. ;
  1240. }
  1241. },
  1242. can: {
  1243. click: function() {
  1244. return (hasTouch || settings.on == 'click');
  1245. },
  1246. show: function() {
  1247. return !$module.hasClass(className.disabled);
  1248. }
  1249. },
  1250. animate: {
  1251. show: function(callback, $subMenu) {
  1252. var
  1253. $currentMenu = $subMenu || $menu,
  1254. start = ($subMenu)
  1255. ? function() {}
  1256. : function() {
  1257. module.hideSubMenus();
  1258. module.hideOthers();
  1259. module.set.active();
  1260. }
  1261. ;
  1262. callback = $.isFunction(callback)
  1263. ? callback
  1264. : function(){}
  1265. ;
  1266. module.set.scrollPosition(module.get.activeItem(), true);
  1267. module.verbose('Doing menu show animation', $currentMenu);
  1268. if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
  1269. if(settings.transition == 'auto') {
  1270. settings.transition = module.is.upward()
  1271. ? 'slide up'
  1272. : 'slide down'
  1273. ;
  1274. module.verbose('Automatically determining animation based on animation direction', settings.transition);
  1275. }
  1276. if(settings.transition == 'none') {
  1277. callback.call(element);
  1278. }
  1279. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  1280. $currentMenu
  1281. .transition({
  1282. animation : settings.transition + ' in',
  1283. debug : settings.debug,
  1284. verbose : settings.verbose,
  1285. duration : settings.duration,
  1286. queue : true,
  1287. onStart : start,
  1288. onComplete : function() {
  1289. callback.call(element);
  1290. }
  1291. })
  1292. ;
  1293. }
  1294. else if(settings.transition == 'slide down') {
  1295. start();
  1296. $currentMenu
  1297. .hide()
  1298. .clearQueue()
  1299. .children()
  1300. .clearQueue()
  1301. .css('opacity', 0)
  1302. .delay(50)
  1303. .animate({
  1304. opacity : 1
  1305. }, settings.duration, 'easeOutQuad', module.event.resetStyle)
  1306. .end()
  1307. .slideDown(100, 'easeOutQuad', function() {
  1308. module.event.resetStyle.call(this);
  1309. callback.call(element);
  1310. })
  1311. ;
  1312. }
  1313. else if(settings.transition == 'fade') {
  1314. start();
  1315. $currentMenu
  1316. .hide()
  1317. .clearQueue()
  1318. .fadeIn(settings.duration, function() {
  1319. module.event.resetStyle.call(this);
  1320. callback.call(element);
  1321. })
  1322. ;
  1323. }
  1324. else {
  1325. module.error(error.transition, settings.transition);
  1326. }
  1327. }
  1328. },
  1329. hide: function(callback, $subMenu) {
  1330. var
  1331. $currentMenu = $subMenu || $menu,
  1332. duration = ($subMenu)
  1333. ? (settings.duration * 0.9)
  1334. : settings.duration,
  1335. start = ($subMenu)
  1336. ? function() {}
  1337. : function() {
  1338. if( module.can.click() ) {
  1339. module.unbind.intent();
  1340. }
  1341. module.focusSearch();
  1342. module.remove.active();
  1343. }
  1344. ;
  1345. callback = $.isFunction(callback)
  1346. ? callback
  1347. : function(){}
  1348. ;
  1349. if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
  1350. module.verbose('Doing menu hide animation', $currentMenu);
  1351. if(settings.transition == 'auto') {
  1352. settings.transition = module.is.upward()
  1353. ? 'slide up'
  1354. : 'slide down'
  1355. ;
  1356. }
  1357. $input.trigger('blur');
  1358. if(settings.transition == 'none') {
  1359. callback.call(element);
  1360. }
  1361. else if($.fn.transition !== undefined && $module.transition('is supported')) {
  1362. $currentMenu
  1363. .transition({
  1364. animation : settings.transition + ' out',
  1365. duration : settings.duration,
  1366. debug : settings.debug,
  1367. verbose : settings.verbose,
  1368. queue : true,
  1369. onStart : start,
  1370. onComplete : function() {
  1371. callback.call(element);
  1372. }
  1373. })
  1374. ;
  1375. }
  1376. else if(settings.transition == 'slide down') {
  1377. start();
  1378. $currentMenu
  1379. .show()
  1380. .clearQueue()
  1381. .children()
  1382. .clearQueue()
  1383. .css('opacity', 1)
  1384. .animate({
  1385. opacity : 0
  1386. }, 100, 'easeOutQuad', module.event.resetStyle)
  1387. .end()
  1388. .delay(50)
  1389. .slideUp(100, 'easeOutQuad', function() {
  1390. module.event.resetStyle.call(this);
  1391. callback.call(element);
  1392. })
  1393. ;
  1394. }
  1395. else if(settings.transition == 'fade') {
  1396. start();
  1397. $currentMenu
  1398. .show()
  1399. .clearQueue()
  1400. .fadeOut(150, function() {
  1401. module.event.resetStyle.call(this);
  1402. callback.call(element);
  1403. })
  1404. ;
  1405. }
  1406. else {
  1407. module.error(error.transition);
  1408. }
  1409. }
  1410. }
  1411. },
  1412. delay: {
  1413. show: function() {
  1414. module.verbose('Delaying show event to ensure user intent');
  1415. clearTimeout(module.timer);
  1416. module.timer = setTimeout(module.show, settings.delay.show);
  1417. },
  1418. hide: function() {
  1419. module.verbose('Delaying hide event to ensure user intent');
  1420. clearTimeout(module.timer);
  1421. module.timer = setTimeout(module.hide, settings.delay.hide);
  1422. }
  1423. },
  1424. escape: {
  1425. regExp: function(text) {
  1426. text = String(text);
  1427. return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
  1428. }
  1429. },
  1430. setting: function(name, value) {
  1431. module.debug('Changing setting', name, value);
  1432. if( $.isPlainObject(name) ) {
  1433. $.extend(true, settings, name);
  1434. }
  1435. else if(value !== undefined) {
  1436. settings[name] = value;
  1437. }
  1438. else {
  1439. return settings[name];
  1440. }
  1441. },
  1442. internal: function(name, value) {
  1443. if( $.isPlainObject(name) ) {
  1444. $.extend(true, module, name);
  1445. }
  1446. else if(value !== undefined) {
  1447. module[name] = value;
  1448. }
  1449. else {
  1450. return module[name];
  1451. }
  1452. },
  1453. debug: function() {
  1454. if(settings.debug) {
  1455. if(settings.performance) {
  1456. module.performance.log(arguments);
  1457. }
  1458. else {
  1459. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1460. module.debug.apply(console, arguments);
  1461. }
  1462. }
  1463. },
  1464. verbose: function() {
  1465. if(settings.verbose && settings.debug) {
  1466. if(settings.performance) {
  1467. module.performance.log(arguments);
  1468. }
  1469. else {
  1470. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1471. module.verbose.apply(console, arguments);
  1472. }
  1473. }
  1474. },
  1475. error: function() {
  1476. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  1477. module.error.apply(console, arguments);
  1478. },
  1479. performance: {
  1480. log: function(message) {
  1481. var
  1482. currentTime,
  1483. executionTime,
  1484. previousTime
  1485. ;
  1486. if(settings.performance) {
  1487. currentTime = new Date().getTime();
  1488. previousTime = time || currentTime;
  1489. executionTime = currentTime - previousTime;
  1490. time = currentTime;
  1491. performance.push({
  1492. 'Name' : message[0],
  1493. 'Arguments' : [].slice.call(message, 1) || '',
  1494. 'Element' : element,
  1495. 'Execution Time' : executionTime
  1496. });
  1497. }
  1498. clearTimeout(module.performance.timer);
  1499. module.performance.timer = setTimeout(module.performance.display, 500);
  1500. },
  1501. display: function() {
  1502. var
  1503. title = settings.name + ':',
  1504. totalTime = 0
  1505. ;
  1506. time = false;
  1507. clearTimeout(module.performance.timer);
  1508. $.each(performance, function(index, data) {
  1509. totalTime += data['Execution Time'];
  1510. });
  1511. title += ' ' + totalTime + 'ms';
  1512. if(moduleSelector) {
  1513. title += ' \'' + moduleSelector + '\'';
  1514. }
  1515. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  1516. console.groupCollapsed(title);
  1517. if(console.table) {
  1518. console.table(performance);
  1519. }
  1520. else {
  1521. $.each(performance, function(index, data) {
  1522. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  1523. });
  1524. }
  1525. console.groupEnd();
  1526. }
  1527. performance = [];
  1528. }
  1529. },
  1530. invoke: function(query, passedArguments, context) {
  1531. var
  1532. object = instance,
  1533. maxDepth,
  1534. found,
  1535. response
  1536. ;
  1537. passedArguments = passedArguments || queryArguments;
  1538. context = element || context;
  1539. if(typeof query == 'string' && object !== undefined) {
  1540. query = query.split(/[\. ]/);
  1541. maxDepth = query.length - 1;
  1542. $.each(query, function(depth, value) {
  1543. var camelCaseValue = (depth != maxDepth)
  1544. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  1545. : query
  1546. ;
  1547. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  1548. object = object[camelCaseValue];
  1549. }
  1550. else if( object[camelCaseValue] !== undefined ) {
  1551. found = object[camelCaseValue];
  1552. return false;
  1553. }
  1554. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  1555. object = object[value];
  1556. }
  1557. else if( object[value] !== undefined ) {
  1558. found = object[value];
  1559. return false;
  1560. }
  1561. else {
  1562. module.error(error.method, query);
  1563. return false;
  1564. }
  1565. });
  1566. }
  1567. if ( $.isFunction( found ) ) {
  1568. response = found.apply(context, passedArguments);
  1569. }
  1570. else if(found !== undefined) {
  1571. response = found;
  1572. }
  1573. if($.isArray(returnedValue)) {
  1574. returnedValue.push(response);
  1575. }
  1576. else if(returnedValue !== undefined) {
  1577. returnedValue = [returnedValue, response];
  1578. }
  1579. else if(response !== undefined) {
  1580. returnedValue = response;
  1581. }
  1582. return found;
  1583. }
  1584. };
  1585. if(methodInvoked) {
  1586. if(instance === undefined) {
  1587. module.initialize();
  1588. }
  1589. module.invoke(query);
  1590. }
  1591. else {
  1592. if(instance !== undefined) {
  1593. instance.invoke('destroy');
  1594. }
  1595. module.initialize();
  1596. }
  1597. })
  1598. ;
  1599. return (returnedValue !== undefined)
  1600. ? returnedValue
  1601. : $allModules
  1602. ;
  1603. };
  1604. $.fn.dropdown.settings = {
  1605. debug : false,
  1606. verbose : true,
  1607. performance : true,
  1608. on : 'click',
  1609. action : 'activate',
  1610. allowTab : true,
  1611. fullTextSearch : false,
  1612. preserveHTML : true,
  1613. sortSelect : false,
  1614. allowCategorySelection : false,
  1615. delay : {
  1616. hide : 300,
  1617. show : 200,
  1618. search : 50,
  1619. touch : 50
  1620. },
  1621. forceSelection: true,
  1622. transition : 'auto',
  1623. duration : 250,
  1624. /* Callbacks */
  1625. onNoResults : function(searchTerm){},
  1626. onChange : function(value, text){},
  1627. onShow : function(){},
  1628. onHide : function(){},
  1629. /* Component */
  1630. name : 'Dropdown',
  1631. namespace : 'dropdown',
  1632. error : {
  1633. action : 'You called a dropdown action that was not defined',
  1634. alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
  1635. method : 'The method you called is not defined.',
  1636. transition : 'The requested transition was not found'
  1637. },
  1638. metadata: {
  1639. defaultText : 'defaultText',
  1640. defaultValue : 'defaultValue',
  1641. placeholderText : 'placeholderText',
  1642. text : 'text',
  1643. value : 'value'
  1644. },
  1645. selector : {
  1646. dropdown : '.ui.dropdown',
  1647. input : '> input[type="hidden"], > select',
  1648. item : '.item',
  1649. menu : '.menu',
  1650. menuIcon : '.dropdown.icon',
  1651. search : '> input.search, .menu > .search > input, .menu > input.search',
  1652. text : '> .text:not(.icon)'
  1653. },
  1654. className : {
  1655. active : 'active',
  1656. animating : 'animating',
  1657. disabled : 'disabled',
  1658. dropdown : 'ui dropdown',
  1659. filtered : 'filtered',
  1660. loading : 'loading',
  1661. menu : 'menu',
  1662. placeholder : 'default',
  1663. search : 'search',
  1664. selected : 'selected',
  1665. selection : 'selection',
  1666. upward : 'upward',
  1667. visible : 'visible'
  1668. }
  1669. };
  1670. /* Templates */
  1671. $.fn.dropdown.settings.templates = {
  1672. menu: function(select) {
  1673. var
  1674. placeholder = select.placeholder || false,
  1675. values = select.values || {},
  1676. html = ''
  1677. ;
  1678. $.each(select.values, function(index, option) {
  1679. html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
  1680. });
  1681. return html;
  1682. },
  1683. dropdown: function(select) {
  1684. var
  1685. placeholder = select.placeholder || false,
  1686. values = select.values || {},
  1687. html = ''
  1688. ;
  1689. html += '<i class="dropdown icon"></i>';
  1690. if(select.placeholder) {
  1691. html += '<div class="default text">' + placeholder + '</div>';
  1692. }
  1693. else {
  1694. html += '<div class="text"></div>';
  1695. }
  1696. html += '<div class="menu">';
  1697. $.each(select.values, function(index, option) {
  1698. html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
  1699. });
  1700. html += '</div>';
  1701. return html;
  1702. }
  1703. };
  1704. /* Dependencies */
  1705. $.extend( $.easing, {
  1706. easeOutQuad: function (x, t, b, c, d) {
  1707. return -c *(t/=d)*(t-2) + b;
  1708. },
  1709. });
  1710. })( jQuery, window , document );