freckie

Add: first version

<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<input type="hidden" id="errorCode" value="error-0">
<p>
<strong>교수명</strong>
<input type="text" id="formInputProfName" name="name" value="김가나">
</p>
<p>
<strong>강좌코드</strong>
<input type="text" id="formInputClassCode" name="classcode" value="CEEEE">
</p>
<p>
<strong>강의명</strong>
<input type="text" id="formInputClassName" name='classname' value="공학과경영">
</p>
<p>
<strong>정원</strong>
<input type="number" id="formInputNumPeople" name="num-people" value="1" min="1">
</p>
<p>
<strong>강의실</strong>
<input type="text" id="formInputClassRoom" name="classroom" value="멀303" placeholder="셀을 선택하면 자동으로 입력됩니다." disabled>
</p>
<p>
<strong>선택 시간</strong>
<input type="text" id="formInputTime" name="time" value="" placeholder="셀을 선택하면 자동으로 입력됩니다." disabled>
</p>
<p>
<input type="button" value="제출" id="formSubmitBtn">
</p>
</form>
<?!= HtmlService.createHtmlOutputFromFile('SidebarJS').getContent(); ?>
</body>
</html>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
/**
* Run initializations on sidebar load.
*/
$(function() {
$('#formSubmitBtn').click(submit);
// Assign handler functions to sidebar elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
// Start polling for updates
poll(1000);
});
/**
* Poll a server-side function at the given interval, to have
* results passed to a successHandler callback.
*
* https://stackoverflow.com/a/24773178/1677912
*
* @param {Number} interval (optional) Time in ms between polls.
* Default is 1s (1000ms)
*/
function poll(interval) {
interval = interval || 1000;
//interval = 500;
setTimeout(function() {
google.script.run
.withSuccessHandler(updateFormValues)
.withFailureHandler(function (error) { //To-do! Failuer처리는 어떻게?
var div = document.getElementById('error');
div.innerHTML = "ERROR: " + error.message;
})
.getRange();
}, interval);
};
function validateRange(range, topHeader) {
// domain내의 범위인가 (top header제외)
const top = 2;
const outOfRange = 34;
if (top >= range.row || outOfRange <= range.row)
return {code: "error-04"};
//range column이 left header와 right header사이에 있는가
const leftHeader = 2;
const rightHeader = 35;
if (range.col <= leftHeader || range.col >= rightHeader){ //To-do! 고정값으로 할 것인가, sheet인식해서 값 변동시킬 것인가.
return {code: "error-02"};
}
//range가 1열로 이루어져있는가
if (range.width != 1)
return {code: "error-01"};
// 이미 예약된 항목과 겹치는가 //To-do! 백엔드에서 동시성 제어하도록 전환할 것
for (var i = 0; i < range.height; ++i) {
for (var j = 0; j < range.width; ++j) {
if (range.values[i][j] !== ""){
return {code: "error-05"};
}
}
}
//수용인원을 초과하는가
var lastIdx = topHeader.lastIndexOf("명")
var startIdx = topHeader.lastIndexOf("\n", lastIdx) + 1;
var capacity = parseInt(topHeader.substring(startIdx, lastIdx));
if (capacity < $('input[name=num-people]').val())
return {code: "error-03"};
return {code: ""};
}
// param: rangeInfo -> [{int col, int width, int height}, String topHeader's value (like 전정\n205\n202명)]
function updateFormValues([range, topHeader, date]) {
var ret = validateRange(range, topHeader);
if (ret.code === "") {
var parsed = topHeader.split("\n");
var classroom = parsed[0] + " " + parsed[1];
$('input[name=classroom]').val(classroom);
var start = 9 * 60 + 30 * (range.row - 3);
var stop = start + 30 * range.height;
var startStr = parseInt(start/60).toString() + ":" + ((start%60)<10 ? '0' + (start % 60).toString() : (start % 60).toString());
var stopStr = parseInt(stop/60).toString() + ":" + ((stop%60)<10 ? '0' + (stop % 60).toString() : (stop % 60).toString());
var timeInterval = startStr + "~" + stopStr;
$('input[name=time]').val(date + " " + timeInterval);
$('#errorCode').val(ret.code);
poll(1000);
return;
}
$('input[name=classroom]').val("");
$('input[name=time]').val("");
$('#errorCode').val(ret.code);
poll(1000);
};
function submit() {
// 변수들
var inputValues = {
profName: $('#formInputProfName').val(),
classCode: $('#formInputClassCode').val(),
className: $('#formInputClassName').val(),
numPeople: $('#formInputNumPeople').val(),
classRoom: $('#formInputClassRoom').val(),
time: $('#formInputTime').val()
};
var errorCode = $('#errorCode').val();
google.script.run
.withSuccessHandler(function () {
})
.withFailureHandler(function (error) {
console.log('[submit() Error]', error);
})
.submit(inputValues, errorCode);
}
</script>
\ No newline at end of file
/**
* Const Values
*/
var ErrorCodeMessages = {
undefined: '등록되지 않은 오류가 발생했습니다. 다시 시도해주세요.',
'error-00': '셀을 다시 선택해주세요.',
'error-01': '한번에 강의실만 선택해주세요.',
'error-02': '상단 혹은 좌측의 Header 선택에서 제외해주세요.',
'error-03': '해당 강의실의 수용인원이 초과되었습니다.',
'error-04': '선택한 시간 범위가 잘못되었습니다.',
'error-05': '이미 예약된 시간입니다.'
};
function onOpen(e) {
SpreadsheetApp.getUi()
.createAddonMenu()
.addItem('View records', 'showSidebar')
.addToUi();
showSidebar();
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* @param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar. The sidebar structure is described in the Sidebar.html
* project file.
*/
function showSidebar() {
var ui = HtmlService.createTemplateFromFile('Sidebar')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('KHU Classroom Lender');
SpreadsheetApp.getUi().showSidebar(ui);
}
function getRange() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveRange();
var values = range.getValues();
var row = range.getRow();
var col = range.getColumn();
var width = range.getWidth();
var height = range.getHeight();
var topHeader = sheet.getRange(1, col).getValue();
var date = sheet.getRange(1, 1).getValue();
return [{values, row, col, width, height}, topHeader, date];
}
function submit(inputValues, errorCode) {
var ui = SpreadsheetApp.getUi();
// 에러가 발생했는지 확인
if (errorCode != '') {
// alert 출력
var msg = (errorCode in ErrorCodeMessages) ? ErrorCodeMessages[errorCode] : ErrorCodeMessages[undefined];
ui.alert(msg);
return;
}
// 변수들이 모두 입력되었는지 확인
if (inputValues.profName === '' ||
inputValues.classCode === '' ||
inputValues.className === '' ||
inputValues.numPeople === '') {
ui.alert('누락된 정보가 있습니다. 모두 입력해주세요.');
}
// 백엔드에다가 여기 예약한다고 보내기
// 최종 확인
var msg = '예약 대상이 [' + inputValues.classRoom + ' / ' + inputValues.time + '] 맞습니까?';
var response = ui.alert('예약 확인', msg, ui.ButtonSet.YES_NO);
if (response != ui.Button.YES) {
ui.alert('예약이 취소되었습니다.');
return;
}
// 셀 병합
var sheet = SpreadsheetApp.getActiveSheet();
var range = getRange()[0];
var sheetRange = sheet.getRange(range.row, range.col, range.height, range.width)
sheetRange.merge();
// 셀에 값 주기
var cellValue = inputValues.className + '\n' + inputValues.profName;
sheetRange.setValue(cellValue);
ui.alert('예약됐다 치자.');
return;
}
\ No newline at end of file