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.

1800 lines
58 KiB

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