diff --git a/src/main/webapp/WEB-INF/jsp/include/tail.jsp b/src/main/webapp/WEB-INF/jsp/include/tail.jsp
index 2b152661..d88bb0cd 100644
--- a/src/main/webapp/WEB-INF/jsp/include/tail.jsp
+++ b/src/main/webapp/WEB-INF/jsp/include/tail.jsp
@@ -1,6 +1,6 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
-
+
Loading...
@@ -20,7 +20,7 @@
">
-">
+">
">
">
">
diff --git a/src/main/webapp/resources/css/xit-core.css b/src/main/webapp/resources/css/xit-core.css
index 2ccb8b67..c49af09f 100644
--- a/src/main/webapp/resources/css/xit-core.css
+++ b/src/main/webapp/resources/css/xit-core.css
@@ -107,7 +107,7 @@
}
.hidden {
- display:none !important;
+ display:none;
}
[hidden] {
diff --git a/src/main/webapp/resources/js/base/base.js b/src/main/webapp/resources/js/base/base.js
deleted file mode 100644
index b617276a..00000000
--- a/src/main/webapp/resources/js/base/base.js
+++ /dev/null
@@ -1,867 +0,0 @@
-var wctx = {
- path:"",
- url:function(path) {
- return this.path + path;
- },
- home:function() {
- top.location.href = wctx.url("/");
- },
- current:function() {
- let str = top.location.href.replace(top.location.origin + wctx.path, "");
- let pos = str.indexOf("?");
- return pos < 0 ? str : str.substr(0, pos);
- },
- trace:true
-};
-
-function log(msg) {
- console.log.apply(console, arguments);
-}
-
-function debug(msg) {
- if (wctx && wctx.trace)
- console.log.apply(console, arguments);
-}
-
-function trim(s) {
- if (null == s || undefined == s) return "";
- if ("string" != typeof(s)) return s;
- return s.replace(/^\s+/, "").replace(/\s+$/, "");
-}
-
-function isEmpty(v) {
- if (v == undefined
- || v == "undefined"
- || v == null
- || v == "null"
- ) return true;
-
- switch (typeof(v)) {
- case "string": return "" == trim(v);
- case "boolean": if (false == v) return false;
- case "number": if (0 == v) return false;
- default: return false;
- }
-}
-
-function ifEmpty(v, nv) {
- if (!isEmpty(v)) return v;
- if (typeof(nv) == "function")
- return nv.apply();
- else
- return nv;
-}
-
-function notEmpty(obj, msg) {
- if (isEmpty(obj))
- throw msg;
- return obj;
-}
-
-function toQuery(map, encode) {
- if (isEmpty(map)) return "";
-
- var query = [];
- for (var key in map) {
- var v = map[key];
- if (v != null && v == undefined) continue;
- if (v != null)
- switch (typeof(v)) {
- case "object":
- case "function": continue;
- }
- if (isEmpty(v))
- query.push(key);
- else
- query.push(key + "=" + (encode != false ? encodeURIComponent(v) : v));
- }
- return query.join("&");
-}
-
-function uuid() {
- var hexDigits = "0123456789abcde",
- result = [];
-
- for (var i = 0; i < 36; ++i)
- result[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
- result[14] = "4";
- result[19] = hexDigits.substr((result[19] & 0x3) | 0x8, 1);
- result[8] = result[13] = result[18] = result[23] = "-";
-
- return result.join("");
-}
-
-function wait(show) {
- if (show == false)
- $(".wait").attr("hidden","hidden");
- else
- $(".wait").removeAttr("hidden");
-}
-
-var dialog = {
- title:"XIT",
- template:null,
- open:function(conf) {
- if (this.template)
- this.create(conf);
- else {
- var self = this;
- ajax.get({
- url:wctx.url("/webjars/html/dialog.html"),
- success:function(resp) {
- self.template = resp;
- self.create(conf);
- }
- });
- }
- },
- close:function(id) {
- $("#close" + id).click();
- },
- create:function(conf) {
- let last = {
- dlg: $("div.modal.show").last()[0],
- setZIndex: (obj, offset) => {
- if (!last.dlg) return;
-
- let zIndex = Number($(last.dlg).css("z-index"));
- obj.css("z-index", zIndex + offset);
- }
- };
-
- conf = conf || {};
- let id = conf.id || "dlg-" + uuid(),
- backdropID = id + "-backdrop",
- size = conf.size || "",
- tmpl = this.template
- .replace(/{id}/g, id)
- .replace(/{title}/g, conf.title || dialog.title);
- if (size)
- size = " modal-" + size;
- tmpl = tmpl.replace(/{size}/, size);
- dlg = $(tmpl).appendTo("body");
-
- dlg.find(".modal-body").html(conf.content || "").fadeIn();
-
- dlg.on("hidden.bs.modal", function() {// on dialog close
- $("#" + id +",#" + backdropID).remove(); // removes the dialog and its backdrop
- if (conf.onClose)
- conf.onClose();
- });
-
- if (conf.onOK) {
- let footer = dlg.find(".modal-footer");
- footer.removeClass("hidden");
- footer.show();
- footer.find("button").unbind("click").click(function() {
- if (conf.getData) {
- var selected = conf.getData.apply();
- if (!selected) return;
-
- conf.onOK(selected);
- dialog.close(id);
- } else {
- conf.onOK();
- dialog.close(id);
- }
- });
- } else {
- if (conf.timeout)
- setTimeout(function(){dialog.close(id);}, conf.timeout);
- }
-
- last.setZIndex(dlg, 10);
- dlg.draggable({handle: ".modal-header"}).modal("show");
- $(".modal-backdrop").each(function() { // gives id to its backdrop
- let backdrop = $(this);
- if (!backdrop.prop("id"))
- backdrop.prop("id", backdropID);
- });
-
- if (conf.init)
- conf.init();
- },
- alert:function(conf) {
- var container = "
{content}
";
- if ("string" == typeof(conf)) {
- conf = {
- content:container.replace(/{content}/g, conf)
- };
- } else {
- conf.content = container.replace(/{content}/g, conf.content);
- }
- conf.timeout = ifEmpty(conf.timeout, dialog.timeout);
- this.open(conf);
- }
-};
-
-function onError(xhr, options, error) {
- if (xhr.readyState == 0)
- return dialog.alert("서버에 접근할 수 없습니다.");
-
- var resp = JSON.parse(xhr.responseText);
- if (resp.handler)
- return eval(resp.handler);
-
- var msgs = [];
- for (key in resp)
- msgs.push(resp[key])
- msgs = msgs.join("
");
- if (msgs)
- dialog.alert(msgs);
-}
-
-var ajax = {
- request:function(options) {
- options.beforeSend = function(xhr) {
- if (wctx.csrf)
- xhr.setRequestHeader(wctx.csrf.header, wctx.csrf.token);
- if (!options.silent)
- wait();
- }
- if (!options.type) {
- if (options.data)
- options.type = "POST";
- }
-
- var success = options.success;
- options.success = function(resp) {
- if ("string" == typeof resp)
- resp = trim(resp);
-
- var stacktrace = resp.stacktrace;
- delete resp.stacktrace;
-
- debug("response", resp);
-
- if (!resp.failed)
- return success(resp);
-
- dialog.alert({
- title:resp.title,
- content:[resp.description, resp.message].join("
")
- });
-
- debug("stacktrace", stacktrace);
- };
- var handleError = options.error || onError;
- options.error = function(xhr, options, error) {
- wait(false);
-
- debug("error", xhr, options, error);
- handleError(xhr, options, error);
- }
-
- var handleComplete = options.complete || function(){};
- options.complete = function() {
- wait(false);
- handleComplete();
- };
- debug("request", options);
- $.ajax(options);
- },
- get:function(options) {
- options.type = "GET";
- ajax.request(options);
- },
- post:function(options) {
- options.type = "POST";
- ajax.request(options);
- }
-};
-
-var json = {
- with:function(options) {
- options.dataType = "json";
- if (typeof(options.data) == "string") {
- options.contentType = "application/json; charset=UTF-8";
- }
- return options;
- },
- get:function(options) {
- ajax.get(json.with(options));
- },
- post:function(options) {
- ajax.post(json.with(options));
- }
-};
-
-function upload(options) {
- options.enctype = "multipart/form-data";
- options.processData = options.contentType = false;
- var data = options.data,
- formData = new FormData();
- for (var key in data) {
- var val = data[key];
- if (!Array.isArray(val))
- formData.append(key, val);
- else {
- for (var i = 0; i < val.length; ++i)
- formData.append(key, val[i]);
- }
- }
- options.data = formData;
- ajax.post(options);
-}
-
-$.fn.onEnterPress = function(handler) {
- return this.each(function(){
- $(this).keypress(function(evt){
- if (!handler || evt.which != 13) return;
- handler.apply();
- });
- });
-}
-
-function labelFor(input) {
- let selector = "label[for='{id}']",
- str = "string" == typeof(input),
- obj = $(input),
- key = str ? input
- : obj.attr("id") || obj.attr("name");
- if (!key) return "";
-
- selector = selector.replace(/{id}/gi, key);
- return $(selector).text()
- || obj.attr("title")
- || obj.attr("placeholder");
-}
-
-function validationFailureHandler() {
- var handler = {
- notice:function(msg, input) {
- dialog.alert({
- content:msg,
- onClose:function(){input.focus();}
- });
- },
- valueMissing: function(input) {
- handler.notice(labelFor(input) + "를(을) 입력하십시오.", input);
- },
- typeMismatch: function(input) {
- handler.notice(input.value + "는 " + labelFor(input) + "의 형식에 맞지 않습니다.", input);
- },
- tooLong: function(input) {
- handler.notice(input.value + " 값이 너무 깁니다.", input);
- },
- patternMismatch: function(input) {
- handler.notice(input.value + "는 " + labelFor(input) + "의 형식에 맞지 않습니다.", input);
- },
- rangeOverflow: function(input) {
- handler.notice(labelFor(input) + "의 값은 " + input.max + "보다 작아야 합니다.", input);
- },
- rangeUnderflow: function(input) {
- handler.notice(labelFor(input) + "의 값은 " + input.min + "보다 커야 합니다.", input);
- },
- stepMismatch: function(input) {
- handler.notice(labelFor(input) + "의 값은 " + input.step + "씩 증가 또는 감소해야 합니다.", input);
- }
- };
- return handler;
-}
-
-/**Returns the result of validation on the input object.
- * The types of validation checks are those defined by input objects' basic validity property, which are
- *
valueMissing
- * typeMismatch
- * tooLong
- * patternMismatch
- * rangeOverflow
- * rangeUnderflow
- * stepMismatch
- *
- * To be effective, the input object must be set with attributes
- *
required
- * type
- * maxLength
- * pattern
- * max
- * min
- * step
- *
- * On failure, failureHandler takes over.
- * The default handler from
validationFailureHandler()
displays a message
- * and puts the focus back to the input object.
- * For the handler to display a message appropriate for the failure,
- * it is recommended to have a label associated with the input object.
- * @param input input object
- * @param failureHandler object that handles validation failure.
- * If not provided, the default handler from
validationFailureHandler()
is used.
- * @returns
- *
true if the value of the input object is valid
- * false otherwise
- *
- */
-function validInput(input, failureHandler) {
- var validity = input.validity;
- if (!validity || validity.valid) return true;
-
- for (var key in validity) {
- if (!validity[key]) continue;
-
- if (!failureHandler)
- failureHandler = validationFailureHandler();
- var handler = failureHandler[key];
- if (handler)
- handler(input);
- else {
- log("Handler not found for validation failure of " + key);
- }
- break;
- }
-
- return false;
-}
-
-/**Returns the result of input validation on the selected input objects.
- * The types of validation checks are those defined by input objects' basic validity property, which are
- *
valueMissing
- * typeMismatch
- * tooLong
- * patternMismatch
- * rangeOverflow
- * rangeUnderflow
- * stepMismatch
- *
- * To be effective, the input objects must be set with attributes
- *
required
- * type
- * maxLength
- * pattern
- * max
- * min
- * step
- *
- * On failure, failureHandler takes over.
- * The default handler from
validationFailureHandler()
displays a message
- * and puts the focus back to the offending input object.
- * For the handler to display a message appropriate for the failure,
- * it is recommended to have labels associated with input objects.
- * @param failureHandler object that handles validation failure.
- * If not provided, the default handler from
validationFailureHandler()
is used.
- * @returns
- *
true if the input values of the selected objects are valid
- * false otherwise
- *
- */
-$.fn.validInputs = function(failureHandler) {
- var valid = true;
- this.each(function(){
- var input = $(this);
- if (!(valid = validInput(input[0], failureHandler))) {
- return false;
- }
- });
- return valid;
-}
-
-$.fn.getValues = function(propertyMapper) {
- var inputValues = {};
- this.each(function() {
- var input = $(this),
- key = input.prop("id") || input.prop("name"),
- value = input.val();
- if (isEmpty(key) || value === undefined) return;
-
- var type = input.prop("type");
- if ("file" == type) {
- value = input.get(0).files;
- } else if (["checkbox", "radio"].indexOf(type) > -1) {
- if (!input.is(":checked")) return;
- }
-
- var stored = inputValues[key];
- if (stored === undefined) {
- inputValues[key] = value;
- return;
- }
-
- if (Array.isArray(stored)) {
- if (!Array.isArray(value))
- stored.push(value);
- else
- stored = stored.concat(value);
- } else {
- var array = [stored];
- if (!Array.isArray(value))
- array.push(value);
- else
- array = array.concat(value);
- inputValues[key] = array;
- }
- });
-
- if (propertyMapper) { // propertyMapper = {property:valueProvider, ...}
- for (var property in propertyMapper) {
- var valueProvider = propertyMapper[property],
- value = undefined;
- switch (typeof(valueProvider)) {
- case "string":
- value = inputValues[valueProvider];
- break;
- case "function":
- value = valueProvider(inputValues);
- break;
- }
- if (value === undefined) continue;
-
- delete inputValues[valueProvider];
- inputValues[property] = value;
- }
- }
-
- return inputValues;
-}
-
-/**
- * @param config
- * {start:0,
- * fetchSize:10,
- * totalSize:135,
- * links:3,
- * first:function(index, label){return "..."},
- * previous:function(index, label){return "..."},
- * link:function(index, label){return "..."},
- * current:function(index, label){return "..."},
- * next:function(index, label){return "..."},
- * last:function(index, label){return "..."}
- * }
- * @returns {String}
- */
-function paginate(config) {
- var rc = config.totalSize || 0;
-// if (!rc) return "";
-
- var fetchCount = config.fetchSize || 0;
-// if (!fetchCount) return "";
-
- var fetch = {
- all:0,
- none:-1,
- count:function(elementCount, size) {
- if (!elementCount || size == fetch.all) return 1;
- return parseInt((elementCount / size) + ((elementCount % size) == 0 ? 0 : 1));
- },
- end:function(elementCount, size, start) {
- if (size < fetch.all) throw "Invalid size: " + size;
- if (elementCount < 0) throw "Invalid elementCount: " + elementCount;
- var last = elementCount - 1;
- if (size == fetch.all) return last;
- return Math.min(last, start + size -1);
- },
- page:function(current, count) {
- return parseInt(count < 1 ? 0 : current / count);
- },
- band:function(page, visibleLinks) {
- return parseInt(visibleLinks < 1 ? 0 : page / visibleLinks);
- }
- };
- var lc = fetch.count(rc, fetchCount);
- if (lc < 2) return "";
-
- var links = ifEmpty(config.links, fetch.all),
- page = fetch.page(ifEmpty(config.start, 0), fetchCount),
- band = fetch.band(page, links),
- tags = {
- link:function(tag, index, label) {
- return !tag ? "" : tag(index, label);
- },
- first:function() {
- return band < 2 ? "" : tags.link(config.first, 0, 1);
- },
- previous:function() {
- if (band < 1) return "";
- var prevBand = band - 1,
- prevPage = (prevBand * links) + (links - 1),
- fromRec = prevPage * fetchCount;
- return tags.link(config.previous, fromRec, prevPage + 1);
- },
- visibleLinks:function() {
- var s = "",
- fromPage = links == fetch.all ? 0 : band * links,
- toPage = links == fetch.all ? lc : Math.min(lc, fromPage + links);
- for (var i = fromPage; i < toPage; ++i) {
- var fromRec = i * fetchCount,
- label = i + 1;
- s += tags.link(i == page ? config.current : config.link, fromRec, label);
- }
- return s;
- },
- next:function(bandCount) {
- bandCount = parseInt(bandCount);
- if (bandCount - band < 2) return "";
-
- var nextBand = band + 1,
- page = nextBand * links,
- fromRec = page * fetchCount;
- return tags.link(config.next, fromRec, page + 1);
- },
- last:function(bandCount) {
- bandCount = parseInt(bandCount);
- var lastBand = bandCount - 1;
- if (lastBand - band < 2) return "";
-
- var pages = lastBand * links,
- fromRec = pages * fetchCount;
- return tags.link(config.last, fromRec, pages + 1);
- }
- },
- tag = "";
- if (links != fetch.all) {
- tag += tags.first();
- tag += tags.previous();
- }
- tag += tags.visibleLinks();
- if (links != fetch.all) {
- var bandCount = parseInt(lc / links);
- bandCount += lc % links == 0 ? 0 : 1;
- tag += tags.next(bandCount);
- tag += tags.last(bandCount);
- }
- return tag;
-}
-
-$.fn.paginate = function(config) {
- return this.each(function(){
- var tag = paginate(config),
- container = $(this);
- if (tag)
- container.html(tag).show();
- else {
- if (config.hideIfEmpty != false)
- container.hide();
- }
- });
-}
-
-$.fn.setPaging = function(config) {
- config.links = 5;
- config.first = function(index, label) {return '
'.replace(/{func}/, config.func.replace(/{index}/, label));};
- config.previous = function(index, label) {return '
'.replace(/{func}/, config.func.replace(/{index}/, label));};
- config.link = function(index, label) {return '
{label} '.replace(/{func}/, config.func.replace(/{index}/, label)).replace(/{label}/, label);};
- config.current = function(index, label) {return '
{label} '.replace(/{label}/, label);};
- config.next = function(index, label) {return '
'.replace(/{func}/, config.func.replace(/{index}/, label));};
- config.last = function(index, label) {return '
'.replace(/{func}/, config.func.replace(/{index}/, label));};
-
- return this.each(function(){
- let list = config.list,
- start = list.empty ? 0 : config.start + 1,
- end = list.empty ? 0 : config.start + list.length,
- pagingInfo = list.empty ? "" : start + " ~ " + numberFormat.format(end) + " / " + numberFormat.format(config.totalSize);
- $("#"+ config.prefix + "PagingInfo").html(pagingInfo);
-
- let tag = paginate(config),
- container = $(this);
- if (tag)
- container.html(tag.replace(/{func}/g, config.func)).show();
- else {
- if (config.hideIfEmpty != false)
- container.hide();
- }
-
- });
-}
-
-$.fn.setPagingInfo = function(config) {
- return this.each(function(){
- let list = config.list;
- let pagingInfo = list.empty ? "" : 1
- + " ~ "
- + numberFormat.format(list.length)
- + " / " + numberFormat.format(config.totalSize);
- $("#"+ config.prefix + "PagingInfo").html(pagingInfo);
- });
-}
-
-$.fn.setCurrentRow = function(val) {
- if (!val) return;
-
- return this.each(function() {
- var e = $(this);
- e.find("tr").each(function(){
- var tr = $(this),
- current = val == tr.attr("data-key");
- if (current)
- tr.addClass("current-row");
- else
- tr.removeClass("current-row");
- });
- });
-}
-
-class FormFields {
- constructor(selector) {
- this.form = document.querySelector(this.selector = selector);
- this.children = ["input", "select", "textarea"].map(tag => this.selector + " " + tag).join(",");
- this.datamap = [];
- }
-
- set(ctrl, obj) {
- let setChanged = evt => {
- let input = evt.target,
- name = input.getAttribute("data-map"),
- val = input.value;
- ctrl.setValue(name, val);
- };
- document.querySelectorAll(this.children).forEach(input => {
- let prop = input.getAttribute("data-map")
- || input.name
- || input.id;
- if (!prop) return;
-
- input.removeEventListener("change", setChanged);
-
- let dataItem = obj instanceof DataItem,
- value = dataItem ? obj.getValue(prop) : obj[prop],
- inputType = (input.type || input.tagName || "").toLowerCase();
-
- switch (inputType) {
- case "radio": input.checked = value && value == input.value; break;
- case "checkbox": input.checked = value && value == input.value; break;
- case "select":
- for(let option of input.options) {
- option.selected = option.value == value;
- }
- break;
- default: input.value = ifEmpty(value, ""); break;
- }
- input.addEventListener("change", setChanged);
- });
- }
-
- get() {
- let obj = {};
- document.querySelectorAll(this.children).forEach(input => {
- let property = input.name || input.id;
- let value = input.value;
- if ("radio" == input.type) {
- if (input.checked)
- obj[property] = value;
- } else {
- obj[property] = value;
- }
-// log(property, value, "radio" == input.type ? "radio" : "", input.checked ? "checked" : "");
- });
- return obj;
- //return Object.fromEntries(new FormData(this.form).entries());
- }
-};
-
-$.fn.datePicker = function(selector) {
- return this.each(function() {
- $(this)
- .datepicker()
- .attr("maxlength", "10")
- .on("input",function(e) {
- if (this.value.length <= 0
- || this.value.length != this.selectionStart
- )
- return;
-
- var value = this.value.replaceAll("-","");
- if (value.length > 7) {
- this.value = value.substring(0,4)+"-"+value.substring(4,6)+"-"+value.substring(6);
- } else if (value.length > 5) {
- this.value = value.substring(0,4)+"-"+value.substring(4);
- }
- })
- .on("paste", function(e) {
- var value = e.originalEvent.clipboardData.getData('text');
- if (value.length == 8)
- this.value = value.substring(0,4)+"-"+value.substring(4,6)+"-"+value.substring(6);
- });
-
- var calendarIcon = $(this).next("button.bx-calendar");
- if (calendarIcon.length > 0) {
- $(calendarIcon).on("click", function() {
- $(this).prev().focus();
- });
- }
- });
-}
-
-/**
- * @param fromSource 시작값을 갖는 input의 selector
- * @param toSource 종료값을 갖는 input의 selector
- */
-function inputsInRange(fromSource, toSource) {
- var from = $(fromSource),
- to = $(toSource),
- compare = function() {
- var fromVal = from.val() || "",
- toVal = to.val() || "",
- ok = toVal >= fromVal;
- if (ok) return;
-
- if ($(this)[0] == from[0])
- to.val(from.val())
- else
- from.val(to.val());
- };
- from.change(compare);
- to.change(compare);
-}
-
-function ignore() {
- console.log.apply(console, arguments);
-}
-
-function fileInput(conf) {
- conf = conf || {};
- var name = conf.name || "upload",
- tag = "
"
- .replace(/{name}/, name)
- .replace(/{multiple}/, conf.multiple ? " multiple" : "")
- .replace(/{accept}/, conf.accept ? " accept='" + conf.accept + "'" : ""),
- obj = {
- name:name,
- input:null,
- files:[],
-
- select:function(onSelect) {
- if (!obj.input) {
- var input = obj.input = $(tag);
- $("body").append(input);
- input.change(function() {
- var files = $(this).get(0).files,
- length = files.length,
- selected = [];
- for (var i = 0; i < length; ++i) {
- var file = files[i];
- file.id = name + (obj.files.length);
- selected.push(file);
- obj.files.push(file);
- }
- onSelect(selected);
- })
- }
- obj.input.click();
- },
-
- getFiles:function() {
- return obj.files;
- },
-
- remove:function(id) {
- if (!id) return;
-
- var files = obj.files;
- for (var i = 0; i < files.length; ++i) {
- var file = files[i];
- if (id == file.id) {
- files.splice(i, 1);
- break;
- }
- }
- },
-
- clear:function() {
- if (obj.input)
- $(obj.input).remove();
- obj.input = null;
- obj.files.forEach(function(file) {delete file;});
- obj.files = [];
- }
- };
- return obj;
-}