]>
git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blob - frontend/js/app.js
e9d469be99d400656e7107259265c8f2503ece1d
5 function asyncForEach ( items
, handler
, callback
) {
8 if ( items
. length
=== 0 ) return callback ();
10 ( function iterator () {
11 handler ( items
[ cur
], function ( error
) {
12 if ( error
) return callback ( error
);
13 if ( cur
>= items
. length
- 1 ) return callback ();
21 function getProfile ( accessToken
, callback
) {
22 callback
= callback
|| function ( error
) { if ( error
) console
. error ( error
); };
24 superagent
. get ( '/api/profile' ). query ({ access_token : accessToken
}). end ( function ( error
, result
) {
28 if ( error
&& ! error
. response
) return callback ( error
);
29 if ( result
. statusCode
!== 200 ) {
30 delete localStorage
. accessToken
;
31 return callback ( 'Invalid access token' );
34 localStorage
. accessToken
= accessToken
;
35 app
. session
. username
= result
. body
. username
;
36 app
. session
. valid
= true ;
42 function sanitize ( filePath
) {
43 filePath
= '/' + filePath
;
44 return filePath
. replace ( /\/+/g , '/' );
47 function encode ( filePath
) {
48 return filePath
. split ( '/' ). map ( encodeURIComponent
). join ( '/' );
51 function decode ( filePath
) {
52 return filePath
. split ( '/' ). map ( decodeURIComponent
). join ( '/' );
56 images : [ '.png' , '.jpg' , '.jpeg' , '.tiff' , '.gif' ],
57 text : [ '.txt' , '.md' ],
59 html : [ '.html' , '.htm' , '.php' ],
60 video : [ '.mp4' , '.mpg' , '.mpeg' , '.ogg' , '.mkv' ]
63 function getPreviewUrl ( entry
, basePath
) {
64 var path
= '/_admin/img/' ;
66 if ( entry
. isDirectory
) return path
+ 'directory.png' ;
67 if ( mimeTypes
. images
. some ( function ( e
) { return entry
. filePath
. endsWith ( e
); })) return sanitize ( basePath
+ '/' + entry
. filePath
);
68 if ( mimeTypes
. text
. some ( function ( e
) { return entry
. filePath
. endsWith ( e
); })) return path
+ 'text.png' ;
69 if ( mimeTypes
. pdf
. some ( function ( e
) { return entry
. filePath
. endsWith ( e
); })) return path
+ 'pdf.png' ;
70 if ( mimeTypes
. html
. some ( function ( e
) { return entry
. filePath
. endsWith ( e
); })) return path
+ 'html.png' ;
71 if ( mimeTypes
. video
. some ( function ( e
) { return entry
. filePath
. endsWith ( e
); })) return path
+ 'video.png' ;
73 return path
+ 'unknown.png' ;
76 // simple extension detection, does not work with double extension like .tar.gz
77 function getExtension ( entry
) {
78 if ( entry
. isFile
) return entry
. filePath
. slice ( entry
. filePath
. lastIndexOf ( '.' ) + 1 );
83 loadDirectory ( app
. path
);
86 function loadDirectory ( filePath
) {
89 filePath
= filePath
? sanitize ( filePath
) : '/' ;
91 superagent
. get ( '/api/files/' + encode ( filePath
)). query ({ access_token : localStorage
. accessToken
}). end ( function ( error
, result
) {
94 if ( result
&& result
. statusCode
=== 401 ) return logout ();
95 if ( error
) return console
. error ( error
);
97 result
. body
. entries
. sort ( function ( a
, b
) { return a
. isDirectory
&& b
. isFile
? - 1 : 1 ; });
98 app
. entries
= result
. body
. entries
. map ( function ( entry
) {
99 entry
. previewUrl
= getPreviewUrl ( entry
, filePath
);
100 entry
. extension
= getExtension ( entry
);
104 app
. pathParts
= decode ( filePath
). split ( '/' ). filter ( function ( e
) { return !! e
; }). map ( function ( e
, i
, a
) {
107 link : '#' + sanitize ( '/' + a
. slice ( 0 , i
). join ( '/' ) + '/' + e
)
111 // update in case this was triggered from code
112 window
. location
. hash
= app
. path
;
116 function open ( row
, event
, column
) {
117 var path
= sanitize ( app
. path
+ '/' + row
. filePath
);
119 if ( row
. isDirectory
) {
120 window
. location
. hash
= path
;
124 window
. open ( encode ( path
));
127 function uploadFiles ( files
) {
128 if (! files
|| ! files
. length
) return ;
130 app
. uploadStatus
. busy
= true ;
131 app
. uploadStatus
. count
= files
. length
;
132 app
. uploadStatus
. done
= 0 ;
133 app
. uploadStatus
. percentDone
= 0 ;
135 asyncForEach ( files
, function ( file
, callback
) {
136 var path
= encode ( sanitize ( app
. path
+ '/' + file
. name
));
138 var formData
= new FormData ();
139 formData
. append ( 'file' , file
);
141 superagent
. post ( '/api/files' + path
). query ({ access_token : localStorage
. accessToken
}). send ( formData
). end ( function ( error
, result
) {
142 if ( result
&& result
. statusCode
=== 401 ) return logout ();
143 if ( result
&& result
. statusCode
!== 201 ) return callback ( 'Error uploading file: ' , result
. statusCode
);
144 if ( error
) return callback ( error
);
146 app
. uploadStatus
. done
+= 1 ;
147 app
. uploadStatus
. percentDone
= Math
. round ( app
. uploadStatus
. done
/ app
. uploadStatus
. count
* 100 );
151 }, function ( error
) {
152 if ( error
) console
. error ( error
);
154 app
. uploadStatus
. busy
= false ;
155 app
. uploadStatus
. count
= 0 ;
156 app
. uploadStatus
. done
= 0 ;
157 app
. uploadStatus
. percentDone
= 100 ;
163 function dragOver ( event
) {
164 event
. preventDefault ();
167 function drop ( event
) {
168 event
. preventDefault ();
169 uploadFiles ( event
. dataTransfer
. files
|| []);
188 folderListingEnabled : false ,
196 onLogin : function () {
199 superagent
. post ( '/api/login' ). send ({ username : app
. loginData
. username
, password : app
. loginData
. password
}). end ( function ( error
, result
) {
202 if ( error
) return console
. error ( error
);
203 if ( result
. statusCode
=== 401 ) return console
. error ( 'Invalid credentials' );
205 getProfile ( result
. body
. accessToken
, function ( error
) {
206 if ( error
) return console
. error ( error
);
208 loadDirectory ( window
. location
. hash
. slice ( 1 ));
212 onOptionsMenu : function ( command
) {
213 if ( command
=== 'folderListing' ) {
214 superagent
. put ( '/api/settings' ). send ({ folderListingEnabled : this . folderListingEnabled
}). query ({ access_token : localStorage
. accessToken
}). end ( function ( error
) {
215 if ( error
) console
. error ( error
);
217 } else if ( command
=== 'about' ) {
219 title : 'About Surfer' ,
220 message : 'Surfer is a static file server written by <a href="https://cloudron.io" target="_blank">Cloudron</a>.<br/><br/>The source code is licensed under MIT and available <a href="https://git.cloudron.io/cloudron/surfer" target="_blank">here</a>.' ,
221 dangerouslyUseHTMLString : true ,
222 confirmButtonText : 'OK' ,
223 showCancelButton : false ,
226 }). then ( function () {}). catch ( function () {});
227 } else if ( command
=== 'logout' ) {
228 superagent
. post ( '/api/logout' ). query ({ access_token : localStorage
. accessToken
}). end ( function ( error
) {
229 if ( error
) console
. error ( error
);
231 app
. session
. valid
= false ;
233 delete localStorage
. accessToken
;
237 onDownload : function ( entry
) {
238 if ( entry
. isDirectory
) return ;
239 window
. location
. href
= encode ( '/api/files/' + sanitize ( app
. path
+ '/' + entry
. filePath
)) + '?access_token=' + localStorage
. accessToken
;
241 onUpload : function () {
242 $( app
.$ refs
. upload
). on ( 'change' , function () {
244 // detach event handler
245 $( app
.$ refs
. upload
). off ( 'change' );
247 uploadFiles ( app
.$ refs
. upload
. files
|| []);
250 // reset the form first to make the change handler retrigger even on the same file selected
251 app
.$ refs
. upload
. value
= '' ;
252 app
.$ refs
. upload
. click ();
254 onDelete : function ( entry
) {
255 var title
= 'Really delete ' + ( entry
. isDirectory
? 'folder ' : '' ) + entry
. filePath
;
256 this .$ confirm ( '' , title
, { confirmButtonText : 'Yes' , cancelButtonText : 'No' }). then ( function () {
257 var path
= encode ( sanitize ( app
. path
+ '/' + entry
. filePath
));
259 superagent
. del ( '/api/files' + path
). query ({ access_token : localStorage
. accessToken
, recursive : true }). end ( function ( error
, result
) {
260 if ( result
&& result
. statusCode
=== 401 ) return logout ();
261 if ( result
&& result
. statusCode
!== 200 ) return console
. error ( 'Error deleting file: ' , result
. statusCode
);
262 if ( error
) return console
. error ( error
);
266 }). catch ( function () {
267 console
. log ( 'delete error:' , arguments
);
270 onRename : function ( entry
) {
271 var title
= 'Rename ' + entry
. filePath
;
272 this .$ prompt ( '' , title
, { confirmButtonText : 'Yes' , cancelButtonText : 'No' , inputPlaceholder : 'new filename' , inputValue : entry
. filePath
}). then ( function ( data
) {
273 var path
= encode ( sanitize ( app
. path
+ '/' + entry
. filePath
));
274 var newFilePath
= sanitize ( app
. path
+ '/' + data
. value
);
276 superagent
. put ( '/api/files' + path
). query ({ access_token : localStorage
. accessToken
}). send ({ newFilePath : newFilePath
}). end ( function ( error
, result
) {
277 if ( result
&& result
. statusCode
=== 401 ) return logout ();
278 if ( result
&& result
. statusCode
!== 200 ) return console
. error ( 'Error renaming file: ' , result
. statusCode
);
279 if ( error
) return console
. error ( error
);
283 }). catch ( function () {
284 console
. log ( 'rename error:' , arguments
);
287 onNewFolder : function () {
288 var title
= 'Create New Folder' ;
289 this .$ prompt ( '' , title
, { confirmButtonText : 'Yes' , cancelButtonText : 'No' , inputPlaceholder : 'new foldername' }). then ( function ( data
) {
290 var path
= encode ( sanitize ( app
. path
+ '/' + data
. value
));
292 superagent
. post ( '/api/files' + path
). query ({ access_token : localStorage
. accessToken
, directory : true }). end ( function ( error
, result
) {
293 if ( result
&& result
. statusCode
=== 401 ) return logout ();
294 if ( result
&& result
. statusCode
=== 403 ) return console
. error ( 'Name not allowed' );
295 if ( result
&& result
. statusCode
=== 409 ) return console
. error ( 'Directory already exists' );
296 if ( result
&& result
. statusCode
!== 201 ) return console
. error ( 'Error creating directory: ' , result
. statusCode
);
297 if ( error
) return console
. error ( error
);
301 }). catch ( function () {
302 console
. log ( 'create folder error:' , arguments
);
305 prettyDate : function ( row
, column
, cellValue
, index
) {
306 var date
= new Date ( cellValue
),
307 diff
= ((( new Date ()). getTime () - date
. getTime ()) / 1000 ),
308 day_diff
= Math
. floor ( diff
/ 86400 );
310 if ( isNaN ( day_diff
) || day_diff
< 0 )
313 return day_diff
=== 0 && (
314 diff
< 60 && 'just now' ||
315 diff
< 120 && '1 minute ago' ||
316 diff
< 3600 && Math
. floor ( diff
/ 60 ) + ' minutes ago' ||
317 diff
< 7200 && '1 hour ago' ||
318 diff
< 86400 && Math
. floor ( diff
/ 3600 ) + ' hours ago' ) ||
319 day_diff
=== 1 && 'Yesterday' ||
320 day_diff
< 7 && day_diff
+ ' days ago' ||
321 day_diff
< 31 && Math
. ceil ( day_diff
/ 7 ) + ' weeks ago' ||
322 day_diff
< 365 && Math
. round ( day_diff
/ 30 ) + ' months ago' ||
323 Math
. round ( day_diff
/ 365 ) + ' years ago' ;
325 prettyFileSize : function ( row
, column
, cellValue
, index
) {
326 return filesize ( cellValue
);
328 loadDirectory : loadDirectory
,
330 window
. location
. hash
= sanitize ( app
. path
. split ( '/' ). slice ( 0 , - 1 ). filter ( function ( p
) { return !! p
; }). join ( '/' ));
338 getProfile ( localStorage
. accessToken
, function ( error
) {
339 if ( error
) return console
. error ( error
);
341 loadDirectory ( window
. location
. hash
. slice ( 1 ));
343 superagent
. get ( '/api/settings' ). query ({ access_token : localStorage
. accessToken
}). end ( function ( error
, result
) {
344 if ( error
) console
. error ( error
);
346 app
. folderListingEnabled
= !! result
. body
. folderListingEnabled
;
350 $( window
). on ( 'hashchange' , function () {
351 loadDirectory ( window
. location
. hash
. slice ( 1 ));