var SIDEBAR_TITLE = 'Column Generator';
var DIALOG_TITLE = 'Preview';
var PROP_COUNT = 8;
var HEAD_NAME = '필드명';
var HEAD_TYPE = '형태';
var HEAD_ALIGN = '정렬';
var HEAD_EDIT = '편집 여부';
var HEAD_NUMB = '숫자 형식';
var HEAD_DATE = '날짜 형식';
var HEAD_VALS = '선택 값';
var HEAD_LBLS = '선택 라벨';
var START_COL = 2;
var TYPE_VALUES = [
'line',
'multiline',
'dropdown',
'search',
'multicheck',
'number',
'date',
];
var TYPE_LABELS = [
'텍스트',
'다중 라인',
'드랍다운',
'부분검색',
'복수 선택',
'숫자',
'날짜',
];
var ALIGN_VALUES = ['near', 'center', 'far'];
var ALIGN_LABELS = ['왼쪽', '가운데', '오른쪽'];
var NFMT_VALUES = ['', '#,##0', '#,##0.0', '#,##0.00'];
var NFMT_LABELS = [
'-',
'정수(#,##0)',
'소숫점 1자리(#,##0.0)',
'소숫점 2자리(#,##0.00)',
];
var DFMT_VALUES = [
'',
'yyyy/MM/dd',
'yyyy-MM-dd',
'yyyy/MM/dd hh:nn:ss',
'yyyy-MM-dd hh:nn:ss',
];
var DFMT_LABELS = [
'-',
'날짜(구분자 "/")',
'날짜(구분자 "-")',
'날짜 + 시간(구분자 "/")',
'날짜 + 시간(구분자 "-")',
];
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
SpreadsheetApp.getUi()
.createAddonMenu()
.addItem(SIDEBAR_TITLE, 'showColumnSidebar')
.addToUi();
}
function showColumnSidebar() {
var sidebar = HtmlService.createTemplateFromFile('ColumnSidebar')
.evaluate()
.setTitle(SIDEBAR_TITLE)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showSidebar(sidebar);
}
function showColumnPreivew(fields, columns) {
var template = HtmlService.createTemplateFromFile('ColumnPreview');
template.fieldInfo = fields;
template.columnInfo = columns;
var preview = template
.evaluate()
.setWidth(600)
.setHeight(500)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showModalDialog(preview, DIALOG_TITLE);
}
function buildForm(colDepth) {
colDepth = parseInt(colDepth);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getDataRange().setDataValidation(null);
sheet.clear().clearNotes();
var colCount = 4;
var colPerGroup = 2;
if (colDepth > 1) {
colCount = Math.pow(colPerGroup, colDepth);
for (var r = 1; r < colDepth; r++) {
for (var c = 0; c < colCount; c++) {
var groupCols = Math.pow(colPerGroup, r);
if (c % groupCols == 0) {
sheet
.getRange(colDepth - r, c + 2, 1, groupCols)
.mergeAcross()
.setValue('그룹');
}
}
}
colCount++;
}
sheet
.getRange(1, 2, colDepth, colCount)
.setHorizontalAlignment('center')
.setVerticalAlignment('middle')
.setBackground('silver')
.setBorder(true, true, true, true, true, true);
for (var i = 0; i < colCount; i++) {
sheet.getRange(colDepth, i + 2).setValue('컬럼' + (i + 1));
sheet.getRange(colDepth + 1, i + 2).setValue('column' + i);
}
var row = 1 + colDepth;
var fieldNameRow = row;
var editTypeRow = row + 1;
var alignmentRow = row + 2;
var editableRow = row + 3;
var numberFmtRow = row + 4;
var dateFmtRow = row + 5;
var valuesRow = row + 6;
var labelsRow = row + 7;
sheet
.getRange(fieldNameRow, 1)
.setValue(HEAD_NAME)
.setFontColor('#cc0000')
.setFontWeight('bold');
sheet
.getRange(editTypeRow, 1)
.setValue(HEAD_TYPE)
.setFontColor('#cc0000')
.setFontWeight('bold');
sheet.getRange(alignmentRow, 1).setValue(HEAD_ALIGN);
sheet.getRange(editableRow, 1).setValue(HEAD_EDIT);
sheet.getRange(numberFmtRow, 1).setValue(HEAD_NUMB);
sheet.getRange(dateFmtRow, 1).setValue(HEAD_DATE);
sheet
.getRange(valuesRow, 1)
.setValue(HEAD_VALS)
.setNote(
'드랍다운 또는 복수선택일 경우\n항목들의 값을 쉼표(,)로 나누어 입력'
);
sheet
.getRange(labelsRow, 1)
.setValue(HEAD_LBLS)
.setNote(
'드랍다운 또는 복수선택일 경우\n항목들의 라벨을 쉼표(,)로 나누어 입력\n미입력시 값이 표시'
);
sheet.getRange(row, 2, PROP_COUNT, colCount).setBackground('#ffff77');
sheet.setFrozenColumns(1);
sheet
.getRange(editTypeRow, 2, 1, colCount)
.setDataValidation(
SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInList(TYPE_LABELS, true)
.build()
)
.setValue('텍스트');
sheet
.getRange(alignmentRow, 2, 1, colCount)
.setDataValidation(
SpreadsheetApp.newDataValidation()
.setAllowInvalid(true)
.requireValueInList(ALIGN_LABELS, true)
.build()
)
.setValue('왼쪽');
sheet
.getRange(editableRow, 2, 1, colCount)
.setDataValidation(
SpreadsheetApp.newDataValidation()
.setAllowInvalid(true)
.requireCheckbox()
.build()
)
.setValue('TRUE');
sheet
.getRange(numberFmtRow, 2, 1, colCount)
.setDataValidation(
SpreadsheetApp.newDataValidation()
.setAllowInvalid(true)
.requireValueInList(NFMT_LABELS, true)
.build()
)
.setValue('');
sheet
.getRange(dateFmtRow, 2, 1, colCount)
.setDataValidation(
SpreadsheetApp.newDataValidation()
.setAllowInvalid(true)
.requireValueInList(DFMT_LABELS, true)
.build()
)
.setValue('');
}
function generateGridInfo() {
var sheet = SpreadsheetApp.getActiveSheet();
var values = sheet.getDataRange().getValues();
if (!values || values.length < 2 || values[0].length < 2) {
throw new Error('시트 데이터가 존재하지 않습니다.');
}
var srow = -1;
var nameRow,
typeRow,
alignRow,
editableRow,
numberRow,
dateRow,
valuesRow,
labelsRow;
for (var r = 0; r < values.length; r++) {
var head = values[r][0];
if (head && srow == -1) {
srow = r;
}
if (head == HEAD_NAME) {
nameRow = r;
} else if (head == HEAD_TYPE) {
typeRow = r;
} else if (head == HEAD_ALIGN) {
alignRow = r;
} else if (head == HEAD_EDIT) {
editableRow = r;
} else if (head == HEAD_NUMB) {
numberRow = r;
} else if (head == HEAD_DATE) {
dateRow = r;
} else if (head == HEAD_VALS) {
valuesRow = r;
} else if (head == HEAD_LBLS) {
labelsRow = r;
}
}
if (!nameRow) {
throw new Error(HEAD_NAME + '행을 찾지 못했습니다.');
}
if (!typeRow) {
throw new Error(HEAD_TYPE + '행을 찾지 못했습니다.');
}
var fields = [];
var columns = [];
for (var c = 1; c < values[0].length; c++) {
var fname = values[nameRow][c];
if (fname) {
var field = {};
var column = {};
field.fieldName = column.fieldName = column.name = fname;
column.width = Math.round(sheet.getColumnWidth(c + 1));
column.header = { text: values[srow - 1][c] };
var typeText = values[typeRow][c];
var typeIndex = TYPE_LABELS.indexOf(typeText);
if (typeIndex == -1) {
throw new Error('존재하지 않은 형태(' + typeText + ') 입니다.');
}
var ftype = TYPE_VALUES[typeIndex];
column.editor = { type: ftype };
if (ftype == 'number' || ftype == 'datetime') {
field.dataType = ftype;
}
var align = ALIGN_VALUES[ALIGN_LABELS.indexOf(values[alignRow][c])];
if (align != 'near') {
column.styles = { textAlignment: align };
}
values[editableRow][c] === false &&
SpreadsheetApp.getActiveSpreadsheet().toast('editable false');
if (!values[editableRow][c]) {
column.editable = false;
}
if (ftype == 'date') {
var fmt = values[dateRow][c];
var formatIndex = DFMT_LABELS.indexOf(fmt);
var dateformat =
formatIndex == -1 ? fmt || 'yyyy/MM/dd' : DFMT_VALUES[formatIndex];
field.datetimeFormat = dateformat;
column.editor.datetimeFormat = dateformat;
}
if (ftype == 'number') {
var fmt = values[numberRow][c];
var formatIndex = NFMT_LABELS.indexOf(fmt);
if (!column.styles) {
column.styles = {};
}
var numberformat =
formatIndex == -1 ? fmt || null : NFMT_VALUES[formatIndex];
column.styles.numberFormat = numberformat;
column.editor.editFormat = numberformat;
column.editor.textAlignment = 'far';
}
if (ftype == 'multicheck' || ftype == 'dropdown') {
column.lookupDisplay = true;
column.editor.showButtons = true;
var vals = values[valuesRow][c].split(',');
var lbls = values[labelsRow][c].split(',');
column.values = vals;
if (lbls.length > 1 || lbls[0] != '') column.labels = lbls;
if (ftype == 'multicheck') column.valueSeparator = ',';
}
fields.push(field);
columns.push(column);
}
}
if (srow > 1) {
var groups = [];
buildColumnGroups(groups, sheet, 1, srow, 2, columns.length + 1, columns);
return { fields: fields, columns: groups };
} else {
return { fields: fields, columns: columns };
}
}
function getCells(sheet, row, startcol, lastcol) {
var cells = [];
for (var i = startcol; i <= lastcol; i++) {
var range = sheet.getRange(row, i);
var merges = range.getMergedRanges();
if (merges.length > 0) {
cells.push(merges[0]);
i += merges[0].getLastColumn() - merges[0].getColumn();
} else {
cells.push(range);
}
}
return cells;
}
function buildColumnGroups(
list,
sheet,
row,
lastRow,
startCol,
lastCol,
columns
) {
var cells = getCells(sheet, row, startCol, lastCol);
var totwidth = 0;
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
var cellStartCol = cell.getColumn();
var cellLastCol = cell.getLastColumn();
if (cellStartCol == cellLastCol) {
var col = columns[cellStartCol - START_COL];
list.push(col);
totwidth += col.width;
} else {
var group = {};
group.header = { text: cell.getValue() };
group.columns = [];
group.width = buildColumnGroups(
group.columns,
sheet,
row + 1,
lastRow,
cellStartCol,
cellLastCol,
columns
);
totwidth += group.width;
list.push(group);
}
}
return totwidth;
}