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,143 @@
1
+ angular.module('rolodex.dropdown', [])
2
+
3
+ .constant('dropdownConfig', dropDownOpen: 'data-dropdown-open')
4
+
5
+ .service('dropdownService', [
6
+ '$document'
7
+ ($document) ->
8
+ openScope = null
9
+
10
+ @open = (dropdownScope) ->
11
+ unless openScope
12
+ $document.bind 'click', closeDropdown
13
+ $document.bind 'keydown', escapeKeyBind
14
+ openScope.isOpen = false if openScope and openScope isnt dropdownScope
15
+ openScope = dropdownScope
16
+
17
+ @close = (dropdownScope) ->
18
+ if openScope is dropdownScope or
19
+ dropdownScope.forceClose
20
+
21
+ if dropdownScope.forceClose
22
+ openScope.isOpen = false if openScope
23
+
24
+ openScope = null
25
+ $document.unbind 'click', closeDropdown
26
+ $document.unbind 'keydown', escapeKeyBind
27
+
28
+ closeDropdown = (evt) ->
29
+ toggleElement = openScope.getToggleElement()
30
+ if evt and toggleElement?[0].contains(evt.target) or
31
+ evt?.target.nodeName.toLowerCase() is 'input' # Don't close if the drop down has an input interaction
32
+ return
33
+
34
+ openScope.$apply ->
35
+ openScope.isOpen = false
36
+
37
+ escapeKeyBind = (evt) ->
38
+ if evt.which is 27
39
+ openScope.focusToggleElement()
40
+ closeDropdown()
41
+
42
+ return this
43
+ ])
44
+
45
+ .controller('DropdownController', [
46
+ '$scope'
47
+ '$attrs'
48
+ '$parse'
49
+ 'dropdownConfig'
50
+ 'dropdownService'
51
+ '$animate'
52
+ ($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) ->
53
+ self = this
54
+ scope = $scope.$new()
55
+ dropDownOpen = dropdownConfig.dropDownOpen
56
+ getIsOpen = undefined
57
+ setIsOpen = angular.noop
58
+ toggleInvoker = (if $attrs.onToggle then $parse($attrs.onToggle) else angular.noop)
59
+
60
+ @init = (element) ->
61
+ self.$element = element
62
+ if $attrs.isOpen
63
+ getIsOpen = $parse($attrs.isOpen)
64
+ setIsOpen = getIsOpen.assign
65
+ $scope.$watch getIsOpen, (value) ->
66
+ scope.isOpen = !!value
67
+
68
+ @toggle = (open) ->
69
+ scope.isOpen = (if arguments.length then !!open else not scope.isOpen)
70
+
71
+ @isOpen = ->
72
+ scope.isOpen
73
+
74
+ scope.getToggleElement = ->
75
+ self.toggleElement
76
+
77
+ scope.focusToggleElement = ->
78
+ self.toggleElement[0].focus() if self.toggleElement
79
+ return
80
+
81
+ scope.$watch 'isOpen', (isOpen, wasOpen) ->
82
+ anchors = self.$element.find('a')
83
+
84
+ if isOpen
85
+ self.$element.attr(dropDownOpen, '')
86
+ scope.focusToggleElement()
87
+ dropdownService.open scope
88
+
89
+ if anchors.length
90
+ scope.forceClose = true
91
+ _.each anchors, (anchor) ->
92
+ angular.element(anchor).on 'click', (evt) ->
93
+ dropdownService.close(scope)
94
+ scope.$digest()
95
+
96
+ else
97
+ self.$element.removeAttr(dropDownOpen)
98
+ dropdownService.close(scope)
99
+
100
+ setIsOpen $scope, isOpen
101
+ if angular.isDefined(isOpen) and isOpen isnt wasOpen
102
+ toggleInvoker $scope,
103
+ open: !!isOpen
104
+
105
+ $scope.$on '$locationChangeSuccess', ->
106
+ scope.isOpen = false
107
+
108
+ $scope.$on '$destroy', ->
109
+ scope.$destroy()
110
+
111
+ return this
112
+
113
+ ])
114
+
115
+ .directive 'dropdown', ->
116
+ controller: 'DropdownController'
117
+ link: (scope, element, attrs, dropdownCtrl) ->
118
+ dropdownCtrl.init element
119
+
120
+ .directive 'dropdownToggle', ->
121
+ require: '?^dropdown'
122
+ link: (scope, element, attrs, dropdownCtrl) ->
123
+ return unless dropdownCtrl
124
+ dropdownCtrl.toggleElement = element
125
+
126
+ toggleDropdown = (event) ->
127
+ event.preventDefault()
128
+ if not element.hasClass('disabled') and not attrs.disabled
129
+ scope.$apply ->
130
+ dropdownCtrl.toggle()
131
+
132
+ element.bind 'click', toggleDropdown
133
+
134
+ # WAI-ARIA
135
+ element.attr
136
+ 'aria-haspopup': true
137
+ 'aria-expanded': false
138
+
139
+ scope.$watch dropdownCtrl.isOpen, (isOpen) ->
140
+ element.attr 'aria-expanded', !!isOpen
141
+
142
+ scope.$on '$destroy', ->
143
+ element.unbind 'click', toggleDropdown
@@ -0,0 +1,331 @@
1
+ #= require 'rolodex_angular/template/modal/window'
2
+
3
+ # Because of the flexibility of UI-Bootstraps modal this is a copy of their source converted to CoffeeScript for
4
+ # maintainability. The module namespace has been changed to suite Rolodex and the template has been adjusted to
5
+ # work with the Rolodex styles. The rest remains true to the Bootstrap source including using their transition
6
+ # animation library and not ngAnimate.
7
+
8
+ angular.module("rolodex.modal", ["rolodex.transition", "templates"])
9
+
10
+ # A helper, internal data structure that acts as a map but also allows getting / removing
11
+ # elements in the LIFO order
12
+ .factory "$$stackedMap", ->
13
+ createNew: ->
14
+ stack = []
15
+ add: (key, value) ->
16
+ stack.push
17
+ key: key
18
+ value: value
19
+
20
+ get: (key) ->
21
+ i = 0
22
+
23
+ while i < stack.length
24
+ return stack[i] if key is stack[i].key
25
+ i++
26
+
27
+ keys: ->
28
+ keys = []
29
+ i = 0
30
+
31
+ while i < stack.length
32
+ keys.push stack[i].key
33
+ i++
34
+ keys
35
+
36
+ top: ->
37
+ stack[stack.length - 1]
38
+
39
+ remove: (key) ->
40
+ idx = -1
41
+ i = 0
42
+
43
+ while i < stack.length
44
+ if key is stack[i].key
45
+ idx = i
46
+ break
47
+ i++
48
+ stack.splice(idx, 1)[0]
49
+
50
+ removeTop: ->
51
+ stack.splice(stack.length - 1, 1)[0]
52
+
53
+ length: ->
54
+ stack.length
55
+
56
+ .directive("modalWindow", [
57
+ "$modalStack"
58
+ "$timeout"
59
+ ($modalStack, $timeout) ->
60
+
61
+ restrict: "EA"
62
+ scope:
63
+ index: "@"
64
+ animate: "="
65
+
66
+ replace: true
67
+ transclude: true
68
+ templateUrl: (tElement, tAttrs) ->
69
+ tAttrs.templateUrl or "rolodex_angular/template/modal/window"
70
+
71
+ link: (scope, element, attrs) ->
72
+ element.addClass attrs.windowClass or ""
73
+ scope.size = attrs.size
74
+ $timeout ->
75
+ scope.animate = true
76
+ element[0].focus() unless element[0].querySelectorAll("[autofocus]").length
77
+ return
78
+
79
+ scope.close = (evt) ->
80
+ modal = $modalStack.getTop()
81
+ # Auto-focusing of a freshly-opened modal element causes any child elements
82
+ # with the autofocus attribute to loose focus. This is an issue on touch
83
+ # based devices which will show and then hide the onscreen keyboard.
84
+ # Attempts to refocus the autofocus element via JavaScript will not reopen
85
+ # the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
86
+ # the modal element if the modal does not contain an autofocus element.
87
+ if modal and modal.value.backdrop and modal.value.backdrop isnt "static" and (evt.target is evt.currentTarget)
88
+ evt.preventDefault()
89
+ evt.stopPropagation()
90
+ $modalStack.dismiss modal.key, "backdrop click"
91
+ ])
92
+
93
+ .directive "modalTransclude", ->
94
+ link: ($scope, $element, $attrs, controller, $transclude) ->
95
+ $transclude $scope.$parent, (clone) ->
96
+ $element.empty()
97
+ $element.append clone
98
+
99
+ .factory("$modalStack", [
100
+ "$transition"
101
+ "$timeout"
102
+ "$document"
103
+ "$compile"
104
+ "$rootScope"
105
+ "$$stackedMap"
106
+ ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) ->
107
+ backdropIndex = ->
108
+ topBackdropIndex = -1
109
+ opened = openedWindows.keys()
110
+ i = 0
111
+
112
+ while i < opened.length
113
+ topBackdropIndex = i if openedWindows.get(opened[i]).value.backdrop
114
+ i++
115
+ topBackdropIndex
116
+ removeModalWindow = (modalInstance) ->
117
+ body = $document.find("body").eq(0)
118
+ modalWindow = openedWindows.get(modalInstance).value
119
+ openedWindows.remove modalInstance
120
+ removeAfterAnimate modalWindow.modalDomEl, modalWindow.modalScope, 300, ->
121
+ modalWindow.modalScope.$destroy()
122
+ body.toggleClass OPENED_MODAL_CLASS, openedWindows.length() > 0
123
+ checkRemoveBackdrop()
124
+ return
125
+
126
+ return
127
+ checkRemoveBackdrop = ->
128
+ if backdropDomEl and backdropIndex() is -1
129
+ backdropScopeRef = backdropScope
130
+ removeAfterAnimate backdropDomEl, backdropScope, 150, ->
131
+ backdropScopeRef.$destroy()
132
+ backdropScopeRef = null
133
+ return
134
+
135
+ backdropDomEl = `undefined`
136
+ backdropScope = `undefined`
137
+ return
138
+ removeAfterAnimate = (domEl, scope, emulateTime, done) ->
139
+ afterAnimating = ->
140
+ return if afterAnimating.done
141
+ afterAnimating.done = true
142
+ domEl.remove()
143
+ done() if done
144
+ return
145
+ scope.animate = false
146
+ transitionEndEventName = $transition.transitionEndEventName
147
+ if transitionEndEventName
148
+ timeout = $timeout(afterAnimating, emulateTime)
149
+ domEl.bind transitionEndEventName, ->
150
+ $timeout.cancel timeout
151
+ afterAnimating()
152
+ scope.$apply()
153
+ return
154
+
155
+ else
156
+ $timeout afterAnimating
157
+ return
158
+ OPENED_MODAL_CLASS = "modal-open"
159
+ backdropDomEl = undefined
160
+ backdropScope = undefined
161
+ openedWindows = $$stackedMap.createNew()
162
+ $modalStack = {}
163
+ $rootScope.$watch backdropIndex, (newBackdropIndex) ->
164
+ backdropScope.index = newBackdropIndex if backdropScope
165
+ return
166
+
167
+ $document.bind "keydown", (evt) ->
168
+ modal = undefined
169
+ if evt.which is 27
170
+ modal = openedWindows.top()
171
+ if modal and modal.value.keyboard
172
+ evt.preventDefault()
173
+ $rootScope.$apply ->
174
+ $modalStack.dismiss modal.key, "escape key press"
175
+ return
176
+
177
+ return
178
+
179
+ $modalStack.open = (modalInstance, modal) ->
180
+ openedWindows.add modalInstance,
181
+ deferred: modal.deferred
182
+ modalScope: modal.scope
183
+ backdrop: modal.backdrop
184
+ keyboard: modal.keyboard
185
+
186
+ body = $document.find("body").eq(0)
187
+ currBackdropIndex = backdropIndex()
188
+ if currBackdropIndex >= 0 and not backdropDomEl
189
+ backdropScope = $rootScope.$new(true)
190
+ backdropScope.index = currBackdropIndex
191
+ angularBackgroundDomEl = angular.element("<div modal-backdrop></div>")
192
+ angularBackgroundDomEl.attr "backdrop-class", modal.backdropClass
193
+ backdropDomEl = $compile(angularBackgroundDomEl)(backdropScope)
194
+ body.append backdropDomEl
195
+ angularDomEl = angular.element("<div modal-window></div>")
196
+ angularDomEl.attr(
197
+ "template-url": modal.windowTemplateUrl
198
+ "window-class": modal.windowClass
199
+ size: modal.size
200
+ index: openedWindows.length() - 1
201
+ animate: "animate"
202
+ ).html modal.content
203
+ modalDomEl = $compile(angularDomEl)(modal.scope)
204
+ openedWindows.top().value.modalDomEl = modalDomEl
205
+ body.append modalDomEl
206
+ body.addClass OPENED_MODAL_CLASS
207
+ return
208
+
209
+ $modalStack.close = (modalInstance, result) ->
210
+ modalWindow = openedWindows.get(modalInstance)
211
+ if modalWindow
212
+ modalWindow.value.deferred.resolve result
213
+ removeModalWindow modalInstance
214
+ return
215
+
216
+ $modalStack.dismiss = (modalInstance, reason) ->
217
+ modalWindow = openedWindows.get(modalInstance)
218
+ if modalWindow
219
+ modalWindow.value.deferred.reject reason
220
+ removeModalWindow modalInstance
221
+ return
222
+
223
+ $modalStack.dismissAll = (reason) ->
224
+ topModal = @getTop()
225
+ while topModal
226
+ @dismiss topModal.key, reason
227
+ topModal = @getTop()
228
+ return
229
+
230
+ $modalStack.getTop = ->
231
+ openedWindows.top()
232
+
233
+ return $modalStack
234
+ ])
235
+
236
+ .provider "$modal", ->
237
+ $modalProvider =
238
+ options:
239
+ backdrop: true #can be also false or 'static'
240
+ keyboard: true
241
+
242
+ $get: [
243
+ "$injector"
244
+ "$rootScope"
245
+ "$q"
246
+ "$http"
247
+ "$templateCache"
248
+ "$controller"
249
+ "$modalStack"
250
+ ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) ->
251
+ getTemplatePromise = (options) ->
252
+ (if options.template then $q.when(options.template) else $http.get((if angular.isFunction(options.templateUrl) then (options.templateUrl)() else options.templateUrl),
253
+ cache: $templateCache
254
+ ).then((result) ->
255
+ result.data
256
+ ))
257
+ getResolvePromises = (resolves) ->
258
+ promisesArr = []
259
+ angular.forEach resolves, (value) ->
260
+ promisesArr.push $q.when($injector.invoke(value)) if angular.isFunction(value) or angular.isArray(value)
261
+ return
262
+
263
+ promisesArr
264
+ $modal = {}
265
+ $modal.open = (modalOptions) ->
266
+ modalResultDeferred = $q.defer()
267
+ modalOpenedDeferred = $q.defer()
268
+
269
+ #prepare an instance of a modal to be injected into controllers and returned to a caller
270
+ modalInstance =
271
+ result: modalResultDeferred.promise
272
+ opened: modalOpenedDeferred.promise
273
+ close: (result) ->
274
+ $modalStack.close modalInstance, result
275
+ return
276
+
277
+ dismiss: (reason) ->
278
+ $modalStack.dismiss modalInstance, reason
279
+ return
280
+
281
+
282
+ #merge and clean up options
283
+ modalOptions = angular.extend({}, $modalProvider.options, modalOptions)
284
+ modalOptions.resolve = modalOptions.resolve or {}
285
+
286
+ #verify options
287
+ throw new Error("One of template or templateUrl options is required.") if not modalOptions.template and not modalOptions.templateUrl
288
+ templateAndResolvePromise = $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)))
289
+ templateAndResolvePromise.then (resolveSuccess = (tplAndVars) ->
290
+ modalScope = (modalOptions.scope or $rootScope).$new()
291
+ modalScope.$close = modalInstance.close
292
+ modalScope.$dismiss = modalInstance.dismiss
293
+ ctrlInstance = undefined
294
+ ctrlLocals = {}
295
+ resolveIter = 1
296
+
297
+ #controllers
298
+ if modalOptions.controller
299
+ ctrlLocals.$scope = modalScope
300
+ ctrlLocals.$modalInstance = modalInstance
301
+ angular.forEach modalOptions.resolve, (value, key) ->
302
+ ctrlLocals[key] = tplAndVars[resolveIter++]
303
+ return
304
+
305
+ ctrlInstance = $controller(modalOptions.controller, ctrlLocals)
306
+ modalScope[modalOptions.controllerAs] = ctrlInstance if modalOptions.controller
307
+ $modalStack.open modalInstance,
308
+ scope: modalScope
309
+ deferred: modalResultDeferred
310
+ content: tplAndVars[0]
311
+ backdrop: modalOptions.backdrop
312
+ keyboard: modalOptions.keyboard
313
+ backdropClass: modalOptions.backdropClass
314
+ windowClass: modalOptions.windowClass
315
+ windowTemplateUrl: modalOptions.windowTemplateUrl
316
+ size: modalOptions.size
317
+
318
+ ), resolveError = (reason) ->
319
+ modalResultDeferred.reject reason
320
+
321
+ templateAndResolvePromise.then (->
322
+ modalOpenedDeferred.resolve true
323
+ ), ->
324
+ modalOpenedDeferred.reject false
325
+
326
+ modalInstance
327
+
328
+ return $modal
329
+ ]
330
+
331
+ $modalProvider