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:
Jonathan Bernard 2011-06-17 16:02:26 -05:00
parent 81503112a8
commit f3ef7db088
24 changed files with 147 additions and 82 deletions

View File

@ -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

View File

@ -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

Binary file not shown.

Binary file not shown.

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.

View File

@ -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
========= ========== ========= ==========

View File

@ -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

View File

@ -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
==================== ====================

View File

@ -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

View 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
========= ==========

View 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
========= ==========

View 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
========= ==========

View 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
========= ==========

View File

@ -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 {

View File

@ -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; }

View File

@ -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" />

View File

@ -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);
}