angular-ui-bootstrap-rails 0.3.0.1 → 0.4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}]);
|