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.

1795 lines
58 KiB

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