rolodex 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +25 -0
  6. data/Rakefile +1 -0
  7. data/karma.conf.js +87 -0
  8. data/lib/rolodex.rb +31 -0
  9. data/lib/rolodex/engine.rb +12 -0
  10. data/lib/rolodex/sass.rb +5 -0
  11. data/lib/rolodex/version.rb +3 -0
  12. data/package.json +33 -0
  13. data/rolodex.gemspec +29 -0
  14. data/spec/javascripts/rolodex_angular/modal.spec.coffee +13 -0
  15. data/spec/spec_helper.rb +0 -0
  16. data/spec/test_lib/angular-mocks.js +2173 -0
  17. data/spec/test_lib/angular.js +21883 -0
  18. data/spec/test_lib/jquery-2.1.1.js +9190 -0
  19. data/spec/test_lib/lodash.js +6785 -0
  20. data/vendor/assets/.keep +0 -0
  21. data/vendor/assets/images/alerts/icon-danger-dark.png +0 -0
  22. data/vendor/assets/images/alerts/icon-danger-dark.svg +9 -0
  23. data/vendor/assets/images/alerts/icon-danger-light.png +0 -0
  24. data/vendor/assets/images/alerts/icon-danger-light.svg +9 -0
  25. data/vendor/assets/images/alerts/icon-flop-dark.png +0 -0
  26. data/vendor/assets/images/alerts/icon-flop-dark.svg +11 -0
  27. data/vendor/assets/images/alerts/icon-flop-light.png +0 -0
  28. data/vendor/assets/images/alerts/icon-flop-light.svg +11 -0
  29. data/vendor/assets/images/alerts/icon-info-dark.png +0 -0
  30. data/vendor/assets/images/alerts/icon-info-dark.svg +9 -0
  31. data/vendor/assets/images/alerts/icon-info-light.png +0 -0
  32. data/vendor/assets/images/alerts/icon-info-light.svg +9 -0
  33. data/vendor/assets/images/alerts/icon-tick-dark.png +0 -0
  34. data/vendor/assets/images/alerts/icon-tick-dark.svg +9 -0
  35. data/vendor/assets/images/alerts/icon-tick-light.png +0 -0
  36. data/vendor/assets/images/alerts/icon-tick-light.svg +9 -0
  37. data/vendor/assets/images/forms/checkbox.png +0 -0
  38. data/vendor/assets/images/forms/checkbox.svg +13 -0
  39. data/vendor/assets/images/forms/icon-calendar.png +0 -0
  40. data/vendor/assets/images/forms/icon-calendar.svg +20 -0
  41. data/vendor/assets/images/forms/icon-search.png +0 -0
  42. data/vendor/assets/images/forms/icon-search.svg +13 -0
  43. data/vendor/assets/images/forms/icon-validating.gif +0 -0
  44. data/vendor/assets/images/forms/icon-validating.psd +0 -0
  45. data/vendor/assets/images/forms/radio-button.png +0 -0
  46. data/vendor/assets/images/forms/radio-button.svg +12 -0
  47. data/vendor/assets/images/icons/icon-caret.png +0 -0
  48. data/vendor/assets/images/icons/icon-caret.svg +24 -0
  49. data/vendor/assets/images/icons/icon-close-x.png +0 -0
  50. data/vendor/assets/images/icons/icon-close-x.svg +9 -0
  51. data/vendor/assets/images/icons/icon-expand-gray.png +0 -0
  52. data/vendor/assets/images/icons/icon-expand-gray.svg +11 -0
  53. data/vendor/assets/images/icons/icon-expand-white.png +0 -0
  54. data/vendor/assets/images/icons/icon-expand-white.svg +11 -0
  55. data/vendor/assets/images/icons/icon-image.png +0 -0
  56. data/vendor/assets/images/icons/icon-image.svg +12 -0
  57. data/vendor/assets/images/icons/icon-invalid.png +0 -0
  58. data/vendor/assets/images/icons/icon-invalid.svg +14 -0
  59. data/vendor/assets/images/icons/icon-plane.png +0 -0
  60. data/vendor/assets/images/icons/icon-plane.svg +15 -0
  61. data/vendor/assets/images/icons/icon-star-banner.png +0 -0
  62. data/vendor/assets/images/icons/icon-star-banner.svg +16 -0
  63. data/vendor/assets/images/icons/icon-suggest.png +0 -0
  64. data/vendor/assets/images/icons/icon-suggest.svg +15 -0
  65. data/vendor/assets/images/icons/icon-tick.png +0 -0
  66. data/vendor/assets/images/icons/icon-tick.svg +9 -0
  67. data/vendor/assets/images/icons/icon-valid.png +0 -0
  68. data/vendor/assets/images/icons/icon-valid.svg +9 -0
  69. data/vendor/assets/images/loading/loading.png +0 -0
  70. data/vendor/assets/images/loading/loading.svg +23 -0
  71. data/vendor/assets/images/logo/belly-logo.png +0 -0
  72. data/vendor/assets/images/logo/belly-logo.svg +19 -0
  73. data/vendor/assets/images/tooltips/tooltip-star.png +0 -0
  74. data/vendor/assets/images/tooltips/tooltip-star.svg +20 -0
  75. data/vendor/assets/javascripts/rolodex_angular.coffee +3 -0
  76. data/vendor/assets/javascripts/rolodex_angular/README.md +68 -0
  77. data/vendor/assets/javascripts/rolodex_angular/rolodex.coffee +11 -0
  78. data/vendor/assets/javascripts/rolodex_angular/src/accordion.coffee +100 -0
  79. data/vendor/assets/javascripts/rolodex_angular/src/alert.coffee +17 -0
  80. data/vendor/assets/javascripts/rolodex_angular/src/buttons.coffee +59 -0
  81. data/vendor/assets/javascripts/rolodex_angular/src/collapse.coffee +65 -0
  82. data/vendor/assets/javascripts/rolodex_angular/src/dateparser.coffee +125 -0
  83. data/vendor/assets/javascripts/rolodex_angular/src/datepicker.coffee +547 -0
  84. data/vendor/assets/javascripts/rolodex_angular/src/dropdown.coffee +143 -0
  85. data/vendor/assets/javascripts/rolodex_angular/src/modal.coffee +331 -0
  86. data/vendor/assets/javascripts/rolodex_angular/src/position.coffee +128 -0
  87. data/vendor/assets/javascripts/rolodex_angular/src/transition.coffee +73 -0
  88. data/vendor/assets/javascripts/rolodex_angular/template/accordion/accordion-group.ngt.haml +7 -0
  89. data/vendor/assets/javascripts/rolodex_angular/template/accordion/accordion.ngt.haml +1 -0
  90. data/vendor/assets/javascripts/rolodex_angular/template/alert/alert.ngt.haml +3 -0
  91. data/vendor/assets/javascripts/rolodex_angular/template/datepicker/datepicker.ngt.haml +4 -0
  92. data/vendor/assets/javascripts/rolodex_angular/template/datepicker/day.ngt.haml +20 -0
  93. data/vendor/assets/javascripts/rolodex_angular/template/datepicker/month.ngt.haml +17 -0
  94. data/vendor/assets/javascripts/rolodex_angular/template/datepicker/popup.ngt.haml +2 -0
  95. data/vendor/assets/javascripts/rolodex_angular/template/datepicker/year.ngt.haml +17 -0
  96. data/vendor/assets/javascripts/rolodex_angular/template/modal/window.ngt.haml +2 -0
  97. data/vendor/assets/javascripts/vendor/jquery-1.10.2.min.js +6 -0
  98. data/vendor/assets/javascripts/vendor/modernizr-2.6.2.min.js +4 -0
  99. data/vendor/assets/stylesheets/rolodex.css.sass +26 -0
  100. data/vendor/assets/stylesheets/rolodex/base/_layout.sass +58 -0
  101. data/vendor/assets/stylesheets/rolodex/base/_typography.sass +123 -0
  102. data/vendor/assets/stylesheets/rolodex/components/_alerts.sass +112 -0
  103. data/vendor/assets/stylesheets/rolodex/components/_buttons.sass +103 -0
  104. data/vendor/assets/stylesheets/rolodex/components/_dropdowns.sass +121 -0
  105. data/vendor/assets/stylesheets/rolodex/components/_forms.sass +326 -0
  106. data/vendor/assets/stylesheets/rolodex/components/_icons.sass +76 -0
  107. data/vendor/assets/stylesheets/rolodex/components/_labels.sass +29 -0
  108. data/vendor/assets/stylesheets/rolodex/components/_lists.sass +15 -0
  109. data/vendor/assets/stylesheets/rolodex/components/_loading.sass +32 -0
  110. data/vendor/assets/stylesheets/rolodex/components/_media.sass +14 -0
  111. data/vendor/assets/stylesheets/rolodex/components/_modals.sass +83 -0
  112. data/vendor/assets/stylesheets/rolodex/components/_tables.sass +9 -0
  113. data/vendor/assets/stylesheets/rolodex/components/_tooltips.sass +123 -0
  114. data/vendor/assets/stylesheets/rolodex/settings/_settings.sass +33 -0
  115. data/vendor/assets/stylesheets/rolodex/settings/mixins/_bump.sass +51 -0
  116. data/vendor/assets/stylesheets/rolodex/settings/mixins/_icons.sass +17 -0
  117. data/vendor/assets/stylesheets/rolodex/settings/mixins/_layout.sass +52 -0
  118. data/vendor/assets/stylesheets/rolodex/settings/mixins/_rems.sass +41 -0
  119. data/vendor/assets/stylesheets/rolodex/settings/mixins/_svg.sass +10 -0
  120. data/vendor/assets/stylesheets/rolodex/settings/mixins/_typography.sass +65 -0
  121. data/vendor/assets/stylesheets/rolodex/settings/utilities/_layout.sass +51 -0
  122. data/vendor/assets/stylesheets/rolodex/settings/utilities/_misc.sass +13 -0
  123. data/vendor/assets/stylesheets/rolodex/settings/utilities/_typography.sass +60 -0
  124. data/vendor/assets/stylesheets/rolodex/settings/variables/_alerts.scss +27 -0
  125. data/vendor/assets/stylesheets/rolodex/settings/variables/_buttons.scss +10 -0
  126. data/vendor/assets/stylesheets/rolodex/settings/variables/_colors.scss +46 -0
  127. data/vendor/assets/stylesheets/rolodex/settings/variables/_labels.scss +10 -0
  128. data/vendor/assets/stylesheets/rolodex/settings/variables/_layout.scss +22 -0
  129. data/vendor/assets/stylesheets/rolodex/settings/variables/_misc.scss +12 -0
  130. data/vendor/assets/stylesheets/rolodex/settings/variables/_typography.scss +34 -0
  131. metadata +263 -0
