feat: [planning-design] 블록 Ctrl+C/V 복사 붙여넣기 및 Delete 삭제
- Ctrl+C: 선택된 블록 클립보드 복사 - Ctrl+V: 클립보드 블록 붙여넣기 (24px 오프셋) - Delete/Backspace: 선택된 블록 삭제 - 연속 Ctrl+V 시 오프셋 누적으로 겹침 방지
This commit is contained in:
@@ -1961,6 +1961,7 @@ function planningCanvas() {
|
||||
_sbBlockDragIdx: null,
|
||||
_sbDrag: null, // { blk, startX, startY, origX, origY }
|
||||
_sbResize: null, // { blk, dir, startX, startY, origW, origH }
|
||||
_sbClipboard: null, // copied block data
|
||||
sbTplOpen: false,
|
||||
sbTplTab: 'preset',
|
||||
sbTplSearch: '',
|
||||
@@ -2760,6 +2761,31 @@ function planningCanvas() {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'y') { e.preventDefault(); this.redoAction(); }
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); this.saveProject(); }
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'd') { e.preventDefault(); this.duplicateNode(); }
|
||||
// 스토리보드 블록 Ctrl+C / Ctrl+V / Delete
|
||||
if (this.viewMode === 'storyboard' && this.sbSelectedBlock) {
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === 'c' || e.key === 'C')) {
|
||||
e.preventDefault();
|
||||
this.sbCopyBlock();
|
||||
return;
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === 'v' || e.key === 'V')) {
|
||||
e.preventDefault();
|
||||
this.sbPasteBlock();
|
||||
return;
|
||||
}
|
||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||
e.preventDefault();
|
||||
this.sbDeleteSelectedBlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.viewMode === 'storyboard' && !this.sbSelectedBlock) {
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === 'v' || e.key === 'V') && this._sbClipboard) {
|
||||
e.preventDefault();
|
||||
this.sbPasteBlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
|
||||
if (this.viewMode === 'kanban' || this.viewMode === 'list') {
|
||||
e.preventDefault();
|
||||
@@ -2990,6 +3016,39 @@ function planningCanvas() {
|
||||
}
|
||||
},
|
||||
|
||||
sbCopyBlock() {
|
||||
const page = this.sbCurrentPage;
|
||||
if (!page || !page.blocks) return;
|
||||
const blk = page.blocks.find(b => b.id === this.sbSelectedBlock);
|
||||
if (!blk) return;
|
||||
this._sbClipboard = JSON.parse(JSON.stringify(blk));
|
||||
},
|
||||
|
||||
sbPasteBlock() {
|
||||
if (!this._sbClipboard) return;
|
||||
const page = this.sbCurrentPage;
|
||||
if (!page) return;
|
||||
if (!page.blocks) page.blocks = [];
|
||||
const copy = JSON.parse(JSON.stringify(this._sbClipboard));
|
||||
copy.id = 'blk_' + Date.now() + '_' + Math.random().toString(36).slice(2, 5);
|
||||
copy.x = (copy.x || 0) + 24;
|
||||
copy.y = (copy.y || 0) + 24;
|
||||
page.blocks.push(copy);
|
||||
this.sbSelectedBlock = copy.id;
|
||||
this._sbClipboard = copy; // 연속 붙여넣기 시 오프셋 누적
|
||||
this.autoSave();
|
||||
},
|
||||
|
||||
sbDeleteSelectedBlock() {
|
||||
const page = this.sbCurrentPage;
|
||||
if (!page || !page.blocks) return;
|
||||
const idx = page.blocks.findIndex(b => b.id === this.sbSelectedBlock);
|
||||
if (idx < 0) return;
|
||||
page.blocks.splice(idx, 1);
|
||||
this.sbSelectedBlock = null;
|
||||
this.autoSave();
|
||||
},
|
||||
|
||||
sbTableAddRow(blk) {
|
||||
const colCount = blk.cols.length;
|
||||
blk.rows.push(Array(colCount).fill(''));
|
||||
|
||||
Reference in New Issue
Block a user