vue2-excel-grid 2.0.2 → 2.1.0

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": "vue2-excel-grid",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Excel-style grid component for Vue 2.6.14 with virtual scrolling",
5
5
  "license": "MIT",
6
6
  "author": "Fozilbek Raimberdiyev",
@@ -3667,6 +3667,17 @@ const ExcelGridComponent = {
3667
3667
  return
3668
3668
  }
3669
3669
 
3670
+ if (key === 'd' && (e.ctrlKey || e.metaKey)) {
3671
+ e.preventDefault()
3672
+ this.fillDown()
3673
+ return
3674
+ }
3675
+ if (key === 'r' && (e.ctrlKey || e.metaKey)) {
3676
+ e.preventDefault()
3677
+ this.fillRight()
3678
+ return
3679
+ }
3680
+
3670
3681
  if (key === 'Delete' || key === 'Backspace') {
3671
3682
  e.preventDefault()
3672
3683
  this.clearSelection()
@@ -5051,6 +5062,107 @@ const ExcelGridComponent = {
5051
5062
  if (skipped.length > 0) this._emitBulkValidationError(skipped, false)
5052
5063
  },
5053
5064
 
5065
+ // =========================================================
5066
+ // Ctrl+D / Ctrl+R — Excel's standard fill-down/fill-right (3.96)
5067
+ // =========================================================
5068
+ // Plain copy, NOT the fill-handle's series continuation (generateFillValues,
5069
+ // 1,2,3->4,5,6) — matches real Excel: Ctrl+D/Ctrl+R just duplicates a row/
5070
+ // column's values, it never extrapolates a pattern.
5071
+ async _fillAxis(direction) {
5072
+ if (this.internalLocked) return
5073
+ if (!this.selectionRanges.length) return
5074
+ const oldData = this.data
5075
+ const newData = oldData.slice()
5076
+ const skipped = []
5077
+ const appliedRanges = []
5078
+
5079
+ for (const range of this.selectionRanges) {
5080
+ const r = normalizeRange(range)
5081
+ if (direction === 'down') {
5082
+ let srcRow, firstTargetRow, lastTargetRow
5083
+ if (r.startRow === r.endRow) {
5084
+ // Single-row selection: Excel fills from the row directly above.
5085
+ srcRow = r.startRow - 1
5086
+ if (srcRow < 0) continue
5087
+ firstTargetRow = r.startRow
5088
+ lastTargetRow = r.startRow
5089
+ } else {
5090
+ srcRow = r.startRow
5091
+ firstTargetRow = r.startRow + 1
5092
+ lastTargetRow = r.endRow
5093
+ }
5094
+ for (let ci = r.startCol; ci <= r.endCol; ci++) {
5095
+ const col = this.leafCols[ci]
5096
+ if (!col) continue
5097
+ const srcVal = oldData[srcRow] ? oldData[srcRow][col.key] : ''
5098
+ for (let ri = firstTargetRow; ri <= lastTargetRow; ri++) {
5099
+ if (!this.isCellEditable(ri, ci)) continue
5100
+ const v = this._coerceCellValue(ci, this._applyColMask(ci, srcVal))
5101
+ if (!this.isCellValueValid(ri, ci, v)) { skipped.push({ row: ri, col: ci, value: v }); continue }
5102
+ if (newData[ri] === oldData[ri]) newData[ri] = { ...oldData[ri] }
5103
+ newData[ri][col.key] = v
5104
+ }
5105
+ }
5106
+ appliedRanges.push({
5107
+ sourceRange: { startRow: srcRow, endRow: srcRow, startCol: r.startCol, endCol: r.endCol },
5108
+ targetRange: { startRow: firstTargetRow, endRow: lastTargetRow, startCol: r.startCol, endCol: r.endCol }
5109
+ })
5110
+ } else {
5111
+ let srcCol, firstTargetCol, lastTargetCol
5112
+ if (r.startCol === r.endCol) {
5113
+ // Single-column selection: Excel fills from the column directly to the left.
5114
+ srcCol = r.startCol - 1
5115
+ if (srcCol < 0) continue
5116
+ firstTargetCol = r.startCol
5117
+ lastTargetCol = r.startCol
5118
+ } else {
5119
+ srcCol = r.startCol
5120
+ firstTargetCol = r.startCol + 1
5121
+ lastTargetCol = r.endCol
5122
+ }
5123
+ const srcColDef = this.leafCols[srcCol]
5124
+ for (let ri = r.startRow; ri <= r.endRow; ri++) {
5125
+ const srcVal = srcColDef && oldData[ri] ? oldData[ri][srcColDef.key] : ''
5126
+ for (let ci = firstTargetCol; ci <= lastTargetCol; ci++) {
5127
+ const col = this.leafCols[ci]
5128
+ if (!col || !this.isCellEditable(ri, ci)) continue
5129
+ const v = this._coerceCellValue(ci, this._applyColMask(ci, srcVal))
5130
+ if (!this.isCellValueValid(ri, ci, v)) { skipped.push({ row: ri, col: ci, value: v }); continue }
5131
+ if (newData[ri] === oldData[ri]) newData[ri] = { ...oldData[ri] }
5132
+ newData[ri][col.key] = v
5133
+ }
5134
+ }
5135
+ appliedRanges.push({
5136
+ sourceRange: { startRow: r.startRow, endRow: r.endRow, startCol: srcCol, endCol: srcCol },
5137
+ targetRange: { startRow: r.startRow, endRow: r.endRow, startCol: firstTargetCol, endCol: lastTargetCol }
5138
+ })
5139
+ }
5140
+ }
5141
+
5142
+ if (!appliedRanges.length) return
5143
+
5144
+ if (this.strictBulkValidation && skipped.length > 0) {
5145
+ this._emitBulkValidationError(skipped, true)
5146
+ return
5147
+ }
5148
+
5149
+ this._emitDataChange(oldData, newData)
5150
+ for (const ar of appliedRanges) {
5151
+ this.$emit('fill', { sourceRange: ar.sourceRange, targetRange: ar.targetRange, values: newData })
5152
+ }
5153
+ if (skipped.length > 0) this._emitBulkValidationError(skipped, false)
5154
+
5155
+ // See pasteAt's/commitFillDrag's _fireCellCallbacksForRange call — same
5156
+ // nextTick deferral reasoning (col.onInput/onSelect after the DOM settles).
5157
+ await this.$nextTick()
5158
+ for (const ar of appliedRanges) {
5159
+ this._fireCellCallbacksForRange(oldData, newData, ar.targetRange.startRow, ar.targetRange.endRow, ar.targetRange.startCol, ar.targetRange.endCol)
5160
+ }
5161
+ },
5162
+
5163
+ fillDown() { return this._fillAxis('down') },
5164
+ fillRight() { return this._fillAxis('right') },
5165
+
5054
5166
  // =========================================================
5055
5167
  // COPY / PASTE (3.4)
5056
5168
  // =========================================================