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