angular-ui-bootstrap-rails 0.5.0.0 → 0.6.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.
@@ -1,4 +1,4 @@
|
|
1
|
-
angular.module("ui.bootstrap", ["ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.
|
1
|
+
angular.module("ui.bootstrap", ["ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
|
2
2
|
angular.module('ui.bootstrap.transition', [])
|
3
3
|
|
4
4
|
/**
|
@@ -336,6 +336,16 @@ angular.module("ui.bootstrap.alert", []).directive('alert', function () {
|
|
336
336
|
};
|
337
337
|
});
|
338
338
|
|
339
|
+
angular.module('ui.bootstrap.bindHtml', [])
|
340
|
+
|
341
|
+
.directive('bindHtmlUnsafe', function () {
|
342
|
+
return function (scope, element, attr) {
|
343
|
+
element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe);
|
344
|
+
scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) {
|
345
|
+
element.html(value || '');
|
346
|
+
});
|
347
|
+
};
|
348
|
+
});
|
339
349
|
angular.module('ui.bootstrap.buttons', [])
|
340
350
|
|
341
351
|
.constant('buttonConfig', {
|
@@ -407,7 +417,7 @@ angular.module('ui.bootstrap.buttons', [])
|
|
407
417
|
/**
|
408
418
|
* @ngdoc overview
|
409
419
|
* @name ui.bootstrap.carousel
|
410
|
-
*
|
420
|
+
*
|
411
421
|
* @description
|
412
422
|
* AngularJS version of an image carousel.
|
413
423
|
*
|
@@ -438,10 +448,10 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
438
448
|
}
|
439
449
|
function goNext() {
|
440
450
|
//If we have a slide to transition from and we have a transition type and we're allowed, go
|
441
|
-
if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
|
451
|
+
if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
|
442
452
|
//We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime
|
443
453
|
nextSlide.$element.addClass(direction);
|
444
|
-
|
454
|
+
var reflow = nextSlide.$element[0].offsetWidth; //force reflow
|
445
455
|
|
446
456
|
//Set all other slides to stop doing their stuff for the new transition
|
447
457
|
angular.forEach(slides, function(slide) {
|
@@ -480,7 +490,7 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
480
490
|
|
481
491
|
$scope.next = function() {
|
482
492
|
var newIndex = (currentIndex + 1) % slides.length;
|
483
|
-
|
493
|
+
|
484
494
|
//Prevent this user-triggered transition from occurring if there is already one in progress
|
485
495
|
if (!$scope.$currentTransition) {
|
486
496
|
return self.select(slides[newIndex], 'next');
|
@@ -489,7 +499,7 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
|
|
489
499
|
|
490
500
|
$scope.prev = function() {
|
491
501
|
var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
|
492
|
-
|
502
|
+
|
493
503
|
//Prevent this user-triggered transition from occurring if there is already one in progress
|
494
504
|
if (!$scope.$currentTransition) {
|
495
505
|
return self.select(slides[newIndex], 'prev');
|
@@ -706,7 +716,7 @@ function CarouselDemoCtrl($scope) {
|
|
706
716
|
var lastValue = scope.active = getActive(scope.$parent);
|
707
717
|
scope.$watch(function parentActiveWatch() {
|
708
718
|
var parentActive = getActive(scope.$parent);
|
709
|
-
|
719
|
+
|
710
720
|
if (parentActive !== scope.active) {
|
711
721
|
// we are out of sync and need to copy
|
712
722
|
if (parentActive !== lastValue) {
|
@@ -746,13 +756,6 @@ angular.module('ui.bootstrap.position', [])
|
|
746
756
|
*/
|
747
757
|
.factory('$position', ['$document', '$window', function ($document, $window) {
|
748
758
|
|
749
|
-
var mouseX, mouseY;
|
750
|
-
|
751
|
-
$document.bind('mousemove', function mouseMoved(event) {
|
752
|
-
mouseX = event.pageX;
|
753
|
-
mouseY = event.pageY;
|
754
|
-
});
|
755
|
-
|
756
759
|
function getStyle(el, cssprop) {
|
757
760
|
if (el.currentStyle) { //IE
|
758
761
|
return el.currentStyle[cssprop];
|
@@ -816,16 +819,9 @@ angular.module('ui.bootstrap.position', [])
|
|
816
819
|
return {
|
817
820
|
width: element.prop('offsetWidth'),
|
818
821
|
height: element.prop('offsetHeight'),
|
819
|
-
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop),
|
820
|
-
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft)
|
822
|
+
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
|
823
|
+
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
|
821
824
|
};
|
822
|
-
},
|
823
|
-
|
824
|
-
/**
|
825
|
-
* Provides the coordinates of the mouse
|
826
|
-
*/
|
827
|
-
mouse: function () {
|
828
|
-
return {x: mouseX, y: mouseY};
|
829
825
|
}
|
830
826
|
};
|
831
827
|
}]);
|
@@ -1104,26 +1100,9 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1104
1100
|
scope.$destroy();
|
1105
1101
|
});
|
1106
1102
|
|
1107
|
-
function formatDate(value) {
|
1108
|
-
return (value) ? dateFilter(value, dateFormat) : null;
|
1109
|
-
}
|
1110
|
-
ngModel.$formatters.push(formatDate);
|
1111
|
-
|
1112
|
-
// TODO: reverse from dateFilter string to Date object
|
1113
|
-
function parseDate(value) {
|
1114
|
-
if ( value ) {
|
1115
|
-
var date = new Date(value);
|
1116
|
-
if (!isNaN(date)) {
|
1117
|
-
return date;
|
1118
|
-
}
|
1119
|
-
}
|
1120
|
-
return value;
|
1121
|
-
}
|
1122
|
-
ngModel.$parsers.push(parseDate);
|
1123
|
-
|
1124
1103
|
var getIsOpen, setIsOpen;
|
1125
|
-
if ( attrs.
|
1126
|
-
getIsOpen = $parse(attrs.
|
1104
|
+
if ( attrs.isOpen ) {
|
1105
|
+
getIsOpen = $parse(attrs.isOpen);
|
1127
1106
|
setIsOpen = getIsOpen.assign;
|
1128
1107
|
|
1129
1108
|
originalScope.$watch(getIsOpen, function updateOpen(value) {
|
@@ -1165,33 +1144,58 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1165
1144
|
datepickerEl.attr(angular.extend({}, originalScope.$eval(attrs.datepickerOptions)));
|
1166
1145
|
}
|
1167
1146
|
|
1168
|
-
|
1147
|
+
// TODO: reverse from dateFilter string to Date object
|
1148
|
+
function parseDate(viewValue) {
|
1149
|
+
if (!viewValue) {
|
1150
|
+
ngModel.$setValidity('date', true);
|
1151
|
+
return null;
|
1152
|
+
} else if (angular.isDate(viewValue)) {
|
1153
|
+
ngModel.$setValidity('date', true);
|
1154
|
+
return viewValue;
|
1155
|
+
} else if (angular.isString(viewValue)) {
|
1156
|
+
var date = new Date(viewValue);
|
1157
|
+
if (isNaN(date)) {
|
1158
|
+
ngModel.$setValidity('date', false);
|
1159
|
+
return undefined;
|
1160
|
+
} else {
|
1161
|
+
ngModel.$setValidity('date', true);
|
1162
|
+
return date;
|
1163
|
+
}
|
1164
|
+
} else {
|
1165
|
+
ngModel.$setValidity('date', false);
|
1166
|
+
return undefined;
|
1167
|
+
}
|
1168
|
+
}
|
1169
|
+
ngModel.$parsers.unshift(parseDate);
|
1169
1170
|
|
1170
1171
|
// Inner change
|
1171
1172
|
scope.dateSelection = function() {
|
1172
|
-
|
1173
|
+
ngModel.$setViewValue(scope.date);
|
1174
|
+
ngModel.$render();
|
1175
|
+
|
1173
1176
|
if (closeOnDateSelection) {
|
1174
1177
|
setOpen( false );
|
1175
1178
|
}
|
1176
1179
|
};
|
1177
1180
|
|
1181
|
+
element.bind('input change keyup', function() {
|
1182
|
+
scope.$apply(function() {
|
1183
|
+
updateCalendar();
|
1184
|
+
});
|
1185
|
+
});
|
1186
|
+
|
1178
1187
|
// Outter change
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
} else {
|
1189
|
-
value = date;
|
1190
|
-
}
|
1191
|
-
}
|
1192
|
-
scope.date = value;
|
1188
|
+
ngModel.$render = function() {
|
1189
|
+
var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
|
1190
|
+
element.val(date);
|
1191
|
+
|
1192
|
+
updateCalendar();
|
1193
|
+
};
|
1194
|
+
|
1195
|
+
function updateCalendar() {
|
1196
|
+
scope.date = ngModel.$modelValue;
|
1193
1197
|
updatePosition();
|
1194
|
-
}
|
1198
|
+
}
|
1195
1199
|
|
1196
1200
|
function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) {
|
1197
1201
|
if (attribute) {
|
@@ -1218,15 +1222,22 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1218
1222
|
scope.position.top = scope.position.top + element.prop('offsetHeight');
|
1219
1223
|
}
|
1220
1224
|
|
1225
|
+
var documentBindingInitialized = false, elementFocusInitialized = false;
|
1221
1226
|
scope.$watch('isOpen', function(value) {
|
1222
1227
|
if (value) {
|
1223
1228
|
updatePosition();
|
1224
1229
|
$document.bind('click', documentClickBind);
|
1225
|
-
|
1226
|
-
|
1230
|
+
if(elementFocusInitialized) {
|
1231
|
+
element.unbind('focus', elementFocusBind);
|
1232
|
+
}
|
1233
|
+
element[0].focus();
|
1234
|
+
documentBindingInitialized = true;
|
1227
1235
|
} else {
|
1228
|
-
|
1236
|
+
if(documentBindingInitialized) {
|
1237
|
+
$document.unbind('click', documentClickBind);
|
1238
|
+
}
|
1229
1239
|
element.bind('focus', elementFocusBind);
|
1240
|
+
elementFocusInitialized = true;
|
1230
1241
|
}
|
1231
1242
|
|
1232
1243
|
if ( setIsOpen ) {
|
@@ -1234,6 +1245,8 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1234
1245
|
}
|
1235
1246
|
});
|
1236
1247
|
|
1248
|
+
var $setModelValue = $parse(attrs.ngModel).assign;
|
1249
|
+
|
1237
1250
|
scope.today = function() {
|
1238
1251
|
$setModelValue(originalScope, new Date());
|
1239
1252
|
};
|
@@ -1260,286 +1273,6 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon
|
|
1260
1273
|
}
|
1261
1274
|
};
|
1262
1275
|
}]);
|
1263
|
-
// The `$dialogProvider` can be used to configure global defaults for your
|
1264
|
-
// `$dialog` service.
|
1265
|
-
var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']);
|
1266
|
-
|
1267
|
-
dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', function($scope, dialog, model){
|
1268
|
-
$scope.title = model.title;
|
1269
|
-
$scope.message = model.message;
|
1270
|
-
$scope.buttons = model.buttons;
|
1271
|
-
$scope.close = function(res){
|
1272
|
-
dialog.close(res);
|
1273
|
-
};
|
1274
|
-
}]);
|
1275
|
-
|
1276
|
-
dialogModule.provider("$dialog", function(){
|
1277
|
-
|
1278
|
-
// The default options for all dialogs.
|
1279
|
-
var defaults = {
|
1280
|
-
backdrop: true,
|
1281
|
-
dialogClass: 'modal',
|
1282
|
-
backdropClass: 'modal-backdrop',
|
1283
|
-
transitionClass: 'fade',
|
1284
|
-
triggerClass: 'in',
|
1285
|
-
resolve:{},
|
1286
|
-
backdropFade: false,
|
1287
|
-
dialogFade:false,
|
1288
|
-
keyboard: true, // close with esc key
|
1289
|
-
backdropClick: true // only in conjunction with backdrop=true
|
1290
|
-
/* other options: template, templateUrl, controller */
|
1291
|
-
};
|
1292
|
-
|
1293
|
-
var globalOptions = {};
|
1294
|
-
|
1295
|
-
var activeBackdrops = {value : 0};
|
1296
|
-
|
1297
|
-
// The `options({})` allows global configuration of all dialogs in the application.
|
1298
|
-
//
|
1299
|
-
// var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){
|
1300
|
-
// // don't close dialog when backdrop is clicked by default
|
1301
|
-
// $dialogProvider.options({backdropClick: false});
|
1302
|
-
// });
|
1303
|
-
this.options = function(value){
|
1304
|
-
globalOptions = value;
|
1305
|
-
};
|
1306
|
-
|
1307
|
-
// Returns the actual `$dialog` service that is injected in controllers
|
1308
|
-
this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition", "$injector",
|
1309
|
-
function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition, $injector) {
|
1310
|
-
|
1311
|
-
var body = $document.find('body');
|
1312
|
-
|
1313
|
-
function createElement(clazz) {
|
1314
|
-
var el = angular.element("<div>");
|
1315
|
-
el.addClass(clazz);
|
1316
|
-
return el;
|
1317
|
-
}
|
1318
|
-
|
1319
|
-
// The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object
|
1320
|
-
// containing at lest template or templateUrl and controller:
|
1321
|
-
//
|
1322
|
-
// var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'});
|
1323
|
-
//
|
1324
|
-
// Dialogs can also be created using templateUrl and controller as distinct arguments:
|
1325
|
-
//
|
1326
|
-
// var d = new Dialog('path/to/dialog.html', MyDialogController);
|
1327
|
-
function Dialog(opts) {
|
1328
|
-
|
1329
|
-
var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts);
|
1330
|
-
this._open = false;
|
1331
|
-
|
1332
|
-
this.backdropEl = createElement(options.backdropClass);
|
1333
|
-
if(options.backdropFade){
|
1334
|
-
this.backdropEl.addClass(options.transitionClass);
|
1335
|
-
this.backdropEl.removeClass(options.triggerClass);
|
1336
|
-
}
|
1337
|
-
|
1338
|
-
this.modalEl = createElement(options.dialogClass);
|
1339
|
-
if(options.dialogFade){
|
1340
|
-
this.modalEl.addClass(options.transitionClass);
|
1341
|
-
this.modalEl.removeClass(options.triggerClass);
|
1342
|
-
}
|
1343
|
-
|
1344
|
-
this.handledEscapeKey = function(e) {
|
1345
|
-
if (e.which === 27) {
|
1346
|
-
self.close();
|
1347
|
-
e.preventDefault();
|
1348
|
-
self.$scope.$apply();
|
1349
|
-
}
|
1350
|
-
};
|
1351
|
-
|
1352
|
-
this.handleBackDropClick = function(e) {
|
1353
|
-
self.close();
|
1354
|
-
e.preventDefault();
|
1355
|
-
self.$scope.$apply();
|
1356
|
-
};
|
1357
|
-
}
|
1358
|
-
|
1359
|
-
// The `isOpen()` method returns wether the dialog is currently visible.
|
1360
|
-
Dialog.prototype.isOpen = function(){
|
1361
|
-
return this._open;
|
1362
|
-
};
|
1363
|
-
|
1364
|
-
// The `open(templateUrl, controller)` method opens the dialog.
|
1365
|
-
// Use the `templateUrl` and `controller` arguments if specifying them at dialog creation time is not desired.
|
1366
|
-
Dialog.prototype.open = function(templateUrl, controller){
|
1367
|
-
var self = this, options = this.options;
|
1368
|
-
|
1369
|
-
if(templateUrl){
|
1370
|
-
options.templateUrl = templateUrl;
|
1371
|
-
}
|
1372
|
-
if(controller){
|
1373
|
-
options.controller = controller;
|
1374
|
-
}
|
1375
|
-
|
1376
|
-
if(!(options.template || options.templateUrl)) {
|
1377
|
-
throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.');
|
1378
|
-
}
|
1379
|
-
|
1380
|
-
this._loadResolves().then(function(locals) {
|
1381
|
-
var $scope = locals.$scope = self.$scope = locals.$scope ? locals.$scope : $rootScope.$new();
|
1382
|
-
|
1383
|
-
self.modalEl.html(locals.$template);
|
1384
|
-
|
1385
|
-
if (self.options.controller) {
|
1386
|
-
var ctrl = $controller(self.options.controller, locals);
|
1387
|
-
self.modalEl.children().data('ngControllerController', ctrl);
|
1388
|
-
}
|
1389
|
-
|
1390
|
-
$compile(self.modalEl)($scope);
|
1391
|
-
self._addElementsToDom();
|
1392
|
-
|
1393
|
-
// trigger tranisitions
|
1394
|
-
setTimeout(function(){
|
1395
|
-
if(self.options.dialogFade){ self.modalEl.addClass(self.options.triggerClass); }
|
1396
|
-
if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); }
|
1397
|
-
});
|
1398
|
-
|
1399
|
-
self._bindEvents();
|
1400
|
-
});
|
1401
|
-
|
1402
|
-
this.deferred = $q.defer();
|
1403
|
-
return this.deferred.promise;
|
1404
|
-
};
|
1405
|
-
|
1406
|
-
// closes the dialog and resolves the promise returned by the `open` method with the specified result.
|
1407
|
-
Dialog.prototype.close = function(result){
|
1408
|
-
var self = this;
|
1409
|
-
var fadingElements = this._getFadingElements();
|
1410
|
-
|
1411
|
-
if(fadingElements.length > 0){
|
1412
|
-
for (var i = fadingElements.length - 1; i >= 0; i--) {
|
1413
|
-
$transition(fadingElements[i], removeTriggerClass).then(onCloseComplete);
|
1414
|
-
}
|
1415
|
-
return;
|
1416
|
-
}
|
1417
|
-
|
1418
|
-
this._onCloseComplete(result);
|
1419
|
-
|
1420
|
-
function removeTriggerClass(el){
|
1421
|
-
el.removeClass(self.options.triggerClass);
|
1422
|
-
}
|
1423
|
-
|
1424
|
-
function onCloseComplete(){
|
1425
|
-
if(self._open){
|
1426
|
-
self._onCloseComplete(result);
|
1427
|
-
}
|
1428
|
-
}
|
1429
|
-
};
|
1430
|
-
|
1431
|
-
Dialog.prototype._getFadingElements = function(){
|
1432
|
-
var elements = [];
|
1433
|
-
if(this.options.dialogFade){
|
1434
|
-
elements.push(this.modalEl);
|
1435
|
-
}
|
1436
|
-
if(this.options.backdropFade){
|
1437
|
-
elements.push(this.backdropEl);
|
1438
|
-
}
|
1439
|
-
|
1440
|
-
return elements;
|
1441
|
-
};
|
1442
|
-
|
1443
|
-
Dialog.prototype._bindEvents = function() {
|
1444
|
-
if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); }
|
1445
|
-
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); }
|
1446
|
-
};
|
1447
|
-
|
1448
|
-
Dialog.prototype._unbindEvents = function() {
|
1449
|
-
if(this.options.keyboard){ body.unbind('keydown', this.handledEscapeKey); }
|
1450
|
-
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.unbind('click', this.handleBackDropClick); }
|
1451
|
-
};
|
1452
|
-
|
1453
|
-
Dialog.prototype._onCloseComplete = function(result) {
|
1454
|
-
this._removeElementsFromDom();
|
1455
|
-
this._unbindEvents();
|
1456
|
-
|
1457
|
-
this.deferred.resolve(result);
|
1458
|
-
};
|
1459
|
-
|
1460
|
-
Dialog.prototype._addElementsToDom = function(){
|
1461
|
-
body.append(this.modalEl);
|
1462
|
-
|
1463
|
-
if(this.options.backdrop) {
|
1464
|
-
if (activeBackdrops.value === 0) {
|
1465
|
-
body.append(this.backdropEl);
|
1466
|
-
}
|
1467
|
-
activeBackdrops.value++;
|
1468
|
-
}
|
1469
|
-
|
1470
|
-
this._open = true;
|
1471
|
-
};
|
1472
|
-
|
1473
|
-
Dialog.prototype._removeElementsFromDom = function(){
|
1474
|
-
this.modalEl.remove();
|
1475
|
-
|
1476
|
-
if(this.options.backdrop) {
|
1477
|
-
activeBackdrops.value--;
|
1478
|
-
if (activeBackdrops.value === 0) {
|
1479
|
-
this.backdropEl.remove();
|
1480
|
-
}
|
1481
|
-
}
|
1482
|
-
this._open = false;
|
1483
|
-
};
|
1484
|
-
|
1485
|
-
// Loads all `options.resolve` members to be used as locals for the controller associated with the dialog.
|
1486
|
-
Dialog.prototype._loadResolves = function(){
|
1487
|
-
var values = [], keys = [], templatePromise, self = this;
|
1488
|
-
|
1489
|
-
if (this.options.template) {
|
1490
|
-
templatePromise = $q.when(this.options.template);
|
1491
|
-
} else if (this.options.templateUrl) {
|
1492
|
-
templatePromise = $http.get(this.options.templateUrl, {cache:$templateCache})
|
1493
|
-
.then(function(response) { return response.data; });
|
1494
|
-
}
|
1495
|
-
|
1496
|
-
angular.forEach(this.options.resolve || [], function(value, key) {
|
1497
|
-
keys.push(key);
|
1498
|
-
values.push(angular.isString(value) ? $injector.get(value) : $injector.invoke(value));
|
1499
|
-
});
|
1500
|
-
|
1501
|
-
keys.push('$template');
|
1502
|
-
values.push(templatePromise);
|
1503
|
-
|
1504
|
-
return $q.all(values).then(function(values) {
|
1505
|
-
var locals = {};
|
1506
|
-
angular.forEach(values, function(value, index) {
|
1507
|
-
locals[keys[index]] = value;
|
1508
|
-
});
|
1509
|
-
locals.dialog = self;
|
1510
|
-
return locals;
|
1511
|
-
});
|
1512
|
-
};
|
1513
|
-
|
1514
|
-
// The actual `$dialog` service that is injected in controllers.
|
1515
|
-
return {
|
1516
|
-
// Creates a new `Dialog` with the specified options.
|
1517
|
-
dialog: function(opts){
|
1518
|
-
return new Dialog(opts);
|
1519
|
-
},
|
1520
|
-
// creates a new `Dialog` tied to the default message box template and controller.
|
1521
|
-
//
|
1522
|
-
// Arguments `title` and `message` are rendered in the modal header and body sections respectively.
|
1523
|
-
// The `buttons` array holds an object with the following members for each button to include in the
|
1524
|
-
// modal footer section:
|
1525
|
-
//
|
1526
|
-
// * `result`: the result to pass to the `close` method of the dialog when the button is clicked
|
1527
|
-
// * `label`: the label of the button
|
1528
|
-
// * `cssClass`: additional css class(es) to apply to the button for styling
|
1529
|
-
messageBox: function(title, message, buttons){
|
1530
|
-
return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve:
|
1531
|
-
{model: function() {
|
1532
|
-
return {
|
1533
|
-
title: title,
|
1534
|
-
message: message,
|
1535
|
-
buttons: buttons
|
1536
|
-
};
|
1537
|
-
}
|
1538
|
-
}});
|
1539
|
-
}
|
1540
|
-
};
|
1541
|
-
}];
|
1542
|
-
});
|
1543
1276
|
|
1544
1277
|
/*
|
1545
1278
|
* dropdownToggle - Provides dropdown menu functionality in place of bootstrap js
|
@@ -1593,93 +1326,391 @@ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['
|
|
1593
1326
|
}
|
1594
1327
|
};
|
1595
1328
|
}]);
|
1596
|
-
angular.module('ui.bootstrap.modal', [
|
1597
|
-
.directive('modal', ['$parse', '$dialog', function($parse, $dialog) {
|
1598
|
-
return {
|
1599
|
-
restrict: 'EA',
|
1600
|
-
terminal: true,
|
1601
|
-
link: function(scope, elm, attrs) {
|
1602
|
-
var opts = angular.extend({}, scope.$eval(attrs.uiOptions || attrs.bsOptions || attrs.options));
|
1603
|
-
var shownExpr = attrs.modal || attrs.show;
|
1604
|
-
var setClosed;
|
1605
|
-
|
1606
|
-
// Create a dialog with the template as the contents of the directive
|
1607
|
-
// Add the current scope as the resolve in order to make the directive scope as a dialog controller scope
|
1608
|
-
opts = angular.extend(opts, {
|
1609
|
-
template: elm.html(),
|
1610
|
-
resolve: { $scope: function() { return scope; } }
|
1611
|
-
});
|
1612
|
-
var dialog = $dialog.dialog(opts);
|
1329
|
+
angular.module('ui.bootstrap.modal', [])
|
1613
1330
|
|
1614
|
-
|
1331
|
+
/**
|
1332
|
+
* A helper, internal data structure that acts as a map but also allows getting / removing
|
1333
|
+
* elements in the LIFO order
|
1334
|
+
*/
|
1335
|
+
.factory('$$stackedMap', function () {
|
1336
|
+
return {
|
1337
|
+
createNew: function () {
|
1338
|
+
var stack = [];
|
1615
1339
|
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1340
|
+
return {
|
1341
|
+
add: function (key, value) {
|
1342
|
+
stack.push({
|
1343
|
+
key: key,
|
1344
|
+
value: value
|
1345
|
+
});
|
1346
|
+
},
|
1347
|
+
get: function (key) {
|
1348
|
+
for (var i = 0; i < stack.length; i++) {
|
1349
|
+
if (key == stack[i].key) {
|
1350
|
+
return stack[i];
|
1351
|
+
}
|
1352
|
+
}
|
1353
|
+
},
|
1354
|
+
keys: function() {
|
1355
|
+
var keys = [];
|
1356
|
+
for (var i = 0; i < stack.length; i++) {
|
1357
|
+
keys.push(stack[i].key);
|
1358
|
+
}
|
1359
|
+
return keys;
|
1360
|
+
},
|
1361
|
+
top: function () {
|
1362
|
+
return stack[stack.length - 1];
|
1363
|
+
},
|
1364
|
+
remove: function (key) {
|
1365
|
+
var idx = -1;
|
1366
|
+
for (var i = 0; i < stack.length; i++) {
|
1367
|
+
if (key == stack[i].key) {
|
1368
|
+
idx = i;
|
1369
|
+
break;
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
return stack.splice(idx, 1)[0];
|
1373
|
+
},
|
1374
|
+
removeTop: function () {
|
1375
|
+
return stack.splice(stack.length - 1, 1)[0];
|
1376
|
+
},
|
1377
|
+
length: function () {
|
1378
|
+
return stack.length;
|
1379
|
+
}
|
1619
1380
|
};
|
1620
|
-
}
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1381
|
+
}
|
1382
|
+
};
|
1383
|
+
})
|
1384
|
+
|
1385
|
+
/**
|
1386
|
+
* A helper directive for the $modal service. It creates a backdrop element.
|
1387
|
+
*/
|
1388
|
+
.directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
|
1389
|
+
return {
|
1390
|
+
restrict: 'EA',
|
1391
|
+
replace: true,
|
1392
|
+
templateUrl: 'template/modal/backdrop.html',
|
1393
|
+
link: function (scope, element, attrs) {
|
1394
|
+
|
1395
|
+
//trigger CSS transitions
|
1396
|
+
$timeout(function () {
|
1397
|
+
scope.animate = true;
|
1398
|
+
});
|
1399
|
+
|
1400
|
+
scope.close = function (evt) {
|
1401
|
+
var modal = $modalStack.getTop();
|
1402
|
+
if (modal && modal.value.backdrop && modal.value.backdrop != 'static') {
|
1403
|
+
evt.preventDefault();
|
1404
|
+
evt.stopPropagation();
|
1405
|
+
$modalStack.dismiss(modal.key, 'backdrop click');
|
1624
1406
|
}
|
1625
1407
|
};
|
1626
1408
|
}
|
1409
|
+
};
|
1410
|
+
}])
|
1627
1411
|
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1412
|
+
.directive('modalWindow', ['$timeout', function ($timeout) {
|
1413
|
+
return {
|
1414
|
+
restrict: 'EA',
|
1415
|
+
scope: {
|
1416
|
+
index: '@'
|
1417
|
+
},
|
1418
|
+
replace: true,
|
1419
|
+
transclude: true,
|
1420
|
+
templateUrl: 'template/modal/window.html',
|
1421
|
+
link: function (scope, element, attrs) {
|
1422
|
+
scope.windowClass = attrs.windowClass || '';
|
1423
|
+
|
1424
|
+
//trigger CSS transitions
|
1425
|
+
$timeout(function () {
|
1426
|
+
scope.animate = true;
|
1427
|
+
});
|
1428
|
+
}
|
1429
|
+
};
|
1430
|
+
}])
|
1431
|
+
|
1432
|
+
.factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap',
|
1433
|
+
function ($document, $compile, $rootScope, $$stackedMap) {
|
1434
|
+
|
1435
|
+
var backdropjqLiteEl, backdropDomEl;
|
1436
|
+
var backdropScope = $rootScope.$new(true);
|
1437
|
+
var body = $document.find('body').eq(0);
|
1438
|
+
var openedWindows = $$stackedMap.createNew();
|
1439
|
+
var $modalStack = {};
|
1440
|
+
|
1441
|
+
function backdropIndex() {
|
1442
|
+
var topBackdropIndex = -1;
|
1443
|
+
var opened = openedWindows.keys();
|
1444
|
+
for (var i = 0; i < opened.length; i++) {
|
1445
|
+
if (openedWindows.get(opened[i]).value.backdrop) {
|
1446
|
+
topBackdropIndex = i;
|
1637
1447
|
}
|
1638
1448
|
}
|
1449
|
+
return topBackdropIndex;
|
1450
|
+
}
|
1451
|
+
|
1452
|
+
$rootScope.$watch(backdropIndex, function(newBackdropIndex){
|
1453
|
+
backdropScope.index = newBackdropIndex;
|
1639
1454
|
});
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1455
|
+
|
1456
|
+
function removeModalWindow(modalInstance) {
|
1457
|
+
|
1458
|
+
var modalWindow = openedWindows.get(modalInstance).value;
|
1459
|
+
|
1460
|
+
//clean up the stack
|
1461
|
+
openedWindows.remove(modalInstance);
|
1462
|
+
|
1463
|
+
//remove window DOM element
|
1464
|
+
modalWindow.modalDomEl.remove();
|
1465
|
+
|
1466
|
+
//remove backdrop if no longer needed
|
1467
|
+
if (backdropIndex() == -1) {
|
1468
|
+
backdropDomEl.remove();
|
1469
|
+
backdropDomEl = undefined;
|
1470
|
+
}
|
1471
|
+
|
1472
|
+
//destroy scope
|
1473
|
+
modalWindow.modalScope.$destroy();
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
$document.bind('keydown', function (evt) {
|
1477
|
+
var modal;
|
1478
|
+
|
1479
|
+
if (evt.which === 27) {
|
1480
|
+
modal = openedWindows.top();
|
1481
|
+
if (modal && modal.value.keyboard) {
|
1482
|
+
$rootScope.$apply(function () {
|
1483
|
+
$modalStack.dismiss(modal.key);
|
1484
|
+
});
|
1485
|
+
}
|
1486
|
+
}
|
1487
|
+
});
|
1488
|
+
|
1489
|
+
$modalStack.open = function (modalInstance, modal) {
|
1490
|
+
|
1491
|
+
openedWindows.add(modalInstance, {
|
1492
|
+
deferred: modal.deferred,
|
1493
|
+
modalScope: modal.scope,
|
1494
|
+
backdrop: modal.backdrop,
|
1495
|
+
keyboard: modal.keyboard
|
1496
|
+
});
|
1497
|
+
|
1498
|
+
var angularDomEl = angular.element('<div modal-window></div>');
|
1499
|
+
angularDomEl.attr('window-class', modal.windowClass);
|
1500
|
+
angularDomEl.attr('index', openedWindows.length() - 1);
|
1501
|
+
angularDomEl.html(modal.content);
|
1502
|
+
|
1503
|
+
var modalDomEl = $compile(angularDomEl)(modal.scope);
|
1504
|
+
openedWindows.top().value.modalDomEl = modalDomEl;
|
1505
|
+
body.append(modalDomEl);
|
1506
|
+
|
1507
|
+
if (backdropIndex() >= 0 && !backdropDomEl) {
|
1508
|
+
backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
|
1509
|
+
backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
|
1510
|
+
body.append(backdropDomEl);
|
1511
|
+
}
|
1512
|
+
};
|
1513
|
+
|
1514
|
+
$modalStack.close = function (modalInstance, result) {
|
1515
|
+
var modal = openedWindows.get(modalInstance);
|
1516
|
+
if (modal) {
|
1517
|
+
modal.value.deferred.resolve(result);
|
1518
|
+
removeModalWindow(modalInstance);
|
1519
|
+
}
|
1520
|
+
};
|
1521
|
+
|
1522
|
+
$modalStack.dismiss = function (modalInstance, reason) {
|
1523
|
+
var modalWindow = openedWindows.get(modalInstance).value;
|
1524
|
+
if (modalWindow) {
|
1525
|
+
modalWindow.deferred.reject(reason);
|
1526
|
+
removeModalWindow(modalInstance);
|
1527
|
+
}
|
1528
|
+
};
|
1529
|
+
|
1530
|
+
$modalStack.getTop = function () {
|
1531
|
+
return openedWindows.top();
|
1532
|
+
};
|
1533
|
+
|
1534
|
+
return $modalStack;
|
1535
|
+
}])
|
1536
|
+
|
1537
|
+
.provider('$modal', function () {
|
1538
|
+
|
1539
|
+
var $modalProvider = {
|
1540
|
+
options: {
|
1541
|
+
backdrop: true, //can be also false or 'static'
|
1542
|
+
keyboard: true
|
1543
|
+
},
|
1544
|
+
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
|
1545
|
+
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
|
1546
|
+
|
1547
|
+
var $modal = {};
|
1548
|
+
|
1549
|
+
function getTemplatePromise(options) {
|
1550
|
+
return options.template ? $q.when(options.template) :
|
1551
|
+
$http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
|
1552
|
+
return result.data;
|
1553
|
+
});
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
function getResolvePromises(resolves) {
|
1557
|
+
var promisesArr = [];
|
1558
|
+
angular.forEach(resolves, function (value, key) {
|
1559
|
+
if (angular.isFunction(value) || angular.isArray(value)) {
|
1560
|
+
promisesArr.push($q.when($injector.invoke(value)));
|
1561
|
+
}
|
1562
|
+
});
|
1563
|
+
return promisesArr;
|
1564
|
+
}
|
1565
|
+
|
1566
|
+
$modal.open = function (modalOptions) {
|
1567
|
+
|
1568
|
+
var modalResultDeferred = $q.defer();
|
1569
|
+
var modalOpenedDeferred = $q.defer();
|
1570
|
+
|
1571
|
+
//prepare an instance of a modal to be injected into controllers and returned to a caller
|
1572
|
+
var modalInstance = {
|
1573
|
+
result: modalResultDeferred.promise,
|
1574
|
+
opened: modalOpenedDeferred.promise,
|
1575
|
+
close: function (result) {
|
1576
|
+
$modalStack.close(modalInstance, result);
|
1577
|
+
},
|
1578
|
+
dismiss: function (reason) {
|
1579
|
+
$modalStack.dismiss(modalInstance, reason);
|
1580
|
+
}
|
1581
|
+
};
|
1582
|
+
|
1583
|
+
//merge and clean up options
|
1584
|
+
modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
|
1585
|
+
modalOptions.resolve = modalOptions.resolve || {};
|
1586
|
+
|
1587
|
+
//verify options
|
1588
|
+
if (!modalOptions.template && !modalOptions.templateUrl) {
|
1589
|
+
throw new Error('One of template or templateUrl options is required.');
|
1590
|
+
}
|
1591
|
+
|
1592
|
+
var templateAndResolvePromise =
|
1593
|
+
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
|
1594
|
+
|
1595
|
+
|
1596
|
+
templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
|
1597
|
+
|
1598
|
+
var modalScope = (modalOptions.scope || $rootScope).$new();
|
1599
|
+
modalScope.$close = modalInstance.close;
|
1600
|
+
modalScope.$dismiss = modalInstance.dismiss;
|
1601
|
+
|
1602
|
+
var ctrlInstance, ctrlLocals = {};
|
1603
|
+
var resolveIter = 1;
|
1604
|
+
|
1605
|
+
//controllers
|
1606
|
+
if (modalOptions.controller) {
|
1607
|
+
ctrlLocals.$scope = modalScope;
|
1608
|
+
ctrlLocals.$modalInstance = modalInstance;
|
1609
|
+
angular.forEach(modalOptions.resolve, function (value, key) {
|
1610
|
+
ctrlLocals[key] = tplAndVars[resolveIter++];
|
1611
|
+
});
|
1612
|
+
|
1613
|
+
ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
|
1614
|
+
}
|
1615
|
+
|
1616
|
+
$modalStack.open(modalInstance, {
|
1617
|
+
scope: modalScope,
|
1618
|
+
deferred: modalResultDeferred,
|
1619
|
+
content: tplAndVars[0],
|
1620
|
+
backdrop: modalOptions.backdrop,
|
1621
|
+
keyboard: modalOptions.keyboard,
|
1622
|
+
windowClass: modalOptions.windowClass
|
1623
|
+
});
|
1624
|
+
|
1625
|
+
}, function resolveError(reason) {
|
1626
|
+
modalResultDeferred.reject(reason);
|
1627
|
+
});
|
1628
|
+
|
1629
|
+
templateAndResolvePromise.then(function () {
|
1630
|
+
modalOpenedDeferred.resolve(true);
|
1631
|
+
}, function () {
|
1632
|
+
modalOpenedDeferred.reject(false);
|
1633
|
+
});
|
1634
|
+
|
1635
|
+
return modalInstance;
|
1636
|
+
};
|
1637
|
+
|
1638
|
+
return $modal;
|
1639
|
+
}]
|
1640
|
+
};
|
1641
|
+
|
1642
|
+
return $modalProvider;
|
1643
|
+
});
|
1643
1644
|
angular.module('ui.bootstrap.pagination', [])
|
1644
1645
|
|
1645
|
-
.controller('PaginationController', ['$scope', '$interpolate', function ($scope, $interpolate) {
|
1646
|
+
.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) {
|
1647
|
+
var self = this;
|
1646
1648
|
|
1647
|
-
this.
|
1649
|
+
this.init = function(defaultItemsPerPage) {
|
1650
|
+
if ($attrs.itemsPerPage) {
|
1651
|
+
$scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
|
1652
|
+
self.itemsPerPage = parseInt(value, 10);
|
1653
|
+
$scope.totalPages = self.calculateTotalPages();
|
1654
|
+
});
|
1655
|
+
} else {
|
1656
|
+
this.itemsPerPage = defaultItemsPerPage;
|
1657
|
+
}
|
1658
|
+
};
|
1648
1659
|
|
1649
1660
|
this.noPrevious = function() {
|
1650
|
-
return this.
|
1661
|
+
return this.page === 1;
|
1651
1662
|
};
|
1652
1663
|
this.noNext = function() {
|
1653
|
-
return this.
|
1664
|
+
return this.page === $scope.totalPages;
|
1654
1665
|
};
|
1655
1666
|
|
1656
1667
|
this.isActive = function(page) {
|
1657
|
-
return this.
|
1668
|
+
return this.page === page;
|
1658
1669
|
};
|
1659
1670
|
|
1660
|
-
this.
|
1661
|
-
$scope.
|
1662
|
-
|
1671
|
+
this.calculateTotalPages = function() {
|
1672
|
+
return this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
|
1673
|
+
};
|
1663
1674
|
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1675
|
+
this.getAttributeValue = function(attribute, defaultValue, interpolate) {
|
1676
|
+
return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
|
1677
|
+
};
|
1678
|
+
|
1679
|
+
this.render = function() {
|
1680
|
+
this.page = parseInt($scope.page, 10) || 1;
|
1681
|
+
$scope.pages = this.getPages(this.page, $scope.totalPages);
|
1667
1682
|
};
|
1668
1683
|
|
1669
|
-
var self = this;
|
1670
1684
|
$scope.selectPage = function(page) {
|
1671
|
-
if ( ! self.isActive(page) && page > 0 && page <= $scope.
|
1672
|
-
$scope.
|
1685
|
+
if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) {
|
1686
|
+
$scope.page = page;
|
1673
1687
|
$scope.onSelectPage({ page: page });
|
1674
1688
|
}
|
1675
1689
|
};
|
1676
1690
|
|
1677
|
-
|
1678
|
-
|
1679
|
-
};
|
1691
|
+
$scope.$watch('totalItems', function() {
|
1692
|
+
$scope.totalPages = self.calculateTotalPages();
|
1693
|
+
});
|
1694
|
+
|
1695
|
+
$scope.$watch('totalPages', function(value) {
|
1696
|
+
if ( $attrs.numPages ) {
|
1697
|
+
$scope.numPages = value; // Readonly variable
|
1698
|
+
}
|
1699
|
+
|
1700
|
+
if ( self.page > value ) {
|
1701
|
+
$scope.selectPage(value);
|
1702
|
+
} else {
|
1703
|
+
self.render();
|
1704
|
+
}
|
1705
|
+
});
|
1706
|
+
|
1707
|
+
$scope.$watch('page', function() {
|
1708
|
+
self.render();
|
1709
|
+
});
|
1680
1710
|
}])
|
1681
1711
|
|
1682
1712
|
.constant('paginationConfig', {
|
1713
|
+
itemsPerPage: 10,
|
1683
1714
|
boundaryLinks: false,
|
1684
1715
|
directionLinks: true,
|
1685
1716
|
firstText: 'First',
|
@@ -1689,14 +1720,14 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1689
1720
|
rotate: true
|
1690
1721
|
})
|
1691
1722
|
|
1692
|
-
.directive('pagination', ['paginationConfig', function(config) {
|
1723
|
+
.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
|
1693
1724
|
return {
|
1694
1725
|
restrict: 'EA',
|
1695
1726
|
scope: {
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1727
|
+
page: '=',
|
1728
|
+
totalItems: '=',
|
1729
|
+
onSelectPage:' &',
|
1730
|
+
numPages: '='
|
1700
1731
|
},
|
1701
1732
|
controller: 'PaginationController',
|
1702
1733
|
templateUrl: 'template/pagination/pagination.html',
|
@@ -1704,13 +1735,23 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1704
1735
|
link: function(scope, element, attrs, paginationCtrl) {
|
1705
1736
|
|
1706
1737
|
// Setup configuration parameters
|
1707
|
-
var
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1738
|
+
var maxSize,
|
1739
|
+
boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ),
|
1740
|
+
directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ),
|
1741
|
+
firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true),
|
1742
|
+
previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
|
1743
|
+
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
|
1744
|
+
lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true),
|
1745
|
+
rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate);
|
1746
|
+
|
1747
|
+
paginationCtrl.init(config.itemsPerPage);
|
1748
|
+
|
1749
|
+
if (attrs.maxSize) {
|
1750
|
+
scope.$parent.$watch($parse(attrs.maxSize), function(value) {
|
1751
|
+
maxSize = parseInt(value, 10);
|
1752
|
+
paginationCtrl.render();
|
1753
|
+
});
|
1754
|
+
}
|
1714
1755
|
|
1715
1756
|
// Create page object used in template
|
1716
1757
|
function makePage(number, text, isActive, isDisabled) {
|
@@ -1722,76 +1763,79 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1722
1763
|
};
|
1723
1764
|
}
|
1724
1765
|
|
1725
|
-
|
1726
|
-
|
1766
|
+
paginationCtrl.getPages = function(currentPage, totalPages) {
|
1767
|
+
var pages = [];
|
1727
1768
|
|
1728
1769
|
// Default page limits
|
1729
|
-
var startPage = 1, endPage =
|
1730
|
-
var isMaxSized = ( angular.isDefined(
|
1770
|
+
var startPage = 1, endPage = totalPages;
|
1771
|
+
var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages );
|
1731
1772
|
|
1732
1773
|
// recompute if maxSize
|
1733
1774
|
if ( isMaxSized ) {
|
1734
1775
|
if ( rotate ) {
|
1735
1776
|
// Current page is displayed in the middle of the visible ones
|
1736
|
-
startPage = Math.max(
|
1737
|
-
endPage = startPage +
|
1777
|
+
startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
|
1778
|
+
endPage = startPage + maxSize - 1;
|
1738
1779
|
|
1739
1780
|
// Adjust if limit is exceeded
|
1740
|
-
if (endPage >
|
1741
|
-
endPage =
|
1742
|
-
startPage = endPage -
|
1781
|
+
if (endPage > totalPages) {
|
1782
|
+
endPage = totalPages;
|
1783
|
+
startPage = endPage - maxSize + 1;
|
1743
1784
|
}
|
1744
1785
|
} else {
|
1745
1786
|
// Visible pages are paginated with maxSize
|
1746
|
-
startPage = ((Math.ceil(
|
1787
|
+
startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
|
1747
1788
|
|
1748
1789
|
// Adjust last page if limit is exceeded
|
1749
|
-
endPage = Math.min(startPage +
|
1790
|
+
endPage = Math.min(startPage + maxSize - 1, totalPages);
|
1750
1791
|
}
|
1751
1792
|
}
|
1752
1793
|
|
1753
1794
|
// Add page number links
|
1754
1795
|
for (var number = startPage; number <= endPage; number++) {
|
1755
1796
|
var page = makePage(number, number, paginationCtrl.isActive(number), false);
|
1756
|
-
|
1797
|
+
pages.push(page);
|
1757
1798
|
}
|
1758
1799
|
|
1759
1800
|
// Add links to move between page sets
|
1760
1801
|
if ( isMaxSized && ! rotate ) {
|
1761
1802
|
if ( startPage > 1 ) {
|
1762
1803
|
var previousPageSet = makePage(startPage - 1, '...', false, false);
|
1763
|
-
|
1804
|
+
pages.unshift(previousPageSet);
|
1764
1805
|
}
|
1765
1806
|
|
1766
|
-
if ( endPage <
|
1807
|
+
if ( endPage < totalPages ) {
|
1767
1808
|
var nextPageSet = makePage(endPage + 1, '...', false, false);
|
1768
|
-
|
1809
|
+
pages.push(nextPageSet);
|
1769
1810
|
}
|
1770
1811
|
}
|
1771
1812
|
|
1772
1813
|
// Add previous & next links
|
1773
1814
|
if (directionLinks) {
|
1774
|
-
var previousPage = makePage(
|
1775
|
-
|
1815
|
+
var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
|
1816
|
+
pages.unshift(previousPage);
|
1776
1817
|
|
1777
|
-
var nextPage = makePage(
|
1778
|
-
|
1818
|
+
var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext());
|
1819
|
+
pages.push(nextPage);
|
1779
1820
|
}
|
1780
1821
|
|
1781
1822
|
// Add first & last links
|
1782
1823
|
if (boundaryLinks) {
|
1783
1824
|
var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious());
|
1784
|
-
|
1825
|
+
pages.unshift(firstPage);
|
1785
1826
|
|
1786
|
-
var lastPage = makePage(
|
1787
|
-
|
1827
|
+
var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext());
|
1828
|
+
pages.push(lastPage);
|
1788
1829
|
}
|
1789
|
-
|
1830
|
+
|
1831
|
+
return pages;
|
1832
|
+
};
|
1790
1833
|
}
|
1791
1834
|
};
|
1792
1835
|
}])
|
1793
1836
|
|
1794
1837
|
.constant('pagerConfig', {
|
1838
|
+
itemsPerPage: 10,
|
1795
1839
|
previousText: '« Previous',
|
1796
1840
|
nextText: 'Next »',
|
1797
1841
|
align: true
|
@@ -1801,9 +1845,10 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1801
1845
|
return {
|
1802
1846
|
restrict: 'EA',
|
1803
1847
|
scope: {
|
1804
|
-
|
1805
|
-
|
1806
|
-
onSelectPage:
|
1848
|
+
page: '=',
|
1849
|
+
totalItems: '=',
|
1850
|
+
onSelectPage:' &',
|
1851
|
+
numPages: '='
|
1807
1852
|
},
|
1808
1853
|
controller: 'PaginationController',
|
1809
1854
|
templateUrl: 'template/pagination/pager.html',
|
@@ -1815,6 +1860,8 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1815
1860
|
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
|
1816
1861
|
align = paginationCtrl.getAttributeValue(attrs.align, config.align);
|
1817
1862
|
|
1863
|
+
paginationCtrl.init(config.itemsPerPage);
|
1864
|
+
|
1818
1865
|
// Create page object used in template
|
1819
1866
|
function makePage(number, text, isDisabled, isPrevious, isNext) {
|
1820
1867
|
return {
|
@@ -1826,16 +1873,12 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1826
1873
|
};
|
1827
1874
|
}
|
1828
1875
|
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
var nextPage = makePage(paginationCtrl.currentPage + 1, nextText, paginationCtrl.noNext(), false, true);
|
1837
|
-
scope.pages.push(nextPage);
|
1838
|
-
});
|
1876
|
+
paginationCtrl.getPages = function(currentPage) {
|
1877
|
+
return [
|
1878
|
+
makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
|
1879
|
+
makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
|
1880
|
+
];
|
1881
|
+
};
|
1839
1882
|
}
|
1840
1883
|
};
|
1841
1884
|
}]);
|
@@ -1845,7 +1888,7 @@ angular.module('ui.bootstrap.pagination', [])
|
|
1845
1888
|
* function, placement as a function, inside, support for more triggers than
|
1846
1889
|
* just mouse enter/leave, html tooltips, and selector delegation.
|
1847
1890
|
*/
|
1848
|
-
angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
1891
|
+
angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] )
|
1849
1892
|
|
1850
1893
|
/**
|
1851
1894
|
* The $tooltip service creates tooltip- and popover-like directives as well as
|
@@ -1878,9 +1921,9 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
1878
1921
|
* $tooltipProvider.options( { placement: 'left' } );
|
1879
1922
|
* });
|
1880
1923
|
*/
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1924
|
+
this.options = function( value ) {
|
1925
|
+
angular.extend( globalOptions, value );
|
1926
|
+
};
|
1884
1927
|
|
1885
1928
|
/**
|
1886
1929
|
* This allows you to extend the set of trigger mappings available. E.g.:
|
@@ -2026,13 +2069,6 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
|
|
2026
2069
|
// Calculate the tooltip's top and left coordinates to center it with
|
2027
2070
|
// this directive.
|
2028
2071
|
switch ( scope.tt_placement ) {
|
2029
|
-
case 'mouse':
|
2030
|
-
var mousePos = $position.mouse();
|
2031
|
-
ttPosition = {
|
2032
|
-
top: mousePos.y,
|
2033
|
-
left: mousePos.x
|
2034
|
-
};
|
2035
|
-
break;
|
2036
2072
|
case 'right':
|
2037
2073
|
ttPosition = {
|
2038
2074
|
top: position.top + position.height / 2 - ttHeight / 2,
|
@@ -2313,60 +2349,86 @@ angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition'])
|
|
2313
2349
|
angular.module('ui.bootstrap.rating', [])
|
2314
2350
|
|
2315
2351
|
.constant('ratingConfig', {
|
2316
|
-
max: 5
|
2352
|
+
max: 5,
|
2353
|
+
stateOn: null,
|
2354
|
+
stateOff: null
|
2317
2355
|
})
|
2318
2356
|
|
2319
|
-
.
|
2320
|
-
return {
|
2321
|
-
restrict: 'EA',
|
2322
|
-
scope: {
|
2323
|
-
value: '=',
|
2324
|
-
onHover: '&',
|
2325
|
-
onLeave: '&'
|
2326
|
-
},
|
2327
|
-
templateUrl: 'template/rating/rating.html',
|
2328
|
-
replace: true,
|
2329
|
-
link: function(scope, element, attrs) {
|
2357
|
+
.controller('RatingController', ['$scope', '$attrs', '$parse', 'ratingConfig', function($scope, $attrs, $parse, ratingConfig) {
|
2330
2358
|
|
2331
|
-
|
2359
|
+
this.maxRange = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max;
|
2360
|
+
this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
|
2361
|
+
this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
|
2332
2362
|
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2336
|
-
|
2363
|
+
this.createDefaultRange = function(len) {
|
2364
|
+
var defaultStateObject = {
|
2365
|
+
stateOn: this.stateOn,
|
2366
|
+
stateOff: this.stateOff
|
2367
|
+
};
|
2337
2368
|
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2369
|
+
var states = new Array(len);
|
2370
|
+
for (var i = 0; i < len; i++) {
|
2371
|
+
states[i] = defaultStateObject;
|
2372
|
+
}
|
2373
|
+
return states;
|
2374
|
+
};
|
2343
2375
|
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2376
|
+
this.normalizeRange = function(states) {
|
2377
|
+
for (var i = 0, n = states.length; i < n; i++) {
|
2378
|
+
states[i].stateOn = states[i].stateOn || this.stateOn;
|
2379
|
+
states[i].stateOff = states[i].stateOff || this.stateOff;
|
2380
|
+
}
|
2381
|
+
return states;
|
2382
|
+
};
|
2350
2383
|
|
2351
|
-
|
2352
|
-
|
2353
|
-
scope.onLeave();
|
2354
|
-
};
|
2355
|
-
scope.reset();
|
2384
|
+
// Get objects used in template
|
2385
|
+
$scope.range = angular.isDefined($attrs.ratingStates) ? this.normalizeRange(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createDefaultRange(this.maxRange);
|
2356
2386
|
|
2357
|
-
|
2358
|
-
|
2359
|
-
|
2387
|
+
$scope.rate = function(value) {
|
2388
|
+
if ( $scope.readonly || $scope.value === value) {
|
2389
|
+
return;
|
2390
|
+
}
|
2360
2391
|
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2392
|
+
$scope.value = value;
|
2393
|
+
};
|
2394
|
+
|
2395
|
+
$scope.enter = function(value) {
|
2396
|
+
if ( ! $scope.readonly ) {
|
2397
|
+
$scope.val = value;
|
2367
2398
|
}
|
2399
|
+
$scope.onHover({value: value});
|
2400
|
+
};
|
2401
|
+
|
2402
|
+
$scope.reset = function() {
|
2403
|
+
$scope.val = angular.copy($scope.value);
|
2404
|
+
$scope.onLeave();
|
2368
2405
|
};
|
2369
|
-
|
2406
|
+
|
2407
|
+
$scope.$watch('value', function(value) {
|
2408
|
+
$scope.val = value;
|
2409
|
+
});
|
2410
|
+
|
2411
|
+
$scope.readonly = false;
|
2412
|
+
if ($attrs.readonly) {
|
2413
|
+
$scope.$parent.$watch($parse($attrs.readonly), function(value) {
|
2414
|
+
$scope.readonly = !!value;
|
2415
|
+
});
|
2416
|
+
}
|
2417
|
+
}])
|
2418
|
+
|
2419
|
+
.directive('rating', function() {
|
2420
|
+
return {
|
2421
|
+
restrict: 'EA',
|
2422
|
+
scope: {
|
2423
|
+
value: '=',
|
2424
|
+
onHover: '&',
|
2425
|
+
onLeave: '&'
|
2426
|
+
},
|
2427
|
+
controller: 'RatingController',
|
2428
|
+
templateUrl: 'template/rating/rating.html',
|
2429
|
+
replace: true
|
2430
|
+
};
|
2431
|
+
});
|
2370
2432
|
|
2371
2433
|
/**
|
2372
2434
|
* @ngdoc overview
|
@@ -2454,7 +2516,7 @@ function TabsetCtrl($scope, $element) {
|
|
2454
2516
|
templateUrl: 'template/tabs/tabset.html',
|
2455
2517
|
compile: function(elm, attrs, transclude) {
|
2456
2518
|
return function(scope, element, attrs, tabsetCtrl) {
|
2457
|
-
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$eval(attrs.vertical) : false;
|
2519
|
+
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
|
2458
2520
|
scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs';
|
2459
2521
|
scope.direction = angular.isDefined(attrs.direction) ? scope.$parent.$eval(attrs.direction) : 'top';
|
2460
2522
|
scope.tabsAbove = (scope.direction != 'below');
|
@@ -2662,7 +2724,7 @@ function($parse, $http, $templateCache, $compile) {
|
|
2662
2724
|
}
|
2663
2725
|
}])
|
2664
2726
|
|
2665
|
-
.directive('tabsetTitles', function($http) {
|
2727
|
+
.directive('tabsetTitles', ['$http', function($http) {
|
2666
2728
|
return {
|
2667
2729
|
restrict: 'A',
|
2668
2730
|
require: '^tabset',
|
@@ -2679,22 +2741,13 @@ function($parse, $http, $templateCache, $compile) {
|
|
2679
2741
|
}
|
2680
2742
|
}
|
2681
2743
|
};
|
2682
|
-
})
|
2744
|
+
}])
|
2683
2745
|
|
2684
2746
|
;
|
2685
2747
|
|
2686
2748
|
|
2687
2749
|
angular.module('ui.bootstrap.timepicker', [])
|
2688
2750
|
|
2689
|
-
.filter('pad', function() {
|
2690
|
-
return function(input) {
|
2691
|
-
if ( angular.isDefined(input) && input.toString().length < 2 ) {
|
2692
|
-
input = '0' + input;
|
2693
|
-
}
|
2694
|
-
return input;
|
2695
|
-
};
|
2696
|
-
})
|
2697
|
-
|
2698
2751
|
.constant('timepickerConfig', {
|
2699
2752
|
hourStep: 1,
|
2700
2753
|
minuteStep: 1,
|
@@ -2704,16 +2757,18 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2704
2757
|
mousewheel: true
|
2705
2758
|
})
|
2706
2759
|
|
2707
|
-
.directive('timepicker', ['
|
2760
|
+
.directive('timepicker', ['$parse', '$log', 'timepickerConfig', function ($parse, $log, timepickerConfig) {
|
2708
2761
|
return {
|
2709
2762
|
restrict: 'EA',
|
2710
|
-
require:'ngModel',
|
2763
|
+
require:'?^ngModel',
|
2711
2764
|
replace: true,
|
2765
|
+
scope: {},
|
2712
2766
|
templateUrl: 'template/timepicker/timepicker.html',
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2767
|
+
link: function(scope, element, attrs, ngModel) {
|
2768
|
+
if ( !ngModel ) {
|
2769
|
+
return; // do nothing if no ng-model
|
2770
|
+
}
|
2771
|
+
|
2717
2772
|
var selected = new Date(), meridians = timepickerConfig.meridians;
|
2718
2773
|
|
2719
2774
|
var hourStep = timepickerConfig.hourStep;
|
@@ -2734,28 +2789,27 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2734
2789
|
scope.showMeridian = timepickerConfig.showMeridian;
|
2735
2790
|
if (attrs.showMeridian) {
|
2736
2791
|
scope.$parent.$watch($parse(attrs.showMeridian), function(value) {
|
2737
|
-
scope.showMeridian = !!
|
2738
|
-
|
2739
|
-
if (
|
2740
|
-
//
|
2741
|
-
var
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2792
|
+
scope.showMeridian = !!value;
|
2793
|
+
|
2794
|
+
if ( ngModel.$error.time ) {
|
2795
|
+
// Evaluate from template
|
2796
|
+
var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
|
2797
|
+
if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
|
2798
|
+
selected.setHours( hours );
|
2799
|
+
refresh();
|
2745
2800
|
}
|
2746
|
-
scope.model = new Date( dt );
|
2747
2801
|
} else {
|
2748
|
-
|
2802
|
+
updateTemplate();
|
2749
2803
|
}
|
2750
2804
|
});
|
2751
2805
|
}
|
2752
2806
|
|
2753
2807
|
// Get scope.hours in 24H mode if valid
|
2754
|
-
function
|
2808
|
+
function getHoursFromTemplate ( ) {
|
2755
2809
|
var hours = parseInt( scope.hours, 10 );
|
2756
2810
|
var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
|
2757
2811
|
if ( !valid ) {
|
2758
|
-
return;
|
2812
|
+
return undefined;
|
2759
2813
|
}
|
2760
2814
|
|
2761
2815
|
if ( scope.showMeridian ) {
|
@@ -2769,14 +2823,22 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2769
2823
|
return hours;
|
2770
2824
|
}
|
2771
2825
|
|
2826
|
+
function getMinutesFromTemplate() {
|
2827
|
+
var minutes = parseInt(scope.minutes, 10);
|
2828
|
+
return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
|
2829
|
+
}
|
2830
|
+
|
2831
|
+
function pad( value ) {
|
2832
|
+
return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
|
2833
|
+
}
|
2834
|
+
|
2772
2835
|
// Input elements
|
2773
|
-
var inputs = element.find('input');
|
2774
|
-
var hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1);
|
2836
|
+
var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1);
|
2775
2837
|
|
2776
2838
|
// Respond on mousewheel spin
|
2777
2839
|
var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel;
|
2778
2840
|
if ( mousewheel ) {
|
2779
|
-
|
2841
|
+
|
2780
2842
|
var isScrollingUp = function(e) {
|
2781
2843
|
if (e.originalEvent) {
|
2782
2844
|
e = e.originalEvent;
|
@@ -2785,7 +2847,7 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2785
2847
|
var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
|
2786
2848
|
return (e.detail || delta > 0);
|
2787
2849
|
};
|
2788
|
-
|
2850
|
+
|
2789
2851
|
hoursInputEl.bind('mousewheel wheel', function(e) {
|
2790
2852
|
scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() );
|
2791
2853
|
e.preventDefault();
|
@@ -2797,50 +2859,54 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2797
2859
|
});
|
2798
2860
|
}
|
2799
2861
|
|
2800
|
-
var keyboardChange = false;
|
2801
2862
|
scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput;
|
2802
2863
|
if ( ! scope.readonlyInput ) {
|
2864
|
+
|
2865
|
+
var invalidate = function(invalidHours, invalidMinutes) {
|
2866
|
+
ngModel.$setViewValue( null );
|
2867
|
+
ngModel.$setValidity('time', false);
|
2868
|
+
if (angular.isDefined(invalidHours)) {
|
2869
|
+
scope.invalidHours = invalidHours;
|
2870
|
+
}
|
2871
|
+
if (angular.isDefined(invalidMinutes)) {
|
2872
|
+
scope.invalidMinutes = invalidMinutes;
|
2873
|
+
}
|
2874
|
+
};
|
2875
|
+
|
2803
2876
|
scope.updateHours = function() {
|
2804
|
-
var hours =
|
2877
|
+
var hours = getHoursFromTemplate();
|
2805
2878
|
|
2806
2879
|
if ( angular.isDefined(hours) ) {
|
2807
|
-
|
2808
|
-
|
2809
|
-
scope.model = new Date( selected );
|
2810
|
-
}
|
2811
|
-
scope.model.setHours( hours );
|
2880
|
+
selected.setHours( hours );
|
2881
|
+
refresh( 'h' );
|
2812
2882
|
} else {
|
2813
|
-
|
2814
|
-
scope.validHours = false;
|
2883
|
+
invalidate(true);
|
2815
2884
|
}
|
2816
2885
|
};
|
2817
2886
|
|
2818
2887
|
hoursInputEl.bind('blur', function(e) {
|
2819
|
-
if ( scope.validHours && scope.hours < 10) {
|
2888
|
+
if ( !scope.validHours && scope.hours < 10) {
|
2820
2889
|
scope.$apply( function() {
|
2821
|
-
scope.hours =
|
2890
|
+
scope.hours = pad( scope.hours );
|
2822
2891
|
});
|
2823
2892
|
}
|
2824
2893
|
});
|
2825
2894
|
|
2826
2895
|
scope.updateMinutes = function() {
|
2827
|
-
var minutes =
|
2828
|
-
|
2829
|
-
|
2830
|
-
|
2831
|
-
|
2832
|
-
}
|
2833
|
-
scope.model.setMinutes( minutes );
|
2896
|
+
var minutes = getMinutesFromTemplate();
|
2897
|
+
|
2898
|
+
if ( angular.isDefined(minutes) ) {
|
2899
|
+
selected.setMinutes( minutes );
|
2900
|
+
refresh( 'm' );
|
2834
2901
|
} else {
|
2835
|
-
|
2836
|
-
scope.validMinutes = false;
|
2902
|
+
invalidate(undefined, true);
|
2837
2903
|
}
|
2838
2904
|
};
|
2839
2905
|
|
2840
2906
|
minutesInputEl.bind('blur', function(e) {
|
2841
|
-
if ( scope.
|
2907
|
+
if ( !scope.invalidMinutes && scope.minutes < 10 ) {
|
2842
2908
|
scope.$apply( function() {
|
2843
|
-
scope.minutes =
|
2909
|
+
scope.minutes = pad( scope.minutes );
|
2844
2910
|
});
|
2845
2911
|
}
|
2846
2912
|
});
|
@@ -2849,38 +2915,49 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2849
2915
|
scope.updateMinutes = angular.noop;
|
2850
2916
|
}
|
2851
2917
|
|
2852
|
-
|
2853
|
-
|
2854
|
-
}, function( timestamp ) {
|
2855
|
-
if ( !isNaN( timestamp ) && timestamp > 0 ) {
|
2856
|
-
selected = new Date( timestamp );
|
2857
|
-
refreshTemplate();
|
2858
|
-
}
|
2859
|
-
});
|
2918
|
+
ngModel.$render = function() {
|
2919
|
+
var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null;
|
2860
2920
|
|
2861
|
-
|
2862
|
-
|
2863
|
-
|
2864
|
-
|
2865
|
-
|
2921
|
+
if ( isNaN(date) ) {
|
2922
|
+
ngModel.$setValidity('time', false);
|
2923
|
+
$log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
|
2924
|
+
} else {
|
2925
|
+
if ( date ) {
|
2926
|
+
selected = date;
|
2927
|
+
}
|
2928
|
+
makeValid();
|
2929
|
+
updateTemplate();
|
2866
2930
|
}
|
2867
|
-
|
2868
|
-
|
2931
|
+
};
|
2932
|
+
|
2933
|
+
// Call internally when we know that model is valid.
|
2934
|
+
function refresh( keyboardChange ) {
|
2935
|
+
makeValid();
|
2936
|
+
ngModel.$setViewValue( new Date(selected) );
|
2937
|
+
updateTemplate( keyboardChange );
|
2938
|
+
}
|
2869
2939
|
|
2870
|
-
|
2871
|
-
|
2872
|
-
scope.
|
2940
|
+
function makeValid() {
|
2941
|
+
ngModel.$setValidity('time', true);
|
2942
|
+
scope.invalidHours = false;
|
2943
|
+
scope.invalidMinutes = false;
|
2944
|
+
}
|
2873
2945
|
|
2874
|
-
|
2946
|
+
function updateTemplate( keyboardChange ) {
|
2947
|
+
var hours = selected.getHours(), minutes = selected.getMinutes();
|
2875
2948
|
|
2876
|
-
|
2949
|
+
if ( scope.showMeridian ) {
|
2950
|
+
hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
|
2951
|
+
}
|
2952
|
+
scope.hours = keyboardChange === 'h' ? hours : pad(hours);
|
2953
|
+
scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
|
2954
|
+
scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
|
2877
2955
|
}
|
2878
2956
|
|
2879
2957
|
function addMinutes( minutes ) {
|
2880
2958
|
var dt = new Date( selected.getTime() + minutes * 60000 );
|
2881
|
-
selected.setHours( dt.getHours() );
|
2882
|
-
|
2883
|
-
scope.model = new Date( selected );
|
2959
|
+
selected.setHours( dt.getHours(), dt.getMinutes() );
|
2960
|
+
refresh();
|
2884
2961
|
}
|
2885
2962
|
|
2886
2963
|
scope.incrementHours = function() {
|
@@ -2902,7 +2979,7 @@ angular.module('ui.bootstrap.timepicker', [])
|
|
2902
2979
|
};
|
2903
2980
|
}]);
|
2904
2981
|
|
2905
|
-
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
2982
|
+
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
|
2906
2983
|
|
2907
2984
|
/**
|
2908
2985
|
* A helper service that can parse typeahead's syntax (string provided by users)
|
@@ -2933,7 +3010,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
2933
3010
|
};
|
2934
3011
|
}])
|
2935
3012
|
|
2936
|
-
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser',
|
3013
|
+
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser',
|
3014
|
+
function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) {
|
2937
3015
|
|
2938
3016
|
var HOT_KEYS = [9, 13, 27, 38, 40];
|
2939
3017
|
|
@@ -3046,7 +3124,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3046
3124
|
|
3047
3125
|
//plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
|
3048
3126
|
//$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
|
3049
|
-
modelCtrl.$parsers.
|
3127
|
+
modelCtrl.$parsers.unshift(function (inputValue) {
|
3050
3128
|
|
3051
3129
|
resetMatches();
|
3052
3130
|
if (inputValue && inputValue.length >= minSearch) {
|
@@ -3062,7 +3140,12 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3062
3140
|
}
|
3063
3141
|
}
|
3064
3142
|
|
3065
|
-
|
3143
|
+
if (isEditable) {
|
3144
|
+
return inputValue;
|
3145
|
+
} else {
|
3146
|
+
modelCtrl.$setValidity('editable', false);
|
3147
|
+
return undefined;
|
3148
|
+
}
|
3066
3149
|
});
|
3067
3150
|
|
3068
3151
|
modelCtrl.$formatters.push(function (modelValue) {
|
@@ -3076,12 +3159,13 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3076
3159
|
return inputFormatter(originalScope, locals);
|
3077
3160
|
|
3078
3161
|
} else {
|
3079
|
-
locals[parserResult.itemName] = modelValue;
|
3080
3162
|
|
3081
3163
|
//it might happen that we don't have enough info to properly render input value
|
3082
3164
|
//we need to check for this situation and simply return model value if we can't apply custom formatting
|
3165
|
+
locals[parserResult.itemName] = modelValue;
|
3083
3166
|
candidateViewValue = parserResult.viewMapper(originalScope, locals);
|
3084
|
-
|
3167
|
+
locals[parserResult.itemName] = undefined;
|
3168
|
+
emptyViewValue = parserResult.viewMapper(originalScope, locals);
|
3085
3169
|
|
3086
3170
|
return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
|
3087
3171
|
}
|
@@ -3095,6 +3179,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3095
3179
|
locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
|
3096
3180
|
model = parserResult.modelMapper(originalScope, locals);
|
3097
3181
|
$setModelValue(originalScope, model);
|
3182
|
+
modelCtrl.$setValidity('editable', true);
|
3098
3183
|
|
3099
3184
|
onSelectCallback(originalScope, {
|
3100
3185
|
$item: item,
|
@@ -3102,8 +3187,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3102
3187
|
$label: parserResult.viewMapper(originalScope, locals)
|
3103
3188
|
});
|
3104
3189
|
|
3105
|
-
//return focus to the input element if a mach was selected via a mouse click event
|
3106
3190
|
resetMatches();
|
3191
|
+
|
3192
|
+
//return focus to the input element if a mach was selected via a mouse click event
|
3107
3193
|
element[0].focus();
|
3108
3194
|
};
|
3109
3195
|
|
@@ -3138,9 +3224,18 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3138
3224
|
}
|
3139
3225
|
});
|
3140
3226
|
|
3141
|
-
|
3142
|
-
|
3143
|
-
|
3227
|
+
// Keep reference to click handler to unbind it.
|
3228
|
+
var dismissClickHandler = function (evt) {
|
3229
|
+
if (element[0] !== evt.target) {
|
3230
|
+
resetMatches();
|
3231
|
+
scope.$digest();
|
3232
|
+
}
|
3233
|
+
};
|
3234
|
+
|
3235
|
+
$document.bind('click', dismissClickHandler);
|
3236
|
+
|
3237
|
+
originalScope.$on('$destroy', function(){
|
3238
|
+
$document.unbind('click', dismissClickHandler);
|
3144
3239
|
});
|
3145
3240
|
|
3146
3241
|
element.after($compile(popUpEl)(scope));
|
@@ -3208,6 +3303,6 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
|
|
3208
3303
|
}
|
3209
3304
|
|
3210
3305
|
return function(matchItem, query) {
|
3211
|
-
return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') :
|
3306
|
+
return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
|
3212
3307
|
};
|
3213
3308
|
});
|