rolodex 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/karma.conf.js +87 -0
- data/lib/rolodex.rb +31 -0
- data/lib/rolodex/engine.rb +12 -0
- data/lib/rolodex/sass.rb +5 -0
- data/lib/rolodex/version.rb +3 -0
- data/package.json +33 -0
- data/rolodex.gemspec +29 -0
- data/spec/javascripts/rolodex_angular/modal.spec.coffee +13 -0
- data/spec/spec_helper.rb +0 -0
- data/spec/test_lib/angular-mocks.js +2173 -0
- data/spec/test_lib/angular.js +21883 -0
- data/spec/test_lib/jquery-2.1.1.js +9190 -0
- data/spec/test_lib/lodash.js +6785 -0
- data/vendor/assets/.keep +0 -0
- data/vendor/assets/images/alerts/icon-danger-dark.png +0 -0
- data/vendor/assets/images/alerts/icon-danger-dark.svg +9 -0
- data/vendor/assets/images/alerts/icon-danger-light.png +0 -0
- data/vendor/assets/images/alerts/icon-danger-light.svg +9 -0
- data/vendor/assets/images/alerts/icon-flop-dark.png +0 -0
- data/vendor/assets/images/alerts/icon-flop-dark.svg +11 -0
- data/vendor/assets/images/alerts/icon-flop-light.png +0 -0
- data/vendor/assets/images/alerts/icon-flop-light.svg +11 -0
- data/vendor/assets/images/alerts/icon-info-dark.png +0 -0
- data/vendor/assets/images/alerts/icon-info-dark.svg +9 -0
- data/vendor/assets/images/alerts/icon-info-light.png +0 -0
- data/vendor/assets/images/alerts/icon-info-light.svg +9 -0
- data/vendor/assets/images/alerts/icon-tick-dark.png +0 -0
- data/vendor/assets/images/alerts/icon-tick-dark.svg +9 -0
- data/vendor/assets/images/alerts/icon-tick-light.png +0 -0
- data/vendor/assets/images/alerts/icon-tick-light.svg +9 -0
- data/vendor/assets/images/forms/checkbox.png +0 -0
- data/vendor/assets/images/forms/checkbox.svg +13 -0
- data/vendor/assets/images/forms/icon-calendar.png +0 -0
- data/vendor/assets/images/forms/icon-calendar.svg +20 -0
- data/vendor/assets/images/forms/icon-search.png +0 -0
- data/vendor/assets/images/forms/icon-search.svg +13 -0
- data/vendor/assets/images/forms/icon-validating.gif +0 -0
- data/vendor/assets/images/forms/icon-validating.psd +0 -0
- data/vendor/assets/images/forms/radio-button.png +0 -0
- data/vendor/assets/images/forms/radio-button.svg +12 -0
- data/vendor/assets/images/icons/icon-caret.png +0 -0
- data/vendor/assets/images/icons/icon-caret.svg +24 -0
- data/vendor/assets/images/icons/icon-close-x.png +0 -0
- data/vendor/assets/images/icons/icon-close-x.svg +9 -0
- data/vendor/assets/images/icons/icon-expand-gray.png +0 -0
- data/vendor/assets/images/icons/icon-expand-gray.svg +11 -0
- data/vendor/assets/images/icons/icon-expand-white.png +0 -0
- data/vendor/assets/images/icons/icon-expand-white.svg +11 -0
- data/vendor/assets/images/icons/icon-image.png +0 -0
- data/vendor/assets/images/icons/icon-image.svg +12 -0
- data/vendor/assets/images/icons/icon-invalid.png +0 -0
- data/vendor/assets/images/icons/icon-invalid.svg +14 -0
- data/vendor/assets/images/icons/icon-plane.png +0 -0
- data/vendor/assets/images/icons/icon-plane.svg +15 -0
- data/vendor/assets/images/icons/icon-star-banner.png +0 -0
- data/vendor/assets/images/icons/icon-star-banner.svg +16 -0
- data/vendor/assets/images/icons/icon-suggest.png +0 -0
- data/vendor/assets/images/icons/icon-suggest.svg +15 -0
- data/vendor/assets/images/icons/icon-tick.png +0 -0
- data/vendor/assets/images/icons/icon-tick.svg +9 -0
- data/vendor/assets/images/icons/icon-valid.png +0 -0
- data/vendor/assets/images/icons/icon-valid.svg +9 -0
- data/vendor/assets/images/loading/loading.png +0 -0
- data/vendor/assets/images/loading/loading.svg +23 -0
- data/vendor/assets/images/logo/belly-logo.png +0 -0
- data/vendor/assets/images/logo/belly-logo.svg +19 -0
- data/vendor/assets/images/tooltips/tooltip-star.png +0 -0
- data/vendor/assets/images/tooltips/tooltip-star.svg +20 -0
- data/vendor/assets/javascripts/rolodex_angular.coffee +3 -0
- data/vendor/assets/javascripts/rolodex_angular/README.md +68 -0
- data/vendor/assets/javascripts/rolodex_angular/rolodex.coffee +11 -0
- data/vendor/assets/javascripts/rolodex_angular/src/accordion.coffee +100 -0
- data/vendor/assets/javascripts/rolodex_angular/src/alert.coffee +17 -0
- data/vendor/assets/javascripts/rolodex_angular/src/buttons.coffee +59 -0
- data/vendor/assets/javascripts/rolodex_angular/src/collapse.coffee +65 -0
- data/vendor/assets/javascripts/rolodex_angular/src/dateparser.coffee +125 -0
- data/vendor/assets/javascripts/rolodex_angular/src/datepicker.coffee +547 -0
- data/vendor/assets/javascripts/rolodex_angular/src/dropdown.coffee +143 -0
- data/vendor/assets/javascripts/rolodex_angular/src/modal.coffee +331 -0
- data/vendor/assets/javascripts/rolodex_angular/src/position.coffee +128 -0
- data/vendor/assets/javascripts/rolodex_angular/src/transition.coffee +73 -0
- data/vendor/assets/javascripts/rolodex_angular/template/accordion/accordion-group.ngt.haml +7 -0
- data/vendor/assets/javascripts/rolodex_angular/template/accordion/accordion.ngt.haml +1 -0
- data/vendor/assets/javascripts/rolodex_angular/template/alert/alert.ngt.haml +3 -0
- data/vendor/assets/javascripts/rolodex_angular/template/datepicker/datepicker.ngt.haml +4 -0
- data/vendor/assets/javascripts/rolodex_angular/template/datepicker/day.ngt.haml +20 -0
- data/vendor/assets/javascripts/rolodex_angular/template/datepicker/month.ngt.haml +17 -0
- data/vendor/assets/javascripts/rolodex_angular/template/datepicker/popup.ngt.haml +2 -0
- data/vendor/assets/javascripts/rolodex_angular/template/datepicker/year.ngt.haml +17 -0
- data/vendor/assets/javascripts/rolodex_angular/template/modal/window.ngt.haml +2 -0
- data/vendor/assets/javascripts/vendor/jquery-1.10.2.min.js +6 -0
- data/vendor/assets/javascripts/vendor/modernizr-2.6.2.min.js +4 -0
- data/vendor/assets/stylesheets/rolodex.css.sass +26 -0
- data/vendor/assets/stylesheets/rolodex/base/_layout.sass +58 -0
- data/vendor/assets/stylesheets/rolodex/base/_typography.sass +123 -0
- data/vendor/assets/stylesheets/rolodex/components/_alerts.sass +112 -0
- data/vendor/assets/stylesheets/rolodex/components/_buttons.sass +103 -0
- data/vendor/assets/stylesheets/rolodex/components/_dropdowns.sass +121 -0
- data/vendor/assets/stylesheets/rolodex/components/_forms.sass +326 -0
- data/vendor/assets/stylesheets/rolodex/components/_icons.sass +76 -0
- data/vendor/assets/stylesheets/rolodex/components/_labels.sass +29 -0
- data/vendor/assets/stylesheets/rolodex/components/_lists.sass +15 -0
- data/vendor/assets/stylesheets/rolodex/components/_loading.sass +32 -0
- data/vendor/assets/stylesheets/rolodex/components/_media.sass +14 -0
- data/vendor/assets/stylesheets/rolodex/components/_modals.sass +83 -0
- data/vendor/assets/stylesheets/rolodex/components/_tables.sass +9 -0
- data/vendor/assets/stylesheets/rolodex/components/_tooltips.sass +123 -0
- data/vendor/assets/stylesheets/rolodex/settings/_settings.sass +33 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_bump.sass +51 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_icons.sass +17 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_layout.sass +52 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_rems.sass +41 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_svg.sass +10 -0
- data/vendor/assets/stylesheets/rolodex/settings/mixins/_typography.sass +65 -0
- data/vendor/assets/stylesheets/rolodex/settings/utilities/_layout.sass +51 -0
- data/vendor/assets/stylesheets/rolodex/settings/utilities/_misc.sass +13 -0
- data/vendor/assets/stylesheets/rolodex/settings/utilities/_typography.sass +60 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_alerts.scss +27 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_buttons.scss +10 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_colors.scss +46 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_labels.scss +10 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_layout.scss +22 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_misc.scss +12 -0
- data/vendor/assets/stylesheets/rolodex/settings/variables/_typography.scss +34 -0
- 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()
|