button-native.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* Native Javascript for Bootstrap 4 | Button
  2. ---------------------------------------------*/
  3. // BUTTON DEFINITION
  4. // ===================
  5. var Button = function( element ) {
  6. // initialization element
  7. element = queryElement(element);
  8. // constant
  9. var toggled = false, // toggled makes sure to prevent triggering twice the change.bs.button events
  10. // strings
  11. component = 'button',
  12. checked = 'checked',
  13. LABEL = 'LABEL',
  14. INPUT = 'INPUT',
  15. // private methods
  16. keyHandler = function(e){
  17. var key = e.which || e.keyCode;
  18. key === 32 && e[target] === DOC.activeElement && toggle(e);
  19. },
  20. preventScroll = function(e){
  21. var key = e.which || e.keyCode;
  22. key === 32 && e[preventDefault]();
  23. },
  24. toggle = function(e) {
  25. var label = e[target].tagName === LABEL ? e[target] : e[target][parentNode].tagName === LABEL ? e[target][parentNode] : null; // the .btn label
  26. if ( !label ) return; //react if a label or its immediate child is clicked
  27. var labels = getElementsByClassName(label[parentNode],'btn'), // all the button group buttons
  28. input = label[getElementsByTagName](INPUT)[0];
  29. if ( !input ) return; // return if no input found
  30. // manage the dom manipulation
  31. if ( input.type === 'checkbox' ) { //checkboxes
  32. if ( !input[checked] ) {
  33. addClass(label,active);
  34. input[getAttribute](checked);
  35. input[setAttribute](checked,checked);
  36. input[checked] = true;
  37. } else {
  38. removeClass(label,active);
  39. input[getAttribute](checked);
  40. input.removeAttribute(checked);
  41. input[checked] = false;
  42. }
  43. if (!toggled) { // prevent triggering the event twice
  44. toggled = true;
  45. bootstrapCustomEvent.call(input, changeEvent, component); //trigger the change for the input
  46. bootstrapCustomEvent.call(element, changeEvent, component); //trigger the change for the btn-group
  47. }
  48. }
  49. if ( input.type === 'radio' && !toggled ) { // radio buttons
  50. // don't trigger if already active (the OR condition is a hack to check if the buttons were selected with key press and NOT mouse click)
  51. if ( !input[checked] || (e.screenX === 0 && e.screenY == 0) ) {
  52. addClass(label,active);
  53. addClass(label,focusEvent);
  54. input[setAttribute](checked,checked);
  55. input[checked] = true;
  56. bootstrapCustomEvent.call(input, changeEvent, component); //trigger the change for the input
  57. bootstrapCustomEvent.call(element, changeEvent, component); //trigger the change for the btn-group
  58. toggled = true;
  59. for (var i = 0, ll = labels[length]; i<ll; i++) {
  60. var otherLabel = labels[i], otherInput = otherLabel[getElementsByTagName](INPUT)[0];
  61. if ( otherLabel !== label && hasClass(otherLabel,active) ) {
  62. removeClass(otherLabel,active);
  63. otherInput.removeAttribute(checked);
  64. otherInput[checked] = false;
  65. bootstrapCustomEvent.call(otherInput, changeEvent, component); // trigger the change
  66. }
  67. }
  68. }
  69. }
  70. setTimeout( function() { toggled = false; }, 50 );
  71. },
  72. focusHandler = function(e) {
  73. addClass(e[target][parentNode],focusEvent);
  74. },
  75. blurHandler = function(e) {
  76. removeClass(e[target][parentNode],focusEvent);
  77. };
  78. // init
  79. if ( !( stringButton in element ) ) { // prevent adding event handlers twice
  80. on( element, clickEvent, toggle );
  81. on( element, keyupEvent, keyHandler ), on( element, keydownEvent, preventScroll );
  82. var allBtns = getElementsByClassName(element, 'btn');
  83. for (var i=0; i<allBtns.length; i++) {
  84. var input = allBtns[i][getElementsByTagName](INPUT)[0];
  85. on( input, focusEvent, focusHandler), on( input, 'blur', blurHandler);
  86. }
  87. }
  88. // activate items on load
  89. var labelsToACtivate = getElementsByClassName(element, 'btn'), lbll = labelsToACtivate[length];
  90. for (var i=0; i<lbll; i++) {
  91. !hasClass(labelsToACtivate[i],active) && queryElement('input:checked',labelsToACtivate[i])
  92. && addClass(labelsToACtivate[i],active);
  93. }
  94. element[stringButton] = this;
  95. };
  96. // BUTTON DATA API
  97. // =================
  98. supports[push]( [ stringButton, Button, '['+dataToggle+'="buttons"]' ] );