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.

1757 lines
57 KiB

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