@@ -39,7 +39,33 @@ export class TkprojEditorProvider implements vscode.CustomTextEditorProvider {
3939 ) : Promise < void > {
4040 webviewPanel . webview . options = { enableScripts : true } ;
4141
42+ if ( document . getText ( ) . trim ( ) === '' ) {
43+ const defaultData : TkprojData = {
44+ Mod : {
45+ Name : "New Project" ,
46+ Author : "Unknown" ,
47+ Version : "1.0.0" ,
48+ Description : "" ,
49+ Id : generateUlidNumber ( ) ,
50+ Contributors : [ ] ,
51+ Dependencies : [ ]
52+ } ,
53+ Flags : {
54+ TrackRemovedRsDbEntries : false
55+ }
56+ } ;
57+ const edit = new vscode . WorkspaceEdit ( ) ;
58+ edit . insert ( document . uri , new vscode . Position ( 0 , 0 ) , JSON . stringify ( defaultData , null , 2 ) ) ;
59+ await vscode . workspace . applyEdit ( edit ) ;
60+ await document . save ( ) ;
61+ }
62+
63+ let isUpdatingFromWebview = false ;
64+
4265 const update = ( ) => {
66+ if ( isUpdatingFromWebview ) {
67+ return ;
68+ }
4369 try {
4470 const data = JSON . parse ( document . getText ( ) ) as TkprojData ;
4571 webviewPanel . webview . html = buildHtml ( data ) ;
@@ -64,14 +90,22 @@ export class TkprojEditorProvider implements vscode.CustomTextEditorProvider {
6490 if ( msg . type === 'update' && msg . field && msg . value !== undefined ) {
6591 const data = JSON . parse ( document . getText ( ) ) as TkprojData ;
6692 applyField ( data , msg . field , msg . value as string ) ;
67- await writeBack ( document , data ) ;
68- }
69- if ( msg . type === 'updateContributors' && msg . contributors ) {
93+ isUpdatingFromWebview = true ;
94+ try {
95+ await writeBack ( document , data ) ;
96+ } finally {
97+ isUpdatingFromWebview = false ;
98+ }
99+ } else if ( msg . type === 'updateContributors' && msg . contributors ) {
70100 const data = JSON . parse ( document . getText ( ) ) as TkprojData ;
71101 data . Mod . Contributors = msg . contributors ;
72- await writeBack ( document , data ) ;
73- }
74- if ( msg . type === 'browseThumbnail' ) {
102+ isUpdatingFromWebview = true ;
103+ try {
104+ await writeBack ( document , data ) ;
105+ } finally {
106+ isUpdatingFromWebview = false ;
107+ }
108+ } else if ( msg . type === 'browseThumbnail' ) {
75109 const result = await vscode . window . showOpenDialog ( {
76110 canSelectMany : false ,
77111 filters : { Images : [ 'png' , 'jpg' , 'jpeg' , 'webp' ] } ,
@@ -128,16 +162,27 @@ function escHtml(s: string): string {
128162 return s . replace ( / & / g, '&' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) . replace ( / " / g, '"' ) ;
129163}
130164
165+ function generateUlidNumber ( ) : string {
166+ let id = '' ;
167+ for ( let i = 0 ; i < 26 ; i ++ ) {
168+ id += Math . floor ( Math . random ( ) * 10 ) . toString ( ) ;
169+ }
170+ if ( id === '00000000000000000000000001' ) {
171+ return generateUlidNumber ( ) ;
172+ }
173+ return id ;
174+ }
175+
131176function buildContributorRows ( contributors : TkprojContributor [ ] ) : string {
132177 if ( ! contributors . length ) {
133178 return '' ;
134179 }
135180 return contributors . map ( ( c , i ) => /* html */ `
136181 <div class="contrib-row" data-idx="${ i } ">
137182 <input type="text" class="contrib-name" placeholder="Name" value="${ escHtml ( c . Author ?? '' ) } "
138- onchange ="updateContrib()" />
183+ oninput ="updateContrib()" />
139184 <input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)"
140- value="${ escHtml ( c . Contribution ?? '' ) } " onchange ="updateContrib()" />
185+ value="${ escHtml ( c . Contribution ?? '' ) } " oninput ="updateContrib()" />
141186 <button class="btn btn-sm btn-danger" onclick="removeContrib(${ i } )">-</button>
142187 </div>` ) . join ( '' ) ;
143188}
@@ -255,22 +300,22 @@ function buildHtml(data: TkprojData): string {
255300 <div class="field">
256301 <label>Name</label>
257302 <input type="text" id="name" value="${ escHtml ( mod . Name ?? '' ) } "
258- onchange ="send('name', this.value)" />
303+ oninput ="send('name', this.value)" />
259304 </div>
260305 <div class="field">
261306 <label>Author</label>
262307 <input type="text" id="author" value="${ escHtml ( mod . Author ?? '' ) } "
263- onchange ="send('author', this.value)" />
308+ oninput ="send('author', this.value)" />
264309 </div>
265310 <div class="field">
266311 <label>Version</label>
267312 <input type="text" id="version" value="${ escHtml ( mod . Version ?? '' ) } "
268- onchange ="send('version', this.value)" />
313+ oninput ="send('version', this.value)" />
269314 </div>
270315 <div class="field">
271316 <label>Description (Markdown supported)</label>
272317 <textarea id="description"
273- onchange ="send('description', this.value)">${ escHtml ( mod . Description ?? '' ) } </textarea>
318+ oninput ="send('description', this.value)">${ escHtml ( mod . Description ?? '' ) } </textarea>
274319 </div>
275320 </div>
276321 </div>
@@ -294,7 +339,7 @@ function buildHtml(data: TkprojData): string {
294339 <label>Thumbnail Path</label>
295340 <div class="thumb-row">
296341 <input type="text" id="thumbnailPath" value="${ escHtml ( thumbPath ) } "
297- onchange ="send('thumbnailPath', this.value)" />
342+ oninput ="send('thumbnailPath', this.value)" />
298343 <button class="btn" onclick="browse()">Browse...</button>
299344 </div>
300345 </div>
@@ -336,8 +381,8 @@ function buildHtml(data: TkprojData): string {
336381 div.className = 'contrib-row';
337382 div.dataset.idx = idx;
338383 div.innerHTML =
339- '<input type="text" class="contrib-name" placeholder="Name" onchange ="updateContrib()" />' +
340- '<input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)" onchange ="updateContrib()" />' +
384+ '<input type="text" class="contrib-name" placeholder="Name" oninput ="updateContrib()" />' +
385+ '<input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)" oninput ="updateContrib()" />' +
341386 '<button class="btn btn-sm btn-danger" onclick="removeContrib(' + idx + ')">-</button>';
342387 list.appendChild(div);
343388 }
0 commit comments