checkbox.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*!
  2. * Angular Material Design
  3. * https://github.com/angular/material
  4. * @license MIT
  5. * v0.11.4
  6. */
  7. goog.provide('ng.material.components.checkbox');
  8. goog.require('ng.material.core');
  9. /**
  10. * @ngdoc module
  11. * @name material.components.checkbox
  12. * @description Checkbox module!
  13. */
  14. angular
  15. .module('material.components.checkbox', ['material.core'])
  16. .directive('mdCheckbox', MdCheckboxDirective);
  17. /**
  18. * @ngdoc directive
  19. * @name mdCheckbox
  20. * @module material.components.checkbox
  21. * @restrict E
  22. *
  23. * @description
  24. * The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
  25. *
  26. * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
  27. * the checkbox is in the accent color by default. The primary color palette may be used with
  28. * the `md-primary` class.
  29. *
  30. * @param {string} ng-model Assignable angular expression to data-bind to.
  31. * @param {string=} name Property name of the form under which the control is published.
  32. * @param {expression=} ng-true-value The value to which the expression should be set when selected.
  33. * @param {expression=} ng-false-value The value to which the expression should be set when not selected.
  34. * @param {string=} ng-change Angular expression to be executed when input changes due to user interaction with the input element.
  35. * @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects
  36. * @param {string=} aria-label Adds label to checkbox for accessibility.
  37. * Defaults to checkbox's text. If no default text is found, a warning will be logged.
  38. *
  39. * @usage
  40. * <hljs lang="html">
  41. * <md-checkbox ng-model="isChecked" aria-label="Finished?">
  42. * Finished ?
  43. * </md-checkbox>
  44. *
  45. * <md-checkbox md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
  46. * No Ink Effects
  47. * </md-checkbox>
  48. *
  49. * <md-checkbox ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
  50. * Disabled
  51. * </md-checkbox>
  52. *
  53. * </hljs>
  54. *
  55. */
  56. function MdCheckboxDirective(inputDirective, $mdAria, $mdConstant, $mdTheming, $mdUtil, $timeout) {
  57. inputDirective = inputDirective[0];
  58. var CHECKED_CSS = 'md-checked';
  59. return {
  60. restrict: 'E',
  61. transclude: true,
  62. require: '?ngModel',
  63. priority: 210, // Run before ngAria
  64. template:
  65. '<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
  66. '<div class="md-icon"></div>' +
  67. '</div>' +
  68. '<div ng-transclude class="md-label"></div>',
  69. compile: compile
  70. };
  71. // **********************************************************
  72. // Private Methods
  73. // **********************************************************
  74. function compile (tElement, tAttrs) {
  75. tAttrs.type = 'checkbox';
  76. tAttrs.tabindex = tAttrs.tabindex || '0';
  77. tElement.attr('role', tAttrs.type);
  78. // Attach a click handler in compile in order to immediately stop propagation
  79. // (especially for ng-click) when the checkbox is disabled.
  80. tElement.on('click', function(event) {
  81. if (this.hasAttribute('disabled')) {
  82. event.stopImmediatePropagation();
  83. }
  84. });
  85. return function postLink(scope, element, attr, ngModelCtrl) {
  86. ngModelCtrl = ngModelCtrl || $mdUtil.fakeNgModel();
  87. $mdTheming(element);
  88. if (attr.ngChecked) {
  89. scope.$watch(
  90. scope.$eval.bind(scope, attr.ngChecked),
  91. ngModelCtrl.$setViewValue.bind(ngModelCtrl)
  92. );
  93. }
  94. $$watchExpr('ngDisabled', 'tabindex', {
  95. true: '-1',
  96. false: attr.tabindex
  97. });
  98. $mdAria.expectWithText(element, 'aria-label');
  99. // Reuse the original input[type=checkbox] directive from Angular core.
  100. // This is a bit hacky as we need our own event listener and own render
  101. // function.
  102. inputDirective.link.pre(scope, {
  103. on: angular.noop,
  104. 0: {}
  105. }, attr, [ngModelCtrl]);
  106. scope.mouseActive = false;
  107. element.on('click', listener)
  108. .on('keypress', keypressHandler)
  109. .on('mousedown', function() {
  110. scope.mouseActive = true;
  111. $timeout(function() {
  112. scope.mouseActive = false;
  113. }, 100);
  114. })
  115. .on('focus', function() {
  116. if (scope.mouseActive === false) {
  117. element.addClass('md-focused');
  118. }
  119. })
  120. .on('blur', function() {
  121. element.removeClass('md-focused');
  122. });
  123. ngModelCtrl.$render = render;
  124. function $$watchExpr(expr, htmlAttr, valueOpts) {
  125. if (attr[expr]) {
  126. scope.$watch(attr[expr], function(val) {
  127. if (valueOpts[val]) {
  128. element.attr(htmlAttr, valueOpts[val]);
  129. }
  130. });
  131. }
  132. }
  133. function keypressHandler(ev) {
  134. var keyCode = ev.which || ev.keyCode;
  135. if (keyCode === $mdConstant.KEY_CODE.SPACE || keyCode === $mdConstant.KEY_CODE.ENTER) {
  136. ev.preventDefault();
  137. if (!element.hasClass('md-focused')) {
  138. element.addClass('md-focused');
  139. }
  140. listener(ev);
  141. }
  142. }
  143. function listener(ev) {
  144. if (element[0].hasAttribute('disabled')) {
  145. return;
  146. }
  147. scope.$apply(function() {
  148. // Toggle the checkbox value...
  149. var viewValue = attr.ngChecked ? attr.checked : !ngModelCtrl.$viewValue;
  150. ngModelCtrl.$setViewValue( viewValue, ev && ev.type);
  151. ngModelCtrl.$render();
  152. });
  153. }
  154. function render() {
  155. if(ngModelCtrl.$viewValue) {
  156. element.addClass(CHECKED_CSS);
  157. } else {
  158. element.removeClass(CHECKED_CSS);
  159. }
  160. }
  161. };
  162. }
  163. }
  164. MdCheckboxDirective.$inject = ["inputDirective", "$mdAria", "$mdConstant", "$mdTheming", "$mdUtil", "$timeout"];
  165. ng.material.components.checkbox = angular.module("material.components.checkbox");