Guest User

Untitled

a guest
Oct 15th, 2018
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.65 KB | None | 0 0
  1. /*
  2. * file: bootstrap-datetime.js
  3. * author: Joe Savona
  4. *
  5. * 日時入力 Datetime Input
  6.  
  7. <input type="datetime" class="datetime" value="2012-04-01 14:33:59">
  8.  
  9. <div class="datetime-input modal hide">
  10. <div class="modal-header">
  11. <a class="close" data-dismiss="modal" title="キャンセル">×</a>
  12. <h3>日時入力</h3>
  13. </div>
  14. <div class="modal-body">
  15. <table class="table table-bordered x-table-condensed datetime-date">
  16. <thead>
  17. <tr>
  18. <th class="prev"><a href="#" class="datetime-prev" title="前の月へ"><i class="icon-arrow-left"></i></a></th>
  19. <th class="year-month" colspan="5"><a href="#" title="年月の選択" class="btn datetime-yyyymm-label">2012年4月</a>
  20. <span class="datetime-yyyymm-input">
  21. <input type="text" size="4" name="year" value="2012">
  22. <input type="text" size="2" name="month" value="4">
  23. <a href="#" class="btn datetime-yyyymm-save">年月へ飛ぶ</a>
  24. </span>
  25. </th>
  26. <th class="next"><a href="#" class="datetime-next" title="次の月へ"><i class="icon-arrow-right"></i></a></th>
  27. </tr>
  28. <tr>
  29. <th class="day">日</th>
  30. <th class="day">月</th>
  31. <th class="day">火</th>
  32. <th class="day">水</th>
  33. <th class="day">木</th>
  34. <th class="day">金</th>
  35. <th class="day">土</th>
  36. </tr>
  37. </thead>
  38. <tbody>
  39. </tbody>
  40. </table>
  41. <table class="table table-bordered x-table-condensed datetime-time">
  42. <thead>
  43. <tr>
  44. <th>時</th>
  45. <th>分</th>
  46. </tr>
  47. </thead>
  48. <tbody>
  49. <tr>
  50. <td><select name="hour">
  51. <option value="10">10時</option>
  52. <option value="11">11時</option>
  53. <option value="12">12時</option>
  54. <option value="13">13時</option>
  55. <option value="14">14時</option>
  56. <option value="15">15時</option>
  57. <option value="16">16時</option>
  58. </select></td>
  59. <td><select name="minute">
  60. <option value="00">0分</option>
  61. <option value="30">30分</option>
  62. </select></td>
  63. </tr>
  64. </tbody>
  65. </table>
  66. </div>
  67. <div class="modal-footer">
  68. <p class="pull-left">
  69. <a href="#" class="btn datetime-now">現在の日時</a>
  70. </p>
  71. <a href="#" class="btn btn-primary datetime-close">保存する</a>
  72. </div>
  73. </div><!--/datetime-input-->
  74. */
  75. (function($) {
  76. var DatetimeInput;
  77.  
  78. DatetimeInput = function($el) {
  79. this.initialize($el);
  80. $.fn.hoverpanel.Constructor.prototype.initialize($el, false);
  81. }
  82.  
  83. DatetimeInput.html = '<div class="datetime-input hoverpanel hide"> <div class="hoverpanel-header"> <a class="close" data-dismiss="hoverpanel" title="キャンセル">×</a> <h3>日時入力</h3> </div> <div class="hoverpanel-body"> <table class="table table-bordered x-table-condensed datetime-date"> <thead> <tr> <th class="prev"><a href="#" class="datetime-prev" title="前の月へ"><i class="icon-arrow-left"></i></a></th> <th class="year-month" colspan="5"><a href="#" title="年月の選択" class="btn datetime-yyyymm-label">2012年4月</a> <span class="datetime-yyyymm-input"> <input type="text" size="4" name="year" value="2012"> <input type="text" size="2" name="month" value="4"> <a href="#" class="btn datetime-yyyymm-save">年月へ飛ぶ</a> </span> </th> <th class="next"><a href="#" class="datetime-next" title="次の月へ"><i class="icon-arrow-right"></i></a></th> </tr> <tr> <th class="day">日</th> <th class="day">月</th> <th class="day">火</th> <th class="day">水</th> <th class="day">木</th> <th class="day">金</th> <th class="day">土</th> </tr> </thead> <tbody> </tbody> </table> <table class="table datetime-time"> <thead> <tr> <th>時</th> <th>分</th> </tr> </thead> <tbody> <tr> <td><select name="hour"> <option value="10">10時</option> <option value="11">11時</option> <option value="12">12時</option> <option value="13">13時</option> <option value="14">14時</option> <option value="15">15時</option> <option value="16">16時</option> </select></td> <td><select name="minute"> <option value="00">0分</option> <option value="30">30分</option> </select></td> </tr> </tbody> </table> </div> <div class="hoverpanel-footer"> <p class="pull-left"> <a href="#" class="btn datetime-now"><i class="icon-time"></i> 現在の日時</a> </p> <a href="#" class="btn btn-primary datetime-close"><i class="icon-ok-sign icon-white"></i> 保存する</a> </div> </div>';
  84.  
  85. DatetimeInput.instance = null;
  86.  
  87. DatetimeInput.FORMAT_DATA_ATTR = 'datetime-format';
  88. DatetimeInput.FORMAT_DATETIME = 'datetime';
  89. DatetimeInput.FORMAT_DATE = 'date';
  90. DatetimeInput.HOUR_MINUTE_OPTIONS_ALL = 'all';
  91. DatetimeInput.DEFAULT_HOUR_OPTIONS = ['08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18'];
  92. DatetimeInput.DEFAULT_MINUTE_OPTIONS = ['00', '30'];
  93.  
  94. DatetimeInput.datetimeFormat = /^\s*(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\s*$/;
  95. DatetimeInput.dateFormat = /^\s*(\d{4})-(\d{2})-(\d{2})\s*$/;
  96.  
  97. DatetimeInput.millisecondsInWeek = 1000 * 60 * 60 * 24 * 7; //1000 ms/sec, 60 secs/min, 60 mins/hr, 24 hrs/day, 7 days/wk
  98.  
  99. DatetimeInput.getInstance = function() {
  100. var $base;
  101. if (DatetimeInput.instance === null) {
  102. $base = $(DatetimeInput.html);
  103. DatetimeInput.instance = new DatetimeInput($base);
  104. }
  105. return DatetimeInput.instance;
  106. }
  107.  
  108. DatetimeInput.formatDateStr = function(date) {
  109. var dateParts = [date.getFullYear(), date.getMonth()+1, date.getDate()],
  110. index,
  111. part;
  112. for (index = 0; index < dateParts.length; index++) {
  113. part = ''+dateParts[index];
  114. if (part.length < 2) {
  115. part = '0' + part;
  116. }
  117. dateParts[index] = part;
  118. }
  119. return dateParts[0] + '-' + dateParts[1] + '-' + dateParts[2];
  120. }
  121.  
  122. DatetimeInput.formatDatetimeStr = function(date) {
  123. var dateParts = [date.getFullYear(), date.getMonth()+1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()],
  124. index,
  125. part;
  126. for (index = 0; index < dateParts.length; index++) {
  127. part = ''+dateParts[index];
  128. if (part.length < 2) {
  129. part = '0' + part;
  130. }
  131. dateParts[index] = part;
  132. }
  133. return dateParts[0] + '-' + dateParts[1] + '-' + dateParts[2] + ' ' + dateParts[3] + ':' + dateParts[4] + ':' + dateParts[5];
  134. }
  135.  
  136. DatetimeInput.formatDateLabel = function(date) {
  137. return date.getFullYear() + '年' + (date.getMonth()+1) + '月';
  138. }
  139.  
  140. DatetimeInput.prototype = $.extend({}, $.fn.hoverpanel.Constructor.prototype, {
  141. constructor: DatetimeInput
  142.  
  143. , initialize: function($el) {
  144. var bindAllMethods;
  145. this.$el = $el;
  146. this.$inputYear = this.$el.find('.datetime-yyyymm-input [name=year]');
  147. this.$inputMonth = this.$el.find('.datetime-yyyymm-input [name=month]');
  148. this.$inputHour = this.$el.find('.datetime-time [name=hour]');
  149. this.$inputMinute = this.$el.find('.datetime-time [name=minute]');
  150. this.$yearMonthLabel = this.$el.find('.datetime-yyyymm-label');
  151. this.$currentInput = null;
  152. this.activeDate = null;
  153. this.bound = false;
  154.  
  155. console.log('binding methods');
  156. bindAllMethods = 'openYearMonth saveYearMonth goPreviousMonth goNextMonth goNow close calendarChoice updateTime'.split(' ');
  157. bindAllMethods.unshift(this);
  158. _.bindAll.apply(_, bindAllMethods);
  159. }
  160.  
  161. , init: function() {
  162. if (this.bound) {
  163. return;
  164. }
  165. this.bound = true;
  166. this.$el.on('click.dt', '.datetime-yyyymm-label', this.openYearMonth);
  167. this.$el.on('click.dt', '.datetime-yyyymm-save', this.saveYearMonth);
  168. this.$el.on('click.dt', '.datetime-prev', this.goPreviousMonth);
  169. this.$el.on('click.dt', '.datetime-next', this.goNextMonth);
  170. this.$el.on('click.dt', '.datetime-now', this.goNow);
  171. this.$el.on('click.dt', '.datetime-close', this.close);
  172. this.$el.on('click.dt', '.datetime-date td a', this.calendarChoice);
  173. this.$inputHour.on('change.dt blur.dt', this.updateTime);
  174. this.$inputMinute.on('change.dt blur.dt', this.updateTime);
  175. }
  176.  
  177. , openYearMonth: function() {
  178. this.$el
  179. .find('.datetime-date').addClass('datetime-yyyymm-on')
  180. .find('.datetime-yyyymm-input input:first').focus();
  181. return false;
  182. }
  183.  
  184. , saveYearMonth: function() {
  185. var year = parseInt(this.$inputYear.val(), 10),
  186. month = parseInt(this.$inputMonth.val(), 10);
  187. if (isNaN(year) || isNaN(month) || year < 2000 || year > 2050 || month < 0 || month >= 12) {
  188. this.$inputYear.val(this.activeDate.getFullYear());
  189. this.$inputMonth.val(this.activeDate.getMonth()+1);
  190. } else {
  191. month -= 1;
  192. this.goDate(new Date(year, month, 1));
  193. }
  194. this.$el.find('.datetime-date').removeClass('datetime-yyyymm-on');
  195. }
  196.  
  197. , calendarChoice: function(e) {
  198. var date = $(e.target).data('date');
  199. date = this._parseDate(date);
  200. if (date === null) {
  201. return;
  202. }
  203. this.goDate(date);
  204. this.close();
  205. }
  206.  
  207. , updateTime: function() {
  208. var date = this.activeDate,
  209. hour = parseInt(this.$inputHour.val(), 10),
  210. minute = parseInt(this.$inputMinute.val(), 10);
  211. if (isNaN(hour) || isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
  212. return;
  213. }
  214. this.activeDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour, minute, 0);
  215. }
  216.  
  217. , setTime: function(date) {
  218. var $matchingItem;
  219.  
  220. $matchingItem = this.$inputHour.find('option[value=' + date.getHours() + ']');
  221. if ($matchingItem.size()) {
  222. $matchingItem.prop('selected', true);
  223. } else {
  224. $matchingItem = this.$inputHour.find('option:first');
  225. if ($matchingItem.size() && parseInt($matchingItem.attr('value'),10) > date.getHours()) {
  226. $matchingItem.prop('selected');
  227. } else {
  228. $matchingItem = this.$inputHour.find('option:last').prop('selected', true);
  229. }
  230. }
  231.  
  232. $matchingItem = this.$inputMinute.find('option[value=' + date.getMinutes() + ']');
  233. if ($matchingItem.size()) {
  234. $matchingItem.prop('selected', true);
  235. } else {
  236. this.$inputMinute.find('option').each(function() {
  237. var $option = $(this);
  238. if (parseInt($option.attr('value'), 10) < date.getMinutes()) {
  239. $option.prop('selected', true);
  240. }
  241. });
  242. }
  243. }
  244.  
  245. , goPreviousMonth: function() {
  246. console.log('goPreviousMonth before', this.activeDate);
  247. this.goDate(new Date(this.activeDate.getFullYear(), this.activeDate.getMonth() - 1, 1));
  248. console.log('goPreviousMonth after', this.activeDate);
  249. return false;
  250. }
  251.  
  252. , goNextMonth: function() {
  253. console.log('goNextMonth before', this.activeDate);
  254. this.goDate(new Date(this.activeDate.getFullYear(), this.activeDate.getMonth() + 1, 1));
  255. console.log('goNextMonth after', this.activeDate);
  256. return false;
  257. }
  258.  
  259. , goNow: function() {
  260. var date = new Date();
  261. this.setTime(date);
  262. this.goDate(date);
  263. return false;
  264. }
  265.  
  266. , goDate: function(date) {
  267. var startOfMonth = new Date(date.getFullYear(), date.getMonth(), 1),
  268. firstSunday = new Date(startOfMonth.getFullYear(), startOfMonth.getMonth(), startOfMonth.getDate() - startOfMonth.getDay()),
  269. endOfMonth = new Date(startOfMonth.getFullYear(), startOfMonth.getMonth()+1, 0),
  270. lastSaturday = new Date(endOfMonth.getFullYear(), endOfMonth.getMonth(), endOfMonth.getDate() + (6 - endOfMonth.getDay())),
  271. currentDate,
  272. currentDateClass,
  273. bodyHtml = '',
  274. weekCount = Math.ceil((lastSaturday - firstSunday) / DatetimeInput.millisecondsInWeek),
  275. currentWeekIndex = 0,
  276. currentDayIndex = 0;
  277. this.activeDate = date;
  278. this.updateTime();
  279. this.$yearMonthLabel.text(DatetimeInput.formatDateLabel(this.activeDate));
  280.  
  281. this.setTime(date);
  282.  
  283. while (currentWeekIndex < weekCount) {
  284. currentDayIndex = 0;
  285. bodyHtml += '<tr>';
  286. while (currentDayIndex < 7) {
  287. currentDate = new Date(firstSunday.getFullYear(), firstSunday.getMonth(), firstSunday.getDate() + (currentWeekIndex * 7) + currentDayIndex);
  288. currentDateClass = (currentDate.getMonth() !== date.getMonth() ? 'inactive' : (currentDate.getDate() !== date.getDate() ? 'active' : 'selected'));
  289. bodyHtml += '<td class="' + currentDateClass + '"><a data-date="' + this._formatDate(currentDate) + '">' + currentDate.getDate() + '</a></td>';
  290. currentDayIndex += 1;
  291. }
  292. bodyHtml += '</tr>';
  293. currentWeekIndex += 1;
  294. }
  295. this.$el.find('.datetime-date tbody').html(bodyHtml);
  296. return false;
  297. }
  298.  
  299. , _formatDate: function(date) {
  300. if (this._isDateInput()) {
  301. return DatetimeInput.formatDateStr(date);
  302. } else {
  303. return DatetimeInput.formatDatetimeStr(date);
  304. }
  305. }
  306.  
  307. , _parseDate: function(dateStr) {
  308. var match,
  309. date,
  310. index,
  311. datetimeMatchCount = 7;
  312. if (this._isDateInput()) {
  313. match = DatetimeInput.dateFormat.exec(dateStr);
  314. } else {
  315. match = DatetimeInput.datetimeFormat.exec(dateStr);
  316. }
  317. if (match) {
  318. for (index = 0; index < datetimeMatchCount; index++) {
  319. match[index] = match.length > index ? parseInt(match[index], 10) : 0;
  320. }
  321. return new Date(match[1], match[2]-1, match[3], match[4], match[5], match[6]);
  322. }
  323. return null;
  324. }
  325.  
  326. , _parseTimeOptions: function($input) {
  327. var hoursOptions,
  328. minuteOptions,
  329. optionIndex,
  330. self;
  331. self = this;
  332. // 何時の選択肢
  333. // data-datetime-hours="10,11,12,13,14,15,16,17,18"
  334. hoursOptions = $input.data('datetime-hours') || DatetimeInput.DEFAULT_HOUR_OPTIONS;
  335. if (hoursOptions === DatetimeInput.HOUR_MINUTE_OPTIONS_ALL) {
  336. hoursOptions = [];
  337. for (optionIndex = 0; optionIndex < 24; optionIndex++) {
  338. hoursOptions.push(optionIndex < 10 ? '0' + optionIndex : '' + optionIndex);
  339. }
  340. }
  341. if (typeof hoursOptions === 'string') {
  342. hoursOptions = hoursOptions.split(',');
  343. }
  344. this.$hourInput = this.$el.find('[name=hour]');
  345. this.$hourInput.empty();
  346. $.each(hoursOptions, function(index, item) {
  347. self.$hourInput.append($('<option></option').attr('value', item).text(item + '時'));
  348. });
  349.  
  350. // 何分の選択肢
  351. // date-datetime-minutes="00,15,30,45"
  352. minuteOptions = $input.data('datetime-minutes') || DatetimeInput.DEFAULT_MINUTE_OPTIONS;
  353. if (minuteOptions === DatetimeInput.HOUR_MINUTE_OPTIONS_ALL) {
  354. minuteOptions = [];
  355. for (optionIndex = 0; optionIndex < 60; optionIndex++) {
  356. minuteOptions.push(optionIndex < 10 ? '0' + optionIndex : '' + optionIndex);
  357. }
  358. }
  359. if (typeof minuteOptions === 'string') {
  360. minuteOptions = minuteOptions.split(',');
  361. }
  362. this.$minuteInput = this.$el.find('[name=minute]');
  363. this.$minuteInput.empty();
  364. $.each(minuteOptions, function(index, item) {
  365. self.$minuteInput.append($('<option></option>').attr('value', item).text(item + '分'));
  366. });
  367. }
  368.  
  369. , _isDatetimeInput: function() {
  370. return this.$currentInput.data(DatetimeInput.FORMAT_DATA_ATTR) !== DatetimeInput.FORMAT_DATE;
  371. }
  372.  
  373. , _isDateInput: function() {
  374. return this.$currentInput.data(DatetimeInput.FORMAT_DATA_ATTR) === DatetimeInput.FORMAT_DATE;
  375. }
  376.  
  377. , close: function() {
  378. this.$currentInput.val(this._formatDate(this.activeDate));
  379. this.$currentInput.trigger('change');
  380. this.activeDate = null;
  381. this.$currentInput = null;
  382. $.fn.hoverpanel.Constructor.prototype.close.call(this);
  383. }
  384.  
  385. , openFor: function($input) {
  386. var date;
  387. this.$currentInput = $input;
  388.  
  389. // インプットから日時を取得する。空である場合は現在日時にする
  390. date = this._parseDate($input.val());
  391. if (date === null) {
  392. date = new Date();
  393. }
  394.  
  395. this._parseTimeOptions($input);
  396.  
  397. // インプット・日時を設定したうえで、UIを初期させる
  398. this.init();
  399. this._isDatetimeInput() ? this.$el.find('.datetime-time').show() : this.$el.find('.datetime-time').hide();
  400. this.setTime(date);
  401. this.goDate(date);
  402. $.fn.hoverpanel.Constructor.prototype.open.call(this, $input);
  403. }
  404. });
  405.  
  406. $.DatetimeInput = DatetimeInput;
  407.  
  408. $(function() {
  409. $('body').on('click', 'input.datetime', function() {
  410. var datetime = DatetimeInput.getInstance();
  411. datetime.openFor($(this));
  412. });
  413. });
  414.  
  415. })(jQuery);
Add Comment
Please, Sign In to add comment