date_year_range.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. (function ($) {
  2. Drupal.behaviors.dateYearRange = {};
  3. Drupal.behaviors.dateYearRange.attach = function (context, settings) {
  4. var $textfield, $textfields, i;
  5. // Turn the years back and forward fieldsets into dropdowns.
  6. $textfields = $('input.select-list-with-custom-option', context).once('date-year-range');
  7. for (i = 0; i < $textfields.length; i++) {
  8. $textfield = $($textfields[i]);
  9. new Drupal.dateYearRange.SelectListWithCustomOption($textfield);
  10. }
  11. };
  12. Drupal.dateYearRange = {};
  13. /**
  14. * Constructor for the SelectListWithCustomOption object.
  15. *
  16. * This object is responsible for turning the years back and forward textfields
  17. * into dropdowns with an 'other' option that lets the user enter a custom
  18. * value.
  19. */
  20. Drupal.dateYearRange.SelectListWithCustomOption = function ($textfield) {
  21. this.$textfield = $textfield;
  22. this.$description = $textfield.next('div.description');
  23. this.defaultValue = $textfield.val();
  24. this.$dropdown = this.createDropdown();
  25. this.$dropdown.insertBefore($textfield);
  26. };
  27. /**
  28. * Get the value of the textfield as it existed on page load.
  29. *
  30. * @param {String} type
  31. * The type of the variable to be returned. Defaults to string.
  32. * @return
  33. * The original value of the textfield. Returned as an integer, if the type
  34. * parameter was 'int'.
  35. */
  36. Drupal.dateYearRange.SelectListWithCustomOption.prototype.getOriginal = function (type) {
  37. var original;
  38. if (type === 'int') {
  39. original = parseInt(this.defaultValue, 10);
  40. if (window.isNaN(original)) {
  41. original = 0;
  42. }
  43. }
  44. else {
  45. original = this.defaultValue;
  46. }
  47. return original;
  48. };
  49. /**
  50. * Get the correct first value for the dropdown.
  51. */
  52. Drupal.dateYearRange.SelectListWithCustomOption.prototype.getStartValue = function () {
  53. var direction = this.getDirection();
  54. var start;
  55. switch (direction) {
  56. case 'back':
  57. // For the 'years back' dropdown, the first option should be -10, unless
  58. // the default value of the textfield is even smaller than that.
  59. start = Math.min(this.getOriginal('int'), -10);
  60. break;
  61. case 'forward':
  62. start = 0;
  63. break;
  64. }
  65. return start;
  66. };
  67. /**
  68. * Get the correct last value for the dropdown.
  69. */
  70. Drupal.dateYearRange.SelectListWithCustomOption.prototype.getEndValue = function () {
  71. var direction = this.getDirection();
  72. var end;
  73. var originalString = this.getOriginal();
  74. switch (direction) {
  75. case 'back':
  76. end = 0;
  77. break;
  78. case 'forward':
  79. // If the original value of the textfield is an absolute year such as
  80. // 2020, don't try to include it in the dropdown.
  81. if (originalString.indexOf('+') === -1) {
  82. end = 10;
  83. }
  84. // If the original value is a relative value (+x), we want it to be
  85. // included in the possible dropdown values.
  86. else {
  87. end = Math.max(this.getOriginal('int'), 10);
  88. }
  89. break;
  90. }
  91. return end;
  92. };
  93. /**
  94. * Create a dropdown select list with the correct options for this textfield.
  95. */
  96. Drupal.dateYearRange.SelectListWithCustomOption.prototype.createDropdown = function () {
  97. var $dropdown = $('<select>').addClass('form-select date-year-range-select');
  98. var $option, i, value;
  99. var start = this.getStartValue();
  100. var end = this.getEndValue();
  101. var direction = this.getDirection();
  102. for (i = start; i <= end; i++) {
  103. // Make sure we include the +/- sign in the option value.
  104. value = i;
  105. if (i > 0) {
  106. value = '+' + i;
  107. }
  108. // Zero values must have a + or - in front.
  109. if (i === 0) {
  110. if (direction === 'back') {
  111. value = '-' + i;
  112. }
  113. else {
  114. value = '+' + i;
  115. }
  116. }
  117. $option = $('<option>' + Drupal.formatPlural(value, '@count year from now', '@count years from now') + '</option>').val(value);
  118. $dropdown.append($option);
  119. }
  120. // Create an 'Other' option.
  121. $option = $('<option class="custom-option">' + Drupal.t('Other') + '</option>').val('');
  122. $dropdown.append($option);
  123. // When the user changes the selected option in the dropdown, perform
  124. // appropriate actions (such as showing or hiding the textfield).
  125. $dropdown.bind('change', $.proxy(this.handleDropdownChange, this));
  126. // Set the initial value of the dropdown.
  127. this._setInitialDropdownValue($dropdown);
  128. return $dropdown;
  129. };
  130. Drupal.dateYearRange.SelectListWithCustomOption.prototype._setInitialDropdownValue = function ($dropdown) {
  131. var textfieldValue = this.getOriginal();
  132. // Determine whether the original textfield value exists in the dropdown.
  133. var possible = $dropdown.find('option[value="' + textfieldValue + '"]');
  134. // If the original textfield value is one of the dropdown options, preselect
  135. // it and hide the 'other' textfield.
  136. if (possible.length) {
  137. $dropdown.val(textfieldValue);
  138. this.hideTextfield();
  139. }
  140. // If the original textfield value isn't one of the dropdown options, choose
  141. // the 'Other' option in the dropdown.
  142. else {
  143. $dropdown.val('');
  144. }
  145. };
  146. /**
  147. * Determine whether this is the "years back" or "years forward" textfield.
  148. */
  149. Drupal.dateYearRange.SelectListWithCustomOption.prototype.getDirection = function () {
  150. if (this.direction) {
  151. return this.direction;
  152. }
  153. var direction;
  154. if (this.$textfield.hasClass('back')) {
  155. direction = 'back';
  156. }
  157. else if (this.$textfield.hasClass('forward')) {
  158. direction = 'forward';
  159. }
  160. this.direction = direction;
  161. return direction;
  162. };
  163. /**
  164. * Change handler for the dropdown, to modify the textfield as appropriate.
  165. */
  166. Drupal.dateYearRange.SelectListWithCustomOption.prototype.handleDropdownChange = function () {
  167. // Since the dropdown changed, we need to make the content of the textfield
  168. // match the (new) selected option.
  169. this.syncTextfield();
  170. // Show the textfield if the 'Other' option was selected, and hide it if one
  171. // of the preset options was selected.
  172. if ($(':selected', this.$dropdown).hasClass('custom-option')) {
  173. this.revealTextfield();
  174. }
  175. else {
  176. this.hideTextfield();
  177. }
  178. };
  179. /**
  180. * Display the textfield and its description.
  181. */
  182. Drupal.dateYearRange.SelectListWithCustomOption.prototype.revealTextfield = function () {
  183. this.$textfield.show();
  184. this.$description.show();
  185. };
  186. /**
  187. * Hide the textfield and its description.
  188. */
  189. Drupal.dateYearRange.SelectListWithCustomOption.prototype.hideTextfield = function () {
  190. this.$textfield.hide();
  191. this.$description.hide();
  192. };
  193. /**
  194. * Copy the selected value of the dropdown to the textfield.
  195. *
  196. * FAPI doesn't know about the JS-only dropdown, so the textfield needs to
  197. * reflect the value of the dropdown.
  198. */
  199. Drupal.dateYearRange.SelectListWithCustomOption.prototype.syncTextfield = function () {
  200. var value = this.$dropdown.val();
  201. this.$textfield.val(value);
  202. };
  203. })(jQuery);