diff --git a/pom.xml b/pom.xml
index 048634e9..5cb68819 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
parse(arg)
that parses the argument for a valueformat(arg)
that formats the argument to a stringlet valueFormats = new ValueFormat({
- * key0: numberFormat,
- * key1: dateFormat,
- * key2: {
- * format(value) {...},
- * parse(value) {...}
- * }
- * })
- */
-class ValueFormat {
- _formats;
- _exprs;
-
- /**Creates a new ValueFormat.
- * @param {object} formats an object whose property names are keys and property values are value formats associated with the keys
- */
- constructor(formats) {
- this._formats = formats || {};
- this._exprs = {};
- }
-
- /**Returns a parser associated with the key.
- * @param {string} key key associated with a value format
- * @returns {function}
- * For a Dataset to work properly, it needs a keymapper to identify user data. - * And you specify it in a Dataset's configuration. - *
let dataset = new Dataset({
- * keymapper: function(info) {return info.keyProperty;},
- * ...
- * });
- *
- * To help access values of user data, a Dataset offers methods - *
let dataset = new Dataset({
- * formats: {
- * numericProperty: {@link numberFormat},
- * customProperty: {
- * format(value) {...},
- * parse(value) {...},
- * }
- * },
- * ...
- * });
- *
- * Working with user data that a Dataset holds, you change the Dataset's state. - * Depending on the type of change, the Dataset calls back approriate methods. - * By default, the methods log the content of the change. - *
- *To override the behavior of the callback methods, - * define a function with the same signature as the method to override - * and assign it to the Dataset's method. - *
let myFunc = obj => {...};
- * let dataset = new Dataset({...});
- * dataset.onDatasetChange = myFunc;
- * You can make it simple like this:
- * let dataset = new Dataset({...});
- * dataset.onDatasetChange = obj => {};
- *
- * Or you specify an overriding function in the configuration used to create a Dataset. - *
let dataset = new Dataset({
- * ...
- * onDatasetChange:obj => {...}
- * });
- *
- */
-class Dataset {
- _items;
- _byKeys;
- _current;
-
- /**Dataset configuration
- */
- conf;
- _formats;
-
- /**Creates a new Dataset with a configuration.
- * The configuration is an object with which you specify
- * dataset.select("key0", true)
- * //To select multiple user data
- * dataset.select(["key0", "key1"])
or dataset.select(["key0", "key1"], true)
- * //To select all user data
- * dataset.select()
or dataset.select(true)
- * //To unselect a user data
- * dataset.select("key0", false)
- * //To unselect multiple user data
- * dataset.select(["key0", "key1"], false)
- * //To unselect all user data
- * dataset.select(false)
- */
- select(...args) {
- let arg0 = ifEmpty(args[0], true),
- arg1 = ifEmpty(args[1], true),
- dirty = false,
- fire = false;
- if ("boolean" == typeof arg0) {
- for (let i = 0, length = this.length; i < length; ++i) {
- dirty = this._items[i].select(arg0) || dirty;
- }
- fire = args[1];
- } else {
- let keys = Array.isArray(arg0) ? arg0 : [arg0];
- for (let i = 0; i < keys.length; ++i) {
- let item = this.getData(keys[i], "item");
- if (item)
- dirty = item.select(arg1) || dirty;
- }
- fire = args[2];
- }
- if (dirty || fire) {
- this.onSelectionChange(this.getDataset("selected"));
- }
- return dirty;
- }
-
- /**Toggles selection of the user data associated with the key.
- * After the selection change, the method
- * - {@link Dataset#onSelectionChange}
- *
- * is called.
- * @param {string} key key associated with user data
- * @returns {boolean} selection status of the user data
- * - true if the user data is selected
- * - false otherwise
- *
- */
- toggle(key) {
- let item = this.getData(key, "item"),
- status = item ? item.toggle() : false;
- this.onSelectionChange(this.getDataset("selected"));
- return status;
- }
-
- /**appends user data to the Dataset.
- * After the user data is appended, the methods
- * - {@link Dataset#onAppend}
- * - {@link Dataset#onCurrentChange}
- * - {@link Dataset#onSelectionChange}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty)
- *
- * are called.
- * @param data {object|array} user data or array of user data
- * @returns the Dataset
- */
- append(data) {
- if (!data) return this;
-
- let notDirty = !this.dirty,
- array = Array.isArray(data) ? data : [data];
- array.forEach(e => {
- let item = new DataItem(e, this._formats);
- this._items.push(item);
-
- let key = this.getKey(e);
- this._byKeys["key-" + key] = item;
- item.state = "added";
- });
-
- let state = this.state;
- this.onAppend(array);
- state.currentKey = this.getKey(array[array.length - 1]);
- this.setState(state);
-
- if (notDirty)
- this.onDirtiesChange(true);
-
- return this;
- };
-
- /**Modifies user data associated with the key using the modifier.
- * After user data modification, the methods
- * - {@link Dataset#onModify}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty)
- *
- * are called.
- * @param {string} key key to a Dataset's user data
- * @param {function} modifier function that modifies the user data.
- * The function must have a sigunature that accepts a DataItem.
- * If the modification fails, it must return ValueFormat.InvalidValue.
- * @returns the Dataset
- * @example
- * let v = ...;
- * let modifier = (dataItem) => {
- * if (v !== ...)
- * return ValueFormat.InvalidValue;
- * let data = dataItem.data;
- * data.prop = v;
- * };
- * ...
- * dataset.modify("key0", modifier);
- */
- modify(key, modifier) {
- if (!modifier) return this;
-
- let item = this.getData(key, "item");
- if (!item)
- return log("Item not found with " + key);
-
- let notDirty = !this.dirty,
- data = item.data,
- prev = Object.assign({}, data),
- modifiedProps = (prev, data) => {
- let changed = [];
- for (let prop in data) {
- let oldVal = prev[prop],
- newVal = data[prop];
- if (oldVal != newVal)
- changed.push(prop);
- }
- return changed;
- };
-
- let current = data == this.getCurrent(),
- revert = modifier(item) == ValueFormat.InvalidValue,
- changed = modifiedProps(prev, data);
-
- if (changed.length > 0) {
- if (!item.state)
- item.state = "modified";
- this.onModify(changed, item, current);
- if (notDirty)
- this.onDirtiesChange(true);
- } else if (revert) {
- this.onModify(Object.getOwnPropertyNames(data), item, current);
- }
-
- return this;
- }
-
- /**Replaces the Dataset's user data with the replacement.
- * After replacement, the methods
- * - {@link Dataset#onReplace}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty or not dirty)
- *
- * are called.
- * @param {object|array} replacement
- * replacement is an object or an array of objects of the following properties.
- * - key - key to the user data to be replaced
- * - data - new user data
- *
- * @returns {Dataset} the Dataset
- * @example
- * //To replace old-keyed user data with new-keyed user data.
- * dataset.replace({key:"old-key", data:{id:"new-key", ...}});
- * //or
- * dataset.replace([
- * {key:"old-key0", data:{id:"new-key0", ...}},
- * {key:"old-key1", data:{id:"new-key1", ...}},
- * ]);
- * //To replace user data with equal-keyed user data
- * dataset.replace({data:{id:"key0", ...}});
- * //or
- * dataset.replace([
- * {data:{id:"key0", ...}},
- * {data:{id:"key1", ...}},
- * ]);
- */
- replace(replacement) {
- if (isEmpty(replacement)) return this;
-
- let before = this.dirty,
- replacements = Array.isArray(replacement) ? replacement : [replacement],
- replacing = [];
- replacements.forEach(obj => {
- let data = obj.data;
- if (!data) return;
-
- let key = obj.key || this.getKey(data);
- if (!key) return;
-
- let oldItem = this.getData(key, "item"),
- newItem = new DataItem(data, this._formats),
- pos = oldItem ? this._items.indexOf(oldItem) : -1;
-
- newItem.selected = oldItem && oldItem.selected;
- if (pos > -1)
- this._items[pos] = newItem;
- else
- this._items.push(newItem);
-
- delete this._byKeys["key-" + key];
- this._byKeys["key-" + this.getKey(data)] = newItem;
-
- if (this._current == oldItem)
- this._current = newItem;
-
- replacing.push(newItem);
- });
- this.onReplace(replacing);
- let after = this.dirty;
- if (before != after)
- this.onDirtiesChange(after);
-
- return this;
- }
-
- /**Removes user data associated with the key.
- * After user data removal, the methods
- * - {@link Dataset#onRemove}
- * - {@link Dataset#onCurrentChange}
- * - {@link Dataset#onSelectionChange}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty or not dirty)
- *
- * are called.
- * @param {string|array} key key or keys to user data
- * @returns {Dataset} the Dataset
- * @example
- * dataset.remove("key0");
- * dataset.remove(["key0", "key1"]);
- */
- remove(key) {
- if (!key || this.empty) return this;
-
- let before = this.dirty,
- keys = Array.isArray(key) ? key : [key],
- removed = this._items.filter(item => {
- let k = this.getKey(item.data),
- remove = keys.includes(k);
- if (remove) {
- item.state = "added" == item.state ? "ignore" : "removed";
- }
- return remove;
- }),
- currentPos = this._items.indexOf(this._current),
- state = this.state;
-
- if (currentPos > -1) {
- let newKey = null;
- for (let i = currentPos, length = this._items.length; i < length; ++i) {
- let item = this._items[i];
- if (item.unreachable) continue;
-
- newKey = this.getKey(item);
- break;
- }
- if (!newKey)
- for (let i = this._items.length - 1; i > 0; --i) {
- let item = this._items[i];
- if (item.unreachable) continue;
-
- newKey = this.getKey(item);
- break;
- }
- state.currentKey = newKey;
- }
- this.onRemove(removed);
- this.setState(state);
- let after = this.dirty;
- if (before != after)
- this.onDirtiesChange(after);
-
- return this;
- }
-
- /**Erases user data associated with the key.
- * After user data removal, the methods
- * - {@link Dataset#onCurrentChange}
- * - {@link Dataset#onSelectionChange}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty or not dirty)
- *
- * are called.
- * Note that unlike {@link Dataset#remove} this method deletes user data completely from the Dataset
- * and the erased user data are not traced as dirty user data.
- * @param {string|array} key key or keys to user data
- * @returns {Dataset} the Dataset
- * @example
- * dataset.erase("key0");
- * dataset.erase(["key0", "key1"]);
- */
- erase(key) {
- if (!key || this.empty) return;
-
- let before = this.dirty,
- keys = Array.isArray(key) ? key : [key],
- erased = this._items.filter(item => {
- let k = this.getKey(item.data),
- erase = keys.indexOf(k) > -1;
- if (erase) {
- delete this._byKeys["key-" + k];
- }
- return erase;
- });
-
- let currentPos = erased.indexOf(this._current) > -1 ? this._items.indexOf(this._current) : -1,
- state = this.state;
-
- if (currentPos > -1) {
- let newKey = null;
- for (let i = currentPos + 1, length = this._items.length; i < length; ++i) {
- let item = this._items[i];
- if (item.unreachable || erased.includes(item)) continue;
-
- newKey = this.getKey(item);
- break;
- }
- if (!newKey)
- for (let i = this._items.length - 1; i > 0; --i) {
- let item = this._items[i];
- if (item.unreachable || erased.includes(item)) continue;
-
- newKey = this.getKey(item);
- break;
- }
- state.currentKey = newKey;
- }
- this._items = this._items.filter(function(item){return !erased.includes(item);});
-
- this.onRemove(erased);
- this.setState(state);
- let after = this.dirty;
- if (before != after)
- this.onDirtiesChange(after);
- }
-
- /**Returns an array of strings converted from the template using the property values of the Dataset's user data.
- * In the template, placeholder for the properties of the user data is specified like {property name}.
- * @param {string} template template string
- * @param {function} formatter function to format a row string with custom property placeholders
- * @returns {array} array of strings converted from the template using the property values of the user data
- */
- inStrings(template, formatter) {
- return this.getDataset("item")
- .map(item => item.inString(template, formatter));
- }
-
- /**Returns a property value of user data.
- * If a value format is associated with the property, the value is formatted.
- * @param args See the example
- * @returns {any|string} property value of a user data
- * @example
- * //To get a property value of user data associated with a key
- * let value = dataset.getValue("key0", "property0");
- * //To get a property value of current user data
- * let value = dataset.getValue("property0");
- */
- getValue(...args) {
- let key = null,
- property = null;
- switch (args.length) {
- case 1:
- key = this.getKey(this.getCurrent());
- property = args[0];
- break;
- case 2:
- key = args[0];
- property = args[1];
- break;
- default: return null;
- }
-
- let item = this.getData(key, "item");
- return item ? item.getValue(property) : undefined;
- }
-
- /**Sets a value to a property of user data.
- * If a value format is associated with the property, the value is parsed before setting to user data.
- * After setting the value, the methods
- * - {@link Dataset#onModify}
- * - {@link Dataset#onDirtiesChange}(if the Dataset gets dirty)
- *
- * are called.
- * @param args See the example
- * @example
- * //To set a value to a property of user data associated with a key
- * dataset.setValue("key0", "property0", "value0");
- * //To set a value to a property of current user data
- * dataset.setValue("property0", "value0");
- */
- setValue(...args) {
- let key = null,
- property = null,
- value = null;
- switch (args.length) {
- case 2:
- key = this.getKey(this.getCurrent());
- property = args[0];
- value = args[1];
- break;
- case 3:
- key = args[0];
- property = args[1];
- value = args[2];
- break;
- default: return this;
- }
- return this.modify(key, function(item){
- return item.setValue(property, value);
- });
- }
-
- /**Called back when user data are set.
- * @param {object|array} obj object that has user data or an array of user data
- */
- onDatasetChange(obj) {this.log("Dataset changed", obj);}
-
- /**Called back when current user data is changed.
- * @param {DataItem} currentItem current dataItem
- */
- onCurrentChange(currentItem) {this.log("Current changed", currentItem);}
-
- /**Called back when user data selection changes.
- * @param {array} selected array of selected user data
- */
- onSelectionChange(selected) {this.log("Selection changed", selected);}
-
- /**Called back when user data is appended.
- * @param {object|array} appended user data or array of user data
- */
- onAppend(appended) {this.log("Data appended", appended);}
-
- /**Called back when user data is modified.
- * @param {array} props names of changed properties
- * @param {DataItem} modified modified user dataItem
- * @param {boolean} current whether current user data is modified
- */
- onModify(props, modified, current) {this.log("Data modified", props, modified, current ? "current" : "");}
-
- /**Called back when user data are replaced.
- * @param {array} replacing array of user dataItems replacing the old ones
- */
- onReplace(replacing) {this.log("Data replaced", replacing);}
-
- /**Called back when user data are removed.
- * @param {array} removed array of removed dataItems
- */
- onRemove(removed) {this.log("Data removed", removed)}
-
- /**Called back when the Dataset gets dirty or not dirty.
- * @param {boolean} dirty
- * - true if the Dataset is dirty
- * - false otherwise
- *
- */
- onDirtiesChange(dirty){this.log("Dirties change", dirty);}
-}
-
-class DatasetControl {
- constructor(conf) {
- notEmpty(conf.keymapper, "keymapper");
- this.prefix = conf.prefix;
- this.prefixName = conf.prefixName;
- this.infoSize = conf.infoSize;
- this.appendData = conf.appendData;
-
- this.query = {};
-
- conf.onDatasetChange = obj => this.onDatasetChange(obj),
- conf.onCurrentChange = item => this.onCurrentChange(item),
- conf.onSelectionChange = selected => this.onSelectionChange(selected),
- conf.onAppend = items => this.onAppend(items),
- conf.onModify = (props, modified, current) => {
- let info = this.dataset.getCurrent("item");
- if (!info || "added" == info.state)
- return;
- this.onModify(props, modified, current);
- }
-
- this.dataset = new Dataset(conf);
-
- this.urls = conf.urls || {
- load:this.url("/list.do"),
- getInfo:this.url("/info.do"),
- create:this.url("/create.do"),
- update:this.url("/update.do"),
- remove:this.url("/remove.do")
- };
- }
-
- prefixed(str) {
- return (this.prefix || "") + str;
- }
-
- url(str) {
- return wctx.url("/" + this.prefixed(str));
- }
-
- load(pageNum) {
- this.query.pageNum = pageNum;
- this._load();
- }
-
- _load() {
- if (!this.query.pageNum)
- this.query.pageNum = 1;
-
- ajax.get({
- url:this.urls.load,
- data:this.query,
- success:resp => {
- if (!this.appendData || this.query.pageNum == 1)
- this.setData(resp);
- else {
- this.addData(resp);
- }
- }
- });
- }
-
- download(type) {
- this.query.download = type || "xls";
- let query = toQuery(this.query);
- this.query.download = null;
- document.location.href = this.urls.load + "?" + query;
- }
-
- setData(obj) {
- this.dataset.setData(obj);
- }
-
- addData(obj) {
- this.dataset.addData(obj);
- }
-
- onDatasetChange(obj) {
- debug("onDatasetChange", obj);
- }
-
- getCurrent(option) {
- return this.dataset.getCurrent(option);
- }
-
- setCurrent(key) {
- this.dataset.setCurrent(key);
- }
-
- onCurrentChange(item) {
- debug(item);
- }
-
- select(key, selected) {
- this.dataset.select(key, selected);
- }
-
- onSelectionChange(selected) {
- debug(selected);
- }
-
- getInfo(params) {
- let info = this.dataset.getCurrent("item");
- if (this.urls.getInfo)
- ajax.get({
- url:this.urls.getInfo,
- data:params || {},
- success:resp => {
- resp = resp.replace(/infoPrefix/g, this.prefix)
- .replace(/prefixName/g, this.prefixName)
- dialog.open({
- id:this.prefixed("dialog"),
- title: this.prefixName + " 정보",
- content:resp,
- size:this.infoSize,
- init:() => this.setInfo(info)
- });
- }
- });
- else
- this.setInfo(info);
- }
-
- setInfo(info) {}
-
- newInfo(obj) {
- this.dataset.append(obj || {});
- this.getInfo();
- }
-
- getValue(name) {
- return this.dataset.getValue(name);
- }
-
- setValue(name, value) {
- this.dataset.setValue(name, value);
- }
-
- onAppend(items) {
- debug("on append", items);
- }
-
- onModify(props, modified, current) {
- debug("on modify", props, "modified", modified, "current", current);
- }
-
- save(info) {
- if (!info) return;
- let item = this.getCurrent("item"),
- create = "added" == item.state;
-
- ajax.post({
- url:!create ? this.urls.update : this.urls.create,
- data:info,
- success:resp => this.onSave(resp)
- });
- }
-
- onSave(resp) {
- if (resp.saved) {
- dialog.alert("저장됐습니다.");
- dialog.close(this.prefixed("dialog"));
- this._load();
- }
- }
-
- remove(params) {
- let selected = this.dataset.getKeys("selected");
- if (selected.length < 1) return;
-
- if (!params) {
- params = {};
- params[this.prefixed("IDs")] = selected.join(",");
- }
-
- ajax.post({
- url:this.urls.remove,
- data:params,
- success:resp => this.onRemove(selected, resp)
- });
- }
-
- onRemove(selected, resp) {
- if (resp.saved)
- this._load();
- }
-
- bindInputs(obj, selector) {
- let inputs = ["input", "select", "textarea"].map(tag => selector + " " + tag).join(","),
- setChanged = evt => {
- let input = evt.target,
- name = input.getAttribute("data-map"),
- val = input.value;
- this.setValue(name, val);
- };
-
- document.querySelectorAll(inputs).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);
- });
- }
-}
\ No newline at end of file
diff --git a/src/main/webapp/resources/js/base/menu-support.js b/src/main/webapp/resources/js/base/menu-support.js
deleted file mode 100644
index a41dc26b..00000000
--- a/src/main/webapp/resources/js/base/menu-support.js
+++ /dev/null
@@ -1,292 +0,0 @@
-/**메뉴의 생성과 선택 시 동작을 지원한다.
- */
-class MenuSupport {
- /**새 MenuSupport를 생성한다.
- * @param selector {string} 메뉴를 담을 컨테이너에 대한 css selector
- */
- constructor(conf) {
- conf = conf || {};
- this._selector = ifEmpty(conf.selector, "#menus");
- this._containerSelector = ifEmpty(conf.containerSelector, "#layout-menu");
- this._container = document.querySelector(this._containerSelector);
- let onclick = conf.onclick || (menu => 'onclick="openMenu(\'{url}\')" '.replace(/{url}/gi, wctx.url(menu.url)));
- this._onclick = (menu => menu && menu.url ? onclick(menu) : "");
-
- this._horizontal = this._container && this._container.classList.contains('menu-horizontal');
- this._orientation = this._horizontal ? "horizontal" : "vertical";
- this._template = this._orientation + "-menu-template";
- this._menuItem = '{menuName}{menuSub} ';
- this._menuSub = ' ';
- this._menus = [];
- this._init();
- }
-
- /**메뉴를 생성할 정보를 설정한다.
- * @param menus {array} 메뉴 정보 배열
- * 각 메뉴 정보의 레이아웃은 다음과 같다.
- * {"id":메뉴 아이디, "name":"메뉴 이름", "url":"실행 url", "parentID":"상위 메뉴 아이디", "description":"메뉴 설명", "imageConf":"이미지 설정", "displayWindow":"표시 창", "children":[하위 메뉴 배열]}
- * @returns MenuSupport
- */
- setMenuInfo(menus) {
- let setParent = menu => {
- let children = menu.children || [];
- if (children.length < 1) return;
-
- children.forEach(child => {
- child.parent = menu;
- setParent(child);
- });
- };
- menus.forEach(menu => setParent(menu));
- this._menus = menus;
-
- let menuItemTag = menu => {
- let tag = this._menuItem
- .replace(/{menuID}/gi, menu.id)
- .replace(/{menuName}/gi, menu.name)
- .replace(/{onclick}/gi, this._onclick(menu))
- .replace(/{title}/gi, (menu.description || ""))
- .replace(/{imageConf}/gi, (menu.imageConf || "bx bx-layout"));
- let parent = menu.children && menu.children.length > 0;
- tag = tag.replace(/{toggle}/gi, !parent ? "" : " menu-toggle");
- if (!parent)
- return tag.replace(/{menuSub}/gi, "");
-
- let children = menu.children.map(child => menuItemTag(child)).join("\n\t")
- return tag.replace(/{menuSub}/gi, this._menuSub.replace(/{children}/gi, children));
- }
- let tags = (menus || []).map(menu => menuItemTag(menu));
- document.querySelector(this._selector).innerHTML = tags.join("");
-
- return this._init();
- }
-
- _toggleMenuAwares(collapse) {
- document.querySelectorAll(".menu-aware").forEach(menuAware => menuAware.style.width = collapse ? "calc(100% - 5.25rem)" : "");
- }
-
- _init() {
- let menu = new Menu(this._container, {
- orientation: this._orientation,
- closeChildren: this._horizontal,
- showDropdownOnHover: localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover')
- ? localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover') === 'true'
- : window.templateCustomizer !== undefined
- ? window.templateCustomizer.settings.defaultShowDropdownOnHover
- : true
- });
- window.Helpers.scrollToActive(false); //animate = false
- window.Helpers.mainMenu = menu;
-
- //Sets toggler
- document.querySelectorAll('.layout-menu-toggle').forEach(item => {
- item.addEventListener('click', event => {
- if (event.fired) {
- return delete event.fired;
- }
- event.fired = true;
- event.preventDefault();
- window.Helpers.toggleCollapsed();
- if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
- try {
- localStorage.setItem(
- 'templateCustomizer-' + this._template + '--LayoutCollapsed',
- String(window.Helpers.isCollapsed())
- );
- } catch (e) {}
- }
- this._toggleMenuAwares(Helpers.isCollapsed());
- });
- });
- // Display menu toggle (layout-menu-toggle) on hover with delay
- let delay = (elem, callback) => {
- let timeout = null;
- elem.onmouseenter = () => {
- // Set timeout to be a timer which will invoke callback after 300ms (not for small screen)
- timeout = !Helpers.isSmallScreen() ? setTimeout(callback, 300) : setTimeout(callback, 0);
- };
-
- elem.onmouseleave = () => {
- // Clear any timers set to timeout
- document.querySelector('.layout-menu-toggle').classList.remove('d-block');
- clearTimeout(timeout);
- };
- };
- if (this._container) {
- delay(this._container, () => {
- // not for small screen
- if (!Helpers.isSmallScreen()) {
- document.querySelector('.layout-menu-toggle').classList.add('d-block');
- }
- });
- }
- // Detect swipe gesture on the target element and call swipe In
- window.Helpers.swipeIn('.drag-target', function (e) {
- window.Helpers.setCollapsed(false);
- });
- // Detect swipe gesture on the target element and call swipe Out
- window.Helpers.swipeOut(this._containerSelector, function (e) {
- if (window.Helpers.isSmallScreen()) window.Helpers.setCollapsed(true);
- });
- // Display in main menu when menu scrolls
- let menuInnerContainer = document.getElementsByClassName('menu-inner'),
- menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0];
- if (menuInnerContainer.length > 0 && menuInnerShadow) {
- menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
- if (this.querySelector('.ps__thumb-y').offsetTop) {
- menuInnerShadow.style.display = 'block';
- } else {
- menuInnerShadow.style.display = 'none';
- }
- });
- }
-
- return this;
- }
-
- open(url) {
- top.document.location.href = url;
- }
-
- /**지정한 url의 메뉴를 활성화 한다.
- * @param url {string} 메뉴 url
- * @returns MenuSupport
- */
- setActive(url) {
- let menu = this.getMenu(url);
- if (!menu) return this;
-
- document
- .querySelectorAll(this._selector + " li")
- .forEach(li => li.classList.remove("active", "open"));
-
- let a = document.querySelector(this._selector + " li[data-key=\"" + menu.id + "\"]");
- if (!a) return this;
-
- let activate = (e, open) => {
- e.classList.add("active");
-
- let p = e.parentNode;
- let tag = (p != this._container ? p : null) ? p.tagName : "";
- if (!tag) return;
-
- if ("li" == tag.toLowerCase()) {
- p.classList.add("active");
- if (open)
- p.classList.add("open");
- }
- activate(p, true);
- };
-
- activate(a);
-
- return this;
- }
-
- /**지정하는 url의 메뉴 정보를 반환한다.
- * @param url {string} 메뉴 url
- * @returns 지정하는 url의 메뉴 정보
- */
- getMenu(url) {
- let find = menus => {
- for (let i = 0; i < menus.length; ++i) {
- let menu = menus[i];
- if (url == menu.url)
- return menu;
- let found = find(menu.children || []);
- if (found)
- return found;
- }
- return null;
- };
- return find(this._menus);
- }
-
- breadcrumb(url, separator = " / ") {
- let menu = this.getMenu(url);
- if (!menu)
- return "";
-
- let getName = menu => {
- let name = menu.name;
- let parent = !menu.parent ? "" : getName(menu.parent);
- return parent ? parent + separator + name : name;
- }
-
- return getName(menu);
- }
-}
-
-class TabControl extends Dataset {
- constructor(conf) {
- if (!conf)
- conf = {};
- conf.keymapper = info => {
- if (!info.index) {
- info.index = "ndx-" + new Date().getTime();
- }
- return info.index;
- };
- conf.dataGetter = obj => null;
- super(conf);
- this.sticky = conf.sticky || {};
- this.maxCount = conf.maxCount || 8;
- this.getMenu = conf.getMenu || ((url) => {throw "getMenu(url) missing"});
-
- }
-
- getTab(by) {
- if (by.startsWith("ndx-"))
- return this.getData(by, "item");
-
- if (by != this.sticky.url) {
- let found = this._items.filter(item => item.data.url == by),
- empty = !found || found.length < 1;
- if (empty)
- return null;
-
- found = found[0];
- return !found.unreachable ? found : null;
- } else {
- let found = this._items.filter(item => item.data.url == this.sticky.url);
- if (!found || found.length < 1) {
- this.addData([this.sticky]);
- }
- }
- }
-
- open(url) {
- if (!url
- || url.startsWith("javascript:void")
- || url == this.sticky.url)
- return;
-
- let tab = this.getTab(url);
- if (tab)
- return this.setCurrent(tab.data.index);
-
- ajax.get({
- url: wctx.url(url),
- success: resp => {
- let menu = this.getMenu(url);
- if (!menu)
- throw "Menu not found for " + url;
-
- if (this.length == this.maxCount) {
- let index = isEmpty(this.sticky) ? 0 : 1,
- first = this._items[index];
- this.close(first.data.url)
- }
-
- menu.content = resp;
- this.addData([menu]);
- this.open(url);
- }
- });
- }
-
- close(url) {
- let tab = this.getTab(url);
- this.erase(tab.data.index);
- }
-}
\ No newline at end of file
diff --git a/src/main/webapp/resources/js/base/menu.js b/src/main/webapp/resources/js/base/menu.js
deleted file mode 100644
index 13b9b957..00000000
--- a/src/main/webapp/resources/js/base/menu.js
+++ /dev/null
@@ -1,77 +0,0 @@
-class MenuControl extends DatasetControl {
- constructor() {
- super({
- keymapper: info => info ? info.id : "",
- prefix:"menu",
- prefixName:"메뉴"
- });
-
- this.urls.load = this.url("/tree.do");
- delete this.urls.getInfo;
- this.menus = [];
- }
-
- setData(obj) {
- let list = [];
- let asList = array => {
- if (!array || array.length < 1) return;
-
- for (var i = 0; i < array.length; ++i) {
- let menu = array[i];
- list.push(menu);
- asList(menu.children);
- }
- };
- asList(this.menus = Array.isArray(obj) ? obj : obj.menus);
- super.setData(list);
- }
-
- move(parentID, menuID) {
- json.post({
- url:wctx.url("/menu/move.do"),
- data:{
- parentID:parentID,
- menuIDs:menuID
- },
- success:resp => {
- this._load();
- this.onMenusChanged();
- }
- });
- }
-
- reorder(menuIDs) {
- json.post({
- url:wctx.url("/menu/reorder.do"),
- data:{
- menuIDs:Array.isArray(menuIDs) ? menuIDs.join(",") : menuIDs
- },
- success:resp => {
- this._load();
- this.onMenusChanged();
- }
- });
- }
-
- onSave(resp) {
- super.onSave(resp);
- this.onMenusChanged();
- }
-
- onRemove(selected, resp) {
- super.onRemove(selected, resp);
- this.onMenusChanged();
- }
-
- onMenusChanged() {}
-
- async getUserMenus() {
- return new Promise((resolve, reject) => {
- json.get({
- url:this.url("/userMenus.do"),
- data:{},
- success:resp => resolve(resp.userMenus)
- });
- });
- }
-}
\ No newline at end of file