yearpicker.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. const version = "1.1.0";
  2. const namespace = "yearpicker";
  3. if (!jQuery) {
  4. alert(`${namespace} ${version} requires jQuery`);
  5. }
  6. let defaults = {
  7. // The Initial Date
  8. year: null,
  9. // Start Date
  10. startYear: null,
  11. // End Date
  12. endYear: null,
  13. // A element tag items
  14. itemTag: "li",
  15. //css class selected date item
  16. selectedClass: "selected",
  17. // css class disabled
  18. disabledClass: "disabled",
  19. hideClass: "hide",
  20. template: `<div class="yearpicker-container">
  21. <div class="yearpicker-header">
  22. <div class="yearpicker-prev" data-view="yearpicker-prev">&lsaquo;</div>
  23. <div class="yearpicker-current" data-view="yearpicker-current">SelectedYear</div>
  24. <div class="yearpicker-next" data-view="yearpicker-next">&rsaquo;</div>
  25. </div>
  26. <div class="yearpicker-body">
  27. <ul class="yearpicker-year" data-view="years">
  28. </ul>
  29. </div>
  30. </div>
  31. `,
  32. // Event shortcuts
  33. onShow: null,
  34. onHide: null,
  35. onChange: null,
  36. };
  37. const event_click = "click.";
  38. const event_focus = "focus.";
  39. const event_keyup = "keyup.";
  40. const event_selected = "selected.";
  41. const event_show = "show.";
  42. const event_hide = "hide.";
  43. const methods = {
  44. // Show datepicker
  45. showView: function showView() {
  46. const $this = this;
  47. if (!$this.build) {
  48. $this.init();
  49. }
  50. if ($this.show) {
  51. return;
  52. }
  53. $this.show = true;
  54. const $template = $this.$template,
  55. options = $this.options;
  56. $template
  57. .removeClass(options.hideClass)
  58. .on(event_click, $.proxy($this.click, $this));
  59. $(document).on(
  60. event_click,
  61. (this.onGlobalClick = $.proxy($this.globalClick, $this))
  62. );
  63. if (options.onShow && $.isFunction(options.onShow)) {
  64. options.onShow($this.year);
  65. }
  66. },
  67. // Hide the datepicker
  68. hideView: function hideView() {
  69. const $this = this;
  70. if (!$this.show) {
  71. return;
  72. }
  73. // if ($this.trigger(event_hide).isDefaultPrevented()) {
  74. // return;
  75. // }
  76. const $template = $this.$template,
  77. options = $this.options;
  78. $template.addClass(options.hideClass).off(event_click, $this.click);
  79. $(document).off(event_click, $this.onGlobalClick);
  80. $this.show = false;
  81. if (options.onHide && $.isFunction(options.onHide)) {
  82. options.onHide($this.year);
  83. }
  84. },
  85. // toggle show and hide
  86. toggle: function toggle() {
  87. if (this.show) {
  88. this.hideView();
  89. } else {
  90. this.show();
  91. }
  92. },
  93. };
  94. const handlers = {
  95. click: function click(e) {
  96. const $target = $(e.target),
  97. viewYear = this.viewYear;
  98. if ($target.hasClass("disabled")) {
  99. return;
  100. }
  101. const view = $target.data("view");
  102. switch (view) {
  103. case "yearpicker-prev":
  104. var year = viewYear - 12;
  105. this.viewYear = year;
  106. this.renderYear();
  107. break;
  108. case "yearpicker-next":
  109. var year = viewYear + 12;
  110. this.viewYear = year;
  111. this.renderYear();
  112. break;
  113. case "yearpicker-items":
  114. this.year = parseInt($target.html());
  115. this.renderYear();
  116. this.hideView();
  117. break;
  118. default:
  119. break;
  120. }
  121. },
  122. globalClick: function globalClick(_ref) {
  123. let target = _ref.target;
  124. let element = this.element;
  125. let hidden = true;
  126. if (target !== document) {
  127. while (
  128. target === element ||
  129. $(target).closest(".yearpicker-header").length === 1
  130. ) {
  131. hidden = false;
  132. break;
  133. }
  134. target = target.parentNode;
  135. }
  136. if (hidden) {
  137. this.hideView();
  138. }
  139. },
  140. };
  141. const render = {
  142. renderYear: function renderYear() {
  143. const $this = this,
  144. options = this.options,
  145. startYear = options.startYear,
  146. endYear = options.endYear;
  147. const disabledClass = options.disabledClass,
  148. viewYear = $this.viewYear,
  149. selectedYear = $this.year,
  150. now = new Date(),
  151. thisYear = now.getFullYear(),
  152. start = -5,
  153. end = 6,
  154. items = [];
  155. let prevDisabled = false;
  156. let nextDisabled = false;
  157. let i = void 0;
  158. for (i = start; i <= end; i++) {
  159. let year = viewYear + i;
  160. let disabled = false;
  161. if (startYear) {
  162. disabled = year < startYear;
  163. if (i === start) {
  164. prevDisabled = disabled;
  165. }
  166. }
  167. if (!disabled && endYear) {
  168. disabled = year > endYear;
  169. if (i === end) {
  170. nextDisabled = disabled;
  171. }
  172. }
  173. // check for this is a selected year
  174. const isSelectedYear = year === selectedYear;
  175. const view = isSelectedYear ? "yearpicker-items" : "yearpicker-items";
  176. items.push(
  177. $this.createItem({
  178. selected: isSelectedYear,
  179. disabled: disabled,
  180. text: viewYear + i,
  181. //view: disabled ? "yearpicker disabled" : view,
  182. view: disabled ? "yearpicker-items disabled" : view,
  183. highlighted: year === thisYear,
  184. })
  185. );
  186. }
  187. $this.yearsPrev.toggleClass(disabledClass, prevDisabled);
  188. $this.yearsNext.toggleClass(disabledClass, nextDisabled);
  189. $this.yearsCurrent.html(selectedYear);
  190. $this.yearsBody.html(items.join(" "));
  191. $this.setValue();
  192. },
  193. };
  194. const Yearpicker = (function () {
  195. function YearPicker(element, options) {
  196. const $this = this;
  197. $this.options = $.extend({}, defaults, options);
  198. $this.$element = $(element);
  199. $this.element = element;
  200. $this.build = false;
  201. $this.show = false;
  202. $this.startYear = null;
  203. $this.endYear = null;
  204. $this.$template = $($this.options.template);
  205. $this.init();
  206. }
  207. YearPicker.prototype = {
  208. /**
  209. * constructor
  210. * configure the yearpicker before initialize
  211. * @returns {null}
  212. */
  213. init: function () {
  214. const $this = this,
  215. $element = this.$element,
  216. options = this.options;
  217. if (this.build) {
  218. return;
  219. }
  220. $this.build = true;
  221. const startYear = options.startYear,
  222. endYear = options.endYear,
  223. defaultYear = $this.getValue(),
  224. $template = $this.$template;
  225. let year = options.year;
  226. $this.isInput = $element.is("input") || $element.is("textarea");
  227. $this.initialValue = defaultYear;
  228. $this.oldValue = defaultYear;
  229. const currentYear = new Date().getFullYear();
  230. // set the defaultyear
  231. year = year || defaultYear || null;
  232. // set the startyear
  233. if (startYear) {
  234. if (year && year < startYear) {
  235. year = startYear;
  236. }
  237. $this.startYear = startYear;
  238. }
  239. // set the endyear
  240. if (endYear) {
  241. if (year && year > endYear) {
  242. year = endYear;
  243. }
  244. $this.endYear = endYear;
  245. }
  246. $this.year = year;
  247. $this.viewYear = year || currentYear;
  248. $this.initialYear = year || currentYear;
  249. $this.bind();
  250. $this.yearsPrev = $template.find(".yearpicker-prev");
  251. $this.yearsCurrent = $template.find(".yearpicker-current");
  252. $this.yearsNext = $template.find(".yearpicker-next");
  253. $this.yearsBody = $template.find(".yearpicker-year");
  254. $template.addClass(options.hideClass);
  255. $element.after($template.addClass(namespace + "-dropdown"));
  256. $this.renderYear();
  257. },
  258. // assign a events
  259. bind: function () {
  260. const $this = this,
  261. $element = this.$element,
  262. options = this.options;
  263. if ($.isFunction(options.show)) {
  264. $element.on(event_show, options.show);
  265. }
  266. if ($.isFunction(options.hide)) {
  267. $element.on(event_hide, options.hide);
  268. }
  269. if ($.isFunction(options.click)) {
  270. $element.on(event_click, options.click);
  271. }
  272. if ($this.isInput) {
  273. $element.on(event_focus, $.proxy($this.showView, $this));
  274. } else {
  275. $element.on(event_click, $.proxy($this.showView, $this));
  276. }
  277. },
  278. getValue: function () {
  279. const $this = this,
  280. $element = this.$element;
  281. const value = $this.isInput ? $element.val() : $element.text();
  282. return parseInt(value);
  283. },
  284. setValue: function () {
  285. const $this = this,
  286. $element = this.$element,
  287. options = this.options,
  288. value = this.year;
  289. const previousValue = $this.isInput ? $element.val() : $element.text();
  290. if ($this.isInput) {
  291. $element.val(value);
  292. } else {
  293. $element.html(value);
  294. }
  295. if (previousValue != value) {
  296. if (options.onChange && $.isFunction(options.onChange)) {
  297. options.onChange($this.year);
  298. }
  299. }
  300. $element.trigger("change");
  301. },
  302. trigger: function (type, data) {
  303. data = data || this.year;
  304. const e = $.Event(type, data);
  305. this.$element.trigger(e);
  306. return e;
  307. },
  308. createItem: function (data) {
  309. const options = this.options,
  310. itemTag = options.itemTag,
  311. classes = [];
  312. const items = {
  313. text: "",
  314. view: "",
  315. selected: false,
  316. disabled: false,
  317. highlighted: false,
  318. };
  319. $.extend(items, data);
  320. if (items.selected) {
  321. classes.push(options.selectedClass);
  322. }
  323. if (items.disabled) {
  324. classes.push(options.disabledClass);
  325. }
  326. return `<${itemTag} class="${items.view} ${classes.join(
  327. " "
  328. )}" data-view="${items.view}">${items.text}</${itemTag}>`;
  329. },
  330. };
  331. return YearPicker;
  332. })();
  333. if ($.extend) {
  334. $.extend(Yearpicker.prototype, methods, render, handlers);
  335. }
  336. if ($.fn) {
  337. $.fn.yearpicker = function jQueryYearpicker(options) {
  338. var result = void 0;
  339. this.each(function (index, element) {
  340. var $element = $(element);
  341. var isDestory = options === "destroy";
  342. var yearpicker = $element.data(namespace);
  343. if (!yearpicker) {
  344. if (isDestory) {
  345. return;
  346. }
  347. yearpicker = new Yearpicker(element, options);
  348. $element.data(namespace, yearpicker);
  349. }
  350. if (typeof options === "string") {
  351. var fn = yearpicker[options];
  352. if ($.isFunction(fn)) {
  353. result = fn.apply(yearpicker, args);
  354. if (isDestory) {
  355. $element.removeData(namespace);
  356. }
  357. }
  358. }
  359. });
  360. return !result ? result : this;
  361. };
  362. $.fn.yearpicker.constractor = Yearpicker;
  363. }