angular-ui-bootstrap-rails 0.3.0.1 → 0.4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +2 -1
- data/lib/angular-ui-bootstrap-rails/version.rb +1 -1
- data/vendor/assets/javascripts/angular-ui-bootstrap-tpls.js +1735 -701
- data/vendor/assets/javascripts/angular-ui-bootstrap.js +4574 -711
- metadata +7 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 228e8d4dcf89892df3b3f8b49e4ec1318dc9162f
|
4
|
+
data.tar.gz: 4b9fe4ac8c6b2bf0a1d871c090ff407995920285
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e9ef81d74df63d12b613cf78355298503c0655f0021fc40e7915f653fcad1b0d6912918122db9a58b31a70f32237cec4caab15f264d805c01db37c1db04a437b
|
7
|
+
data.tar.gz: 85dc8e5ea4a12e094b26f4172d88da1b9f43b81920b12274ad04722630c4e7a5eedcea286f2d36f47285b047e2b5b21dae9fc2ba0bf58288a0b32240e396849d
|
data/README.md
CHANGED
@@ -16,4 +16,5 @@ If you would like to use the default bootstrap templates, use the following dire
|
|
16
16
|
|
17
17
|
//= require angular-ui-bootstrap-tpls
|
18
18
|
|
19
|
-
Gem based on Angularjs-rails(https://github.com/
|
19
|
+
Gem based on Angularjs-rails(https://github.com/hiravgandhi/angularjs-rails) by Hirav Gandhi
|
20
|
+
|
@@ -1,5 +1,5 @@
|
|
1
|
-
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.position","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.typeahead"]);
|
2
|
-
angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/dialog/message.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/rating/rating.html","template/tabs/
|
1
|
+
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.datepicker","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.position","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
|
2
|
+
angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/dialog/message.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead.html"]);
|
3
3
|
angular.module('ui.bootstrap.transition', [])
|
4
4
|
|
5
5
|
/**
|
@@ -82,7 +82,7 @@ angular.module('ui.bootstrap.transition', [])
|
|
82
82
|
$transition.animationEndEventName = findEndEventName(animationEndEventNames);
|
83
83
|
return $transition;
|
84
84
|
}]);
|
85
|
-
|
85
|
+
|
86
86
|
angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
|
87
87
|
|
88
88
|
// The collapsible directive indicates a block of html that will expand and collapse
|
@@ -178,149 +178,149 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
|
|
178
178
|
}
|
179
179
|
};
|
180
180
|
}]);
|
181
|
-
|
182
|
-
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
183
|
-
|
184
|
-
.constant('accordionConfig', {
|
185
|
-
closeOthers: true
|
186
|
-
})
|
187
|
-
|
188
|
-
.controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
|
189
|
-
|
190
|
-
// This array keeps track of the accordion groups
|
191
|
-
this.groups = [];
|
192
|
-
|
193
|
-
// Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
|
194
|
-
this.closeOthers = function(openGroup) {
|
195
|
-
var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
|
196
|
-
if ( closeOthers ) {
|
197
|
-
angular.forEach(this.groups, function (group) {
|
198
|
-
if ( group !== openGroup ) {
|
199
|
-
group.isOpen = false;
|
200
|
-
}
|
201
|
-
});
|
202
|
-
}
|
203
|
-
};
|
204
|
-
|
205
|
-
// This is called from the accordion-group directive to add itself to the accordion
|
206
|
-
this.addGroup = function(groupScope) {
|
207
|
-
var that = this;
|
208
|
-
this.groups.push(groupScope);
|
209
|
-
|
210
|
-
groupScope.$on('$destroy', function (event) {
|
211
|
-
that.removeGroup(groupScope);
|
212
|
-
});
|
213
|
-
};
|
214
|
-
|
215
|
-
// This is called from the accordion-group directive when to remove itself
|
216
|
-
this.removeGroup = function(group) {
|
217
|
-
var index = this.groups.indexOf(group);
|
218
|
-
if ( index !== -1 ) {
|
219
|
-
this.groups.splice(this.groups.indexOf(group), 1);
|
220
|
-
}
|
221
|
-
};
|
222
|
-
|
223
|
-
}])
|
224
|
-
|
225
|
-
// The accordion directive simply sets up the directive controller
|
226
|
-
// and adds an accordion CSS class to itself element.
|
227
|
-
.directive('accordion', function () {
|
228
|
-
return {
|
229
|
-
restrict:'EA',
|
230
|
-
controller:'AccordionController',
|
231
|
-
transclude: true,
|
232
|
-
replace: false,
|
233
|
-
templateUrl: 'template/accordion/accordion.html'
|
234
|
-
};
|
235
|
-
})
|
236
|
-
|
237
|
-
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
|
238
|
-
.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
|
239
|
-
return {
|
240
|
-
require:'^accordion', // We need this directive to be inside an accordion
|
241
|
-
restrict:'EA',
|
242
|
-
transclude:true, // It transcludes the contents of the directive into the template
|
243
|
-
replace: true, // The element containing the directive will be replaced with the template
|
244
|
-
templateUrl:'template/accordion/accordion-group.html',
|
245
|
-
scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope
|
246
|
-
controller: ['$scope', function($scope) {
|
247
|
-
this.setHeading = function(element) {
|
248
|
-
this.heading = element;
|
249
|
-
};
|
250
|
-
}],
|
251
|
-
link: function(scope, element, attrs, accordionCtrl) {
|
252
|
-
var getIsOpen, setIsOpen;
|
253
|
-
|
254
|
-
accordionCtrl.addGroup(scope);
|
255
|
-
|
256
|
-
scope.isOpen = false;
|
257
|
-
|
258
|
-
if ( attrs.isOpen ) {
|
259
|
-
getIsOpen = $parse(attrs.isOpen);
|
260
|
-
setIsOpen = getIsOpen.assign;
|
261
|
-
|
262
|
-
scope.$watch(
|
263
|
-
function watchIsOpen() { return getIsOpen(scope.$parent); },
|
264
|
-
function updateOpen(value) { scope.isOpen = value; }
|
265
|
-
);
|
266
|
-
|
267
|
-
scope.isOpen = getIsOpen ? getIsOpen(scope.$parent) : false;
|
268
|
-
}
|
269
|
-
|
270
|
-
scope.$watch('isOpen', function(value) {
|
271
|
-
if ( value ) {
|
272
|
-
accordionCtrl.closeOthers(scope);
|
273
|
-
}
|
274
|
-
if ( setIsOpen ) {
|
275
|
-
setIsOpen(scope.$parent, value);
|
276
|
-
}
|
277
|
-
});
|
278
|
-
}
|
279
|
-
};
|
280
|
-
}])
|
281
|
-
|
282
|
-
// Use accordion-heading below an accordion-group to provide a heading containing HTML
|
283
|
-
// <accordion-group>
|
284
|
-
// <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
|
285
|
-
// </accordion-group>
|
286
|
-
.directive('accordionHeading', function() {
|
287
|
-
return {
|
288
|
-
restrict: '
|
289
|
-
transclude: true, // Grab the contents to be used as the heading
|
290
|
-
template: '', // In effect remove this element!
|
291
|
-
replace: true,
|
292
|
-
require: '^accordionGroup',
|
293
|
-
compile: function(element, attr, transclude) {
|
294
|
-
return function link(scope, element, attr, accordionGroupCtrl) {
|
295
|
-
// Pass the heading to the accordion-group controller
|
296
|
-
// so that it can be transcluded into the right place in the template
|
297
|
-
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
|
298
|
-
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
|
299
|
-
};
|
300
|
-
}
|
301
|
-
};
|
302
|
-
})
|
303
|
-
|
304
|
-
// Use in the accordion-group template to indicate where you want the heading to be transcluded
|
305
|
-
// You must provide the property on the accordion-group controller that will hold the transcluded element
|
306
|
-
// <div class="accordion-group">
|
307
|
-
// <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
|
308
|
-
// ...
|
309
|
-
// </div>
|
310
|
-
.directive('accordionTransclude', function() {
|
311
|
-
return {
|
312
|
-
require: '^accordionGroup',
|
313
|
-
link: function(scope, element, attr, controller) {
|
314
|
-
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
|
315
|
-
if ( heading ) {
|
316
|
-
element.html('');
|
317
|
-
element.append(heading);
|
318
|
-
}
|
319
|
-
});
|
320
|
-
}
|
321
|
-
};
|
322
|
-
});
|
323
|
-
|
181
|
+
|
182
|
+
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
|
183
|
+
|
184
|
+
.constant('accordionConfig', {
|
185
|
+
closeOthers: true
|
186
|
+
})
|
187
|
+
|
188
|
+
.controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
|
189
|
+
|
190
|
+
// This array keeps track of the accordion groups
|
191
|
+
this.groups = [];
|
192
|
+
|
193
|
+
// Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
|
194
|
+
this.closeOthers = function(openGroup) {
|
195
|
+
var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
|
196
|
+
if ( closeOthers ) {
|
197
|
+
angular.forEach(this.groups, function (group) {
|
198
|
+
if ( group !== openGroup ) {
|
199
|
+
group.isOpen = false;
|
200
|
+
}
|
201
|
+
});
|
202
|
+
}
|
203
|
+
};
|
204
|
+
|
205
|
+
// This is called from the accordion-group directive to add itself to the accordion
|
206
|
+
this.addGroup = function(groupScope) {
|
207
|
+
var that = this;
|
208
|
+
this.groups.push(groupScope);
|
209
|
+
|
210
|
+
groupScope.$on('$destroy', function (event) {
|
211
|
+
that.removeGroup(groupScope);
|
212
|
+
});
|
213
|
+
};
|
214
|
+
|
215
|
+
// This is called from the accordion-group directive when to remove itself
|
216
|
+
this.removeGroup = function(group) {
|
217
|
+
var index = this.groups.indexOf(group);
|
218
|
+
if ( index !== -1 ) {
|
219
|
+
this.groups.splice(this.groups.indexOf(group), 1);
|
220
|
+
}
|
221
|
+
};
|
222
|
+
|
223
|
+
}])
|
224
|
+
|
225
|
+
// The accordion directive simply sets up the directive controller
|
226
|
+
// and adds an accordion CSS class to itself element.
|
227
|
+
.directive('accordion', function () {
|
228
|
+
return {
|
229
|
+
restrict:'EA',
|
230
|
+
controller:'AccordionController',
|
231
|
+
transclude: true,
|
232
|
+
replace: false,
|
233
|
+
templateUrl: 'template/accordion/accordion.html'
|
234
|
+
};
|
235
|
+
})
|
236
|
+
|
237
|
+
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
|
238
|
+
.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
|
239
|
+
return {
|
240
|
+
require:'^accordion', // We need this directive to be inside an accordion
|
241
|
+
restrict:'EA',
|
242
|
+
transclude:true, // It transcludes the contents of the directive into the template
|
243
|
+
replace: true, // The element containing the directive will be replaced with the template
|
244
|
+
templateUrl:'template/accordion/accordion-group.html',
|
245
|
+
scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope
|
246
|
+
controller: ['$scope', function($scope) {
|
247
|
+
this.setHeading = function(element) {
|
248
|
+
this.heading = element;
|
249
|
+
};
|
250
|
+
}],
|
251
|
+
link: function(scope, element, attrs, accordionCtrl) {
|
252
|
+
var getIsOpen, setIsOpen;
|
253
|
+
|
254
|
+
accordionCtrl.addGroup(scope);
|
255
|
+
|
256
|
+
scope.isOpen = false;
|
257
|
+
|
258
|
+
if ( attrs.isOpen ) {
|
259
|
+
getIsOpen = $parse(attrs.isOpen);
|
260
|
+
setIsOpen = getIsOpen.assign;
|
261
|
+
|
262
|
+
scope.$watch(
|
263
|
+
function watchIsOpen() { return getIsOpen(scope.$parent); },
|
264
|
+
function updateOpen(value) { scope.isOpen = value; }
|
265
|
+
);
|
266
|
+
|
267
|
+
scope.isOpen = getIsOpen ? getIsOpen(scope.$parent) : false;
|
268
|
+
}
|
269
|
+
|
270
|
+
scope.$watch('isOpen', function(value) {
|
271
|
+
if ( value ) {
|
272
|
+
accordionCtrl.closeOthers(scope);
|
273
|
+
}
|
274
|
+
if ( setIsOpen ) {
|
275
|
+
setIsOpen(scope.$parent, value);
|
276
|
+
}
|
277
|
+
});
|
278
|
+
}
|
279
|
+
};
|
280
|
+
}])
|
281
|
+
|
282
|
+
// Use accordion-heading below an accordion-group to provide a heading containing HTML
|
283
|
+
// <accordion-group>
|
284
|
+
// <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
|
285
|
+
// </accordion-group>
|
286
|
+
.directive('accordionHeading', function() {
|
287
|
+
return {
|
288
|
+
restrict: 'EA',
|
289
|
+
transclude: true, // Grab the contents to be used as the heading
|
290
|
+
template: '', // In effect remove this element!
|
291
|
+
replace: true,
|
292
|
+
require: '^accordionGroup',
|
293
|
+
compile: function(element, attr, transclude) {
|
294
|
+
return function link(scope, element, attr, accordionGroupCtrl) {
|
295
|
+
// Pass the heading to the accordion-group controller
|
296
|
+
// so that it can be transcluded into the right place in the template
|
297
|
+
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
|
298
|
+
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
|
299
|
+
};
|
300
|
+
}
|
301
|
+
};
|
302
|
+
})
|
303
|
+
|
304
|
+
// Use in the accordion-group template to indicate where you want the heading to be transcluded
|
305
|
+
// You must provide the property on the accordion-group controller that will hold the transcluded element
|
306
|
+
// <div class="accordion-group">
|
307
|
+
// <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
|
308
|
+
// ...
|
309
|
+
// </div>
|
310
|
+
.directive('accordionTransclude', function() {
|
311
|
+
return {
|
312
|
+
require: '^accordionGroup',
|
313
|
+
link: function(scope, element, attr, controller) {
|
314
|
+
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
|
315
|
+
if ( heading ) {
|
316
|
+
element.html('');
|
317
|
+
element.append(heading);
|
318
|
+
}
|
319
|
+
});
|
320
|
+
}
|
321
|
+
};
|
322
|
+
});
|
323
|
+
|
324
324
|
angular.module("ui.bootstrap.alert", []).directive('alert', function () {
|
325
325
|
return {
|
326
326
|
restrict:'EA',
|
@@ -336,93 +336,78 @@ angular.module("ui.bootstrap.alert", []).directive('alert', function () {
|
|
336
336
|
}
|
337
337
|
};
|
338
338
|
});
|
339
|
-
|
340
|
-
angular.module('ui.bootstrap.buttons', [])
|
341
|
-
|
342
|
-
.constant('buttonConfig', {
|
343
|
-
activeClass:'active',
|
344
|
-
toggleEvent:'click'
|
345
|
-
})
|
346
|
-
|
347
|
-
.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
|
348
|
-
var activeClass = buttonConfig.activeClass || 'active';
|
349
|
-
var toggleEvent = buttonConfig.toggleEvent || 'click';
|
350
|
-
|
351
|
-
return {
|
352
|
-
|
353
|
-
require:'ngModel',
|
354
|
-
link:function (scope, element, attrs, ngModelCtrl) {
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue);
|
411
|
-
});
|
412
|
-
});
|
413
|
-
}
|
414
|
-
};
|
415
|
-
}]);
|
416
|
-
/*
|
417
|
-
*
|
418
|
-
* AngularJS Bootstrap Carousel
|
339
|
+
|
340
|
+
angular.module('ui.bootstrap.buttons', [])
|
341
|
+
|
342
|
+
.constant('buttonConfig', {
|
343
|
+
activeClass:'active',
|
344
|
+
toggleEvent:'click'
|
345
|
+
})
|
346
|
+
|
347
|
+
.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
|
348
|
+
var activeClass = buttonConfig.activeClass || 'active';
|
349
|
+
var toggleEvent = buttonConfig.toggleEvent || 'click';
|
350
|
+
|
351
|
+
return {
|
352
|
+
|
353
|
+
require:'ngModel',
|
354
|
+
link:function (scope, element, attrs, ngModelCtrl) {
|
355
|
+
|
356
|
+
//model -> UI
|
357
|
+
ngModelCtrl.$render = function () {
|
358
|
+
element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
|
359
|
+
};
|
360
|
+
|
361
|
+
//ui->model
|
362
|
+
element.bind(toggleEvent, function () {
|
363
|
+
if (!element.hasClass(activeClass)) {
|
364
|
+
scope.$apply(function () {
|
365
|
+
ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio));
|
366
|
+
ngModelCtrl.$render();
|
367
|
+
});
|
368
|
+
}
|
369
|
+
});
|
370
|
+
}
|
371
|
+
};
|
372
|
+
}])
|
373
|
+
|
374
|
+
.directive('btnCheckbox', ['buttonConfig', function (buttonConfig) {
|
375
|
+
|
376
|
+
var activeClass = buttonConfig.activeClass || 'active';
|
377
|
+
var toggleEvent = buttonConfig.toggleEvent || 'click';
|
378
|
+
|
379
|
+
return {
|
380
|
+
require:'ngModel',
|
381
|
+
link:function (scope, element, attrs, ngModelCtrl) {
|
382
|
+
|
383
|
+
var trueValue = scope.$eval(attrs.btnCheckboxTrue);
|
384
|
+
var falseValue = scope.$eval(attrs.btnCheckboxFalse);
|
385
|
+
|
386
|
+
trueValue = angular.isDefined(trueValue) ? trueValue : true;
|
387
|
+
falseValue = angular.isDefined(falseValue) ? falseValue : false;
|
388
|
+
|
389
|
+
//model -> UI
|
390
|
+
ngModelCtrl.$render = function () {
|
391
|
+
element.toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, trueValue));
|
392
|
+
};
|
393
|
+
|
394
|
+
//ui->model
|
395
|
+
element.bind(toggleEvent, function () {
|
396
|
+
scope.$apply(function () {
|
397
|
+
ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue);
|
398
|
+
ngModelCtrl.$render();
|
399
|
+
});
|
400
|
+
});
|
401
|
+
}
|
402
|
+
};
|
403
|
+
}]);
|
404
|
+
/**
|
405
|
+
* @ngdoc overview
|
406
|
+
* @name ui.bootstrap.carousel
|
407
|
+
*
|
408
|
+
* @description
|
409
|
+
* AngularJS version of an image carousel.
|
419
410
|
*
|
420
|
-
* A pure AngularJS carousel.
|
421
|
-
*
|
422
|
-
* For no interval set the interval to non-number, or milliseconds of desired interval
|
423
|
-
* Template: <carousel interval="none"><slide>{{anything}}</slide></carousel>
|
424
|
-
* To change the carousel's active slide set the active attribute to true
|
425
|
-
* Template: <carousel interval="none"><slide active="someModel">{{anything}}</slide></carousel>
|
426
411
|
*/
|
427
412
|
angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
428
413
|
.controller('CarouselController', ['$scope', '$timeout', '$transition', '$q', function ($scope, $timeout, $transition, $q) {
|
@@ -492,12 +477,20 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
492
477
|
|
493
478
|
$scope.next = function() {
|
494
479
|
var newIndex = (currentIndex + 1) % slides.length;
|
495
|
-
|
480
|
+
|
481
|
+
//Prevent this user-triggered transition from occurring if there is already one in progress
|
482
|
+
if (!$scope.$currentTransition) {
|
483
|
+
return self.select(slides[newIndex], 'next');
|
484
|
+
}
|
496
485
|
};
|
497
486
|
|
498
487
|
$scope.prev = function() {
|
499
488
|
var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
|
500
|
-
|
489
|
+
|
490
|
+
//Prevent this user-triggered transition from occurring if there is already one in progress
|
491
|
+
if (!$scope.$currentTransition) {
|
492
|
+
return self.select(slides[newIndex], 'prev');
|
493
|
+
}
|
501
494
|
};
|
502
495
|
|
503
496
|
$scope.select = function(slide) {
|
@@ -537,9 +530,11 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
537
530
|
}
|
538
531
|
};
|
539
532
|
$scope.pause = function() {
|
540
|
-
|
541
|
-
|
542
|
-
|
533
|
+
if (!$scope.noPause) {
|
534
|
+
isPlaying = false;
|
535
|
+
if (currentTimeout) {
|
536
|
+
$timeout.cancel(currentTimeout);
|
537
|
+
}
|
543
538
|
}
|
544
539
|
};
|
545
540
|
|
@@ -567,9 +562,50 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
567
562
|
} else {
|
568
563
|
self.select(slides[index]);
|
569
564
|
}
|
565
|
+
} else if (currentIndex > index) {
|
566
|
+
currentIndex--;
|
570
567
|
}
|
571
568
|
};
|
572
569
|
}])
|
570
|
+
|
571
|
+
/**
|
572
|
+
* @ngdoc directive
|
573
|
+
* @name ui.bootstrap.carousel.directive:carousel
|
574
|
+
* @restrict EA
|
575
|
+
*
|
576
|
+
* @description
|
577
|
+
* Carousel is the outer container for a set of image 'slides' to showcase.
|
578
|
+
*
|
579
|
+
* @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
|
580
|
+
* @param {boolean=} noTransition Whether to disable transitions on the carousel.
|
581
|
+
* @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
|
582
|
+
*
|
583
|
+
* @example
|
584
|
+
<example module="ui.bootstrap">
|
585
|
+
<file name="index.html">
|
586
|
+
<carousel>
|
587
|
+
<slide>
|
588
|
+
<img src="http://placekitten.com/150/150" style="margin:auto;">
|
589
|
+
<div class="carousel-caption">
|
590
|
+
<p>Beautiful!</p>
|
591
|
+
</div>
|
592
|
+
</slide>
|
593
|
+
<slide>
|
594
|
+
<img src="http://placekitten.com/100/150" style="margin:auto;">
|
595
|
+
<div class="carousel-caption">
|
596
|
+
<p>D'aww!</p>
|
597
|
+
</div>
|
598
|
+
</slide>
|
599
|
+
</carousel>
|
600
|
+
</file>
|
601
|
+
<file name="demo.css">
|
602
|
+
.carousel-indicators {
|
603
|
+
top: auto;
|
604
|
+
bottom: 15px;
|
605
|
+
}
|
606
|
+
</file>
|
607
|
+
</example>
|
608
|
+
*/
|
573
609
|
.directive('carousel', [function() {
|
574
610
|
return {
|
575
611
|
restrict: 'EA',
|
@@ -580,11 +616,77 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
580
616
|
templateUrl: 'template/carousel/carousel.html',
|
581
617
|
scope: {
|
582
618
|
interval: '=',
|
583
|
-
noTransition: '='
|
619
|
+
noTransition: '=',
|
620
|
+
noPause: '='
|
584
621
|
}
|
585
622
|
};
|
586
623
|
}])
|
587
|
-
|
624
|
+
|
625
|
+
/**
|
626
|
+
* @ngdoc directive
|
627
|
+
* @name ui.bootstrap.carousel.directive:slide
|
628
|
+
* @restrict EA
|
629
|
+
*
|
630
|
+
* @description
|
631
|
+
* Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element.
|
632
|
+
*
|
633
|
+
* @param {boolean=} active Model binding, whether or not this slide is currently active.
|
634
|
+
*
|
635
|
+
* @example
|
636
|
+
<example module="ui.bootstrap">
|
637
|
+
<file name="index.html">
|
638
|
+
<div ng-controller="CarouselDemoCtrl">
|
639
|
+
<carousel>
|
640
|
+
<slide ng-repeat="slide in slides" active="slide.active">
|
641
|
+
<img ng-src="{{slide.image}}" style="margin:auto;">
|
642
|
+
<div class="carousel-caption">
|
643
|
+
<h4>Slide {{$index}}</h4>
|
644
|
+
<p>{{slide.text}}</p>
|
645
|
+
</div>
|
646
|
+
</slide>
|
647
|
+
</carousel>
|
648
|
+
<div class="row-fluid">
|
649
|
+
<div class="span6">
|
650
|
+
<ul>
|
651
|
+
<li ng-repeat="slide in slides">
|
652
|
+
<button class="btn btn-mini" ng-class="{'btn-info': !slide.active, 'btn-success': slide.active}" ng-disabled="slide.active" ng-click="slide.active = true">select</button>
|
653
|
+
{{$index}}: {{slide.text}}
|
654
|
+
</li>
|
655
|
+
</ul>
|
656
|
+
<a class="btn" ng-click="addSlide()">Add Slide</a>
|
657
|
+
</div>
|
658
|
+
<div class="span6">
|
659
|
+
Interval, in milliseconds: <input type="number" ng-model="myInterval">
|
660
|
+
<br />Enter a negative number to stop the interval.
|
661
|
+
</div>
|
662
|
+
</div>
|
663
|
+
</div>
|
664
|
+
</file>
|
665
|
+
<file name="script.js">
|
666
|
+
function CarouselDemoCtrl($scope) {
|
667
|
+
$scope.myInterval = 5000;
|
668
|
+
var slides = $scope.slides = [];
|
669
|
+
$scope.addSlide = function() {
|
670
|
+
var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
|
671
|
+
slides.push({
|
672
|
+
image: 'http://placekitten.com/' + newWidth + '/200',
|
673
|
+
text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' '
|
674
|
+
['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4]
|
675
|
+
});
|
676
|
+
};
|
677
|
+
for (var i=0; i<4; i++) $scope.addSlide();
|
678
|
+
}
|
679
|
+
</file>
|
680
|
+
<file name="demo.css">
|
681
|
+
.carousel-indicators {
|
682
|
+
top: auto;
|
683
|
+
bottom: 15px;
|
684
|
+
}
|
685
|
+
</file>
|
686
|
+
</example>
|
687
|
+
*/
|
688
|
+
|
689
|
+
.directive('slide', ['$parse', function($parse) {
|
588
690
|
return {
|
589
691
|
require: '^carousel',
|
590
692
|
restrict: 'EA',
|
@@ -592,9 +694,30 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
592
694
|
replace: true,
|
593
695
|
templateUrl: 'template/carousel/slide.html',
|
594
696
|
scope: {
|
595
|
-
active: '='
|
596
697
|
},
|
597
698
|
link: function (scope, element, attrs, carouselCtrl) {
|
699
|
+
//Set up optional 'active' = binding
|
700
|
+
if (attrs.active) {
|
701
|
+
var getActive = $parse(attrs.active);
|
702
|
+
var setActive = getActive.assign;
|
703
|
+
var lastValue = scope.active = getActive(scope.$parent);
|
704
|
+
scope.$watch(function parentActiveWatch() {
|
705
|
+
var parentActive = getActive(scope.$parent);
|
706
|
+
|
707
|
+
if (parentActive !== scope.active) {
|
708
|
+
// we are out of sync and need to copy
|
709
|
+
if (parentActive !== lastValue) {
|
710
|
+
// parent changed and it has precedence
|
711
|
+
lastValue = scope.active = parentActive;
|
712
|
+
} else {
|
713
|
+
// if the parent can be assigned then do so
|
714
|
+
setActive(scope.$parent, parentActive = lastValue = scope.active);
|
715
|
+
}
|
716
|
+
}
|
717
|
+
return parentActive;
|
718
|
+
});
|
719
|
+
}
|
720
|
+
|
598
721
|
carouselCtrl.addSlide(scope, element);
|
599
722
|
//when the scope is destroyed then remove the slide from the current slides array
|
600
723
|
scope.$on('$destroy', function() {
|
@@ -609,7 +732,221 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
609
732
|
}
|
610
733
|
};
|
611
734
|
}]);
|
612
|
-
|
735
|
+
|
736
|
+
angular.module('ui.bootstrap.datepicker', [])
|
737
|
+
|
738
|
+
.constant('datepickerConfig', {
|
739
|
+
dayFormat: 'dd',
|
740
|
+
monthFormat: 'MMMM',
|
741
|
+
yearFormat: 'yyyy',
|
742
|
+
dayHeaderFormat: 'EEE',
|
743
|
+
dayTitleFormat: 'MMMM yyyy',
|
744
|
+
monthTitleFormat: 'yyyy',
|
745
|
+
showWeeks: true,
|
746
|
+
startingDay: 0,
|
747
|
+
yearRange: 20
|
748
|
+
})
|
749
|
+
|
750
|
+
.directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', function (dateFilter, $parse, datepickerConfig) {
|
751
|
+
return {
|
752
|
+
restrict: 'EA',
|
753
|
+
replace: true,
|
754
|
+
scope: {
|
755
|
+
model: '=ngModel',
|
756
|
+
dateDisabled: '&'
|
757
|
+
},
|
758
|
+
templateUrl: 'template/datepicker/datepicker.html',
|
759
|
+
link: function(scope, element, attrs) {
|
760
|
+
scope.mode = 'day'; // Initial mode
|
761
|
+
|
762
|
+
// Configuration parameters
|
763
|
+
var selected = new Date(), showWeeks, minDate, maxDate, format = {};
|
764
|
+
format.day = angular.isDefined(attrs.dayFormat) ? scope.$eval(attrs.dayFormat) : datepickerConfig.dayFormat;
|
765
|
+
format.month = angular.isDefined(attrs.monthFormat) ? scope.$eval(attrs.monthFormat) : datepickerConfig.monthFormat;
|
766
|
+
format.year = angular.isDefined(attrs.yearFormat) ? scope.$eval(attrs.yearFormat) : datepickerConfig.yearFormat;
|
767
|
+
format.dayHeader = angular.isDefined(attrs.dayHeaderFormat) ? scope.$eval(attrs.dayHeaderFormat) : datepickerConfig.dayHeaderFormat;
|
768
|
+
format.dayTitle = angular.isDefined(attrs.dayTitleFormat) ? scope.$eval(attrs.dayTitleFormat) : datepickerConfig.dayTitleFormat;
|
769
|
+
format.monthTitle = angular.isDefined(attrs.monthTitleFormat) ? scope.$eval(attrs.monthTitleFormat) : datepickerConfig.monthTitleFormat;
|
770
|
+
var startingDay = angular.isDefined(attrs.startingDay) ? scope.$eval(attrs.startingDay) : datepickerConfig.startingDay;
|
771
|
+
var yearRange = angular.isDefined(attrs.yearRange) ? scope.$eval(attrs.yearRange) : datepickerConfig.yearRange;
|
772
|
+
|
773
|
+
if (attrs.showWeeks) {
|
774
|
+
scope.$parent.$watch($parse(attrs.showWeeks), function(value) {
|
775
|
+
showWeeks = !! value;
|
776
|
+
updateShowWeekNumbers();
|
777
|
+
});
|
778
|
+
} else {
|
779
|
+
showWeeks = datepickerConfig.showWeeks;
|
780
|
+
updateShowWeekNumbers();
|
781
|
+
}
|
782
|
+
|
783
|
+
if (attrs.min) {
|
784
|
+
scope.$parent.$watch($parse(attrs.min), function(value) {
|
785
|
+
minDate = new Date(value);
|
786
|
+
refill();
|
787
|
+
});
|
788
|
+
}
|
789
|
+
if (attrs.max) {
|
790
|
+
scope.$parent.$watch($parse(attrs.max), function(value) {
|
791
|
+
maxDate = new Date(value);
|
792
|
+
refill();
|
793
|
+
});
|
794
|
+
}
|
795
|
+
|
796
|
+
function updateCalendar (rows, labels, title) {
|
797
|
+
scope.rows = rows;
|
798
|
+
scope.labels = labels;
|
799
|
+
scope.title = title;
|
800
|
+
}
|
801
|
+
|
802
|
+
// Define whether the week number are visible
|
803
|
+
function updateShowWeekNumbers() {
|
804
|
+
scope.showWeekNumbers = ( scope.mode === 'day' && showWeeks );
|
805
|
+
}
|
806
|
+
|
807
|
+
function compare( date1, date2 ) {
|
808
|
+
if ( scope.mode === 'year') {
|
809
|
+
return date2.getFullYear() - date1.getFullYear();
|
810
|
+
} else if ( scope.mode === 'month' ) {
|
811
|
+
return new Date( date2.getFullYear(), date2.getMonth() ) - new Date( date1.getFullYear(), date1.getMonth() );
|
812
|
+
} else if ( scope.mode === 'day' ) {
|
813
|
+
return (new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) - new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) );
|
814
|
+
}
|
815
|
+
}
|
816
|
+
|
817
|
+
function isDisabled(date) {
|
818
|
+
return ((minDate && compare(date, minDate) > 0) || (maxDate && compare(date, maxDate) < 0) || (scope.dateDisabled && scope.dateDisabled({ date: date, mode: scope.mode })));
|
819
|
+
}
|
820
|
+
|
821
|
+
// Split array into smaller arrays
|
822
|
+
var split = function(a, size) {
|
823
|
+
var arrays = [];
|
824
|
+
while (a.length > 0) {
|
825
|
+
arrays.push(a.splice(0, size));
|
826
|
+
}
|
827
|
+
return arrays;
|
828
|
+
};
|
829
|
+
var getDaysInMonth = function( year, month ) {
|
830
|
+
return new Date(year, month + 1, 0).getDate();
|
831
|
+
};
|
832
|
+
|
833
|
+
var fill = {
|
834
|
+
day: function() {
|
835
|
+
var days = [], labels = [], lastDate = null;
|
836
|
+
|
837
|
+
function addDays( dt, n, isCurrentMonth ) {
|
838
|
+
for (var i =0; i < n; i ++) {
|
839
|
+
days.push( {date: new Date(dt), isCurrent: isCurrentMonth, isSelected: isSelected(dt), label: dateFilter(dt, format.day), disabled: isDisabled(dt) } );
|
840
|
+
dt.setDate( dt.getDate() + 1 );
|
841
|
+
}
|
842
|
+
lastDate = dt;
|
843
|
+
}
|
844
|
+
|
845
|
+
var d = new Date(selected);
|
846
|
+
d.setDate(1);
|
847
|
+
|
848
|
+
var difference = startingDay - d.getDay();
|
849
|
+
var numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference;
|
850
|
+
|
851
|
+
if ( numDisplayedFromPreviousMonth > 0 ) {
|
852
|
+
d.setDate( - numDisplayedFromPreviousMonth + 1 );
|
853
|
+
addDays(d, numDisplayedFromPreviousMonth, false);
|
854
|
+
}
|
855
|
+
addDays(lastDate || d, getDaysInMonth(selected.getFullYear(), selected.getMonth()), true);
|
856
|
+
addDays(lastDate, (7 - days.length % 7) % 7, false);
|
857
|
+
|
858
|
+
// Day labels
|
859
|
+
for (i = 0; i < 7; i++) {
|
860
|
+
labels.push( dateFilter(days[i].date, format.dayHeader) );
|
861
|
+
}
|
862
|
+
updateCalendar( split( days, 7 ), labels, dateFilter(selected, format.dayTitle) );
|
863
|
+
},
|
864
|
+
month: function() {
|
865
|
+
var months = [], i = 0, year = selected.getFullYear();
|
866
|
+
while ( i < 12 ) {
|
867
|
+
var dt = new Date(year, i++, 1);
|
868
|
+
months.push( {date: dt, isCurrent: true, isSelected: isSelected(dt), label: dateFilter(dt, format.month), disabled: isDisabled(dt)} );
|
869
|
+
}
|
870
|
+
updateCalendar( split( months, 3 ), [], dateFilter(selected, format.monthTitle) );
|
871
|
+
},
|
872
|
+
year: function() {
|
873
|
+
var years = [], year = parseInt((selected.getFullYear() - 1) / yearRange, 10) * yearRange + 1;
|
874
|
+
for ( var i = 0; i < yearRange; i++ ) {
|
875
|
+
var dt = new Date(year + i, 0, 1);
|
876
|
+
years.push( {date: dt, isCurrent: true, isSelected: isSelected(dt), label: dateFilter(dt, format.year), disabled: isDisabled(dt)} );
|
877
|
+
}
|
878
|
+
var title = years[0].label + ' - ' + years[years.length - 1].label;
|
879
|
+
updateCalendar( split( years, 5 ), [], title );
|
880
|
+
}
|
881
|
+
};
|
882
|
+
var refill = function() {
|
883
|
+
fill[scope.mode]();
|
884
|
+
};
|
885
|
+
var isSelected = function( dt ) {
|
886
|
+
if ( scope.model && scope.model.getFullYear() === dt.getFullYear() ) {
|
887
|
+
if ( scope.mode === 'year' ) {
|
888
|
+
return true;
|
889
|
+
}
|
890
|
+
if ( scope.model.getMonth() === dt.getMonth() ) {
|
891
|
+
return ( scope.mode === 'month' || (scope.mode === 'day' && scope.model.getDate() === dt.getDate()) );
|
892
|
+
}
|
893
|
+
}
|
894
|
+
return false;
|
895
|
+
};
|
896
|
+
|
897
|
+
scope.$watch('model', function ( dt, olddt ) {
|
898
|
+
if ( angular.isDate(dt) ) {
|
899
|
+
selected = angular.copy(dt);
|
900
|
+
}
|
901
|
+
|
902
|
+
if ( ! angular.equals(dt, olddt) ) {
|
903
|
+
refill();
|
904
|
+
}
|
905
|
+
});
|
906
|
+
scope.$watch('mode', function() {
|
907
|
+
updateShowWeekNumbers();
|
908
|
+
refill();
|
909
|
+
});
|
910
|
+
|
911
|
+
scope.select = function( dt ) {
|
912
|
+
selected = new Date(dt);
|
913
|
+
|
914
|
+
if ( scope.mode === 'year' ) {
|
915
|
+
scope.mode = 'month';
|
916
|
+
selected.setFullYear( dt.getFullYear() );
|
917
|
+
} else if ( scope.mode === 'month' ) {
|
918
|
+
scope.mode = 'day';
|
919
|
+
selected.setMonth( dt.getMonth() );
|
920
|
+
} else if ( scope.mode === 'day' ) {
|
921
|
+
scope.model = new Date(selected);
|
922
|
+
}
|
923
|
+
};
|
924
|
+
scope.move = function(step) {
|
925
|
+
if (scope.mode === 'day') {
|
926
|
+
selected.setMonth( selected.getMonth() + step );
|
927
|
+
} else if (scope.mode === 'month') {
|
928
|
+
selected.setFullYear( selected.getFullYear() + step );
|
929
|
+
} else if (scope.mode === 'year') {
|
930
|
+
selected.setFullYear( selected.getFullYear() + step * yearRange );
|
931
|
+
}
|
932
|
+
refill();
|
933
|
+
};
|
934
|
+
scope.toggleMode = function() {
|
935
|
+
scope.mode = ( scope.mode === 'day' ) ? 'month' : ( scope.mode === 'month' ) ? 'year' : 'day';
|
936
|
+
};
|
937
|
+
scope.getWeekNumber = function(row) {
|
938
|
+
if ( scope.mode !== 'day' || ! scope.showWeekNumbers || row.length !== 7 ) {
|
939
|
+
return;
|
940
|
+
}
|
941
|
+
|
942
|
+
var index = ( startingDay > 4 ) ? 11 - startingDay : 4 - startingDay; // Thursday
|
943
|
+
var d = new Date( row[ index ].date );
|
944
|
+
d.setHours(0, 0, 0);
|
945
|
+
return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 86400000) + 1) / 7); // 86400000 = 1000*60*60*24;
|
946
|
+
};
|
947
|
+
}
|
948
|
+
};
|
949
|
+
}]);
|
613
950
|
// The `$dialogProvider` can be used to configure global defaults for your
|
614
951
|
// `$dialog` service.
|
615
952
|
var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']);
|
@@ -632,7 +969,6 @@ dialogModule.provider("$dialog", function(){
|
|
632
969
|
backdropClass: 'modal-backdrop',
|
633
970
|
transitionClass: 'fade',
|
634
971
|
triggerClass: 'in',
|
635
|
-
dialogOpenClass: 'modal-open',
|
636
972
|
resolve:{},
|
637
973
|
backdropFade: false,
|
638
974
|
dialogFade:false,
|
@@ -744,7 +1080,6 @@ dialogModule.provider("$dialog", function(){
|
|
744
1080
|
|
745
1081
|
$compile(self.modalEl)($scope);
|
746
1082
|
self._addElementsToDom();
|
747
|
-
body.addClass(self.options.dialogOpenClass);
|
748
1083
|
|
749
1084
|
// trigger tranisitions
|
750
1085
|
setTimeout(function(){
|
@@ -764,7 +1099,6 @@ dialogModule.provider("$dialog", function(){
|
|
764
1099
|
var self = this;
|
765
1100
|
var fadingElements = this._getFadingElements();
|
766
1101
|
|
767
|
-
body.removeClass(self.options.dialogOpenClass);
|
768
1102
|
if(fadingElements.length > 0){
|
769
1103
|
for (var i = fadingElements.length - 1; i >= 0; i--) {
|
770
1104
|
$transition(fadingElements[i], removeTriggerClass).then(onCloseComplete);
|
@@ -800,8 +1134,6 @@ dialogModule.provider("$dialog", function(){
|
|
800
1134
|
Dialog.prototype._bindEvents = function() {
|
801
1135
|
if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); }
|
802
1136
|
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); }
|
803
|
-
|
804
|
-
this.$scope.$on('$locationChangeSuccess', this.handleLocationChange);
|
805
1137
|
};
|
806
1138
|
|
807
1139
|
Dialog.prototype._unbindEvents = function() {
|
@@ -899,7 +1231,7 @@ dialogModule.provider("$dialog", function(){
|
|
899
1231
|
};
|
900
1232
|
}];
|
901
1233
|
});
|
902
|
-
|
1234
|
+
|
903
1235
|
/*
|
904
1236
|
* dropdownToggle - Provides dropdown menu functionality in place of bootstrap js
|
905
1237
|
* @restrict class or attribute
|
@@ -914,8 +1246,7 @@ dialogModule.provider("$dialog", function(){
|
|
914
1246
|
</li>
|
915
1247
|
*/
|
916
1248
|
|
917
|
-
angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
|
918
|
-
['$document', '$location', '$window', function ($document, $location, $window) {
|
1249
|
+
angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) {
|
919
1250
|
var openElement = null,
|
920
1251
|
closeMenu = angular.noop;
|
921
1252
|
return {
|
@@ -923,13 +1254,18 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
|
|
923
1254
|
link: function(scope, element, attrs) {
|
924
1255
|
scope.$watch('$location.path', function() { closeMenu(); });
|
925
1256
|
element.parent().bind('click', function() { closeMenu(); });
|
926
|
-
element.bind('click', function(event) {
|
1257
|
+
element.bind('click', function (event) {
|
1258
|
+
|
1259
|
+
var elementWasOpen = (element === openElement);
|
1260
|
+
|
927
1261
|
event.preventDefault();
|
928
1262
|
event.stopPropagation();
|
929
|
-
|
1263
|
+
|
930
1264
|
if (!!openElement) {
|
931
|
-
closeMenu();
|
932
|
-
|
1265
|
+
closeMenu();
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
if (!elementWasOpen) {
|
933
1269
|
element.parent().addClass('open');
|
934
1270
|
openElement = element;
|
935
1271
|
closeMenu = function (event) {
|
@@ -939,7 +1275,7 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
|
|
939
1275
|
}
|
940
1276
|
$document.unbind('click', closeMenu);
|
941
1277
|
element.parent().removeClass('open');
|
942
|
-
closeMenu
|
1278
|
+
closeMenu = angular.noop;
|
943
1279
|
openElement = null;
|
944
1280
|
};
|
945
1281
|
$document.bind('click', closeMenu);
|
@@ -947,7 +1283,7 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle',
|
|
947
1283
|
});
|
948
1284
|
}
|
949
1285
|
};
|
950
|
-
}]);
|
1286
|
+
}]);
|
951
1287
|
angular.module('ui.bootstrap.modal', ['ui.bootstrap.dialog'])
|
952
1288
|
.directive('modal', ['$parse', '$dialog', function($parse, $dialog) {
|
953
1289
|
return {
|
@@ -994,16 +1330,38 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.dialog'])
|
|
994
1330
|
});
|
995
1331
|
}
|
996
1332
|
};
|
997
|
-
}]);
|
1333
|
+
}]);
|
998
1334
|
angular.module('ui.bootstrap.pagination', [])
|
999
1335
|
|
1336
|
+
.controller('PaginationController', ['$scope', function (scope) {
|
1337
|
+
|
1338
|
+
scope.noPrevious = function() {
|
1339
|
+
return scope.currentPage === 1;
|
1340
|
+
};
|
1341
|
+
scope.noNext = function() {
|
1342
|
+
return scope.currentPage === scope.numPages;
|
1343
|
+
};
|
1344
|
+
|
1345
|
+
scope.isActive = function(page) {
|
1346
|
+
return scope.currentPage === page;
|
1347
|
+
};
|
1348
|
+
|
1349
|
+
scope.selectPage = function(page) {
|
1350
|
+
if ( ! scope.isActive(page) && page > 0 && page <= scope.numPages) {
|
1351
|
+
scope.currentPage = page;
|
1352
|
+
scope.onSelectPage({ page: page });
|
1353
|
+
}
|
1354
|
+
};
|
1355
|
+
}])
|
1356
|
+
|
1000
1357
|
.constant('paginationConfig', {
|
1001
1358
|
boundaryLinks: false,
|
1002
1359
|
directionLinks: true,
|
1003
1360
|
firstText: 'First',
|
1004
1361
|
previousText: 'Previous',
|
1005
1362
|
nextText: 'Next',
|
1006
|
-
lastText: 'Last'
|
1363
|
+
lastText: 'Last',
|
1364
|
+
rotate: true
|
1007
1365
|
})
|
1008
1366
|
|
1009
1367
|
.directive('pagination', ['paginationConfig', function(paginationConfig) {
|
@@ -1015,6 +1373,7 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1015
1373
|
maxSize: '=',
|
1016
1374
|
onSelectPage: '&'
|
1017
1375
|
},
|
1376
|
+
controller: 'PaginationController',
|
1018
1377
|
templateUrl: 'template/pagination/pagination.html',
|
1019
1378
|
replace: true,
|
1020
1379
|
link: function(scope, element, attrs) {
|
@@ -1022,10 +1381,11 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1022
1381
|
// Setup configuration parameters
|
1023
1382
|
var boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
|
1024
1383
|
var directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$eval(attrs.directionLinks) : paginationConfig.directionLinks;
|
1025
|
-
var firstText = angular.isDefined(attrs.firstText) ? attrs.firstText : paginationConfig.firstText;
|
1026
|
-
var previousText = angular.isDefined(attrs.previousText) ? attrs.previousText : paginationConfig.previousText;
|
1027
|
-
var nextText = angular.isDefined(attrs.nextText) ? attrs.nextText : paginationConfig.nextText;
|
1028
|
-
var lastText = angular.isDefined(attrs.lastText) ? attrs.lastText : paginationConfig.lastText;
|
1384
|
+
var firstText = angular.isDefined(attrs.firstText) ? scope.$parent.$eval(attrs.firstText) : paginationConfig.firstText;
|
1385
|
+
var previousText = angular.isDefined(attrs.previousText) ? scope.$parent.$eval(attrs.previousText) : paginationConfig.previousText;
|
1386
|
+
var nextText = angular.isDefined(attrs.nextText) ? scope.$parent.$eval(attrs.nextText) : paginationConfig.nextText;
|
1387
|
+
var lastText = angular.isDefined(attrs.lastText) ? scope.$parent.$eval(attrs.lastText) : paginationConfig.lastText;
|
1388
|
+
var rotate = angular.isDefined(attrs.rotate) ? scope.$eval(attrs.rotate) : paginationConfig.rotate;
|
1029
1389
|
|
1030
1390
|
// Create page object used in template
|
1031
1391
|
function makePage(number, text, isActive, isDisabled) {
|
@@ -1042,16 +1402,26 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1042
1402
|
|
1043
1403
|
// Default page limits
|
1044
1404
|
var startPage = 1, endPage = scope.numPages;
|
1405
|
+
var isMaxSized = ( angular.isDefined(scope.maxSize) && scope.maxSize < scope.numPages );
|
1045
1406
|
|
1046
1407
|
// recompute if maxSize
|
1047
|
-
if (
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1408
|
+
if ( isMaxSized ) {
|
1409
|
+
if ( rotate ) {
|
1410
|
+
// Current page is displayed in the middle of the visible ones
|
1411
|
+
startPage = Math.max(scope.currentPage - Math.floor(scope.maxSize/2), 1);
|
1412
|
+
endPage = startPage + scope.maxSize - 1;
|
1413
|
+
|
1414
|
+
// Adjust if limit is exceeded
|
1415
|
+
if (endPage > scope.numPages) {
|
1416
|
+
endPage = scope.numPages;
|
1417
|
+
startPage = endPage - scope.maxSize + 1;
|
1418
|
+
}
|
1419
|
+
} else {
|
1420
|
+
// Visible pages are paginated with maxSize
|
1421
|
+
startPage = ((Math.ceil(scope.currentPage / scope.maxSize) - 1) * scope.maxSize) + 1;
|
1422
|
+
|
1423
|
+
// Adjust last page if limit is exceeded
|
1424
|
+
endPage = Math.min(startPage + scope.maxSize - 1, scope.numPages);
|
1055
1425
|
}
|
1056
1426
|
}
|
1057
1427
|
|
@@ -1061,6 +1431,19 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1061
1431
|
scope.pages.push(page);
|
1062
1432
|
}
|
1063
1433
|
|
1434
|
+
// Add links to move between page sets
|
1435
|
+
if ( isMaxSized && ! rotate ) {
|
1436
|
+
if ( startPage > 1 ) {
|
1437
|
+
var previousPageSet = makePage(startPage - 1, '...', false, false);
|
1438
|
+
scope.pages.unshift(previousPageSet);
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
if ( endPage < scope.numPages ) {
|
1442
|
+
var nextPageSet = makePage(endPage + 1, '...', false, false);
|
1443
|
+
scope.pages.push(nextPageSet);
|
1444
|
+
}
|
1445
|
+
}
|
1446
|
+
|
1064
1447
|
// Add previous & next links
|
1065
1448
|
if (directionLinks) {
|
1066
1449
|
var previousPage = makePage(scope.currentPage - 1, previousText, false, scope.noPrevious());
|
@@ -1079,116 +1462,167 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1079
1462
|
scope.pages.push(lastPage);
|
1080
1463
|
}
|
1081
1464
|
|
1082
|
-
|
1083
1465
|
if ( scope.currentPage > scope.numPages ) {
|
1084
1466
|
scope.selectPage(scope.numPages);
|
1085
1467
|
}
|
1086
1468
|
});
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1469
|
+
}
|
1470
|
+
};
|
1471
|
+
}])
|
1472
|
+
|
1473
|
+
.constant('pagerConfig', {
|
1474
|
+
previousText: '« Previous',
|
1475
|
+
nextText: 'Next »',
|
1476
|
+
align: true
|
1477
|
+
})
|
1478
|
+
|
1479
|
+
.directive('pager', ['pagerConfig', function(config) {
|
1480
|
+
return {
|
1481
|
+
restrict: 'EA',
|
1482
|
+
scope: {
|
1483
|
+
numPages: '=',
|
1484
|
+
currentPage: '=',
|
1485
|
+
onSelectPage: '&'
|
1486
|
+
},
|
1487
|
+
controller: 'PaginationController',
|
1488
|
+
templateUrl: 'template/pagination/pager.html',
|
1489
|
+
replace: true,
|
1490
|
+
link: function(scope, element, attrs, paginationCtrl) {
|
1491
|
+
|
1492
|
+
// Setup configuration parameters
|
1493
|
+
var previousText = angular.isDefined(attrs.previousText) ? scope.$parent.$eval(attrs.previousText) : config.previousText;
|
1494
|
+
var nextText = angular.isDefined(attrs.nextText) ? scope.$parent.$eval(attrs.nextText) : config.nextText;
|
1495
|
+
var align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : config.align;
|
1496
|
+
|
1497
|
+
// Create page object used in template
|
1498
|
+
function makePage(number, text, isDisabled, isPrevious, isNext) {
|
1499
|
+
return {
|
1500
|
+
number: number,
|
1501
|
+
text: text,
|
1502
|
+
disabled: isDisabled,
|
1503
|
+
previous: ( align && isPrevious ),
|
1504
|
+
next: ( align && isNext )
|
1505
|
+
};
|
1506
|
+
}
|
1096
1507
|
|
1097
|
-
scope
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1508
|
+
scope.$watch('numPages + currentPage', function() {
|
1509
|
+
scope.pages = [];
|
1510
|
+
|
1511
|
+
// Add previous & next links
|
1512
|
+
var previousPage = makePage(scope.currentPage - 1, previousText, scope.noPrevious(), true, false);
|
1513
|
+
scope.pages.unshift(previousPage);
|
1514
|
+
|
1515
|
+
var nextPage = makePage(scope.currentPage + 1, nextText, scope.noNext(), false, true);
|
1516
|
+
scope.pages.push(nextPage);
|
1517
|
+
|
1518
|
+
if ( scope.currentPage > scope.numPages ) {
|
1519
|
+
scope.selectPage(scope.numPages);
|
1101
1520
|
}
|
1102
|
-
};
|
1521
|
+
});
|
1103
1522
|
}
|
1104
1523
|
};
|
1105
|
-
}]);
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
* A set of utility methods that can be use to retrieve position of DOM elements.
|
1110
|
-
* It is meant to be used where we need to absolute-position DOM elements in
|
1111
|
-
* relation to other, existing elements (this is the case for tooltips, popovers,
|
1112
|
-
* typeahead suggestions etc.).
|
1113
|
-
*/
|
1114
|
-
.factory('$position', ['$document', '$window', function ($document, $window) {
|
1115
|
-
|
1116
|
-
function getStyle(el, cssprop) {
|
1117
|
-
if (el.currentStyle) { //IE
|
1118
|
-
return el.currentStyle[cssprop];
|
1119
|
-
} else if ($window.getComputedStyle) {
|
1120
|
-
return $window.getComputedStyle(el)[cssprop];
|
1121
|
-
}
|
1122
|
-
// finally try and get inline style
|
1123
|
-
return el.style[cssprop];
|
1124
|
-
}
|
1125
|
-
|
1126
|
-
/**
|
1127
|
-
* Checks if a given element is statically positioned
|
1128
|
-
* @param element - raw DOM element
|
1129
|
-
*/
|
1130
|
-
function isStaticPositioned(element) {
|
1131
|
-
return (getStyle(element, "position") || 'static' ) === 'static';
|
1132
|
-
}
|
1133
|
-
|
1134
|
-
/**
|
1135
|
-
* returns the closest, non-statically positioned parentOffset of a given element
|
1136
|
-
* @param element
|
1137
|
-
*/
|
1138
|
-
var parentOffsetEl = function (element) {
|
1139
|
-
var docDomEl = $document[0];
|
1140
|
-
var offsetParent = element.offsetParent || docDomEl;
|
1141
|
-
while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
|
1142
|
-
offsetParent = offsetParent.offsetParent;
|
1143
|
-
}
|
1144
|
-
return offsetParent || docDomEl;
|
1145
|
-
};
|
1146
|
-
|
1147
|
-
return {
|
1148
|
-
/**
|
1149
|
-
* Provides read-only equivalent of jQuery's position function:
|
1150
|
-
* http://api.jquery.com/position/
|
1151
|
-
*/
|
1152
|
-
position: function (element) {
|
1153
|
-
var elBCR = this.offset(element);
|
1154
|
-
var offsetParentBCR = { top: 0, left: 0 };
|
1155
|
-
var offsetParentEl = parentOffsetEl(element[0]);
|
1156
|
-
if (offsetParentEl != $document[0]) {
|
1157
|
-
offsetParentBCR = this.offset(angular.element(offsetParentEl));
|
1158
|
-
offsetParentBCR.top += offsetParentEl.clientTop;
|
1159
|
-
offsetParentBCR.left += offsetParentEl.clientLeft;
|
1160
|
-
}
|
1161
|
-
|
1162
|
-
return {
|
1163
|
-
width: element.prop('offsetWidth'),
|
1164
|
-
height: element.prop('offsetHeight'),
|
1165
|
-
top: elBCR.top - offsetParentBCR.top,
|
1166
|
-
left: elBCR.left - offsetParentBCR.left
|
1167
|
-
};
|
1168
|
-
},
|
1169
|
-
|
1170
|
-
/**
|
1171
|
-
* Provides read-only equivalent of jQuery's offset function:
|
1172
|
-
* http://api.jquery.com/offset/
|
1173
|
-
*/
|
1174
|
-
offset: function (element) {
|
1175
|
-
var boundingClientRect = element[0].getBoundingClientRect();
|
1176
|
-
return {
|
1177
|
-
width: element.prop('offsetWidth'),
|
1178
|
-
height: element.prop('offsetHeight'),
|
1179
|
-
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop),
|
1180
|
-
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft)
|
1181
|
-
};
|
1182
|
-
}
|
1183
|
-
};
|
1184
|
-
}]);
|
1185
|
-
|
1524
|
+
}]);
|
1525
|
+
|
1526
|
+
angular.module('ui.bootstrap.position', [])
|
1527
|
+
|
1186
1528
|
/**
|
1187
|
-
*
|
1188
|
-
*
|
1189
|
-
*
|
1529
|
+
* A set of utility methods that can be use to retrieve position of DOM elements.
|
1530
|
+
* It is meant to be used where we need to absolute-position DOM elements in
|
1531
|
+
* relation to other, existing elements (this is the case for tooltips, popovers,
|
1532
|
+
* typeahead suggestions etc.).
|
1190
1533
|
*/
|
1191
|
-
|
1534
|
+
.factory('$position', ['$document', '$window', function ($document, $window) {
|
1535
|
+
|
1536
|
+
var mouseX, mouseY;
|
1537
|
+
|
1538
|
+
$document.bind('mousemove', function mouseMoved(event) {
|
1539
|
+
mouseX = event.pageX;
|
1540
|
+
mouseY = event.pageY;
|
1541
|
+
});
|
1542
|
+
|
1543
|
+
function getStyle(el, cssprop) {
|
1544
|
+
if (el.currentStyle) { //IE
|
1545
|
+
return el.currentStyle[cssprop];
|
1546
|
+
} else if ($window.getComputedStyle) {
|
1547
|
+
return $window.getComputedStyle(el)[cssprop];
|
1548
|
+
}
|
1549
|
+
// finally try and get inline style
|
1550
|
+
return el.style[cssprop];
|
1551
|
+
}
|
1552
|
+
|
1553
|
+
/**
|
1554
|
+
* Checks if a given element is statically positioned
|
1555
|
+
* @param element - raw DOM element
|
1556
|
+
*/
|
1557
|
+
function isStaticPositioned(element) {
|
1558
|
+
return (getStyle(element, "position") || 'static' ) === 'static';
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
/**
|
1562
|
+
* returns the closest, non-statically positioned parentOffset of a given element
|
1563
|
+
* @param element
|
1564
|
+
*/
|
1565
|
+
var parentOffsetEl = function (element) {
|
1566
|
+
var docDomEl = $document[0];
|
1567
|
+
var offsetParent = element.offsetParent || docDomEl;
|
1568
|
+
while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
|
1569
|
+
offsetParent = offsetParent.offsetParent;
|
1570
|
+
}
|
1571
|
+
return offsetParent || docDomEl;
|
1572
|
+
};
|
1573
|
+
|
1574
|
+
return {
|
1575
|
+
/**
|
1576
|
+
* Provides read-only equivalent of jQuery's position function:
|
1577
|
+
* http://api.jquery.com/position/
|
1578
|
+
*/
|
1579
|
+
position: function (element) {
|
1580
|
+
var elBCR = this.offset(element);
|
1581
|
+
var offsetParentBCR = { top: 0, left: 0 };
|
1582
|
+
var offsetParentEl = parentOffsetEl(element[0]);
|
1583
|
+
if (offsetParentEl != $document[0]) {
|
1584
|
+
offsetParentBCR = this.offset(angular.element(offsetParentEl));
|
1585
|
+
offsetParentBCR.top += offsetParentEl.clientTop;
|
1586
|
+
offsetParentBCR.left += offsetParentEl.clientLeft;
|
1587
|
+
}
|
1588
|
+
|
1589
|
+
return {
|
1590
|
+
width: element.prop('offsetWidth'),
|
1591
|
+
height: element.prop('offsetHeight'),
|
1592
|
+
top: elBCR.top - offsetParentBCR.top,
|
1593
|
+
left: elBCR.left - offsetParentBCR.left
|
1594
|
+
};
|
1595
|
+
},
|
1596
|
+
|
1597
|
+
/**
|
1598
|
+
* Provides read-only equivalent of jQuery's offset function:
|
1599
|
+
* http://api.jquery.com/offset/
|
1600
|
+
*/
|
1601
|
+
offset: function (element) {
|
1602
|
+
var boundingClientRect = element[0].getBoundingClientRect();
|
1603
|
+
return {
|
1604
|
+
width: element.prop('offsetWidth'),
|
1605
|
+
height: element.prop('offsetHeight'),
|
1606
|
+
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop),
|
1607
|
+
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft)
|
1608
|
+
};
|
1609
|
+
},
|
1610
|
+
|
1611
|
+
/**
|
1612
|
+
* Provides the coordinates of the mouse
|
1613
|
+
*/
|
1614
|
+
mouse: function () {
|
1615
|
+
return {x: mouseX, y: mouseY};
|
1616
|
+
}
|
1617
|
+
};
|
1618
|
+
}]);
|
1619
|
+
|
1620
|
+
/**
|
1621
|
+
* The following features are still outstanding: animation as a
|
1622
|
+
* function, placement as a function, inside, support for more triggers than
|
1623
|
+
* just mouse enter/leave, html tooltips, and selector delegation.
|
1624
|
+
*/
|
1625
|
+
angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
1192
1626
|
|
1193
1627
|
/**
|
1194
1628
|
* The $tooltip service creates tooltip- and popover-like directives as well as
|
@@ -1225,6 +1659,15 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1225
1659
|
angular.extend( globalOptions, value );
|
1226
1660
|
};
|
1227
1661
|
|
1662
|
+
/**
|
1663
|
+
* This allows you to extend the set of trigger mappings available. E.g.:
|
1664
|
+
*
|
1665
|
+
* $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
|
1666
|
+
*/
|
1667
|
+
this.setTriggers = function setTriggers ( triggers ) {
|
1668
|
+
angular.extend( triggerMap, triggers );
|
1669
|
+
};
|
1670
|
+
|
1228
1671
|
/**
|
1229
1672
|
* This is a helper function for translating camel-case to snake-case.
|
1230
1673
|
*/
|
@@ -1240,7 +1683,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1240
1683
|
* Returns the actual instance of the $tooltip service.
|
1241
1684
|
* TODO support multiple triggers
|
1242
1685
|
*/
|
1243
|
-
this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', function ( $window, $compile, $timeout, $parse, $document, $position ) {
|
1686
|
+
this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) {
|
1244
1687
|
return function $tooltip ( type, prefix, defaultTriggerShow ) {
|
1245
1688
|
var options = angular.extend( {}, defaultOptions, globalOptions );
|
1246
1689
|
|
@@ -1277,11 +1720,13 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1277
1720
|
var directiveName = snake_case( type );
|
1278
1721
|
var triggers = setTriggers( undefined );
|
1279
1722
|
|
1723
|
+
var startSym = $interpolate.startSymbol();
|
1724
|
+
var endSym = $interpolate.endSymbol();
|
1280
1725
|
var template =
|
1281
1726
|
'<'+ directiveName +'-popup '+
|
1282
|
-
'title="
|
1283
|
-
'content="
|
1284
|
-
'placement="
|
1727
|
+
'title="'+startSym+'tt_title'+endSym+'" '+
|
1728
|
+
'content="'+startSym+'tt_content'+endSym+'" '+
|
1729
|
+
'placement="'+startSym+'tt_placement'+endSym+'" '+
|
1285
1730
|
'animation="tt_animation()" '+
|
1286
1731
|
'is-open="tt_isOpen"'+
|
1287
1732
|
'>'+
|
@@ -1295,6 +1740,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1295
1740
|
var transitionTimeout;
|
1296
1741
|
var popupTimeout;
|
1297
1742
|
var $body;
|
1743
|
+
var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
|
1298
1744
|
|
1299
1745
|
// By default, the tooltip is not open.
|
1300
1746
|
// TODO add ability to start tooltip opened
|
@@ -1346,15 +1792,15 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1346
1792
|
|
1347
1793
|
// Now we add it to the DOM because need some info about it. But it's not
|
1348
1794
|
// visible yet anyway.
|
1349
|
-
if (
|
1795
|
+
if ( appendToBody ) {
|
1350
1796
|
$body = $body || $document.find( 'body' );
|
1351
1797
|
$body.append( tooltip );
|
1352
1798
|
} else {
|
1353
1799
|
element.after( tooltip );
|
1354
1800
|
}
|
1355
|
-
|
1801
|
+
|
1356
1802
|
// Get the position of the directive element.
|
1357
|
-
position = $position.position( element );
|
1803
|
+
position = options.appendToBody ? $position.offset( element ) : $position.position( element );
|
1358
1804
|
|
1359
1805
|
// Get the height and width of the tooltip so we can center it.
|
1360
1806
|
ttWidth = tooltip.prop( 'offsetWidth' );
|
@@ -1363,32 +1809,42 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1363
1809
|
// Calculate the tooltip's top and left coordinates to center it with
|
1364
1810
|
// this directive.
|
1365
1811
|
switch ( scope.tt_placement ) {
|
1812
|
+
case 'mouse':
|
1813
|
+
var mousePos = $position.mouse();
|
1814
|
+
ttPosition = {
|
1815
|
+
top: mousePos.y,
|
1816
|
+
left: mousePos.x
|
1817
|
+
};
|
1818
|
+
break;
|
1366
1819
|
case 'right':
|
1367
1820
|
ttPosition = {
|
1368
|
-
top:
|
1369
|
-
left:
|
1821
|
+
top: position.top + position.height / 2 - ttHeight / 2,
|
1822
|
+
left: position.left + position.width
|
1370
1823
|
};
|
1371
1824
|
break;
|
1372
1825
|
case 'bottom':
|
1373
1826
|
ttPosition = {
|
1374
|
-
top:
|
1375
|
-
left:
|
1827
|
+
top: position.top + position.height,
|
1828
|
+
left: position.left + position.width / 2 - ttWidth / 2
|
1376
1829
|
};
|
1377
1830
|
break;
|
1378
1831
|
case 'left':
|
1379
1832
|
ttPosition = {
|
1380
|
-
top:
|
1381
|
-
left:
|
1833
|
+
top: position.top + position.height / 2 - ttHeight / 2,
|
1834
|
+
left: position.left - ttWidth
|
1382
1835
|
};
|
1383
1836
|
break;
|
1384
1837
|
default:
|
1385
1838
|
ttPosition = {
|
1386
|
-
top:
|
1387
|
-
left:
|
1839
|
+
top: position.top - ttHeight,
|
1840
|
+
left: position.left + position.width / 2 - ttWidth / 2
|
1388
1841
|
};
|
1389
1842
|
break;
|
1390
1843
|
}
|
1391
|
-
|
1844
|
+
|
1845
|
+
ttPosition.top += 'px';
|
1846
|
+
ttPosition.left += 'px';
|
1847
|
+
|
1392
1848
|
// Now set the calculated positioning.
|
1393
1849
|
tooltip.css( ttPosition );
|
1394
1850
|
|
@@ -1451,6 +1907,30 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1451
1907
|
element.bind( triggers.hide, hideTooltipBind );
|
1452
1908
|
}
|
1453
1909
|
});
|
1910
|
+
|
1911
|
+
attrs.$observe( prefix+'AppendToBody', function ( val ) {
|
1912
|
+
appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody;
|
1913
|
+
});
|
1914
|
+
|
1915
|
+
// if a tooltip is attached to <body> we need to remove it on
|
1916
|
+
// location change as its parent scope will probably not be destroyed
|
1917
|
+
// by the change.
|
1918
|
+
if ( appendToBody ) {
|
1919
|
+
scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () {
|
1920
|
+
if ( scope.tt_isOpen ) {
|
1921
|
+
hide();
|
1922
|
+
}
|
1923
|
+
});
|
1924
|
+
}
|
1925
|
+
|
1926
|
+
// Make sure tooltip is destroyed and removed.
|
1927
|
+
scope.$on('$destroy', function onDestroyTooltip() {
|
1928
|
+
if ( scope.tt_isOpen ) {
|
1929
|
+
hide();
|
1930
|
+
} else {
|
1931
|
+
tooltip.remove();
|
1932
|
+
}
|
1933
|
+
});
|
1454
1934
|
}
|
1455
1935
|
};
|
1456
1936
|
};
|
@@ -1481,11 +1961,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1481
1961
|
|
1482
1962
|
.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) {
|
1483
1963
|
return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' );
|
1484
|
-
}])
|
1485
|
-
|
1486
|
-
;
|
1964
|
+
}]);
|
1487
1965
|
|
1488
|
-
|
1489
1966
|
/**
|
1490
1967
|
* The following features are still outstanding: popup delay, animation as a
|
1491
1968
|
* function, placement as a function, inside, support for more triggers than
|
@@ -1504,7 +1981,7 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
|
|
1504
1981
|
return $tooltip( 'popover', 'popover', 'click' );
|
1505
1982
|
}]);
|
1506
1983
|
|
1507
|
-
|
1984
|
+
|
1508
1985
|
angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
|
1509
1986
|
|
1510
1987
|
.constant('progressConfig', {
|
@@ -1556,7 +2033,7 @@ angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
|
|
1556
2033
|
replace: true,
|
1557
2034
|
controller: 'ProgressBarController',
|
1558
2035
|
scope: {
|
1559
|
-
value: '=',
|
2036
|
+
value: '=percent',
|
1560
2037
|
onFull: '&',
|
1561
2038
|
onEmpty: '&'
|
1562
2039
|
},
|
@@ -1610,7 +2087,7 @@ angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
|
|
1610
2087
|
});
|
1611
2088
|
}
|
1612
2089
|
};
|
1613
|
-
}]);
|
2090
|
+
}]);
|
1614
2091
|
angular.module('ui.bootstrap.rating', [])
|
1615
2092
|
|
1616
2093
|
.constant('ratingConfig', {
|
@@ -1663,320 +2140,787 @@ angular.module('ui.bootstrap.rating', [])
|
|
1663
2140
|
}
|
1664
2141
|
}
|
1665
2142
|
};
|
1666
|
-
}]);
|
2143
|
+
}]);
|
2144
|
+
|
2145
|
+
/**
|
2146
|
+
* @ngdoc overview
|
2147
|
+
* @name ui.bootstrap.tabs
|
2148
|
+
*
|
2149
|
+
* @description
|
2150
|
+
* AngularJS version of the tabs directive.
|
2151
|
+
*/
|
2152
|
+
|
1667
2153
|
angular.module('ui.bootstrap.tabs', [])
|
1668
|
-
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
|
1669
|
-
var panes = $scope.panes = [];
|
1670
2154
|
|
1671
|
-
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
2155
|
+
.directive('tabs', function() {
|
2156
|
+
return function() {
|
2157
|
+
throw new Error("The `tabs` directive is deprecated, please migrate to `tabset`. Instructions can be found at http://github.com/angular-ui/bootstrap/tree/master/CHANGELOG.md");
|
2158
|
+
};
|
2159
|
+
})
|
2160
|
+
|
2161
|
+
.controller('TabsetController', ['$scope', '$element',
|
2162
|
+
function TabsetCtrl($scope, $element) {
|
2163
|
+
var ctrl = this,
|
2164
|
+
tabs = ctrl.tabs = $scope.tabs = [];
|
2165
|
+
|
2166
|
+
ctrl.select = function(tab) {
|
2167
|
+
angular.forEach(tabs, function(tab) {
|
2168
|
+
tab.active = false;
|
2169
|
+
});
|
2170
|
+
tab.active = true;
|
1676
2171
|
};
|
1677
2172
|
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
2173
|
+
ctrl.addTab = function addTab(tab) {
|
2174
|
+
tabs.push(tab);
|
2175
|
+
if (tabs.length == 1) {
|
2176
|
+
ctrl.select(tab);
|
1681
2177
|
}
|
1682
|
-
panes.push(pane);
|
1683
2178
|
};
|
1684
2179
|
|
1685
|
-
|
1686
|
-
var index =
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
2180
|
+
ctrl.removeTab = function removeTab(tab) {
|
2181
|
+
var index = tabs.indexOf(tab);
|
2182
|
+
//Select a new tab if the tab to be removed is selected
|
2183
|
+
if (tab.active && tabs.length > 1) {
|
2184
|
+
//If this is the last tab, select the previous tab. else, the next tab.
|
2185
|
+
var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
|
2186
|
+
ctrl.select(tabs[newActiveIndex]);
|
1691
2187
|
}
|
2188
|
+
tabs.splice(index, 1);
|
1692
2189
|
};
|
1693
2190
|
}])
|
1694
|
-
|
2191
|
+
|
2192
|
+
/**
|
2193
|
+
* @ngdoc directive
|
2194
|
+
* @name ui.bootstrap.tabs.directive:tabset
|
2195
|
+
* @restrict EA
|
2196
|
+
*
|
2197
|
+
* @description
|
2198
|
+
* Tabset is the outer container for the tabs directive
|
2199
|
+
*
|
2200
|
+
* @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
|
2201
|
+
*
|
2202
|
+
* @example
|
2203
|
+
<example module="ui.bootstrap">
|
2204
|
+
<file name="index.html">
|
2205
|
+
<tabset>
|
2206
|
+
<tab heading="Vertical Tab 1"><b>First</b> Content!</tab>
|
2207
|
+
<tab heading="Vertical Tab 2"><i>Second</i> Content!</tab>
|
2208
|
+
</tabset>
|
2209
|
+
<hr />
|
2210
|
+
<tabset vertical="true">
|
2211
|
+
<tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
|
2212
|
+
<tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
|
2213
|
+
</tabset>
|
2214
|
+
</file>
|
2215
|
+
</example>
|
2216
|
+
*/
|
2217
|
+
.directive('tabset', function() {
|
1695
2218
|
return {
|
1696
2219
|
restrict: 'EA',
|
1697
2220
|
transclude: true,
|
1698
2221
|
scope: {},
|
1699
|
-
controller: '
|
1700
|
-
templateUrl: 'template/tabs/
|
1701
|
-
|
2222
|
+
controller: 'TabsetController',
|
2223
|
+
templateUrl: 'template/tabs/tabset.html',
|
2224
|
+
link: function(scope, element, attrs) {
|
2225
|
+
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$eval(attrs.vertical) : false;
|
2226
|
+
scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs';
|
2227
|
+
}
|
1702
2228
|
};
|
1703
2229
|
})
|
1704
|
-
|
2230
|
+
|
2231
|
+
/**
|
2232
|
+
* @ngdoc directive
|
2233
|
+
* @name ui.bootstrap.tabs.directive:tab
|
2234
|
+
* @restrict EA
|
2235
|
+
*
|
2236
|
+
* @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
|
2237
|
+
* @param {string=} select An expression to evaluate when the tab is selected.
|
2238
|
+
* @param {boolean=} active A binding, telling whether or not this tab is selected.
|
2239
|
+
* @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
|
2240
|
+
*
|
2241
|
+
* @description
|
2242
|
+
* Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
|
2243
|
+
*
|
2244
|
+
* @example
|
2245
|
+
<example module="ui.bootstrap">
|
2246
|
+
<file name="index.html">
|
2247
|
+
<div ng-controller="TabsDemoCtrl">
|
2248
|
+
<button class="btn btn-small" ng-click="items[0].active = true">
|
2249
|
+
Select item 1, using active binding
|
2250
|
+
</button>
|
2251
|
+
<button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
|
2252
|
+
Enable/disable item 2, using disabled binding
|
2253
|
+
</button>
|
2254
|
+
<br />
|
2255
|
+
<tabset>
|
2256
|
+
<tab heading="Tab 1">First Tab</tab>
|
2257
|
+
<tab select="alertMe()">
|
2258
|
+
<tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
|
2259
|
+
Second Tab, with alert callback and html heading!
|
2260
|
+
</tab>
|
2261
|
+
<tab ng-repeat="item in items"
|
2262
|
+
heading="{{item.title}}"
|
2263
|
+
disabled="item.disabled"
|
2264
|
+
active="item.active">
|
2265
|
+
{{item.content}}
|
2266
|
+
</tab>
|
2267
|
+
</tabset>
|
2268
|
+
</div>
|
2269
|
+
</file>
|
2270
|
+
<file name="script.js">
|
2271
|
+
function TabsDemoCtrl($scope) {
|
2272
|
+
$scope.items = [
|
2273
|
+
{ title:"Dynamic Title 1", content:"Dynamic Item 0" },
|
2274
|
+
{ title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
|
2275
|
+
];
|
2276
|
+
|
2277
|
+
$scope.alertMe = function() {
|
2278
|
+
setTimeout(function() {
|
2279
|
+
alert("You've selected the alert tab!");
|
2280
|
+
});
|
2281
|
+
};
|
2282
|
+
};
|
2283
|
+
</file>
|
2284
|
+
</example>
|
2285
|
+
*/
|
2286
|
+
|
2287
|
+
/**
|
2288
|
+
* @ngdoc directive
|
2289
|
+
* @name ui.bootstrap.tabs.directive:tabHeading
|
2290
|
+
* @restrict EA
|
2291
|
+
*
|
2292
|
+
* @description
|
2293
|
+
* Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
|
2294
|
+
*
|
2295
|
+
* @example
|
2296
|
+
<example module="ui.bootstrap">
|
2297
|
+
<file name="index.html">
|
2298
|
+
<tabset>
|
2299
|
+
<tab>
|
2300
|
+
<tab-heading><b>HTML</b> in my titles?!</tab-heading>
|
2301
|
+
And some content, too!
|
2302
|
+
</tab>
|
2303
|
+
<tab>
|
2304
|
+
<tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
|
2305
|
+
That's right.
|
2306
|
+
</tab>
|
2307
|
+
</tabset>
|
2308
|
+
</file>
|
2309
|
+
</example>
|
2310
|
+
*/
|
2311
|
+
.directive('tab', ['$parse', '$http', '$templateCache', '$compile',
|
2312
|
+
function($parse, $http, $templateCache, $compile) {
|
1705
2313
|
return {
|
1706
|
-
require: '^
|
2314
|
+
require: '^tabset',
|
1707
2315
|
restrict: 'EA',
|
2316
|
+
replace: true,
|
2317
|
+
templateUrl: 'template/tabs/tab.html',
|
1708
2318
|
transclude: true,
|
1709
|
-
scope:{
|
1710
|
-
heading:'@'
|
2319
|
+
scope: {
|
2320
|
+
heading: '@',
|
2321
|
+
onSelect: '&select' //This callback is called in contentHeadingTransclude
|
2322
|
+
//once it inserts the tab's content into the dom
|
1711
2323
|
},
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
scope
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
2324
|
+
controller: function() {
|
2325
|
+
//Empty controller so other directives can require being 'under' a tab
|
2326
|
+
},
|
2327
|
+
compile: function(elm, attrs, transclude) {
|
2328
|
+
return function postLink(scope, elm, attrs, tabsetCtrl) {
|
2329
|
+
var getActive, setActive;
|
2330
|
+
scope.active = false; // default value
|
2331
|
+
if (attrs.active) {
|
2332
|
+
getActive = $parse(attrs.active);
|
2333
|
+
setActive = getActive.assign;
|
2334
|
+
scope.$parent.$watch(getActive, function updateActive(value) {
|
2335
|
+
if ( !!value && scope.disabled ) {
|
2336
|
+
setActive(scope.$parent, false); // Prevent active assignment
|
2337
|
+
} else {
|
2338
|
+
scope.active = !!value;
|
2339
|
+
}
|
2340
|
+
});
|
2341
|
+
} else {
|
2342
|
+
setActive = getActive = angular.noop;
|
1727
2343
|
}
|
1728
|
-
|
1729
|
-
|
2344
|
+
|
2345
|
+
scope.$watch('active', function(active) {
|
2346
|
+
setActive(scope.$parent, active);
|
2347
|
+
if (active) {
|
2348
|
+
tabsetCtrl.select(scope);
|
2349
|
+
scope.onSelect();
|
2350
|
+
}
|
2351
|
+
});
|
2352
|
+
|
2353
|
+
scope.disabled = false;
|
2354
|
+
if ( attrs.disabled ) {
|
2355
|
+
scope.$parent.$watch($parse(attrs.disabled), function(value) {
|
2356
|
+
scope.disabled = !! value;
|
2357
|
+
});
|
2358
|
+
}
|
2359
|
+
|
2360
|
+
scope.select = function() {
|
2361
|
+
if ( ! scope.disabled ) {
|
2362
|
+
scope.active = true;
|
2363
|
+
}
|
2364
|
+
};
|
2365
|
+
|
2366
|
+
tabsetCtrl.addTab(scope);
|
2367
|
+
scope.$on('$destroy', function() {
|
2368
|
+
tabsetCtrl.removeTab(scope);
|
2369
|
+
});
|
2370
|
+
//If the tabset sets this tab to active, set the parent scope's active
|
2371
|
+
//binding too. We do this so the watch for the parent's initial active
|
2372
|
+
//value won't overwrite what is initially set by the tabset
|
2373
|
+
if (scope.active) {
|
2374
|
+
setActive(scope.$parent, true);
|
2375
|
+
}
|
2376
|
+
|
2377
|
+
//Transclude the collection of sibling elements. Use forEach to find
|
2378
|
+
//the heading if it exists. We don't use a directive for tab-heading
|
2379
|
+
//because it is problematic. Discussion @ http://git.io/MSNPwQ
|
2380
|
+
transclude(scope.$parent, function(clone) {
|
2381
|
+
//Look at every element in the clone collection. If it's tab-heading,
|
2382
|
+
//mark it as that. If it's not tab-heading, mark it as tab contents
|
2383
|
+
var contents = [], heading;
|
2384
|
+
angular.forEach(clone, function(el) {
|
2385
|
+
//See if it's a tab-heading attr or element directive
|
2386
|
+
//First make sure it's a normal element, one that has a tagName
|
2387
|
+
if (el.tagName &&
|
2388
|
+
(el.hasAttribute("tab-heading") ||
|
2389
|
+
el.hasAttribute("data-tab-heading") ||
|
2390
|
+
el.tagName.toLowerCase() == "tab-heading" ||
|
2391
|
+
el.tagName.toLowerCase() == "data-tab-heading"
|
2392
|
+
)) {
|
2393
|
+
heading = el;
|
2394
|
+
} else {
|
2395
|
+
contents.push(el);
|
2396
|
+
}
|
2397
|
+
});
|
2398
|
+
//Share what we found on the scope, so our tabHeadingTransclude and
|
2399
|
+
//tabContentTransclude directives can find out what the heading and
|
2400
|
+
//contents are.
|
2401
|
+
if (heading) {
|
2402
|
+
scope.headingElement = angular.element(heading);
|
2403
|
+
}
|
2404
|
+
scope.contentElement = angular.element(contents);
|
2405
|
+
});
|
2406
|
+
};
|
2407
|
+
}
|
2408
|
+
};
|
2409
|
+
}])
|
2410
|
+
|
2411
|
+
.directive('tabHeadingTransclude', [function() {
|
2412
|
+
return {
|
2413
|
+
restrict: 'A',
|
2414
|
+
require: '^tab',
|
2415
|
+
link: function(scope, elm, attrs, tabCtrl) {
|
2416
|
+
scope.$watch('headingElement', function updateHeadingElement(heading) {
|
2417
|
+
if (heading) {
|
2418
|
+
elm.html('');
|
2419
|
+
elm.append(heading);
|
1730
2420
|
}
|
1731
2421
|
});
|
2422
|
+
}
|
2423
|
+
};
|
2424
|
+
}])
|
1732
2425
|
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
2426
|
+
.directive('tabContentTransclude', ['$parse', function($parse) {
|
2427
|
+
return {
|
2428
|
+
restrict: 'A',
|
2429
|
+
require: '^tabset',
|
2430
|
+
link: function(scope, elm, attrs, tabsetCtrl) {
|
2431
|
+
scope.$watch($parse(attrs.tabContentTransclude), function(tab) {
|
2432
|
+
elm.html('');
|
2433
|
+
if (tab) {
|
2434
|
+
elm.append(tab.contentElement);
|
2435
|
+
}
|
1736
2436
|
});
|
2437
|
+
}
|
2438
|
+
};
|
2439
|
+
}])
|
2440
|
+
|
2441
|
+
;
|
2442
|
+
|
2443
|
+
|
2444
|
+
angular.module('ui.bootstrap.timepicker', [])
|
2445
|
+
|
2446
|
+
.filter('pad', function() {
|
2447
|
+
return function(input) {
|
2448
|
+
if ( angular.isDefined(input) && input.toString().length < 2 ) {
|
2449
|
+
input = '0' + input;
|
2450
|
+
}
|
2451
|
+
return input;
|
2452
|
+
};
|
2453
|
+
})
|
2454
|
+
|
2455
|
+
.constant('timepickerConfig', {
|
2456
|
+
hourStep: 1,
|
2457
|
+
minuteStep: 1,
|
2458
|
+
showMeridian: true,
|
2459
|
+
meridians: ['AM', 'PM'],
|
2460
|
+
readonlyInput: false,
|
2461
|
+
mousewheel: true
|
2462
|
+
})
|
2463
|
+
|
2464
|
+
.directive('timepicker', ['padFilter', '$parse', 'timepickerConfig', function (padFilter, $parse, timepickerConfig) {
|
2465
|
+
return {
|
2466
|
+
restrict: 'EA',
|
2467
|
+
require:'ngModel',
|
2468
|
+
replace: true,
|
2469
|
+
templateUrl: 'template/timepicker/timepicker.html',
|
2470
|
+
scope: {
|
2471
|
+
model: '=ngModel'
|
1737
2472
|
},
|
1738
|
-
|
1739
|
-
|
2473
|
+
link: function(scope, element, attrs, ngModelCtrl) {
|
2474
|
+
var selected = new Date(), meridians = timepickerConfig.meridians;
|
2475
|
+
|
2476
|
+
var hourStep = timepickerConfig.hourStep;
|
2477
|
+
if (attrs.hourStep) {
|
2478
|
+
scope.$parent.$watch($parse(attrs.hourStep), function(value) {
|
2479
|
+
hourStep = parseInt(value, 10);
|
2480
|
+
});
|
2481
|
+
}
|
2482
|
+
|
2483
|
+
var minuteStep = timepickerConfig.minuteStep;
|
2484
|
+
if (attrs.minuteStep) {
|
2485
|
+
scope.$parent.$watch($parse(attrs.minuteStep), function(value) {
|
2486
|
+
minuteStep = parseInt(value, 10);
|
2487
|
+
});
|
2488
|
+
}
|
2489
|
+
|
2490
|
+
// 12H / 24H mode
|
2491
|
+
scope.showMeridian = timepickerConfig.showMeridian;
|
2492
|
+
if (attrs.showMeridian) {
|
2493
|
+
scope.$parent.$watch($parse(attrs.showMeridian), function(value) {
|
2494
|
+
scope.showMeridian = !! value;
|
2495
|
+
|
2496
|
+
if ( ! scope.model ) {
|
2497
|
+
// Reset
|
2498
|
+
var dt = new Date( selected );
|
2499
|
+
var hours = getScopeHours();
|
2500
|
+
if (angular.isDefined( hours )) {
|
2501
|
+
dt.setHours( hours );
|
2502
|
+
}
|
2503
|
+
scope.model = new Date( dt );
|
2504
|
+
} else {
|
2505
|
+
refreshTemplate();
|
2506
|
+
}
|
2507
|
+
});
|
2508
|
+
}
|
2509
|
+
|
2510
|
+
// Get scope.hours in 24H mode if valid
|
2511
|
+
function getScopeHours ( ) {
|
2512
|
+
var hours = parseInt( scope.hours, 10 );
|
2513
|
+
var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
|
2514
|
+
if ( !valid ) {
|
2515
|
+
return;
|
2516
|
+
}
|
2517
|
+
|
2518
|
+
if ( scope.showMeridian ) {
|
2519
|
+
if ( hours === 12 ) {
|
2520
|
+
hours = 0;
|
2521
|
+
}
|
2522
|
+
if ( scope.meridian === meridians[1] ) {
|
2523
|
+
hours = hours + 12;
|
2524
|
+
}
|
2525
|
+
}
|
2526
|
+
return hours;
|
2527
|
+
}
|
2528
|
+
|
2529
|
+
// Input elements
|
2530
|
+
var inputs = element.find('input');
|
2531
|
+
var hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1);
|
2532
|
+
|
2533
|
+
// Respond on mousewheel spin
|
2534
|
+
var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel;
|
2535
|
+
if ( mousewheel ) {
|
2536
|
+
|
2537
|
+
var isScrollingUp = function(e) {
|
2538
|
+
if (e.originalEvent) {
|
2539
|
+
e = e.originalEvent;
|
2540
|
+
}
|
2541
|
+
return (e.detail || e.wheelDelta > 0);
|
2542
|
+
};
|
2543
|
+
|
2544
|
+
hoursInputEl.bind('mousewheel', function(e) {
|
2545
|
+
scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() );
|
2546
|
+
e.preventDefault();
|
2547
|
+
});
|
2548
|
+
|
2549
|
+
minutesInputEl.bind('mousewheel', function(e) {
|
2550
|
+
scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() );
|
2551
|
+
e.preventDefault();
|
2552
|
+
});
|
2553
|
+
}
|
2554
|
+
|
2555
|
+
var keyboardChange = false;
|
2556
|
+
scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput;
|
2557
|
+
if ( ! scope.readonlyInput ) {
|
2558
|
+
scope.updateHours = function() {
|
2559
|
+
var hours = getScopeHours();
|
2560
|
+
|
2561
|
+
if ( angular.isDefined(hours) ) {
|
2562
|
+
keyboardChange = 'h';
|
2563
|
+
if ( scope.model === null ) {
|
2564
|
+
scope.model = new Date( selected );
|
2565
|
+
}
|
2566
|
+
scope.model.setHours( hours );
|
2567
|
+
} else {
|
2568
|
+
scope.model = null;
|
2569
|
+
scope.validHours = false;
|
2570
|
+
}
|
2571
|
+
};
|
2572
|
+
|
2573
|
+
hoursInputEl.bind('blur', function(e) {
|
2574
|
+
if ( scope.validHours && scope.hours < 10) {
|
2575
|
+
scope.$apply( function() {
|
2576
|
+
scope.hours = padFilter( scope.hours );
|
2577
|
+
});
|
2578
|
+
}
|
2579
|
+
});
|
2580
|
+
|
2581
|
+
scope.updateMinutes = function() {
|
2582
|
+
var minutes = parseInt(scope.minutes, 10);
|
2583
|
+
if ( minutes >= 0 && minutes < 60 ) {
|
2584
|
+
keyboardChange = 'm';
|
2585
|
+
if ( scope.model === null ) {
|
2586
|
+
scope.model = new Date( selected );
|
2587
|
+
}
|
2588
|
+
scope.model.setMinutes( minutes );
|
2589
|
+
} else {
|
2590
|
+
scope.model = null;
|
2591
|
+
scope.validMinutes = false;
|
2592
|
+
}
|
2593
|
+
};
|
2594
|
+
|
2595
|
+
minutesInputEl.bind('blur', function(e) {
|
2596
|
+
if ( scope.validMinutes && scope.minutes < 10 ) {
|
2597
|
+
scope.$apply( function() {
|
2598
|
+
scope.minutes = padFilter( scope.minutes );
|
2599
|
+
});
|
2600
|
+
}
|
2601
|
+
});
|
2602
|
+
} else {
|
2603
|
+
scope.updateHours = angular.noop;
|
2604
|
+
scope.updateMinutes = angular.noop;
|
2605
|
+
}
|
2606
|
+
|
2607
|
+
scope.$watch( function getModelTimestamp() {
|
2608
|
+
return +scope.model;
|
2609
|
+
}, function( timestamp ) {
|
2610
|
+
if ( !isNaN( timestamp ) && timestamp > 0 ) {
|
2611
|
+
selected = new Date( timestamp );
|
2612
|
+
refreshTemplate();
|
2613
|
+
}
|
2614
|
+
});
|
2615
|
+
|
2616
|
+
function refreshTemplate() {
|
2617
|
+
var hours = selected.getHours();
|
2618
|
+
if ( scope.showMeridian ) {
|
2619
|
+
// Convert 24 to 12 hour system
|
2620
|
+
hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12;
|
2621
|
+
}
|
2622
|
+
scope.hours = ( keyboardChange === 'h' ) ? hours : padFilter(hours);
|
2623
|
+
scope.validHours = true;
|
2624
|
+
|
2625
|
+
var minutes = selected.getMinutes();
|
2626
|
+
scope.minutes = ( keyboardChange === 'm' ) ? minutes : padFilter(minutes);
|
2627
|
+
scope.validMinutes = true;
|
2628
|
+
|
2629
|
+
scope.meridian = ( scope.showMeridian ) ? (( selected.getHours() < 12 ) ? meridians[0] : meridians[1]) : '';
|
2630
|
+
|
2631
|
+
keyboardChange = false;
|
2632
|
+
}
|
2633
|
+
|
2634
|
+
function addMinutes( minutes ) {
|
2635
|
+
var dt = new Date( selected.getTime() + minutes * 60000 );
|
2636
|
+
if ( dt.getDate() !== selected.getDate()) {
|
2637
|
+
dt.setDate( dt.getDate() - 1 );
|
2638
|
+
}
|
2639
|
+
selected.setTime( dt.getTime() );
|
2640
|
+
scope.model = new Date( selected );
|
2641
|
+
}
|
2642
|
+
|
2643
|
+
scope.incrementHours = function() {
|
2644
|
+
addMinutes( hourStep * 60 );
|
2645
|
+
};
|
2646
|
+
scope.decrementHours = function() {
|
2647
|
+
addMinutes( - hourStep * 60 );
|
2648
|
+
};
|
2649
|
+
scope.incrementMinutes = function() {
|
2650
|
+
addMinutes( minuteStep );
|
2651
|
+
};
|
2652
|
+
scope.decrementMinutes = function() {
|
2653
|
+
addMinutes( - minuteStep );
|
2654
|
+
};
|
2655
|
+
scope.toggleMeridian = function() {
|
2656
|
+
addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
|
2657
|
+
};
|
2658
|
+
}
|
1740
2659
|
};
|
1741
2660
|
}]);
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
*
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
var
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
scope
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
scope.
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
2661
|
+
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
2662
|
+
|
2663
|
+
/**
|
2664
|
+
* A helper service that can parse typeahead's syntax (string provided by users)
|
2665
|
+
* Extracted to a separate service for ease of unit testing
|
2666
|
+
*/
|
2667
|
+
.factory('typeaheadParser', ['$parse', function ($parse) {
|
2668
|
+
|
2669
|
+
// 00000111000000000000022200000000000000003333333333333330000000000044000
|
2670
|
+
var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/;
|
2671
|
+
|
2672
|
+
return {
|
2673
|
+
parse:function (input) {
|
2674
|
+
|
2675
|
+
var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source;
|
2676
|
+
if (!match) {
|
2677
|
+
throw new Error(
|
2678
|
+
"Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" +
|
2679
|
+
" but got '" + input + "'.");
|
2680
|
+
}
|
2681
|
+
|
2682
|
+
return {
|
2683
|
+
itemName:match[3],
|
2684
|
+
source:$parse(match[4]),
|
2685
|
+
viewMapper:$parse(match[2] || match[1]),
|
2686
|
+
modelMapper:$parse(match[1])
|
2687
|
+
};
|
2688
|
+
}
|
2689
|
+
};
|
2690
|
+
}])
|
2691
|
+
|
2692
|
+
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) {
|
2693
|
+
|
2694
|
+
var HOT_KEYS = [9, 13, 27, 38, 40];
|
2695
|
+
|
2696
|
+
return {
|
2697
|
+
require:'ngModel',
|
2698
|
+
link:function (originalScope, element, attrs, modelCtrl) {
|
2699
|
+
|
2700
|
+
var selected;
|
2701
|
+
|
2702
|
+
//minimal no of characters that needs to be entered before typeahead kicks-in
|
2703
|
+
var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
|
2704
|
+
|
2705
|
+
//minimal wait time after last character typed before typehead kicks-in
|
2706
|
+
var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
|
2707
|
+
|
2708
|
+
//expressions used by typeahead
|
2709
|
+
var parserResult = typeaheadParser.parse(attrs.typeahead);
|
2710
|
+
|
2711
|
+
//should it restrict model values to the ones selected from the popup only?
|
2712
|
+
var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
|
2713
|
+
|
2714
|
+
var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
|
2715
|
+
|
2716
|
+
var onSelectCallback = $parse(attrs.typeaheadOnSelect);
|
2717
|
+
|
2718
|
+
//pop-up element used to display matches
|
2719
|
+
var popUpEl = angular.element('<typeahead-popup></typeahead-popup>');
|
2720
|
+
popUpEl.attr({
|
2721
|
+
matches: 'matches',
|
2722
|
+
active: 'activeIdx',
|
2723
|
+
select: 'select(activeIdx)',
|
2724
|
+
query: 'query',
|
2725
|
+
position: 'position'
|
2726
|
+
});
|
2727
|
+
|
2728
|
+
//create a child scope for the typeahead directive so we are not polluting original scope
|
2729
|
+
//with typeahead-specific data (matches, query etc.)
|
2730
|
+
var scope = originalScope.$new();
|
2731
|
+
originalScope.$on('$destroy', function(){
|
2732
|
+
scope.$destroy();
|
2733
|
+
});
|
2734
|
+
|
2735
|
+
var resetMatches = function() {
|
2736
|
+
scope.matches = [];
|
2737
|
+
scope.activeIdx = -1;
|
2738
|
+
};
|
2739
|
+
|
2740
|
+
var getMatchesAsync = function(inputValue) {
|
2741
|
+
|
2742
|
+
var locals = {$viewValue: inputValue};
|
2743
|
+
isLoadingSetter(originalScope, true);
|
2744
|
+
$q.when(parserResult.source(scope, locals)).then(function(matches) {
|
2745
|
+
|
2746
|
+
//it might happen that several async queries were in progress if a user were typing fast
|
2747
|
+
//but we are interested only in responses that correspond to the current view value
|
2748
|
+
if (inputValue === modelCtrl.$viewValue) {
|
2749
|
+
if (matches.length > 0) {
|
2750
|
+
|
2751
|
+
scope.activeIdx = 0;
|
2752
|
+
scope.matches.length = 0;
|
2753
|
+
|
2754
|
+
//transform labels
|
2755
|
+
for(var i=0; i<matches.length; i++) {
|
2756
|
+
locals[parserResult.itemName] = matches[i];
|
2757
|
+
scope.matches.push({
|
2758
|
+
label: parserResult.viewMapper(scope, locals),
|
2759
|
+
model: matches[i]
|
2760
|
+
});
|
2761
|
+
}
|
2762
|
+
|
2763
|
+
scope.query = inputValue;
|
2764
|
+
//position pop-up with matches - we need to re-calculate its position each time we are opening a window
|
2765
|
+
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
|
2766
|
+
//due to other elements being rendered
|
2767
|
+
scope.position = $position.position(element);
|
2768
|
+
scope.position.top = scope.position.top + element.prop('offsetHeight');
|
2769
|
+
|
2770
|
+
} else {
|
2771
|
+
resetMatches();
|
2772
|
+
}
|
2773
|
+
isLoadingSetter(originalScope, false);
|
2774
|
+
}
|
2775
|
+
}, function(){
|
2776
|
+
resetMatches();
|
2777
|
+
isLoadingSetter(originalScope, false);
|
2778
|
+
});
|
2779
|
+
};
|
2780
|
+
|
2781
|
+
resetMatches();
|
2782
|
+
|
2783
|
+
//we need to propagate user's query so we can higlight matches
|
2784
|
+
scope.query = undefined;
|
2785
|
+
|
2786
|
+
//plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
|
2787
|
+
//$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
|
2788
|
+
modelCtrl.$parsers.push(function (inputValue) {
|
2789
|
+
|
2790
|
+
var timeoutId;
|
2791
|
+
|
2792
|
+
resetMatches();
|
2793
|
+
if (selected) {
|
2794
|
+
return inputValue;
|
2795
|
+
} else {
|
2796
|
+
if (inputValue && inputValue.length >= minSearch) {
|
2797
|
+
if (waitTime > 0) {
|
2798
|
+
if (timeoutId) {
|
2799
|
+
$timeout.cancel(timeoutId);//cancel previous timeout
|
2800
|
+
}
|
2801
|
+
timeoutId = $timeout(function () {
|
2802
|
+
getMatchesAsync(inputValue);
|
2803
|
+
}, waitTime);
|
2804
|
+
} else {
|
2805
|
+
getMatchesAsync(inputValue);
|
2806
|
+
}
|
2807
|
+
}
|
2808
|
+
}
|
2809
|
+
|
2810
|
+
return isEditable ? inputValue : undefined;
|
2811
|
+
});
|
2812
|
+
|
2813
|
+
modelCtrl.$render = function () {
|
2814
|
+
var locals = {};
|
2815
|
+
locals[parserResult.itemName] = selected || modelCtrl.$viewValue;
|
2816
|
+
element.val(parserResult.viewMapper(scope, locals) || modelCtrl.$viewValue);
|
2817
|
+
selected = undefined;
|
2818
|
+
};
|
2819
|
+
|
2820
|
+
scope.select = function (activeIdx) {
|
2821
|
+
//called from within the $digest() cycle
|
2822
|
+
var locals = {};
|
2823
|
+
var model, item;
|
2824
|
+
locals[parserResult.itemName] = item = selected = scope.matches[activeIdx].model;
|
2825
|
+
|
2826
|
+
model = parserResult.modelMapper(scope, locals);
|
2827
|
+
modelCtrl.$setViewValue(model);
|
2828
|
+
modelCtrl.$render();
|
2829
|
+
onSelectCallback(scope, {
|
2830
|
+
$item: item,
|
2831
|
+
$model: model,
|
2832
|
+
$label: parserResult.viewMapper(scope, locals)
|
2833
|
+
});
|
2834
|
+
|
2835
|
+
element[0].focus();
|
2836
|
+
};
|
2837
|
+
|
2838
|
+
//bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
|
2839
|
+
element.bind('keydown', function (evt) {
|
2840
|
+
|
2841
|
+
//typeahead is open and an "interesting" key was pressed
|
2842
|
+
if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
|
2843
|
+
return;
|
2844
|
+
}
|
2845
|
+
|
2846
|
+
evt.preventDefault();
|
2847
|
+
|
2848
|
+
if (evt.which === 40) {
|
2849
|
+
scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
|
2850
|
+
scope.$digest();
|
2851
|
+
|
2852
|
+
} else if (evt.which === 38) {
|
2853
|
+
scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1;
|
2854
|
+
scope.$digest();
|
2855
|
+
|
2856
|
+
} else if (evt.which === 13 || evt.which === 9) {
|
2857
|
+
scope.$apply(function () {
|
2858
|
+
scope.select(scope.activeIdx);
|
2859
|
+
});
|
2860
|
+
|
2861
|
+
} else if (evt.which === 27) {
|
2862
|
+
evt.stopPropagation();
|
2863
|
+
|
2864
|
+
resetMatches();
|
2865
|
+
scope.$digest();
|
2866
|
+
}
|
2867
|
+
});
|
2868
|
+
|
2869
|
+
$document.bind('click', function(){
|
2870
|
+
resetMatches();
|
2871
|
+
scope.$digest();
|
2872
|
+
});
|
2873
|
+
|
2874
|
+
element.after($compile(popUpEl)(scope));
|
2875
|
+
}
|
2876
|
+
};
|
2877
|
+
|
2878
|
+
}])
|
2879
|
+
|
2880
|
+
.directive('typeaheadPopup', function () {
|
2881
|
+
return {
|
2882
|
+
restrict:'E',
|
2883
|
+
scope:{
|
2884
|
+
matches:'=',
|
2885
|
+
query:'=',
|
2886
|
+
active:'=',
|
2887
|
+
position:'=',
|
2888
|
+
select:'&'
|
2889
|
+
},
|
2890
|
+
replace:true,
|
2891
|
+
templateUrl:'template/typeahead/typeahead.html',
|
2892
|
+
link:function (scope, element, attrs) {
|
2893
|
+
|
2894
|
+
scope.isOpen = function () {
|
2895
|
+
return scope.matches.length > 0;
|
2896
|
+
};
|
2897
|
+
|
2898
|
+
scope.isActive = function (matchIdx) {
|
2899
|
+
return scope.active == matchIdx;
|
2900
|
+
};
|
2901
|
+
|
2902
|
+
scope.selectActive = function (matchIdx) {
|
2903
|
+
scope.active = matchIdx;
|
2904
|
+
};
|
2905
|
+
|
2906
|
+
scope.selectMatch = function (activeIdx) {
|
2907
|
+
scope.select({activeIdx:activeIdx});
|
2908
|
+
};
|
2909
|
+
}
|
2910
|
+
};
|
2911
|
+
})
|
2912
|
+
|
2913
|
+
.filter('typeaheadHighlight', function() {
|
2914
|
+
|
2915
|
+
function escapeRegexp(queryToEscape) {
|
2916
|
+
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
2917
|
+
}
|
2918
|
+
|
2919
|
+
return function(matchItem, query) {
|
2920
|
+
return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : query;
|
2921
|
+
};
|
2922
|
+
});
|
2923
|
+
|
1980
2924
|
angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
|
1981
2925
|
$templateCache.put("template/accordion/accordion-group.html",
|
1982
2926
|
"<div class=\"accordion-group\">\n" +
|
@@ -1985,12 +2929,12 @@ angular.module("template/accordion/accordion-group.html", []).run(["$templateCac
|
|
1985
2929
|
" <div class=\"accordion-inner\" ng-transclude></div> </div>\n" +
|
1986
2930
|
"</div>");
|
1987
2931
|
}]);
|
1988
|
-
|
2932
|
+
|
1989
2933
|
angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
|
1990
2934
|
$templateCache.put("template/accordion/accordion.html",
|
1991
2935
|
"<div class=\"accordion\" ng-transclude></div>");
|
1992
2936
|
}]);
|
1993
|
-
|
2937
|
+
|
1994
2938
|
angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
|
1995
2939
|
$templateCache.put("template/alert/alert.html",
|
1996
2940
|
"<div class='alert' ng-class='type && \"alert-\" + type'>\n" +
|
@@ -1999,7 +2943,7 @@ angular.module("template/alert/alert.html", []).run(["$templateCache", function(
|
|
1999
2943
|
"</div>\n" +
|
2000
2944
|
"");
|
2001
2945
|
}]);
|
2002
|
-
|
2946
|
+
|
2003
2947
|
angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
|
2004
2948
|
$templateCache.put("template/carousel/carousel.html",
|
2005
2949
|
"<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\">\n" +
|
@@ -2012,7 +2956,7 @@ angular.module("template/carousel/carousel.html", []).run(["$templateCache", fun
|
|
2012
2956
|
"</div>\n" +
|
2013
2957
|
"");
|
2014
2958
|
}]);
|
2015
|
-
|
2959
|
+
|
2016
2960
|
angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
|
2017
2961
|
$templateCache.put("template/carousel/slide.html",
|
2018
2962
|
"<div ng-class=\"{\n" +
|
@@ -2024,21 +2968,67 @@ angular.module("template/carousel/slide.html", []).run(["$templateCache", functi
|
|
2024
2968
|
" }\" class=\"item\" ng-transclude></div>\n" +
|
2025
2969
|
"");
|
2026
2970
|
}]);
|
2027
|
-
|
2971
|
+
|
2972
|
+
angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
|
2973
|
+
$templateCache.put("template/datepicker/datepicker.html",
|
2974
|
+
"<table class=\"well well-large\">\n" +
|
2975
|
+
" <thead>\n" +
|
2976
|
+
" <tr class=\"text-center\">\n" +
|
2977
|
+
" <th><button class=\"btn pull-left\" ng-click=\"move(-1)\"><i class=\"icon-chevron-left\"></i></button></th>\n" +
|
2978
|
+
" <th colspan=\"{{rows[0].length - 2 + showWeekNumbers}}\"><button class=\"btn btn-block\" ng-click=\"toggleMode()\"><strong>{{title}}</strong></button></th>\n" +
|
2979
|
+
" <th><button class=\"btn pull-right\" ng-click=\"move(1)\"><i class=\"icon-chevron-right\"></i></button></th>\n" +
|
2980
|
+
" </tr>\n" +
|
2981
|
+
" <tr class=\"text-center\" ng-show=\"labels.length > 0\">\n" +
|
2982
|
+
" <th ng-show=\"showWeekNumbers\">#</th>\n" +
|
2983
|
+
" <th ng-repeat=\"label in labels\">{{label}}</th>\n" +
|
2984
|
+
" </tr>\n" +
|
2985
|
+
" </thead>\n" +
|
2986
|
+
" <tbody>\n" +
|
2987
|
+
" <tr ng-repeat=\"row in rows\">\n" +
|
2988
|
+
" <td ng-show=\"showWeekNumbers\" class=\"text-center\"><em>{{ getWeekNumber(row) }}</em></td>\n" +
|
2989
|
+
" <td ng-repeat=\"dt in row\" class=\"text-center\">\n" +
|
2990
|
+
" <button style=\"width:100%;\" class=\"btn\" ng-class=\"{'btn-info': dt.isSelected}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\"><span ng-class=\"{muted: ! dt.isCurrent}\">{{dt.label}}</span></button>\n" +
|
2991
|
+
" </td>\n" +
|
2992
|
+
" </tr>\n" +
|
2993
|
+
" </tbody>\n" +
|
2994
|
+
"</table>\n" +
|
2995
|
+
"");
|
2996
|
+
}]);
|
2997
|
+
|
2028
2998
|
angular.module("template/dialog/message.html", []).run(["$templateCache", function($templateCache) {
|
2029
2999
|
$templateCache.put("template/dialog/message.html",
|
2030
3000
|
"<div class=\"modal-header\">\n" +
|
2031
|
-
" <
|
3001
|
+
" <h3>{{ title }}</h3>\n" +
|
2032
3002
|
"</div>\n" +
|
2033
3003
|
"<div class=\"modal-body\">\n" +
|
2034
3004
|
" <p>{{ message }}</p>\n" +
|
2035
3005
|
"</div>\n" +
|
2036
3006
|
"<div class=\"modal-footer\">\n" +
|
2037
|
-
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class
|
3007
|
+
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"btn\" ng-class=\"btn.cssClass\">{{ btn.label }}</button>\n" +
|
2038
3008
|
"</div>\n" +
|
2039
3009
|
"");
|
2040
3010
|
}]);
|
2041
|
-
|
3011
|
+
|
3012
|
+
angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
|
3013
|
+
$templateCache.put("template/modal/backdrop.html",
|
3014
|
+
"<div class=\"modal-backdrop\"></div>");
|
3015
|
+
}]);
|
3016
|
+
|
3017
|
+
angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
|
3018
|
+
$templateCache.put("template/modal/window.html",
|
3019
|
+
"<div class=\"modal in\" ng-transclude></div>");
|
3020
|
+
}]);
|
3021
|
+
|
3022
|
+
angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
|
3023
|
+
$templateCache.put("template/pagination/pager.html",
|
3024
|
+
"<div class=\"pager\">\n" +
|
3025
|
+
" <ul>\n" +
|
3026
|
+
" <li ng-repeat=\"page in pages\" ng-class=\"{disabled: page.disabled, previous: page.previous, next: page.next}\"><a ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>\n" +
|
3027
|
+
" </ul>\n" +
|
3028
|
+
"</div>\n" +
|
3029
|
+
"");
|
3030
|
+
}]);
|
3031
|
+
|
2042
3032
|
angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
|
2043
3033
|
$templateCache.put("template/pagination/pagination.html",
|
2044
3034
|
"<div class=\"pagination\"><ul>\n" +
|
@@ -2047,7 +3037,7 @@ angular.module("template/pagination/pagination.html", []).run(["$templateCache",
|
|
2047
3037
|
"</div>\n" +
|
2048
3038
|
"");
|
2049
3039
|
}]);
|
2050
|
-
|
3040
|
+
|
2051
3041
|
angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) {
|
2052
3042
|
$templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html",
|
2053
3043
|
"<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
|
@@ -2056,7 +3046,7 @@ angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$tem
|
|
2056
3046
|
"</div>\n" +
|
2057
3047
|
"");
|
2058
3048
|
}]);
|
2059
|
-
|
3049
|
+
|
2060
3050
|
angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
|
2061
3051
|
$templateCache.put("template/tooltip/tooltip-popup.html",
|
2062
3052
|
"<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
|
@@ -2065,7 +3055,7 @@ angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache",
|
|
2065
3055
|
"</div>\n" +
|
2066
3056
|
"");
|
2067
3057
|
}]);
|
2068
|
-
|
3058
|
+
|
2069
3059
|
angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
|
2070
3060
|
$templateCache.put("template/popover/popover.html",
|
2071
3061
|
"<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
|
@@ -2078,17 +3068,17 @@ angular.module("template/popover/popover.html", []).run(["$templateCache", funct
|
|
2078
3068
|
"</div>\n" +
|
2079
3069
|
"");
|
2080
3070
|
}]);
|
2081
|
-
|
3071
|
+
|
2082
3072
|
angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
|
2083
3073
|
$templateCache.put("template/progressbar/bar.html",
|
2084
3074
|
"<div class=\"bar\" ng-class='type && \"bar-\" + type'></div>");
|
2085
3075
|
}]);
|
2086
|
-
|
3076
|
+
|
2087
3077
|
angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
|
2088
3078
|
$templateCache.put("template/progressbar/progress.html",
|
2089
3079
|
"<div class=\"progress\"><progressbar ng-repeat=\"bar in bars\" width=\"bar.to\" old=\"bar.from\" animate=\"bar.animate\" type=\"bar.type\"></progressbar></div>");
|
2090
3080
|
}]);
|
2091
|
-
|
3081
|
+
|
2092
3082
|
angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
|
2093
3083
|
$templateCache.put("template/rating/rating.html",
|
2094
3084
|
"<span ng-mouseleave=\"reset()\">\n" +
|
@@ -2096,13 +3086,21 @@ angular.module("template/rating/rating.html", []).run(["$templateCache", functio
|
|
2096
3086
|
"</span>\n" +
|
2097
3087
|
"");
|
2098
3088
|
}]);
|
2099
|
-
|
3089
|
+
|
2100
3090
|
angular.module("template/tabs/pane.html", []).run(["$templateCache", function($templateCache) {
|
2101
3091
|
$templateCache.put("template/tabs/pane.html",
|
2102
3092
|
"<div class=\"tab-pane\" ng-class=\"{active: selected}\" ng-show=\"selected\" ng-transclude></div>\n" +
|
2103
3093
|
"");
|
2104
3094
|
}]);
|
2105
|
-
|
3095
|
+
|
3096
|
+
angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
|
3097
|
+
$templateCache.put("template/tabs/tab.html",
|
3098
|
+
"<li ng-class=\"{active: active, disabled: disabled}\">\n" +
|
3099
|
+
" <a ng-click=\"select()\" tab-heading-transclude>{{heading}}</a>\n" +
|
3100
|
+
"</li>\n" +
|
3101
|
+
"");
|
3102
|
+
}]);
|
3103
|
+
|
2106
3104
|
angular.module("template/tabs/tabs.html", []).run(["$templateCache", function($templateCache) {
|
2107
3105
|
$templateCache.put("template/tabs/tabs.html",
|
2108
3106
|
"<div class=\"tabbable\">\n" +
|
@@ -2115,12 +3113,48 @@ angular.module("template/tabs/tabs.html", []).run(["$templateCache", function($t
|
|
2115
3113
|
"</div>\n" +
|
2116
3114
|
"");
|
2117
3115
|
}]);
|
2118
|
-
|
2119
|
-
angular.module("template/
|
2120
|
-
$templateCache.put("template/
|
2121
|
-
"
|
2122
|
-
|
2123
|
-
|
3116
|
+
|
3117
|
+
angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
|
3118
|
+
$templateCache.put("template/tabs/tabset.html",
|
3119
|
+
"\n" +
|
3120
|
+
"<div class=\"tabbable\">\n" +
|
3121
|
+
" <ul class=\"nav {{type && 'nav-' + type}}\" ng-class=\"{'nav-stacked': vertical}\" ng-transclude>\n" +
|
3122
|
+
" </ul>\n" +
|
3123
|
+
" <div class=\"tab-content\">\n" +
|
3124
|
+
" <div class=\"tab-pane\" \n" +
|
3125
|
+
" ng-repeat=\"tab in tabs\" \n" +
|
3126
|
+
" ng-class=\"{active: tab.active}\"\n" +
|
3127
|
+
" tab-content-transclude=\"tab\" tt=\"tab\">\n" +
|
3128
|
+
" </div>\n" +
|
3129
|
+
" </div>\n" +
|
3130
|
+
"</div>\n" +
|
3131
|
+
"");
|
3132
|
+
}]);
|
3133
|
+
|
3134
|
+
angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
|
3135
|
+
$templateCache.put("template/timepicker/timepicker.html",
|
3136
|
+
"<table class=\"form-inline\">\n" +
|
3137
|
+
" <tr class=\"text-center\">\n" +
|
3138
|
+
" <td><a ng-click=\"incrementHours()\" class=\"btn btn-link\"><i class=\"icon-chevron-up\"></i></a></td>\n" +
|
3139
|
+
" <td> </td>\n" +
|
3140
|
+
" <td><a ng-click=\"incrementMinutes()\" class=\"btn btn-link\"><i class=\"icon-chevron-up\"></i></a></td>\n" +
|
3141
|
+
" <td ng-show=\"showMeridian\"></td>\n" +
|
3142
|
+
" </tr>\n" +
|
3143
|
+
" <tr>\n" +
|
3144
|
+
" <td class=\"control-group\" ng-class=\"{'error': !validHours}\"><input type=\"text\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"span1 text-center\" ng-mousewheel=\"incrementHours()\" ng-readonly=\"readonlyInput\" maxlength=\"2\" /></td>\n" +
|
3145
|
+
" <td>:</td>\n" +
|
3146
|
+
" <td class=\"control-group\" ng-class=\"{'error': !validMinutes}\"><input type=\"text\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"span1 text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\"></td>\n" +
|
3147
|
+
" <td ng-show=\"showMeridian\"><button ng-click=\"toggleMeridian()\" class=\"btn text-center\">{{meridian}}</button></td>\n" +
|
3148
|
+
" </tr>\n" +
|
3149
|
+
" <tr class=\"text-center\">\n" +
|
3150
|
+
" <td><a ng-click=\"decrementHours()\" class=\"btn btn-link\"><i class=\"icon-chevron-down\"></i></a></td>\n" +
|
3151
|
+
" <td> </td>\n" +
|
3152
|
+
" <td><a ng-click=\"decrementMinutes()\" class=\"btn btn-link\"><i class=\"icon-chevron-down\"></i></a></td>\n" +
|
3153
|
+
" <td ng-show=\"showMeridian\"></td>\n" +
|
3154
|
+
" </tr>\n" +
|
3155
|
+
"</table>");
|
3156
|
+
}]);
|
3157
|
+
|
2124
3158
|
angular.module("template/typeahead/typeahead.html", []).run(["$templateCache", function($templateCache) {
|
2125
3159
|
$templateCache.put("template/typeahead/typeahead.html",
|
2126
3160
|
"<ul class=\"typeahead dropdown-menu\" ng-style=\"{display: isOpen()&&'block' || 'none', top: position.top+'px', left: position.left+'px'}\">\n" +
|
@@ -2128,4 +3162,4 @@ angular.module("template/typeahead/typeahead.html", []).run(["$templateCache", f
|
|
2128
3162
|
" <a tabindex=\"-1\" ng-click=\"selectMatch($index)\" ng-bind-html-unsafe=\"match.label | typeaheadHighlight:query\"></a>\n" +
|
2129
3163
|
" </li>\n" +
|
2130
3164
|
"</ul>");
|
2131
|
-
}]);
|
3165
|
+
}]);
|