Added UUIDs to timestamps, refactored the build process
* Added UUIDs to `ts_entry` records. Updated `ts_json:construct_record` to
respond to `uuid` member properties if present. UUIDs are not required by the
strict parsing functions in `ts_json` because the client will make a request
with no UUID if it is a purely new timestamp. IN fact, this is the normal
case. The UUID is only present when another tool is syncing its copy of this
timeline wand adding entries that it has created and assigned UUIDs to.
* `ts_entry:new` will create a UUID for a new entry if it does not already have
one.
* Restructured the build process to put all build artifacts into a dedicated
`build` subdirectory, instead of mising them in an amongst the source code.
* Added the `uuid` module to the project. It can be found at
https://gitorious.org/avtobiff/erlang-uuid
* Rewrote asset URLs to use relative paths instead of absolute paths. Relative
paths are correct in this case, becuase assets always live alongside the HTML
pages. This change was needed to accomodate the new organization of the JDB
Labs dev environment, where all projects live under subdirectories of the
same virtual server instead of subdomains.
* Tweaked the timestamp entry fields in the web UI to save when the field is
blurred, not just when <Enter> or <Ctrl>-<Enter> is pressed (though those
still work).
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<title>TimeStamper - Simple Time Tracking</title>
|
||||
<link href='//fonts.googleapis.com/css?family=Anonymous+Pro|Arvo|Bentham|Cantarell|Josefin+Sans' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" media="screen" href="/css/ts-screen.css" type="text/css"/>
|
||||
<link rel="stylesheet" media="screen" href="css/ts-screen.css" type="text/css"/>
|
||||
<!-- Needed for IE, but I'm not sure if I'm going to support IE with this tool. -->
|
||||
<!--<script type="text/javascript" src="/js/json2.js"></script>-->
|
||||
<!-- PROD -->
|
||||
@@ -12,13 +12,13 @@
|
||||
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script>
|
||||
-->
|
||||
<!-- DEV -->
|
||||
<script type="text/javascript" src="/js/jquery-1.5.js"></script>
|
||||
<script type="text/javascript" src="js/jquery-1.5.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/js/showdown.js"></script>
|
||||
<script type="text/javascript" src="/js/underscore.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/ts.js"></script>
|
||||
<script type="text/javascript" src="js/showdown.js"></script>
|
||||
<script type="text/javascript" src="js/underscore.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/ts.js"></script>
|
||||
<script type="text/javascript">
|
||||
<erl>
|
||||
out(YArg) ->
|
||||
@@ -77,7 +77,7 @@ out(YArg) ->
|
||||
<input class="timeline-id-input" type="text" value='{{id}}'/>
|
||||
<ul class="drop-menu-items">
|
||||
<li class="new-timeline-link"><a href="#">
|
||||
<img src="/img/round_plus_icon_16.png"/>new</a></li>
|
||||
<img src="img/round_plus_icon_16.png"/>new</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</script>
|
||||
@@ -86,8 +86,8 @@ out(YArg) ->
|
||||
</script>
|
||||
<script type="text/html" id="entryTemplate">
|
||||
<div class="mark">
|
||||
<img class="expand-entry" src="/img/br_down_icon_16.png"/>
|
||||
<img class="collapse-entry" src="/img/br_up_icon_16.png"/>
|
||||
<img class="expand-entry" src="img/br_down_icon_16.png"/>
|
||||
<img class="collapse-entry" src="img/br_up_icon_16.png"/>
|
||||
<span>{{mark}}</span>
|
||||
</div>
|
||||
<input class="mark-input" type="text" value="{{mark}}"/>
|
||||
|
||||
64
www/js/ts.js
64
www/js/ts.js
@@ -130,18 +130,18 @@ $(document).ready(function(){
|
||||
"dblclick div.mark" : "editMark",
|
||||
"dblclick div.timestamp" : "editTimestamp",
|
||||
"dblclick div.notes" : "editNotes",
|
||||
"keypress .mark-input" : "updateOnEnter",
|
||||
"keypress .timestamp-input" : "updateOnEnter",
|
||||
"keypress .notes-input" : "updateOnCtrlEnter",
|
||||
"blur .mark-input" : "close",
|
||||
"blur .timestamp-input" : "close",
|
||||
"blur .notes-input" : "close"
|
||||
"keypress .mark-input" : "saveOnEnter",
|
||||
"keypress .timestamp-input" : "saveOnEnter",
|
||||
"keypress .notes-input" : "saveOnCtrlEnter",
|
||||
"blur .mark-input" : "save",
|
||||
"blur .timestamp-input" : "save",
|
||||
"blur .notes-input" : "save"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
_.bindAll(this, 'render', 'close', 'editTImestamp', 'editMark',
|
||||
'update', 'updateOnEnter', 'updateOnCtrlEnter', 'getViewModel',
|
||||
'renderNotes', 'showNotes', 'hideNotes');
|
||||
_.bindAll(this, 'render', 'editTImestamp', 'editMark', 'update',
|
||||
'saveOnEnter', 'saveOnCtrlEnter', 'getViewModel',
|
||||
'renderNotes', 'showNotes', 'hideNotes', 'save');
|
||||
|
||||
this.markdownConverter = options.markdownConverter;
|
||||
|
||||
@@ -183,8 +183,7 @@ $(document).ready(function(){
|
||||
|
||||
renderNotes: function(source) {
|
||||
if (!this.notesCache) {
|
||||
this.notesCache = this.markdownConverter.makeHtml(source);
|
||||
}
|
||||
this.notesCache = this.markdownConverter.makeHtml(source); }
|
||||
|
||||
return this.notesCache
|
||||
},
|
||||
@@ -228,26 +227,24 @@ $(document).ready(function(){
|
||||
return data;
|
||||
},
|
||||
|
||||
/** Close editable fields. */
|
||||
close: function() {
|
||||
$(this.el).removeClass('edit-mark edit-timestamp edit-notes');
|
||||
},
|
||||
|
||||
/** Persist changes in input fields. */
|
||||
/** Save and close editable fields. */
|
||||
save: function() {
|
||||
this.model.save({
|
||||
mark: this.$('.mark-input').val(),
|
||||
timestamp: new Date(this.$('.timestamp-input').val()),
|
||||
notes: this.$('.notes-input').val()});
|
||||
|
||||
this.$('.notes-text').html(this.renderNotes(this.model.get('notes')));
|
||||
$(this.el).removeClass('edit-mark edit-timestamp edit-notes');
|
||||
},
|
||||
|
||||
/** Event handler for keypresses on entry input fields. */
|
||||
updateOnEnter: function(e) {
|
||||
if(e.keyCode == 13) { this.save(); this.close(); }
|
||||
saveOnEnter: function(e) {
|
||||
if(e.keyCode == 13) { this.save(); }
|
||||
},
|
||||
|
||||
updateOnCtrlEnter: function(e) {
|
||||
if (e.keyCode == 10) { this.save(); this.close(); }
|
||||
saveOnCtrlEnter: function(e) {
|
||||
if (e.keyCode == 10) { this.save(); }
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -305,8 +302,7 @@ $(document).ready(function(){
|
||||
showNotes: function() {
|
||||
if (!this.notesCache) {
|
||||
this.$('.notes-text').html(
|
||||
this.renderNotes(this.model.get('notes')))
|
||||
}
|
||||
this.renderNotes(this.model.get('notes'))); }
|
||||
|
||||
this.$('.notes').slideDown();
|
||||
$(this.el).addClass('show-notes');
|
||||
@@ -473,14 +469,14 @@ $(document).ready(function(){
|
||||
events: {
|
||||
"dblclick .timeline-id" : "editId",
|
||||
"dblclick .timeline-desc" : "editDesc",
|
||||
"keypress .timeline-id-input" : "updateOnEnter",
|
||||
"keypress .timeline-desc-input" : "updateOnEnter",
|
||||
"keypress .timeline-id-input" : "saveOnEnter",
|
||||
"keypress .timeline-desc-input" : "saveOnEnter",
|
||||
"click .new-timeline-link" : "showNewTimelineDialog"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
_.bindAll(this, 'render', 'renderOne', 'editId',
|
||||
'editDesc', 'updateOnEnter', 'close');
|
||||
'editDesc', 'saveOnEnter', 'save');
|
||||
|
||||
if (options.initialTimelineId == undefined) {
|
||||
throw "Can not create a TimelineListView without an initial timeline."
|
||||
@@ -517,7 +513,7 @@ $(document).ready(function(){
|
||||
return this;
|
||||
},
|
||||
|
||||
close: function() {
|
||||
save: function() {
|
||||
this.selectedModel.save({
|
||||
id: this.$('.timeline-id-input').val(),
|
||||
description: this.$('.timeline-desc-input').val()});
|
||||
@@ -529,8 +525,8 @@ $(document).ready(function(){
|
||||
TS.app.newTimelineDialog.show();
|
||||
},
|
||||
|
||||
updateOnEnter: function(e) {
|
||||
if (e.keyCode == 13) { this.close(); this.save() }
|
||||
saveOnEnter: function(e) {
|
||||
if (e.keyCode == 13) { this.save(); }
|
||||
}
|
||||
|
||||
});
|
||||
@@ -543,11 +539,11 @@ $(document).ready(function(){
|
||||
|
||||
events: {
|
||||
'dblclick .fullname': 'editFullname',
|
||||
'keypress .fullname-input': 'updateOnEnter'
|
||||
'keypress .fullname-input': 'saveOnEnter'
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll(this, 'render', 'close', 'editFullname', 'updateOnEnter');
|
||||
_.bindAll(this, 'render', 'save', 'editFullname', 'saveOnEnter');
|
||||
this.model.bind('change', this.render);
|
||||
this.model.view = this;
|
||||
},
|
||||
@@ -563,14 +559,14 @@ $(document).ready(function(){
|
||||
return this;
|
||||
},
|
||||
|
||||
close: function() {
|
||||
save: function() {
|
||||
this.model.set({name: this.$('fullname-input').val()});
|
||||
this.model.save();
|
||||
$(this.el).removeClass('edit-fullname');
|
||||
},
|
||||
|
||||
updateOnEnter: function(e) {
|
||||
if (e.keyCode == 13) this.close();
|
||||
saveOnEnter: function(e) {
|
||||
if (e.keyCode == 13) this.save();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user