Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanboniface committed Oct 29, 2014
0 parents commit 2cff32f
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 0 deletions.
136 changes: 136 additions & 0 deletions csvtogeocoder.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
@font-face {
font-family: 'fira_sansbold';
src: url('./fonts/FiraSans-Bold.eot');
src: url('./fonts/FiraSans-Bold.eot?#iefix') format('embedded-opentype'),
url('./fonts/FiraSans-Bold.woff') format('woff'),
url('./fonts/FiraSans-Bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;

}


@font-face {
font-family: 'fira_sansregular';
src: url('./fonts/FiraSans-Regular.eot');
src: url('./fonts/FiraSans-Regular.eot?#iefix') format('embedded-opentype'),
url('./fonts/FiraSans-Regular.woff') format('woff'),
url('./fonts/FiraSans-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}

@font-face {
font-family: 'fira_sanslight';
src: url('./fonts/FiraSans-Light.eot');
src: url('./fonts/FiraSans-Light.eot?#iefix') format('embedded-opentype'),
url('./fonts/FiraSans-Light.woff') format('woff'),
url('./fonts/FiraSans-Light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
.csvtogeocoder {
font-family: 'fira_sanslight', sans-serif;
padding: 20px;
}
.csvtogeocoder h1, .csvtogeocoder h2 {
font-family: 'fira_sansbold', sans-serif;
font-weight: normal;
}
.csvtogeocoder #holder,
.csvtogeocoder #chosenColumns,
.csvtogeocoder #availableColumns {
width: 90%;
margin: 20px auto;
}
.csvtogeocoder #holder {
border: 1px dashed #ccc;
height: 200px;
text-align: center;
line-height: 200px;
}
.csvtogeocoder #availableColumns {
padding: 0;
}
.csvtogeocoder #holder.hover { border: 1px dashed #333; }
.csvtogeocoder #chosenColumns {
padding: 0;
height: 37px;
line-height: 37px;
border: 1px dashed #ccc;
color: #ccc;
}
.csvtogeocoder #chosenColumns:empty:before {
content: 'Drag columns here';
padding-left: 5px;
}
.csvtogeocoder #chosenColumns li,
.csvtogeocoder #availableColumns li {
background-color: #eee;
border: 1px solid #aaa;
display: inline;
padding: 5px 5px 5px 0;;
cursor: grab;
color: #444;
margin-right: 2px;
}
.csvtogeocoder #chosenColumns li:before,
.csvtogeocoder #availableColumns li:before {
background-color: #999;
color: #efefef;
content: "+";
display: inline-block;
font-family: fira_sansbold;
height: 35px;
line-height: 35px;
margin-right: 5px;
padding: 0 5px;
vertical-align: middle;
cursor: pointer;
}
.csvtogeocoder #chosenColumns li:before {
content: '-';
}
.csvtogeocoder #chosenColumns.hover { border: 1px dashed #333; }
.csvtogeocoder #fileInput {display: none;}
.csvtogeocoder input[type="button"] {
display: block;
min-width: 200px;
background-color: #2c3e50;
color: #fff;
border: none;
margin-bottom: 14px;
text-align: center;
min-height: 56px;
line-height: 56px;
border-radius: 2px;
font-weight: normal;
cursor: pointer;
margin-left: auto;
margin-right: auto;
}
.csvtogeocoder input[type="button"]:hover {
background-color: #34495e;
}
.csvtogeocoder .progressBar {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 10px;
width: 90%;
margin: 20px auto;
border: 1px solid #444;
}
.csvtogeocoder .progressBar hr {
background-color: #444;
border: medium none;
color: #444;
height: 8px;
line-height: 10px;
margin: 0;
text-align: left;
vertical-align: middle;
width: 0;
-webkit-transition: all 500ms ease-in;
transition: all 500ms ease-in;
}
196 changes: 196 additions & 0 deletions csvtogeocoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
var CSVToGeocoder = function (options) {
options = options || {};

var createNode = function (what, attrs, parent, content) {
var el = document.createElement(what);
for (var attr in attrs || {}) el[attr] = attrs[attr];
if (typeof parent !== 'undefined') parent.appendChild(el);
if (content) {
if (content.nodeType && content.nodeType === 1) el.appendChild(content);
else el.innerHTML = content;
}
return el;
};

var reader = new FileReader(), file,
formData = new FormData(), container;
if (options.container) {
if (typeof options.container === "string") container = document.querySelector(options.container);
else container = options.container;
} else {
container = document.body;
}
container.setAttribute('class', (container.getAttribute('class') ? container.getAttribute('class') + ' ' : '') + 'csvtogeocoder');
createNode('h2', {}, container, '1. Choose a file');
var fileInput = createNode('input', {type: 'file', id: 'fileInput'}, container);
var holder = createNode('div', {id: 'holder'}, container, 'Drag your file here, or <a id="browseLink" href="#">browse</a>');
createNode('h2', {}, container, '2. Choose the columns to consider');
var availableColumns = createNode('ul', {id: 'availableColumns'}, container);
var chosenColumns = createNode('ul', {id: 'chosenColumns'}, container);
createNode('h2', {}, container, '3. Run the process');
var optionsContainer = createNode('div', {id: 'options'}, container),
matchAllContainer = createNode('label', {'for': 'matchAll'}, optionsContainer, 'Strict (all words must be found)'),
matchAll = createNode('input', {type: 'checkbox', id: 'matchAll'}, matchAllContainer);
var submitButton = createNode('input', {type: 'button', value: 'Geocode', disabled: 'disabled'}, container);

var stop = function (e) {
e.stopPropagation();
e.preventDefault();
};
var submit = function () {
var progressBarContainer = createNode('div', {className: 'progressBar'}, container),
progressBar = createNode('hr', {}, progressBarContainer);
var xhr = new XMLHttpRequest();
xhr.open('POST', options.postURL || '.');
xhr.overrideMimeType('text/csv; charset=utf-8');
var columns = document.querySelectorAll('#chosenColumns li');
for (var i = 0; i < columns.length; i++) {
formData.append('columns', columns[i].id);
}
formData.append('match_all', !!matchAll.checked);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
window.URL = window.URL || window.webkitURL;
var blob = new Blob([xhr.responseText], {type: 'text/csv'});
window.open(window.URL.createObjectURL(blob));
}
};
xhr.upload.addEventListener("progress", function (e) {
if (e.lengthComputable) {
var percentage = Math.round((e.loaded * 100) / e.total);
progressBar.style.width = percentage + '%';
}
}, false);
xhr.upload.addEventListener("load", function(e){
progressBarContainer.parentNode.removeChild(progressBarContainer);
}, false);
xhr.send(formData);
return false;
};
var processFile = function (f) {
file = f;
reader.readAsText(file);
holder.innerHTML = '<strong>' + file.name + '</strong> (or drag another file here, or <a id="browseLink" href="#">browse</a>)';
listenBrowseLink();
};
var onFileDrop = function (e) {
this.className = '';
stop(e);
processFile(e.dataTransfer.files[0]);
};
var onDragOver = function (e) {
stop(e);
this.className = 'hover';
};
var onDragLeave = function (e) {
stop(e);
this.className = '';
return false;
};
var onDragEnter = function (e) {
stop(e);
};
var onFileLoad = function () {
var rawHeaders = reader.result.slice(0, reader.result.indexOf('\n')),
separators = [',', ';', '|', ':'], currentCount = 0, separator, count;
for (var i = 0; i < separators.length; i++) {
count = (rawHeaders.match(new RegExp('\\' + separators[i],'g')) || []).length;
if (count > currentCount) {
currentCount = count;
separator = separators[i];
}
}
if (currentCount === 0) return;
var headers = rawHeaders.split(separator), column;
availableColumns.innerHTML = '';
chosenColumns.innerHTML = '';
for (var j = 0; j < headers.length; j++) {
column = document.createElement('li');
column.setAttribute('draggable', 'true');
column.innerHTML = column.value = column.id = headers[j];
column.ondragstart = onColumnDragStart;
column.onclick = onColumnClick;
column.ondrop = onColumnDrop;
column.ondragover = onColumnDragOver;
column.ondragleave = onColumnDragLeave;
availableColumns.appendChild(column);
}
submitButton.disabled = false;
var blob = new Blob([reader.result], {type: 'text/csv'});
formData.append('data', blob);
};
var onSubmit = function (e) {
stop(e);
submit(file);
return false;
};
var onColumnDragStart = function (e) {
e.dataTransfer.effectAllowed = 'copyMove';
e.dataTransfer.setData('text/plain', this.id);
};
var onColumnDropboxDragover = function (e) {
stop(e);
this.className = 'hover';
e.dataTransfer.dropEffect = 'copyMove';
};
var onColumnDropboxDragleave = function (e) {
stop(e);
this.className = '';
};
var onColumnDropboxDrop = function (e) {
this.className = '';
stop(e);
var el = document.getElementById(e.dataTransfer.getData('text/plain'));
el.parentNode.removeChild(el);
chosenColumns.appendChild(el);
return false;
};
var onColumnDrop = function (e) {
stop(e);
var el = document.getElementById(e.dataTransfer.getData('text/plain'));
this.parentNode.insertBefore(el, this);
};
var onColumnClick = function (e) {
this.className = '';
var from, to;
if (this.parentNode === chosenColumns) {
from = chosenColumns;
to = availableColumns;
} else {
from = availableColumns;
to = chosenColumns;
}
from.removeChild(this);
to.appendChild(this);
};
var onColumnDragOver = function (e) {
this.className = 'hover';
};
var onColumnDragLeave = function (e) {
this.className = '';
};
var onFileInputChange = function (e) {
stop(e);
processFile(this.files[0]);
};
var listenBrowseLink = function () {
var browseLink = document.querySelector('#browseLink');
var onBrowseLinkClick = function (e) {
stop(e);
fileInput.click();
};
browseLink.addEventListener('click', onBrowseLinkClick, false);
};
listenBrowseLink();
reader.addEventListener('load', onFileLoad, false);
holder.addEventListener('dragenter', onDragEnter, false);
holder.addEventListener('dragover', onDragOver, false);
holder.addEventListener('dragleave', onDragLeave, false);
holder.addEventListener('drop', onFileDrop, false);
submitButton.addEventListener('click', onSubmit, false);
chosenColumns.addEventListener('dragover', onColumnDropboxDragover, false);
chosenColumns.addEventListener('dragleave', onColumnDropboxDragleave, false);
chosenColumns.addEventListener('drop', onColumnDropboxDrop, false);
fileInput.addEventListener('change', onFileInputChange, false);

};
Binary file added fonts/FiraSans-Bold.eot
Binary file not shown.
Binary file added fonts/FiraSans-Bold.ttf
Binary file not shown.
Binary file added fonts/FiraSans-Bold.woff
Binary file not shown.
Binary file added fonts/FiraSans-Light.eot
Binary file not shown.
Binary file added fonts/FiraSans-Light.ttf
Binary file not shown.
Binary file added fonts/FiraSans-Light.woff
Binary file not shown.
Binary file added fonts/FiraSans-Regular.eot
Binary file not shown.
Binary file added fonts/FiraSans-Regular.ttf
Binary file not shown.
Binary file added fonts/FiraSans-Regular.woff
Binary file not shown.
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "csvtogeocoder-ui",
"version": "0.0.1",
"description": "Javascript UI to help users upload a CSV to be geocoded",
"main": "csvtogeocode.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"csv",
"geocoding"
],
"author": "Yohan Boniface",
"license": "WTFPL"
}

0 comments on commit 2cff32f

Please sign in to comment.