watch_tower 0.0.0.1 → 0.0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|