evui 3.4.43 → 3.4.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evui",
3
- "version": "3.4.43",
3
+ "version": "3.4.44",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -367,6 +367,7 @@
367
367
  highlight: row[0] === highlightIdx,
368
368
  'non-border': !!borderStyle && borderStyle !== 'rows',
369
369
  }"
370
+ :disabled="row[ROW_DISABLED_INDEX]"
370
371
  @click="onRowClick($event, row)"
371
372
  @contextmenu="onRowClick($event, row, true)"
372
373
  @dblclick="onRowDblClick($event, row)"
@@ -388,7 +389,7 @@
388
389
  <ev-checkbox
389
390
  v-model="row[1]"
390
391
  class="row-checkbox-input"
391
- :disabled="row[5]"
392
+ :disabled="row[5] || row[ROW_DISABLED_INDEX]"
392
393
  @change="onCheck($event, row)"
393
394
  />
394
395
  </td>
@@ -439,12 +440,14 @@
439
440
  'border-right': orderedColumns.length - 1 === cellIndex
440
441
  ? 'none' : '1px solid #CFCFCF',
441
442
  }"
443
+ :disabled="row[ROW_DISABLED_INDEX]"
442
444
  >
443
445
  <!-- Cell Renderer -->
444
446
  <div v-if="!!$slots[column.field]">
445
447
  <slot
446
448
  :name="column.field"
447
449
  :item="{ row, column }"
450
+ :disabled="row[ROW_DISABLED_INDEX]"
448
451
  />
449
452
  </div>
450
453
  <!-- Cell Value -->
@@ -470,10 +473,12 @@
470
473
  'min-width': '30px',
471
474
  'line-height': `${rowHeight}px`,
472
475
  }"
476
+ :disabled="row[ROW_DISABLED_INDEX]"
473
477
  >
474
478
  <template v-if="$slots.contextmenuIcon">
475
479
  <span
476
480
  class="row-contextmenu__btn"
481
+ :disabled="row[ROW_DISABLED_INDEX]"
477
482
  @click="onContextMenu($event)"
478
483
  >
479
484
  <slot name="contextmenuIcon"></slot>
@@ -483,6 +488,7 @@
483
488
  <grid-option-button
484
489
  icon="ev-icon-warning2"
485
490
  class="row-contextmenu__btn"
491
+ :disabled="row[ROW_DISABLED_INDEX]"
486
492
  @click="onContextMenu($event)"
487
493
  />
488
494
  </template>
@@ -658,6 +664,10 @@ export default {
658
664
  type: [Array],
659
665
  default: () => [],
660
666
  },
