diff --git a/index.html b/index.html index 56c7a7c..7e54a19 100644 --- a/index.html +++ b/index.html @@ -168,6 +168,9 @@

2 · 복사할 항목

+
+ +

복사하지 않는 값: 좌표 · IP · 받침 EL · 코핑 상면 EL · 기초 하단 EL · 지반고 · 기둥 높이 · 말뚝 선단 EL · 계단 구간

diff --git a/src/core/copy-targets.ts b/src/core/copy-targets.ts index 994aedf..7400dbb 100644 --- a/src/core/copy-targets.ts +++ b/src/core/copy-targets.ts @@ -1,4 +1,5 @@ -import type { CopyItem } from './copy'; +import { COPY_ITEMS, type CopyItem } from './copy'; +import { overrideKeys, type PierValues } from './changes'; import type { MemberId } from './shape-options'; /** One pier as a target of 속성 복사. */ @@ -43,3 +44,12 @@ export const MEMBER_COPY_ITEMS: Record = { export function copyItemsFor(member: MemberId): CopyItem[] { return MEMBER_COPY_ITEMS[member]; } + +/** + * The copy items whose values the 기준 pier has changed from the imported default (되돌리기가 보이는 항목). + * They are ticked by default; the user can change the ticks afterwards. + */ +export function copyItemsWithOverrides(source: PierValues): CopyItem[] { + const changed = new Set(overrideKeys(source)); + return (Object.keys(COPY_ITEMS) as CopyItem[]).filter((item) => COPY_ITEMS[item].keys.some((k) => changed.has(k))); +} diff --git a/src/main.ts b/src/main.ts index 32179f3..ec4dd41 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,8 +8,8 @@ import { NOT_IMPLEMENTED_RULES, validateInput, validatePier } from './core/valid import { buildTemplateWorkbook } from './core/template'; import { EDITABLE_FIELDS, FIELD_LABELS, overrideKeys, pendingKeys, revertDraft, type EditableKey, type PierValues } from './core/changes'; import { adjustRow, layoutText, resolveRowCounts, rowLayout, totalPiles } from './core/piles'; -import { applyCopy, COPY_ITEMS, DEFAULT_COPY_ITEMS, planCopy, type CopyItem } from './core/copy'; -import { copyCandidates, copyItemsFor, selectedTargets, type CopyCandidate } from './core/copy-targets'; +import { applyCopy, COPY_ITEMS, planCopy, type CopyItem } from './core/copy'; +import { copyCandidates, copyItemsFor, copyItemsWithOverrides, selectedTargets, type CopyCandidate } from './core/copy-targets'; import { pileGeometry } from './core/geometry'; import { rebarSummary, type RebarRow } from './core/rebar/summary'; import { shearSegments } from './core/rebar/coping'; @@ -649,11 +649,18 @@ function chosenCopyItems(): CopyItem[] { return copyItemsFor(state.member).filter((item) => copyItemChoice.has(item)); } -/** The items ticked by the user; kept across 부재 changes. */ -let copyItemChoice = new Set(DEFAULT_COPY_ITEMS); +/** The items ticked by the user. Reset to the 기준 pier's changed items when the 기준 pier or 부재 changes. */ +let copyItemChoice = new Set(); +let copyItemKey = ''; /** Shows the copy items of the selected 부재 only. A 부재 without items shows a note instead. */ function renderCopyItems(): void { + const src = activePier(); + const key = `${src?.input.name ?? ''}|${state.member}`; + if (key !== copyItemKey) { + copyItemKey = key; + copyItemChoice = new Set(src ? copyItemsWithOverrides(src) : []); + } const box = $('cp-items'); box.replaceChildren(); const items = copyItemsFor(state.member); @@ -3080,6 +3087,12 @@ $('cp-select-same').addEventListener('click', () => { renderCopyTargets(); renderCopyPreview(); }); +$('cp-items-reset').addEventListener('click', () => { + const src = activePier(); + copyItemChoice = new Set(src ? copyItemsWithOverrides(src) : []); + renderCopyItems(); + renderCopyPreview(); +}); $('cp-clear').addEventListener('click', () => { copySelection = new Set(); renderCopyTargets(); diff --git a/tests/copy-targets.test.ts b/tests/copy-targets.test.ts index 63591e7..8b5960d 100644 --- a/tests/copy-targets.test.ts +++ b/tests/copy-targets.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { copyCandidates, copyItemsFor, selectedTargets, type CopyCandidate } from '../src/core/copy-targets'; +import { copyCandidates, copyItemsFor, copyItemsWithOverrides, selectedTargets, type CopyCandidate } from '../src/core/copy-targets'; +import { loadP1 } from './helpers'; const piers: CopyCandidate[] = [ { name: 'P1', type: 'T형', hasModel: true }, @@ -63,3 +64,24 @@ describe('copyItemsFor (부재 선택에 해당하는 복사 항목)', () => { expect([...all].sort()).toEqual(['coping-length', 'coping-width', 'ground-position', 'pile-length', 'pile-rows']); }); }); + +describe('copyItemsWithOverrides (기준 교각에서 되돌리기가 표시된 항목)', () => { + const base = loadP1(); + const source = (draft: Partial) => ({ defaults: base, input: base, draft: { ...base, ...draft } }); + + it('is empty when the 기준 pier has no changed values', () => { + expect(copyItemsWithOverrides(source({}))).toEqual([]); + }); + + it('selects the item of a changed coping length', () => { + expect(copyItemsWithOverrides(source({ copingLengthMm: base.copingLengthMm + 500 }))).toEqual(['coping-length']); + }); + + it('selects the pile item when the pile length changed', () => { + expect(copyItemsWithOverrides(source({ pileLengthMm: base.pileLengthMm + 100 }))).toEqual(['pile-length']); + }); + + it('ignores a changed value that no copy item carries (groundEl)', () => { + expect(copyItemsWithOverrides(source({ groundEl: base.groundEl + 0.5 }))).toEqual([]); + }); +});