password-manager-mirror/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/DataImport/Input.js

278 lines
7.9 KiB
JavaScript

/*
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({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Input',
getInitialState: function() {
return {
'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,
//'parsedInput': (this.props.importContext.parsedInput) ? this.props.importContext.parsedInput : null,
};
},
/*
componentDidMount: function() {
this.updateNextStatus(this.state.inputString);
},
//-------------------------------------------------------------------------
handleNextStep: function() {
var result;
var jsonData;
var parsedInput;
var inputString = this.refs['input-textarea'].value.trim();
// this.props.importContext.setData(inputString);
result = {'inputString': inputString};
/*
parsedInput = this.parseJson(inputString);
if (parsedInput) {
MochiKit.Base.update(result, this.props.importContext.getInitialJsonContext(parsedInput));
} else {
parsedInput = this.parseCsv(inputString);
if (parsedInput) {
MochiKit.Base.update(result, this.props.importContext.getInitialCsvContext(parsedInput));
} else {
result = false;
}
}
* /
return result;
},
updateNextStatus: function(newInputString) {
// this.props.setNextStepCallback((newInputString) ? this.handleNextStep : null);
},
//=========================================================================
extractJsonFromClipperzExport: function(someHtml) {
var textarea;
var regexMatch;
var result;
var re = new RegExp('.*<textarea>(.*)<\/textarea>.*','g');
if (re.test(someHtml)) {
textarea = this.refs['input-textarea'];
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;
},
*/
//=========================================================================
updateTextAreaContent: function (aValue, shouldMoveForwardToo) {
var value;
value = this.props.importContext.setInputString(aValue, shouldMoveForwardToo);
this.setState({'inputString': value});
},
handleUploadFiles: function (someFiles) {
var file;
var reader;
if (someFiles.length == 1) {
file = someFiles[0];
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;
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);
} else {
// Should this be removed?
alert("Error: expecting a file as input.");
}
},
handleOnDrop: function (anEvent) {
anEvent.preventDefault();
this.handleUploadFiles(anEvent.dataTransfer.files)
},
handleInputFiles: function (anEvent) {
anEvent.preventDefault();
this.handleUploadFiles(anEvent.target.files)
},
handleOnDragOver: function (anEvent) {
// 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
anEvent.stopPropagation();
anEvent.preventDefault();
anEvent.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
},
handleTextareaChange: function () {
// var newInputString;
//
// newInputString = this.refs['input-textarea'].value;
// this.setState({'inputString': newInputString});
// this.props.importContext.setInputString(newInputString);
this.updateTextAreaContent(this.refs['input-textarea'].value, false);
},
//=========================================================================
render: function() {
return React.DOM.div({},[
React.DOM.div({'className':'description'}, [
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."),
]),
React.DOM.form({'key':'form', 'className':'importForm' }, [
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,
'className': 'dropArea'
}, [
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',
'onClick': MochiKit.Base.bind(function() { this.refs['upload-input'].click() }, this),
}, "select it manually")
]),
React.DOM.div({'className': 'description'},
React.DOM.p({}, "Alternatively you may type or paste any properly formatted CSV or JSON data.")
),
React.DOM.div({'key':'fields'},[
React.DOM.textarea({
'key':'input-textarea',
'name':'input-textarea',
'ref':'input-textarea',
'placeholder':"Type or copy your data here",
'value': this.state.inputString,
'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);