ide-assi 0.370.0 → 0.372.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/dist/bundle.cjs.js +30 -41
- package/dist/bundle.esm.js +30 -41
- package/dist/components/ideDiff.js +32 -43
- package/package.json +1 -1
- package/src/components/ideDiff.js +32 -43
package/dist/bundle.cjs.js
CHANGED
|
@@ -234776,7 +234776,7 @@ function requireDiffMatchPatch () {
|
|
|
234776
234776
|
|
|
234777
234777
|
var diffMatchPatchExports = requireDiffMatchPatch();
|
|
234778
234778
|
|
|
234779
|
-
// Diff 데코레이션을 위한 StateField 정의 (
|
|
234779
|
+
// Diff 데코레이션을 위한 StateField 정의 (변동 없음)
|
|
234780
234780
|
const asisDiffDecorations = StateField.define({
|
|
234781
234781
|
create() { return Decoration.none; },
|
|
234782
234782
|
update(decorations, tr) {
|
|
@@ -234790,7 +234790,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
234790
234790
|
provide: f => EditorView.decorations.from(f)
|
|
234791
234791
|
});
|
|
234792
234792
|
|
|
234793
|
-
// Diff 데코레이션을 위한 StateField 정의 (tobe 에디터용)
|
|
234794
234793
|
const tobeDiffDecorations = StateField.define({
|
|
234795
234794
|
create() { return Decoration.none; },
|
|
234796
234795
|
update(decorations, tr) {
|
|
@@ -234804,7 +234803,6 @@ const tobeDiffDecorations = StateField.define({
|
|
|
234804
234803
|
provide: f => EditorView.decorations.from(f)
|
|
234805
234804
|
});
|
|
234806
234805
|
|
|
234807
|
-
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
234808
234806
|
const setAsisDecorationsEffect = StateEffect.define();
|
|
234809
234807
|
const setTobeDecorationsEffect = StateEffect.define();
|
|
234810
234808
|
|
|
@@ -234817,10 +234815,9 @@ class IdeDiff extends HTMLElement {
|
|
|
234817
234815
|
|
|
234818
234816
|
#languageCompartment = new Compartment();
|
|
234819
234817
|
|
|
234820
|
-
// ⭐️ 스크롤 동기화 활성/비활성화 플래그 및 핸들러 참조
|
|
234821
234818
|
#isScrollSyncActive = false;
|
|
234822
|
-
_asisScrollHandler = null;
|
|
234823
|
-
_tobeScrollHandler = null;
|
|
234819
|
+
_asisScrollHandler = null;
|
|
234820
|
+
_tobeScrollHandler = null;
|
|
234824
234821
|
|
|
234825
234822
|
|
|
234826
234823
|
constructor() {
|
|
@@ -234831,38 +234828,35 @@ class IdeDiff extends HTMLElement {
|
|
|
234831
234828
|
connectedCallback() {
|
|
234832
234829
|
this.shadowRoot.innerHTML = `
|
|
234833
234830
|
<style>
|
|
234834
|
-
/* ninegrid CSS 및 필요한 기본 스타일 */
|
|
234831
|
+
/* ninegrid CSS 및 필요한 기본 스타일 (변동 없음) */
|
|
234835
234832
|
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
|
|
234836
234833
|
${ninegrid.getCustomPath(this, "ideDiff.css")}
|
|
234837
234834
|
|
|
234838
|
-
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 */
|
|
234835
|
+
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 (변동 없음) */
|
|
234839
234836
|
.wrapper {
|
|
234840
234837
|
display: flex;
|
|
234841
234838
|
width: 100%;
|
|
234842
|
-
height: 100%;
|
|
234843
|
-
overflow: hidden;
|
|
234839
|
+
height: 100%;
|
|
234840
|
+
overflow: hidden;
|
|
234844
234841
|
}
|
|
234845
234842
|
.panel {
|
|
234846
|
-
flex: 1;
|
|
234847
|
-
overflow: hidden;
|
|
234848
|
-
min-width: 0;
|
|
234843
|
+
flex: 1;
|
|
234844
|
+
overflow: hidden;
|
|
234845
|
+
min-width: 0;
|
|
234849
234846
|
}
|
|
234850
234847
|
.cm-editor {
|
|
234851
|
-
height: 100%;
|
|
234848
|
+
height: 100%;
|
|
234852
234849
|
}
|
|
234853
234850
|
|
|
234854
|
-
/* Diff 시각화를 위한 CSS 클래스 */
|
|
234855
|
-
|
|
234856
|
-
.cm-
|
|
234857
|
-
.cm-deleted-line-bg { background-color: #ffe6e6; } /* 연한 빨간색 */
|
|
234858
|
-
|
|
234859
|
-
/* 인라인(단어/문자) 변경 강조 */
|
|
234851
|
+
/* Diff 시각화를 위한 CSS 클래스 (변동 없음) */
|
|
234852
|
+
.cm-inserted-line-bg { background-color: #e6ffe6; }
|
|
234853
|
+
.cm-deleted-line-bg { background-color: #ffe6e6; }
|
|
234860
234854
|
.cm-inserted-inline {
|
|
234861
|
-
background-color: #90ee90;
|
|
234855
|
+
background-color: #90ee90;
|
|
234862
234856
|
font-weight: bold;
|
|
234863
234857
|
}
|
|
234864
234858
|
.cm-deleted-inline {
|
|
234865
|
-
background-color: #ff9999;
|
|
234859
|
+
background-color: #ff9999;
|
|
234866
234860
|
text-decoration: line-through;
|
|
234867
234861
|
font-weight: bold;
|
|
234868
234862
|
}
|
|
@@ -234923,11 +234917,10 @@ class IdeDiff extends HTMLElement {
|
|
|
234923
234917
|
EditorState.readOnly.of(true),
|
|
234924
234918
|
this.#languageCompartment.of(javascript()),
|
|
234925
234919
|
asisDiffDecorations,
|
|
234926
|
-
// ⭐️
|
|
234920
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
234927
234921
|
EditorView.updateListener.of((update) => {
|
|
234928
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
234929
234922
|
if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
|
|
234930
|
-
update.view._initialAsisContentLoaded = true;
|
|
234923
|
+
update.view._initialAsisContentLoaded = true;
|
|
234931
234924
|
console.log("CodeMirror ASIS view is ready for initial content.");
|
|
234932
234925
|
}
|
|
234933
234926
|
})
|
|
@@ -234946,11 +234939,10 @@ class IdeDiff extends HTMLElement {
|
|
|
234946
234939
|
EditorState.readOnly.of(true),
|
|
234947
234940
|
this.#languageCompartment.of(javascript()),
|
|
234948
234941
|
tobeDiffDecorations,
|
|
234949
|
-
// ⭐️
|
|
234942
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
234950
234943
|
EditorView.updateListener.of((update) => {
|
|
234951
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
234952
234944
|
if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
|
|
234953
|
-
update.view._initialTobeContentLoaded = true;
|
|
234945
|
+
update.view._initialTobeContentLoaded = true;
|
|
234954
234946
|
console.log("CodeMirror TOBE view is ready for initial content.");
|
|
234955
234947
|
}
|
|
234956
234948
|
})
|
|
@@ -234959,14 +234951,11 @@ class IdeDiff extends HTMLElement {
|
|
|
234959
234951
|
parent: this.#tobeEditorEl
|
|
234960
234952
|
});
|
|
234961
234953
|
|
|
234962
|
-
// ⭐️ 초기 스크롤 동기화는 여기서 설정만 하고, initialize에서 활성화 제어
|
|
234963
234954
|
this.#setupScrollSync();
|
|
234964
234955
|
};
|
|
234965
234956
|
|
|
234966
|
-
// ⭐️ 스크롤 리스너를 제어할 수 있도록 플래그 및 클래스 메서드 사용
|
|
234967
234957
|
#setupScrollSync = () => {
|
|
234968
|
-
|
|
234969
|
-
if (this._asisScrollHandler) { // 핸들러가 이미 할당되어 있다면
|
|
234958
|
+
if (this._asisScrollHandler) {
|
|
234970
234959
|
this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
|
|
234971
234960
|
this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
|
|
234972
234961
|
}
|
|
@@ -234975,7 +234964,7 @@ class IdeDiff extends HTMLElement {
|
|
|
234975
234964
|
let scrollingB = false;
|
|
234976
234965
|
|
|
234977
234966
|
this._asisScrollHandler = () => {
|
|
234978
|
-
if (!this.#isScrollSyncActive) return;
|
|
234967
|
+
if (!this.#isScrollSyncActive) return;
|
|
234979
234968
|
|
|
234980
234969
|
if (!scrollingB) {
|
|
234981
234970
|
scrollingA = true;
|
|
@@ -234986,7 +234975,7 @@ class IdeDiff extends HTMLElement {
|
|
|
234986
234975
|
};
|
|
234987
234976
|
|
|
234988
234977
|
this._tobeScrollHandler = () => {
|
|
234989
|
-
if (!this.#isScrollSyncActive) return;
|
|
234978
|
+
if (!this.#isScrollSyncActive) return;
|
|
234990
234979
|
|
|
234991
234980
|
if (!scrollingA) {
|
|
234992
234981
|
scrollingB = true;
|
|
@@ -235000,7 +234989,6 @@ class IdeDiff extends HTMLElement {
|
|
|
235000
234989
|
this.#tobeEditorView.scrollDOM.addEventListener('scroll', this._tobeScrollHandler);
|
|
235001
234990
|
};
|
|
235002
234991
|
|
|
235003
|
-
// #applyDiffDecorations 함수 (이전 수정본과 동일, Text.of 사용)
|
|
235004
234992
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
235005
234993
|
const dmp = new diffMatchPatchExports.diff_match_patch();
|
|
235006
234994
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -235014,6 +235002,8 @@ class IdeDiff extends HTMLElement {
|
|
|
235014
235002
|
let asisCursor = 0;
|
|
235015
235003
|
let tobeCursor = 0;
|
|
235016
235004
|
|
|
235005
|
+
// ⭐️ 중요: 새로운 문서 내용을 기반으로 임시 Doc 객체를 생성합니다.
|
|
235006
|
+
// 이 Doc 객체를 사용하여 lineAt()을 호출합니다.
|
|
235017
235007
|
const asisDoc = Text.of(asisSrc.split('\n'));
|
|
235018
235008
|
const tobeDoc = Text.of(tobeSrc.split('\n'));
|
|
235019
235009
|
|
|
@@ -235123,8 +235113,7 @@ class IdeDiff extends HTMLElement {
|
|
|
235123
235113
|
return;
|
|
235124
235114
|
}
|
|
235125
235115
|
|
|
235126
|
-
|
|
235127
|
-
this.#isScrollSyncActive = false;
|
|
235116
|
+
this.#isScrollSyncActive = false; // 스크롤 동기화 일시 중지
|
|
235128
235117
|
|
|
235129
235118
|
let langExtension;
|
|
235130
235119
|
switch(language) {
|
|
@@ -235139,6 +235128,7 @@ class IdeDiff extends HTMLElement {
|
|
|
235139
235128
|
const { asisEffect, tobeEffect } = this.#applyDiffDecorations(src1, src2);
|
|
235140
235129
|
|
|
235141
235130
|
// 1단계: 텍스트 내용 변경과 언어 확장을 먼저 디스패치합니다.
|
|
235131
|
+
// 'to' 값을 현재 문서 길이 전체로 지정하여 정확한 교체를 보장합니다.
|
|
235142
235132
|
this.#asisEditorView.dispatch({
|
|
235143
235133
|
changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 },
|
|
235144
235134
|
effects: [
|
|
@@ -235153,10 +235143,9 @@ class IdeDiff extends HTMLElement {
|
|
|
235153
235143
|
]
|
|
235154
235144
|
});
|
|
235155
235145
|
|
|
235156
|
-
// 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가
|
|
235146
|
+
// ⭐️ 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
|
|
235157
235147
|
// 다음 프레임에서 데코레이션 효과만 별도로 디스패치합니다.
|
|
235158
235148
|
requestAnimationFrame(() => {
|
|
235159
|
-
console.log(asisEffect, tobeEffect);
|
|
235160
235149
|
this.#asisEditorView.dispatch({
|
|
235161
235150
|
effects: [asisEffect]
|
|
235162
235151
|
});
|
|
@@ -235164,8 +235153,8 @@ class IdeDiff extends HTMLElement {
|
|
|
235164
235153
|
effects: [tobeEffect]
|
|
235165
235154
|
});
|
|
235166
235155
|
|
|
235167
|
-
// 3단계: 데코레이션까지 적용된 후
|
|
235168
|
-
//
|
|
235156
|
+
// ⭐️ 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
|
|
235157
|
+
// 그 다음 프레임에서 스크롤 동기화를 활성화합니다.
|
|
235169
235158
|
requestAnimationFrame(() => {
|
|
235170
235159
|
this.#isScrollSyncActive = true;
|
|
235171
235160
|
// 필요하다면 여기서 초기 스크롤 위치를 0으로 리셋하여 정렬을 보장할 수 있습니다.
|
package/dist/bundle.esm.js
CHANGED
|
@@ -234772,7 +234772,7 @@ function requireDiffMatchPatch () {
|
|
|
234772
234772
|
|
|
234773
234773
|
var diffMatchPatchExports = requireDiffMatchPatch();
|
|
234774
234774
|
|
|
234775
|
-
// Diff 데코레이션을 위한 StateField 정의 (
|
|
234775
|
+
// Diff 데코레이션을 위한 StateField 정의 (변동 없음)
|
|
234776
234776
|
const asisDiffDecorations = StateField.define({
|
|
234777
234777
|
create() { return Decoration.none; },
|
|
234778
234778
|
update(decorations, tr) {
|
|
@@ -234786,7 +234786,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
234786
234786
|
provide: f => EditorView.decorations.from(f)
|
|
234787
234787
|
});
|
|
234788
234788
|
|
|
234789
|
-
// Diff 데코레이션을 위한 StateField 정의 (tobe 에디터용)
|
|
234790
234789
|
const tobeDiffDecorations = StateField.define({
|
|
234791
234790
|
create() { return Decoration.none; },
|
|
234792
234791
|
update(decorations, tr) {
|
|
@@ -234800,7 +234799,6 @@ const tobeDiffDecorations = StateField.define({
|
|
|
234800
234799
|
provide: f => EditorView.decorations.from(f)
|
|
234801
234800
|
});
|
|
234802
234801
|
|
|
234803
|
-
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
234804
234802
|
const setAsisDecorationsEffect = StateEffect.define();
|
|
234805
234803
|
const setTobeDecorationsEffect = StateEffect.define();
|
|
234806
234804
|
|
|
@@ -234813,10 +234811,9 @@ class IdeDiff extends HTMLElement {
|
|
|
234813
234811
|
|
|
234814
234812
|
#languageCompartment = new Compartment();
|
|
234815
234813
|
|
|
234816
|
-
// ⭐️ 스크롤 동기화 활성/비활성화 플래그 및 핸들러 참조
|
|
234817
234814
|
#isScrollSyncActive = false;
|
|
234818
|
-
_asisScrollHandler = null;
|
|
234819
|
-
_tobeScrollHandler = null;
|
|
234815
|
+
_asisScrollHandler = null;
|
|
234816
|
+
_tobeScrollHandler = null;
|
|
234820
234817
|
|
|
234821
234818
|
|
|
234822
234819
|
constructor() {
|
|
@@ -234827,38 +234824,35 @@ class IdeDiff extends HTMLElement {
|
|
|
234827
234824
|
connectedCallback() {
|
|
234828
234825
|
this.shadowRoot.innerHTML = `
|
|
234829
234826
|
<style>
|
|
234830
|
-
/* ninegrid CSS 및 필요한 기본 스타일 */
|
|
234827
|
+
/* ninegrid CSS 및 필요한 기본 스타일 (변동 없음) */
|
|
234831
234828
|
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
|
|
234832
234829
|
${ninegrid.getCustomPath(this, "ideDiff.css")}
|
|
234833
234830
|
|
|
234834
|
-
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 */
|
|
234831
|
+
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 (변동 없음) */
|
|
234835
234832
|
.wrapper {
|
|
234836
234833
|
display: flex;
|
|
234837
234834
|
width: 100%;
|
|
234838
|
-
height: 100%;
|
|
234839
|
-
overflow: hidden;
|
|
234835
|
+
height: 100%;
|
|
234836
|
+
overflow: hidden;
|
|
234840
234837
|
}
|
|
234841
234838
|
.panel {
|
|
234842
|
-
flex: 1;
|
|
234843
|
-
overflow: hidden;
|
|
234844
|
-
min-width: 0;
|
|
234839
|
+
flex: 1;
|
|
234840
|
+
overflow: hidden;
|
|
234841
|
+
min-width: 0;
|
|
234845
234842
|
}
|
|
234846
234843
|
.cm-editor {
|
|
234847
|
-
height: 100%;
|
|
234844
|
+
height: 100%;
|
|
234848
234845
|
}
|
|
234849
234846
|
|
|
234850
|
-
/* Diff 시각화를 위한 CSS 클래스 */
|
|
234851
|
-
|
|
234852
|
-
.cm-
|
|
234853
|
-
.cm-deleted-line-bg { background-color: #ffe6e6; } /* 연한 빨간색 */
|
|
234854
|
-
|
|
234855
|
-
/* 인라인(단어/문자) 변경 강조 */
|
|
234847
|
+
/* Diff 시각화를 위한 CSS 클래스 (변동 없음) */
|
|
234848
|
+
.cm-inserted-line-bg { background-color: #e6ffe6; }
|
|
234849
|
+
.cm-deleted-line-bg { background-color: #ffe6e6; }
|
|
234856
234850
|
.cm-inserted-inline {
|
|
234857
|
-
background-color: #90ee90;
|
|
234851
|
+
background-color: #90ee90;
|
|
234858
234852
|
font-weight: bold;
|
|
234859
234853
|
}
|
|
234860
234854
|
.cm-deleted-inline {
|
|
234861
|
-
background-color: #ff9999;
|
|
234855
|
+
background-color: #ff9999;
|
|
234862
234856
|
text-decoration: line-through;
|
|
234863
234857
|
font-weight: bold;
|
|
234864
234858
|
}
|
|
@@ -234919,11 +234913,10 @@ class IdeDiff extends HTMLElement {
|
|
|
234919
234913
|
EditorState.readOnly.of(true),
|
|
234920
234914
|
this.#languageCompartment.of(javascript()),
|
|
234921
234915
|
asisDiffDecorations,
|
|
234922
|
-
// ⭐️
|
|
234916
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
234923
234917
|
EditorView.updateListener.of((update) => {
|
|
234924
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
234925
234918
|
if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
|
|
234926
|
-
update.view._initialAsisContentLoaded = true;
|
|
234919
|
+
update.view._initialAsisContentLoaded = true;
|
|
234927
234920
|
console.log("CodeMirror ASIS view is ready for initial content.");
|
|
234928
234921
|
}
|
|
234929
234922
|
})
|
|
@@ -234942,11 +234935,10 @@ class IdeDiff extends HTMLElement {
|
|
|
234942
234935
|
EditorState.readOnly.of(true),
|
|
234943
234936
|
this.#languageCompartment.of(javascript()),
|
|
234944
234937
|
tobeDiffDecorations,
|
|
234945
|
-
// ⭐️
|
|
234938
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
234946
234939
|
EditorView.updateListener.of((update) => {
|
|
234947
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
234948
234940
|
if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
|
|
234949
|
-
update.view._initialTobeContentLoaded = true;
|
|
234941
|
+
update.view._initialTobeContentLoaded = true;
|
|
234950
234942
|
console.log("CodeMirror TOBE view is ready for initial content.");
|
|
234951
234943
|
}
|
|
234952
234944
|
})
|
|
@@ -234955,14 +234947,11 @@ class IdeDiff extends HTMLElement {
|
|
|
234955
234947
|
parent: this.#tobeEditorEl
|
|
234956
234948
|
});
|
|
234957
234949
|
|
|
234958
|
-
// ⭐️ 초기 스크롤 동기화는 여기서 설정만 하고, initialize에서 활성화 제어
|
|
234959
234950
|
this.#setupScrollSync();
|
|
234960
234951
|
};
|
|
234961
234952
|
|
|
234962
|
-
// ⭐️ 스크롤 리스너를 제어할 수 있도록 플래그 및 클래스 메서드 사용
|
|
234963
234953
|
#setupScrollSync = () => {
|
|
234964
|
-
|
|
234965
|
-
if (this._asisScrollHandler) { // 핸들러가 이미 할당되어 있다면
|
|
234954
|
+
if (this._asisScrollHandler) {
|
|
234966
234955
|
this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
|
|
234967
234956
|
this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
|
|
234968
234957
|
}
|
|
@@ -234971,7 +234960,7 @@ class IdeDiff extends HTMLElement {
|
|
|
234971
234960
|
let scrollingB = false;
|
|
234972
234961
|
|
|
234973
234962
|
this._asisScrollHandler = () => {
|
|
234974
|
-
if (!this.#isScrollSyncActive) return;
|
|
234963
|
+
if (!this.#isScrollSyncActive) return;
|
|
234975
234964
|
|
|
234976
234965
|
if (!scrollingB) {
|
|
234977
234966
|
scrollingA = true;
|
|
@@ -234982,7 +234971,7 @@ class IdeDiff extends HTMLElement {
|
|
|
234982
234971
|
};
|
|
234983
234972
|
|
|
234984
234973
|
this._tobeScrollHandler = () => {
|
|
234985
|
-
if (!this.#isScrollSyncActive) return;
|
|
234974
|
+
if (!this.#isScrollSyncActive) return;
|
|
234986
234975
|
|
|
234987
234976
|
if (!scrollingA) {
|
|
234988
234977
|
scrollingB = true;
|
|
@@ -234996,7 +234985,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234996
234985
|
this.#tobeEditorView.scrollDOM.addEventListener('scroll', this._tobeScrollHandler);
|
|
234997
234986
|
};
|
|
234998
234987
|
|
|
234999
|
-
// #applyDiffDecorations 함수 (이전 수정본과 동일, Text.of 사용)
|
|
235000
234988
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
235001
234989
|
const dmp = new diffMatchPatchExports.diff_match_patch();
|
|
235002
234990
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -235010,6 +234998,8 @@ class IdeDiff extends HTMLElement {
|
|
|
235010
234998
|
let asisCursor = 0;
|
|
235011
234999
|
let tobeCursor = 0;
|
|
235012
235000
|
|
|
235001
|
+
// ⭐️ 중요: 새로운 문서 내용을 기반으로 임시 Doc 객체를 생성합니다.
|
|
235002
|
+
// 이 Doc 객체를 사용하여 lineAt()을 호출합니다.
|
|
235013
235003
|
const asisDoc = Text.of(asisSrc.split('\n'));
|
|
235014
235004
|
const tobeDoc = Text.of(tobeSrc.split('\n'));
|
|
235015
235005
|
|
|
@@ -235119,8 +235109,7 @@ class IdeDiff extends HTMLElement {
|
|
|
235119
235109
|
return;
|
|
235120
235110
|
}
|
|
235121
235111
|
|
|
235122
|
-
|
|
235123
|
-
this.#isScrollSyncActive = false;
|
|
235112
|
+
this.#isScrollSyncActive = false; // 스크롤 동기화 일시 중지
|
|
235124
235113
|
|
|
235125
235114
|
let langExtension;
|
|
235126
235115
|
switch(language) {
|
|
@@ -235135,6 +235124,7 @@ class IdeDiff extends HTMLElement {
|
|
|
235135
235124
|
const { asisEffect, tobeEffect } = this.#applyDiffDecorations(src1, src2);
|
|
235136
235125
|
|
|
235137
235126
|
// 1단계: 텍스트 내용 변경과 언어 확장을 먼저 디스패치합니다.
|
|
235127
|
+
// 'to' 값을 현재 문서 길이 전체로 지정하여 정확한 교체를 보장합니다.
|
|
235138
235128
|
this.#asisEditorView.dispatch({
|
|
235139
235129
|
changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 },
|
|
235140
235130
|
effects: [
|
|
@@ -235149,10 +235139,9 @@ class IdeDiff extends HTMLElement {
|
|
|
235149
235139
|
]
|
|
235150
235140
|
});
|
|
235151
235141
|
|
|
235152
|
-
// 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가
|
|
235142
|
+
// ⭐️ 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
|
|
235153
235143
|
// 다음 프레임에서 데코레이션 효과만 별도로 디스패치합니다.
|
|
235154
235144
|
requestAnimationFrame(() => {
|
|
235155
|
-
console.log(asisEffect, tobeEffect);
|
|
235156
235145
|
this.#asisEditorView.dispatch({
|
|
235157
235146
|
effects: [asisEffect]
|
|
235158
235147
|
});
|
|
@@ -235160,8 +235149,8 @@ class IdeDiff extends HTMLElement {
|
|
|
235160
235149
|
effects: [tobeEffect]
|
|
235161
235150
|
});
|
|
235162
235151
|
|
|
235163
|
-
// 3단계: 데코레이션까지 적용된 후
|
|
235164
|
-
//
|
|
235152
|
+
// ⭐️ 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
|
|
235153
|
+
// 그 다음 프레임에서 스크롤 동기화를 활성화합니다.
|
|
235165
235154
|
requestAnimationFrame(() => {
|
|
235166
235155
|
this.#isScrollSyncActive = true;
|
|
235167
235156
|
// 필요하다면 여기서 초기 스크롤 위치를 0으로 리셋하여 정렬을 보장할 수 있습니다.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ninegrid from "ninegrid2";
|
|
2
2
|
|
|
3
|
-
// CodeMirror 6 핵심 및 확장 임포트
|
|
3
|
+
// CodeMirror 6 핵심 및 확장 임포트 (변동 없음)
|
|
4
4
|
import {
|
|
5
5
|
EditorView, lineNumbers, highlightSpecialChars, drawSelection,
|
|
6
6
|
dropCursor, keymap, highlightActiveLine, highlightActiveLineGutter,
|
|
@@ -21,10 +21,10 @@ import { indentOnInput, syntaxHighlighting, defaultHighlightStyle } from "@codem
|
|
|
21
21
|
import { lintKeymap } from "@codemirror/lint";
|
|
22
22
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
23
23
|
|
|
24
|
-
// Diff 로직을 위해 diff-match-patch 사용
|
|
24
|
+
// Diff 로직을 위해 diff-match-patch 사용 (변동 없음)
|
|
25
25
|
import { diff_match_patch } from 'diff-match-patch';
|
|
26
26
|
|
|
27
|
-
// Diff 데코레이션을 위한 StateField 정의 (
|
|
27
|
+
// Diff 데코레이션을 위한 StateField 정의 (변동 없음)
|
|
28
28
|
const asisDiffDecorations = StateField.define({
|
|
29
29
|
create() { return Decoration.none; },
|
|
30
30
|
update(decorations, tr) {
|
|
@@ -38,7 +38,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
38
38
|
provide: f => EditorView.decorations.from(f)
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
// Diff 데코레이션을 위한 StateField 정의 (tobe 에디터용)
|
|
42
41
|
const tobeDiffDecorations = StateField.define({
|
|
43
42
|
create() { return Decoration.none; },
|
|
44
43
|
update(decorations, tr) {
|
|
@@ -52,7 +51,6 @@ const tobeDiffDecorations = StateField.define({
|
|
|
52
51
|
provide: f => EditorView.decorations.from(f)
|
|
53
52
|
});
|
|
54
53
|
|
|
55
|
-
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
56
54
|
const setAsisDecorationsEffect = StateEffect.define();
|
|
57
55
|
const setTobeDecorationsEffect = StateEffect.define();
|
|
58
56
|
|
|
@@ -65,10 +63,9 @@ export class IdeDiff extends HTMLElement {
|
|
|
65
63
|
|
|
66
64
|
#languageCompartment = new Compartment();
|
|
67
65
|
|
|
68
|
-
// ⭐️ 스크롤 동기화 활성/비활성화 플래그 및 핸들러 참조
|
|
69
66
|
#isScrollSyncActive = false;
|
|
70
|
-
_asisScrollHandler = null;
|
|
71
|
-
_tobeScrollHandler = null;
|
|
67
|
+
_asisScrollHandler = null;
|
|
68
|
+
_tobeScrollHandler = null;
|
|
72
69
|
|
|
73
70
|
|
|
74
71
|
constructor() {
|
|
@@ -79,38 +76,35 @@ export class IdeDiff extends HTMLElement {
|
|
|
79
76
|
connectedCallback() {
|
|
80
77
|
this.shadowRoot.innerHTML = `
|
|
81
78
|
<style>
|
|
82
|
-
/* ninegrid CSS 및 필요한 기본 스타일 */
|
|
79
|
+
/* ninegrid CSS 및 필요한 기본 스타일 (변동 없음) */
|
|
83
80
|
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
|
|
84
81
|
${ninegrid.getCustomPath(this, "ideDiff.css")}
|
|
85
82
|
|
|
86
|
-
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 */
|
|
83
|
+
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 (변동 없음) */
|
|
87
84
|
.wrapper {
|
|
88
85
|
display: flex;
|
|
89
86
|
width: 100%;
|
|
90
|
-
height: 100%;
|
|
91
|
-
overflow: hidden;
|
|
87
|
+
height: 100%;
|
|
88
|
+
overflow: hidden;
|
|
92
89
|
}
|
|
93
90
|
.panel {
|
|
94
|
-
flex: 1;
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
min-width: 0;
|
|
91
|
+
flex: 1;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
min-width: 0;
|
|
97
94
|
}
|
|
98
95
|
.cm-editor {
|
|
99
|
-
height: 100%;
|
|
96
|
+
height: 100%;
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
/* Diff 시각화를 위한 CSS 클래스 */
|
|
103
|
-
|
|
104
|
-
.cm-
|
|
105
|
-
.cm-deleted-line-bg { background-color: #ffe6e6; } /* 연한 빨간색 */
|
|
106
|
-
|
|
107
|
-
/* 인라인(단어/문자) 변경 강조 */
|
|
99
|
+
/* Diff 시각화를 위한 CSS 클래스 (변동 없음) */
|
|
100
|
+
.cm-inserted-line-bg { background-color: #e6ffe6; }
|
|
101
|
+
.cm-deleted-line-bg { background-color: #ffe6e6; }
|
|
108
102
|
.cm-inserted-inline {
|
|
109
|
-
background-color: #90ee90;
|
|
103
|
+
background-color: #90ee90;
|
|
110
104
|
font-weight: bold;
|
|
111
105
|
}
|
|
112
106
|
.cm-deleted-inline {
|
|
113
|
-
background-color: #ff9999;
|
|
107
|
+
background-color: #ff9999;
|
|
114
108
|
text-decoration: line-through;
|
|
115
109
|
font-weight: bold;
|
|
116
110
|
}
|
|
@@ -171,11 +165,10 @@ export class IdeDiff extends HTMLElement {
|
|
|
171
165
|
EditorState.readOnly.of(true),
|
|
172
166
|
this.#languageCompartment.of(javascript()),
|
|
173
167
|
asisDiffDecorations,
|
|
174
|
-
// ⭐️
|
|
168
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
175
169
|
EditorView.updateListener.of((update) => {
|
|
176
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
177
170
|
if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
|
|
178
|
-
update.view._initialAsisContentLoaded = true;
|
|
171
|
+
update.view._initialAsisContentLoaded = true;
|
|
179
172
|
console.log("CodeMirror ASIS view is ready for initial content.");
|
|
180
173
|
}
|
|
181
174
|
})
|
|
@@ -194,11 +187,10 @@ export class IdeDiff extends HTMLElement {
|
|
|
194
187
|
EditorState.readOnly.of(true),
|
|
195
188
|
this.#languageCompartment.of(javascript()),
|
|
196
189
|
tobeDiffDecorations,
|
|
197
|
-
// ⭐️
|
|
190
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
198
191
|
EditorView.updateListener.of((update) => {
|
|
199
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
200
192
|
if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
|
|
201
|
-
update.view._initialTobeContentLoaded = true;
|
|
193
|
+
update.view._initialTobeContentLoaded = true;
|
|
202
194
|
console.log("CodeMirror TOBE view is ready for initial content.");
|
|
203
195
|
}
|
|
204
196
|
})
|
|
@@ -207,14 +199,11 @@ export class IdeDiff extends HTMLElement {
|
|
|
207
199
|
parent: this.#tobeEditorEl
|
|
208
200
|
});
|
|
209
201
|
|
|
210
|
-
// ⭐️ 초기 스크롤 동기화는 여기서 설정만 하고, initialize에서 활성화 제어
|
|
211
202
|
this.#setupScrollSync();
|
|
212
203
|
};
|
|
213
204
|
|
|
214
|
-
// ⭐️ 스크롤 리스너를 제어할 수 있도록 플래그 및 클래스 메서드 사용
|
|
215
205
|
#setupScrollSync = () => {
|
|
216
|
-
|
|
217
|
-
if (this._asisScrollHandler) { // 핸들러가 이미 할당되어 있다면
|
|
206
|
+
if (this._asisScrollHandler) {
|
|
218
207
|
this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
|
|
219
208
|
this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
|
|
220
209
|
}
|
|
@@ -223,7 +212,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
223
212
|
let scrollingB = false;
|
|
224
213
|
|
|
225
214
|
this._asisScrollHandler = () => {
|
|
226
|
-
if (!this.#isScrollSyncActive) return;
|
|
215
|
+
if (!this.#isScrollSyncActive) return;
|
|
227
216
|
|
|
228
217
|
if (!scrollingB) {
|
|
229
218
|
scrollingA = true;
|
|
@@ -234,7 +223,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
234
223
|
};
|
|
235
224
|
|
|
236
225
|
this._tobeScrollHandler = () => {
|
|
237
|
-
if (!this.#isScrollSyncActive) return;
|
|
226
|
+
if (!this.#isScrollSyncActive) return;
|
|
238
227
|
|
|
239
228
|
if (!scrollingA) {
|
|
240
229
|
scrollingB = true;
|
|
@@ -248,7 +237,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
248
237
|
this.#tobeEditorView.scrollDOM.addEventListener('scroll', this._tobeScrollHandler);
|
|
249
238
|
};
|
|
250
239
|
|
|
251
|
-
// #applyDiffDecorations 함수 (이전 수정본과 동일, Text.of 사용)
|
|
252
240
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
253
241
|
const dmp = new diff_match_patch();
|
|
254
242
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -262,6 +250,8 @@ export class IdeDiff extends HTMLElement {
|
|
|
262
250
|
let asisCursor = 0;
|
|
263
251
|
let tobeCursor = 0;
|
|
264
252
|
|
|
253
|
+
// ⭐️ 중요: 새로운 문서 내용을 기반으로 임시 Doc 객체를 생성합니다.
|
|
254
|
+
// 이 Doc 객체를 사용하여 lineAt()을 호출합니다.
|
|
265
255
|
const asisDoc = Text.of(asisSrc.split('\n'));
|
|
266
256
|
const tobeDoc = Text.of(tobeSrc.split('\n'));
|
|
267
257
|
|
|
@@ -371,8 +361,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
371
361
|
return;
|
|
372
362
|
}
|
|
373
363
|
|
|
374
|
-
|
|
375
|
-
this.#isScrollSyncActive = false;
|
|
364
|
+
this.#isScrollSyncActive = false; // 스크롤 동기화 일시 중지
|
|
376
365
|
|
|
377
366
|
let langExtension;
|
|
378
367
|
switch(language) {
|
|
@@ -387,6 +376,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
387
376
|
const { asisEffect, tobeEffect } = this.#applyDiffDecorations(src1, src2);
|
|
388
377
|
|
|
389
378
|
// 1단계: 텍스트 내용 변경과 언어 확장을 먼저 디스패치합니다.
|
|
379
|
+
// 'to' 값을 현재 문서 길이 전체로 지정하여 정확한 교체를 보장합니다.
|
|
390
380
|
this.#asisEditorView.dispatch({
|
|
391
381
|
changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 },
|
|
392
382
|
effects: [
|
|
@@ -401,10 +391,9 @@ export class IdeDiff extends HTMLElement {
|
|
|
401
391
|
]
|
|
402
392
|
});
|
|
403
393
|
|
|
404
|
-
// 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가
|
|
394
|
+
// ⭐️ 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
|
|
405
395
|
// 다음 프레임에서 데코레이션 효과만 별도로 디스패치합니다.
|
|
406
396
|
requestAnimationFrame(() => {
|
|
407
|
-
console.log(asisEffect, tobeEffect);
|
|
408
397
|
this.#asisEditorView.dispatch({
|
|
409
398
|
effects: [asisEffect]
|
|
410
399
|
});
|
|
@@ -412,8 +401,8 @@ export class IdeDiff extends HTMLElement {
|
|
|
412
401
|
effects: [tobeEffect]
|
|
413
402
|
});
|
|
414
403
|
|
|
415
|
-
// 3단계: 데코레이션까지 적용된 후
|
|
416
|
-
//
|
|
404
|
+
// ⭐️ 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
|
|
405
|
+
// 그 다음 프레임에서 스크롤 동기화를 활성화합니다.
|
|
417
406
|
requestAnimationFrame(() => {
|
|
418
407
|
this.#isScrollSyncActive = true;
|
|
419
408
|
// 필요하다면 여기서 초기 스크롤 위치를 0으로 리셋하여 정렬을 보장할 수 있습니다.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ninegrid from "ninegrid2";
|
|
2
2
|
|
|
3
|
-
// CodeMirror 6 핵심 및 확장 임포트
|
|
3
|
+
// CodeMirror 6 핵심 및 확장 임포트 (변동 없음)
|
|
4
4
|
import {
|
|
5
5
|
EditorView, lineNumbers, highlightSpecialChars, drawSelection,
|
|
6
6
|
dropCursor, keymap, highlightActiveLine, highlightActiveLineGutter,
|
|
@@ -21,10 +21,10 @@ import { indentOnInput, syntaxHighlighting, defaultHighlightStyle } from "@codem
|
|
|
21
21
|
import { lintKeymap } from "@codemirror/lint";
|
|
22
22
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
23
23
|
|
|
24
|
-
// Diff 로직을 위해 diff-match-patch 사용
|
|
24
|
+
// Diff 로직을 위해 diff-match-patch 사용 (변동 없음)
|
|
25
25
|
import { diff_match_patch } from 'diff-match-patch';
|
|
26
26
|
|
|
27
|
-
// Diff 데코레이션을 위한 StateField 정의 (
|
|
27
|
+
// Diff 데코레이션을 위한 StateField 정의 (변동 없음)
|
|
28
28
|
const asisDiffDecorations = StateField.define({
|
|
29
29
|
create() { return Decoration.none; },
|
|
30
30
|
update(decorations, tr) {
|
|
@@ -38,7 +38,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
38
38
|
provide: f => EditorView.decorations.from(f)
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
// Diff 데코레이션을 위한 StateField 정의 (tobe 에디터용)
|
|
42
41
|
const tobeDiffDecorations = StateField.define({
|
|
43
42
|
create() { return Decoration.none; },
|
|
44
43
|
update(decorations, tr) {
|
|
@@ -52,7 +51,6 @@ const tobeDiffDecorations = StateField.define({
|
|
|
52
51
|
provide: f => EditorView.decorations.from(f)
|
|
53
52
|
});
|
|
54
53
|
|
|
55
|
-
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
56
54
|
const setAsisDecorationsEffect = StateEffect.define();
|
|
57
55
|
const setTobeDecorationsEffect = StateEffect.define();
|
|
58
56
|
|
|
@@ -65,10 +63,9 @@ export class IdeDiff extends HTMLElement {
|
|
|
65
63
|
|
|
66
64
|
#languageCompartment = new Compartment();
|
|
67
65
|
|
|
68
|
-
// ⭐️ 스크롤 동기화 활성/비활성화 플래그 및 핸들러 참조
|
|
69
66
|
#isScrollSyncActive = false;
|
|
70
|
-
_asisScrollHandler = null;
|
|
71
|
-
_tobeScrollHandler = null;
|
|
67
|
+
_asisScrollHandler = null;
|
|
68
|
+
_tobeScrollHandler = null;
|
|
72
69
|
|
|
73
70
|
|
|
74
71
|
constructor() {
|
|
@@ -79,38 +76,35 @@ export class IdeDiff extends HTMLElement {
|
|
|
79
76
|
connectedCallback() {
|
|
80
77
|
this.shadowRoot.innerHTML = `
|
|
81
78
|
<style>
|
|
82
|
-
/* ninegrid CSS 및 필요한 기본 스타일 */
|
|
79
|
+
/* ninegrid CSS 및 필요한 기본 스타일 (변동 없음) */
|
|
83
80
|
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
|
|
84
81
|
${ninegrid.getCustomPath(this, "ideDiff.css")}
|
|
85
82
|
|
|
86
|
-
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 */
|
|
83
|
+
/* CodeMirror를 위한 기본적인 Flexbox 레이아웃 (변동 없음) */
|
|
87
84
|
.wrapper {
|
|
88
85
|
display: flex;
|
|
89
86
|
width: 100%;
|
|
90
|
-
height: 100%;
|
|
91
|
-
overflow: hidden;
|
|
87
|
+
height: 100%;
|
|
88
|
+
overflow: hidden;
|
|
92
89
|
}
|
|
93
90
|
.panel {
|
|
94
|
-
flex: 1;
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
min-width: 0;
|
|
91
|
+
flex: 1;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
min-width: 0;
|
|
97
94
|
}
|
|
98
95
|
.cm-editor {
|
|
99
|
-
height: 100%;
|
|
96
|
+
height: 100%;
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
/* Diff 시각화를 위한 CSS 클래스 */
|
|
103
|
-
|
|
104
|
-
.cm-
|
|
105
|
-
.cm-deleted-line-bg { background-color: #ffe6e6; } /* 연한 빨간색 */
|
|
106
|
-
|
|
107
|
-
/* 인라인(단어/문자) 변경 강조 */
|
|
99
|
+
/* Diff 시각화를 위한 CSS 클래스 (변동 없음) */
|
|
100
|
+
.cm-inserted-line-bg { background-color: #e6ffe6; }
|
|
101
|
+
.cm-deleted-line-bg { background-color: #ffe6e6; }
|
|
108
102
|
.cm-inserted-inline {
|
|
109
|
-
background-color: #90ee90;
|
|
103
|
+
background-color: #90ee90;
|
|
110
104
|
font-weight: bold;
|
|
111
105
|
}
|
|
112
106
|
.cm-deleted-inline {
|
|
113
|
-
background-color: #ff9999;
|
|
107
|
+
background-color: #ff9999;
|
|
114
108
|
text-decoration: line-through;
|
|
115
109
|
font-weight: bold;
|
|
116
110
|
}
|
|
@@ -171,11 +165,10 @@ export class IdeDiff extends HTMLElement {
|
|
|
171
165
|
EditorState.readOnly.of(true),
|
|
172
166
|
this.#languageCompartment.of(javascript()),
|
|
173
167
|
asisDiffDecorations,
|
|
174
|
-
// ⭐️
|
|
168
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
175
169
|
EditorView.updateListener.of((update) => {
|
|
176
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
177
170
|
if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
|
|
178
|
-
update.view._initialAsisContentLoaded = true;
|
|
171
|
+
update.view._initialAsisContentLoaded = true;
|
|
179
172
|
console.log("CodeMirror ASIS view is ready for initial content.");
|
|
180
173
|
}
|
|
181
174
|
})
|
|
@@ -194,11 +187,10 @@ export class IdeDiff extends HTMLElement {
|
|
|
194
187
|
EditorState.readOnly.of(true),
|
|
195
188
|
this.#languageCompartment.of(javascript()),
|
|
196
189
|
tobeDiffDecorations,
|
|
197
|
-
// ⭐️
|
|
190
|
+
// ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
|
|
198
191
|
EditorView.updateListener.of((update) => {
|
|
199
|
-
// 뷰의 DOM 내용이 비어있지 않고, 아직 초기 로드가 완료되지 않았다면
|
|
200
192
|
if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
|
|
201
|
-
update.view._initialTobeContentLoaded = true;
|
|
193
|
+
update.view._initialTobeContentLoaded = true;
|
|
202
194
|
console.log("CodeMirror TOBE view is ready for initial content.");
|
|
203
195
|
}
|
|
204
196
|
})
|
|
@@ -207,14 +199,11 @@ export class IdeDiff extends HTMLElement {
|
|
|
207
199
|
parent: this.#tobeEditorEl
|
|
208
200
|
});
|
|
209
201
|
|
|
210
|
-
// ⭐️ 초기 스크롤 동기화는 여기서 설정만 하고, initialize에서 활성화 제어
|
|
211
202
|
this.#setupScrollSync();
|
|
212
203
|
};
|
|
213
204
|
|
|
214
|
-
// ⭐️ 스크롤 리스너를 제어할 수 있도록 플래그 및 클래스 메서드 사용
|
|
215
205
|
#setupScrollSync = () => {
|
|
216
|
-
|
|
217
|
-
if (this._asisScrollHandler) { // 핸들러가 이미 할당되어 있다면
|
|
206
|
+
if (this._asisScrollHandler) {
|
|
218
207
|
this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
|
|
219
208
|
this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
|
|
220
209
|
}
|
|
@@ -223,7 +212,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
223
212
|
let scrollingB = false;
|
|
224
213
|
|
|
225
214
|
this._asisScrollHandler = () => {
|
|
226
|
-
if (!this.#isScrollSyncActive) return;
|
|
215
|
+
if (!this.#isScrollSyncActive) return;
|
|
227
216
|
|
|
228
217
|
if (!scrollingB) {
|
|
229
218
|
scrollingA = true;
|
|
@@ -234,7 +223,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
234
223
|
};
|
|
235
224
|
|
|
236
225
|
this._tobeScrollHandler = () => {
|
|
237
|
-
if (!this.#isScrollSyncActive) return;
|
|
226
|
+
if (!this.#isScrollSyncActive) return;
|
|
238
227
|
|
|
239
228
|
if (!scrollingA) {
|
|
240
229
|
scrollingB = true;
|
|
@@ -248,7 +237,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
248
237
|
this.#tobeEditorView.scrollDOM.addEventListener('scroll', this._tobeScrollHandler);
|
|
249
238
|
};
|
|
250
239
|
|
|
251
|
-
// #applyDiffDecorations 함수 (이전 수정본과 동일, Text.of 사용)
|
|
252
240
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
253
241
|
const dmp = new diff_match_patch();
|
|
254
242
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -262,6 +250,8 @@ export class IdeDiff extends HTMLElement {
|
|
|
262
250
|
let asisCursor = 0;
|
|
263
251
|
let tobeCursor = 0;
|
|
264
252
|
|
|
253
|
+
// ⭐️ 중요: 새로운 문서 내용을 기반으로 임시 Doc 객체를 생성합니다.
|
|
254
|
+
// 이 Doc 객체를 사용하여 lineAt()을 호출합니다.
|
|
265
255
|
const asisDoc = Text.of(asisSrc.split('\n'));
|
|
266
256
|
const tobeDoc = Text.of(tobeSrc.split('\n'));
|
|
267
257
|
|
|
@@ -371,8 +361,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
371
361
|
return;
|
|
372
362
|
}
|
|
373
363
|
|
|
374
|
-
|
|
375
|
-
this.#isScrollSyncActive = false;
|
|
364
|
+
this.#isScrollSyncActive = false; // 스크롤 동기화 일시 중지
|
|
376
365
|
|
|
377
366
|
let langExtension;
|
|
378
367
|
switch(language) {
|
|
@@ -387,6 +376,7 @@ export class IdeDiff extends HTMLElement {
|
|
|
387
376
|
const { asisEffect, tobeEffect } = this.#applyDiffDecorations(src1, src2);
|
|
388
377
|
|
|
389
378
|
// 1단계: 텍스트 내용 변경과 언어 확장을 먼저 디스패치합니다.
|
|
379
|
+
// 'to' 값을 현재 문서 길이 전체로 지정하여 정확한 교체를 보장합니다.
|
|
390
380
|
this.#asisEditorView.dispatch({
|
|
391
381
|
changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 },
|
|
392
382
|
effects: [
|
|
@@ -401,10 +391,9 @@ export class IdeDiff extends HTMLElement {
|
|
|
401
391
|
]
|
|
402
392
|
});
|
|
403
393
|
|
|
404
|
-
// 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가
|
|
394
|
+
// ⭐️ 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
|
|
405
395
|
// 다음 프레임에서 데코레이션 효과만 별도로 디스패치합니다.
|
|
406
396
|
requestAnimationFrame(() => {
|
|
407
|
-
console.log(asisEffect, tobeEffect);
|
|
408
397
|
this.#asisEditorView.dispatch({
|
|
409
398
|
effects: [asisEffect]
|
|
410
399
|
});
|
|
@@ -412,8 +401,8 @@ export class IdeDiff extends HTMLElement {
|
|
|
412
401
|
effects: [tobeEffect]
|
|
413
402
|
});
|
|
414
403
|
|
|
415
|
-
// 3단계: 데코레이션까지 적용된 후
|
|
416
|
-
//
|
|
404
|
+
// ⭐️ 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
|
|
405
|
+
// 그 다음 프레임에서 스크롤 동기화를 활성화합니다.
|
|
417
406
|
requestAnimationFrame(() => {
|
|
418
407
|
this.#isScrollSyncActive = true;
|
|
419
408
|
// 필요하다면 여기서 초기 스크롤 위치를 0으로 리셋하여 정렬을 보장할 수 있습니다.
|