Work on front-side UI.
* Resolved D0003: Add day separators. * Created ``daySeparatorTemplate`` for ICanHaz templating. * Refactored ``EntryListView.render`` to spit out day separators in between days on the timeline. Fixed the "Today" separator to the top of the entry container. We no longer prepend entries to the entry container, we now put them after the top separator in the entry container. * Created ``EntryListView.formatDaySeparator`` to format the labels according to the relative time to today: "Yesterday", "Last Monday", "Friday, May 28" for example. * Removed the cludgier ``toWords``, ``daysApart``, and `` capitalize`` functions that were going to serve the same purpose. * Resolved D0021: Constrain notes width to mark.
This commit is contained in:
parent
81503112a8
commit
f3ef7db088
@ -95,12 +95,12 @@ setlocal nowinfixwidth
|
|||||||
setlocal wrap
|
setlocal wrap
|
||||||
setlocal wrapmargin=0
|
setlocal wrapmargin=0
|
||||||
silent! normal! zE
|
silent! normal! zE
|
||||||
let s:l = 1 - ((0 * winheight(0) + 36) / 72)
|
let s:l = 104 - ((59 * winheight(0) + 35) / 71)
|
||||||
if s:l < 1 | let s:l = 1 | endif
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
exe s:l
|
exe s:l
|
||||||
normal! zt
|
normal! zt
|
||||||
1
|
104
|
||||||
normal! 0
|
normal! 038l
|
||||||
lcd /mnt/secure/projects/jdb-labs/timestamper/web-app/www
|
lcd /mnt/secure/projects/jdb-labs/timestamper/web-app/www
|
||||||
let &so = s:so_save | let &siso = s:siso_save
|
let &so = s:so_save | let &siso = s:siso_save
|
||||||
doautoall SessionLoadPost
|
doautoall SessionLoadPost
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0
|
let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0
|
||||||
argglobal
|
argglobal
|
||||||
edit ~/projects/jdb-labs/timestamper/web-app/www/css/ts-screen.scss
|
edit /mnt/secure/projects/jdb-labs/timestamper/web-app/www/css/ts-screen.scss
|
||||||
setlocal keymap=
|
setlocal keymap=
|
||||||
setlocal noarabic
|
setlocal noarabic
|
||||||
setlocal autoindent
|
setlocal autoindent
|
||||||
@ -26,8 +26,8 @@ setlocal nodiff
|
|||||||
setlocal equalprg=
|
setlocal equalprg=
|
||||||
setlocal errorformat=
|
setlocal errorformat=
|
||||||
setlocal expandtab
|
setlocal expandtab
|
||||||
if &filetype != 'scss'
|
if &filetype != ''
|
||||||
setlocal filetype=scss
|
setlocal filetype=
|
||||||
endif
|
endif
|
||||||
setlocal foldcolumn=0
|
setlocal foldcolumn=0
|
||||||
setlocal foldenable
|
setlocal foldenable
|
||||||
@ -83,8 +83,8 @@ setlocal statusline=
|
|||||||
setlocal suffixesadd=
|
setlocal suffixesadd=
|
||||||
setlocal swapfile
|
setlocal swapfile
|
||||||
setlocal synmaxcol=3000
|
setlocal synmaxcol=3000
|
||||||
if &syntax != 'scss'
|
if &syntax != 'sass'
|
||||||
setlocal syntax=scss
|
setlocal syntax=sass
|
||||||
endif
|
endif
|
||||||
setlocal tabstop=4
|
setlocal tabstop=4
|
||||||
setlocal tags=
|
setlocal tags=
|
||||||
@ -95,12 +95,12 @@ setlocal nowinfixwidth
|
|||||||
setlocal wrap
|
setlocal wrap
|
||||||
setlocal wrapmargin=0
|
setlocal wrapmargin=0
|
||||||
silent! normal! zE
|
silent! normal! zE
|
||||||
let s:l = 120 - ((39 * winheight(0) + 23) / 46)
|
let s:l = 392 - ((46 * winheight(0) + 35) / 71)
|
||||||
if s:l < 1 | let s:l = 1 | endif
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
exe s:l
|
exe s:l
|
||||||
normal! zt
|
normal! zt
|
||||||
120
|
392
|
||||||
normal! 012l
|
normal! 022l
|
||||||
let &so = s:so_save | let &siso = s:siso_save
|
let &so = s:so_save | let &siso = s:siso_save
|
||||||
doautoall SessionLoadPost
|
doautoall SessionLoadPost
|
||||||
" vim: set ft=vim :
|
" vim: set ft=vim :
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
db/test/id_counter.DCL
Normal file
BIN
db/test/id_counter.DCL
Normal file
Binary file not shown.
Binary file not shown.
BIN
db/test/ts_entry.DCL
Normal file
BIN
db/test/ts_entry.DCL
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,7 +4,12 @@ Generate day seperators.
|
|||||||
When generating EventViews in the EventListView, we need to automatically
|
When generating EventViews in the EventListView, we need to automatically
|
||||||
create and insert day seperators (see prototype).
|
create and insert day seperators (see prototype).
|
||||||
|
|
||||||
|
Resolution
|
||||||
|
----------
|
||||||
|
|
||||||
|
Day separators are added to the timeline by EntryListView.render.
|
||||||
|
|
||||||
========= ==========
|
========= ==========
|
||||||
Created: 2011-05-15
|
Created: 2011-05-15
|
||||||
Resolved: YYYY-MM-DD
|
Resolved: 2011-05-17
|
||||||
========= ==========
|
========= ==========
|
@ -2,6 +2,9 @@ Implement correct start time editor.
|
|||||||
====================================
|
====================================
|
||||||
|
|
||||||
The start time input field needs to look the same as the start time view.
|
The start time input field needs to look the same as the start time view.
|
||||||
|
Alternatively, use a date picker.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
========= ==========
|
========= ==========
|
||||||
Created: 2011-05-15
|
Created: 2011-05-15
|
||||||
|
@ -3,5 +3,5 @@ Constrain width of notes fields to width of mark.
|
|||||||
|
|
||||||
========= ==========
|
========= ==========
|
||||||
Created: 2011-06-10
|
Created: 2011-06-10
|
||||||
Resolved: YYYY-MM-DD
|
Resolved: 2011-06-17
|
||||||
====================
|
====================
|
@ -4,6 +4,8 @@ Deleting an entry should cascade delete extended data.
|
|||||||
Currently the data remains in the database. It should not cause any
|
Currently the data remains in the database. It should not cause any
|
||||||
problems, but it is wasting space.
|
problems, but it is wasting space.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
========= ==========
|
========= ==========
|
||||||
Created: 2011-06-15
|
Created: 2011-06-15
|
||||||
Resolved: YYYY-MM-DD
|
Resolved: YYYY-MM-DD
|
||||||
|
11
doc/issues/desktop/0024tn5.rst
Normal file
11
doc/issues/desktop/0024tn5.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Hide day separators when all entries that day are excluded.
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
We should hide headings when there is no visible data.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
========= ==========
|
||||||
|
Created: 2011-06-17
|
||||||
|
Resolved: YYYY-MM-DD
|
||||||
|
========= ==========
|
21
doc/issues/desktop/0025tn5.rst
Normal file
21
doc/issues/desktop/0025tn5.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Never animate excluded entries.
|
||||||
|
===============================
|
||||||
|
|
||||||
|
We need to have some visible indication when a user enters an
|
||||||
|
exlucded item that it was added, but it looks ugly and dirty when
|
||||||
|
we first render the list.
|
||||||
|
|
||||||
|
Part of this is motivated by the fact that entering an excluded
|
||||||
|
entry is the excpected way for a user to stop the timer on an item
|
||||||
|
without having an explicit next item.
|
||||||
|
|
||||||
|
If we choose to implement *D0026* this would free up the UI a bit.
|
||||||
|
In that case, we could gently flash the 'Show/Hide Excluded Items'
|
||||||
|
button (*D0027*).
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
========= ==========
|
||||||
|
Created: 2011-06-17
|
||||||
|
Resolved: YYYY-MM-DD
|
||||||
|
========= ==========
|
16
doc/issues/desktop/0026fn4.rst
Normal file
16
doc/issues/desktop/0026fn4.rst
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Add a default 'stop' behaviour.
|
||||||
|
===============================
|
||||||
|
|
||||||
|
It might be more natural to allow the user to hit a button on
|
||||||
|
the current entry to stop the timer on it than to explicitly
|
||||||
|
create a new excluded entry.
|
||||||
|
|
||||||
|
Maybe have a default exclusion for all users, "ENTRY STOP" for example,
|
||||||
|
and have the button automatically add this entry.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
========= ==========
|
||||||
|
Created: 2011-06-17
|
||||||
|
Resolved: YYYY-MM-DD
|
||||||
|
========= ==========
|
12
doc/issues/desktop/0027fn4.rst
Normal file
12
doc/issues/desktop/0027fn4.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Create a way to unhide excluded entries.
|
||||||
|
========================================
|
||||||
|
|
||||||
|
A button somewhere would be a good way to allow users to
|
||||||
|
show/hide excluded entries.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
========= ==========
|
||||||
|
Created: 2011-06-17
|
||||||
|
Resolved: YYYY-MM-DD
|
||||||
|
========= ==========
|
@ -297,7 +297,8 @@ input {
|
|||||||
font-family: Cantarell;
|
font-family: Cantarell;
|
||||||
font-size: small;
|
font-size: small;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0 0 1em; }
|
padding: 0 0 0 1em;
|
||||||
|
width: 70%; }
|
||||||
#entry-list .entry .notes :first-child {
|
#entry-list .entry .notes :first-child {
|
||||||
margin-top: 0; }
|
margin-top: 0; }
|
||||||
#entry-list .entry .notes .notes-input, #entry-list .entry .notes pre, #entry-list .entry .notes code {
|
#entry-list .entry .notes .notes-input, #entry-list .entry .notes pre, #entry-list .entry .notes code {
|
||||||
|
@ -389,6 +389,7 @@ input {
|
|||||||
font-size: small;
|
font-size: small;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0 0 1em;
|
padding: 0 0 0 1em;
|
||||||
|
width: 70%;
|
||||||
|
|
||||||
:first-child { margin-top: 0; }
|
:first-child { margin-top: 0; }
|
||||||
|
|
||||||
|
@ -99,6 +99,14 @@ out(YArg) ->
|
|||||||
<textarea class="notes-input" rows="10">{{notes}}</textarea>
|
<textarea class="notes-input" rows="10">{{notes}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
<script type="text/html" id="daySeparatorTemplate">
|
||||||
|
<div class="day-seperator">
|
||||||
|
<h4 class="mark">{{separatorLabel}}</h4>
|
||||||
|
<h5 class="timestamp">start</h5>
|
||||||
|
<h5 class="duration">duration</h5>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -145,11 +153,6 @@ out(YArg) ->
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="entry-list">
|
<div id="entry-list">
|
||||||
<div class="day-seperator">
|
|
||||||
<h4 class="mark">Today</h4>
|
|
||||||
<h5 class="timestamp">start</h5>
|
|
||||||
<h5 class="duration">duration</h5>
|
|
||||||
</div>
|
|
||||||
<div id="new-entry">
|
<div id="new-entry">
|
||||||
<input id="new-entry-input" class="mark-input"
|
<input id="new-entry-input" class="mark-input"
|
||||||
placeholder="Start a new task..." type="text" />
|
placeholder="Start a new task..." type="text" />
|
||||||
|
116
www/js/ts.js
116
www/js/ts.js
@ -355,8 +355,8 @@ $(document).ready(function(){
|
|||||||
// render the element
|
// render the element
|
||||||
var el = entry.view.render().el;
|
var el = entry.view.render().el;
|
||||||
|
|
||||||
// add it to the container
|
// add it to the container after the topmost separator ("Today")
|
||||||
this.entryContainer.prepend(el);
|
this.topSeparator.after(el);
|
||||||
|
|
||||||
// hide it if excluded
|
// hide it if excluded
|
||||||
if (excluded) {
|
if (excluded) {
|
||||||
@ -401,21 +401,67 @@ $(document).ready(function(){
|
|||||||
this.entryContainer.empty();
|
this.entryContainer.empty();
|
||||||
|
|
||||||
// last day we have printed a separator for
|
// last day we have printed a separator for
|
||||||
var currentDay = null;
|
var today = new Date()
|
||||||
var today = new Date();
|
var currentDay = this.collection.at(0) ?
|
||||||
|
this.collection.at(0).get("timestamp"): today;
|
||||||
|
|
||||||
|
// add the top-most day separator
|
||||||
|
this.topSeparator = ich.daySeparatorTemplate({
|
||||||
|
separatorLabel: this.formatDaySeparator(today, today) });
|
||||||
|
this.entryContainer.prepend(this.topSeparator);
|
||||||
|
|
||||||
// iterate through the collection and render the elements.
|
// iterate through the collection and render the elements.
|
||||||
for (var i = 0, len = this.collection.length; i < len; i++) {
|
for (var i = 0, len = this.collection.length; i < len; i++) {
|
||||||
var entry = this.collection.at(i);
|
var entry = this.collection.at(i);
|
||||||
var nextEntry = (i + 1 < len ? this.collection.at(i + 1) : null);
|
var nextEntry = (i + 1 < len ? this.collection.at(i + 1) : null);
|
||||||
|
|
||||||
if (currentDay != entry.get('timestamp').getDate()) {
|
// we are rendering buttom up, which means we need to insert the
|
||||||
currentDay = entry.get('timestamp').getDate();
|
// day separator before the first entry of the *next* period
|
||||||
|
if (currentDay.getDate() != entry.get("timestamp").getDate()) {
|
||||||
|
this.topSeparator.after(ich.daySeparatorTemplate(
|
||||||
|
{separatorLabel: this.formatDaySeparator(today, currentDay)}));
|
||||||
|
currentDay = entry.get('timestamp');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderOne(entry, nextEntry);
|
this.renderOne(entry, nextEntry);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDaySeparator: function(today, labelDay) {
|
||||||
|
|
||||||
|
var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
|
||||||
|
'Friday', 'Saturday'];
|
||||||
|
var months = ['January', 'February', 'March', 'April', 'May',
|
||||||
|
'June', 'July', 'August', 'September', 'October',
|
||||||
|
'November', 'December'];
|
||||||
|
|
||||||
|
var yearDiff = today.getFullYear() - labelDay.getFullYear();
|
||||||
|
var monthDiff = today.getMonth() - labelDay.getMonth();
|
||||||
|
var dayDiff = today.getDate() - labelDay.getDate();
|
||||||
|
|
||||||
|
// more than a calendar year old
|
||||||
|
if (yearDiff > 0) {
|
||||||
|
|
||||||
|
return days[labelDay.getDay()] + ", " +
|
||||||
|
months[labelDay.getMonth()] + " " + labelDay.getDate() +
|
||||||
|
", " + labelDay.getFullYear(); }
|
||||||
|
|
||||||
|
// same calendar year, more than a week ago
|
||||||
|
else if (monthDiff > 0 || dayDiff > 7) {
|
||||||
|
|
||||||
|
return days[labelDay.getDay()] + ", " +
|
||||||
|
months[labelDay.getMonth()] + " " + labelDay.getDate(); }
|
||||||
|
|
||||||
|
// less than a week ago, more than yesterday
|
||||||
|
else if (dayDiff > 1) {
|
||||||
|
return "Last " + days[labelDay.getDay()]; }
|
||||||
|
|
||||||
|
// yesterday
|
||||||
|
else if (dayDiff == 1) { return "Yesterday"; }
|
||||||
|
|
||||||
|
// today
|
||||||
|
else if (dayDiff == 0) { return "Today"; }
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -757,59 +803,3 @@ function dateToJSON(d) {
|
|||||||
+ pad(d.getUTCMinutes())+':'
|
+ pad(d.getUTCMinutes())+':'
|
||||||
+ pad(d.getUTCSeconds())+'Z';
|
+ pad(d.getUTCSeconds())+'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
function daysApart(d1, d2) {
|
|
||||||
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
|
|
||||||
|
|
||||||
days1 = (d1.getFullYear() * 365) + daysInMonth[d1.getMonth()] + d1.getDate();
|
|
||||||
days2 = (d2.getFullYear() * 365) + daysInMonth[d2.getMonth()] + d2.getDate();
|
|
||||||
|
|
||||||
return days1 - days2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEnglishDate(d) {
|
|
||||||
if (typeof getEnglishDate.today == 'undefined') {
|
|
||||||
getEnglishDate.today = new Date() };
|
|
||||||
|
|
||||||
var yearDiff = today.getFullYear() - d.getFullYear();
|
|
||||||
var monthDiff = today.getMonth() - d.getMonth();
|
|
||||||
var dayDiff = today.getDate() - d.getDate();
|
|
||||||
|
|
||||||
if (yearDiff > 1) { return capitalize(toWords(yearDiff)) + " years ago."; }
|
|
||||||
else if (yearDiff > 0) { return "Last year"; }
|
|
||||||
else if (monthDiff > 1) {
|
|
||||||
return capitalize(toWords(monthDiff)) + "months ago."; }
|
|
||||||
else if (monthDiff > 0) { return "Last month."; }
|
|
||||||
else if (dayDiff > 0) {
|
|
||||||
// weeks as 7-day periods
|
|
||||||
var weekDiff = Math.ceil(dayDiff / 7)
|
|
||||||
|
|
||||||
// adjust for the hard boundary of the weekend
|
|
||||||
if (today.getDay() > d.getDay()) { weekDiff--; }
|
|
||||||
|
|
||||||
if (weekDiff > 1) {
|
|
||||||
return capitalize(toWords(weekDiff)) + " weeks ago."; }
|
|
||||||
else if (weekDiff > 0) { return "Last week."; }
|
|
||||||
else { return capitalize(toWords(dayDiff)) + " days ago."; }
|
|
||||||
|
|
||||||
} else if (yearDiff < 0 || monthDiff < 0 || daysDiff < 0) {
|
|
||||||
return "In the future."; }
|
|
||||||
else { return "Today."; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function toWords(i) {
|
|
||||||
if (typeof toWords.words == 'undefined') {
|
|
||||||
toWords.words = ['zero','one','two','three','four', 'five','six',
|
|
||||||
'seven','eight','nine','ten','eleven','twelve',
|
|
||||||
'thirteen', 'fourteen','fifteen','sixteen',
|
|
||||||
'seventeen','eighteen','nineteen' ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 20) { return toWords.words[i]; }
|
|
||||||
else { return i.toString(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
function capitalize(s) {
|
|
||||||
return s.slice(0, 1).toUpperCase() + s.slice(1);
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user