@@ -69,23 +69,15 @@ export class FileSystemDrive implements Contents.IDrive {
6969 } ;
7070 }
7171
72- let parentHandle = root ;
73- // If requesting a file/directory that is not under root, we need the right directory handle
74- for ( const subPath of path . split ( '/' ) . slice ( 0 , - 1 ) ) {
75- parentHandle = await parentHandle . getDirectoryHandle ( subPath ) ;
76- }
72+ const parentHandle = await this . getParentHandle ( path ) ;
7773
7874 const parentPath = PathExt . dirname ( path ) ;
7975 const localPath = PathExt . basename ( path ) ;
8076
8177 let localHandle : FileSystemDirectoryHandle | FileSystemFileHandle ;
8278
83- const currentContent = await toArray ( parentHandle . values ( ) ) ;
84-
8579 if ( localPath ) {
86- localHandle = currentContent . filter (
87- element => element . name === localPath
88- ) [ 0 ] ;
80+ localHandle = await this . getHandle ( parentHandle , localPath ) ;
8981 } else {
9082 localHandle = parentHandle ;
9183 }
@@ -137,7 +129,7 @@ export class FileSystemDrive implements Contents.IDrive {
137129 }
138130
139131 return {
140- name : PathExt . basename ( parentPath ) ,
132+ name : localPath ,
141133 path : PathExt . join ( parentPath , localPath ) ,
142134 last_modified : '' ,
143135 created : '' ,
@@ -155,8 +147,43 @@ export class FileSystemDrive implements Contents.IDrive {
155147 throw new Error ( 'Method not implemented.' ) ;
156148 }
157149
158- newUntitled ( options ?: Contents . ICreateOptions ) : Promise < Contents . IModel > {
159- throw new Error ( 'Method not implemented.' ) ;
150+ async newUntitled (
151+ options ?: Contents . ICreateOptions
152+ ) : Promise < Contents . IModel > {
153+ const type = options ?. type || 'directory' ;
154+ const path = PathExt . join (
155+ options ?. path || '' ,
156+ type === 'directory' ? 'Untitled Folder' : 'untitled'
157+ ) ;
158+ const ext = options ?. ext || 'txt' ;
159+
160+ const parentHandle = await this . getParentHandle ( path ) ;
161+
162+ const parentPath = PathExt . dirname ( path ) ;
163+ let localPath = PathExt . basename ( path ) ;
164+ const name = localPath ;
165+
166+ if ( type === 'directory' ) {
167+ let i = 1 ;
168+ while ( await this . hasHandle ( parentHandle , localPath ) ) {
169+ localPath = `${ name } ${ i ++ } ` ;
170+ }
171+
172+ await parentHandle . getDirectoryHandle ( localPath , { create : true } ) ;
173+
174+ return this . get ( PathExt . join ( parentPath , localPath ) ) ;
175+ } else {
176+ let i = 1 ;
177+ while ( await this . hasHandle ( parentHandle , `${ localPath } .${ ext } ` ) ) {
178+ localPath = `${ name } ${ i ++ } ` ;
179+ }
180+
181+ const filename = `${ localPath } .${ ext } ` ;
182+
183+ await parentHandle . getFileHandle ( filename , { create : true } ) ;
184+
185+ return this . get ( PathExt . join ( parentPath , filename ) ) ;
186+ }
160187 }
161188
162189 delete ( path : string ) : Promise < void > {
@@ -171,17 +198,7 @@ export class FileSystemDrive implements Contents.IDrive {
171198 path : string ,
172199 options ?: Partial < Contents . IModel >
173200 ) : Promise < Contents . IModel > {
174- const root = this . _rootHandle ;
175-
176- if ( ! root ) {
177- throw new Error ( 'No root file handle' ) ;
178- }
179-
180- let parentHandle = root ;
181- // If saving a file that is not under root, we need the right directory handle
182- for ( const subPath of path . split ( '/' ) . slice ( 0 , - 1 ) ) {
183- parentHandle = await parentHandle . getDirectoryHandle ( subPath ) ;
184- }
201+ const parentHandle = await this . getParentHandle ( path ) ;
185202
186203 const handle = await parentHandle . getFileHandle ( PathExt . basename ( path ) ) ;
187204 const writable = await handle . createWritable ( { } ) ;
@@ -195,6 +212,7 @@ export class FileSystemDrive implements Contents.IDrive {
195212 await writable . write ( content ) ;
196213 }
197214 await writable . close ( ) ;
215+
198216 return this . get ( path ) ;
199217 }
200218
@@ -226,6 +244,50 @@ export class FileSystemDrive implements Contents.IDrive {
226244 return Promise . resolve ( void 0 ) ;
227245 }
228246
247+ private async getParentHandle (
248+ path : string
249+ ) : Promise < FileSystemDirectoryHandle > {
250+ const root = this . _rootHandle ;
251+
252+ if ( ! root ) {
253+ throw new Error ( 'No root file handle' ) ;
254+ }
255+
256+ let parentHandle = root ;
257+ // If saving a file that is not under root, we need the right directory handle
258+ for ( const subPath of path . split ( '/' ) . slice ( 0 , - 1 ) ) {
259+ parentHandle = await parentHandle . getDirectoryHandle ( subPath ) ;
260+ }
261+
262+ return parentHandle ;
263+ }
264+
265+ private async getHandle (
266+ parentHandle : FileSystemDirectoryHandle ,
267+ localPath : string
268+ ) : Promise < FileSystemDirectoryHandle | FileSystemFileHandle > {
269+ const content = await toArray ( parentHandle . values ( ) ) ;
270+
271+ const matches = content . filter ( element => element . name === localPath ) ;
272+
273+ if ( matches . length ) {
274+ return matches [ 0 ] ;
275+ }
276+
277+ throw new Error ( `${ localPath } does not exist.` ) ;
278+ }
279+
280+ private async hasHandle (
281+ parentHandle : FileSystemDirectoryHandle ,
282+ localPath : string
283+ ) : Promise < boolean > {
284+ const content = await toArray ( parentHandle . values ( ) ) ;
285+
286+ const matches = content . filter ( element => element . name === localPath ) ;
287+
288+ return Boolean ( matches . length ) ;
289+ }
290+
229291 private _isDisposed = false ;
230292 private _fileChanged = new Signal < Contents . IDrive , Contents . IChangedArgs > (
231293 this
0 commit comments