667
+ disabled: {
668
+ type: [Array],
669
+ default: () => [],
670
+ },
661
671
  option: {
662
672
  type: Object,
663
673
  default: () => ({}),
@@ -684,6 +694,7 @@ export default {
684
694
  const ROW_DATA_INDEX = 2;
685
695
  const ROW_SELECT_INDEX = 3;
686
696
  const ROW_EXPAND_INDEX = 4;
697
+ const ROW_DISABLED_INDEX = 6;
687
698
  const {
688
699
  isRenderer,
689
700
  getComponentName,
@@ -731,8 +742,11 @@ export default {
731
742
  left: 0,
732
743
  columnListMenuWidth: 0,
733
744
  },
745
+ useDefaultColumnSetting: computed(
746
+ () => props.option?.useGridSetting?.useDefaultColumnSetting ?? true,
747
+ ),
734
748
  columnSettingTextInfo: {
735
- columnList: props.option?.useGridSetting?.columnMenuText ?? 'Column List',
749
+ title: props.option?.useGridSetting?.columnMenuText ?? 'Column List',
736
750
  search: props.option?.useGridSetting?.searchText ?? 'Search',
737
751
  empty: props.option?.useGridSetting?.emptyText ?? 'No records',
738
752
  ok: props.option?.useGridSetting?.okBtnText ?? 'OK',
@@ -761,7 +775,7 @@ export default {
761
775
  const extraColumns = stores.originColumns?.filter(
762
776
  column => !orderedColumnsIndexes.includes(column.index),
763
777
  );
764
- const copyOrderedColumns = cloneDeep(stores.orderedColumns);
778
+ const copyOrderedColumns = stores.orderedColumns;
765
779
  return [...copyOrderedColumns, ...extraColumns];
766
780
  }),
767
781
  });
@@ -1057,14 +1071,29 @@ export default {
1057
1071
 
1058
1072
  watch(
1059
1073
  () => props.columns,
1060
- () => {
1061
- sortInfo.isSorting = false;
1062
- sortInfo.sortField = '';
1063
- filterInfo.filteringColumn = null;
1064
- filterInfo.filteringItemsByColumn = {};
1065
- stores.filterStore = [];
1066
- setStore([], false);
1067
- initColumnSettingInfo();
1074
+ (newColumns, prevColumns) => {
1075
+ const isSameColumns = () => {
1076
+ // Column의 field로 동일한 컬럼인지 확인
1077
+ const newColumnsFields = newColumns.map(column => column.field);
1078
+ const prevColumnsFields = prevColumns.map(column => column.field);
1079
+ return prevColumnsFields.every(field => newColumnsFields.includes(field));
1080
+ };
1081
+
1082
+ if (newColumns.length !== prevColumns.length || !isSameColumns()) {
1083
+ // 동일하지 않은 컬럼으로 변경된 경우 initialize
1084
+ sortInfo.isSorting = false;
1085
+ sortInfo.sortField = '';
1086
+ filterInfo.filteringColumn = null;
1087
+ filterInfo.filteringItemsByColumn = {};
1088
+ stores.filterStore = [];
1089
+ setStore([], false);
1090
+ initColumnSettingInfo();
1091
+ } else if (stores.filteredColumns.length) {
1092
+ // 새로운 컬럼 기준으로 filteredColumns 를 업데이트 한다.
1093
+ stores.filteredColumns = newColumns.filter(
1094
+ column => !column.hidden && !column.hiddenDisplay,
1095
+ );
1096
+ }
1068
1097
  }, { deep: true },
1069
1098
  );
1070
1099
  watch(
@@ -1101,6 +1130,13 @@ export default {
1101
1130
  checkInfo.checkedRows = value;
1102
1131
  },
1103
1132
  );
1133
+ watch(() => props.disabled, () => {
1134
+ if (stores.store.length) {
1135
+ stores.store.forEach((row) => {
1136
+ row[ROW_DISABLED_INDEX] = props.disabled.includes(row[ROW_DATA_INDEX]);
1137
+ });
1138
+ }
1139
+ }, { deep: true });
1104
1140
  watch(
1105
1141
  () => checkInfo.checkedRows,
1106
1142
  (value) => {
@@ -1131,7 +1167,8 @@ export default {
1131
1167
  (value) => {
1132
1168
  if (selectInfo.useSelect) {
1133
1169
  stores.store.forEach((row) => {
1134
- row[ROW_SELECT_INDEX] = value.includes(row[ROW_DATA_INDEX]);
1170
+ row[ROW_SELECT_INDEX] = value.includes(row[ROW_DATA_INDEX])
1171
+ && !props.disabled.includes(row[ROW_DATA_INDEX]);
1135
1172
  });
1136
1173
  updateVScroll();
1137
1174
  }
@@ -1455,6 +1492,8 @@ export default {
1455
1492
  onDragStart,
1456
1493
  onDragOver,
1457
1494
  onDrop,
1495
+
1496
+ ROW_DISABLED_INDEX,
1458
1497
  };
1459
1498
  },
1460
1499
  };
@@ -8,7 +8,7 @@
8
8
  :style="columnSettingStyle"
9
9
  >
10
10
  <div class="ev-grid-column-setting__header">
11
- <p class="header-title"> {{ textInfo.columnList }} </p>
11
+ <p class="header-title"> {{ textInfo.title }} </p>
12
12
  <ev-text-field
13
13
  v-model="searchVm"
14
14
  type="search"
@@ -92,7 +92,7 @@ export default {
92
92
  textInfo: {
93
93
  type: Object,
94
94
  default: () => ({
95
- columnList: 'Column List',
95
+ title: 'Column List',
96
96
  search: 'Search',
97
97
  empty: 'No records',
98
98
  ok: 'OK',
@@ -151,6 +151,10 @@
151
151
  color: inherit;
152
152
  white-space: nowrap;
153
153
 
154
+ &[disabled=true] {
155
+ cursor: not-allowed;
156
+ }
157
+
154
158
  @include evThemify() {
155
159
  border-bottom: 1px solid evThemed('grid-bottom-border');
156
160
  }
@@ -166,7 +170,7 @@
166
170
  color: #FFFFFF;
167
171
  }
168
172
  &:hover {
169
- .row-contextmenu__btn {
173
+ .row-contextmenu__btn:not([disabled=true]) {
170
174
  display: grid;
171
175
  &:hover {
172
176
  cursor: pointer;
@@ -515,6 +515,7 @@ export const checkEvent = (params) => {
515
515
 
516
516
  const isAllChecked = store
517
517
  .filter(rowData => !props.uncheckable.includes(rowData[ROW_DATA_INDEX]))
518
+ .filter(rowData => !props.disabled.includes(rowData[ROW_DATA_INDEX]))
518
519
  .every(d => d[ROW_CHECK_INDEX]);
519
520
  if (store.length && isAllChecked) {
520
521
  checkInfo.isHeaderChecked = true;
@@ -545,7 +546,8 @@ export const checkEvent = (params) => {
545
546
  store = getPagingData();
546
547
  }
547
548
  store.forEach((row) => {
548
- const uncheckable = props.uncheckable.includes(row[ROW_DATA_INDEX]);
549
+ const uncheckable = props.uncheckable.includes(row[ROW_DATA_INDEX])
550
+ || props.disabled.includes(row[ROW_DATA_INDEX]);
549
551
  if (isHeaderChecked) {
550
552
  if (!checkInfo.checkedRows.includes(row[ROW_DATA_INDEX]) && !uncheckable) {
551
553
  checkInfo.checkedRows.push(row[ROW_DATA_INDEX]);
@@ -742,7 +744,8 @@ export const filterEvent = (params) => {
742
744
  checkInfo.isHeaderChecked = rowData.length === checkedCount;
743
745
  checkInfo.isHeaderIndeterminate = (rowData.length !== checkedCount) && checkedCount > 0;
744
746
  checkInfo.isHeaderUncheckable = rowData
745
- .every(row => props.uncheckable.includes(row[ROW_DATA_INDEX]));
747
+ .every(row => props.uncheckable.includes(row[ROW_DATA_INDEX])
748
+ || props.disabled.includes(row[ROW_DATA_INDEX]));
746
749
  }
747
750
  };
748
751
  /**
@@ -940,8 +943,8 @@ export const filterEvent = (params) => {
940
943
  stores.searchStore = stores.store.filter((row) => {
941
944
  let isShow = false;
942
945
  const rowData = columnSettingInfo.isFilteringColumn ? row[ROW_DATA_INDEX]
943
- .filter((data, idx) => columnSettingInfo.visibleColumnIdx
944
- .includes(idx)) : row[ROW_DATA_INDEX];
946
+ .filter((data, idx) => columnSettingInfo.visibleColumnIdx
947
+ .includes(idx)) : row[ROW_DATA_INDEX];
945
948
 
946
949
  for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
947
950
  const column = stores.orderedColumns[ix] || {};
@@ -1050,7 +1053,7 @@ export const contextMenuEvent = (params) => {
1050
1053
  if (event.target.className === 'column-name') {
1051
1054
  const sortable = column.sortable === undefined ? true : column.sortable;
1052
1055
  const filterable = filterInfo.isFiltering
1053
- && column.filterable === undefined ? true : column.filterable;
1056
+ && column.filterable === undefined ? true : column.filterable;
1054
1057
  const columnMenuItems = [
1055
1058
  {
1056
1059
  text: contextInfo.columnMenuTextInfo?.ascending ?? 'Ascending',
@@ -1114,8 +1117,9 @@ export const contextMenuEvent = (params) => {
1114
1117
  * @param {object} e - 이벤트 객체
1115
1118
  */
1116
1119
  const onGridSettingContextMenu = (e) => {
1120
+ const { useDefaultColumnSetting, columnSettingTextInfo } = columnSettingInfo;
1117
1121
  const columnListMenu = {
1118
- text: columnSettingInfo.columnSettingTextInfo?.columnList ?? 'Column List',
1122
+ text: columnSettingTextInfo?.columnList ?? 'Column List',
1119
1123
  isShowMenu: true,
1120
1124
  click: () => {
1121
1125
  columnSettingInfo.isShowColumnSetting = true;
@@ -1126,10 +1130,11 @@ export const contextMenuEvent = (params) => {
1126
1130
  if (contextInfo.customGridSettingContextMenu.length) {
1127
1131
  contextInfo.gridSettingContextMenuItems = [
1128
1132
  ...contextInfo.customGridSettingContextMenu,
1129
- columnListMenu,
1130
1133
  ];
1131
- } else {
1132
- contextInfo.gridSettingContextMenuItems = [columnListMenu];
1134
+ }
1135
+
1136
+ if (useDefaultColumnSetting) {
1137
+ contextInfo.gridSettingContextMenuItems.push(columnListMenu);
1133
1138
  }
1134
1139
  contextInfo.gridSettingMenu.show(e);
1135
1140
  };
@@ -1168,7 +1173,7 @@ export const storeEvent = (params) => {
1168
1173
  let hasUnChecked = false;
1169
1174
  rows.forEach((row, idx) => {
1170
1175
  const checked = props.checked.includes(row);
1171
- const uncheckable = props.uncheckable.includes(row);
1176
+ const uncheckable = props.uncheckable.includes(row) || props.disabled.includes(row);
1172
1177
  let selected = false;
1173
1178
  if (selectInfo.useSelect) {
1174
1179
  selected = props.selected.includes(row);
@@ -1180,11 +1185,13 @@ export const storeEvent = (params) => {
1180
1185
  if (expandedInfo.useRowDetail) {
1181
1186
  expanded = props.expanded.includes(row);
1182
1187
  }
1183
- store.push([idx, checked, row, selected, expanded, uncheckable]);
1188
+ const disabled = props.disabled.includes(row);
1189
+ store.push([idx, checked, row, selected, expanded, uncheckable, disabled]);
1184
1190
  });
1185
1191
  checkInfo.isHeaderChecked = rows.length > 0 ? !hasUnChecked : false;
1186
1192
  checkInfo.isHeaderIndeterminate = hasUnChecked && !!checkInfo.checkedRows.length;
1187
- checkInfo.isHeaderUncheckable = rows.every(row => props.uncheckable.includes(row));
1193
+ checkInfo.isHeaderUncheckable = rows.every(row => props.uncheckable.includes(row)
1194
+ || props.disabled.includes(row));
1188
1195
  stores.originStore = store;
1189
1196
  }
1190
1197
  if (filterInfo.isFiltering) {
@@ -259,7 +259,6 @@ import {
259
259
  onMounted,
260
260
  onUnmounted,
261
261
  } from 'vue';
262
- import { cloneDeep } from 'lodash-es';
263
262
  import TreeGridNode from './TreeGridNode';
264
263
  import Toolbar from './TreeGridToolbar';
265
264
  import GridPagination from '../grid/GridPagination';
@@ -366,8 +365,11 @@ export default {
366
365
  left: 0,
367
366
  columnListMenuWidth: 0,
368
367
  },
368
+ useDefaultColumnSetting: computed(
369
+ () => props.option?.useGridSetting?.useDefaultColumnSetting ?? true,
370
+ ),
369
371
  columnSettingTextInfo: {
370
- columnList: props.option?.useGridSetting?.columnMenuText ?? 'Column List',
372
+ title: props.option?.useGridSetting?.columnMenuText ?? 'Column List',
371
373
  search: props.option?.useGridSetting?.searchText ?? 'Search',
372
374
  empty: props.option?.useGridSetting?.emptyText ?? 'No records',
373
375
  ok: props.option?.useGridSetting?.okBtnText ?? 'OK',
@@ -391,7 +393,7 @@ export default {
391
393
  const extraColumns = stores.originColumns?.filter(
392
394
  column => !orderedColumnsIndexes.includes(column.index),
393
395
  );
394
- const copyOrderedColumns = cloneDeep(stores.orderedColumns);
396
+ const copyOrderedColumns = stores.orderedColumns;
395
397
  return [...copyOrderedColumns, ...extraColumns];
396
398
  }),
397
399
  });
@@ -648,8 +650,22 @@ export default {
648
650
 
649
651
  watch(
650
652
  () => props.columns,
651
- () => {
652
- initColumnSettingInfo();
653
+ (newColumns, prevColumns) => {
654
+ const isSameColumns = () => {
655
+ // Column의 field로 동일한 컬럼인지 확인
656
+ const newColumnsFields = newColumns.map(column => column.field);
657
+ const prevColumnsFields = prevColumns.map(column => column.field);
658
+ return prevColumnsFields.every(field => newColumnsFields.includes(field));
659
+ };
660
+
661
+ if (newColumns.length !== prevColumns.length || !isSameColumns()) {
662
+ initColumnSettingInfo();
663
+ } else if (stores.filteredColumns.length) {
664
+ // 새로운 컬럼 기준으로 filteredColumns 를 업데이트 한다.
665
+ stores.filteredColumns = newColumns.filter(
666
+ column => !column.hidden && !column.hiddenDisplay,
667
+ );
668
+ }
653
669
  }, { deep: true },
654
670
  );
655
671
  watch(
@@ -666,8 +666,9 @@ export const contextMenuEvent = (params) => {
666
666
  * @param {object} e - 이벤트 객체
667
667
  */
668
668
  const onGridSettingContextMenu = (e) => {
669
+ const { useDefaultColumnSetting, columnSettingTextInfo } = columnSettingInfo;
669
670
  const columnListMenu = {
670
- text: columnSettingInfo.columnSettingTextInfo?.columnList ?? 'Column List',
671
+ text: columnSettingTextInfo?.columnList ?? 'Column List',
671
672
  isShowMenu: true,
672
673
  click: () => {
673
674
  columnSettingInfo.isShowColumnSetting = true;
@@ -678,10 +679,11 @@ export const contextMenuEvent = (params) => {
678
679
  if (contextInfo.customGridSettingContextMenu.length) {
679
680
  contextInfo.gridSettingContextMenuItems = [
680
681
  ...contextInfo.customGridSettingContextMenu,
681
- columnListMenu,
682
682
  ];
683
- } else {
684
- contextInfo.gridSettingContextMenuItems = [columnListMenu];
683
+ }
684
+
685
+ if (useDefaultColumnSetting) {
686
+ contextInfo.gridSettingContextMenuItems.push(columnListMenu);
685
687
  }
686
688
  contextInfo.gridSettingMenu.show(e);
687
689
  };