gaga.agGrid.js 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874
  1. /*
  2. * ag-Grid(https://www.ag-grid.com) Common Java Script written by gagamel.
  3. *
  4. * Copyright (c) 2019 gagamel
  5. * Dual licensed under GPL (GPL-LICENSE.txt) licenses.
  6. *
  7. * $Date: 2019-03-31 $
  8. */
  9. var isNavigationKey = function(event) {
  10. var KEY_LEFT = 37;
  11. var KEY_UP = 38;
  12. var KEY_RIGHT = 39;
  13. var KEY_DOWN = 40;
  14. var KEY_PAGE_UP = 33;
  15. var KEY_PAGE_DOWN = 34;
  16. var KEY_PAGE_HOME = 36;
  17. var KEY_PAGE_END = 35;
  18. var keyCode = event.keyCode;
  19. return keyCode === KEY_LEFT || keyCode === KEY_RIGHT || keyCode === KEY_UP || keyCode === KEY_DOWN
  20. || keyCode === KEY_PAGE_DOWN || keyCode === KEY_PAGE_UP || keyCode === KEY_PAGE_HOME || keyCode === KEY_PAGE_END;
  21. }
  22. /**
  23. * Customer loading
  24. * @author gagamel
  25. * @since 2019. 4. 10
  26. */
  27. var getCustomLoadingOverlay = function() {
  28. function CustomLoadingOverlay() {};
  29. CustomLoadingOverlay.prototype.init = function(params) {
  30. this.eGui = document.createElement('div');
  31. this.eGui.innerHTML = ''
  32. + '<div style="'
  33. + 'background: url(/ux/plugins/gaga/loader.gif); border-style: none; background-repeat: no-repeat; '
  34. + 'position: absolute; top: 45%; left: 50%; width: auto; '
  35. + 'z-index: 101; padding: 16px; margin: 5px;'
  36. + '"></div>';
  37. };
  38. CustomLoadingOverlay.prototype.getGui = function() {
  39. // Button disabled & progressBar creation
  40. //$('.btn').each(function(idx) { $(this).attr('disabled', true); });
  41. return this.eGui;
  42. };
  43. return CustomLoadingOverlay;
  44. }
  45. /**
  46. * Datepicker component
  47. * <pre>
  48. * cellEditor : 'datePicker'
  49. * </pre>
  50. * @author gagamel
  51. * @since 2019. 4. 8
  52. */
  53. var getDatePicker = function(pattern) {
  54. if (typeof(pattern) == 'undefined') {
  55. pattern = "yyyy/mm/dd";
  56. }
  57. // function to act as a class
  58. function Datepicker() {};
  59. // gets called once before the renderer is used
  60. Datepicker.prototype.init = function(params) {
  61. this.eGui = document.createElement('div');
  62. this.eGui.innerHTML = '<input'
  63. + ' name="' + params.colDef.field + '"'
  64. + (!gagajf.isNull(params.value) ? ' value="' + params.value + '"' : '')
  65. + (!gagajf.isNull(params.maxlength) ? ' maxlength="' + params.maxlength + '"' : '')
  66. + (!gagajf.isNull(params.validType) ? ' data-valid-type="' + params.validType + '"' : '')
  67. + ' style="width: 100%; z-index: 999999"/>';
  68. this.eInput = this.eGui.querySelector('input');
  69. if (params.required) {
  70. this.eInput.required = 'required';
  71. // this.eInput.classList.add('required');
  72. }
  73. $(this.eInput).datepicker({
  74. startView: 0,
  75. format: pattern,
  76. todayBtn: "linked",
  77. keyboardNavigation: false,
  78. forceParse: false,
  79. autoclose: true,
  80. todayHighlight: true,
  81. onSelect: function(dateText, inst) {
  82. params.stopEditing();
  83. }
  84. });
  85. };
  86. // gets called once when grid ready to insert the element
  87. Datepicker.prototype.getGui = function() {
  88. return this.eGui;
  89. };
  90. // focus and select can be done after the gui is attached
  91. Datepicker.prototype.afterGuiAttached = function() {
  92. this.eInput.focus();
  93. this.eInput.select();
  94. };
  95. // returns the new value after editing
  96. Datepicker.prototype.getValue = function() {
  97. return this.eInput.value;
  98. };
  99. // any cleanup we need to be done here
  100. Datepicker.prototype.destroy = function() {
  101. // but this example is simple, no cleanup, we could
  102. // even leave this method out as it's optional
  103. };
  104. // if true, then this editor will appear in a popup
  105. Datepicker.prototype.isPopup = function() {
  106. // and we could leave this method out also, false is the default
  107. return true;
  108. };
  109. return Datepicker;
  110. }
  111. /**
  112. * Datepicker component
  113. * <pre>
  114. * cellEditor : 'dateTimer'
  115. * </pre>
  116. * @author gagamel
  117. * @since 2020. 1. 09
  118. */
  119. var getDateTimer = function(pattern) {
  120. // function to act as a class
  121. function DateTimer() {};
  122. // gets called once before the renderer is used
  123. DateTimer.prototype.init = function(params) {
  124. this.eGui = document.createElement('div');
  125. // 시간 초기화
  126. var TimeH = '';
  127. var TimeM = '';
  128. var SecGb = params.colDef.field;
  129. if( SecGb.indexOf('ed') > -1 || SecGb.indexOf('end') > -1) {
  130. TimeH = '23';
  131. TimeM = '59';
  132. this.sec = '59';
  133. }else{
  134. TimeH = '00';
  135. TimeM = '00';
  136. this.sec = '00';
  137. }
  138. if(typeof(params.value) != 'undefined') {
  139. var time = params.value.split(":");
  140. TimeH = time[0];
  141. TimeM = time[1];
  142. }
  143. // 시간 셀렉트 박스
  144. var time = 0;
  145. var Hhtml = '';
  146. Hhtml += '<select name="' + params.colDef.field + 'H">\n';
  147. for (var i = 0; i < 24; i++) {
  148. time = i;
  149. if ( time < 10)
  150. time = '0' + time;
  151. if (TimeH != i) {
  152. Hhtml += '<option value="' + time + '">' + time + '시</option>\n';
  153. } else {
  154. Hhtml += '<option selected="selected" value="' + time + '">' + time + '시</option>\n';
  155. }
  156. }
  157. Hhtml += '</select>\n';
  158. this.eGui.innerHTML = Hhtml;
  159. this.eSelectH = this.eGui.querySelector('select');
  160. this.eSelectH.innerHTML = Hhtml;
  161. // 분 셀렉트 박스
  162. time = 0;
  163. var Mhtml ='';
  164. Mhtml = '<select name="' + params.colDef.field + 'M">\n';
  165. for (var i = 0; i < 60; i++) {
  166. time = i;
  167. if ( time < 10)
  168. time = '0' + time;
  169. if (TimeM != i) {
  170. Mhtml += '<option value="' + time + '">' + time + '분</option>\n';
  171. } else {
  172. Mhtml += '<option selected="selected" value="' + time + '">' + time + '분</option>\n';
  173. }
  174. }
  175. Mhtml += '</select>';
  176. this.eGui.innerHTML = Mhtml;
  177. this.eSelectM = this.eGui.querySelector('select');
  178. this.eSelectM.innerHTML = Mhtml;
  179. this.eGui.innerHTML = Hhtml + Mhtml; // html 전체가 있어야 하기 떄문에 마지막에 전체 입력
  180. if (params.required) {
  181. this.eSelectH.required = 'required';
  182. this.eSelectM.required = 'required';
  183. // this.eInput.classList.add('required');
  184. }
  185. };
  186. // gets called once when grid ready to insert the element
  187. DateTimer.prototype.getGui = function() {
  188. return this.eGui;
  189. };
  190. // focus and select can be done after the gui is attached
  191. DateTimer.prototype.afterGuiAttached = function() {
  192. this.eSelectH.focus();
  193. };
  194. // returns the new value after editing
  195. DateTimer.prototype.getValue = function() {
  196. return $('[name=' + this.eSelectH.name + '] option:selected').val() + ':' + $('[name=' + this.eSelectM.name + '] option:selected').val() + ':' + this.sec ;
  197. };
  198. // any cleanup we need to be done here
  199. DateTimer.prototype.destroy = function() {
  200. // but this example is simple, no cleanup, we could
  201. // even leave this method out as it's optional
  202. };
  203. // if true, then this editor will appear in a popup
  204. DateTimer.prototype.isPopup = function() {
  205. // and we could leave this method out also, false is the default
  206. return false;
  207. };
  208. return DateTimer;
  209. }
  210. /**
  211. * Numeric editor component
  212. * <pre>
  213. * cellEditor: 'numericCellEditor'
  214. * </pre>
  215. * @author gagamel
  216. * @since 2019. 4. 25
  217. */
  218. var getNumericCellEditor = function() {
  219. function isCharNumeric(charStr) {
  220. return !!/\d/.test(charStr);
  221. }
  222. function getCharCodeFromEvent(event) {
  223. event = event || window.event;
  224. return (typeof event.which == "undefined") ? event.keyCode : event.which;
  225. }
  226. function isKeyPressedNumeric(event) {
  227. var charCode = getCharCodeFromEvent(event);
  228. var charStr = String.fromCharCode(charCode);
  229. return isCharNumeric(charStr);
  230. }
  231. // function to act as a class
  232. function NumericCellEditor() {};
  233. // gets called once before the renderer is used
  234. NumericCellEditor.prototype.init = function(params) {
  235. // create the cell
  236. this.eInput = document.createElement('input');
  237. if (isCharNumeric(params.charPress)) {
  238. this.eInput.value = params.charPress;
  239. } else {
  240. if (!gagajf.isNull(params.value)) {
  241. this.eInput.value = params.value;
  242. }
  243. }
  244. var that = this;
  245. this.eInput.addEventListener('keypress', function(event) {
  246. if (!isKeyPressedNumeric(event)) {
  247. that.eInput.focus();
  248. if (event.preventDefault) event.preventDefault();
  249. //} else if (that.isKeyPressedNavigation(event)) {
  250. } else if (isNavigationKey(event)) {
  251. event.stopPropagation();
  252. }
  253. });
  254. // only start edit if key pressed is a number, not a letter
  255. var charPressIsNotANumber = params.charPress && ('1234567890'.indexOf(params.charPress) < 0);
  256. this.cancelBeforeStart = charPressIsNotANumber;
  257. };
  258. // NumericCellEditor.prototype.isKeyPressedNavigation = function(event) {
  259. // return event.keyCode === 39 || event.keyCode === 37;
  260. // };
  261. // gets called once when grid ready to insert the element
  262. NumericCellEditor.prototype.getGui = function() {
  263. return this.eInput;
  264. };
  265. // focus and select can be done after the gui is attached
  266. NumericCellEditor.prototype.afterGuiAttached = function() {
  267. this.eInput.focus();
  268. };
  269. // returns the new value after editing
  270. NumericCellEditor.prototype.isCancelBeforeStart = function() {
  271. return this.cancelBeforeStart;
  272. };
  273. // example - will reject the number if it contains the value 007
  274. // - not very practical, but demonstrates the method.
  275. NumericCellEditor.prototype.isCancelAfterEnd = function() {
  276. var value = this.getValue();
  277. return value.indexOf('007') > -1;
  278. };
  279. // returns the new value after editing
  280. NumericCellEditor.prototype.getValue = function() {
  281. return this.eInput.value;
  282. };
  283. // any cleanup we need to be done here
  284. NumericCellEditor.prototype.destroy = function() {
  285. // but this example is simple, no cleanup, we could even leave this method out as it's optional
  286. };
  287. // if true, then this editor will appear in a popup
  288. NumericCellEditor.prototype.isPopup = function() {
  289. // and we could leave this method out also, false is the default
  290. return false;
  291. };
  292. return NumericCellEditor;
  293. }
  294. /**
  295. * Cell renderer component for checkbox with value (Y/N)
  296. * <pre>
  297. * cellRenderer: 'booleanCellRenderer'
  298. * </pre>
  299. * @author gagamel
  300. * @since 2019. 4. 8
  301. */
  302. var getBooleanCellRenderer = function() {
  303. // function to act as a class
  304. function BooleanCellRenderer() {};
  305. // gets called once before the renderer is used
  306. BooleanCellRenderer.prototype.init = function(params) {
  307. this.eGui = document.createElement('span');
  308. if (!gagajf.isNull(params.value)) {
  309. var checked = (params.value == "Y" || params.value == "1") ? "checked" : "";
  310. var input = document.createElement('input');
  311. input.type = "checkbox";
  312. input.checked = checked;
  313. input.value = params.value;
  314. input.addEventListener('click', function (event) {
  315. if (params.value == "Y") params.value = "N";
  316. else if (params.value == "N") params.value = "Y";
  317. else if (params.value == "1") params.value = "0";
  318. else if (params.value == "0") params.value = "1";
  319. // checked input value has changed, perform your update here
  320. params.data[params.colDef.field] = params.value;
  321. params.data.crud = "U";
  322. params.api.updateRowData({update: [params.data]});
  323. });
  324. this.eGui.innerHTML = '';
  325. this.eGui.appendChild(input);
  326. }
  327. };
  328. // gets called once when grid ready to insert the element
  329. BooleanCellRenderer.prototype.getGui = function() {
  330. return this.eGui;
  331. };
  332. // focus and select can be done after the gui is attached
  333. BooleanCellRenderer.prototype.afterGuiAttached = function() {
  334. };
  335. // returns the new value after editing
  336. BooleanCellRenderer.prototype.getValue = function() {
  337. return this.eGui.value;
  338. };
  339. // any cleanup we need to be done here
  340. BooleanCellRenderer.prototype.destroy = function() {
  341. // but this example is simple, no cleanup, we could
  342. // even leave this method out as it's optional
  343. };
  344. // if true, then this editor will appear in a popup
  345. BooleanCellRenderer.prototype.isPopup = function() {
  346. // and we could leave this method out also, false is the default
  347. return false;
  348. };
  349. return BooleanCellRenderer;
  350. }
  351. /**
  352. * Checkbox editor component with value (Y/N)
  353. * <pre>
  354. * cellEditor: 'booleanCellEditor'
  355. * </pre>
  356. * @author gagamel
  357. * @since 2019. 4. 8
  358. */
  359. var getBooleanCellEditor = function() {
  360. // function to act as a class
  361. function BooleanCellEditor() {};
  362. // gets called once before the renderer is used
  363. BooleanCellEditor.prototype.init = function(params) {
  364. this.container = document.createElement('div');
  365. this.value = params.value;
  366. params.stopEditing();
  367. };
  368. // gets called once when grid ready to insert the element
  369. BooleanCellEditor.prototype.getGui = function() {
  370. return this.container;
  371. };
  372. // focus and select can be done after the gui is attached
  373. BooleanCellEditor.prototype.afterGuiAttached = function() {
  374. };
  375. BooleanCellEditor.prototype.getValue = function() {
  376. return this.value;
  377. };
  378. // any cleanup we need to be done here
  379. BooleanCellEditor.prototype.destroy = function() {
  380. };
  381. // if true, then this editor will appear in a popup
  382. BooleanCellEditor.prototype.isPopup = function() {
  383. return true;
  384. };
  385. return BooleanCellEditor;
  386. }
  387. ///**
  388. // * Cell renderer component for selectbox
  389. // * <pre>
  390. // * cellRenderer: 'selectCellRenderer'
  391. // * </pre>
  392. // * @param comboList - Combo List
  393. // * @author gagamel
  394. // * @since 2019. 4. 29
  395. // */
  396. //var getSelectCellRenderer = function(comboList) {
  397. //
  398. // // function to act as a class
  399. // function SelectCellRenderer() {};
  400. //
  401. // // gets called once before the renderer is used
  402. // SelectCellRenderer.prototype.init = function(params) {
  403. // this.eGui = document.createElement('span');
  404. // var select = document.createElement('select');
  405. //
  406. // console.log('========getSelectCellRenderer========');
  407. // console.log(comboList);
  408. //
  409. // var options;
  410. // var comboLen = comboList.length;
  411. // for (var i = 0; i < comboLen; i++) {
  412. // options += '<option value="' + comboList[i].cd + '">' + comboList[i].cdNm + '</option>';
  413. // }
  414. //
  415. // console.log(options);
  416. // select.appendChild(options);
  417. //
  418. // //input.value = params.value;
  419. // this.eGui.innerHTML = '';
  420. // this.eGui.appendChild(select);
  421. // };
  422. //
  423. // // gets called once when grid ready to insert the element
  424. // SelectCellRenderer.prototype.getGui = function() {
  425. // return this.eGui;
  426. // };
  427. //
  428. // // focus and select can be done after the gui is attached
  429. // SelectCellRenderer.prototype.afterGuiAttached = function() {
  430. //
  431. // };
  432. //
  433. // // returns the new value after editing
  434. // SelectCellRenderer.prototype.getValue = function() {
  435. // return this.eGui.value;
  436. // };
  437. //
  438. // // any cleanup we need to be done here
  439. // SelectCellRenderer.prototype.destroy = function() {
  440. // // but this example is simple, no cleanup, we could
  441. // // even leave this method out as it's optional
  442. // };
  443. //
  444. // // if true, then this editor will appear in a popup
  445. // SelectCellRenderer.prototype.isPopup = function() {
  446. // // and we could leave this method out also, false is the default
  447. // return false;
  448. // };
  449. //
  450. // return SelectCellRenderer;
  451. //}
  452. //
  453. ///**
  454. // * Selectbox editor component
  455. // * <pre>
  456. // * cellEditor: 'selectCellEditor'
  457. // * </pre>
  458. // * @author gagamel
  459. // * @since 2019. 4. 29
  460. // */
  461. //var getSelectCellEditor = function() {
  462. // // function to act as a class
  463. // function SelectCellEditor() {};
  464. //
  465. // // gets called once before the renderer is used
  466. // SelectCellEditor.prototype.init = function(params) {
  467. // // create the cell
  468. // this.eInput = document.createElement('select');
  469. // this.eInput.value = params.value;
  470. //
  471. // var that = this;
  472. // this.eInput.addEventListener('change', function(event) {
  473. // console.log('SelectCellEditor change');
  474. //// that.eInput.focus();
  475. //// if (event.preventDefault) event.preventDefault();
  476. // event.stopPropagation();
  477. // });
  478. // };
  479. //
  480. // // gets called once when grid ready to insert the element
  481. // SelectCellEditor.prototype.getGui = function() {
  482. // console.log('SelectCellEditor getGui');
  483. // return this.eInput;
  484. // };
  485. //
  486. // // focus and select can be done after the gui is attached
  487. // SelectCellEditor.prototype.afterGuiAttached = function() {
  488. // console.log('SelectCellEditor afterGuiAttached');
  489. // this.eInput.focus();
  490. // };
  491. //
  492. // // returns the new value after editing
  493. // SelectCellEditor.prototype.isCancelBeforeStart = function() {
  494. // console.log('SelectCellEditor isCancelBeforeStart');
  495. // //return this.cancelBeforeStart;
  496. // };
  497. //
  498. // // not very practical, but demonstrates the method.
  499. // SelectCellEditor.prototype.isCancelAfterEnd = function() {
  500. // console.log('SelectCellEditor isCancelAfterEnd');
  501. // };
  502. //
  503. // // returns the new value after editing
  504. // SelectCellEditor.prototype.getValue = function() {
  505. // console.log('SelectCellEditor getValue');
  506. // return this.eInput.value;
  507. // };
  508. //
  509. // // any cleanup we need to be done here
  510. // SelectCellEditor.prototype.destroy = function() {
  511. // console.log('SelectCellEditor destroy');
  512. // // but this example is simple, no cleanup, we could even leave this method out as it's optional
  513. // };
  514. //
  515. // // if true, then this editor will appear in a popup
  516. // SelectCellEditor.prototype.isPopup = function() {
  517. // console.log('SelectCellEditor isPopup');
  518. // // and we could leave this method out also, false is the default
  519. // return false;
  520. // };
  521. //
  522. // return SelectCellEditor;
  523. //}
  524. /**
  525. * Text Tooltip component
  526. * <pre>
  527. * textTooltip: TextTooltip
  528. * </pre>
  529. * @author gagamel
  530. * @since 2019. 4. 29
  531. */
  532. var getTextTooltip = function() {
  533. // function to act as a class
  534. function TextTooltip() {};
  535. TextTooltip.prototype.init = function(params) {
  536. var eGui = this.eGui = document.createElement('div');
  537. var color = params.color || 'white';
  538. eGui.classList.add('custom-tooltip');
  539. eGui.style['background-color'] = color;
  540. /*var data = params.api.getRowNode(params.rowIndex).data;
  541. eGui.innerHTML =
  542. '<p><span class"name">' + data.athlete + '</span></p>' +
  543. '<p><span>Country: </span>' + data.country + '</p>' +
  544. '<p><span>Total: </span>' + data.total + '</p>';*/
  545. eGui.innerHTML = '<p><span>' + params.value + '</span>';
  546. };
  547. TextTooltip.prototype.getGui = function() {
  548. return this.eGui;
  549. };
  550. return TextTooltip;
  551. }
  552. /**
  553. * Text cell editor component
  554. * <pre>
  555. * cellEditor: 'textCellEditor'
  556. * </pre>
  557. * @author gagamel
  558. * @since 2019. 4. 30
  559. */
  560. var getTextCellEditor = function() {
  561. // function to act as a class
  562. function TextCellEditor() {};
  563. TextCellEditor.prototype.init = function(params) {
  564. this.eGui = document.createElement('div');
  565. this.eGui.innerHTML = '<input'
  566. + ' name="' + params.colDef.field + '"'
  567. + (!gagajf.isNull(params.value) ? ' value="' + params.value + '"' : '')
  568. + (!gagajf.isNull(params.maxlength) ? ' maxlength="' + params.maxlength + '"' : '')
  569. + (!gagajf.isNull(params.validType) ? ' data-valid-type="' + params.validType + '"' : '')
  570. + (!gagajf.isNull(params.onblur) ? ' onblur="' + params.onblur + '"' : '')
  571. + ' style="width: 100%"/>';
  572. this.eInput = this.eGui.querySelector('input');
  573. if (params.required) {
  574. this.eInput.required = 'required';
  575. // this.eInput.classList.add('required');
  576. }
  577. // this.eInput.addEventListener('input', this.inputChanged.bind(this));
  578. // var that = this;
  579. // this.eInput.addEventListener('keypress', function(event) {
  580. // if (!isKeyPressedNumeric(event)) {
  581. // that.eInput.focus();
  582. // if (event.preventDefault) event.preventDefault();
  583. // //} else if (that.isKeyPressedNavigation(event)) {
  584. // } else if (isNavigationKey(event)) {
  585. // event.stopPropagation();
  586. // }
  587. // });
  588. // this.eInput.addEventListener('blur', function(event) {
  589. // if (params.required) {
  590. // if (gagajf.isNull(event.target.value)) {
  591. // alert(params.colDef.headerName + ' 을(를) 입력해 주세요.');
  592. // that.eInput.focus();
  593. // if (event.preventDefault) event.preventDefault();
  594. // event.stopPropagation();
  595. // return false;
  596. // }
  597. // }
  598. // });
  599. }
  600. // TextCellEditor.prototype.inputChanged = function(event) {
  601. // console.log('TextCellEditor.prototype.inputChanged');
  602. // console.log(event);
  603. //
  604. // const val = event.target.value;
  605. //
  606. //// if (!this.isValid(val)) {
  607. //// this.eInput.classList.add('invalid-cell');
  608. //// } else {
  609. //// this.eInput.classList.remove('invalid-cell');
  610. //// }
  611. //
  612. // if (this.eInput.required === 'required') {
  613. // if (gagajf.isNull(val)) {
  614. // alert('을(를) 입력해 주세요.');
  615. // return false;
  616. // }
  617. // }
  618. //
  619. // return true;
  620. // }
  621. // TextCellEditor.prototype.isValid = function(value) {
  622. // return value.length <= this.maxLength;
  623. // }
  624. TextCellEditor.prototype.getValue = function() {
  625. return this.eInput.value;
  626. }
  627. TextCellEditor.prototype.isCancelAfterEnd = function() {
  628. // return !this.isValid(this.eInput.value);
  629. }
  630. TextCellEditor.prototype.getGui = function() {
  631. return this.eGui;
  632. }
  633. TextCellEditor.prototype.destroy = function() {
  634. this.eInput.removeEventListener('input', this.inputChanged);
  635. }
  636. return TextCellEditor;
  637. }
  638. /**
  639. * 공통 그리드 util
  640. */
  641. var gagaAgGrid = {
  642. defaultBlank : " - ",
  643. eGridDiv : "",
  644. /**
  645. * 기본 Grid Options을 얻는다.
  646. * @param colDefs - Column Definition
  647. */
  648. getGridOptions : function(colDefs) {
  649. return {
  650. // a default column definition with properties that get applied to every column
  651. defaultColDef: {
  652. sortable: true, // make every column sortable
  653. resizable: true, // make every column resizable
  654. filter: 'agTextColumnFilter', // make every column use 'text' filter by default
  655. tooltipComponent: 'textTooltip',
  656. suppressSizeToFit: true // this columns width to be fixed during 'size to fit' operation.
  657. },
  658. // floatingFilter: true, // display filter region
  659. // if we had column groups, we could provide default group items here
  660. defaultColGroupDef: {
  661. //marryChildren: true
  662. },
  663. // define a column type (you can define as many as you like)
  664. columnTypes: {
  665. boolean: {
  666. cellClass: 'text-center',
  667. /*cellRenderer: function(params) {
  668. return '<input type="checkbox" ' + (params.value ? "checked" : "") + '/>';
  669. },*/
  670. cellRenderer: 'booleanCellRenderer',
  671. cellEditor: 'booleanCellEditor'
  672. },
  673. numeric: {
  674. filter: 'agNumberColumnFilter'
  675. },
  676. date: {
  677. filter: 'agDateColumnFilter',
  678. filterParams: {
  679. comparator: function(filterLocalDateAtMidnight, cellValue) {
  680. // Dates are stored as yyyy/MM/dd
  681. // We create a Date object for comparison against the filter date
  682. var dateParts = cellValue.split('/');
  683. var year = Number(dateParts[0]);
  684. var month = Number(dateParts[1]) - 1;
  685. var day = Number(dateParts[2]);
  686. var cellDate = new Date(day, month, year);
  687. // Now that both parameters are Date objects, we can compare
  688. if (cellDate < filterLocalDateAtMidnight) {
  689. return -1;
  690. } else if (cellDate > filterLocalDateAtMidnight) {
  691. return 1;
  692. } else {
  693. return 0;
  694. }
  695. }
  696. },
  697. suppressMenu: true
  698. },
  699. measure: {
  700. // test 김유중
  701. // chartDataType: 'series',
  702. // cellClass: 'number',
  703. valueFormatter: 'numberCellFormatter',
  704. cellRenderer: 'agAnimateShowChangeCellRenderer'
  705. },
  706. numberValue: {
  707. enableValue: true,
  708. aggFunc: 'sum',
  709. editable: true,
  710. // valueParser: numberParser
  711. },
  712. nonEditable: {
  713. editable: false
  714. }
  715. },
  716. columnDefs: colDefs,
  717. // Columns
  718. suppressAutoSize: false, // suppresses auto-sizing columns
  719. // Selection
  720. //rowSelection: 'single', // 'single' or 'multiple'
  721. //suppressRowClickSelection: false,
  722. enableRangeSelection: true, // enable Range Selection
  723. // Rendering & Styling
  724. animateRows: true, // enable Row Animation
  725. // Localization
  726. localeText: {
  727. noRowsToShow: '조회 결과가 없습니다.'
  728. },
  729. // Overlays
  730. suppressLoadingOverlay: true, // disables the 'loading' overlay
  731. loadingOverlayComponent: 'customLoadingOverlay',
  732. loadingOverlayComponentParams: {
  733. loadingMessage: 'Loading... one moment please...'
  734. },
  735. // Scrolling
  736. //suppressHorizontalScroll: false,
  737. statusBar: {
  738. statusPanels: [
  739. { statusPanel: 'agTotalRowCountComponent', align: 'left' },
  740. { statusPanel: 'agFilteredRowCountComponent' },
  741. { statusPanel: 'agSelectedRowCountComponent' },
  742. { statusPanel: 'agAggregationComponent' }
  743. ]
  744. },
  745. // 헤더의 열에 aggFunc명(예, sum, avg 등) 표시 제거
  746. suppressAggFuncInHeader: true,
  747. // Grouping Custom Function
  748. aggFuncs: {
  749. // this overrides the grids built in sum function
  750. 'sum': this.sum,
  751. 'avg': this.avg,
  752. 'ratio': this.ratio
  753. },
  754. onGridReady: function(params) {
  755. params.api.sizeColumnsToFit(); // 자동 맞춤
  756. },
  757. // 창 크기 변경 되었을 때 이벤트
  758. onGridSizeChanged: function(params) {
  759. params.api.sizeColumnsToFit(); // 자동 맞춤
  760. },
  761. // debug: true,
  762. onCellValueChanged: function(event) {
  763. // if cell is editable and changed value
  764. if (event.colDef.editable && event.oldValue != event.newValue) {
  765. /*var cellClass = event.colDef.cellClass;
  766. event.colDef.cellClass = cellClass ? cellClass + ' modified' : 'modified';
  767. var row = this.api.getDisplayedRowAtIndex(event.rowIndex);
  768. this.api.redrawRows({ rowNodes: [row] });*/
  769. }
  770. },
  771. onCellEditingStopped: function(event) {
  772. if (event.colDef.editable && event.data.crud != "C") {
  773. event.data.crud = "U";
  774. //gridOptions.api.updateRowData({update: [event.data]});
  775. }
  776. },
  777. // 총합계, 소계 등을 표시하기 위한 row의 스타일
  778. getRowStyle: function(params) {
  779. if (params.node.rowPinned) {
  780. return {'font-weight': 'bold', 'color': '#721c24', 'background': '#f8d7da'};
  781. }
  782. },
  783. components:{
  784. customLoadingOverlay: getCustomLoadingOverlay(),
  785. booleanCellRenderer: getBooleanCellRenderer(),
  786. booleanCellEditor: getBooleanCellEditor(),
  787. numericCellEditor: getNumericCellEditor(),
  788. datePicker: getDatePicker(),
  789. dateTimer: getDateTimer(),
  790. textTooltip: getTextTooltip(),
  791. textCellEditor: getTextCellEditor(),
  792. ComboboxCellRenderer : getComboboxCellRenderer(),
  793. ComboboxHeaderComponent : getComboboxHeaderComponent()
  794. }
  795. };
  796. },
  797. /**
  798. * Create a ag-Grid
  799. * @param gridId - ag-Grid ID
  800. * @param gridOptions - ag-Grid options
  801. * @author gagamel
  802. * @since 2019. 4. 8
  803. */
  804. createGrid : function (gridId, gridOptions) {
  805. eGridDiv = document.querySelector('#' + gridId);
  806. if (typeof gridOptions.rowHeight == "undefined") gridOptions.rowHeight = 32;
  807. new agGrid.Grid(eGridDiv, gridOptions);
  808. },
  809. /**
  810. * Progress bar
  811. */
  812. showProgressbar : function(isLoading) {
  813. if (isLoading) {
  814. // Button disabled & progressBar creation
  815. $('.btn').each(function(idx) { $(this).attr('disabled', true); });
  816. var load_AjaxSubmit = '<div id="load_AjaxSubmit" style="'
  817. + 'background: url(/ux/plugins/gaga/loader.gif); border-style: none; background-repeat: no-repeat; '
  818. + 'position: absolute; top: 45%; left: 50%; width: auto; '
  819. + 'z-index: 101; padding: 16px; margin: 5px;'
  820. + '"></div>';
  821. $(eGridDiv).append(load_AjaxSubmit);
  822. } else {
  823. // Button activated & progressBar remove
  824. $('.btn').each(function(idx) { $(this).attr('disabled', false); });
  825. $('#load_AjaxSubmit').remove();
  826. }
  827. },
  828. /**
  829. * Hide the status bar of bottom
  830. * gagaAgGrid.createGrid() 함수 사용 후 호출한다.
  831. * <pre>
  832. * gagaAgGrid.createGrid('gridList', gridOptions);
  833. * gagaAgGrid.hideStatusBar('gridList');
  834. * </pre>
  835. * @param gridId - ag-Grid ID
  836. * @author gagamel
  837. * @since 2021. 1. 14
  838. */
  839. hideStatusBar : function(gridId) {
  840. $('#' + gridId + ' .ag-status-bar').hide();
  841. },
  842. /**
  843. * Fetch data using json format.
  844. * <pre>
  845. * var actionUrl = $('#searchForm').prop('action') + '?' + $('#searchForm').serialize();
  846. * gagaAgGrid.fetch(actionUrl, gridOptions);
  847. * </pre>
  848. * @param actionUrl - request URL. 필수
  849. * @param gridOptions - ag-Grid options. 필수
  850. * @param formId - form ID. option. 옵션
  851. * @param callbackFn - Callback function. 옵션
  852. * @author gagamel
  853. * @since 2019. 4. 8
  854. */
  855. fetch : function(actionUrl, gridOptions, formId, callbackFn) {
  856. // gridOptions.api.showLoadingOverlay();
  857. var _this = this;
  858. if (typeof(formId) == 'undefined' || gagajf.isNull(formId)) { // formId 값이 없으면
  859. // fetch(actionUrl).then(function(response) {
  860. // return response.json(); // promise 반환
  861. // }).then(function(data) {
  862. // gridOptions.api.setRowData(data);
  863. // _this.showProgressbar(false);
  864. // });
  865. $.ajax({
  866. type : 'GET',
  867. url : actionUrl,
  868. data : null,
  869. dataType : 'json',
  870. beforeSend : function(xhr, settings) {
  871. // Button disabled & progressBar creation
  872. _this.showProgressbar(true);
  873. },
  874. complete : function() {
  875. _this.showProgressbar(false);
  876. },
  877. success : function(data) {
  878. try {
  879. gridOptions.api.setRowData(data);
  880. } catch (e) {
  881. console.log(e);
  882. mcxDialog.alert('오류로 인해 처리되지 않았습니다.');
  883. }
  884. if (typeof(callbackFn) == "function") {
  885. callbackFn.call(this, data);
  886. }
  887. },
  888. error : function(data) {
  889. console.log(data);
  890. _this.showProgressbar(false);
  891. mcxDialog.alert('오류로 인해 처리되지 않았습니다.');
  892. }
  893. });
  894. } else { // formId 값이 있으면
  895. // comma(,) 제거
  896. gagajf.removeCommaAtNumberFormattedInput(formId);
  897. var jsonData = JSON.stringify($(formId).serializeObject());
  898. $.ajax({
  899. type : 'POST',
  900. url : actionUrl,
  901. data : jsonData,
  902. dataType : 'json',
  903. beforeSend : function(xhr, settings) {
  904. // dataType: "json"일 때
  905. xhr.setRequestHeader('Accept', 'application/json');
  906. xhr.setRequestHeader('Content-Type', 'application/json');
  907. // Button disabled & progressBar creation
  908. _this.showProgressbar(true);
  909. },
  910. complete : function() {
  911. _this.showProgressbar(false);
  912. },
  913. success : function(data) {
  914. try {
  915. gridOptions.api.setRowData(data);
  916. } catch (e) {
  917. console.log(e);
  918. mcxDialog.alert('오류로 인해 처리되지 않았습니다.');
  919. }
  920. if (typeof(callbackFn) == "function") {
  921. callbackFn.call(this, data);
  922. }
  923. },
  924. error : function(data) {
  925. console.log(data);
  926. _this.showProgressbar(false);
  927. mcxDialog.alert('오류로 인해 처리되지 않았습니다.');
  928. }
  929. });
  930. // var options = {
  931. // method: "POST",
  932. // headers: { "Content-Type": "application/json; charset=utf-8" },
  933. // body: jsonData
  934. // };
  935. //
  936. // fetch(actionUrl, options).then(function(response) {
  937. // return response.json(); // promise 반환
  938. // }).then(function(data) {
  939. // gridOptions.api.setRowData(data);
  940. // _this.showProgressbar(false);
  941. // });
  942. }
  943. // Button activated & progressBar remove
  944. // gridOptions.api.hideOverlay();
  945. },
  946. /**
  947. * 그리드의 총건수 가져오기
  948. * <pre>
  949. * gagaAgGrid.getTotalCount(gridOptions);
  950. * </pre>
  951. * @param gridOptions - ag-Grid options
  952. * @author gagamel
  953. * @since 2019. 5. 8
  954. */
  955. getTotalCount : function(gridOptions) {
  956. return gridOptions.api.getDisplayedRowCount();
  957. },
  958. /**
  959. * 그리드 컬럼을 보이기/감추기
  960. * <pre>
  961. * gagaAgGrid.showOrHideColumn(gridOptions, "useYn", false);
  962. * </pre>
  963. * @param gridOptions - ag-Grid options
  964. * @param colKey - column ID
  965. * @param isShow - show or hide (true/false)
  966. * @author gagamel
  967. * @since 2019. 4. 8
  968. */
  969. showOrHideColumn : function(gridOptions, colKey, isShow) {
  970. gridOptions.columnApi.setColumnVisible(colKey, isShow);
  971. },
  972. /**
  973. * 그리드 컬럼의 Header명을 설정
  974. * <pre>
  975. * gagaAgGrid.setColumnHeaderName(gridOptions, 'M1', '1월');
  976. * </pre>
  977. * @param gridOptions - ag-Grid options
  978. * @param colKey - column ID or column group ID
  979. * @param headerName - header name
  980. * @author gagamel
  981. * @since 2019. 5. 7
  982. */
  983. setColumnHeaderName : function(gridOptions, colKey, headerName) {
  984. gridOptions.columnApi.getColumn(colKey).colDef.headerName = headerName;
  985. // gridOptions.columnApi.resetColumnState();
  986. },
  987. /**
  988. * 그리드 컬럼 그룹의 Header명을 설정
  989. * <pre>
  990. * gagaAgGrid.setColumnGroupHeaderName(gridOptions, 'M1', '1월');
  991. * </pre>
  992. * @param gridOptions - ag-Grid options
  993. * @param colKey - column ID
  994. * @param headerName - header name
  995. * @author gagamel
  996. * @since 2019. 5. 7
  997. */
  998. setColumnGroupHeaderName : function(gridOptions, colKey, headerName) {
  999. gridOptions.columnApi.getColumn(colKey).parent.originalColumnGroup.colGroupDef.headerName = headerName;
  1000. // gridOptions.columnApi.resetColumnState();
  1001. },
  1002. /**
  1003. * 그리드 내에 변경된 데이터를 배열로 반환한다.
  1004. * <pre>
  1005. * var changedData = gagaAgGrid.getChangedData(gridOptions);
  1006. * </pre>
  1007. * @param gridOptions - ag-Grid options
  1008. * @author gagamel
  1009. * @since 2019. 4. 8
  1010. */
  1011. getChangedData : function(gridOptions) {
  1012. // Stop editing
  1013. gridOptions.api.stopEditing();
  1014. var changedData = [];
  1015. gridOptions.api.forEachNode(function(rowNode, index) {
  1016. if (rowNode.data.crud == "C" || rowNode.data.crud == "U" || rowNode.data.crud == "D") {
  1017. rowNode.data.index = index;
  1018. changedData.push(rowNode.data);
  1019. }
  1020. });
  1021. return changedData;
  1022. },
  1023. /**
  1024. * 그리드 첫번째 row에 data를 갖는 행을 추가한다.
  1025. * <pre>
  1026. * var data = { cdGb: "", cd: "", cdNm: "", cdChar: "40", cdNum: 1, cdDt: today, dispRk: 1, useYn: "Y" };
  1027. * gagaAgGrid.addRowData(gridOptions, data, "cdGb");
  1028. * </pre>
  1029. * @param gridOptions - ag-Grid options
  1030. * @param data - 추가할 데이터
  1031. * @param focusedColKey - Column ID to focus
  1032. * @author gagamel
  1033. * @since 2019. 4. 9
  1034. */
  1035. addRowData : function(gridOptions, data, focusedColKey) {
  1036. data.crud = "C";
  1037. gridOptions.api.updateRowData({add: [data], addIndex: 0});
  1038. // Focused cell
  1039. gridOptions.api.setFocusedCell(0, focusedColKey, null);
  1040. // start editing cell
  1041. //gridOptions.api.startEditing({rowIndex: 0, colKey: focusedColKey});
  1042. },
  1043. /**
  1044. * 그리드 내에 선택된 데이터를 가져온다
  1045. * <pre>
  1046. * gagaAgGrid.selectedRowData(gridOptions);
  1047. * </pre>
  1048. * @param gridOptions - ag-Grid options
  1049. * @author gagamel
  1050. * @since 2019. 7. 9
  1051. */
  1052. selectedRowData : function(gridOptions) {
  1053. return gridOptions.api.getSelectedRows();
  1054. },
  1055. /**
  1056. * 그리드 내에 전체 데이터를 가져온다
  1057. * <pre>
  1058. * gagaAgGrid.getAllRowData(gridOptions);
  1059. * </pre>
  1060. * @param gridOptions - ag-Grid options
  1061. * @author qkwlstktma
  1062. * @since 2019. 7. 25
  1063. */
  1064. getAllRowData : function(gridOptions){
  1065. var data = [];
  1066. gridOptions.api.forEachNode(function(rowNode, index) {
  1067. data.push(rowNode.data);
  1068. });
  1069. return data;
  1070. },
  1071. /**
  1072. * 그리드 내에 선택된 데이터를 삭제하고 배열에 담아 반환한다.
  1073. * 실제 삭제되지 않고 해당 행이 보이지 않게 된다.
  1074. * <pre>
  1075. * gagaAgGrid.removeRowData(gridOptions);
  1076. * </pre>
  1077. * @param gridOptions - ag-Grid options
  1078. * @param isShow - Row 보이기(true/false. 디폴트는 보이는 것으로). 옵션
  1079. * @author gagamel
  1080. * @since 2019. 4. 9
  1081. */
  1082. removeRowData : function(gridOptions, isShow) {
  1083. var selectedData = gridOptions.api.getSelectedRows();
  1084. var removedData = [];
  1085. selectedData.forEach(function(item, index) {
  1086. if (item.crud == 'C') {
  1087. gridOptions.api.updateRowData({remove: [item]});
  1088. } else {
  1089. removedData.push(item);
  1090. if (typeof(isShow) != 'undefined' && !isShow) {
  1091. gridOptions.api.updateRowData({remove: [item]});
  1092. }
  1093. }
  1094. });
  1095. return removedData;
  1096. },
  1097. /**
  1098. * 그리드 내에 고정된(pinned) top 또는 bottom에 데이터 표시
  1099. * <pre>
  1100. * var data = {
  1101. * sellDt: '총합계',
  1102. * orderQty: 100, orderAmt: 10000,
  1103. * };
  1104. * gagaAgGrid.setPinnedRowData(gridOptions, data, 'top');
  1105. * </pre>
  1106. * @param gridOptions - ag-Grid options. 필수
  1107. * @param data - 고정된 row에 보일 데이터. 필수
  1108. * @param topBottom - top/bottom. 옵션
  1109. * @author gagamel
  1110. * @since 2019. 9. 7
  1111. */
  1112. setPinnedRowData : function(gridOptions, data, topBottom) {
  1113. if (typeof(topBottom) == 'undefined' || topBottom == 'top') {
  1114. gridOptions.api.setPinnedTopRowData([data]);
  1115. } else {
  1116. gridOptions.api.setPinnedBottomRowData([data]);
  1117. }
  1118. },
  1119. checkRequired : function(gridOptions, validItem) {
  1120. var isInvalid = true;
  1121. for (var i = 0; i < gridOptions.columnDefs.length; i++) {
  1122. var column = gridOptions.columnDefs[i];
  1123. if (typeof(column.cellEditorParams) == 'undefined')
  1124. continue;
  1125. if (typeof(column.cellEditorParams.required) == 'undefined')
  1126. continue;
  1127. if (!column.cellEditorParams.required)
  1128. continue;
  1129. if (!gagajf.isNull(validItem[column.field]))
  1130. continue;
  1131. mcxDialog.alert(column.headerName + '은[는] 필수 입력 항목입니다.');
  1132. // Focused cell
  1133. gridOptions.api.setFocusedCell(validItem.index, column.field, null);
  1134. isInvalid = false;
  1135. break;
  1136. }
  1137. return isInvalid;
  1138. },
  1139. validation : function(gridOptions, validData) {
  1140. var isInvalid = true;
  1141. validData.every(function(item, index) {
  1142. if (gagaAgGrid.checkRequired(gridOptions, item))
  1143. return true;
  1144. isInvalid = false;
  1145. return false;
  1146. });
  1147. return isInvalid;
  1148. },
  1149. /*// 그리드 값 넣기
  1150. setRowData : function (gridOptions, rowData) {
  1151. //$('#'+gridDiv).children().remove();
  1152. gridOptions.api.setRowData(rowData);
  1153. },*/
  1154. /**
  1155. * mappings(코드목록배열) 중에 명칭만을 배열로 구성해 반환한다.
  1156. * <pre>
  1157. * cellEditorParams: { values: gagaAgGrid.extractValues(mappings) }
  1158. * </pre>
  1159. * @param mappings - 코드목록배열. 필수
  1160. * 예) { "10":"항공(AIR)", "20":"해운(OCEAN)", ... }
  1161. * @author gagamel
  1162. * @since 2019. 4. 7
  1163. */
  1164. extractValues : function(mappings) {
  1165. return Object.keys(mappings);
  1166. },
  1167. /**
  1168. * mappings(코드목록배열) 중에 키(key)에 메핑되는 값을 반환한다.
  1169. * <pre>
  1170. * valueFormatter: function (params) { return gagaAgGrid.lookupValue(mappings, params.value); }
  1171. * </pre>
  1172. * @param mappings - 코드목록배열. 필수
  1173. * 예) { "10":"항공(AIR)", "20":"해운(OCEAN)", ... }
  1174. * @param key - 키. 필수
  1175. * @author gagamel
  1176. * @since 2019. 4. 7
  1177. */
  1178. lookupValue : function(mappings, key) {
  1179. return mappings[key];
  1180. },
  1181. /**
  1182. * mappings(코드목록배열) 중에 name(콤보박스 option text)에 메핑되는 Key를 반환한다.
  1183. * <pre>
  1184. * valueParser: function (params) { return gagaAgGrid.lookupKey(mappings, params.newValue); }
  1185. * </pre>
  1186. * @param mappings - 코드목록배열. 필수
  1187. * 예) { "10":"항공(AIR)", "20":"해운(OCEAN)", ... }
  1188. * @param name - 콤보박스 option text. 필수
  1189. * @author gagamel
  1190. * @since 2019. 4. 7
  1191. */
  1192. lookupKey : function(mappings, name) {
  1193. for (var key in mappings) {
  1194. if (mappings.hasOwnProperty(key)) {
  1195. if (name === mappings[key]) {
  1196. return key;
  1197. }
  1198. }
  1199. }
  1200. },
  1201. /**
  1202. * value를 yyyy-MM-dd 형식으로 반환
  1203. * <pre>
  1204. * cellRenderer: function (params) { return gagaAgGrid.toDateFormat(params.value); }
  1205. * </pre>
  1206. * @param value - 일자 (yyyyMMdd 형식)
  1207. * @author gagamel
  1208. * @since 2019. 4. 8
  1209. */
  1210. toDateFormat : function(value) {
  1211. if (gagajf.isNull(value))
  1212. return "";
  1213. return value.replaceAll("/", "").replaceAll("-", "").toDate("YYYYMMDD").format("YYYY-MM-DD");
  1214. },
  1215. /**
  1216. * value를 yyyy-MM-dd HH:mm:ss 형식으로 반환
  1217. * <pre>
  1218. * cellRenderer: function (params) { return gagaAgGrid.toDateTimeFormat(params.value); }
  1219. * </pre>
  1220. * @param value - 일자 (yyyyMMddHHmmss 형식)
  1221. * @param format - 일자표현식
  1222. * @author gagamel
  1223. * @since 2019. 6. 7
  1224. */
  1225. toDateTimeFormat : function(value, format) {
  1226. if (gagajf.isNull(value))
  1227. return "";
  1228. var rst = "";
  1229. if (format == "YYYYMMDD") {
  1230. rst = value.replace(/[^0-9]/g, "").toDate("YYYYMMDDHHmmss").format("YYYYMMDD");
  1231. } else if (format == "hh:mm:ss") {
  1232. rst = value.replace(/[^0-9]/g, "").toDate("YYYYMMDDHHmmss").format("hh:mm:ss");
  1233. } else if (format == "yyyy-MM-dd") {
  1234. rst = value.replace(/[^0-9]/g, "").toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD");
  1235. } else {
  1236. rst = value.replace(/[^0-9]/g, "").toDate("YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss");
  1237. }
  1238. return rst;
  1239. },
  1240. /**
  1241. * value가 숫자 타입일 때 comma(,)를 붙여 반환
  1242. * <pre>
  1243. * cellRenderer: function (params) { return gagaAgGrid.toAddComma(params.value); }
  1244. * </pre>
  1245. * @param value - 숫자
  1246. * @author gagamel
  1247. * @since 2019. 9. 8
  1248. */
  1249. toAddComma : function(value) {
  1250. if (gagajf.isNull(value) || typeof value != 'number')
  1251. return '';
  1252. return value.addComma();
  1253. },
  1254. /**
  1255. * value가 실수 타입일 때 comma(,)를 붙여 반환 소수점 n까지 반환
  1256. * <pre>
  1257. * cellRenderer: function (params) { return gagaAgGrid.toFixed(params.value, n); }
  1258. * </pre>
  1259. * @param value - 숫자
  1260. * @author ldh
  1261. * @since 2019. 12. 10
  1262. */
  1263. toFixed : function(value, n) {
  1264. if (gagajf.isNull(value) || typeof value != 'number')
  1265. return '';
  1266. return value.toFixed(n);
  1267. },
  1268. /*
  1269. convertTime : function (param){
  1270. if (!param.value) {
  1271. return this.defaultBlank;
  1272. } else {
  1273. return moment(param.value, "YYYYMMDDHHmmss").format("HH:mm");
  1274. }
  1275. },
  1276. convertTimestamp : function(param) { // 8자리 문자열을 날짜로 변환
  1277. if (!param.value) {
  1278. return this.defaultBlank;
  1279. } else {
  1280. return moment(param.value, "YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss");
  1281. }
  1282. },
  1283. formatDate : function(param) { // long 값을 날짜로 변환
  1284. if (!param.value) {
  1285. return this.defaultBlank;
  1286. } else {
  1287. return moment(parseInt(param.value)).format("YYYY-MM-DD");
  1288. }
  1289. },
  1290. formatTimestamp : function(param) { // long 값을 날짜로 변환
  1291. if (!param.value) {
  1292. return this.defaultBlank;
  1293. } else {
  1294. return moment(parseInt(param.value)).format("YYYY-MM-DD HH:mm:ss");
  1295. }
  1296. },
  1297. numberOnly : function(param){
  1298. if (!param.value || param.value =='')
  1299. return '';
  1300. if (typeof param.value === 'string') {
  1301. return param.value.replace(/[^0-9\.]+/g, '');
  1302. }
  1303. return CommonGrid.formatCurrency(param);
  1304. },
  1305. formatCurrency : function (param){
  1306. if (!param.value && param.value != "0") {
  1307. return this.defaultBlank;
  1308. }
  1309. return parseInt(param.value).format();
  1310. },
  1311. formatNumber : function(param){
  1312. if (!param.value && param.value != "0") {
  1313. return this.defaultBlank;
  1314. }
  1315. return numberFormatPoint2Digits(param.value);
  1316. },
  1317. convertCommon : function(codes, param){
  1318. if (!codes) return " - ";
  1319. for (var i = 0; i < codes.length;i++) {
  1320. if (param.value == codes[i].name) {
  1321. return codes[i].value;
  1322. }
  1323. }
  1324. return this.defaultBlank;
  1325. },
  1326. getCode : function(codes, value) {
  1327. for (var i = 0; i < codes.length; i++) {
  1328. if (value == codes[i].value) {
  1329. return codes[i].name;
  1330. }
  1331. }
  1332. return "";
  1333. },
  1334. checkMobile : function(gridOpts){
  1335. // 모바일 브라우저 가로크기 체크
  1336. if (document.body.clientWidth < 800) {
  1337. if (gridOpts){
  1338. gridOpts.columnDefs.forEach(function(el) {
  1339. el.pinned = null;
  1340. if(el.children){
  1341. el.children.forEach(function(subEl) {
  1342. subEl.pinned = null;
  1343. });
  1344. }
  1345. });
  1346. }
  1347. }
  1348. },
  1349. makeTopGrid : function(gridMainOpts, rowData, params) {
  1350. var colsSum = [];
  1351. gridMainOpts.columnDefs.forEach(function(coldefs, index) {
  1352. if (coldefs.children) {
  1353. coldefs.children.forEach(function(child, index) {
  1354. if (child.isSum && child.isSum == true){
  1355. var temp = {};
  1356. temp[child.field] = 0;
  1357. temp["field"] = child.field;
  1358. colsSum.push(temp);
  1359. }
  1360. });
  1361. } else {
  1362. if (coldefs.isSum && coldefs.isSum == true) {
  1363. var temp = {};
  1364. temp[coldefs.field] = 0;
  1365. temp["field"] = coldefs.field;
  1366. colsSum.push(temp);
  1367. }
  1368. }
  1369. });
  1370. rowData.forEach(function(rowvalue, index) {
  1371. colsSum.forEach(function(value, index) {
  1372. if (rowvalue[value.field] && !rowvalue[value.field].isNaN)
  1373. value[value.field] += rowvalue[value.field];
  1374. });
  1375. });
  1376. var resultSum = {}
  1377. colsSum.forEach(function(cValue, index) {
  1378. resultSum[cValue.field] = cValue[cValue.field];
  1379. });
  1380. if (params && params.length > 0) {
  1381. params.forEach(function(value, index) {
  1382. resultSum[value.field] = value.value;
  1383. });
  1384. }
  1385. resultSum['top'] = true;
  1386. var resultArray = [];
  1387. resultArray[0] = resultSum;
  1388. gridMainOpts.api.setPinnedTopRowData(resultArray);
  1389. }*/
  1390. // sum function has no advantage over the built in sum function.
  1391. // it's shown here as it's the simplest form of aggregation and
  1392. // showing it can be good as a starting point for understanding
  1393. // how the aggregation functions work.
  1394. sum : function(values) {
  1395. var result = 0;
  1396. values.forEach(function(value) {
  1397. if (typeof value === 'number') {
  1398. result += value;
  1399. }
  1400. });
  1401. return result;
  1402. },
  1403. // Average function
  1404. avg : function(values) {
  1405. var result = 0;
  1406. var cnt = 0;
  1407. values.forEach(function(value) {
  1408. if (typeof value === 'number') {
  1409. result += value;
  1410. cnt++;
  1411. }
  1412. });
  1413. return gagaAgGrid.toAddComma(Number(gagaAgGrid.toFixed(result / cnt)));
  1414. },
  1415. // Ratio function
  1416. ratio : function(values) {
  1417. var value1 = 0;
  1418. var value2 = 0;
  1419. values.forEach(function(value) {
  1420. if (value && value.value1) {
  1421. value1 += value.value1;
  1422. }
  1423. if (value && value.value2) {
  1424. value2 += value.value2;
  1425. }
  1426. });
  1427. return gagaAgGrid.setRatio(value1, value2);
  1428. },
  1429. /**
  1430. * 2개의 값으로 비율값을 계산해 설정한다.
  1431. * <pre>
  1432. * valueGetter: function (params) { if (!params.node.group) return gagaAgGrid.setRatio(params.data.payAmt, params.data.sellTagAmt); }
  1433. * </pre>
  1434. * @param value1 - 분자
  1435. * @param value2 - 분모
  1436. * @author gagamel
  1437. * @since 2020. 5. 11
  1438. */
  1439. setRatio : function(value1, value2) {
  1440. return {
  1441. value1: value1,
  1442. value2: value2,
  1443. toString: function() {
  1444. return value1 && value2 ? gagaAgGrid.toFixed(value1 / value2 * 100, 2) : 0;
  1445. }
  1446. };
  1447. },
  1448. // csv 파일 export
  1449. exportToCsv : function(title, gridOptions) {
  1450. var params = {
  1451. skipHeader: false,
  1452. skipFooters: false,
  1453. columnGroups: true,
  1454. skipGroups: false,
  1455. skipPinnedTop: false,
  1456. skipPinnedBottom: false,
  1457. allColumns: true,
  1458. onlySelected: false,
  1459. fileName: title + moment().format("YYYYMMDDHHmmss") + '.csv'
  1460. };
  1461. gridOptions.api.exportDataAsCsv(params);
  1462. },
  1463. /**
  1464. * 그리드 데이터를 엑셀로 내보내기
  1465. * <pre>
  1466. * gagaAgGrid.exportToExcel('주문목록', gridOptionsOrderList, columnKeys);
  1467. * or
  1468. * gagaAgGrid.exportToExcel('주문목록', gridOptionsOrderList, columnKeys, true);
  1469. * </pre>
  1470. * @param title - 엑셀의 타이틀
  1471. * @param gridOptions - Grid options
  1472. * @param columnKeys - Column keys (출력하고자 하는 칼럼 정의)
  1473. * @param isSelected - true/false
  1474. * @author gagamel
  1475. * @since 2019. 6. 7
  1476. */
  1477. exportToExcel : function(title, gridOptions, isSelected) {
  1478. var sColumnKeys = (typeof(columnKeys) == 'undefined') ? [] : columnKeys;
  1479. var bOnlySelected = (typeof(isSelected) == 'undefined') ? false : isSelected;
  1480. var params = {
  1481. columnKeys: sColumnKeys,
  1482. onlySelected: bOnlySelected, // true: Only export selected rows
  1483. fileName : title + "_" + new Date().format("YYYYMMDDHHmmss"),
  1484. sheetName: "DATA"/* ,
  1485. customHeader: title,
  1486. customFooter: "Copyright(c) 2019 TSIT, All rights reserved." */
  1487. };
  1488. gridOptions.excelStyles = [
  1489. {
  1490. id: 'dateFormat',
  1491. dataType: 'dateTime',
  1492. numberFormat: {
  1493. format: 'YYYY-MM-DD;@'
  1494. }
  1495. },
  1496. {
  1497. id: 'textFormat',
  1498. dataType: 'string'
  1499. }
  1500. ]
  1501. gridOptions.api.exportDataAsExcel(params);
  1502. },
  1503. }
  1504. /*var gDefaultTxt = '';
  1505. var gIsDisplayCode = true;
  1506. var ComboboxCellRenderer = function(defaultTxt, isDisplayCode) {
  1507. if (defaultTxt) gDefaultTxt = defaultTxt;
  1508. if (isDisplayCode) gIsDisplayCode = isDisplayCode;
  1509. }
  1510. ComboboxCellRenderer.prototype.init = function(params) {
  1511. this.eGui = document.createElement('span');
  1512. if (!gagajf.isNull(params.value)) {
  1513. var checked = (params.value == "Y" || params.value == "1") ? "checked" : "";
  1514. var input = document.createElement('input');
  1515. input.type = "checkbox";
  1516. input.checked = checked;
  1517. input.value = params.value;
  1518. input.addEventListener('click', function (event) {
  1519. if (params.value == "Y") params.value = "N";
  1520. else if (params.value == "N") params.value = "Y";
  1521. else if (params.value == "1") params.value = "0";
  1522. else if (params.value == "0") params.value = "1";
  1523. //checked input value has changed, perform your update here
  1524. console.log("addEventListener params.value: "+ params.value);
  1525. });
  1526. this.eGui.innerHTML = '';
  1527. this.eGui.appendChild(input);
  1528. }
  1529. };
  1530. ComboboxCellRenderer.prototype.getGui = function() {
  1531. return this.eGui;
  1532. };*/
  1533. // cellRenderer: 'ComboboxCellRenderer'
  1534. var getComboboxCellRenderer = function() {
  1535. function ComboboxCellRenderer() {};
  1536. ComboboxCellRenderer.prototype.init = function(params) {
  1537. this.eGui = document.createElement('span');
  1538. var span1 = document.createElement('span');
  1539. var span2 = document.createElement('span');
  1540. var span3 = document.createElement('span');
  1541. this.eGui.classList = 'cellChecked'
  1542. span1.classList = 'ag-selection-checkbox';
  1543. var check = 'params.data.' + params.colDef.field;
  1544. $(".allChecked").closest('div').each(function(){
  1545. if($(this).attr('col-id')==params.colDef.field){
  1546. if($(this).children('.allChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-unchecked').hasClass('ag-hidden')){
  1547. eval(check+' = "Y"');
  1548. }else if($(this).children('.allChecked').hasClass('uncheckedAll')){
  1549. eval(check+' = "N"');
  1550. }
  1551. }
  1552. });
  1553. if(eval(check)=='Y'){
  1554. span2.classList = 'ag-icon ag-icon-checkbox-checked';
  1555. span3.classList = 'ag-icon ag-icon-checkbox-unchecked ag-hidden';
  1556. }else{
  1557. eval(check+' = "N"');
  1558. span2.classList = 'ag-icon ag-icon-checkbox-checked ag-hidden';
  1559. span3.classList = 'ag-icon ag-icon-checkbox-unchecked';
  1560. }
  1561. this.eGui.addEventListener('click', function (event) {
  1562. if(span2.classList.contains('ag-hidden')){
  1563. eval(check+' = "Y"');
  1564. span2.classList.remove('ag-hidden');
  1565. span3.classList.add('ag-hidden');
  1566. $(".allChecked").closest('div').each(function(){
  1567. if($(this).attr('col-id')==params.colDef.field){
  1568. $(this).children('.allChecked').removeClass('uncheckedAll');
  1569. }
  1570. });
  1571. }else{
  1572. eval(check+' = "N"');
  1573. span2.classList.add('ag-hidden');
  1574. span3.classList.remove('ag-hidden');
  1575. $(".allChecked").closest('div').each(function(){
  1576. if($(this).attr('col-id')==params.colDef.field){
  1577. $(this).children('.allChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-checked').addClass('ag-hidden');
  1578. $(this).children('.allChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-unchecked').removeClass('ag-hidden');
  1579. }
  1580. });
  1581. }
  1582. });
  1583. span1.appendChild(span2);
  1584. span1.appendChild(span3);
  1585. this.eGui.innerHTML = '';
  1586. this.eGui.appendChild(span1);
  1587. };
  1588. ComboboxCellRenderer.prototype.getGui = function() {
  1589. return this.eGui;
  1590. };
  1591. return ComboboxCellRenderer;
  1592. }
  1593. // headerComponent : 'ComboboxHeaderComponent'
  1594. var getComboboxHeaderComponent = function() {
  1595. function ComboboxHeaderComponent() {};
  1596. ComboboxHeaderComponent.prototype.init = function(params) {
  1597. this.eGui = document.createElement('span');
  1598. var span1 = document.createElement('span');
  1599. var span2 = document.createElement('span');
  1600. var span3 = document.createElement('span');
  1601. this.eGui.classList = 'allChecked'
  1602. span1.classList = 'ag-selection-checkbox';
  1603. span2.classList = 'ag-icon ag-icon-checkbox-checked ag-hidden';
  1604. span3.classList = 'ag-icon ag-icon-checkbox-unchecked';
  1605. this.eGui.addEventListener('click', function (event) {
  1606. if(span2.classList.contains('ag-hidden')){
  1607. this.classList.remove('uncheckedAll');
  1608. span2.classList.remove('ag-hidden');
  1609. span3.classList.add('ag-hidden');
  1610. $(".ag-icon-checkbox-checked").closest('div').each(function(){
  1611. if($(this).attr('col-id')==params.column.colId){
  1612. $(this).children('.cellChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-checked').addClass('ag-hidden');
  1613. $(this).children('.cellChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-unchecked').removeClass('ag-hidden');
  1614. $(this).children('.cellChecked').click();
  1615. }
  1616. });
  1617. }else{
  1618. this.classList.add('uncheckedAll');
  1619. span2.classList.add('ag-hidden');
  1620. span3.classList.remove('ag-hidden');
  1621. $(".ag-icon-checkbox-checked").closest('div').each(function(){
  1622. if($(this).attr('col-id')==params.column.colId){
  1623. $(this).children('.cellChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-checked').removeClass('ag-hidden');
  1624. $(this).children('.cellChecked').children('.ag-selection-checkbox').children('.ag-icon-checkbox-unchecked').addClass('ag-hidden');
  1625. $(this).children('.cellChecked').click();
  1626. }
  1627. });
  1628. }
  1629. });
  1630. span1.appendChild(span2);
  1631. span1.appendChild(span3);
  1632. span1.append(" "+params.displayName);
  1633. this.eGui.innerHTML = '';
  1634. this.eGui.appendChild(span1);
  1635. };
  1636. ComboboxHeaderComponent.prototype.getGui = function() {
  1637. return this.eGui;
  1638. };
  1639. return ComboboxHeaderComponent;
  1640. }