@visactor/vtable-plugins 1.22.4-alpha.10 → 1.22.4-alpha.12

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.
@@ -10362,19 +10362,25 @@ ${recordsStr}
10362
10362
  class ValueFilter {
10363
10363
  table;
10364
10364
  filterStateManager;
10365
+ pluginOptions;
10365
10366
  styles;
10366
10367
  uniqueKeys = new Map();
10367
10368
  displayToRawValueMap = new Map();
10368
10369
  selectedField;
10369
10370
  valueFilterOptionList = new Map();
10370
10371
  filterByValuePanel;
10372
+ searchContainer;
10373
+ optionsContainer;
10374
+ selectAllItemDiv;
10375
+ selectAllLabel;
10371
10376
  filterByValueSearchInput;
10372
10377
  selectAllCheckbox;
10373
10378
  filterItemsContainer;
10374
- constructor(table, filterStateManager, styles) {
10379
+ constructor(table, filterStateManager, pluginOptions) {
10375
10380
  this.table = table;
10376
10381
  this.filterStateManager = filterStateManager;
10377
- this.styles = styles;
10382
+ this.pluginOptions = pluginOptions;
10383
+ this.styles = pluginOptions.styles;
10378
10384
  this.filterStateManager.subscribe((state) => {
10379
10385
  const filterState = state.filters.get(this.selectedField);
10380
10386
  if (filterState && filterState.type === 'byValue') {
@@ -10591,6 +10597,7 @@ ${recordsStr}
10591
10597
  initFilterStateFromTableData(fieldId) {
10592
10598
  const filter = this.filterStateManager.getFilterState(fieldId);
10593
10599
  const isEnable = filter?.enable;
10600
+ const syncCheckboxCheckedState = this.pluginOptions?.syncCheckboxCheckedState ?? true;
10594
10601
  if (isEnable) {
10595
10602
  const selectedRawValues = new Set();
10596
10603
  const displayToRawMap = this.displayToRawValueMap.get(fieldId);
@@ -10630,7 +10637,7 @@ ${recordsStr}
10630
10637
  }
10631
10638
  }
10632
10639
  const hasChanged = !arrayEqual(filter.values, Array.from(selectedRawValues));
10633
- if (hasChanged) {
10640
+ if (hasChanged && syncCheckboxCheckedState) {
10634
10641
  this.filterStateManager.dispatch({
10635
10642
  type: exports.FilterActionType.UPDATE_FILTER,
10636
10643
  payload: {
@@ -10641,22 +10648,20 @@ ${recordsStr}
10641
10648
  }
10642
10649
  }
10643
10650
  else {
10644
- if (!filter) {
10645
- const availableRawValues = this.uniqueKeys
10646
- .get(fieldId)
10647
- ?.filter(item => item.count > 0)
10648
- ?.map(item => item.rawValue)
10649
- .filter(v => v !== undefined && v !== null) || [];
10650
- this.filterStateManager.dispatch({
10651
- type: exports.FilterActionType.ADD_FILTER,
10652
- payload: {
10653
- field: fieldId,
10654
- type: 'byValue',
10655
- values: availableRawValues,
10656
- enable: false
10657
- }
10658
- });
10659
- }
10651
+ const availableRawValues = this.uniqueKeys
10652
+ .get(fieldId)
10653
+ ?.filter(item => !syncCheckboxCheckedState || item.count > 0)
10654
+ ?.map(item => item.rawValue)
10655
+ .filter(v => v !== undefined && v !== null) || [];
10656
+ this.filterStateManager.dispatch({
10657
+ type: exports.FilterActionType.ADD_FILTER,
10658
+ payload: {
10659
+ field: fieldId,
10660
+ type: 'byValue',
10661
+ values: availableRawValues,
10662
+ enable: false
10663
+ }
10664
+ });
10660
10665
  }
10661
10666
  }
10662
10667
  syncCheckboxesWithFilterState(filter) {
@@ -10697,14 +10702,15 @@ ${recordsStr}
10697
10702
  }
10698
10703
  }
10699
10704
  applyFilter(fieldId = this.selectedField) {
10700
- const visibleSelectedKeys = Array.from(this.filterStateManager.getVisibleSelectedValues(fieldId));
10701
- if (visibleSelectedKeys.length > 0 && visibleSelectedKeys.length < this.uniqueKeys.get(fieldId)?.length) {
10705
+ const filter = this.filterStateManager.getFilterState(fieldId);
10706
+ const allSelectedValues = filter.values;
10707
+ if (allSelectedValues.length >= 0 && allSelectedValues.length < this.uniqueKeys.get(fieldId)?.length) {
10702
10708
  this.filterStateManager.dispatch({
10703
10709
  type: exports.FilterActionType.APPLY_FILTERS,
10704
10710
  payload: {
10705
10711
  field: fieldId,
10706
10712
  type: 'byValue',
10707
- values: visibleSelectedKeys,
10713
+ values: allSelectedValues,
10708
10714
  enable: true
10709
10715
  }
10710
10716
  });
@@ -10730,31 +10736,46 @@ ${recordsStr}
10730
10736
  render(container) {
10731
10737
  this.filterByValuePanel = document.createElement('div');
10732
10738
  applyStyles(this.filterByValuePanel, this.styles.filterPanel);
10733
- const searchContainer = document.createElement('div');
10734
- applyStyles(searchContainer, this.styles.searchContainer);
10739
+ this.searchContainer = document.createElement('div');
10740
+ applyStyles(this.searchContainer, this.styles.searchContainer);
10735
10741
  this.filterByValueSearchInput = document.createElement('input');
10736
10742
  this.filterByValueSearchInput.type = 'text';
10737
10743
  this.filterByValueSearchInput.placeholder = this.styles.searchInput?.placeholder || '可使用空格分隔多个关键词';
10738
10744
  applyStyles(this.filterByValueSearchInput, this.styles.searchInput);
10739
- searchContainer.appendChild(this.filterByValueSearchInput);
10740
- const optionsContainer = document.createElement('div');
10741
- applyStyles(optionsContainer, this.styles.optionsContainer);
10742
- const selectAllItemDiv = document.createElement('div');
10743
- applyStyles(selectAllItemDiv, this.styles.optionItem);
10744
- const selectAllLabel = document.createElement('label');
10745
- applyStyles(selectAllLabel, this.styles.optionLabel);
10745
+ this.searchContainer.appendChild(this.filterByValueSearchInput);
10746
+ this.optionsContainer = document.createElement('div');
10747
+ applyStyles(this.optionsContainer, this.styles.optionsContainer);
10748
+ this.selectAllItemDiv = document.createElement('div');
10749
+ applyStyles(this.selectAllItemDiv, this.styles.optionItem);
10750
+ this.selectAllLabel = document.createElement('label');
10751
+ applyStyles(this.selectAllLabel, this.styles.optionLabel);
10746
10752
  this.selectAllCheckbox = document.createElement('input');
10747
10753
  this.selectAllCheckbox.type = 'checkbox';
10748
10754
  this.selectAllCheckbox.checked = true;
10749
10755
  applyStyles(this.selectAllCheckbox, this.styles.checkbox);
10750
- selectAllLabel.append(this.selectAllCheckbox, ' 全选');
10751
- selectAllItemDiv.appendChild(selectAllLabel);
10756
+ this.selectAllLabel.append(this.selectAllCheckbox, ' 全选');
10757
+ this.selectAllItemDiv.appendChild(this.selectAllLabel);
10752
10758
  this.filterItemsContainer = document.createElement('div');
10753
- optionsContainer.append(selectAllItemDiv, this.filterItemsContainer);
10754
- this.filterByValuePanel.append(searchContainer, optionsContainer);
10759
+ this.optionsContainer.append(this.selectAllItemDiv, this.filterItemsContainer);
10760
+ this.filterByValuePanel.append(this.searchContainer, this.optionsContainer);
10755
10761
  container.appendChild(this.filterByValuePanel);
10756
10762
  this.bindEventForFilterByValue();
10757
10763
  }
10764
+ updatePluginOptions(pluginOptions) {
10765
+ this.pluginOptions = pluginOptions;
10766
+ this.styles = pluginOptions.styles;
10767
+ this.updateStyles(pluginOptions.styles);
10768
+ }
10769
+ updateStyles(styles) {
10770
+ applyStyles(this.filterByValuePanel, styles.filterPanel);
10771
+ applyStyles(this.searchContainer, styles.searchContainer);
10772
+ this.filterByValueSearchInput.placeholder = styles.searchInput?.placeholder || '可使用空格分隔多个关键词';
10773
+ applyStyles(this.filterByValueSearchInput, styles.searchInput);
10774
+ applyStyles(this.optionsContainer, styles.optionsContainer);
10775
+ applyStyles(this.selectAllItemDiv, styles.optionItem);
10776
+ applyStyles(this.selectAllLabel, styles.optionLabel);
10777
+ applyStyles(this.selectAllCheckbox, styles.checkbox);
10778
+ }
10758
10779
  renderFilterOptions(field) {
10759
10780
  this.filterItemsContainer.innerHTML = '';
10760
10781
  this.valueFilterOptionList.delete(field);
@@ -10906,19 +10927,25 @@ ${recordsStr}
10906
10927
  filterStateManager;
10907
10928
  styles;
10908
10929
  filterByConditionPanel;
10930
+ conditionContainer;
10931
+ categoryLabel;
10909
10932
  selectedField;
10910
10933
  operatorSelect;
10911
10934
  valueInput;
10935
+ andLabel;
10912
10936
  valueInputMax;
10913
10937
  categorySelect;
10938
+ operatorLabel;
10939
+ rangeInputContainer;
10940
+ valueLabel;
10914
10941
  currentCategory = exports.FilterOperatorCategory.ALL;
10915
10942
  categories = [];
10916
10943
  operators = [];
10917
- constructor(table, filterStateManager, styles, conditionCategories) {
10944
+ constructor(table, filterStateManager, pluginOptions) {
10918
10945
  this.table = table;
10919
- this.styles = styles;
10946
+ this.styles = pluginOptions.styles;
10920
10947
  this.filterStateManager = filterStateManager;
10921
- this.categories = conditionCategories;
10948
+ this.categories = pluginOptions.conditionCategories;
10922
10949
  this.operators = operators;
10923
10950
  }
10924
10951
  setSelectedField(fieldId) {
@@ -11091,10 +11118,10 @@ ${recordsStr}
11091
11118
  render(container) {
11092
11119
  this.filterByConditionPanel = document.createElement('div');
11093
11120
  applyStyles(this.filterByConditionPanel, this.styles.filterPanel);
11094
- const conditionContainer = document.createElement('div');
11095
- applyStyles(conditionContainer, this.styles.conditionContainer);
11096
- const categoryLabel = createElement('label', {}, ['筛选类型:']);
11097
- applyStyles(categoryLabel, this.styles.formLabel);
11121
+ this.conditionContainer = document.createElement('div');
11122
+ applyStyles(this.conditionContainer, this.styles.conditionContainer);
11123
+ this.categoryLabel = createElement('label', {}, ['筛选类型:']);
11124
+ applyStyles(this.categoryLabel, this.styles.formLabel);
11098
11125
  this.categorySelect = createElement('select');
11099
11126
  applyStyles(this.categorySelect, this.styles.operatorSelect);
11100
11127
  this.categories.forEach(category => {
@@ -11103,43 +11130,61 @@ ${recordsStr}
11103
11130
  option.textContent = category.label;
11104
11131
  this.categorySelect.appendChild(option);
11105
11132
  });
11106
- const operatorLabel = createElement('label', {}, ['筛选条件:']);
11107
- applyStyles(operatorLabel, this.styles.formLabel);
11133
+ this.operatorLabel = createElement('label', {}, ['筛选条件:']);
11134
+ applyStyles(this.operatorLabel, this.styles.formLabel);
11108
11135
  this.operatorSelect = createElement('select');
11109
11136
  applyStyles(this.operatorSelect, this.styles.operatorSelect);
11110
- const valueLabel = createElement('label', {}, ['筛选值:']);
11111
- applyStyles(valueLabel, this.styles.formLabel);
11112
- const rangeInputContainer = createElement('div');
11113
- applyStyles(rangeInputContainer, this.styles.rangeInputContainer);
11137
+ this.valueLabel = createElement('label', {}, ['筛选值:']);
11138
+ applyStyles(this.valueLabel, this.styles.formLabel);
11139
+ this.rangeInputContainer = createElement('div');
11140
+ applyStyles(this.rangeInputContainer, this.styles.rangeInputContainer);
11114
11141
  this.valueInput = createElement('input', {
11115
11142
  type: 'text',
11116
11143
  placeholder: '请输入筛选值'
11117
11144
  });
11118
11145
  applyStyles(this.valueInput, this.styles.searchInput);
11119
- const andLabel = createElement('span', {}, ['和']);
11120
- applyStyles(andLabel, this.styles.addLabel);
11121
- andLabel.style.display = 'none';
11146
+ this.andLabel = createElement('span', {}, ['和']);
11147
+ applyStyles(this.andLabel, this.styles.addLabel);
11148
+ this.andLabel.style.display = 'none';
11122
11149
  this.valueInputMax = createElement('input', {
11123
11150
  type: 'text',
11124
11151
  placeholder: '最大值'
11125
11152
  });
11126
11153
  applyStyles(this.valueInputMax, this.styles.searchInput);
11127
11154
  this.valueInputMax.style.display = 'none';
11128
- rangeInputContainer.appendChild(this.valueInput);
11129
- rangeInputContainer.appendChild(andLabel);
11130
- rangeInputContainer.appendChild(this.valueInputMax);
11131
- conditionContainer.appendChild(categoryLabel);
11132
- conditionContainer.appendChild(this.categorySelect);
11133
- conditionContainer.appendChild(operatorLabel);
11134
- conditionContainer.appendChild(this.operatorSelect);
11135
- conditionContainer.appendChild(valueLabel);
11136
- conditionContainer.appendChild(rangeInputContainer);
11137
- this.filterByConditionPanel.appendChild(conditionContainer);
11155
+ this.rangeInputContainer.appendChild(this.valueInput);
11156
+ this.rangeInputContainer.appendChild(this.andLabel);
11157
+ this.rangeInputContainer.appendChild(this.valueInputMax);
11158
+ this.conditionContainer.appendChild(this.categoryLabel);
11159
+ this.conditionContainer.appendChild(this.categorySelect);
11160
+ this.conditionContainer.appendChild(this.operatorLabel);
11161
+ this.conditionContainer.appendChild(this.operatorSelect);
11162
+ this.conditionContainer.appendChild(this.valueLabel);
11163
+ this.conditionContainer.appendChild(this.rangeInputContainer);
11164
+ this.filterByConditionPanel.appendChild(this.conditionContainer);
11138
11165
  container.appendChild(this.filterByConditionPanel);
11139
11166
  this.hide();
11140
11167
  this.updateOperatorOptions();
11141
11168
  this.bindEvents();
11142
11169
  }
11170
+ updatePluginOptions(filterOptions) {
11171
+ this.styles = filterOptions.styles;
11172
+ this.categories = filterOptions.conditionCategories;
11173
+ this.updateStyles(filterOptions.styles);
11174
+ }
11175
+ updateStyles(styles) {
11176
+ applyStyles(this.filterByConditionPanel, styles.filterPanel);
11177
+ applyStyles(this.conditionContainer, styles.conditionContainer);
11178
+ applyStyles(this.categoryLabel, styles.formLabel);
11179
+ applyStyles(this.categorySelect, styles.operatorSelect);
11180
+ applyStyles(this.operatorLabel, styles.formLabel);
11181
+ applyStyles(this.operatorSelect, styles.operatorSelect);
11182
+ applyStyles(this.valueLabel, styles.formLabel);
11183
+ applyStyles(this.rangeInputContainer, styles.rangeInputContainer);
11184
+ applyStyles(this.valueInput, styles.searchInput);
11185
+ applyStyles(this.andLabel, styles.addLabel);
11186
+ applyStyles(this.valueInputMax, styles.searchInput);
11187
+ }
11143
11188
  bindEvents() {
11144
11189
  this.valueInput.addEventListener('keypress', event => {
11145
11190
  if (event.key === 'Enter') {
@@ -11193,20 +11238,22 @@ ${recordsStr}
11193
11238
  selectedField = null;
11194
11239
  filterModes = [];
11195
11240
  filterMenu;
11241
+ filterTabsContainer;
11196
11242
  filterMenuWidth;
11197
11243
  currentCol;
11198
11244
  currentRow;
11199
11245
  filterTabByValue;
11200
11246
  filterTabByCondition;
11247
+ footerContainer;
11201
11248
  clearFilterOptionLink;
11202
11249
  cancelFilterButton;
11203
11250
  applyFilterButton;
11204
- constructor(table, filterStateManager, styles, conditionCategories) {
11251
+ constructor(table, filterStateManager, pluginOptions) {
11205
11252
  this.table = table;
11206
11253
  this.filterStateManager = filterStateManager;
11207
- this.styles = styles;
11208
- this.valueFilter = new ValueFilter(this.table, this.filterStateManager, this.styles);
11209
- this.conditionFilter = new ConditionFilter(this.table, this.filterStateManager, this.styles, conditionCategories);
11254
+ this.styles = pluginOptions.styles;
11255
+ this.valueFilter = new ValueFilter(this.table, this.filterStateManager, pluginOptions);
11256
+ this.conditionFilter = new ConditionFilter(this.table, this.filterStateManager, pluginOptions);
11210
11257
  this.filterMenuWidth = 300;
11211
11258
  this.filterStateManager.subscribe(state => {
11212
11259
  if (this.isVisible && this.selectedField !== null) {
@@ -11214,6 +11261,10 @@ ${recordsStr}
11214
11261
  }
11215
11262
  });
11216
11263
  }
11264
+ updatePluginOptions(pluginOptions) {
11265
+ this.valueFilter.updatePluginOptions(pluginOptions);
11266
+ this.conditionFilter.updatePluginOptions(pluginOptions);
11267
+ }
11217
11268
  onTabSwitch(tab) {
11218
11269
  this.activeTab = tab;
11219
11270
  if (tab === 'byValue') {
@@ -11269,17 +11320,17 @@ ${recordsStr}
11269
11320
  this.filterMenu.classList.add('vtable-filter-menu');
11270
11321
  applyStyles(this.filterMenu, this.styles.filterMenu);
11271
11322
  this.filterMenu.style.width = `${this.filterMenuWidth}px`;
11272
- const filterTabsContainer = document.createElement('div');
11273
- applyStyles(filterTabsContainer, this.styles.tabsContainer);
11323
+ this.filterTabsContainer = document.createElement('div');
11324
+ applyStyles(this.filterTabsContainer, this.styles.tabsContainer);
11274
11325
  this.filterTabByValue = document.createElement('button');
11275
11326
  this.filterTabByValue.innerText = '按值筛选';
11276
11327
  applyStyles(this.filterTabByValue, this.styles.tabStyle(true));
11277
11328
  this.filterTabByCondition = document.createElement('button');
11278
11329
  this.filterTabByCondition.innerText = '按条件筛选';
11279
11330
  applyStyles(this.filterTabByCondition, this.styles.tabStyle(false));
11280
- filterTabsContainer.append(this.filterTabByValue, this.filterTabByCondition);
11281
- const footerContainer = document.createElement('div');
11282
- applyStyles(footerContainer, this.styles.footerContainer);
11331
+ this.filterTabsContainer.append(this.filterTabByValue, this.filterTabByCondition);
11332
+ this.footerContainer = document.createElement('div');
11333
+ applyStyles(this.footerContainer, this.styles.footerContainer);
11283
11334
  this.clearFilterOptionLink = document.createElement('a');
11284
11335
  this.clearFilterOptionLink.href = '#';
11285
11336
  this.clearFilterOptionLink.innerText = '清除筛选';
@@ -11292,14 +11343,25 @@ ${recordsStr}
11292
11343
  this.applyFilterButton.innerText = '确认';
11293
11344
  applyStyles(this.applyFilterButton, this.styles.footerButton(true));
11294
11345
  footerButtons.append(this.cancelFilterButton, this.applyFilterButton);
11295
- footerContainer.append(this.clearFilterOptionLink, footerButtons);
11296
- this.filterMenu.append(filterTabsContainer);
11346
+ this.footerContainer.append(this.clearFilterOptionLink, footerButtons);
11347
+ this.filterMenu.append(this.filterTabsContainer);
11297
11348
  this.valueFilter.render(this.filterMenu);
11298
11349
  this.conditionFilter.render(this.filterMenu);
11299
- this.filterMenu.append(footerContainer);
11350
+ this.filterMenu.append(this.footerContainer);
11300
11351
  container.appendChild(this.filterMenu);
11301
11352
  this.attachEventListeners();
11302
11353
  }
11354
+ updateStyles(styles) {
11355
+ applyStyles(this.filterMenu, styles.filterMenu);
11356
+ applyStyles(this.filterTabsContainer, styles.tabsContainer);
11357
+ applyStyles(this.filterTabByValue, styles.tabStyle(true));
11358
+ applyStyles(this.footerContainer, styles.footerContainer);
11359
+ applyStyles(this.clearFilterOptionLink, styles.clearLink);
11360
+ applyStyles(this.cancelFilterButton, styles.footerButton(false));
11361
+ applyStyles(this.applyFilterButton, styles.footerButton(true));
11362
+ this.valueFilter.updateStyles(styles);
11363
+ this.conditionFilter.updateStyles(styles);
11364
+ }
11303
11365
  attachEventListeners() {
11304
11366
  this.filterTabByValue.addEventListener('click', () => {
11305
11367
  this.onTabSwitch('byValue');
@@ -11342,6 +11404,8 @@ ${recordsStr}
11342
11404
  let top = 0;
11343
11405
  const canvasBounds = this.table.canvas.getBoundingClientRect();
11344
11406
  const cell = this.table.getCellRelativeRect(effectiveCol, effectiveRow);
11407
+ const filterMenuWidth = this.filterMenuWidth;
11408
+ const filterMenuHeight = 380;
11345
11409
  if (cell.right < this.filterMenuWidth) {
11346
11410
  left = cell.left + canvasBounds.left;
11347
11411
  top = cell.bottom + canvasBounds.top;
@@ -11350,6 +11414,8 @@ ${recordsStr}
11350
11414
  left = cell.right + canvasBounds.left - this.filterMenuWidth;
11351
11415
  top = cell.bottom + canvasBounds.top;
11352
11416
  }
11417
+ left = Math.max(0, Math.min(window.innerWidth - filterMenuWidth, left));
11418
+ top = Math.max(0, Math.min(window.innerHeight - filterMenuHeight, top));
11353
11419
  this.filterMenu.style.display = this.isVisible ? 'block' : 'none';
11354
11420
  this.filterMenu.style.left = `${left}px`;
11355
11421
  this.filterMenu.style.top = `${top}px`;
@@ -20906,7 +20972,7 @@ ${recordsStr}
20906
20972
  initFilterPlugin(eventArgs) {
20907
20973
  this.filterEngine = new FilterEngine();
20908
20974
  this.filterStateManager = new FilterStateManager(this.table, this.filterEngine);
20909
- this.filterToolbar = new FilterToolbar(this.table, this.filterStateManager, this.pluginOptions.styles, this.pluginOptions.conditionCategories);
20975
+ this.filterToolbar = new FilterToolbar(this.table, this.filterStateManager, this.pluginOptions);
20910
20976
  this.columns = eventArgs.options.columns;
20911
20977
  this.filterToolbar.render(document.body);
20912
20978
  this.updateFilterIcons(this.columns);
@@ -20960,14 +21026,18 @@ ${recordsStr}
20960
21026
  }
20961
21027
  }
20962
21028
  }
21029
+ updatePluginOptions(pluginOptions) {
21030
+ this.pluginOptions = lodashExports.merge(this.pluginOptions, pluginOptions);
21031
+ this.filterToolbar.updatePluginOptions(this.pluginOptions);
21032
+ }
20963
21033
  update() {
20964
21034
  if (this.filterToolbar.valueFilter) {
20965
21035
  const allFields = this.table.columns.map(col => col.field);
20966
21036
  const valueFilter = this.filterToolbar.valueFilter;
20967
21037
  allFields.forEach(field => {
20968
21038
  valueFilter.collectUniqueColumnValues(field, true);
20969
- valueFilter.updateUI(this.filterStateManager.getFilterState(field));
20970
21039
  });
21040
+ valueFilter.updateUI(this.filterStateManager.getFilterState(this.filterToolbar.selectedField));
20971
21041
  }
20972
21042
  if (this.filterStateManager) {
20973
21043
  this.reapplyActiveFilters();