Trying to tighten up the design. More functionality implemented.
This commit is contained in:
parent
cf5153c90b
commit
dd3387a0f1
@ -4,19 +4,29 @@
|
|||||||
*/
|
*/
|
||||||
/* _rounded.scss */
|
/* _rounded.scss */
|
||||||
* {
|
* {
|
||||||
color: #222222;
|
color: inherit;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0; }
|
padding: 0; }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 70%;
|
color: #222222;
|
||||||
|
width: 75%;
|
||||||
margin: auto; }
|
margin: auto; }
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: solid thin #555555;
|
||||||
|
-webkit-box-shadow: inset 0px 2px 4px #CCC;
|
||||||
|
box-shadow: inset 0px 2px 4px #CCC;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
font-family: Cantarell; }
|
||||||
|
|
||||||
#top {
|
#top {
|
||||||
|
background: #222222;
|
||||||
|
color: #eeeeee;
|
||||||
|
padding: 0.5rem 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
background: white;
|
width: 75%; }
|
||||||
width: 70%; }
|
|
||||||
#top #fade-bar {
|
#top #fade-bar {
|
||||||
background: url("img/fade.png") repeat-x;
|
background: url("img/fade.png") repeat-x;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@ -24,35 +34,32 @@ body {
|
|||||||
|
|
||||||
#user {
|
#user {
|
||||||
font-family: "Josefin Sans";
|
font-family: "Josefin Sans";
|
||||||
|
margin-top: -0.3rem;
|
||||||
|
padding: 0 2rem;
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
#user .fullname, #user .username {
|
#user .fullname, #user .username {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: larger; }
|
font-size: larger; }
|
||||||
#user .fullname-input {
|
#user .fullname-input {
|
||||||
display: none; }
|
display: none; }
|
||||||
#user.fullname-edit .fullname-input {
|
#user.edit-fullname .fullname-input {
|
||||||
display: inline-block; }
|
display: inline-block; }
|
||||||
#user.fullname-edit .fullname {
|
#user.edit-fullname .fullname {
|
||||||
display: none; }
|
display: none; }
|
||||||
#user .drop-menu {
|
#user .drop-menu {
|
||||||
display: inline-block; }
|
display: inline-block; }
|
||||||
#user .drop-menu .drop-menu-items {
|
#user .drop-menu .drop-menu-items {
|
||||||
float: right;
|
margin-top: -0.5em;
|
||||||
list-style: none; }
|
text-align: right;
|
||||||
#user .drop-menu .drop-menu-items li {
|
right: 0;
|
||||||
float: right;
|
list-style: none;
|
||||||
text-align: center;
|
width: 10em; }
|
||||||
padding-right: 1em; }
|
|
||||||
#user a {
|
|
||||||
display: inline-block;
|
|
||||||
text-decoration: none; }
|
|
||||||
#user a:hover {
|
|
||||||
text-decoration: underline; }
|
|
||||||
|
|
||||||
#timeline {
|
#timeline {
|
||||||
border-bottom: thin solid black;
|
border-bottom: thin solid #eeeeee;
|
||||||
font-family: Arvo;
|
font-family: Arvo;
|
||||||
font-size: 1.5em; }
|
font-size: 1.5em;
|
||||||
|
padding: 0 2rem; }
|
||||||
#timeline .timeline-desc {
|
#timeline .timeline-desc {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 70%; }
|
width: 70%; }
|
||||||
@ -76,32 +83,24 @@ body {
|
|||||||
width: 29%; }
|
width: 29%; }
|
||||||
#timeline .drop-menu .drop-menu-items {
|
#timeline .drop-menu .drop-menu-items {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
right: 0; }
|
right: 0;
|
||||||
|
width: 172.41%; }
|
||||||
|
#timeline .drop-menu .drop-menu-items .timeline-link {
|
||||||
|
font-size: medium; }
|
||||||
|
|
||||||
|
#entry-list {
|
||||||
|
margin-top: 6rem;
|
||||||
|
padding-bottom: 1rem; }
|
||||||
|
|
||||||
#new-entry {
|
#new-entry {
|
||||||
margin-top: 5.5em;
|
margin-top: 0.5rem;
|
||||||
padding: 0.5em 0.5em; }
|
padding: 0 2rem; }
|
||||||
#new-entry .mark-input, #new-entry .timestamp-input {
|
|
||||||
border: solid thin #555555;
|
|
||||||
-webkit-box-shadow: inset 0px 2px 4px #CCC;
|
|
||||||
box-shadow: inset 0px 2px 4px #CCC;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
font-family: Cantarell; }
|
|
||||||
#new-entry .mark-input {
|
#new-entry .mark-input {
|
||||||
width: 78%; }
|
width: 78%; }
|
||||||
#new-entry .edit-mark .mark-input {
|
|
||||||
display: inline-block; }
|
|
||||||
#new-entry .edit-mark .mark {
|
|
||||||
display: none; }
|
|
||||||
#new-entry .edit-timestamp .timestamp-input {
|
|
||||||
display: inline-block; }
|
|
||||||
#new-entry .edit-timestamp .timestamp {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
#entries {
|
|
||||||
padding: 0.5em 0.5em; }
|
|
||||||
#entries .entry {
|
#entries .entry {
|
||||||
font-family: Cantarell; }
|
font-family: Cantarell;
|
||||||
|
padding: 0 2rem; }
|
||||||
#entries .entry div {
|
#entries .entry div {
|
||||||
display: inline-block; }
|
display: inline-block; }
|
||||||
#entries .entry .timestamp, #entries .entry .timestamp-input {
|
#entries .entry .timestamp, #entries .entry .timestamp-input {
|
||||||
@ -114,27 +113,49 @@ body {
|
|||||||
display: none; }
|
display: none; }
|
||||||
#entries .entry .notes {
|
#entries .entry .notes {
|
||||||
display: none; }
|
display: none; }
|
||||||
|
#entries .entry.edit-mark .mark-input {
|
||||||
|
display: inline-block; }
|
||||||
|
#entries .entry.edit-mark .mark {
|
||||||
|
display: none; }
|
||||||
|
#entries .entry.edit-timestamp .timestamp-input {
|
||||||
|
display: inline-block; }
|
||||||
|
#entries .entry.edit-timestamp .timestamp {
|
||||||
|
display: none; }
|
||||||
|
|
||||||
|
.day-seperator {
|
||||||
|
background: #cccccc;
|
||||||
|
color: #222222;
|
||||||
|
font-family: Cantarell;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0 2rem; }
|
||||||
|
|
||||||
.drop-menu {
|
.drop-menu {
|
||||||
position: relative; }
|
position: relative; }
|
||||||
.drop-menu .drop-menu-items {
|
.drop-menu .drop-menu-items {
|
||||||
background: white;
|
|
||||||
display: none;
|
display: none;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
position: absolute; }
|
position: absolute; }
|
||||||
|
.drop-menu .drop-menu-items li {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 0.5em; }
|
||||||
.drop-menu:hover .drop-menu-items, .drop-menu .drop-menu-items:hover {
|
.drop-menu:hover .drop-menu-items, .drop-menu .drop-menu-items:hover {
|
||||||
display: block; }
|
display: block; }
|
||||||
|
.drop-menu a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none; }
|
||||||
|
.drop-menu a:hover {
|
||||||
|
text-decoration: underline; }
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
border-top: thin solid black;
|
background: #222222;
|
||||||
color: #888888;
|
color: #eeeeee;
|
||||||
font-family: Bentham;
|
font-family: Bentham;
|
||||||
margin: 1em 0;
|
padding: 1rem 0;
|
||||||
padding-top: 1em;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
.footer a {
|
.footer a {
|
||||||
color: #888888;
|
color: white;
|
||||||
text-decoration: none; }
|
text-decoration: none; }
|
||||||
.footer a:hover {
|
.footer a:hover {
|
||||||
text-decoration: underline; }
|
text-decoration: underline; }
|
||||||
|
@ -5,24 +5,39 @@
|
|||||||
|
|
||||||
@import "rounded";
|
@import "rounded";
|
||||||
|
|
||||||
$txtClr: #222;
|
$darkTxt: #222;
|
||||||
|
$lightTxt: #eee;
|
||||||
|
$darkBg: #222;
|
||||||
|
$lightBg: #eee;
|
||||||
|
$medBg: #CCC;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
color: $txtClr;
|
color: inherit;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 70%;
|
color: $darkTxt;
|
||||||
|
width: 75%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: solid thin lighten($darkTxt, 20%);
|
||||||
|
-webkit-box-shadow: inset 0px 2px 4px #CCC;
|
||||||
|
box-shadow: inset 0px 2px 4px #CCC;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
font-family: Cantarell;
|
||||||
|
}
|
||||||
|
|
||||||
#top {
|
#top {
|
||||||
|
background: $darkBg;
|
||||||
|
color: $lightTxt;
|
||||||
|
padding: 0.5rem 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
background: white;
|
width: 75%;
|
||||||
width: 70%;
|
|
||||||
|
|
||||||
#fade-bar {
|
#fade-bar {
|
||||||
background: url('img/fade.png') repeat-x;
|
background: url('img/fade.png') repeat-x;
|
||||||
@ -34,6 +49,8 @@ body {
|
|||||||
#user {
|
#user {
|
||||||
|
|
||||||
font-family: "Josefin Sans";
|
font-family: "Josefin Sans";
|
||||||
|
margin-top: -0.3rem;
|
||||||
|
padding: 0 2rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.fullname, .username {
|
.fullname, .username {
|
||||||
@ -43,7 +60,7 @@ body {
|
|||||||
|
|
||||||
.fullname-input { display: none; }
|
.fullname-input { display: none; }
|
||||||
|
|
||||||
&.fullname-edit {
|
&.edit-fullname{
|
||||||
.fullname-input { display: inline-block; }
|
.fullname-input { display: inline-block; }
|
||||||
.fullname { display: none; }
|
.fullname { display: none; }
|
||||||
}
|
}
|
||||||
@ -51,33 +68,22 @@ body {
|
|||||||
.drop-menu { display: inline-block; }
|
.drop-menu { display: inline-block; }
|
||||||
|
|
||||||
.drop-menu .drop-menu-items {
|
.drop-menu .drop-menu-items {
|
||||||
|
margin-top: -0.5em;
|
||||||
float: right;
|
text-align: right;
|
||||||
|
right: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
width: 10em;
|
||||||
li {
|
|
||||||
float: right;
|
|
||||||
text-align: center;
|
|
||||||
//margin-top: -0.5em;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#timeline {
|
#timeline {
|
||||||
|
|
||||||
border-bottom: thin solid black;
|
border-bottom: thin solid $lightBg;
|
||||||
font-family: Arvo;
|
font-family: Arvo;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
|
padding: 0 2rem;
|
||||||
|
|
||||||
.timeline-desc {
|
.timeline-desc {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -108,42 +114,34 @@ body {
|
|||||||
.drop-menu-items {
|
.drop-menu-items {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
width: 172.41%;
|
||||||
|
|
||||||
|
.timeline-link {
|
||||||
|
font-size: medium;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#entry-list {
|
||||||
|
margin-top: 6rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
#new-entry {
|
#new-entry {
|
||||||
margin-top: 5.5em;
|
margin-top: 0.5rem;
|
||||||
padding: 0.5em 0.5em;
|
padding: 0 2rem;
|
||||||
|
|
||||||
.mark-input, .timestamp-input {
|
|
||||||
border: solid thin lighten($txtClr, 20%);
|
|
||||||
-webkit-box-shadow: inset 0px 2px 4px #CCC;
|
|
||||||
box-shadow: inset 0px 2px 4px #CCC;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
font-family: Cantarell;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mark-input { width: 78%; }
|
.mark-input { width: 78%; }
|
||||||
|
|
||||||
.edit-mark {
|
|
||||||
.mark-input { display: inline-block; }
|
|
||||||
.mark { display: none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-timestamp {
|
|
||||||
.timestamp-input { display: inline-block; }
|
|
||||||
.timestamp { display: none; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#entries {
|
#entries {
|
||||||
|
|
||||||
padding: 0.5em 0.5em;
|
|
||||||
|
|
||||||
.entry {
|
.entry {
|
||||||
|
|
||||||
font-family: Cantarell;
|
font-family: Cantarell;
|
||||||
|
padding: 0 2rem;
|
||||||
|
|
||||||
div { display: inline-block; }
|
div { display: inline-block; }
|
||||||
|
|
||||||
@ -157,38 +155,66 @@ body {
|
|||||||
|
|
||||||
.notes { display: none; }
|
.notes { display: none; }
|
||||||
|
|
||||||
|
&.edit-mark {
|
||||||
|
.mark-input { display: inline-block; }
|
||||||
|
.mark { display: none; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.edit-timestamp {
|
||||||
|
.timestamp-input { display: inline-block; }
|
||||||
|
.timestamp { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-seperator {
|
||||||
|
background: $medBg;
|
||||||
|
color: $darkBg;
|
||||||
|
font-family: Cantarell;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drop-menu {
|
.drop-menu {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.drop-menu-items {
|
.drop-menu-items {
|
||||||
background: white;
|
|
||||||
display: none;
|
display: none;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .drop-menu-items, .drop-menu-items:hover {
|
&:hover .drop-menu-items, .drop-menu-items:hover { display: block; }
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
|
||||||
border-top: thin solid black;
|
background: $darkBg;
|
||||||
color: lighten($txtClr, 40%);
|
color: $lightTxt;
|
||||||
font-family: Bentham;
|
font-family: Bentham;
|
||||||
margin: 1em 0;
|
padding: 1rem 0;
|
||||||
padding-top: 1em;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: lighten($txtClr, 40%);
|
color: lighten($lightTxt, 20%);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover { text-decoration: underline; }
|
&:hover { text-decoration: underline; }
|
||||||
|
120
www/index.yaws
120
www/index.yaws
@ -20,67 +20,100 @@
|
|||||||
<script type="text/javascript" src="/js/ICanHaz.js"></script>
|
<script type="text/javascript" src="/js/ICanHaz.js"></script>
|
||||||
<script type="text/javascript" src="/js/backbone.js"></script>
|
<script type="text/javascript" src="/js/backbone.js"></script>
|
||||||
<script type="text/javascript" src="/js/ts.js"></script>
|
<script type="text/javascript" src="/js/ts.js"></script>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
<script type="text/javascript">
|
||||||
|
<erl>
|
||||||
|
out(YArg) ->
|
||||||
|
Session = ts_api_session:get_session(YArg),
|
||||||
|
case Session of not_logged_in -> {html, "//not logged in"}; session_expired -> {html, "//session expired"};
|
||||||
|
_S ->
|
||||||
|
Username = element(2, Session),
|
||||||
|
|
||||||
<script id="timelineLink" type="text/html">
|
% get the user
|
||||||
<li class="timeline-link"><a href="#">{{id}}</a></li>
|
{content, _, UserJSON} = ts_api:get_user(YArg, Username),
|
||||||
|
UserRecord = ts_user:lookup(Username),
|
||||||
|
|
||||||
|
% get the timelines
|
||||||
|
{content, _, TimelineListJSON} = ts_api:list_timelines(YArg, Username),
|
||||||
|
|
||||||
|
% get the selected timeline
|
||||||
|
SelectedTimeline = case lists:keyfind(
|
||||||
|
selected_timeline, 1, element(8, UserRecord)) of
|
||||||
|
false -> ts_timeline:list(Username, 0, 1);
|
||||||
|
T -> T
|
||||||
|
end,
|
||||||
|
|
||||||
|
% get entries for this timeline
|
||||||
|
{content, _, EntryListJSON} =
|
||||||
|
ts_api:list_entries(YArg, Username, SelectedTimeline),
|
||||||
|
|
||||||
|
{html, f(
|
||||||
|
"function bootstrap() {~n"
|
||||||
|
" var data = {};~n"
|
||||||
|
" data.user = ~p;~n"
|
||||||
|
" data.timelines = ~p;~n"
|
||||||
|
" data.initialTimelineId = ~p;~n"
|
||||||
|
" data.entries = ~p;~n"
|
||||||
|
" return data;~n"
|
||||||
|
"};",
|
||||||
|
[UserJSON, TimelineListJSON, SelectedTimeline, EntryListJSON])}
|
||||||
|
end.
|
||||||
|
</erl>
|
||||||
</script>
|
</script>
|
||||||
<script id="entry" type="text/html">
|
<script type="text/html" id="userTemplate">
|
||||||
<div class="entry">
|
<div class="fullname">{{name}}</div>
|
||||||
<div class="mark">{{mark}}</div>
|
<input class='fullname-input' type='text' value='{{name}}'/></div>
|
||||||
<input class="mark-input" type="text">{{mark}}</input>
|
|
||||||
<div class="timestamp">{{timestamp}}</div>
|
|
||||||
<input class="timestamp-input" type="text">{{timestamp}}</input>
|
|
||||||
<div class="duration">4<span class="tick-tock">:</span>03<span class="tick-tock">:</span>57</div>
|
|
||||||
<div class="notes">{{notes}}</div>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="top">
|
|
||||||
<div id="timeline">
|
|
||||||
<span class="timeline-desc">No timeline loaded.</span>
|
|
||||||
<input class="timeline-desc-input" type="text"/>
|
|
||||||
<div class="drop-menu">
|
|
||||||
<div class="timeline-id">( none )</div>
|
|
||||||
<input class="timeline-id-input" type="text"/>
|
|
||||||
<ul class="drop-menu-items">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="user">
|
|
||||||
<div class="fullname">Not Logged In</div>
|
|
||||||
<input class='fullname-input' type='text'/>
|
|
||||||
<div class='drop-menu'>
|
<div class='drop-menu'>
|
||||||
<div class="username"> - not_logged_in</div>
|
<div class="username"> - {{id}}</div>
|
||||||
<ul class="drop-menu-items">
|
<ul class="drop-menu-items">
|
||||||
<li><a href="#">logout</a></li>
|
<li><a href="#">logout</a></li>
|
||||||
<li><a href="#">user info</a></li>
|
<li><a href="#">user info</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="timelineTemplate">
|
||||||
|
<span class="timeline-desc">{{description}}</span>
|
||||||
|
<input class="timeline-desc-input" type="text" value='{{description}}'/>
|
||||||
|
<div class="drop-menu">
|
||||||
|
<div class="timeline-id">( {{id}} )</div>
|
||||||
|
<input class="timeline-id-input" type="text" value='{{id}}'/>
|
||||||
|
<ul class="drop-menu-items">
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="timelineLinkTemplate">
|
||||||
|
<li class="timeline-link"><a href="#">{{id}}</a></li>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="entryTemplate">
|
||||||
|
<div class="mark">{{mark}}</div>
|
||||||
|
<input class="mark-input" type="text" value="{{mark}}"/>
|
||||||
|
<div class="timestamp">{{timestamp}}</div>
|
||||||
|
<input class="timestamp-input" type="text" value="{{timestamp}}"/>
|
||||||
|
<!-- TODO <div class="duration">4<span class="tick-tock">:</span>03<span class="tick-tock">:</span>57</div>-->
|
||||||
|
<div class="notes">{{notes}}</div>
|
||||||
|
</script>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="top">
|
||||||
|
|
||||||
|
<!-- == TIMELINE == -->
|
||||||
|
<div id="timeline"><!-- rendered by app --></div>
|
||||||
|
|
||||||
|
<!-- == USER == -->
|
||||||
|
<div id="user"><!-- rendered by app --></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="entry-list">
|
<div id="entry-list">
|
||||||
|
<div class="day-seperator">Today</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" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="entries">
|
<div id="entries"></div>
|
||||||
<div class="entry">
|
|
||||||
<div class="mark">ITHelp: Entering tickets.</div>
|
|
||||||
<input class="mark-input" type="text"/>
|
|
||||||
<div class="timestamp">12:32</div>
|
|
||||||
<input class="timestamp-input" type="text"/>
|
|
||||||
<div class="duration">4<span class="tick-tock">:</span>03<span class="tick-tock">:</span>57</div>
|
|
||||||
<div class="notes">Some notes should go here, but they should be hidden by default</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@ -100,6 +133,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<p class="validate-tips"></p>
|
<p class="validate-tips"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
249
www/js/ts.js
249
www/js/ts.js
@ -20,7 +20,7 @@ $(document).ready(function(){
|
|||||||
/* Timeline model.
|
/* Timeline model.
|
||||||
* Attributes:
|
* Attributes:
|
||||||
* - id
|
* - id
|
||||||
* - desc
|
* - description
|
||||||
* - created
|
* - created
|
||||||
*/
|
*/
|
||||||
TS.TimelineModel = Backbone.Model.extend({
|
TS.TimelineModel = Backbone.Model.extend({
|
||||||
@ -56,7 +56,7 @@ $(document).ready(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
url: function() {
|
url: function() {
|
||||||
return "/entries/" + this.timeline.get('user_id') + "/" + this.timeline.get('id');
|
return "/ts_api/entries/" + this.timeline.get('user_id') + "/" + this.timeline.get('id');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -89,6 +89,8 @@ $(document).ready(function(){
|
|||||||
|
|
||||||
model: TS.EntryModel,
|
model: TS.EntryModel,
|
||||||
|
|
||||||
|
className: 'entry',
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
"dblclick div.mark" : "editMark",
|
"dblclick div.mark" : "editMark",
|
||||||
"dblclick div.timestamp" : "editTimestamp",
|
"dblclick div.timestamp" : "editTimestamp",
|
||||||
@ -104,7 +106,7 @@ $(document).ready(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
$(this.el).html(ich.entry(this.model.toJSON()));
|
$(this.el).html(ich.entryTemplate(this.model.toJSON()));
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -125,6 +127,7 @@ $(document).ready(function(){
|
|||||||
mark: this.$('.mark-input').val(),
|
mark: this.$('.mark-input').val(),
|
||||||
timestamp: this.$('.timestamp-input').val()});
|
timestamp: this.$('.timestamp-input').val()});
|
||||||
$(this.el).removeClass('edit-mark edit-timestamp');
|
$(this.el).removeClass('edit-mark edit-timestamp');
|
||||||
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
@ -137,7 +140,7 @@ $(document).ready(function(){
|
|||||||
el: $("#entry-list"),
|
el: $("#entry-list"),
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
"#new-entry" : "createNewEntry"
|
"keypress #new-entry-input" : "createNewEntryOnEnter"
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
@ -153,10 +156,18 @@ $(document).ready(function(){
|
|||||||
this.entryContainer.prepend(entry.view.render().el);
|
this.entryContainer.prepend(entry.view.render().el);
|
||||||
},
|
},
|
||||||
|
|
||||||
createNewEntry: function() {
|
createNewEntryOnEnter: function(e) {
|
||||||
|
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
|
||||||
|
// grab the mark data
|
||||||
var entryMark = this.$("#new-entry-input").val();
|
var entryMark = this.$("#new-entry-input").val();
|
||||||
var newEntry = TS.EntryModel({mark: entryMark});
|
|
||||||
this.collection.create({mark: entryMark}).fetch();
|
// create the mark. Immediately fetch to get server-side timestamp
|
||||||
|
this.collection.create({mark: entryMark,
|
||||||
|
notes: '',
|
||||||
|
timestamp: getUTCTimestamp()}).fetch();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@ -165,11 +176,10 @@ $(document).ready(function(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
TS.TimelineView = Backbone.View.extend({
|
TS.TimelineListView = Backbone.View.extend({
|
||||||
|
|
||||||
el: $("#timeline"),
|
el: $("#timeline"),
|
||||||
|
|
||||||
model: TS.TimelineModel,
|
collection: TS.TimelineList,
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
"dblclick .timeline-id" : "editId",
|
"dblclick .timeline-id" : "editId",
|
||||||
@ -178,18 +188,31 @@ $(document).ready(function(){
|
|||||||
"keypress .timeline-desc-input" : "updateOnEnter"
|
"keypress .timeline-desc-input" : "updateOnEnter"
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function(options) {
|
||||||
_.bindAll(this, 'render', 'close', 'editId', 'editDesc',
|
_.bindAll(this, 'render', 'renderOne', 'editId',
|
||||||
'updateOnEnter');
|
'editDesc', 'updateOnEnter');
|
||||||
this.model.bind('change', this.render);
|
|
||||||
this.model.view = this;
|
if (options.initialTimelineId == undefined) {
|
||||||
|
throw "Can not create a TimelineListView without an initial timeline."
|
||||||
|
} else {
|
||||||
|
this.selected = this.collection.get(options.initialTimelineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.collection.bind('add', this.renderOne);
|
||||||
|
this.collection.bind('refresh', this.render);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderOne: function(timeline) {
|
||||||
|
this.$('.drop-menu-items').append(
|
||||||
|
ich.timelineLinkTemplate(timeline.toJSON()));
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
this.$('.timeline-id').html('( ' +
|
// render the basic template
|
||||||
this.model.get('id') + ' )');
|
$(this.el).html(ich.timelineTemplate(this.selected.toJSON()));
|
||||||
this.$('.timeline-desc').text(this.model.get('desc'));
|
|
||||||
return this;
|
// render the selection list
|
||||||
|
_.each(this.collection.without([this.selected]), this.renderOne);
|
||||||
},
|
},
|
||||||
|
|
||||||
editId: function() {
|
editId: function() {
|
||||||
@ -205,39 +228,17 @@ $(document).ready(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.model.save({
|
this.selected.save({
|
||||||
id: this.$('timeline-id-input').val(),
|
id: this.$('.timeline-id-input').val(),
|
||||||
desc: this.$('.timeline-desc-input').val()});
|
description: this.$('.timeline-desc-input').val()});
|
||||||
$(this.el).removeClass('.edit-id .edit-desc');
|
$(this.el).removeClass('edit-id edit-desc');
|
||||||
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
if (e.keyCode == 13) this.close();
|
if (e.keyCode == 13) this.close();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
TS.TimelineListView = Backbone.View.extend({
|
|
||||||
el: $("#timeline .drop-menu-items"),
|
|
||||||
|
|
||||||
collection: TS.TimelineList,
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
_.bindAll(this, 'render', 'renderOne');
|
|
||||||
this.collection.bind('add', this.renderOne);
|
|
||||||
this.collection.bind('refresh', this.render);
|
|
||||||
this.collection.view = this;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderOne: function(timeline) {
|
|
||||||
if (!timeline.view) { new TS.TimelineView(timeline); }
|
|
||||||
$(this.el).append(ich.timelineLink(timeline.toJSON()));
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
$(this.el).remove(".timeline-link");
|
|
||||||
this.collection.each(this.renderOne);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
TS.UserView = Backbone.View.extend({
|
TS.UserView = Backbone.View.extend({
|
||||||
@ -258,25 +259,24 @@ $(document).ready(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
this.$('.fullname').text(this.model.get('name'));
|
$(this.el).html(ich.userTemplate(this.model.toJSON()));
|
||||||
this.$('.username').text(" - " + this.model.get('id'));
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
editFullname: function() {
|
editFullname: function() {
|
||||||
$(this.el).addClass('.edit-fullname');
|
$(this.el).addClass('edit-fullname');
|
||||||
this.$('.fullname-input').focus();
|
this.$('.fullname-input').focus();
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.model.set({name: this.$('.fullname-input').val()});
|
this.model.set({name: this.$('fullname-input').val()});
|
||||||
this.model.save();
|
this.model.save();
|
||||||
$(this.el).removeClass('.edit-fullname');
|
$(this.el).removeClass('edit-fullname');
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOnEnter: function(e) {
|
updateOnEnter: function(e) {
|
||||||
if (keyCode == 13) this.close();
|
if (e.keyCode == 13) this.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -285,36 +285,110 @@ $(document).ready(function(){
|
|||||||
el: $("body"),
|
el: $("body"),
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'click #timeline .drop-menu-items a': 'selectTimeline',
|
'click #timeline .drop-menu-items a': 'selectTimeline'
|
||||||
'keypress #new-entry-input' : 'newTimestamp',
|
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
_.bindAll(this, 'render');
|
|
||||||
|
_.bindAll(this, 'initializeViews', 'loadInitialData');
|
||||||
|
|
||||||
|
appThis = this;
|
||||||
|
|
||||||
|
// create the login dialog
|
||||||
|
this.loginDialog = new TS.LoginView
|
||||||
|
|
||||||
|
if (window.bootstrap) { this.initializeData(window.bootstrap()) }
|
||||||
|
else {
|
||||||
|
// this is async (waiting for user input)
|
||||||
|
this.loginDialog.authenticate(function() {
|
||||||
|
appThis.initializeData(appThis.loadInitialData())});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
renderTimelineList: function() {
|
initializeData: function(data) {
|
||||||
var tlUL = this.$('#timeline ul.drop-menu-items');
|
|
||||||
//var curTimeline =
|
// create user data
|
||||||
//var remTimelines = TS.user.timelines.filter(function(timeline)
|
this.user = {};
|
||||||
}
|
this.user.model = new TS.UserModel(data.user);
|
||||||
|
this.user.view = new TS.UserView({model: this.user.model});
|
||||||
|
|
||||||
|
// create timeline models from the bootstrapped data
|
||||||
|
var tlModels = _.map(data.timelines, function(timeline) {
|
||||||
|
return new TS.TimelineModel(timeline);
|
||||||
});
|
});
|
||||||
|
|
||||||
// wire the login dialog using jQuery UI
|
// create the timeline list collection
|
||||||
$("#login-dialog").dialog({
|
this.timelines = {};
|
||||||
|
this.timelines.collection = new TS.TimelineList(
|
||||||
|
tlModels, {user: this.user.model});
|
||||||
|
this.timelines.view = new TS.TimelineListView(
|
||||||
|
{collection: this.timelines.collection,
|
||||||
|
initialTimelineId: data.initialTimelineId});
|
||||||
|
|
||||||
|
// create entry models from the bootstrapped data
|
||||||
|
var entryModels = _.map(data.entries, function(entry) {
|
||||||
|
return new TS.EntryModel(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
// create the entry collection
|
||||||
|
this.entries = {};
|
||||||
|
this.entries.collection = new TS.EntryList(entryModels,
|
||||||
|
{timeline: this.timelines.view.selected});
|
||||||
|
this.entries.view = new TS.EntryListView(
|
||||||
|
{collection: this.entries.collection});
|
||||||
|
|
||||||
|
// render views
|
||||||
|
this.user.view.render();
|
||||||
|
this.timelines.view.render();
|
||||||
|
this.entries.view.render();
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
loadInitialData: function() {
|
||||||
|
// assume we are authenticated
|
||||||
|
|
||||||
|
var username = $("#login-name").val(); // hackish
|
||||||
|
var data = jQuery.parseJSON($.ajax({
|
||||||
|
url: '/ts_api/app/user_summary/' + username,
|
||||||
|
async: false}).responseText);
|
||||||
|
|
||||||
|
data.initialTimelineId = data.timelines[0].id;
|
||||||
|
data.entries = jQuery.parseJSON($.ajax({
|
||||||
|
url: '/ts_api/entries/' + username + '/' +
|
||||||
|
data.initialTimelineId,
|
||||||
|
async: false}).responseText);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
TS.LoginView = Backbone.View.extend({
|
||||||
|
el: $("#login-dialog"),
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
_.bindAll(this, 'doLogin', 'authenticate');
|
||||||
|
|
||||||
|
var viewThis = this;
|
||||||
|
$(this.el).dialog({
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
height: 400,
|
height: 400,
|
||||||
width: 400,
|
width: 400,
|
||||||
modal: true,
|
modal: true,
|
||||||
buttons: { Login: function(){login()} }
|
buttons: { Login: viewThis.doLogin}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
$('#login-dialog').dialog('open');
|
action: function() {},
|
||||||
|
|
||||||
})
|
authenticate: function(nextAction) {
|
||||||
|
this.action = nextAction;
|
||||||
|
$(this.el).dialog("open");
|
||||||
|
},
|
||||||
|
|
||||||
function login() {
|
doLogin: function(){
|
||||||
// lookup the login dialog elements
|
var viewThis = this;
|
||||||
var name = $("#login-name");
|
var name = $("#login-name");
|
||||||
var pwd = $("#login-password");
|
var pwd = $("#login-password");
|
||||||
|
|
||||||
@ -324,6 +398,7 @@ function login() {
|
|||||||
processData: false,
|
processData: false,
|
||||||
data: JSON.stringify({username: name.val(), password: pwd.val()}),
|
data: JSON.stringify({username: name.val(), password: pwd.val()}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
async: false,
|
||||||
|
|
||||||
error: function(jqXHR, textStatus, error) {
|
error: function(jqXHR, textStatus, error) {
|
||||||
// assuming bad credentials (possible server error or bad request,
|
// assuming bad credentials (possible server error or bad request,
|
||||||
@ -335,21 +410,27 @@ function login() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
success: function(data, textStatus, jqXHR) {
|
success: function(data, textStatus, jqXHR) {
|
||||||
|
$(viewThis.el).dialog("close");
|
||||||
// initialize the app data
|
viewThis.action()
|
||||||
// TODO: possiblty replace by script generated server-side
|
|
||||||
|
|
||||||
// create the user model
|
|
||||||
TS.user = new TS.UserModel({
|
|
||||||
id: name.val(),
|
|
||||||
name: '' });
|
|
||||||
|
|
||||||
// fetch the initial user data from the server
|
|
||||||
TS.user.fetch();
|
|
||||||
|
|
||||||
// create the user view
|
|
||||||
new TS.UserView({model: TS.user});
|
|
||||||
TS.user.view.render();
|
|
||||||
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TS.app = new TS.AppView;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
function getUTCTimestamp() {
|
||||||
|
var d = new Date();
|
||||||
|
|
||||||
|
function pad(n){return n<10 ? '0'+n : n}
|
||||||
|
|
||||||
|
return d.getUTCFullYear()+'-'
|
||||||
|
+ pad(d.getUTCMonth()+1)+'-'
|
||||||
|
+ pad(d.getUTCDate())+'T'
|
||||||
|
+ pad(d.getUTCHours())+':'
|
||||||
|
+ pad(d.getUTCMinutes())+':'
|
||||||
|
+ pad(d.getUTCSeconds())+'Z';
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user