この記事は、株式会社Y's アドベントカレンダー23日目の記事になります。
##はじめに
これはJqueryとJquery UIのみ使用可の案件に途中から入り、カレンダーをいい感じにしたときのお話である。
ちなみに今までにJquery UIは使ったことはないです。
##そもそもjqueryUIとかdatepickerって?
ライブラリです。機能がいっぱいあります。
datepickerはその中のカレンダー機能みたいな感じです。ふわふわした説明ですみません…
##まずは現状
jqueryUIのdatepickerを使用してカレンダーが作られている
##やりたいこと
某旅行会社とかみたいに、選択期間が塗りつぶされるようにしたい
期間が選択されていると塗りつぶされる
どう対応したか
まず塗りつぶす用のスタイルを作成
#ui-datepicker-div .ui-state-select {
border: 1px solid #003eff;
background: #87bdf3;
font-weight: normal;
color: #fff;
}
次はそのクラスをカレンダーに当てる
focusイベントで上記のクラス付与してみる
特に条件指定してないんで普通に付与できればすべての日付の部分が水色で染まるはず
$(document).on('focus', 'input', function () {
$('.ui-state-default').addClass('ui-state-select');
});
イベント発生時にDOMが生成されていないので当たらない
じゃあDelayさせてみる
$(document).on('focus', 'input', function () {
setTimeout(function () {
$('.ui-state-default').addClass('ui-state-select');
}, 100);
});
当たるっちゃ当たる
けど生成とイベント発生に時間差があるので表示時に微妙にチラついて気持ち悪い
じゃあDOM生成と同じタイミングでクラス当てればいいのでは???
ということで
ライブラリいじりました
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
tempDate = new Date(),
today = this._daylightSavingAdjust(
new Date(tempDate.getFullYear(), tempDate.getMonth(),tempDate.getDate())), // clear time
isRTL = this._get(inst, "isRTL"),
showButtonPanel = this._get(inst, "showButtonPanel"),
hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
numMonths = this._getNumberOfMonths(inst),
showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
stepMonths = this._get(inst, "stepMonths"),
isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
minDate = this._getMinMaxDate(inst, "min"),
maxDate = this._getMinMaxDate(inst, "max"),
drawMonth = inst.drawMonth - showCurrentAtPos,
drawYear = inst.drawYear;
/* user change */
var startDate = $('#start-date').val(),
endDate = $('#end-date').val(),
startSel = false;
if (startDate && endDate) {
startSel = true;
var startDate = new Date(startDate),
endDate = new Date(endDate);
}
/* user change */以降が追加した処理
datepickerで使用する変数沢山宣言してるところに追加で
開始日と終了日がどちらも入力されているとフラグtrue
開始日と終了日のDateインスタンスを作成
for (dow = 0; dow < 7; dow++) { // create date picker days
daySettings = (beforeShowDay ?
beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
otherMonth = (printDate.getMonth() !== drawMonth);
unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
tbody += "<td class='" +
((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
// or defaultDate is current printedDate and defaultDate is selectedDate
" " + this._dayOverClass : "") + // highlight selected day
(unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "") + // highlight unselectable days
(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
(otherMonth && !showOtherMonths ? " " : // display for other months
(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
/* user change */
(startSel && startDate.getTime() <= printDate.getTime() && printDate.getTime() <= endDate.getTime() ? " ui-state-select" : "") +
(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
printDate.setDate(printDate.getDate() + 1);
printDate = this._daylightSavingAdjust(printDate);
}
カレンダーのを生成している部分に
(// create date picker daysって書いてあるので分かりやすいですね)
先程のフラグがtrueであれば開始日〜終了日にクラス付与
という処理を記載
##結果
できたー
カレンダーを作成しながらクラスを付与しているので時間の差分によるチラつきとかもない
##おわりに
あとでJquery UIのリファレンスをじっくり読んだ結果、
__beforeShowDay__というDOMの生成前にパラメータを渡せる素晴らしい関数が用意されていました (ライブラリいじる必要なかった…!)
ただ、ライブラリの中身を読んで内容をなんとなく理解して処理を足すというのは個人的に新鮮で、今後どこかで活かせるのではと思いました。
明日は@Larry_rahaiさんの記事です!乞うご期待!!!