2015-05-14 18:55:18 +02:00
/ *
Copyright 2008 - 2015 Clipperz Srl
This file is part of Clipperz , the online password manager .
For further information about its features and functionalities please
refer to http : //www.clipperz.com.
* Clipperz is free software : you can redistribute it and / or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
* Clipperz is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU Affero General Public License for more details .
* You should have received a copy of the GNU Affero General Public
License along with Clipperz . If not , see http : //www.gnu.org/licenses/.
* /
"use strict" ;
Clipperz . Base . module ( 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport' ) ;
Clipperz . PM . UI . Components . ExtraFeatures . DataImport . InputClass = React . createClass ( {
2015-06-27 19:08:20 +02:00
2016-03-29 11:45:50 +02:00
displayName : 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Input' ,
2015-05-21 14:32:51 +02:00
getInitialState : function ( ) {
return {
2015-06-27 19:08:20 +02:00
'inputString' : this . props . importContext . inputString ( ) ,
// 'inputString': (this.props.importContext.inputString) ? this.props.importContext.inputString : null,
// 'format': (this.props.importContext.format) ? this.props.importContext.format : null,
2015-05-21 14:32:51 +02:00
//'parsedInput': (this.props.importContext.parsedInput) ? this.props.importContext.parsedInput : null,
} ;
} ,
2015-06-27 19:08:20 +02:00
/ *
2015-05-21 14:32:51 +02:00
componentDidMount : function ( ) {
this . updateNextStatus ( this . state . inputString ) ;
} ,
//-------------------------------------------------------------------------
handleNextStep : function ( ) {
var result ;
var jsonData ;
var parsedInput ;
2016-03-29 11:45:50 +02:00
var inputString = this . refs [ 'input-textarea' ] . value . trim ( ) ;
2015-06-27 19:08:20 +02:00
// this.props.importContext.setData(inputString);
2015-05-21 14:32:51 +02:00
result = { 'inputString' : inputString } ;
2015-06-27 19:08:20 +02:00
/ *
2015-05-21 14:32:51 +02:00
parsedInput = this . parseJson ( inputString ) ;
if ( parsedInput ) {
2015-06-27 19:08:20 +02:00
MochiKit . Base . update ( result , this . props . importContext . getInitialJsonContext ( parsedInput ) ) ;
2015-05-21 14:32:51 +02:00
} else {
parsedInput = this . parseCsv ( inputString ) ;
if ( parsedInput ) {
MochiKit . Base . update ( result , this . props . importContext . getInitialCsvContext ( parsedInput ) ) ;
} else {
result = false ;
}
}
2015-06-27 19:08:20 +02:00
* /
2015-05-21 14:32:51 +02:00
return result ;
} ,
updateNextStatus : function ( newInputString ) {
2015-06-27 19:08:20 +02:00
// this.props.setNextStepCallback((newInputString) ? this.handleNextStep : null);
2015-05-21 14:32:51 +02:00
} ,
//=========================================================================
extractJsonFromClipperzExport : function ( someHtml ) {
var textarea ;
var regexMatch ;
var result ;
var re = new RegExp ( '.*<textarea>(.*)<\/textarea>.*' , 'g' ) ;
if ( re . test ( someHtml ) ) {
2016-03-29 11:45:50 +02:00
textarea = this . refs [ 'input-textarea' ] ;
2015-05-21 14:32:51 +02:00
textarea . innerHTML = someHtml . replace ( re , '$1' ) ;
result = textarea . innerHTML ;
} else {
result = false ;
}
return result ;
} ,
addImportIds : function ( someJson ) {
var count ;
for ( count = 0 ; count < someJson . length ; count ++ ) {
someJson [ count ] [ '_importId' ] = count ;
}
} ,
parseJson : function ( aJsonString ) {
var result ;
var jsonData ;
try {
jsonData = JSON . parse ( aJsonString ) ;
this . addImportIds ( jsonData ) ;
result = jsonData ;
} catch ( e ) {
result = false ;
}
return result ;
} ,
parseCsv : function ( aCsvString ) {
var result ;
var i ;
var parsedCsv = Papa . parse ( aCsvString ) ;
if ( parsedCsv . errors . length != 0 ) {
result = false ;
} else {
result = this . csvFillEmptyCells ( parsedCsv . data ) ;
}
return result ;
} ,
csvFillEmptyCells : function ( table ) {
var i , j ;
var result = [ ] ;
var maxColumns = MochiKit . Iter . reduce ( function ( prev , next ) {
return Math . max ( prev , next )
} , MochiKit . Base . map ( function ( row ) { return row . length ; } , table ) ) ;
for ( i = 0 ; i < table . length ; i ++ ) {
result [ i ] = [ ] ;
for ( j = 0 ; j < maxColumns ; j ++ ) {
result [ i ] [ j ] = ( typeof ( table [ i ] [ j ] ) != "undefined" ) ? table [ i ] [ j ] : "" ;
}
}
return result ;
} ,
2015-06-27 19:08:20 +02:00
* /
2015-05-21 14:32:51 +02:00
//=========================================================================
2015-06-27 19:08:20 +02:00
updateTextAreaContent : function ( aValue , shouldMoveForwardToo ) {
var value ;
value = this . props . importContext . setInputString ( aValue , shouldMoveForwardToo ) ;
this . setState ( { 'inputString' : value } ) ;
} ,
handleUploadFiles : function ( someFiles ) {
2015-05-14 18:55:18 +02:00
var file ;
var reader ;
if ( someFiles . length == 1 ) {
file = someFiles [ 0 ] ;
2015-06-27 19:08:20 +02:00
reader = new FileReader ( ) ;
// Binary files are just thrown in the textarea as weird UTF-8 characters: should we do something about it?
reader . onloadend = MochiKit . Base . bind ( function ( ) {
/ *
var extractedJson = this . extractJsonFromClipperzExport ( reader . result ) ;
var newInputString ;
2015-05-14 18:55:18 +02:00
2015-06-27 19:08:20 +02:00
if ( extractedJson ) {
newInputString = extractedJson ;
} else {
newInputString = reader . result ;
}
this . setState ( { 'inputString' : newInputString } ) ;
this . updateNextStatus ( newInputString ) ;
* /
//console.log("handleUploadFiles", this.props.importContext, this.state, this);
// this.props.importContext.setInputString(reader.result);
this . updateTextAreaContent ( reader . result , true ) ;
} , this ) ;
reader . readAsText ( file ) ;
2015-05-14 18:55:18 +02:00
} else {
2015-05-21 14:32:51 +02:00
// Should this be removed?
2015-05-14 18:55:18 +02:00
alert ( "Error: expecting a file as input." ) ;
}
} ,
2015-06-27 19:08:20 +02:00
handleOnDrop : function ( anEvent ) {
anEvent . preventDefault ( ) ;
2015-05-14 18:55:18 +02:00
2015-06-27 19:08:20 +02:00
this . handleUploadFiles ( anEvent . dataTransfer . files )
2015-05-14 18:55:18 +02:00
} ,
2015-06-27 19:08:20 +02:00
handleInputFiles : function ( anEvent ) {
anEvent . preventDefault ( ) ;
2015-05-14 18:55:18 +02:00
2015-06-27 19:08:20 +02:00
this . handleUploadFiles ( anEvent . target . files )
2015-05-14 18:55:18 +02:00
} ,
2015-06-27 19:08:20 +02:00
handleOnDragOver : function ( anEvent ) {
2015-05-14 18:55:18 +02:00
// Somehow necessary:
// http://enome.github.io/javascript/2014/03/24/drag-and-drop-with-react-js.html
// https://code.google.com/p/chromium/issues/detail?id=168387
// http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
2016-03-29 11:45:50 +02:00
anEvent . stopPropagation ( ) ;
2015-06-27 19:08:20 +02:00
anEvent . preventDefault ( ) ;
2016-03-29 11:45:50 +02:00
anEvent . dataTransfer . dropEffect = 'copy' ; // Explicitly show this is a copy.
2015-05-14 18:55:18 +02:00
} ,
2015-06-27 19:08:20 +02:00
handleTextareaChange : function ( ) {
// var newInputString;
//
2016-03-29 11:45:50 +02:00
// newInputString = this.refs['input-textarea'].value;
2015-06-27 19:08:20 +02:00
// this.setState({'inputString': newInputString});
// this.props.importContext.setInputString(newInputString);
2016-03-29 11:45:50 +02:00
this . updateTextAreaContent ( this . refs [ 'input-textarea' ] . value , false ) ;
2015-05-14 18:55:18 +02:00
} ,
2015-05-21 14:32:51 +02:00
//=========================================================================
2015-05-14 18:55:18 +02:00
render : function ( ) {
return React . DOM . div ( { } , [
2015-06-27 19:08:20 +02:00
React . DOM . div ( { 'className' : 'description' } , [
2015-07-04 18:43:59 +02:00
React . DOM . p ( { } , "Import data from a CSV file (like those produced by most password managers) or copy data from another Clipperz account using a JSON/HTML export file created by Clipperz." ) ,
2015-06-27 19:08:20 +02:00
] ) ,
2015-05-21 14:32:51 +02:00
React . DOM . form ( { 'key' : 'form' , 'className' : 'importForm' } , [
2015-05-14 18:55:18 +02:00
React . DOM . input ( {
'type' : 'file' ,
'ref' : 'upload-input' ,
'onClick' : function ( e ) { e . target . value = null } ,
'onChange' : this . handleInputFiles ,
'style' : { 'display' : 'none' }
} ) ,
React . DOM . div ( {
'onDragOver' : this . handleOnDragOver ,
'onDrop' : this . handleOnDrop ,
2015-05-21 14:32:51 +02:00
'className' : 'dropArea'
2015-07-04 18:43:59 +02:00
} , [
React . DOM . span ( { } , "Drag your CSV or Clipperz export file here" ) ,
React . DOM . br ( { } ) ,
React . DOM . span ( { } , "or" ) ,
React . DOM . br ( { } ) ,
React . DOM . a ( {
'className' : 'button' ,
2016-03-29 11:45:50 +02:00
'onClick' : MochiKit . Base . bind ( function ( ) { this . refs [ 'upload-input' ] . click ( ) } , this ) ,
2015-07-04 18:43:59 +02:00
} , "select it manually" )
] ) ,
React . DOM . div ( { 'className' : 'description' } ,
React . DOM . p ( { } , "Alternatively you may type or paste any properly formatted CSV or JSON data." )
) ,
2015-05-14 18:55:18 +02:00
React . DOM . div ( { 'key' : 'fields' } , [
React . DOM . textarea ( {
'key' : 'input-textarea' ,
'name' : 'input-textarea' ,
'ref' : 'input-textarea' ,
2015-07-04 18:43:59 +02:00
'placeholder' : "Type or copy your data here" ,
2015-05-21 14:32:51 +02:00
'value' : this . state . inputString ,
2015-05-14 18:55:18 +02:00
'onChange' : this . handleTextareaChange ,
'onDragOver' : this . handleOnDragOver ,
'onDrop' : this . handleOnDrop ,
} ) ,
] )
] )
] ) ;
}
} ) ;
Clipperz . PM . UI . Components . ExtraFeatures . DataImport . Input = React . createFactory ( Clipperz . PM . UI . Components . ExtraFeatures . DataImport . InputClass ) ;