packages feed

hledger-web-1.50: static/hledger.js

/* hledger web ui javascript */

//----------------------------------------------------------------------
// STARTUP

$(document).ready(function() {

  // add form helpers XXX move to addForm ?

  // date picker
  // http://bootstrap-datepicker.readthedocs.io/en/latest/options.html
  var dateEl = $('#dateWrap').datepicker({
    showOnFocus: false,
    autoclose: true,
    format: 'yyyy-mm-dd',
    todayHighlight: true,
    weekStart: 1 // Monday
  });;

  // focus and pre-fill the add form whenever it is shown
  $('#addmodal')
    .on('shown.bs.modal', function() {
      addformFocus();
    })
    .on('hidden.bs.modal', function() {
      // close the date picker if open
      dateEl.datepicker('hide');
    });

  // ensure that the keypress listener on the final amount input is always active
  $('#addform')
    .on('focus', '.amount-input:last', function() {
      addformLastAmountBindKey();
    });

  // keyboard shortcuts
  // 'body' seems to hold focus better than document in FF
  $('body').bind('keydown', 'h',       function(){ $('#helpmodal').modal('toggle'); return false; });
  $('body').bind('keydown', 'shift+/', function(){ $('#helpmodal').modal('toggle'); return false; });
  $('body').bind('keydown', 'j',       function(){ location.href = document.hledgerWebBaseurl+'/journal'; return false; });
  $('body').bind('keydown', 's',       function(){ sidebarToggle(); return false; });
  $('body').bind('keydown', 'e',       function(){ emptyAccountsToggle(); return false; });
  $('body').bind('keydown', 'a',       function(){ addformShow(); return false; });
  $('body').bind('keydown', 'n',       function(){ addformShow(); return false; });
  $('body').bind('keydown', 'f',       function(){ $('#searchform input').focus(); return false; });

  // highlight the entry from the url hash
  if (window.location.hash && $(window.location.hash)[0]) {
    $(window.location.hash).addClass('highlighted');
  }
  $(window).on('hashchange', function() {
    $('.highlighted').removeClass('highlighted');
    $(window.location.hash).addClass('highlighted');
  });
  $('[data-toggle="offcanvas"]').click(function () {
      $('.row-offcanvas').toggleClass('active');
  });
});

//----------------------------------------------------------------------
// ADD FORM

function addformShow(showmsg) {
  showmsg = typeof showmsg !== 'undefined' ? showmsg : false;
  addformReset(showmsg);
  $('#addmodal').modal('show');
}

// Make sure the add form is empty and clean and has the default number of rows.
function addformReset(showmsg) {
  showmsg = typeof showmsg !== 'undefined' ? showmsg : false;
  if ($('form#addform').length > 0) {
    if (!showmsg) $('div#message').html('');
    $('#addform .account-group.added-row').remove();
    addformLastAmountBindKey();
    $('#addform')[0].reset();
    // reset typehead state (though not fetched completions)
    $('.typeahead').typeahead('val', '');
    $('.tt-dropdown-menu').hide();
  }
}

// Set the add-new-row-on-keypress handler on the add form's current last amount field, only.
// (NB: removes all other keypress handlers from all amount fields).
function addformLastAmountBindKey() {
  $('input[name=amount]').off('keypress');
  $('input[name=amount]:last').keypress(addformAddPosting);
}

// Pre-fill today's date and focus the description field in the add form.
function addformFocus() {
  $('#addform input[name=date]').val(isoDate());
  focus($('#addform input[name=description]'));
}

function isoDate() {
  return new Date().toLocaleDateString("sv");  // https://stackoverflow.com/a/58633651/84401
}

// Focus a jquery-wrapped element, working around http://stackoverflow.com/a/7046837.
function focus($el) {
  setTimeout(function (){
    $el.focus();
  }, 0);
}

// Insert another posting row in the add form.
function addformAddPosting() {
  if (!$('#addform').is(':visible')) { return; }

  // Clone the last row.
  var newrow = $('#addform .account-group:last').clone().addClass('added-row');
  var newnum = $('#addform .account-group').length + 1;

  // Clear the new account and amount fields and update their placeholder text.
  var accountfield = newrow.find('input[name=account]');
  var amountfield  = newrow.find('input[name=amount]');
  accountfield.val('').prop('placeholder', 'Account '+newnum);
  amountfield.val('').prop('placeholder', 'Amount '+newnum);

  // Enable autocomplete in the new account field.
  // We must first remove these typehead helper elements cloned from the old row,
  // or it will recursively add helper elements for those, causing confusion (#2215).
  newrow.find('.tt-hint').remove();
  newrow.find('.tt-input').removeClass('tt-input');
  accountfield.typeahead({ highlight: true }, { source: globalThis.accountsCompleter.ttAdapter() });

  // Add the new row to the page.
  $('#addform .account-postings').append(newrow);

  // And move the keypress handler to the new last amount field.
  addformLastAmountBindKey();
}

// Remove the add form's last posting row, if empty, keeping at least two.
function addformDeletePosting() {
  if ($('#addform .account-group').length <= 2) {
    return;
  }
  // remember if the last row's field or button had focus
  var focuslost =
    $('.account-input:last').is(':focus')
    || $('.amount-input:last').is(':focus');
  // delete last row
  $('#addform .account-group:last').remove();
  if (focuslost) {
    focus($('.account-input:last'));
  }
  // move the keypress handler to the new last amount field
  addformLastAmountBindKey();
}

//----------------------------------------------------------------------
// SIDEBAR

function sidebarToggle() {
  $('#sidebar-menu').toggleClass('col-md-4 col-sm-4 col-any-0');
  $('#main-content').toggleClass('col-md-8 col-sm-8 col-md-12 col-sm-12');
  $('#spacer').toggleClass('col-md-4 col-sm-4 col-any-0');
  $.cookie('showsidebar', $('#sidebar-menu').hasClass('col-any-0') ? '0' : '1');
}

function emptyAccountsToggle() {
  $('.acct.empty').parent().toggleClass('hide');
  $.cookie('hideemptyaccts', $.cookie('hideemptyaccts') === '1' ? '0' : '1')
}