| 
          // ==UserScript== | 
        
        
           | 
          // @name        Postfinance CSV Export | 
        
        
           | 
          // @namespace   http://death-knight.com | 
        
        
           | 
          // @include     https://www.postfinance.ch/ap/ra/ob/html/finance/* | 
        
        
           | 
          // @updateURL   https://gist.github.com/weiserr/bc0745d3145b29f02b1d/raw/postfinance-ynab.user.js | 
        
        
           | 
          // @downloadURL https://gist.github.com/weiserr/bc0745d3145b29f02b1d/raw/postfinance-ynab.user.js | 
        
        
           | 
          // @version     14 | 
        
        
           | 
          // @grant       none | 
        
        
           | 
          // ==/UserScript== | 
        
        
           | 
          
 | 
        
        
           | 
          // Function definitions | 
        
        
           | 
          function createGenerateButton() { | 
        
        
           | 
              let input = document.createElement("button"); | 
        
        
           | 
              input.type = "button"; | 
        
        
           | 
              input.className = "ynab-button fpui-button text-sm fpui-button--primary fpui-button--normal"; | 
        
        
           | 
              input.textContent = "YNAP Export"; | 
        
        
           | 
              input.onclick = createExportButton; | 
        
        
           | 
          
 | 
        
        
           | 
              document.querySelectorAll('fpui-actions').forEach(elem => {if(elem.querySelectorAll(".ynab-button").length < 1) {elem.appendChild(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"; | 
        
        
           | 
          
 | 
        
        
           | 
              // create a temporary download link | 
        
        
           | 
              let input = document.createElement("a"); | 
        
        
           | 
              input.setAttribute('href', 'data:text/csv;charset=UTF-8,' + encodeURIComponent(csv)); | 
        
        
           | 
              input.setAttribute('download', filename); | 
        
        
           | 
              input.style.display = 'none'; | 
        
        
           | 
          
 | 
        
        
           | 
              // ...and click it to trigger the download | 
        
        
           | 
              document.body.appendChild(input); | 
        
        
           | 
              input.click(); | 
        
        
           | 
              document.body.removeChild(input); | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          function createCSV() { | 
        
        
           | 
              // acquire the data computed by the Post | 
        
        
           | 
              const rows = Array.from(document.querySelector('[data-cy="movements-table"] > tbody').querySelectorAll("tr")); | 
        
        
           | 
          
 | 
        
        
           | 
              // process the content | 
        
        
           | 
              let result = rows.map((row, index) => sanitizeRow(row)); | 
        
        
           | 
          
 | 
        
        
           | 
              // add the header | 
        
        
           | 
              result.unshift(createHeader()); | 
        
        
           | 
          
 | 
        
        
           | 
              // join the results into a single string | 
        
        
           | 
              return result.join("\n"); | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          function createHeader() { | 
        
        
           | 
              return 'Date,Payee,Category,Memo,Outflow,Inflow'; | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          function sanitizeRow(row) { | 
        
        
           | 
              const date = row.querySelector('[data-cy="date"] > span:nth-child(2)').textContent; | 
        
        
           | 
              const payee = row.querySelector('[data-cy="shortText"] > span:nth-child(2)').textContent.replace(/\"/gi, '').replace(/\n/gi, ' ').replace(/,/gi, ';  ').trim(); | 
        
        
           | 
              const category = ''; | 
        
        
           | 
              const memo = ''; | 
        
        
           | 
              const outflow = row.querySelector('[data-cy="debit"] > span:nth-child(2) > fpui-amount > span:nth-child(1)')?.textContent?.replace(/[^\d\.]/g, '')?.trim() ?? ''; | 
        
        
           | 
              const inflow = row.querySelector('[data-cy="credit"] > span:nth-child(2) > fpui-amount > span:nth-child(1)')?.textContent?.replace(/[^\d\.]/g, '')?.trim() ?? ''; | 
        
        
           | 
          
 | 
        
        
           | 
              let line = []; | 
        
        
           | 
              line.push(date); | 
        
        
           | 
              line.push(payee); | 
        
        
           | 
              line.push(category); | 
        
        
           | 
              line.push(memo); | 
        
        
           | 
              line.push(outflow); | 
        
        
           | 
              line.push(inflow); | 
        
        
           | 
          
 | 
        
        
           | 
              return line.join(','); | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          function waitForElem(selector) { | 
        
        
           | 
              if (document.URL == "https://www.postfinance.ch/ap/ra/ob/html/finance/assets/movements-overview" && document.querySelector(selector)) { | 
        
        
           | 
                  createGenerateButton(); | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              const observer = new MutationObserver((mutations) => { | 
        
        
           | 
                  if (document.URL == "https://www.postfinance.ch/ap/ra/ob/html/finance/assets/movements-overview" && document.querySelector(selector)) { | 
        
        
           | 
                      createGenerateButton(); | 
        
        
           | 
                  } | 
        
        
           | 
              }); | 
        
        
           | 
          
 | 
        
        
           | 
              observer.observe(document.body, { | 
        
        
           | 
                  childList: true, | 
        
        
           | 
                  subtree: true, | 
        
        
           | 
              }); | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          waitForElem('fpui-actions'); | 
        
  
Hi Weiser, wow. That looks great! Impressive.
I am using Greasymonkey for the first time, can you quickly explain how it works? Where do I have to add the code? Thank you!!!