/* hledger web ui javascript */ //---------------------------------------------------------------------- // STARTUP $(document).ready(function() { // ensure add form always focusses its first field $('#addmodal') .on('shown.bs.modal', function (e) { addformFocus(); }) // show add form if ?add=1 if ($.url.param('add')) { addformShow(true); } // sidebar account hover handlers $('#sidebar td a').mouseenter(function(){ $(this).parent().addClass('mouseover'); }); $('#sidebar td').mouseleave(function(){ $(this).removeClass('mouseover'); }); // 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', 'a', function(){ addformShow(); return false; }); $('body').bind('keydown', 'n', function(){ addformShow(); return false; }); $('body').bind('keydown', 'f', function(){ $('#searchform input').focus(); return false; }); $('body, #addform input, #addform select').bind('keydown', 'ctrl+shift+=', addformAddPosting); $('body, #addform input, #addform select').bind('keydown', 'ctrl+=', addformAddPosting); $('body, #addform input, #addform select').bind('keydown', 'ctrl+-', addformDeletePosting); $('.amount-input:last').keypress(addformAddPosting); // highlight the entry from the url hash if (window.location.hash && $(window.location.hash)[0]) { $(window.location.hash).addClass('highlighted'); } $(window).on('hashchange', function(event) { $('.highlighted').removeClass('highlighted'); $(window.location.hash).addClass('highlighted'); }); }); //---------------------------------------------------------------------- // REGISTER CHART function registerChart($container, series) { // https://github.com/flot/flot/blob/master/API.md return $container.plot( series, { /* general chart options */ xaxis: { mode: "time", timeformat: "%Y/%m/%d" }, legend: { position: 'sw' }, grid: { markings: function (axes) { var now = Date.now(); var markings = [ { xaxis: { to: now }, // past yaxis: { to: 0 }, // <0 color: '#ffdddd', }, { xaxis: { from: now }, // future yaxis: { from: 0 }, // >0 color: '#e0e0e0', }, { xaxis: { from: now }, // future yaxis: { to: 0 }, // <0 color: '#e8c8c8', }, { yaxis: { from: 0, to: 0 }, // =0 color: '#bb0000', lineWidth:1 }, ]; return markings; }, hoverable: true, autoHighlight: true, clickable: true, }, /* https://github.com/krzysu/flot.tooltip */ tooltip: true, tooltipOpts: { xDateFormat: "%Y/%m/%d", content: function(label, x, y, flotitem) { var data = flotitem.series.data[flotitem.dataIndex]; return data[3]+" balance on %x after "+data[2]+" posted by transaction:
"+data[4]+"
"; }, onHover: function(flotitem, $tooltipel) { $tooltipel.css('border-color',flotitem.series.color); }, }, } ).data("plot"); } function registerChartClick(ev, pos, item) { if (item) { targetselector = '#'+item.series.data[item.dataIndex][5]; $target = $(targetselector); if ($target.length) { window.location.hash = targetselector; $('html, body').animate({ scrollTop: $target.offset().top }, 1000); } } } //---------------------------------------------------------------------- // 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 for display. function addformReset(showmsg) { showmsg = typeof showmsg !== 'undefined' ? showmsg : false; if ($('form#addform').length > 0) { if (!showmsg) $('div#message').html(''); $('form#addform')[0].reset(); // reset typehead state (though not fetched completions) $('.typeahead').typeahead('val', ''); $('.tt-dropdown-menu').hide(); $('input#date').val(''); // #322 don't set a default, typeahead(?) clears it on tab. See also Foundation.hs } } // Focus the first add form field. function addformFocus() { focus($('#addform input#date')); } // 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() { $('.amount-input:last').off('keypress'); // do nothing if it's not currently visible if (!$('#addform').is(':visible')) return; // save a copy of last row var lastrow = $('#addform .form-group:last').clone(); // replace the submit button with an amount field, clear and renumber it, add the keybindings var num = $('#addform .account-group').length; // insert the new last row $('#addform .account-postings').append(lastrow); // TODO: Enable typehead on dynamically created inputs var $acctinput = $('.account-input:last'); var $amntinput = $('.amount-input:last'); // clear and renumber the field, add keybindings $acctinput .val('') .prop('id','account'+(num+1)) .prop('name','account'+(num+1)) .prop('placeholder','Account '+(num+1)); //lastrow.find('input') // not :last this time $acctinput .bind('keydown', 'ctrl+shift+=', addformAddPosting) .bind('keydown', 'ctrl+=', addformAddPosting) .bind('keydown', 'ctrl+-', addformDeletePosting); $amntinput .val('') .prop('id','amount'+(num+1)) .prop('name','amount'+(num+1)) .prop('placeholder','Amount '+(num+1)) .keypress(addformAddPosting); $acctinput .bind('keydown', 'ctrl+shift+=', addformAddPosting) .bind('keydown', 'ctrl+=', addformAddPosting) .bind('keydown', 'ctrl+-', addformDeletePosting); } // Remove the add form's last posting row, if empty, keeping at least two. function addformDeletePosting() { var num = $('#addform .account-group').length; if (num <= 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')); } // Rebind keypress $('.amount-input:last').keypress(addformAddPosting); } //---------------------------------------------------------------------- // SIDEBAR function sidebarToggle() { var visible = $('#sidebar').is(':visible'); // if opening sidebar, start an ajax fetch of its content if (!visible) { $.get("sidebar" ,null ,function(data) { $("#sidebar-body" ).html(data); }) .fail(function() { alert("Loading the sidebar did fail"); }); } // set a cookie to communicate the new sidebar state to the server $.cookie('showsidebar', visible ? '0' : '1'); $('#sidebar').animate({'width': visible ? 'hide' : 'show'}); } //---------------------------------------------------------------------- // MISC function enableTypeahead($el, suggester) { return $el.typeahead( { highlight: true }, { source: suggester.ttAdapter() } ); } // function journalSelect(ev) { // var textareas = $('textarea', $('form#editform')); // for (i=0; i