Showing
3 changed files
with
270 additions
and
0 deletions
GoogleAppsScript/Sidebar.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html> | ||
3 | + <head> | ||
4 | + <base target="_top"> | ||
5 | + </head> | ||
6 | + <body> | ||
7 | + <form> | ||
8 | + <input type="hidden" id="errorCode" value="error-0"> | ||
9 | + <p> | ||
10 | + <strong>교수명</strong> | ||
11 | + <input type="text" id="formInputProfName" name="name" value="김가나"> | ||
12 | + </p> | ||
13 | + <p> | ||
14 | + <strong>강좌코드</strong> | ||
15 | + <input type="text" id="formInputClassCode" name="classcode" value="CEEEE"> | ||
16 | + </p> | ||
17 | + | ||
18 | + <p> | ||
19 | + <strong>강의명</strong> | ||
20 | + <input type="text" id="formInputClassName" name='classname' value="공학과경영"> | ||
21 | + </p> | ||
22 | + <p> | ||
23 | + <strong>정원</strong> | ||
24 | + <input type="number" id="formInputNumPeople" name="num-people" value="1" min="1"> | ||
25 | + </p> | ||
26 | + <p> | ||
27 | + <strong>강의실</strong> | ||
28 | + <input type="text" id="formInputClassRoom" name="classroom" value="멀303" placeholder="셀을 선택하면 자동으로 입력됩니다." disabled> | ||
29 | + </p> | ||
30 | + <p> | ||
31 | + <strong>선택 시간</strong> | ||
32 | + <input type="text" id="formInputTime" name="time" value="" placeholder="셀을 선택하면 자동으로 입력됩니다." disabled> | ||
33 | + </p> | ||
34 | + <p> | ||
35 | + <input type="button" value="제출" id="formSubmitBtn"> | ||
36 | + </p> | ||
37 | + </form> | ||
38 | + <?!= HtmlService.createHtmlOutputFromFile('SidebarJS').getContent(); ?> | ||
39 | + </body> | ||
40 | +</html> |
GoogleAppsScript/SidebarJS.html
0 → 100644
1 | +<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | ||
2 | +<script> | ||
3 | + /** | ||
4 | + * Run initializations on sidebar load. | ||
5 | + */ | ||
6 | + $(function() { | ||
7 | + $('#formSubmitBtn').click(submit); | ||
8 | + | ||
9 | + // Assign handler functions to sidebar elements here, if needed. | ||
10 | + | ||
11 | + // Call the server here to retrieve any information needed to build | ||
12 | + // the dialog, if necessary. | ||
13 | + | ||
14 | + // Start polling for updates | ||
15 | + poll(1000); | ||
16 | + }); | ||
17 | + | ||
18 | + /** | ||
19 | + * Poll a server-side function at the given interval, to have | ||
20 | + * results passed to a successHandler callback. | ||
21 | + * | ||
22 | + * https://stackoverflow.com/a/24773178/1677912 | ||
23 | + * | ||
24 | + * @param {Number} interval (optional) Time in ms between polls. | ||
25 | + * Default is 1s (1000ms) | ||
26 | + */ | ||
27 | + function poll(interval) { | ||
28 | + interval = interval || 1000; | ||
29 | + //interval = 500; | ||
30 | + setTimeout(function() { | ||
31 | + google.script.run | ||
32 | + .withSuccessHandler(updateFormValues) | ||
33 | + .withFailureHandler(function (error) { //To-do! Failuer처리는 어떻게? | ||
34 | + var div = document.getElementById('error'); | ||
35 | + div.innerHTML = "ERROR: " + error.message; | ||
36 | + }) | ||
37 | + .getRange(); | ||
38 | + }, interval); | ||
39 | + }; | ||
40 | + | ||
41 | + | ||
42 | + function validateRange(range, topHeader) { | ||
43 | + // domain내의 범위인가 (top header제외) | ||
44 | + const top = 2; | ||
45 | + const outOfRange = 34; | ||
46 | + if (top >= range.row || outOfRange <= range.row) | ||
47 | + return {code: "error-04"}; | ||
48 | + | ||
49 | + //range column이 left header와 right header사이에 있는가 | ||
50 | + const leftHeader = 2; | ||
51 | + const rightHeader = 35; | ||
52 | + if (range.col <= leftHeader || range.col >= rightHeader){ //To-do! 고정값으로 할 것인가, sheet인식해서 값 변동시킬 것인가. | ||
53 | + return {code: "error-02"}; | ||
54 | + } | ||
55 | + | ||
56 | + //range가 1열로 이루어져있는가 | ||
57 | + if (range.width != 1) | ||
58 | + return {code: "error-01"}; | ||
59 | + | ||
60 | + // 이미 예약된 항목과 겹치는가 //To-do! 백엔드에서 동시성 제어하도록 전환할 것 | ||
61 | + for (var i = 0; i < range.height; ++i) { | ||
62 | + for (var j = 0; j < range.width; ++j) { | ||
63 | + if (range.values[i][j] !== ""){ | ||
64 | + return {code: "error-05"}; | ||
65 | + } | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + //수용인원을 초과하는가 | ||
70 | + var lastIdx = topHeader.lastIndexOf("명") | ||
71 | + var startIdx = topHeader.lastIndexOf("\n", lastIdx) + 1; | ||
72 | + var capacity = parseInt(topHeader.substring(startIdx, lastIdx)); | ||
73 | + if (capacity < $('input[name=num-people]').val()) | ||
74 | + return {code: "error-03"}; | ||
75 | + | ||
76 | + return {code: ""}; | ||
77 | + } | ||
78 | + | ||
79 | + | ||
80 | + | ||
81 | + | ||
82 | + | ||
83 | + // param: rangeInfo -> [{int col, int width, int height}, String topHeader's value (like 전정\n205\n202명)] | ||
84 | + function updateFormValues([range, topHeader, date]) { | ||
85 | + var ret = validateRange(range, topHeader); | ||
86 | + if (ret.code === "") { | ||
87 | + var parsed = topHeader.split("\n"); | ||
88 | + var classroom = parsed[0] + " " + parsed[1]; | ||
89 | + | ||
90 | + $('input[name=classroom]').val(classroom); | ||
91 | + | ||
92 | + var start = 9 * 60 + 30 * (range.row - 3); | ||
93 | + var stop = start + 30 * range.height; | ||
94 | + var startStr = parseInt(start/60).toString() + ":" + ((start%60)<10 ? '0' + (start % 60).toString() : (start % 60).toString()); | ||
95 | + var stopStr = parseInt(stop/60).toString() + ":" + ((stop%60)<10 ? '0' + (stop % 60).toString() : (stop % 60).toString()); | ||
96 | + var timeInterval = startStr + "~" + stopStr; | ||
97 | + $('input[name=time]').val(date + " " + timeInterval); | ||
98 | + $('#errorCode').val(ret.code); | ||
99 | + poll(1000); | ||
100 | + return; | ||
101 | + | ||
102 | + } | ||
103 | + $('input[name=classroom]').val(""); | ||
104 | + $('input[name=time]').val(""); | ||
105 | + $('#errorCode').val(ret.code); | ||
106 | + poll(1000); | ||
107 | + }; | ||
108 | + | ||
109 | + function submit() { | ||
110 | + // 변수들 | ||
111 | + var inputValues = { | ||
112 | + profName: $('#formInputProfName').val(), | ||
113 | + classCode: $('#formInputClassCode').val(), | ||
114 | + className: $('#formInputClassName').val(), | ||
115 | + numPeople: $('#formInputNumPeople').val(), | ||
116 | + classRoom: $('#formInputClassRoom').val(), | ||
117 | + time: $('#formInputTime').val() | ||
118 | + }; | ||
119 | + var errorCode = $('#errorCode').val(); | ||
120 | + | ||
121 | + google.script.run | ||
122 | + .withSuccessHandler(function () { | ||
123 | + }) | ||
124 | + .withFailureHandler(function (error) { | ||
125 | + console.log('[submit() Error]', error); | ||
126 | + }) | ||
127 | + .submit(inputValues, errorCode); | ||
128 | + } | ||
129 | + | ||
130 | +</script> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
GoogleAppsScript/main.gs
0 → 100644
1 | +/** | ||
2 | + * Const Values | ||
3 | + */ | ||
4 | + | ||
5 | +var ErrorCodeMessages = { | ||
6 | + undefined: '등록되지 않은 오류가 발생했습니다. 다시 시도해주세요.', | ||
7 | + 'error-00': '셀을 다시 선택해주세요.', | ||
8 | + 'error-01': '한번에 한 강의실만 선택해주세요.', | ||
9 | + 'error-02': '상단 혹은 좌측의 Header는 선택에서 제외해주세요.', | ||
10 | + 'error-03': '해당 강의실의 수용인원이 초과되었습니다.', | ||
11 | + 'error-04': '선택한 시간 범위가 잘못되었습니다.', | ||
12 | + 'error-05': '이미 예약된 시간입니다.' | ||
13 | +}; | ||
14 | + | ||
15 | + | ||
16 | +function onOpen(e) { | ||
17 | + SpreadsheetApp.getUi() | ||
18 | + .createAddonMenu() | ||
19 | + .addItem('View records', 'showSidebar') | ||
20 | + .addToUi(); | ||
21 | + showSidebar(); | ||
22 | +} | ||
23 | + | ||
24 | +/** | ||
25 | + * Runs when the add-on is installed; calls onOpen() to ensure menu creation and | ||
26 | + * any other initializion work is done immediately. | ||
27 | + * | ||
28 | + * @param {Object} e The event parameter for a simple onInstall trigger. | ||
29 | + */ | ||
30 | +function onInstall(e) { | ||
31 | + onOpen(e); | ||
32 | +} | ||
33 | + | ||
34 | +/** | ||
35 | + * Opens a sidebar. The sidebar structure is described in the Sidebar.html | ||
36 | + * project file. | ||
37 | + */ | ||
38 | +function showSidebar() { | ||
39 | + var ui = HtmlService.createTemplateFromFile('Sidebar') | ||
40 | + .evaluate() | ||
41 | + .setSandboxMode(HtmlService.SandboxMode.IFRAME) | ||
42 | + .setTitle('KHU Classroom Lender'); | ||
43 | + SpreadsheetApp.getUi().showSidebar(ui); | ||
44 | +} | ||
45 | + | ||
46 | +function getRange() { | ||
47 | + var sheet = SpreadsheetApp.getActiveSheet(); | ||
48 | + var range = sheet.getActiveRange(); | ||
49 | + var values = range.getValues(); | ||
50 | + var row = range.getRow(); | ||
51 | + var col = range.getColumn(); | ||
52 | + var width = range.getWidth(); | ||
53 | + var height = range.getHeight(); | ||
54 | + var topHeader = sheet.getRange(1, col).getValue(); | ||
55 | + var date = sheet.getRange(1, 1).getValue(); | ||
56 | + return [{values, row, col, width, height}, topHeader, date]; | ||
57 | +} | ||
58 | + | ||
59 | +function submit(inputValues, errorCode) { | ||
60 | + var ui = SpreadsheetApp.getUi(); | ||
61 | + | ||
62 | + // 에러가 발생했는지 확인 | ||
63 | + if (errorCode != '') { | ||
64 | + // alert 출력 | ||
65 | + var msg = (errorCode in ErrorCodeMessages) ? ErrorCodeMessages[errorCode] : ErrorCodeMessages[undefined]; | ||
66 | + ui.alert(msg); | ||
67 | + return; | ||
68 | + } | ||
69 | + | ||
70 | + // 변수들이 모두 입력되었는지 확인 | ||
71 | + if (inputValues.profName === '' || | ||
72 | + inputValues.classCode === '' || | ||
73 | + inputValues.className === '' || | ||
74 | + inputValues.numPeople === '') { | ||
75 | + ui.alert('누락된 정보가 있습니다. 모두 입력해주세요.'); | ||
76 | + } | ||
77 | + | ||
78 | + // 백엔드에다가 여기 예약한다고 보내기 | ||
79 | + | ||
80 | + // 최종 확인 | ||
81 | + var msg = '예약 대상이 [' + inputValues.classRoom + ' / ' + inputValues.time + '] 이 맞습니까?'; | ||
82 | + var response = ui.alert('예약 확인', msg, ui.ButtonSet.YES_NO); | ||
83 | + if (response != ui.Button.YES) { | ||
84 | + ui.alert('예약이 취소되었습니다.'); | ||
85 | + return; | ||
86 | + } | ||
87 | + | ||
88 | + // 셀 병합 | ||
89 | + var sheet = SpreadsheetApp.getActiveSheet(); | ||
90 | + var range = getRange()[0]; | ||
91 | + var sheetRange = sheet.getRange(range.row, range.col, range.height, range.width) | ||
92 | + sheetRange.merge(); | ||
93 | + | ||
94 | + // 셀에 값 주기 | ||
95 | + var cellValue = inputValues.className + '\n' + inputValues.profName; | ||
96 | + sheetRange.setValue(cellValue); | ||
97 | + | ||
98 | + ui.alert('예약됐다 치자.'); | ||
99 | + return; | ||
100 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment