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.

1808 lines
59 KiB

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