@@ -0,0 +1,547 @@
1
+ #= require 'rolodex_angular/template/datepicker/datepicker'
2
+ #= require 'rolodex_angular/template/datepicker/day'
3
+ #= require 'rolodex_angular/template/datepicker/month'
4
+ #= require 'rolodex_angular/template/datepicker/popup'
5
+ #= require 'rolodex_angular/template/datepicker/year'
6
+
7
+ angular.module('rolodex.datepicker', [
8
+ 'rolodex.dateparser'
9
+ 'rolodex.dropdown'
10
+ 'rolodex.position'
11
+ ])
12
+
13
+ .constant 'datepickerConfig',
14
+ formatDay: 'd'
15
+ formatMonth: 'MMMM'
16
+ formatYear: 'yyyy'
17
+ formatDayHeader: 'EEE'
18
+ formatDayTitle: 'MMMM yyyy'
19
+ formatMonthTitle: 'yyyy'
20
+ datepickerMode: 'day'
21
+ minMode: 'day'
22
+ maxMode: 'year'
23
+ showWeeks: true
24
+ startingDay: 0
25
+ yearRange: 20
26
+ minDate: null
27
+ maxDate: null
28
+
29
+ .controller 'DatepickerController', [
30
+ '$scope'
31
+ '$attrs'
32
+ '$parse'
33
+ '$interpolate'
34
+ '$timeout'
35
+ '$log'
36
+ 'dateFilter'
37
+ 'datepickerConfig'
38
+ ($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) ->
39
+ self = this
40
+ ngModelCtrl = $setViewValue: angular.noop
41
+ @modes = [
42
+ 'day'
43
+ 'month'
44
+ 'year'
45
+ ]
46
+ angular.forEach [
47
+ 'formatDay'
48
+ 'formatMonth'
49
+ 'formatYear'
50
+ 'formatDayHeader'
51
+ 'formatDayTitle'
52
+ 'formatMonthTitle'
53
+ 'minMode'
54
+ 'maxMode'
55
+ 'showWeeks'
56
+ 'startingDay'
57
+ 'yearRange'
58
+ ], (key, index) ->
59
+ self[key] = (if angular.isDefined($attrs[key]) then ((if index < 8 then $interpolate($attrs[key])($scope.$parent) else $scope.$parent.$eval($attrs[key]))) else datepickerConfig[key])
60
+ return
61
+
62
+ angular.forEach [
63
+ 'minDate'
64
+ 'maxDate'
65
+ ], (key) ->
66
+ if $attrs[key]
67
+ $scope.$parent.$watch $parse($attrs[key]), (value) ->
68
+ self[key] = (if value then new Date(value) else null)
69
+ self.refreshView()
70
+
71
+ else
72
+ self[key] = (if datepickerConfig[key] then new Date(datepickerConfig[key]) else null)
73
+
74
+ $scope.datepickerMode = $scope.datepickerMode or datepickerConfig.datepickerMode
75
+
76
+ $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000)
77
+
78
+ @activeDate = (if angular.isDefined($attrs.initDate) then $scope.$parent.$eval($attrs.initDate) else new Date())
79
+
80
+ @init = (ngModelCtrl_) ->
81
+ ngModelCtrl = ngModelCtrl_
82
+ ngModelCtrl.$render = ->
83
+ self.render()
84
+
85
+ @render = ->
86
+ if ngModelCtrl.$modelValue
87
+ date = new Date(ngModelCtrl.$modelValue)
88
+ isValid = not isNaN(date)
89
+
90
+ if isValid
91
+ @activeDate = date
92
+ else
93
+ $log.error 'Datepicker directive: \'ng-model\' value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'
94
+
95
+ ngModelCtrl.$setValidity 'date', isValid
96
+
97
+ @refreshView()
98
+
99
+ @refreshView = ->
100
+ if @element
101
+ @_refreshView()
102
+ date = (if ngModelCtrl.$modelValue then new Date(ngModelCtrl.$modelValue) else null)
103
+ ngModelCtrl.$setValidity 'date-disabled', not date or (@element and not @isDisabled(date))
104
+
105
+ @createDateObject = (date, format) ->
106
+ model = (if ngModelCtrl.$modelValue then new Date(ngModelCtrl.$modelValue) else null)
107
+ date: date
108
+ label: dateFilter(date, format)
109
+ selected: model and @compare(date, model) is 0
110
+ disabled: @isDisabled(date)
111
+ current: @compare(date, new Date()) is 0
112
+
113
+ @isDisabled = (date) ->
114
+ (@minDate and @compare(date, @minDate) < 0) or (@maxDate and @compare(date, @maxDate) > 0) or ($attrs.dateDisabled and $scope.dateDisabled(date: date, mode: $scope.datepickerMode))
115
+
116
+ @split = (arr, size) ->
117
+ arrays = []
118
+ arrays.push arr.splice(0, size) while arr.length > 0
119
+ arrays
120
+
121
+ $scope.select = (date) =>
122
+ return if @isDisabled(date)
123
+
124
+ if $scope.datepickerMode is self.minMode
125
+ dt = (if ngModelCtrl.$modelValue then new Date(ngModelCtrl.$modelValue) else new Date(0, 0, 0, 0, 0, 0, 0))
126
+ dt.setFullYear date.getFullYear(), date.getMonth(), date.getDate()
127
+ ngModelCtrl.$setViewValue dt
128
+ ngModelCtrl.$render()
129
+ else
130
+ self.activeDate = date
131
+ $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1]
132
+
133
+ $scope.move = (direction) ->
134
+ year = self.activeDate.getFullYear() + direction * (self.step.years or 0)
135
+ month = self.activeDate.getMonth() + direction * (self.step.months or 0)
136
+ self.activeDate.setFullYear year, month, 1
137
+ self.refreshView()
138
+
139
+ $scope.toggleMode = (direction) ->
140
+ direction = direction or 1
141
+ return if ($scope.datepickerMode is self.maxMode and direction is 1) or ($scope.datepickerMode is self.minMode and direction is -1)
142
+ $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction]
143
+
144
+ $scope.keys =
145
+ 13: 'enter'
146
+ 32: 'space'
147
+ 33: 'pageup'
148
+ 34: 'pagedown'
149
+ 35: 'end'
150
+ 36: 'home'
151
+ 37: 'left'
152
+ 38: 'up'
153
+ 39: 'right'
154
+ 40: 'down'
155
+
156
+ focusElement = ->
157
+ $timeout (->
158
+ self.element[0].focus()
159
+ ), 0, false
160
+
161
+ $scope.$on 'datepicker.focus', focusElement
162
+
163
+ $scope.keydown = (evt) ->
164
+ key = $scope.keys[evt.which]
165
+ return if not key or evt.shiftKey or evt.altKey
166
+ evt.preventDefault()
167
+ evt.stopPropagation()
168
+
169
+ if key is 'enter' or key is 'space'
170
+ return if self.isDisabled(self.activeDate)
171
+ $scope.select self.activeDate
172
+ focusElement()
173
+ else if evt.ctrlKey and (key is 'up' or key is 'down')
174
+ $scope.toggleMode (if key is 'up' then 1 else -1)
175
+ focusElement()
176
+ else
177
+ self.handleKeyDown key, evt
178
+ self.refreshView()
179
+
180
+ return this
181
+ ]
182
+
183
+ .directive 'datepicker', ->
184
+ restrict: 'EA'
185
+ replace: true
186
+ templateUrl: 'rolodex_angular/template/datepicker/datepicker'
187
+ scope:
188
+ datepickerMode: '=?'
189
+ dateDisabled: '&'
190
+
191
+ require: [
192
+ 'datepicker'
193
+ '?^ngModel'
194
+ ]
195
+ controller: 'DatepickerController'
196
+ link: (scope, element, attrs, ctrls) ->
197
+ datepickerCtrl = ctrls[0]
198
+ ngModelCtrl = ctrls[1]
199
+ datepickerCtrl.init ngModelCtrl if ngModelCtrl
200
+
201
+ .directive 'daypicker', [
202
+ 'dateFilter'
203
+ (dateFilter) ->
204
+ return (
205
+ restrict: 'EA'
206
+ replace: true
207
+ templateUrl: 'rolodex_angular/template/datepicker/day'
208
+ require: '^datepicker'
209
+ link: (scope, element, attrs, ctrl) ->
210
+ getDaysInMonth = (year, month) ->
211
+ (if ((month is 1) and (year % 4 is 0) and ((year % 100 isnt 0) or (year % 400 is 0))) then 29 else DAYS_IN_MONTH[month])
212
+ getDates = (startDate, n) ->
213
+ dates = new Array(n)
214
+ current = new Date(startDate)
215
+ i = 0
216
+ current.setHours 12
217
+ while i < n
218
+ dates[i++] = new Date(current)
219
+ current.setDate current.getDate() + 1
220
+ dates
221
+ getISO8601WeekNumber = (date) ->
222
+ checkDate = new Date(date)
223
+ checkDate.setDate checkDate.getDate() + 4 - (checkDate.getDay() or 7)
224
+ time = checkDate.getTime()
225
+ checkDate.setMonth 0
226
+ checkDate.setDate 1
227
+ Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1
228
+ scope.showWeeks = ctrl.showWeeks
229
+ ctrl.step = months: 1
230
+ ctrl.element = element
231
+ DAYS_IN_MONTH = [
232
+ 31
233
+ 28
234
+ 31
235
+ 30
236
+ 31
237
+ 30
238
+ 31
239
+ 31
240
+ 30
241
+ 31
242
+ 30
243
+ 31
244
+ ]
245
+ ctrl._refreshView = ->
246
+ year = ctrl.activeDate.getFullYear()
247
+ month = ctrl.activeDate.getMonth()
248
+ firstDayOfMonth = new Date(year, month, 1)
249
+ difference = ctrl.startingDay - firstDayOfMonth.getDay()
250
+ numDisplayedFromPreviousMonth = (if (difference > 0) then 7 - difference else -difference)
251
+ firstDate = new Date(firstDayOfMonth)
252
+ firstDate.setDate -numDisplayedFromPreviousMonth + 1 if numDisplayedFromPreviousMonth > 0
253
+ days = getDates(firstDate, 42)
254
+ i = 0
255
+
256
+ while i < 42
257
+ days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay),
258
+ secondary: days[i].getMonth() isnt month
259
+ uid: scope.uniqueId + '-' + i
260
+ )
261
+ i++
262
+ scope.labels = new Array(7)
263
+ j = 0
264
+
265
+ while j < 7
266
+ scope.labels[j] =
267
+ abbr: dateFilter(days[j].date, ctrl.formatDayHeader).substr(0, 2)
268
+ full: dateFilter(days[j].date, 'EEEE')
269
+ j++
270
+ scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle)
271
+ scope.rows = ctrl.split(days, 7)
272
+ if scope.showWeeks
273
+ scope.weekNumbers = []
274
+ weekNumber = getISO8601WeekNumber(scope.rows[0][0].date)
275
+ numWeeks = scope.rows.length
276
+ continue while scope.weekNumbers.push(weekNumber++) < numWeeks
277
+
278
+ ctrl.compare = (date1, date2) ->
279
+ new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate())
280
+
281
+ ctrl.handleKeyDown = (key, evt) ->
282
+ date = ctrl.activeDate.getDate()
283
+ if key is 'left'
284
+ date = date - 1
285
+ else if key is 'up'
286
+ date = date - 7
287
+ else if key is 'right'
288
+ date = date + 1
289
+ else if key is 'down'
290
+ date = date + 7
291
+ else if key is 'pageup' or key is 'pagedown'
292
+ month = ctrl.activeDate.getMonth() + ((if key is 'pageup' then -1 else 1))
293
+ ctrl.activeDate.setMonth month, 1
294
+ date = Math.min(getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()), date)
295
+ else if key is 'home'
296
+ date = 1
297
+ else date = getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()) if key is 'end'
298
+ ctrl.activeDate.setDate date
299
+
300
+ ctrl.refreshView()
301
+ )
302
+ ]
303
+
304
+ .directive 'monthpicker', [
305
+ 'dateFilter'
306
+ (dateFilter) ->
307
+ return (
308
+ restrict: 'EA'
309
+ replace: true
310
+ templateUrl: 'rolodex_angular/template/datepicker/month'
311
+ require: '^datepicker'
312
+ link: (scope, element, attrs, ctrl) ->
313
+ ctrl.step = years: 1
314
+ ctrl.element = element
315
+ ctrl._refreshView = ->
316
+ months = new Array(12)
317
+ year = ctrl.activeDate.getFullYear()
318
+ i = 0
319
+
320
+ while i < 12
321
+ months[i] = angular.extend(ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth),
322
+ uid: scope.uniqueId + '-' + i
323
+ )
324
+ i++
325
+ scope.title = dateFilter(ctrl.activeDate, ctrl.formatMonthTitle)
326
+ scope.rows = ctrl.split(months, 3)
327
+
328
+ ctrl.compare = (date1, date2) ->
329
+ new Date(date1.getFullYear(), date1.getMonth()) - new Date(date2.getFullYear(), date2.getMonth())
330
+
331
+ ctrl.handleKeyDown = (key, evt) ->
332
+ date = ctrl.activeDate.getMonth()
333
+ if key is 'left'
334
+ date = date - 1
335
+ else if key is 'up'
336
+ date = date - 3
337
+ else if key is 'right'
338
+ date = date + 1
339
+ else if key is 'down'
340
+ date = date + 3
341
+ else if key is 'pageup' or key is 'pagedown'
342
+ year = ctrl.activeDate.getFullYear() + ((if key is 'pageup' then -1 else 1))
343
+ ctrl.activeDate.setFullYear year
344
+ else if key is 'home'
345
+ date = 0
346
+ else date = 11 if key is 'end'
347
+ ctrl.activeDate.setMonth date
348
+
349
+ ctrl.refreshView()
350
+ )
351
+ ]
352
+
353
+ .directive 'yearpicker', [
354
+ 'dateFilter'
355
+ (dateFilter) ->
356
+ return (
357
+ restrict: 'EA'
358
+ replace: true
359
+ templateUrl: 'rolodex_angular/template/datepicker/year'
360
+ require: '^datepicker'
361
+ link: (scope, element, attrs, ctrl) ->
362
+ getStartingYear = (year) ->
363
+ parseInt((year - 1) / range, 10) * range + 1
364
+ range = ctrl.yearRange
365
+ ctrl.step = years: range
366
+ ctrl.element = element
367
+ ctrl._refreshView = ->
368
+ years = new Array(range)
369
+ i = 0
370
+ start = getStartingYear(ctrl.activeDate.getFullYear())
371
+
372
+ while i < range
373
+ years[i] = angular.extend(ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear),
374
+ uid: scope.uniqueId + '-' + i
375
+ )
376
+ i++
377
+ scope.title = [
378
+ years[0].label
379
+ years[range - 1].label
380
+ ].join(' - ')
381
+ scope.rows = ctrl.split(years, 5)
382
+
383
+ ctrl.compare = (date1, date2) ->
384
+ date1.getFullYear() - date2.getFullYear()
385
+
386
+ ctrl.handleKeyDown = (key, evt) ->
387
+ date = ctrl.activeDate.getFullYear()
388
+ if key is 'left'
389
+ date = date - 1
390
+ else if key is 'up'
391
+ date = date - 5
392
+ else if key is 'right'
393
+ date = date + 1
394
+ else if key is 'down'
395
+ date = date + 5
396
+ else if key is 'pageup' or key is 'pagedown'
397
+ date += ((if key is 'pageup' then -1 else 1)) * ctrl.step.years
398
+ else if key is 'home'
399
+ date = getStartingYear(ctrl.activeDate.getFullYear())
400
+ else date = getStartingYear(ctrl.activeDate.getFullYear()) + range - 1 if key is 'end'
401
+ ctrl.activeDate.setFullYear date
402
+
403
+ ctrl.refreshView()
404
+ )
405
+ ]
406
+
407
+ .constant 'datepickerPopupConfig',
408
+ datepickerPopup: 'yyyy-MM-dd'
409
+ currentText: 'Today'
410
+ clearText: 'Clear'
411
+ closeText: 'Done'
412
+ closeOnDateSelection: true
413
+ appendToBody: false
414
+ showButtonBar: true
415
+
416
+ .directive 'datepickerPopup', [
417
+ '$compile'
418
+ '$parse'
419
+ '$document'
420
+ 'dateFilter'
421
+ 'dateParser'
422
+ 'datepickerPopupConfig'
423
+ 'dropdownService'
424
+ ($compile, $parse, $document, dateFilter, dateParser, datepickerPopupConfig, dropdownService) ->
425
+ return (
426
+ restrict: 'EA'
427
+ require: 'ngModel'
428
+ scope:
429
+ isOpen: '=?'
430
+ currentText: '@'
431
+ clearText: '@'
432
+ closeText: '@'
433
+ dateDisabled: '&'
434
+
435
+ link: (scope, element, attrs, ngModel) ->
436
+
437
+ cameltoDash = (string) ->
438
+ string.replace /([A-Z])/g, ($1) ->
439
+ '-' + $1.toLowerCase()
440
+
441
+ parseDate = (viewValue) ->
442
+ unless viewValue
443
+ ngModel.$setValidity 'date', true
444
+ null
445
+ else if angular.isDate(viewValue) and not isNaN(viewValue)
446
+ ngModel.$setValidity 'date', true
447
+ viewValue
448
+ else if angular.isString(viewValue)
449
+ date = dateParser.parse(viewValue, dateFormat) or new Date(viewValue)
450
+ if isNaN(date)
451
+ ngModel.$setValidity 'date', false
452
+ `undefined`
453
+ else
454
+ ngModel.$setValidity 'date', true
455
+ date
456
+ else
457
+ ngModel.$setValidity 'date', false
458
+ `undefined`
459
+ dateFormat = undefined
460
+ closeOnDateSelection = (if angular.isDefined(attrs.closeOnDateSelection) then scope.$parent.$eval(attrs.closeOnDateSelection) else datepickerPopupConfig.closeOnDateSelection)
461
+ appendToBody = (if angular.isDefined(attrs.datepickerAppendToBody) then scope.$parent.$eval(attrs.datepickerAppendToBody) else datepickerPopupConfig.appendToBody)
462
+ scope.showButtonBar = (if angular.isDefined(attrs.showButtonBar) then scope.$parent.$eval(attrs.showButtonBar) else datepickerPopupConfig.showButtonBar)
463
+ scope.getText = (key) ->
464
+ scope[key + 'Text'] or datepickerPopupConfig[key + 'Text']
465
+
466
+ attrs.$observe 'datepickerPopup', (value) ->
467
+ dateFormat = value or datepickerPopupConfig.datepickerPopup
468
+ ngModel.$render()
469
+
470
+ popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>')
471
+ popupEl.attr
472
+ 'ng-model': 'date'
473
+ 'ng-change': 'dateSelection()'
474
+
475
+ datepickerEl = angular.element(popupEl.children()[0])
476
+
477
+ if attrs.datepickerOptions
478
+ angular.forEach scope.$parent.$eval(attrs.datepickerOptions), (value, option) ->
479
+ datepickerEl.attr cameltoDash(option), value
480
+
481
+ scope.watchData = {}
482
+ angular.forEach [
483
+ 'minDate'
484
+ 'maxDate'
485
+ 'datepickerMode'
486
+ ], (key) ->
487
+ if attrs[key]
488
+ getAttribute = $parse(attrs[key])
489
+
490
+ scope.$parent.$watch getAttribute, (value) ->
491
+ scope.watchData[key] = value
492
+
493
+ datepickerEl.attr cameltoDash(key), 'watchData.' + key
494
+ if key is 'datepickerMode'
495
+ setAttribute = getAttribute.assign
496
+ scope.$watch 'watchData.' + key, (value, oldvalue) ->
497
+ setAttribute scope.$parent, value if value isnt oldvalue
498
+
499
+ datepickerEl.attr 'date-disabled', 'dateDisabled({ date: date, mode: mode })' if attrs.dateDisabled
500
+ ngModel.$parsers.unshift parseDate
501
+ scope.dateSelection = (dt) ->
502
+ scope.date = dt if angular.isDefined(dt)
503
+ ngModel.$setViewValue scope.date
504
+ ngModel.$render()
505
+ if closeOnDateSelection
506
+ scope.isOpen = false
507
+ scope.forceClose = true
508
+ dropdownService.close(scope)
509
+ element[0].focus()
510
+
511
+ element.bind 'input change keyup', ->
512
+ scope.$apply ->
513
+ scope.date = ngModel.$modelValue
514
+
515
+ ngModel.$render = ->
516
+ date = (if ngModel.$viewValue then dateFilter(ngModel.$viewValue, dateFormat) else '')
517
+ element.val date
518
+ scope.date = parseDate(ngModel.$modelValue)
519
+
520
+ scope.select = (date) ->
521
+
522
+ if date is 'today'
523
+ today = new Date()
524
+ if angular.isDate(ngModel.$modelValue)
525
+ date = new Date(ngModel.$modelValue)
526
+ date.setFullYear today.getFullYear(), today.getMonth(), today.getDate()
527
+ else
528
+ date = new Date(today.setHours(0, 0, 0, 0))
529
+ scope.dateSelection date
530
+ $popup = $compile(popupEl)(scope)
531
+ if appendToBody
532
+ $document.find('body').append $popup
533
+ else
534
+ element.after $popup
535
+ scope.$on '$destroy', ->
536
+ $popup.remove()
537
+ )
538
+ ]
539
+ .directive 'datepickerPopupWrap', ->
540
+ restrict: 'EA'
541
+ replace: true
542
+ transclude: true
543
+ templateUrl: 'rolodex_angular/template/datepicker/popup'
544
+ link: (scope, element, attrs) ->
545
+ element.bind 'click', (event) ->
546
+ event.preventDefault()
547
+ event.stopPropagation()