diff --git a/src/html/api/entry.php b/src/html/api/entry.php index 95ef2cf..16501ad 100644 --- a/src/html/api/entry.php +++ b/src/html/api/entry.php @@ -36,16 +36,16 @@ class EntryAPI extends RestAPI { $connection=$this->get_db_connection(); if($entry['id'] != null) { - $statement=$connection->prepare("update entry set value_date=:value_date, operation_date=:operation_date, label=:label, value=:value, account_id=:account, category=:category where id=:id"); + $statement=$connection->prepare("update entry set value_date=:value_date, operation_date=:operation_date, label=:label, value=:value, account_id=:account_id, category=:category where id=:id"); } else { - $statement=$connection->prepare("insert into entry (value_date, operation_date, label, value, account_id, category) values (:value_date, :operation_date, :label, :value, :account, :category)"); + $statement=$connection->prepare("insert into entry (value_date, operation_date, label, value, account_id, category) values (:value_date, :operation_date, :label, :value, :account_id, :category)"); } $statement->bindParam("value_date", $entry['value_date']); $statement->bindParam("operation_date", $entry['operation_date'] == '' ? null : $entry['operation_date']); $statement->bindParam("label", $entry['label']); $statement->bindParam("value", $entry['value']); - $statement->bindParam("account", $entry['account']); + $statement->bindParam("account_id", $entry['account_id']); $statement->bindParam("id", $entry['id']); $statement->bindParam("category", $entry['category']); diff --git a/src/html/datepicker/css/datepicker.css b/src/html/datepicker/css/datepicker.css index bd9b6b9..f9cf497 100644 --- a/src/html/datepicker/css/datepicker.css +++ b/src/html/datepicker/css/datepicker.css @@ -1,7 +1,158 @@ - /* - Datepicker for Bootstrap - Copyright 2012 Stefan Petre - Licensed under the Apache License v2.0 - http://www.apache.org/licenses/LICENSE-2.0 +/*! +* Datepicker for Bootstrap +* +* Original Idea: http://www.eyecon.ro/bootstrap-datepicker (Copyright 2012 Stefan Petre) +* Updated by AymKdn (http://kodono.info - https://github.com/Aymkdn/Datepicker-for-Bootstrap) +* Licensed under the Apache License v2.0 +* http://www.apache.org/licenses/LICENSE-2.0 +* */ - .datepicker { top: 0; left: 0; padding: 4px; margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; /*.dow { border-top: 1px solid #ddd !important; }*/ } .datepicker:before { content: ''; display: inline-block; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 6px; } .datepicker:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 7px; } .datepicker > div { display: none; } .datepicker table { width: 100%; margin: 0; } .datepicker td, .datepicker th { text-align: center; width: 20px; height: 20px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td.day:hover { background: #eeeeee; cursor: pointer; } .datepicker td.old, .datepicker td.new { color: #999999; } .datepicker td.active, .datepicker td.active:hover { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td.active:hover, .datepicker td.active:hover:hover, .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active, .datepicker td.active.disabled, .datepicker td.active:hover.disabled, .datepicker td.active[disabled], .datepicker td.active:hover[disabled] { background-color: #0044cc; } .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active { background-color: #003399 \9; } .datepicker td span { display: block; width: 47px; height: 54px; line-height: 54px; float: left; margin: 2px; cursor: pointer; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td span:hover { background: #eeeeee; } .datepicker td span.active { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td span.active:hover, .datepicker td span.active:active, .datepicker td span.active.active, .datepicker td span.active.disabled, .datepicker td span.active[disabled] { background-color: #0044cc; } .datepicker td span.active:active, .datepicker td span.active.active { background-color: #003399 \9; } .datepicker td span.old { color: #999999; } .datepicker th.switch { width: 145px; } .datepicker th.next, .datepicker th.prev { font-size: 19.5px; } .datepicker thead tr:first-child th { cursor: pointer; } .datepicker thead tr:first-child th:hover { background: #eeeeee; } .input-append.date .add-on i, .input-prepend.date .add-on i { display: block; cursor: pointer; width: 16px; height: 16px; } \ No newline at end of file +.datepicker { +top: 0; +left: 0; +padding: 4px; +margin-top: 1px; +-webkit-border-radius: 4px; +-moz-border-radius: 4px; +border-radius: 4px; +/*.dow { +border-top: 1px solid #ddd !important; +}*/ +} +.datepicker:before { +content: ''; +display: inline-block; +border-left: 7px solid transparent; +border-right: 7px solid transparent; +border-bottom: 7px solid #ccc; +border-bottom-color: rgba(0, 0, 0, 0.2); +position: absolute; +top: -7px; +left: 6px; +} +.datepicker:after { +content: ''; +display: inline-block; +border-left: 6px solid transparent; +border-right: 6px solid transparent; +border-bottom: 6px solid #ffffff; +position: absolute; +top: -6px; +left: 7px; +} +.datepicker > div { +display: none; +} +.datepicker table { +width: 100%; +margin: 0; +} +.datepicker td, .datepicker th { +text-align: center; +width: 20px; +height: 20px; +-webkit-border-radius: 4px; +-moz-border-radius: 4px; +border-radius: 4px; +} +.datepicker td.day:hover { +background: #eeeeee; +cursor: pointer; +} +.datepicker td.old, .datepicker td.new { +color: #999999; +} +.datepicker td.active, .datepicker td.active:hover { +background-color: #006dcc; +background-image: -moz-linear-gradient(top, #0088cc, #0044cc); +background-image: -ms-linear-gradient(top, #0088cc, #0044cc); +background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); +background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); +background-image: -o-linear-gradient(top, #0088cc, #0044cc); +background-image: linear-gradient(top, #0088cc, #0044cc); +background-repeat: repeat-x; +filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); +border-color: #0044cc #0044cc #002a80; +border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +color: #fff; +text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker td.active:hover, +.datepicker td.active:hover:hover, +.datepicker td.active:active, +.datepicker td.active:hover:active, +.datepicker td.active.active, +.datepicker td.active:hover.active, +.datepicker td.active.disabled, +.datepicker td.active:hover.disabled, +.datepicker td.active[disabled], +.datepicker td.active:hover[disabled] { +background-color: #0044cc; +} +.datepicker td.active:active, +.datepicker td.active:hover:active, +.datepicker td.active.active, +.datepicker td.active:hover.active { +background-color: #003399 \9; +} +.datepicker td span { +display: block; +width: 47px; +height: 54px; +line-height: 54px; +float: left; +margin: 2px; +cursor: pointer; +-webkit-border-radius: 4px; +-moz-border-radius: 4px; +border-radius: 4px; +} +.datepicker td span:hover { +background: #eeeeee; +} +.datepicker td span.active { +background-color: #006dcc; +background-image: -moz-linear-gradient(top, #0088cc, #0044cc); +background-image: -ms-linear-gradient(top, #0088cc, #0044cc); +background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); +background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); +background-image: -o-linear-gradient(top, #0088cc, #0044cc); +background-image: linear-gradient(top, #0088cc, #0044cc); +background-repeat: repeat-x; +filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); +border-color: #0044cc #0044cc #002a80; +border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +color: #fff; +text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker td span.active:hover, +.datepicker td span.active:active, +.datepicker td span.active.active, +.datepicker td span.active.disabled, +.datepicker td span.active[disabled] { +background-color: #0044cc; +} +.datepicker td span.active:active, .datepicker td span.active.active { +background-color: #003399 \9; +} +.datepicker td span.old { +color: #999999; +} +.datepicker th.switch { +width: 145px; +} +.datepicker thead tr:first-child th { +cursor: pointer; +} +.datepicker thead tr:first-child th:hover { +background: #eeeeee; +} +.input-append.date .add-on i, .input-prepend.date .add-on i { +display: block; +cursor: pointer; +width: 16px; +height: 16px; +} +.dropdown-menu.datepicker { max-width:220px } \ No newline at end of file diff --git a/src/html/datepicker/js/bootstrap-datepicker.js b/src/html/datepicker/js/bootstrap-datepicker.js index 8875ec1..b9fc641 100644 --- a/src/html/datepicker/js/bootstrap-datepicker.js +++ b/src/html/datepicker/js/bootstrap-datepicker.js @@ -1,8 +1,8 @@ -/* ========================================================= +/*! ========================================================= * bootstrap-datepicker.js - * http://www.eyecon.ro/bootstrap-datepicker + * Original Idea: http://www.eyecon.ro/bootstrap-datepicker (Copyright 2012 Stefan Petre) + * Updated by AymKdn (http://kodono.info - https://github.com/Aymkdn/Datepicker-for-Bootstrap) * ========================================================= - * Copyright 2012 Stefan Petre * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,59 +24,31 @@ var Datepicker = function(element, options){ this.element = $(element); this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); - this.picker = $(DPGlobal.template) - .appendTo('body') - .on({ - click: $.proxy(this.click, this), - mousedown: $.proxy(this.mousedown, this) - }); - this.isInput = this.element.is('input'); + this.picker = $(DPGlobal.template).appendTo('body').hide().on('mousedown.Datepicker',$.proxy(this.mousedown, this)).on('click.Datepicker',$.proxy(this.click, this)); + + this.isInput = this.element.is('input') || this.element.is('textarea'); this.component = this.element.is('.date') ? this.element.find('.add-on') : false; if (this.isInput) { this.element.on({ - focus: $.proxy(this.show, this), - blur: $.proxy(this.hide, this), - keyup: $.proxy(this.update, this) + "focus.Datepicker": $.proxy(this.show, this), + "click.Datepicker": $.proxy(this.show, this), + "blur.Datepicker": $.proxy(this.blur, this), + "keyup.Datepicker": $.proxy(this.update, this), + "keydown.Datepicker": $.proxy(this.keydown, this) }); } else { if (this.component){ - this.component.on('click', $.proxy(this.show, this)); + this.component.on('click.Datepicker', $.proxy(this.show, this)); } else { - this.element.on('click', $.proxy(this.show, this)); + this.element.on('click.Datepicker', $.proxy(this.show, this)); } } - this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; - if (typeof this.minViewMode === 'string') { - switch (this.minViewMode) { - case 'months': - this.minViewMode = 1; - break; - case 'years': - this.minViewMode = 2; - break; - default: - this.minViewMode = 0; - break; - } - } - this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; - if (typeof this.viewMode === 'string') { - switch (this.viewMode) { - case 'months': - this.viewMode = 1; - break; - case 'years': - this.viewMode = 2; - break; - default: - this.viewMode = 0; - break; - } - } - this.startViewMode = this.viewMode; + + this.viewMode = 0; this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; - this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; + this.scroll = (options.scroll != undefined ? options.scroll : true); + this.weekEnd = this.weekStart == 0 ? 6 : this.weekStart - 1; this.fillDow(); this.fillMonths(); this.update(); @@ -87,39 +59,34 @@ constructor: Datepicker, show: function(e) { + $('div.datepicker.dropdown-menu').hide(); //make sure to hide all other calendars this.picker.show(); this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); this.place(); - $(window).on('resize', $.proxy(this.place, this)); - if (e ) { + $(window).on('resize.Datepicker', $.proxy(this.place, this)); + $('body').on('click.Datepicker', $.proxy(this.hide, this)); + if (e) { e.stopPropagation(); e.preventDefault(); } if (!this.isInput) { - $(document).on('mousedown', $.proxy(this.hide, this)); + $(document).on('mousedown.Datepicker', $.proxy(this.hide, this)); } this.element.trigger({ type: 'show', date: this.date }); + // make sure we see the datepicker + var elem = this.picker; + var docScrollTop = $(document).scrollTop(); + var winHeight = $(window).height(); + var elemTop = elem.position().top; + var elemHeight = elem.height(); + if (this.scroll && docScrollTop+winHeight'); } clsName = ''; @@ -204,11 +161,11 @@ } else if (prevMonth.getMonth() > month) { clsName += ' new'; } - if (prevMonth.valueOf() === currentDate) { + if (prevMonth.valueOf() == currentDate) { clsName += ' active'; } html.push(''+prevMonth.getDate() + ''); - if (prevMonth.getDay() === this.weekEnd) { + if (prevMonth.getDay() == this.weekEnd) { html.push(''); } prevMonth.setDate(prevMonth.getDate()+1); @@ -221,7 +178,7 @@ .text(year) .end() .find('span').removeClass('active'); - if (currentYear === year) { + if (currentYear == year) { months.eq(this.date.getMonth()).addClass('active'); } @@ -234,17 +191,34 @@ .find('td'); year -= 1; for (var i = -1; i < 11; i++) { - html += ''+year+''; + html += ''+year+''; year += 1; } yearCont.html(html); }, - click: function(e) { + blur:function(e) { + }, + + hide: function(e){ + this.picker.hide(); + $(window).off('resize.Datepicker', this.place); + this.viewMode = 0; + this.showMode(); + if (!this.isInput) { + $(document).off('mousedown.Datepicker', this.hide); + } + $('body').off('click.Datepicker',$.proxy(this.click, this)); + }, + click:function(e) { + e.stopPropagation(); + e.preventDefault(); + }, + mousedown: function(e) { e.stopPropagation(); e.preventDefault(); var target = $(e.target).closest('span, td, th'); - if (target.length === 1) { + if (target.length == 1) { switch(target[0].nodeName.toLowerCase()) { case 'th': switch(target[0].className) { @@ -256,10 +230,9 @@ this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( this.viewDate, this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + - DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) + DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1) ); this.fill(); - this.set(); break; } break; @@ -271,17 +244,8 @@ var year = parseInt(target.text(), 10)||0; this.viewDate.setFullYear(year); } - if (this.viewMode !== 0) { - this.date = new Date(this.viewDate); - this.element.trigger({ - type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName - }); - } this.showMode(-1); this.fill(); - this.set(); break; case 'td': if (target.is('.day')){ @@ -294,42 +258,43 @@ } var year = this.viewDate.getFullYear(); this.date = new Date(year, month, day,0,0,0,0); - this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); + this.viewDate = new Date(year, month, day,0,0,0,0); this.fill(); - this.set(); + this.setValue(); this.element.trigger({ type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName + date: this.date }); + this.hide(); } break; } } }, - - mousedown: function(e){ - e.stopPropagation(); - e.preventDefault(); - }, - + keydown:function(e) { + var keyCode = e.keyCode || e.which; + if (keyCode == 9) this.hide(); // when hiting TAB, for accessibility + }, + showMode: function(dir) { if (dir) { - this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); + this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir)); } this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - } + }, + + destroy: function() { this.element.removeData("datepicker").off(".Datepicker"); this.picker.remove() } }; - $.fn.datepicker = function ( option, val ) { + $.fn.datepicker = function ( option ) { return this.each(function () { var $this = $(this), data = $this.data('datepicker'), - options = typeof option === 'object' && option; + options = typeof option == 'object' && option; if (!data) { $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); } - if (typeof option === 'string') data[option](val); + if (typeof option == 'string') data[option](); }); }; @@ -368,22 +333,20 @@ return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] }, parseFormat: function(format){ - var separator = format.match(/[.\/\-\s].*?/), + var separator = format.match(/[.\/-].*?/), parts = format.split(/\W+/); - if (!separator || !parts || parts.length === 0){ + if (!separator || !parts || parts.length == 0){ throw new Error("Invalid date format."); } return {separator: separator, parts: parts}; }, parseDate: function(date, format) { + var today=new Date(); + if (!date) date=""; var parts = date.split(format.separator), - date = new Date(), + date = new Date(today.getFullYear(),today.getMonth(),today.getDate(),0,0,0), val; - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - if (parts.length === format.parts.length) { + if (parts.length == format.parts.length) { for (var i=0, cnt = format.parts.length; i < cnt; i++) { val = parseInt(parts[i], 10)||1; switch(format.parts[i]) { @@ -423,9 +386,9 @@ }, headTemplate: ''+ ''+ - '‹'+ + ''+ ''+ - '›'+ + ''+ ''+ '', contTemplate: '' diff --git a/src/html/index.html b/src/html/index.html index 4167fc6..3421ffa 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -103,12 +103,12 @@ + + + @@ -147,6 +150,7 @@ + diff --git a/src/html/js/date.js b/src/html/js/date.js new file mode 100644 index 0000000..c014a21 --- /dev/null +++ b/src/html/js/date.js @@ -0,0 +1,69 @@ +// a global month names array +var gsMonthNames = new Array( +'January', +'February', +'March', +'April', +'May', +'June', +'July', +'August', +'September', +'October', +'November', +'December' +); +// a global day names array +var gsDayNames = new Array( +'Sunday', +'Monday', +'Tuesday', +'Wednesday', +'Thursday', +'Friday', +'Saturday' +); + +// VB-like string replicator +String.prototype.times = function(n) +{ + var s = ''; + for (var i = 0; i < n; i++) + s += this; + + return s; +} + +// Zero-Padding +String.prototype.zp = function(n) { return '0'.times(n - this.length) + this; } +Number.prototype.zp = function(n) { thisStr = this.toString(); return '0'.times(n - thisStr.length) + thisStr; } + +// the date format prototype +Date.prototype.format = function(f) +{ + if (!this.valueOf()) + return ' '; + + var d = this; + + return f.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi, + function($1) + { + switch ($1.toLowerCase()) + { + case 'yyyy': return d.getFullYear(); + case 'mmmm': return gsMonthNames[d.getMonth()]; + case 'mmm': return gsMonthNames[d.getMonth()].substr(0, 3); + case 'mm': return (d.getMonth() + 1).zp(2); + case 'dddd': return gsDayNames[d.getDay()]; + case 'ddd': return gsDayNames[d.getDay()].substr(0, 3); + case 'dd': return d.getDate().zp(2); + case 'hh': return ((h = d.getHours() % 12) ? h : 12).zp(2); + case 'nn': return d.getMinutes().zp(2); + case 'ss': return d.getSeconds().zp(2); + case 'a/p': return d.getHours() < 12 ? 'a' : 'p'; + } + } + ); +} + diff --git a/src/html/js/entries.js b/src/html/js/entries.js index 02942be..71e18d8 100644 --- a/src/html/js/entries.js +++ b/src/html/js/entries.js @@ -5,9 +5,9 @@ function entry(data){ this.operation_date=ko.observable(ko.utils.unwrapObservable(data.operation_date)); this.label=ko.observable(ko.utils.unwrapObservable(data.label)); this.value=ko.observable(ko.utils.unwrapObservable(data.value)); - this.account=ko.observable(ko.utils.unwrapObservable(data.account)); + this.account_id=ko.observable(ko.utils.unwrapObservable(data.account_id)); this.sold=ko.observable(ko.utils.unwrapObservable(data.sold)); - this.pointedSold=ko.observable(ko.utils.unwrapObservable(data.pointedSold)); + this.pointedsold=ko.observable(ko.utils.unwrapObservable(data.pointedsold)); this.category=ko.observable(ko.utils.unwrapObservable(data.category)); } @@ -31,8 +31,10 @@ var ListViewModel = function() { // Entry store and selection self.entries = ko.observableArray([]); self.selectedItem = ko.observable(); + // Placeholder for saved value to cancel entry edition - self.savedItem = ko.observable(); + self.savedItem = null; + // Placeholder for entry to remove to be available in modal function "yes" click callback self.itemToRemove = ko.observable(); @@ -125,22 +127,7 @@ var ListViewModel = function() { // Clean up selected entry. self.selectedItem(null); - var entries = []; - $.each(data, function(index, element) { - entries.push(new entry({ - id: element.id, - value_date: new Date(element.value_date), - operation_date: element.operation_date ? new Date(element.operation_date) : null, - label: element.label, - value: element.value, - account: element.account_id, - sold: element.sold, - pointedSold: element.operation_date ? element.pointedsold : '', - category: element.category - })); - }); - - self.entries(entries); + self.entries(ko.utils.arrayMap(data, ko.mapping.fromJS)); }); }; @@ -189,34 +176,32 @@ var ListViewModel = function() { }; self.edit = function(item) { - if(self.savedItem() != null) { + if(self.savedItem) { self.cancel(); } - self.savedItem(new entry(item)); + self.savedItem=ko.toJS(item); self.selectedItem(item); - $("#value_date").datepicker({format: "yyyy-mm-dd"}).on('changeDate', function(ev){ - self.selectedItem().value_date(new Date(ev.date.valueOf())); + console.debug(self.savedItem); + + $("#value_date").datepicker().on('changeDate', function(ev){ + self.selectedItem().value_date(ev.date.format(ev.currentTarget.dataset.dateFormat)); }); - $("#operation_date").datepicker({format: "yyyy-mm-dd"}).on('changeDate', function(ev){ - self.selectedItem().operation_date(new Date(ev.date.valueOf())); - }); - - $("#operation_date_clear").click(function(e){ - self.selectedItem().operation_date(null); + $("#operation_date").datepicker().on('changeDate', function(ev){ + self.selectedItem().operation_date(ev.date.format(ev.currentTarget.dataset.dateFormat)); }); }; self.cancel = function() { - if(self.selectedItem() && self.savedItem()) { - self.selectedItem().id(self.savedItem().id()); - self.selectedItem().operation_date(self.savedItem().operation_date()); - self.selectedItem().value_date(self.savedItem().value_date()); - self.selectedItem().label(self.savedItem().label()); - self.selectedItem().value(self.savedItem().value()); - self.selectedItem().account(self.savedItem().account()); + if(self.selectedItem() && self.savedItem) { + self.selectedItem().id(self.savedItem.id); // id should not change, but just in case... + self.selectedItem().operation_date(self.savedItem.operation_date); + self.selectedItem().value_date(self.savedItem.value_date); + self.selectedItem().label(self.savedItem.label); + self.selectedItem().value(self.savedItem.value); + self.selectedItem().account_id(self.savedItem.account_id); // account_id should not change, but just in case... } // This item was just added. @@ -224,46 +209,23 @@ var ListViewModel = function() { self.entries.remove(self.selectedItem()); } - self.savedItem(null); + self.savedItem = null; self.selectedItem(null); }; self.add = function() { - if(self.savedItem() != null) { - self.cancel(); - } - var newEntry = new entry({ - account: self.account().id + account_id: self.account().id }); self.entries.unshift(newEntry); - self.selectedItem(newEntry); - $("#value_date").datepicker({format: "yyyy-mm-dd"}).on('changeDate', function(ev){ - self.selectedItem().value_date(new Date(ev.date.valueOf())); - }); - - $("#operation_date").datepicker({format: "yyyy-mm-dd"}).on('changeDate', function(ev){ - self.selectedItem().operation_date(new Date(ev.date.valueOf())); - }); - - $("#operation_date_clear").click(function(e){ - self.selectedItem().operation_date(null); - }); + self.edit(newEntry); }; self.save = function() { var item = ko.toJS(self.selectedItem()); - if(item.value_date) { - item.value_date = dateToString(item.value_date); - } - - if(item.operation_date) { - item.operation_date = dateToString(item.operation_date); - } - $.post("api/entry.php", {action: "save_entry", entry:item}).success(function(data) { message("success", "Save", data.message); @@ -309,77 +271,6 @@ var ListViewModel = function() { }; }; -function dateToString(date) { - if(date) { - var year = date.getFullYear(); - var month = date.getMonth() + 1; - var day = date.getDate(); - - var dateStr = year + "-" + (month < 10 ? '0' : '') + month + "-" + (day < 10 ? '0' : '') + day; - - return dateStr;; - } else { - return ''; - } -}; - - -ko.bindingHandlers.date = { - init: function (element, valueAccessor, allBindingsAccessor, viewModel) { - var unwrap = ko.utils.unwrapObservable; - var dataSource = valueAccessor(); - - var value = dataSource ? unwrap(dataSource) : null; - - if(value) { - $(element).text(dateToString(value)); - } else { - $(element).text(''); - } - }, - - update: function (element, valueAccessor, allBindingsAccessor, viewModel) { - var unwrap = ko.utils.unwrapObservable; - var dataSource = valueAccessor(); - - var value = dataSource ? unwrap(dataSource) : null; - - if(value) { - $(element).text(dateToString(value)); - } else { - $(element).text(''); - } - } -}; - -ko.bindingHandlers.dateValue = { - init: function (element, valueAccessor, allBindingsAccessor, viewModel) { - var unwrap = ko.utils.unwrapObservable; - var dataSource = valueAccessor(); - - var value = dataSource ? unwrap(dataSource) : null; - - if(value) { - $(element).val(dateToString(value)); - } else { - $(element).val(''); - } - }, - - update: function (element, valueAccessor, allBindingsAccessor, viewModel) { - var unwrap = ko.utils.unwrapObservable; - var dataSource = valueAccessor(); - - var value = dataSource ? unwrap(dataSource) : null; - - if(value) { - $(element).val(dateToString(value)); - } else { - $(element).val(''); - } - } -}; - drawChart = function(entries, element) { // clear previous chart $(element).html(""); diff --git a/src/html/knockout/knockout-mapping.min.js b/src/html/knockout/knockout-mapping.min.js new file mode 100644 index 0000000..6566fdf --- /dev/null +++ b/src/html/knockout/knockout-mapping.min.js @@ -0,0 +1,21 @@ +/// Knockout Mapping plugin v2.3.5 +/// (c) 2012 Steven Sanderson, Roy Jacobs - http://knockoutjs.com/ +/// License: MIT (http://www.opensource.org/licenses/mit-license.php) +(function(e){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?e(require("knockout"),exports):"function"===typeof define&&define.amd?define(["knockout","exports"],e):e(ko,ko.mapping={})})(function(e,f){function x(b,c){var a,d;for(d in c)if(c.hasOwnProperty(d)&&c[d])if(a=f.getType(b[d]),d&&b[d]&&"array"!==a&&"string"!==a)x(b[d],c[d]);else if("array"===f.getType(b[d])&&"array"===f.getType(c[d])){a=b;for(var e=d,k=b[d],m=c[d],s={},g=k.length-1;0<=g;--g)s[k[g]]=k[g];for(g= +m.length-1;0<=g;--g)s[m[g]]=m[g];k=[];m=void 0;for(m in s)k.push(s[m]);a[e]=k}else b[d]=c[d]}function D(b,c){var a={};x(a,b);x(a,c);return a}function y(b,c){for(var a=D({},b),e=K.length-1;0<=e;e--){var f=K[e];a[f]&&(a[""]instanceof Object||(a[""]={}),a[""][f]=a[f],delete a[f])}c&&(a.ignore=h(c.ignore,a.ignore),a.include=h(c.include,a.include),a.copy=h(c.copy,a.copy),a.observe=h(c.observe,a.observe));a.ignore=h(a.ignore,i.ignore);a.include=h(a.include,i.include);a.copy=h(a.copy,i.copy);a.observe=h(a.observe, +i.observe);a.mappedProperties=a.mappedProperties||{};a.copiedProperties=a.copiedProperties||{};return a}function h(b,c){"array"!==f.getType(b)&&(b="undefined"===f.getType(b)?[]:[b]);"array"!==f.getType(c)&&(c="undefined"===f.getType(c)?[]:[c]);return e.utils.arrayGetDistinctValues(b.concat(c))}function E(b,c,a,d,j,k,m){var s="array"===f.getType(e.utils.unwrapObservable(c)),k=k||"";if(f.isMapped(b))var g=e.utils.unwrapObservable(b)[n],a=D(g,a);var i=m||j,h=function(){return a[d]&&a[d].create instanceof +Function},w=function(b){var f=F,g=e.dependentObservable;e.dependentObservable=function(a,b,c){c=c||{};a&&"object"==typeof a&&(c=a);var d=c.deferEvaluation,L=!1;c.deferEvaluation=!0;a=new G(a,b,c);if(!d){var g=a,d=e.dependentObservable;e.dependentObservable=G;a=e.isWriteableObservable(g);e.dependentObservable=d;a=G({read:function(){L||(e.utils.arrayRemoveItem(f,g),L=!0);return g.apply(g,arguments)},write:a&&function(a){return g(a)},deferEvaluation:!0});f.push(a)}return a};e.dependentObservable.fn= +G.fn;e.computed=e.dependentObservable;b=e.utils.unwrapObservable(j)instanceof Array?a[d].create({data:b||c,parent:i,skip:M}):a[d].create({data:b||c,parent:i});e.dependentObservable=g;e.computed=e.dependentObservable;return b},t=function(){return a[d]&&a[d].update instanceof Function},u=function(b,f){var g={data:f||c,parent:i,target:e.utils.unwrapObservable(b)};e.isWriteableObservable(b)&&(g.observable=b);return a[d].update(g)};if(m=H.get(c))return m;d=d||"";if(s){var s=[],r=!1,l=function(a){return a}; +a[d]&&a[d].key&&(l=a[d].key,r=!0);e.isObservable(b)||(b=e.observableArray([]),b.mappedRemove=function(a){var c="function"==typeof a?a:function(b){return b===l(a)};return b.remove(function(a){return c(l(a))})},b.mappedRemoveAll=function(a){var c=B(a,l);return b.remove(function(a){return-1!=e.utils.arrayIndexOf(c,l(a))})},b.mappedDestroy=function(a){var c="function"==typeof a?a:function(b){return b===l(a)};return b.destroy(function(a){return c(l(a))})},b.mappedDestroyAll=function(a){var c=B(a,l);return b.destroy(function(a){return-1!= +e.utils.arrayIndexOf(c,l(a))})},b.mappedIndexOf=function(a){var c=B(b(),l),a=l(a);return e.utils.arrayIndexOf(c,a)},b.mappedCreate=function(a){if(-1!==b.mappedIndexOf(a))throw Error("There already is an object with the key that you specified.");var c=h()?w(a):a;t()&&(a=u(c,a),e.isWriteableObservable(c)?c(a):c=a);b.push(c);return c});m=B(e.utils.unwrapObservable(b),l).sort();g=B(c,l);r&&g.sort();var r=e.utils.compareArrays(m,g),m={},I,z=e.utils.unwrapObservable(c),x={},y=!0,g=0;for(I=z.length;g