@@ -6,76 +6,82 @@
// @grant none
// ==/UserScript==
// Function definitions
function createAndAppendButton ( ) {
var input = document . createElement ( "input" ) ;
input . type = "button" ;
input . value = "Generate CSV Link" ;
input . className = "efinance-button" ;
input . onclick = provideCSVLink ;
$ ( "p.buttons" ) . append ( input ) ;
function initializeYnabExport ( ) {
// adapt the name of the standard export button
$ ( "button" , $ ( "input[name='data']" ) [ 0 ] . parentNode ) [ 0 ] . textContent = "1. Export" ;
// add the generation button
createGenerateButton ( ) ;
}
function provideCSVLink ( ) {
var input = document . createElement ( "a" ) ;
var csv = createCSV ( ) ;
var date = new Date ( ) ;
var year = date . getFullYear ( ) ;
var month = date . getMonth ( ) + 1 ;
var day = date . getDate ( ) ;
var filename = "ynab-" + year + "-" + month + "-" + day + ".csv" ;
input . setAttribute ( 'href' , 'data:text/csv;charset=UTF-8,' + encodeURIComponent ( csv ) ) ;
input . innerHTML = "Export to CSV" ;
input . className = "efinance-button" ;
input . setAttribute ( 'download' , filename ) ;
$ ( "p.buttons" ) . append ( input ) ;
function createGenerateButton ( ) {
let input = document . createElement ( "input" ) ;
input . type = "button" ;
input . value = "2. YNAB Generate" ;
input . className = "btn" ;
input . style . setProperty ( 'margin-left' , '8px' ) ;
input . onclick = createExportButton ;
$ ( "input[name='filename']" ) [ 0 ] . parentNode . append ( input ) ;
}
function createExportButton ( ) {
const csv = createCSV ( ) ;
const date = new Date ( ) ;
const year = date . getFullYear ( ) ;
const month = date . getMonth ( ) + 1 ;
const day = date . getDate ( ) ;
const filename = "ynab-" + year + "-" + month + "-" + day + ".csv" ;
let input = document . createElement ( "a" ) ;
input . setAttribute ( 'href' , 'data:text/csv;charset=UTF-8,' + encodeURIComponent ( csv ) ) ;
input . innerHTML = "3. YNAB Export" ;
input . className = "btn" ;
input . style . setProperty ( 'margin-left' , '8px' ) ;
input . setAttribute ( 'download' , filename ) ;
$ ( "input[name='filename']" ) [ 0 ] . parentNode . append ( input ) ;
}
function createCSV ( ) {
var result = [ ] ;
var lines = $ ( "tbody" ) . children ( "#detail_page tr" ) ;
// push the header
result . push ( 'Date,Payee,Category,Memo,Outflow,Inflow' ) ;
lines . each ( function ( ) { appendCreditDebitLine ( $ ( this ) , result ) } ) ;
return result . join ( "\n" ) ;
// acquire the data computed by the Post
let result = JSON . parse ( $ ( "input[name='data']" ) [ 0 ] . value )
// process the content
result = result . filter ( row => row . length === 6 ) . map ( ( row , index ) => index > 0 ? sanitizeRow ( row ) : createHeader ( ) ) ;
// join the results into a single string
return result . join ( "\n" ) ;
}
// Date,Payee,Category,Memo,Outflow,Inflow
function appendCreditDebitLine ( context , lines ) {
var line = [ ] ;
var cells = context . children ( "td" ) ;
var date = sanitize ( cells . get ( 5 ) ) ;
var payee = "" ;
var category = "" ;
var memo = sanitize ( cells . get ( 2 ) ) ;
var outflow = sanitize ( cells . get ( 4 ) ) ;
var inflow = sanitize ( cells . get ( 3 ) ) ;
// create a CSV line
line . push ( date ) ;
line . push ( payee ) ;
line . push ( category ) ;
line . push ( memo ) ;
line . push ( outflow ) ;
line . push ( inflow ) ;
// append the CSV line
lines . push ( line . join ( "," ) ) ;
function createHeader ( ) {
return 'Date,Payee,Category,Memo,Outflow,Inflow' ;
}
function sanitize ( cell ) {
return cell . innerHTML . replace ( / < b r > / gi, " " ) . replace ( / & n b s p ; / gi, "" ) . replace ( / ' / gi, '' ) . trimLeft ( ) . trimRight ( )
// TODO: properly sanitize and sort the values
function sanitizeRow ( row ) {
const date = row [ 0 ] ;
const payee = row [ 1 ] ;
const category = '' ;
const memo = '' ;
const outflow = row [ 3 ] ;
const inflow = '' ;
let line = [ ] ;
line . push ( date ) ;
line . push ( payee ) ;
line . push ( category ) ;
line . push ( memo ) ;
line . push ( outflow ) ;
line . push ( inflow ) ;
return line . join ( ',' ) ;
}
/* waitForKeyElements(): A handy, utility function that
* does what it says.
*/
function waitForKeyElements (
function waitForKeyElements (
selectorTxt , /* Required: The jQuery selector string that
specifies the desired element(s).
*/
@@ -90,64 +96,63 @@ function waitForKeyElements (
iframeSelector /* Optional: If set, identifies the iframe to
search.
*/
)
{
) {
var targetNodes , btargetsFound ;
if ( typeof iframeSelector == "undefined" )
targetNodes = $ ( selectorTxt ) ;
targetNodes = $ ( selectorTxt ) ;
else
targetNodes = $ ( iframeSelector ) . contents ( )
. find ( selectorTxt ) ;
targetNodes = $ ( iframeSelector ) . contents ( )
. find ( selectorTxt ) ;
if ( targetNodes && targetNodes . length > 0 ) {
if ( targetNodes && targetNodes . length > 0 ) {
/*--- Found target node(s). Go through each and act if they
are new.
*/
targetNodes . each ( function ( ) {
var jThis = $ ( this ) ;
var alreadyFound = jThis . data ( 'alreadyFound' ) || false ;
targetNodes . each ( function ( ) {
var jThis = $ ( this ) ;
var alreadyFound = jThis . data ( 'alreadyFound' ) || false ;
if ( ! alreadyFound ) {
//--- Call the payload function.
actionFunction ( jThis ) ;
jThis . data ( 'alreadyFound' , true ) ;
actionFunction ( jThis ) ;
jThis . data ( 'alreadyFound' , true ) ;
}
} ) ;
btargetsFound = true ;
} ) ;
btargetsFound = true ;
}
else {
btargetsFound = false ;
btargetsFound = false ;
}
//--- Get the timer-control variable for this selector.
var controlObj = waitForKeyElements . controlObj || { } ;
var controlKey = selectorTxt . replace ( / [ ^ \w ] / g, "_" ) ;
var timeControl = controlObj [ controlKey ] ;
var controlObj = waitForKeyElements . controlObj || { } ;
var controlKey = selectorTxt . replace ( / [ ^ \w ] / g, "_" ) ;
var timeControl = controlObj [ controlKey ] ;
//--- Now set or clear the timer as appropriate.
if ( btargetsFound && bWaitOnce && timeControl ) {
if ( btargetsFound && bWaitOnce && timeControl ) {
//--- The only condition where we need to clear the timer.
clearInterval ( timeControl ) ;
delete controlObj [ controlKey ]
clearInterval ( timeControl ) ;
delete controlObj [ controlKey ]
}
else {
//--- Set a timer, if needed.
if ( ! timeControl ) {
timeControl = setInterval ( function ( ) {
waitForKeyElements ( selectorTxt ,
actionFunction ,
bWaitOnce ,
iframeSelector
) ;
} ,
if ( ! timeControl ) {
timeControl = setInterval ( function ( ) {
waitForKeyElements ( selectorTxt ,
actionFunction ,
bWaitOnce ,
iframeSelector
) ;
} ,
500
) ;
controlObj [ controlKey ] = timeControl ;
controlObj [ controlKey ] = timeControl ;
}
}
waitForKeyElements . controlObj = controlObj ;
waitForKeyElements . controlObj = controlObj ;
}
// Main entry point
waitForKeyElements ( "p.buttons ", createAndAppendButton ) ;
waitForKeyElements ( "input[name='data'] ", initializeYnabExport ) ;