watch_tower 0.0.0.1 → 0.0.1.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.todo +3 -0
- data/.travis.yml +4 -0
- data/Gemfile +0 -4
- data/README.md +48 -2
- data/TODO +3 -0
- data/ci/travis.rb +4 -1
- data/lib/watch_tower/appscript.rb +65 -7
- data/lib/watch_tower/cli/install.rb +27 -3
- data/lib/watch_tower/cli/open.rb +2 -0
- data/lib/watch_tower/cli/start.rb +3 -1
- data/lib/watch_tower/cli.rb +2 -0
- data/lib/watch_tower/config.rb +2 -0
- data/lib/watch_tower/core_ext.rb +2 -0
- data/lib/watch_tower/editor/base_appscript.rb +28 -1
- data/lib/watch_tower/editor/base_ps.rb +25 -0
- data/lib/watch_tower/editor/textmate.rb +2 -0
- data/lib/watch_tower/editor/xcode.rb +2 -0
- data/lib/watch_tower/editor.rb +2 -0
- data/lib/watch_tower/errors.rb +2 -0
- data/lib/watch_tower/eye.rb +13 -2
- data/lib/watch_tower/file_tree.rb +78 -0
- data/lib/watch_tower/project/any_based.rb +2 -0
- data/lib/watch_tower/project/git_based.rb +2 -0
- data/lib/watch_tower/project/init.rb +2 -0
- data/lib/watch_tower/project/path_based.rb +2 -0
- data/lib/watch_tower/project.rb +2 -0
- data/lib/watch_tower/server/app.rb +37 -7
- data/lib/watch_tower/server/assets/javascripts/application.js +4 -0
- data/lib/watch_tower/server/assets/javascripts/datepicker.coffee +21 -0
- data/lib/watch_tower/server/assets/javascripts/file_tree.coffee +30 -0
- data/lib/watch_tower/server/assets/javascripts/percentage.coffee +15 -5
- data/lib/watch_tower/server/assets/stylesheets/application.css +1 -0
- data/lib/watch_tower/server/assets/stylesheets/date.sass +17 -0
- data/lib/watch_tower/server/assets/stylesheets/file_tree.sass +42 -0
- data/lib/watch_tower/server/assets/stylesheets/global.sass +7 -4
- data/lib/watch_tower/server/configurations/asset.rb +2 -0
- data/lib/watch_tower/server/configurations.rb +2 -0
- data/lib/watch_tower/server/database.rb +2 -0
- data/lib/watch_tower/server/db/migrate/001_create_projects.rb +2 -0
- data/lib/watch_tower/server/db/migrate/002_create_files.rb +2 -0
- data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +2 -0
- data/lib/watch_tower/server/db/migrate/004_create_durations.rb +2 -0
- data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +2 -0
- data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +2 -0
- data/lib/watch_tower/server/db/migrate/007_add_editor_to_times_entries.rb +8 -0
- data/lib/watch_tower/server/db/migrate/008_rename_editor_to_editor_name_in_times_entries.rb +5 -0
- data/lib/watch_tower/server/db/migrate/009_remove_editor_index_from_time_entries.rb +7 -0
- data/lib/watch_tower/server/db/migrate/010_add_editor_version_to_times_entries.rb +7 -0
- data/lib/watch_tower/server/helpers/asset.rb +2 -0
- data/lib/watch_tower/server/helpers/improved_partials.rb +2 -0
- data/lib/watch_tower/server/helpers/presenters.rb +33 -0
- data/lib/watch_tower/server/helpers.rb +3 -0
- data/lib/watch_tower/server/models/duration.rb +9 -0
- data/lib/watch_tower/server/models/file.rb +17 -0
- data/lib/watch_tower/server/models/project.rb +30 -0
- data/lib/watch_tower/server/models/time_entry.rb +5 -0
- data/lib/watch_tower/server/presenters/application_presenter.rb +165 -0
- data/lib/watch_tower/server/presenters/file_presenter.rb +10 -0
- data/lib/watch_tower/server/presenters/project_presenter.rb +20 -0
- data/lib/watch_tower/server/presenters.rb +13 -0
- data/lib/watch_tower/server/public/assets/{WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg → WatchTower-58eff0713efffbc6054defddc879e0b1.jpg} +0 -0
- data/lib/watch_tower/server/public/assets/application-4e6971066e06aa53b0c8e52c764044d1.css +389 -0
- data/lib/watch_tower/server/public/assets/application-6a1be75d4fd6a545faceb638e47a2486.js +23778 -0
- data/lib/watch_tower/server/public/assets/calendar-379834cd6e6321a940b662ace47f3032.gif +0 -0
- data/lib/watch_tower/server/public/assets/calendar-blue-d6aa74feef7ee4287532761db99a6c0a.gif +0 -0
- data/lib/watch_tower/server/public/assets/calendar-green-3752fe2996091379c8d321f759039385.gif +0 -0
- data/lib/watch_tower/server/public/assets/jquery.datepick-9c8dfe3a4d40bcafc7b182e194c13836.css +227 -0
- data/lib/watch_tower/server/public/assets/{percentage-d8589e21a5fc85d32a445f531ff8ab95.png → percentage-d0176e99520c95e93eee63738ef5d487.png} +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar-blue.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar-green.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-ext.js +266 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-validation.js +232 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick.js +2092 -0
- data/lib/watch_tower/server/vendor/assets/stylesheets/jquery.datepick.css +226 -0
- data/lib/watch_tower/server/views/_project.haml +10 -13
- data/lib/watch_tower/server/views/index.haml +9 -6
- data/lib/watch_tower/server/views/layout.haml +7 -4
- data/lib/watch_tower/server/views/project.haml +9 -11
- data/lib/watch_tower/server.rb +8 -1
- data/lib/watch_tower/templates/{watchtower.plist → watchtower.plist.erb} +5 -6
- data/lib/watch_tower/version.rb +12 -3
- data/lib/watch_tower.rb +20 -1
- data/spec/factories.rb +2 -0
- data/spec/watch_tower/appscript_spec.rb +36 -2
- data/spec/watch_tower/editor/base_appscript_spec.rb +83 -0
- data/spec/watch_tower/editor/textmate_spec.rb +37 -0
- data/spec/watch_tower/editor/xcode_spec.rb +6 -0
- data/spec/watch_tower/eye_spec.rb +21 -0
- data/spec/watch_tower/file_tree_spec.rb +156 -0
- data/spec/watch_tower/server/app_spec.rb +64 -20
- data/spec/watch_tower/server/models/file_spec.rb +93 -31
- data/spec/watch_tower/server/models/project_spec.rb +147 -18
- data/spec/watch_tower/server/models/time_entry_spec.rb +10 -0
- data/spec/watch_tower/server/{decorator/project_decorator_spec.rb → presenters/application_presenter_spec.rb} +24 -13
- data/spec/watch_tower/server/presenters/file_presenter_spec.rb +8 -0
- data/spec/watch_tower/server/presenters/project_presenter_spec.rb +130 -0
- data/watch_tower.gemspec +10 -4
- metadata +114 -74
- data/lib/watch_tower/server/decorator/application_decorator.rb +0 -91
- data/lib/watch_tower/server/decorator/file_decorator.rb +0 -38
- data/lib/watch_tower/server/decorator/project_decorator.rb +0 -51
- data/lib/watch_tower/server/decorator.rb +0 -21
- data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +0 -107
- data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +0 -9359
- data/lib/watch_tower/server/views/_file.haml +0 -9
@@ -0,0 +1,232 @@
|
|
1
|
+
/* http://keith-wood.name/datepick.html
|
2
|
+
Datepicker Validation extension for jQuery 4.0.6.
|
3
|
+
Requires Jörn Zaefferer's Validation plugin (http://plugins.jquery.com/project/validate).
|
4
|
+
Written by Keith Wood (kbwood{at}iinet.com.au).
|
5
|
+
Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
|
6
|
+
MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
|
7
|
+
Please attribute the author if you use it. */
|
8
|
+
|
9
|
+
(function($) { // Hide the namespace
|
10
|
+
|
11
|
+
/* Add validation methods if validation plugin available. */
|
12
|
+
if ($.fn.validate) {
|
13
|
+
|
14
|
+
$.datepick.selectDateOrig = $.datepick.selectDate;
|
15
|
+
|
16
|
+
$.extend($.datepick.regional[''], {
|
17
|
+
validateDate: 'Please enter a valid date',
|
18
|
+
validateDateMin: 'Please enter a date on or after {0}',
|
19
|
+
validateDateMax: 'Please enter a date on or before {0}',
|
20
|
+
validateDateMinMax: 'Please enter a date between {0} and {1}',
|
21
|
+
validateDateCompare: 'Please enter a date {0} {1}',
|
22
|
+
validateDateToday: 'today',
|
23
|
+
validateDateOther: 'the other date',
|
24
|
+
validateDateEQ: 'equal to',
|
25
|
+
validateDateNE: 'not equal to',
|
26
|
+
validateDateLT: 'before',
|
27
|
+
validateDateGT: 'after',
|
28
|
+
validateDateLE: 'not after',
|
29
|
+
validateDateGE: 'not before'
|
30
|
+
});
|
31
|
+
|
32
|
+
$.extend($.datepick._defaults, $.datepick.regional['']);
|
33
|
+
|
34
|
+
$.extend($.datepick, {
|
35
|
+
|
36
|
+
/* Trigger a validation after updating the input field with the selected date.
|
37
|
+
@param target (element) the control to examine
|
38
|
+
@param elem (element) the selected datepicker element */
|
39
|
+
selectDate: function(target, elem) {
|
40
|
+
this.selectDateOrig(target, elem);
|
41
|
+
var inst = $.data(target, $.datepick.dataName);
|
42
|
+
if (!inst.inline && $.fn.validate) {
|
43
|
+
var validation = $(target).parents('form').validate();
|
44
|
+
if (validation) {
|
45
|
+
validation.element('#' + target.id);
|
46
|
+
}
|
47
|
+
}
|
48
|
+
},
|
49
|
+
|
50
|
+
/* Correct error placement for validation errors - after any trigger.
|
51
|
+
@param error (jQuery) the error message
|
52
|
+
@param element (jQuery) the field in error */
|
53
|
+
errorPlacement: function(error, element) {
|
54
|
+
var inst = $.data(element[0], $.datepick.dataName);
|
55
|
+
if (inst) {
|
56
|
+
error[inst.get('isRTL') ? 'insertBefore' : 'insertAfter'](
|
57
|
+
inst.trigger.length > 0 ? inst.trigger : element);
|
58
|
+
}
|
59
|
+
else {
|
60
|
+
error.insertAfter(element);
|
61
|
+
}
|
62
|
+
},
|
63
|
+
|
64
|
+
/* Format a validation error message involving dates.
|
65
|
+
@param source (string) the error message
|
66
|
+
@param params (Date[]) the dates
|
67
|
+
@return (string) the formatted message */
|
68
|
+
errorFormat: function(source, params) {
|
69
|
+
var format = ($.datepick.curInst ?
|
70
|
+
$.datepick.curInst.get('dateFormat') :
|
71
|
+
$.datepick._defaults.dateFormat);
|
72
|
+
$.each(params, function(index, value) {
|
73
|
+
source = source.replace(new RegExp('\\{' + index + '\\}', 'g'),
|
74
|
+
$.datepick.formatDate(format, value) || 'nothing');
|
75
|
+
});
|
76
|
+
return source;
|
77
|
+
}
|
78
|
+
});
|
79
|
+
|
80
|
+
var lastElement = null;
|
81
|
+
|
82
|
+
/* Validate date field. */
|
83
|
+
$.validator.addMethod('dpDate', function(value, element) {
|
84
|
+
lastElement = element;
|
85
|
+
return this.optional(element) || validateEach(value, element);
|
86
|
+
},
|
87
|
+
function(params) {
|
88
|
+
var inst = $.data(lastElement, $.datepick.dataName);
|
89
|
+
var minDate = inst.get('minDate');
|
90
|
+
var maxDate = inst.get('maxDate');
|
91
|
+
var messages = $.datepick._defaults;
|
92
|
+
return (minDate && maxDate ?
|
93
|
+
$.datepick.errorFormat(messages.validateDateMinMax, [minDate, maxDate]) :
|
94
|
+
(minDate ? $.datepick.errorFormat(messages.validateDateMin, [minDate]) :
|
95
|
+
(maxDate ? $.datepick.errorFormat(messages.validateDateMax, [maxDate]) :
|
96
|
+
messages.validateDate)));
|
97
|
+
});
|
98
|
+
|
99
|
+
/* Apply a validation test to each date provided.
|
100
|
+
@param value (string) the current field value
|
101
|
+
@param element (element) the field control
|
102
|
+
@return (boolean) true if OK, false if failed validation */
|
103
|
+
function validateEach(value, element) {
|
104
|
+
var inst = $.data(element, $.datepick.dataName);
|
105
|
+
var rangeSelect = inst.get('rangeSelect');
|
106
|
+
var multiSelect = inst.get('multiSelect');
|
107
|
+
var dates = (multiSelect ? value.split(inst.get('multiSeparator')) :
|
108
|
+
(rangeSelect ? value.split(inst.get('rangeSeparator')) : [value]));
|
109
|
+
var ok = (multiSelect && dates.length <= multiSelect) ||
|
110
|
+
(!multiSelect && rangeSelect && dates.length == 2) ||
|
111
|
+
(!multiSelect && !rangeSelect && dates.length == 1);
|
112
|
+
if (ok) {
|
113
|
+
try {
|
114
|
+
var dateFormat = inst.get('dateFormat');
|
115
|
+
var minDate = inst.get('minDate');
|
116
|
+
var maxDate = inst.get('maxDate');
|
117
|
+
var dp = $(element);
|
118
|
+
$.each(dates, function(i, v) {
|
119
|
+
dates[i] = $.datepick.parseDate(dateFormat, v);
|
120
|
+
ok = ok && (!dates[i] || (dp.datepick('isSelectable', dates[i]) &&
|
121
|
+
(!minDate || dates[i].getTime() >= minDate.getTime()) &&
|
122
|
+
(!maxDate || dates[i].getTime() <= maxDate.getTime())));
|
123
|
+
});
|
124
|
+
}
|
125
|
+
catch (e) {
|
126
|
+
ok = false;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
if (ok && rangeSelect) {
|
130
|
+
ok = (dates[0].getTime() <= dates[1].getTime());
|
131
|
+
}
|
132
|
+
return ok;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* And allow as a class rule. */
|
136
|
+
$.validator.addClassRules('dpDate', {dpDate: true});
|
137
|
+
|
138
|
+
var comparisons = {equal: 'eq', same: 'eq', notEqual: 'ne', notSame: 'ne',
|
139
|
+
lessThan: 'lt', before: 'lt', greaterThan: 'gt', after: 'gt',
|
140
|
+
notLessThan: 'ge', notBefore: 'ge', notGreaterThan: 'le', notAfter: 'le'};
|
141
|
+
|
142
|
+
/* Cross-validate date fields.
|
143
|
+
params should be an array with [0] comparison type eq/ne/lt/gt/le/ge or synonyms,
|
144
|
+
[1] 'today' or date string or Date or other field selector/element/jQuery OR
|
145
|
+
an object with one attribute with name eq/ne/lt/gt/le/ge or synonyms
|
146
|
+
and value 'today' or date string or Date or other field selector/element/jQuery OR
|
147
|
+
a string with eq/ne/lt/gt/le/ge or synonyms followed by 'today' or date string or jQuery selector */
|
148
|
+
$.validator.addMethod('dpCompareDate', function(value, element, params) {
|
149
|
+
if (this.optional(element)) {
|
150
|
+
return true;
|
151
|
+
}
|
152
|
+
params = normaliseParams(params);
|
153
|
+
var thisDate = $(element).datepick('getDate');
|
154
|
+
var thatDate = extractOtherDate(element, params[1]);
|
155
|
+
if (thisDate.length == 0 || thatDate.length == 0) {
|
156
|
+
return true;
|
157
|
+
}
|
158
|
+
lastElement = element;
|
159
|
+
var finalResult = true;
|
160
|
+
for (var i = 0; i < thisDate.length; i++) {
|
161
|
+
switch (comparisons[params[0]] || params[0]) {
|
162
|
+
case 'eq': finalResult = (thisDate[i].getTime() == thatDate[0].getTime()); break;
|
163
|
+
case 'ne': finalResult = (thisDate[i].getTime() != thatDate[0].getTime()); break;
|
164
|
+
case 'lt': finalResult = (thisDate[i].getTime() < thatDate[0].getTime()); break;
|
165
|
+
case 'gt': finalResult = (thisDate[i].getTime() > thatDate[0].getTime()); break;
|
166
|
+
case 'le': finalResult = (thisDate[i].getTime() <= thatDate[0].getTime()); break;
|
167
|
+
case 'ge': finalResult = (thisDate[i].getTime() >= thatDate[0].getTime()); break;
|
168
|
+
default: finalResult = true;
|
169
|
+
}
|
170
|
+
if (!finalResult) {
|
171
|
+
break;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
return finalResult;
|
175
|
+
},
|
176
|
+
function(params) {
|
177
|
+
var messages = $.datepick._defaults;
|
178
|
+
var inst = $.data(lastElement, $.datepick.dataName);
|
179
|
+
params = normaliseParams(params);
|
180
|
+
var thatDate = extractOtherDate(lastElement, params[1], true);
|
181
|
+
thatDate = (params[1] == 'today' ? messages.validateDateToday : (thatDate.length ?
|
182
|
+
$.datepick.formatDate(inst.get('dateFormat'), thatDate[0], inst.getConfig()) :
|
183
|
+
messages.validateDateOther));
|
184
|
+
return messages.validateDateCompare.replace(/\{0\}/,
|
185
|
+
messages['validateDate' + (comparisons[params[0]] || params[0]).toUpperCase()]).
|
186
|
+
replace(/\{1\}/, thatDate);
|
187
|
+
});
|
188
|
+
|
189
|
+
/* Normalise the comparison parameters to an array.
|
190
|
+
@param params (array or object or string) the original parameters
|
191
|
+
@return (array) the normalised parameters */
|
192
|
+
function normaliseParams(params) {
|
193
|
+
if (typeof params == 'string') {
|
194
|
+
params = params.split(' ');
|
195
|
+
}
|
196
|
+
else if (!$.isArray(params)) {
|
197
|
+
var opts = [];
|
198
|
+
for (var name in params) {
|
199
|
+
opts[0] = name;
|
200
|
+
opts[1] = params[name];
|
201
|
+
}
|
202
|
+
params = opts;
|
203
|
+
}
|
204
|
+
return params;
|
205
|
+
}
|
206
|
+
|
207
|
+
/* Determine the comparison date.
|
208
|
+
@param element (element) the current datepicker element
|
209
|
+
@param source (string or Date or jQuery or element) the source of the other date
|
210
|
+
@param noOther (boolean) true to not get the date from another field
|
211
|
+
@return (Date[1]) the date for comparison */
|
212
|
+
function extractOtherDate(element, source, noOther) {
|
213
|
+
if (source.constructor == Date) {
|
214
|
+
return [source];
|
215
|
+
}
|
216
|
+
var inst = $.data(element, $.datepick.dataName);
|
217
|
+
var thatDate = null;
|
218
|
+
try {
|
219
|
+
if (typeof source == 'string' && source != 'today') {
|
220
|
+
thatDate = $.datepick.parseDate(inst.get('dateFormat'), source, inst.getConfig());
|
221
|
+
}
|
222
|
+
}
|
223
|
+
catch (e) {
|
224
|
+
// Ignore
|
225
|
+
}
|
226
|
+
thatDate = (thatDate ? [thatDate] : (source == 'today' ?
|
227
|
+
[$.datepick.today()] : (noOther ? [] : $(source).datepick('getDate'))));
|
228
|
+
return thatDate;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
})(jQuery);
|