289 lines
12 KiB
JavaScript
289 lines
12 KiB
JavaScript
/*
|
||
@config : next999.json
|
||
@filename : ${psFileBasename}
|
||
@title : 2.カレンダー表示
|
||
@name : 2.カレンダー表示
|
||
@siteIds : 310514
|
||
@siteTitles : イオン多摩平シフト希望
|
||
@disabled: false
|
||
*/
|
||
|
||
//カレンダーを生成して挿入する関数
|
||
function renderCalendar(year, month, checkedDates = [], selectedHoursArray = []) {
|
||
$('#custom-calendar-container').remove();
|
||
|
||
let containerHtml = `<div id="custom-calendar-container">`; // メインコンテナ
|
||
|
||
let calendarAndControlsFlexContainer = `<div id="custom-calendar">`; // カレンダーと操作ボタンのFlexコンテナ
|
||
|
||
// カレンダー本体
|
||
let calendarTableHtml = `<div><table border="1"><thead><tr>
|
||
<th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th>
|
||
</tr></thead><tbody><tr>`;
|
||
|
||
let firstDay = new Date(year, month - 1, 1);
|
||
let lastDay = new Date(year, month, 0);
|
||
for (let i = 0; i < firstDay.getDay(); i++) calendarTableHtml += "<td></td>";
|
||
|
||
for (let d = 1; d <= lastDay.getDate(); d++) {
|
||
let dateObj = new Date(year, month - 1, d);
|
||
let dayOfWeek = dateObj.getDay();
|
||
let dateStr = `${year}-${String(month).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
||
let checked = checkedDates.includes(dateStr) ? 'checked' : '';
|
||
calendarTableHtml += `<td><label><input type="checkbox" class="calendar-checkbox" value="${dateStr}" data-day="${dayOfWeek}" ${checked}><br>${d}</label></td>`;
|
||
if ((firstDay.getDay() + d) % 7 === 0 && d !== lastDay.getDate()) calendarTableHtml += "</tr><tr>";
|
||
}
|
||
|
||
let lastDayOfWeek = new Date(year, month - 1, lastDay.getDate()).getDay();
|
||
for (let i = lastDayOfWeek + 1; i <= 6; i++) calendarTableHtml += "<td></td>";
|
||
calendarTableHtml += "</tr></tbody></table></div>"; // カレンダーテーブルの閉じタグ
|
||
calendarAndControlsFlexContainer += calendarTableHtml;
|
||
|
||
|
||
// 操作コントロール(ボタンとタイムバー)のコンテナ
|
||
let controlsContainerHtml = `<div class="controls-container">`;
|
||
|
||
// 一括操作ボタン
|
||
controlsContainerHtml += `
|
||
<div>
|
||
<button type="button" id="calendar-check-all">全てチェック</button>
|
||
<button type="button" id="calendar-uncheck-all">全て解除</button>
|
||
</div>`;
|
||
|
||
// 曜日ボタン
|
||
controlsContainerHtml += `<div class="day-toggle-buttons">
|
||
<button type="button" class="calendar-day-toggle" data-day="1">月</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="2">火</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="3">水</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="4">木</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="5">金</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="6">土</button>
|
||
<button type="button" class="calendar-day-toggle" data-day="0">日</button>
|
||
</div>`;
|
||
|
||
// 時間選択バー
|
||
controlsContainerHtml += `
|
||
<div id="time-selector-container">
|
||
<label>希望時間帯 (10時~21時) - 開始と終了時間を選択:</label>
|
||
<div id="time-bar">`;
|
||
for (let hour = 10; hour <= 21; hour++) {
|
||
controlsContainerHtml += `<div class="time-slot" data-hour="${hour}" style="color: darkblue;">${hour}</div>`;
|
||
}
|
||
controlsContainerHtml += `</div>
|
||
<p>選択された時間: <span id="selected-hours-display">なし</span></p>
|
||
</div>
|
||
`;
|
||
controlsContainerHtml += `</div>`; // controls-container の閉じタグ
|
||
calendarAndControlsFlexContainer += controlsContainerHtml;
|
||
calendarAndControlsFlexContainer += `</div>`; // custom-calendar (Flexコンテナ) の閉じタグ
|
||
containerHtml += calendarAndControlsFlexContainer;
|
||
containerHtml += "</div>"; // custom-calendar-container の閉じタグ
|
||
|
||
$('#SectionFields1Container').after(containerHtml);
|
||
|
||
// ボタンイベント (変更なし)
|
||
$('#calendar-check-all').off('click').on('click', function () {
|
||
$('#custom-calendar .calendar-checkbox').prop('checked', true);
|
||
});
|
||
$('#calendar-uncheck-all').off('click').on('click', function () {
|
||
$('#custom-calendar .calendar-checkbox').prop('checked', false);
|
||
});
|
||
|
||
let dayToggleState = { 0: false, 1: false, 2: false, 3: false, 4: false, 5: false, 6: false };
|
||
|
||
$('.calendar-day-toggle').off('click').on('click', function () {
|
||
const day = $(this).data('day');
|
||
dayToggleState[day] = !dayToggleState[day];
|
||
$('#custom-calendar .calendar-checkbox[data-day="' + day + '"]').prop('checked', dayToggleState[day]);
|
||
if (dayToggleState[day]) {
|
||
$(this).css('background', '#0078d7').css('color', '#fff');
|
||
} else {
|
||
$(this).css('background', '').css('color', '');
|
||
}
|
||
});
|
||
|
||
// 時間選択バーのロジック (変更なし)
|
||
const timeSlots = $('.time-slot');
|
||
const selectedHoursDisplay = $('#selected-hours-display');
|
||
let isDragging = false;
|
||
let selectionStartHour = -1;
|
||
let selectionEndHour = -1;
|
||
|
||
if (selectedHoursArray && selectedHoursArray.length > 0) {
|
||
if (selectedHoursArray.length >= 1) {
|
||
selectionStartHour = Math.min(...selectedHoursArray);
|
||
selectionEndHour = Math.max(...selectedHoursArray);
|
||
updateSelectionVisuals();
|
||
if (selectedHoursArray.length >= 2) {
|
||
selectedHoursDisplay.text(selectedHoursArray.sort((a, b) => a - b).join(','));
|
||
} else {
|
||
selectedHoursDisplay.text('最低2時間選択してください');
|
||
}
|
||
}
|
||
}
|
||
|
||
timeSlots.on('mousedown touchstart', function (e) { // touchstart を追加
|
||
e.preventDefault();
|
||
isDragging = true;
|
||
const currentHour = parseInt($(this).data('hour'));
|
||
selectionStartHour = currentHour;
|
||
selectionEndHour = currentHour;
|
||
updateSelectionVisuals();
|
||
});
|
||
|
||
timeSlots.on('mousemove touchmove', function (e) { // touchmove を追加
|
||
if (isDragging) {
|
||
let pageX;
|
||
if (e.type === 'touchmove') {
|
||
pageX = e.originalEvent.touches[0].pageX;
|
||
} else {
|
||
pageX = e.pageX;
|
||
}
|
||
// マウス/タッチ位置から最も近いスロットを見つける
|
||
let closestSlot = null;
|
||
let minDistance = Infinity;
|
||
timeSlots.each(function () {
|
||
const slot = $(this);
|
||
const slotCenterX = slot.offset().left + slot.width() / 2;
|
||
const distance = Math.abs(pageX - slotCenterX);
|
||
if (distance < minDistance) {
|
||
minDistance = distance;
|
||
closestSlot = slot;
|
||
}
|
||
});
|
||
if (closestSlot) {
|
||
const currentHour = parseInt(closestSlot.data('hour'));
|
||
selectionEndHour = currentHour;
|
||
updateSelectionVisuals();
|
||
}
|
||
}
|
||
});
|
||
|
||
$(document).on('mouseup touchend', function () { // touchend を追加
|
||
if (isDragging) {
|
||
isDragging = false;
|
||
const start = Math.min(selectionStartHour, selectionEndHour);
|
||
const end = Math.max(selectionStartHour, selectionEndHour);
|
||
const selectedCount = (start !== -1 && end !== -1) ? (end - start + 1) : 0;
|
||
|
||
if (selectedCount < 2 && selectedCount > 0) {
|
||
$p.ex.setMyMessage('alert-error new-status-red', '開始時間と終了時間を選択してください');
|
||
timeSlots.css('background-color', '');
|
||
selectedHoursDisplay.text('なし');
|
||
$p.set($('#Results_ClassD'), JSON.stringify([]));
|
||
selectionStartHour = -1;
|
||
selectionEndHour = -1;
|
||
} else if (selectedCount >= 2) {
|
||
$p.clearMessage();
|
||
saveSelectedHoursToField();
|
||
} else {
|
||
$p.clearMessage();
|
||
timeSlots.css('background-color', '');
|
||
selectedHoursDisplay.text('なし');
|
||
$p.set($('#Results_ClassD'), JSON.stringify([]));
|
||
selectionStartHour = -1;
|
||
selectionEndHour = -1;
|
||
}
|
||
}
|
||
});
|
||
|
||
function updateSelectionVisuals() {
|
||
timeSlots.css('background-color', '');
|
||
const start = Math.min(selectionStartHour, selectionEndHour);
|
||
const end = Math.max(selectionStartHour, selectionEndHour);
|
||
|
||
if (start !== -1 && end !== -1) {
|
||
for (let i = start; i <= end; i++) {
|
||
$(`.time-slot[data-hour="${i}"]`).css('background-color', '#a0c4ff');
|
||
}
|
||
}
|
||
}
|
||
|
||
function saveSelectedHoursToField() {
|
||
const selected = [];
|
||
if (selectionStartHour !== -1 && selectionEndHour !== -1) {
|
||
const start = Math.min(selectionStartHour, selectionEndHour);
|
||
const end = Math.max(selectionStartHour, selectionEndHour);
|
||
if ((end - start + 1) >= 2) {
|
||
for (let i = start; i <= end; i++) {
|
||
selected.push(i.toString());
|
||
}
|
||
|
||
selectedHoursDisplay.text(selected.join(',') || 'なし');
|
||
|
||
$p.set($('#Results_ClassD'), JSON.stringify(selected));
|
||
console.log('Selected hours saved to Results_ClassD:', JSON.stringify(selected));
|
||
} else {
|
||
selectedHoursDisplay.text('開始時間と終了時間を選択してください');
|
||
$p.set($('#Results_ClassD'), JSON.stringify([]));
|
||
console.log('Selection less than 2 hours, not saved.');
|
||
}
|
||
} else {
|
||
selectedHoursDisplay.text('なし');
|
||
$p.set($('#Results_ClassD'), JSON.stringify([]));
|
||
}
|
||
}
|
||
}
|
||
|
||
//チェックされた日付を取得する関数 (変更なし)
|
||
function getCheckedDates() {
|
||
return $('.calendar-checkbox:checked').map(function () {
|
||
return this.value;
|
||
}).get();
|
||
}
|
||
|
||
//選択された時間を取得する関数 (Results_ClassDから読み込む)
|
||
function getSelectedHours() {
|
||
const classD = $('#Results_ClassD').val();
|
||
let hoursArray = [];
|
||
if (classD[0] === 'いつでも') {
|
||
hoursArray = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
|
||
} else {
|
||
for (let i = 0; i < classD.length; i++) {
|
||
hoursArray.push(parseFloat(classD[i]));
|
||
}
|
||
|
||
}
|
||
|
||
return hoursArray;
|
||
}
|
||
|
||
/*
|
||
|
||
console.log(hoursString);
|
||
if (hoursString) {
|
||
try {
|
||
const parsedHours = JSON.parse(hoursString);
|
||
if (Array.isArray(parsedHours) && parsedHours.every(h => typeof h === 'number')) {
|
||
return parsedHours;
|
||
}
|
||
} catch (e) {
|
||
console.error("Error parsing selected hours from Results_ClassD:", e);
|
||
if (typeof hoursString === 'string' && hoursString.includes(',')) {
|
||
return hoursString.split(',').map(h => parseInt(h.trim(), 10)).filter(h => !isNaN(h));
|
||
}
|
||
}
|
||
}
|
||
return [];
|
||
}
|
||
*/
|
||
|
||
//年月選択UIとイベント (変更なし)
|
||
function setupCalendarUI(initialYear, initialMonth, checkedDates = [], initialSelectedHoursArray = []) {
|
||
renderCalendar(initialYear, initialMonth, checkedDates, initialSelectedHoursArray);
|
||
|
||
$p.on('change', 'ClassA', function () {
|
||
let y = parseFloat($('#Results_ClassA').val().split('年')[0]);
|
||
let m = parseFloat($('#Results_ClassA').val().split('年')[1].split('月')[0]);
|
||
renderCalendar(y, m, getCheckedDates(), getSelectedHours());
|
||
});
|
||
}
|
||
|
||
function setupCalendar() {
|
||
let initialYear = parseFloat($('#Results_ClassA').val().split('年')[0]);
|
||
let initialMonth = parseFloat($('#Results_ClassA').val().split('年')[1].split('月')[0]);
|
||
let initialCheckedDates = $('#Results_ClassW').val() ? JSON.parse($('#Results_ClassW').val()) : [];
|
||
let initialSelectedHoursArray = getSelectedHours();
|
||
|
||
setupCalendarUI(initialYear, initialMonth, initialCheckedDates, initialSelectedHoursArray);
|
||
} |