angular-pack 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ /*global angular */
2
+ /*
3
+ jQuery UI Datepicker plugin wrapper
4
+
5
+ @note If ≤ IE8 make sure you have a polyfill for Date.toISOString()
6
+ @param [ui-date] {object} Options to pass to $.fn.datepicker() merged onto uiDateConfig
7
+ */
8
+
9
+ angular.module('ui.date', [])
10
+
11
+ .constant('uiDateConfig', {})
12
+
13
+ .directive('uiDate', ['uiDateConfig', function (uiDateConfig) {
14
+ 'use strict';
15
+ var options;
16
+ options = {};
17
+ angular.extend(options, uiDateConfig);
18
+ return {
19
+ require:'?ngModel',
20
+ link:function (scope, element, attrs, controller) {
21
+ var getOptions = function () {
22
+ return angular.extend({}, uiDateConfig, scope.$eval(attrs.uiDate));
23
+ };
24
+ var initDateWidget = function () {
25
+ var showing = false;
26
+ var opts = getOptions();
27
+
28
+ // If we have a controller (i.e. ngModelController) then wire it up
29
+ if (controller) {
30
+
31
+ // Set the view value in a $apply block when users selects
32
+ // (calling directive user's function too if provided)
33
+ var _onSelect = opts.onSelect || angular.noop;
34
+ opts.onSelect = function (value, picker) {
35
+ scope.$apply(function() {
36
+ showing = true;
37
+ controller.$setViewValue(element.datepicker("getDate"));
38
+ _onSelect(value, picker);
39
+ element.blur();
40
+ });
41
+ };
42
+ opts.beforeShow = function() {
43
+ showing = true;
44
+ };
45
+ opts.onClose = function(value, picker) {
46
+ showing = false;
47
+ };
48
+ element.on('blur', function() {
49
+ if ( !showing ) {
50
+ scope.$apply(function() {
51
+ element.datepicker("setDate", element.datepicker("getDate"));
52
+ controller.$setViewValue(element.datepicker("getDate"));
53
+ });
54
+ }
55
+ });
56
+
57
+ // Update the date picker when the model changes
58
+ controller.$render = function () {
59
+ var date = controller.$viewValue;
60
+ if ( angular.isDefined(date) && date !== null && !angular.isDate(date) ) {
61
+ throw new Error('ng-Model value must be a Date object - currently it is a ' + typeof date + ' - use ui-date-format to convert it from a string');
62
+ }
63
+ element.datepicker("setDate", date);
64
+ };
65
+ }
66
+ // If we don't destroy the old one it doesn't update properly when the config changes
67
+ element.datepicker('destroy');
68
+ // Create the new datepicker widget
69
+ element.datepicker(opts);
70
+ if ( controller ) {
71
+ // Force a render to override whatever is in the input text box
72
+ controller.$render();
73
+ }
74
+ };
75
+ // Watch for changes to the directives options
76
+ scope.$watch(getOptions, initDateWidget, true);
77
+ }
78
+ };
79
+ }
80
+ ])
81
+
82
+ .constant('uiDateFormatConfig', '')
83
+
84
+ .directive('uiDateFormat', ['uiDateFormatConfig', function(uiDateFormatConfig) {
85
+ var directive = {
86
+ require:'ngModel',
87
+ link: function(scope, element, attrs, modelCtrl) {
88
+ var dateFormat = attrs.uiDateFormat || uiDateFormatConfig;
89
+ if ( dateFormat ) {
90
+ // Use the datepicker with the attribute value as the dateFormat string to convert to and from a string
91
+ modelCtrl.$formatters.push(function(value) {
92
+ if (angular.isString(value) ) {
93
+ return jQuery.datepicker.parseDate(dateFormat, value);
94
+ }
95
+ return null;
96
+ });
97
+ modelCtrl.$parsers.push(function(value){
98
+ if (value) {
99
+ return jQuery.datepicker.formatDate(dateFormat, value);
100
+ }
101
+ return null;
102
+ });
103
+ } else {
104
+ // Default to ISO formatting
105
+ modelCtrl.$formatters.push(function(value) {
106
+ if (angular.isString(value) ) {
107
+ return new Date(value);
108
+ }
109
+ return null;
110
+ });
111
+ modelCtrl.$parsers.push(function(value){
112
+ if (value) {
113
+ return value.toISOString();
114
+ }
115
+ return null;
116
+ });
117
+ }
118
+ }
119
+ };
120
+ return directive;
121
+ }]);
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ (function () {
4
+ var app = angular.module('ui.map', ['ui.event']);
5
+
6
+ //Setup map events from a google map object to trigger on a given element too,
7
+ //then we just use ui-event to catch events from an element
8
+ function bindMapEvents(scope, eventsStr, googleObject, element) {
9
+ angular.forEach(eventsStr.split(' '), function (eventName) {
10
+ //Prefix all googlemap events with 'map-', so eg 'click'
11
+ //for the googlemap doesn't interfere with a normal 'click' event
12
+ window.google.maps.event.addListener(googleObject, eventName, function (event) {
13
+ element.triggerHandler('map-' + eventName, event);
14
+ //We create an $apply if it isn't happening. we need better support for this
15
+ //We don't want to use timeout because tons of these events fire at once,
16
+ //and we only need one $apply
17
+ if (!scope.$$phase){ scope.$apply();}
18
+ });
19
+ });
20
+ }
21
+
22
+ app.value('uiMapConfig', {}).directive('uiMap',
23
+ ['uiMapConfig', '$parse', function (uiMapConfig, $parse) {
24
+
25
+ var mapEvents = 'bounds_changed center_changed click dblclick drag dragend ' +
26
+ 'dragstart heading_changed idle maptypeid_changed mousemove mouseout ' +
27
+ 'mouseover projection_changed resize rightclick tilesloaded tilt_changed ' +
28
+ 'zoom_changed';
29
+ var options = uiMapConfig || {};
30
+
31
+ return {
32
+ restrict: 'A',
33
+ //doesn't work as E for unknown reason
34
+ link: function (scope, elm, attrs) {
35
+ var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
36
+ var map = new window.google.maps.Map(elm[0], opts);
37
+ var model = $parse(attrs.uiMap);
38
+
39
+ //Set scope variable for the map
40
+ model.assign(scope, map);
41
+
42
+ bindMapEvents(scope, mapEvents, map, elm);
43
+ }
44
+ };
45
+ }]);
46
+
47
+ app.value('uiMapInfoWindowConfig', {}).directive('uiMapInfoWindow',
48
+ ['uiMapInfoWindowConfig', '$parse', '$compile', function (uiMapInfoWindowConfig, $parse, $compile) {
49
+
50
+ var infoWindowEvents = 'closeclick content_change domready ' +
51
+ 'position_changed zindex_changed';
52
+ var options = uiMapInfoWindowConfig || {};
53
+
54
+ return {
55
+ link: function (scope, elm, attrs) {
56
+ var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
57
+ opts.content = elm[0];
58
+ var model = $parse(attrs.uiMapInfoWindow);
59
+ var infoWindow = model(scope);
60
+
61
+ if (!infoWindow) {
62
+ infoWindow = new window.google.maps.InfoWindow(opts);
63
+ model.assign(scope, infoWindow);
64
+ }
65
+
66
+ bindMapEvents(scope, infoWindowEvents, infoWindow, elm);
67
+
68
+ /* The info window's contents dont' need to be on the dom anymore,
69
+ google maps has them stored. So we just replace the infowindow element
70
+ with an empty div. (we don't just straight remove it from the dom because
71
+ straight removing things from the dom can mess up angular) */
72
+ elm.replaceWith('<div></div>');
73
+
74
+ //Decorate infoWindow.open to $compile contents before opening
75
+ var _open = infoWindow.open;
76
+ infoWindow.open = function open(a1, a2, a3, a4, a5, a6) {
77
+ $compile(elm.contents())(scope);
78
+ _open.call(infoWindow, a1, a2, a3, a4, a5, a6);
79
+ };
80
+ }
81
+ };
82
+ }]);
83
+
84
+ /*
85
+ * Map overlay directives all work the same. Take map marker for example
86
+ * <ui-map-marker="myMarker"> will $watch 'myMarker' and each time it changes,
87
+ * it will hook up myMarker's events to the directive dom element. Then
88
+ * ui-event will be able to catch all of myMarker's events. Super simple.
89
+ */
90
+ function mapOverlayDirective(directiveName, events) {
91
+ app.directive(directiveName, [function () {
92
+ return {
93
+ restrict: 'A',
94
+ link: function (scope, elm, attrs) {
95
+ scope.$watch(attrs[directiveName], function (newObject) {
96
+ if (newObject) {
97
+ bindMapEvents(scope, events, newObject, elm);
98
+ }
99
+ });
100
+ }
101
+ };
102
+ }]);
103
+ }
104
+
105
+ mapOverlayDirective('uiMapMarker',
106
+ 'animation_changed click clickable_changed cursor_changed ' +
107
+ 'dblclick drag dragend draggable_changed dragstart flat_changed icon_changed ' +
108
+ 'mousedown mouseout mouseover mouseup position_changed rightclick ' +
109
+ 'shadow_changed shape_changed title_changed visible_changed zindex_changed');
110
+
111
+ mapOverlayDirective('uiMapPolyline',
112
+ 'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');
113
+
114
+ mapOverlayDirective('uiMapPolygon',
115
+ 'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');
116
+
117
+ mapOverlayDirective('uiMapRectangle',
118
+ 'bounds_changed click dblclick mousedown mousemove mouseout mouseover ' +
119
+ 'mouseup rightclick');
120
+
121
+ mapOverlayDirective('uiMapCircle',
122
+ 'center_changed click dblclick mousedown mousemove ' +
123
+ 'mouseout mouseover mouseup radius_changed rightclick');
124
+
125
+ mapOverlayDirective('uiMapGroundOverlay',
126
+ 'click dblclick');
127
+
128
+ })();
@@ -0,0 +1,211 @@
1
+ /*
2
+ jQuery UI Sortable plugin wrapper
3
+
4
+ @param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config
5
+ */
6
+ angular.module('ui.sortable', [])
7
+ .value('uiSortableConfig',{})
8
+ .directive('uiSortable', [
9
+ 'uiSortableConfig', '$timeout', '$log',
10
+ function(uiSortableConfig, $timeout, $log) {
11
+ return {
12
+ require: '?ngModel',
13
+ link: function(scope, element, attrs, ngModel) {
14
+ var savedNodes;
15
+
16
+ function combineCallbacks(first,second){
17
+ if(second && (typeof second === 'function')) {
18
+ return function(e, ui) {
19
+ first(e, ui);
20
+ second(e, ui);
21
+ };
22
+ }
23
+ return first;
24
+ }
25
+
26
+ var opts = {};
27
+
28
+ var callbacks = {
29
+ receive: null,
30
+ remove:null,
31
+ start:null,
32
+ stop:null,
33
+ update:null
34
+ };
35
+
36
+ angular.extend(opts, uiSortableConfig);
37
+
38
+ if (ngModel) {
39
+
40
+ // When we add or remove elements, we need the sortable to 'refresh'
41
+ // so it can find the new/removed elements.
42
+ scope.$watch(attrs.ngModel+'.length', function() {
43
+ // Timeout to let ng-repeat modify the DOM
44
+ $timeout(function() {
45
+ // ensure that the jquery-ui-sortable widget instance
46
+ // is still bound to the directive's element
47
+ if (!!element.data('ui-sortable')) {
48
+ element.sortable('refresh');
49
+ }
50
+ });
51
+ });
52
+
53
+ callbacks.start = function(e, ui) {
54
+ // Save the starting position of dragged item
55
+ ui.item.sortable = {
56
+ index: ui.item.index(),
57
+ cancel: function () {
58
+ ui.item.sortable._isCanceled = true;
59
+ },
60
+ isCanceled: function () {
61
+ return ui.item.sortable._isCanceled;
62
+ },
63
+ _isCanceled: false
64
+ };
65
+ };
66
+
67
+ callbacks.activate = function(/*e, ui*/) {
68
+ // We need to make a copy of the current element's contents so
69
+ // we can restore it after sortable has messed it up.
70
+ // This is inside activate (instead of start) in order to save
71
+ // both lists when dragging between connected lists.
72
+ savedNodes = element.contents();
73
+
74
+ // If this list has a placeholder (the connected lists won't),
75
+ // don't inlcude it in saved nodes.
76
+ var placeholder = element.sortable('option','placeholder');
77
+
78
+ // placeholder.element will be a function if the placeholder, has
79
+ // been created (placeholder will be an object). If it hasn't
80
+ // been created, either placeholder will be false if no
81
+ // placeholder class was given or placeholder.element will be
82
+ // undefined if a class was given (placeholder will be a string)
83
+ if (placeholder && placeholder.element && typeof placeholder.element === 'function') {
84
+ var phElement = placeholder.element();
85
+ // workaround for jquery ui 1.9.x,
86
+ // not returning jquery collection
87
+ if (!phElement.jquery) {
88
+ phElement = angular.element(phElement);
89
+ }
90
+
91
+ // exact match with the placeholder's class attribute to handle
92
+ // the case that multiple connected sortables exist and
93
+ // the placehoilder option equals the class of sortable items
94
+ var excludes = element.find('[class="' + phElement.attr('class') + '"]');
95
+
96
+ savedNodes = savedNodes.not(excludes);
97
+ }
98
+ };
99
+
100
+ callbacks.update = function(e, ui) {
101
+ // Save current drop position but only if this is not a second
102
+ // update that happens when moving between lists because then
103
+ // the value will be overwritten with the old value
104
+ if(!ui.item.sortable.received) {
105
+ ui.item.sortable.dropindex = ui.item.index();
106
+ ui.item.sortable.droptarget = ui.item.parent();
107
+
108
+ // Cancel the sort (let ng-repeat do the sort for us)
109
+ // Don't cancel if this is the received list because it has
110
+ // already been canceled in the other list, and trying to cancel
111
+ // here will mess up the DOM.
112
+ element.sortable('cancel');
113
+ }
114
+
115
+ // Put the nodes back exactly the way they started (this is very
116
+ // important because ng-repeat uses comment elements to delineate
117
+ // the start and stop of repeat sections and sortable doesn't
118
+ // respect their order (even if we cancel, the order of the
119
+ // comments are still messed up).
120
+ if (element.sortable('option','helper') === 'clone') {
121
+ // restore all the savedNodes except .ui-sortable-helper element
122
+ // (which is placed last). That way it will be garbage collected.
123
+ savedNodes = savedNodes.not(savedNodes.last());
124
+ }
125
+ savedNodes.appendTo(element);
126
+
127
+ // If received is true (an item was dropped in from another list)
128
+ // then we add the new item to this list otherwise wait until the
129
+ // stop event where we will know if it was a sort or item was
130
+ // moved here from another list
131
+ if(ui.item.sortable.received && !ui.item.sortable.isCanceled()) {
132
+ scope.$apply(function () {
133
+ ngModel.$modelValue.splice(ui.item.sortable.dropindex, 0,
134
+ ui.item.sortable.moved);
135
+ });
136
+ }
137
+ };
138
+
139
+ callbacks.stop = function(e, ui) {
140
+ // If the received flag hasn't be set on the item, this is a
141
+ // normal sort, if dropindex is set, the item was moved, so move
142
+ // the items in the list.
143
+ if(!ui.item.sortable.received &&
144
+ ('dropindex' in ui.item.sortable) &&
145
+ !ui.item.sortable.isCanceled()) {
146
+
147
+ scope.$apply(function () {
148
+ ngModel.$modelValue.splice(
149
+ ui.item.sortable.dropindex, 0,
150
+ ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0]);
151
+ });
152
+ } else {
153
+ // if the item was not moved, then restore the elements
154
+ // so that the ngRepeat's comment are correct.
155
+ if((!('dropindex' in ui.item.sortable) || ui.item.sortable.isCanceled()) && element.sortable('option','helper') !== 'clone') {
156
+ savedNodes.appendTo(element);
157
+ }
158
+ }
159
+ };
160
+
161
+ callbacks.receive = function(e, ui) {
162
+ // An item was dropped here from another list, set a flag on the
163
+ // item.
164
+ ui.item.sortable.received = true;
165
+ };
166
+
167
+ callbacks.remove = function(e, ui) {
168
+ // Remove the item from this list's model and copy data into item,
169
+ // so the next list can retrive it
170
+ if (!ui.item.sortable.isCanceled()) {
171
+ scope.$apply(function () {
172
+ ui.item.sortable.moved = ngModel.$modelValue.splice(
173
+ ui.item.sortable.index, 1)[0];
174
+ });
175
+ }
176
+ };
177
+
178
+ scope.$watch(attrs.uiSortable, function(newVal /*, oldVal*/) {
179
+ // ensure that the jquery-ui-sortable widget instance
180
+ // is still bound to the directive's element
181
+ if (!!element.data('ui-sortable')) {
182
+ angular.forEach(newVal, function(value, key) {
183
+ if(callbacks[key]) {
184
+ if( key === 'stop' ){
185
+ // call apply after stop
186
+ value = combineCallbacks(
187
+ value, function() { scope.$apply(); });
188
+ }
189
+ // wrap the callback
190
+ value = combineCallbacks(callbacks[key], value);
191
+ }
192
+
193
+ element.sortable('option', key, value);
194
+ });
195
+ }
196
+ }, true);
197
+
198
+ angular.forEach(callbacks, function(value, key) {
199
+ opts[key] = combineCallbacks(value, opts[key]);
200
+ });
201
+
202
+ } else {
203
+ $log.info('ui.sortable: ngModel not provided!', element);
204
+ }
205
+
206
+ // Create sortable
207
+ element.sortable(opts);
208
+ }
209
+ };
210
+ }
211
+ ]);