import { CoreDOMWidgetModel } from './widget_core' ; import { DOMWidgetView } from '@jupyter-widgets/base' ; interface IFileUploaded { content : ArrayBuffer ; name : string ; size : number ; type : string ; last_modified : number ; } export class FileUploadModel extends CoreDOMWidgetModel { defaults ( ) { return { ... super . defaults ( ) , _model_name : 'FileUploadModel' , _view_name : 'FileUploadView' , accept : '' , description : 'Upload' , disabled : false , icon : 'upload' , button_style : '' , multiple : false , value : [ ] , error : '' , style : null , } ; } static serializers = { ... CoreDOMWidgetModel . serializers , value : { serialize : < T > ( x ) : T => x } , } ; } export class FileUploadView extends DOMWidgetView { el : HTMLButtonElement ; fileInput : HTMLInputElement ; preinitialize ( ) { this . tagName = 'button' ; } render ( ) { super . render ( ) ; this . el . classList . add ( 'jupyter-widgets' ) ; this . el . classList . add ( 'widget-upload' ) ; this . el . classList . add ( 'jupyter-button' ) ; this . fileInput = document . createElement ( 'input' ) ; this . fileInput . type = 'file' ; this . fileInput . style . display = 'none' ; this . el . addEventListener ( 'click' , ( ) => { this . fileInput . click ( ) ; } ) ; this . fileInput . addEventListener ( 'click' , ( ) => { this . fileInput . value = '' ; } ) ; this . fileInput . addEventListener ( 'change' , ( ) => { const promisesFile = [ ] ; Array . from ( this . fileInput . files ?? [ ] ) . forEach ( ( file ) => { promisesFile . push ( new Promise ( ( resolve , reject ) => { const fileReader = new FileReader ( ) ; fileReader . onload = ( ) : void => { const content = fileReader . result as ArrayBuffer ; resolve ( { content , name : file . name , type : file . type , size : file . size , last_modified : file . lastModified , } ) ; } ; fileReader . onerror = ( ) : void => { reject ( ) ; } ; fileReader . onabort = fileReader . onerror ; fileReader . readAsArrayBuffer ( file ) ; } ) ) ; } ) ; Promise . all ( promisesFile ) . then ( ( files ) => { this . model . set ( { value : files , error : '' , } ) ; this . touch ( ) ; } ) . catch ( ( err ) => { console . error ( 'error in file upload: %o' , err ) ; this . model . set ( { error : err , } ) ; this . touch ( ) ; } ) ; } ) ; this . listenTo ( this . model , 'change:button_style' , this . update_button_style ) ; this . set_button_style ( ) ; this . update ( ) ; } update ( ) { this . el . disabled = this . model . get ( 'disabled' ) ; this . el . setAttribute ( 'title' , this . model . get ( 'tooltip' ) ) ; const value = this . model . get ( 'value' ) ; const description = `${ this . model . get ( 'description' ) } (${ value . length })` ; const icon = this . model . get ( 'icon' ) ; if ( description . length || icon . length ) { this . el . textContent = '' ; if ( icon . length ) { const i = document . createElement ( 'i' ) ; i . classList . add ( 'fa' ) ; i . classList . add ( 'fa-' + icon ) ; if ( description . length === 0 ) { i . classList . add ( 'center' ) ; } this . el . appendChild ( i ) ; } this . el . appendChild ( document . createTextNode ( description ) ) ; } this . fileInput . accept = this . model . get ( 'accept' ) ; this . fileInput . multiple = this . model . get ( 'multiple' ) ; return super . update ( ) ; } update_button_style ( ) { this . update_mapped_classes ( FileUploadView . class_map , 'button_style' , this . el ) ; } set_button_style ( ) { this . set_mapped_classes ( FileUploadView . class_map , 'button_style' , this . el ) ; } static class_map = { primary : [ 'mod-primary' ] , success : [ 'mod-success' ] , info : [ 'mod-info' ] , warning : [ 'mod-warning' ] , danger : [ 'mod-danger' ] , } ; }