Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #1077 from mgcrea/update-angular-strap

Update angular strap
  • Loading branch information...
commit 44581a2d84e90b321da1b1f1e1e6a5353d2f918b 2 parents fd87e37 + 8b460ae
@Lockyc Lockyc authored
View
903 ajax/libs/angular-strap/0.6.6/angular-strap.js
@@ -0,0 +1,903 @@
+/**
+ * AngularStrap - Twitter Bootstrap directives for AngularJS
+ * @version v0.6.6 - 2013-02-13
+ * @link http://mgcrea.github.com/angular-strap
+ * @author Olivier Louvignes
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
+
+
+angular.module('$strap.config', []).value('$strap.config', {});
+angular.module('$strap.filters', ['$strap.config']);
+angular.module('$strap.directives', ['$strap.config']);
+angular.module('$strap', ['$strap.filters', '$strap.directives', '$strap.config']);
+
+
+angular.module('$strap.directives')
+
+.directive('bsAlert', ['$parse', '$timeout', '$compile', function($parse, $timeout, $compile) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ link: function postLink(scope, element, attrs) {
+
+ var getter = $parse(attrs.bsAlert),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // For static alerts
+ if(!attrs.bsAlert) {
+
+ // Setup close button
+ if(angular.isUndefined(attrs.closeButton) || (attrs.closeButton !== '0' && attrs.closeButton !== 'false')) {
+ element.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>');
+ }
+
+ } else {
+
+ scope.$watch(attrs.bsAlert, function(newValue, oldValue) {
+ value = newValue;
+
+ // Set alert content
+ element.html((newValue.title ? '<strong>' + newValue.title + '</strong>&nbsp;' : '') + newValue.content || '');
+
+ if(!!newValue.closed) {
+ element.hide();
+ }
+
+ // Compile alert content
+ //$timeout(function(){
+ $compile(element.contents())(scope);
+ //});
+
+ // Add proper class
+ if(newValue.type || oldValue.type) {
+ oldValue.type && element.removeClass('alert-' + oldValue.type);
+ newValue.type && element.addClass('alert-' + newValue.type);
+ }
+
+ // Setup close button
+ if(angular.isUndefined(attrs.closeButton) || (attrs.closeButton !== '0' && attrs.closeButton !== 'false')) {
+ element.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>');
+ }
+
+ }, true);
+
+ }
+
+ element.addClass('alert').alert();
+
+ // Support fade-in effect
+ if(element.hasClass('fade')) {
+ element.removeClass('in');
+ setTimeout(function() {
+ element.addClass('in');
+ });
+ }
+
+ var parentArray = attrs.ngRepeat && attrs.ngRepeat.split(' in ').pop();
+
+ element.on('close', function(ev) { console.warn('close!');
+ var removeElement;
+
+ if(parentArray) { // ngRepeat, remove from parent array
+ ev.preventDefault();
+
+ element.removeClass('in');
+ console.warn(scope.$parent);
+
+ removeElement = function() {
+ element.trigger('closed');
+ if(scope.$parent) {
+ scope.$parent.$apply(function() {
+ scope.$parent[parentArray].splice(scope.$index, 1);
+ });
+ }
+ };
+
+ $.support.transition && element.hasClass('fade') ?
+ element.on($.support.transition.end, removeElement) :
+ removeElement();
+
+ } else if(value) { // object, set closed property to 'true'
+ ev.preventDefault();
+
+ element.removeClass('in');
+
+ removeElement = function() {
+ element.trigger('closed');
+ scope.$apply(function() {
+ value.closed = true;
+ });
+ };
+
+ $.support.transition && element.hasClass('fade') ?
+ element.on($.support.transition.end, removeElement) :
+ removeElement();
+
+ } else { // static, regular behavior
+ }
+
+ });
+
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsButton', ['$parse', '$timeout', function($parse, $timeout) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+
+ // Set as single toggler if not part of a btn-group
+ if(!element.parent('[data-toggle="buttons-checkbox"], [data-toggle="buttons-radio"]').length) {
+ element.attr('data-toggle', 'button');
+ }
+
+ // Handle start state
+ var startValue = !!scope.$eval(attrs.ngModel);
+ if(startValue) {
+ element.addClass('active');
+ }
+
+ // Watch model for changes
+ scope.$watch(attrs.ngModel, function(newValue, oldValue) {
+ var bNew = !!newValue, bOld = !!oldValue;
+ if(bNew !== bOld) {
+ $.fn.button.Constructor.prototype.toggle.call(button);
+ // Handle $q promises
+ } else if(bNew && !startValue) {
+ element.addClass('active');
+ }
+ });
+
+ }
+
+ // Support buttons without .btn class
+ if(!element.hasClass('btn')) {
+ element.on('click.button.data-api', function (e) {
+ element.button('toggle');
+ });
+ }
+
+ // Initialize button
+ element.button();
+
+ // Bootstrap override to handle toggling
+ var button = element.data('button');
+ button.toggle = function() {
+
+ if(!controller) {
+ return $.fn.button.Constructor.prototype.toggle.call(this);
+ }
+
+ var $parent = element.parent('[data-toggle="buttons-radio"]');
+
+ if($parent.length) {
+ element.siblings('[ng-model]').each(function(k, v) {
+ $parse($(v).attr('ng-model')).assign(scope, false);
+ });
+ scope.$digest();
+ if(!controller.$modelValue) {
+ controller.$setViewValue(!controller.$modelValue);
+ scope.$digest();
+ }
+ } else {
+ scope.$apply(function () {
+ controller.$setViewValue(!controller.$modelValue);
+ });
+ }
+
+ };
+
+ /*Provide scope display functions
+ scope._button = function(event) {
+ element.button(event);
+ };
+ scope.loading = function() {
+ element.tooltip('loading');
+ };
+ scope.reset = function() {
+ element.tooltip('reset');
+ };
+
+ if(attrs.loadingText) element.click(function () {
+ //var btn = $(this)
+ element.button('loading')
+ setTimeout(function () {
+ element.button('reset')
+ }, 1000)
+ });*/
+
+ }
+ };
+
+}])
+
+.directive('bsButtonsCheckbox', ['$parse', function($parse) {
+ 'use strict';
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ compile: function compile(tElement, tAttrs, transclude) {
+ tElement.attr('data-toggle', 'buttons-checkbox').find('a, button').each(function(k, v) {
+ $(v).attr('bs-button', '');
+ });
+ }
+ };
+
+}])
+
+.directive('bsButtonsRadio', ['$parse', function($parse) {
+ 'use strict';
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ compile: function compile(tElement, tAttrs, transclude) {
+
+ tElement.attr('data-toggle', 'buttons-radio');
+
+ // Delegate to children ngModel
+ if(!tAttrs.ngModel) {
+ tElement.find('a, button').each(function(k, v) {
+ $(v).attr('bs-button', '');
+ });
+ }
+
+ return function postLink(scope, iElement, iAttrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+
+ iElement
+ .find('[value]').button()
+ .filter('[value="' + scope.$eval(iAttrs.ngModel) + '"]')
+ .addClass('active');
+
+ iElement.on('click.button.data-api', function (ev) {
+ scope.$apply(function () {
+ controller.$setViewValue($(ev.target).closest('button').attr('value'));
+ });
+ });
+
+ // Watch model for changes
+ scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ var $btn = iElement.find('[value="' + scope.$eval(iAttrs.ngModel) + '"]');
+ if($btn.length) {
+ $.fn.button.Constructor.prototype.toggle.call($btn.data('button'));
+ }
+ }
+ });
+
+ }
+
+ };
+ }
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsButtonSelect', ['$parse', '$timeout', function($parse, $timeout) {
+ 'use strict';
+
+ var isTouch = 'ontouchstart' in window;
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attr, ctrl) {
+
+ var getter = $parse(attr.bsButtonSelect),
+ setter = getter.assign;
+
+ // Bind ngModelController
+ if(ctrl) {
+ element.text(scope.$eval(attr.ngModel));
+ // Watch model for changes
+ scope.$watch(attr.ngModel, function(newValue, oldValue) {
+ element.text(newValue);
+ });
+ }
+
+
+ // Click handling
+ var values, value, index, newValue;
+ element.on(isTouch ? 'touchstart.bsButtonSelect.data-api' : 'click.bsButtonSelect.data-api', function(ev) {
+ values = getter(scope);
+ value = ctrl ? scope.$eval(attr.ngModel) : element.text();
+ index = values.indexOf(value);
+ newValue = index > values.length - 2 ? values[0] : values[index + 1];
+
+ scope.$apply(function() {
+ element.text(newValue);
+ if(ctrl) {
+ ctrl.$setViewValue(newValue);
+ }
+ });
+ });
+ }
+ };
+}]);
+
+// https://github.com/eternicode/bootstrap-datepicker
+
+angular.module('$strap.directives')
+
+.directive('bsDatepicker', ['$timeout', function($timeout) {
+ 'use strict';
+
+ var isTouch = 'ontouchstart' in window && !window.navigator.userAgent.match(/PhantomJS/i);
+
+ var DATE_REGEXP_MAP = {
+ '/' : '[\\/]',
+ '-' : '[-]',
+ '.' : '[.]',
+ 'dd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ 'd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ 'mm' : '(?:[0]?[1-9]|[1][012])',
+ 'm' : '(?:[0]?[1-9]|[1][012])',
+ 'yyyy' : '(?:(?:[1]{1}[0-9]{1}[0-9]{1}[0-9]{1})|(?:[2]{1}[0-9]{3}))(?![[0-9]])',
+ 'yy' : '(?:(?:[0-9]{1}[0-9]{1}))(?![[0-9]])'
+ };
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+ //console.log('postLink', this, arguments); window.element = element;
+
+ var regexpForDateFormat = function(dateFormat, options) {
+ options || (options = {});
+ var re = dateFormat, regexpMap = DATE_REGEXP_MAP;
+ /*if(options.mask) {
+ regexpMap['/'] = '';
+ regexpMap['-'] = '';
+ }*/
+ angular.forEach(regexpMap, function(v, k) { re = re.split(k).join(v); });
+ return new RegExp('^' + re + '$', ['i']);
+ };
+
+ var dateFormatRegexp = isTouch ? 'yyyy/mm/dd' : regexpForDateFormat(attrs.dateFormat || 'mm/dd/yyyy'/*, {mask: !!attrs.uiMask}*/);
+
+ // Handle date validity according to dateFormat
+ if(controller) {
+ controller.$parsers.unshift(function(viewValue) {
+ //console.warn('viewValue', viewValue, dateFormatRegexp, dateFormatRegexp.test(viewValue));
+ if (!viewValue || dateFormatRegexp.test(viewValue)) {
+ controller.$setValidity('date', true);
+ return viewValue;
+ } else {
+ controller.$setValidity('date', false);
+ return undefined;
+ }
+ });
+ }
+
+ // Support add-on
+ var component = element.next('[data-toggle="datepicker"]');
+ if(component.length) {
+ component.on('click', function() { isTouch ? element.trigger('focus') : element.datepicker('show'); });
+ }
+
+ // Use native interface for touch devices
+ if(isTouch && element.prop('type') === 'text') {
+
+ element.prop('type', 'date');
+ element.on('change', function(ev) {
+ scope.$apply(function () {
+ controller.$setViewValue(element.val());
+ });
+ });
+
+ } else {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ element.on('changeDate', function(ev) {
+ scope.$apply(function () {
+ controller.$setViewValue(element.val());
+ });
+ });
+ }
+
+ // Popover GarbageCollection
+ var $popover = element.closest('.popover');
+ if($popover) {
+ $popover.on('hide', function(e) {
+ var datepicker = element.data('datepicker');
+ if(datepicker) {
+ datepicker.picker.remove();
+ element.data('datepicker', null);
+ }
+ });
+ }
+
+ // Create datepicker
+ element.attr('data-toggle', 'datepicker');
+ element.datepicker({
+ autoclose: true,
+ language: attrs.language || 'en'
+ });
+
+ }
+
+ }
+
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsDropdown', ['$parse', '$compile', function($parse, $compile) {
+ 'use strict';
+
+ var slice = Array.prototype.slice;
+
+ var template = '' +
+ '<ul class="dropdown-menu" role="menu" aria-labelledby="drop1">' +
+ '<li ng-repeat="item in items" ng-class="{divider: !!item.divider, \'dropdown-submenu\': !!item.submenu && item.submenu.length}">' +
+ '<a ng-hide="!!item.divider" tabindex="-1" ng-href="{{item.href}}" ng-click="{{item.click}}" target="{{item.target}}" ng-bind-html-unsafe="item.text"></a>' +
+ '</li>' +
+ '</ul>';
+
+ var linkSubmenu = function(items, parent, scope) {
+ var subitems, submenu, subscope;
+ for (var i = 0, l = items.length; i < l; i++) {
+ if(subitems = items[i].submenu) {
+ subscope = scope.$new();
+ subscope.items = subitems;
+ submenu = $compile(template)(subscope);
+ submenu = submenu.appendTo(parent.children('li:nth-child(' + (i+1) + ')'));
+ asyncLinkSubmenu(subitems, submenu, subscope);
+ }
+ }
+ };
+
+ var asyncLinkSubmenu = function() {
+ var args = slice.call(arguments);
+ setTimeout(function() {
+ linkSubmenu.apply(null, args);
+ });
+ };
+
+ return {
+ restrict: 'EA',
+ scope: true,
+ link: function postLink(scope, element, attr) {
+
+ var getter = $parse(attr.bsDropdown);
+
+ scope.items = getter(scope);
+ var dropdown = $compile(template)(scope);
+ asyncLinkSubmenu(scope.items, dropdown, scope);
+ dropdown.insertAfter(element);
+
+ element
+ .addClass('dropdown-toggle')
+ .attr('data-toggle', "dropdown");
+
+ }
+ };
+
+}]);
+
+angular.module('$strap.directives')
+
+.directive('bsModal', ['$parse', '$compile', '$http', '$timeout', '$q', '$templateCache', function($parse, $compile, $http, $timeout, $q, $templateCache) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attr, ctrl) {
+
+ var getter = $parse(attr.bsModal),
+ setter = getter.assign,
+ value = getter(scope);
+
+ $q.when($templateCache.get(value) || $http.get(value, {cache: true})).then(function onSuccess(template) {
+
+ // Handle response from $http promise
+ if(angular.isObject(template)) {
+ template = template.data;
+ }
+
+ // Build modal object
+ var id = getter(scope).replace('.html', '').replace(/\//g, '-').replace(/\./g, '-') + '-' + scope.$id;
+ var $modal = $('<div class="modal hide" tabindex="-1"></div>')
+ .attr('id', id)
+ .attr('data-backdrop', attr.backdrop || true)
+ .attr('data-keyboard', attr.keyboard || true)
+ .addClass(attr.modalClass ? 'fade ' + attr.modalClass : 'fade')
+ .html(template);
+
+ $('body').append($modal);
+
+ // Configure element
+ element.attr('href', '#' + id).attr('data-toggle', 'modal');
+
+ // Compile modal content
+ $timeout(function(){
+ $compile($modal)(scope);
+ });
+
+ // Provide scope display functions
+ scope._modal = function(name) {
+ $modal.modal(name);
+ };
+ scope.hide = function() {
+ $modal.modal('hide');
+ };
+ scope.show = function() {
+ $modal.modal('show');
+ };
+ scope.dismiss = scope.hide;
+
+ });
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsNavbar', ['$location', function($location) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ link: function postLink($scope, element, attrs, controller) {
+ // Watch for the $location
+ $scope.$watch(function() {
+ return $location.path();
+ }, function(newValue, oldValue) {
+
+ element.find('li[data-match-route]').each(function(k, li) {
+ var $li = angular.element(li),
+ // data('match-rout') does not work with dynamic attributes
+ pattern = $li.attr('data-match-route'),
+ regexp = new RegExp('^' + pattern + '$', ["i"]);
+
+ if(regexp.test(newValue)) {
+ $li.addClass('active');
+ } else {
+ $li.removeClass('active');
+ }
+
+ });
+ });
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsPopover', ['$parse', '$compile', '$http', '$timeout', '$q', '$templateCache', function($parse, $compile, $http, $timeout, $q, $templateCache) {
+ 'use strict';
+
+ // Hide popovers when pressing esc
+ $("body").on("keyup", function(ev) {
+ if(ev.keyCode === 27) {
+ $(".popover.in").each(function() {
+ $(this).popover('hide');
+ });
+ }
+ });
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attr, ctrl) {
+
+ var getter = $parse(attr.bsPopover),
+ setter = getter.assign,
+ value = getter(scope),
+ options = {};
+
+ if(angular.isObject(value)) {
+ options = value;
+ }
+
+ $q.when(options.content || $templateCache.get(value) || $http.get(value, {cache: true})).then(function onSuccess(template) {
+
+ // Handle response from $http promise
+ if(angular.isObject(template)) {
+ template = template.data;
+ }
+
+ // Handle data-unique attribute
+ if(!!attr.unique) {
+ element.on('show', function(ev) { // requires bootstrap 2.3.0+
+ // Hide any active popover except self
+ $(".popover.in").each(function() {
+ var $this = $(this),
+ popover = $this.data('popover');
+ if(popover && !popover.$element.is(element)) {
+ $this.popover('hide');
+ }
+ });
+ });
+ }
+
+ // Handle data-hide attribute to toggle visibility
+ if(!!attr.hide) {
+ scope.$watch(attr.hide, function(newValue, oldValue) {
+ if(!!newValue) {
+ popover.hide();
+ } else if(newValue !== oldValue) {
+ popover.show();
+ }
+ });
+ }
+
+ // Initialize popover
+ element.popover(angular.extend({}, options, {
+ content: template,
+ html: true
+ }));
+
+ // Bootstrap override to provide tip() reference & compilation
+ var popover = element.data('popover');
+ popover.hasContent = function() {
+ return this.getTitle() || template; // fix multiple $compile()
+ };
+ popover.getPosition = function() {
+ var r = $.fn.popover.Constructor.prototype.getPosition.apply(this, arguments);
+
+ // Compile content
+ $compile(this.$tip)(scope);
+ scope.$digest();
+
+ // Bind popover to the tip()
+ this.$tip.data('popover', this);
+
+ return r;
+ };
+
+ // Provide scope display functions
+ scope._popover = function(name) {
+ element.popover(name);
+ };
+ scope.hide = function() {
+ element.popover('hide');
+ };
+ scope.show = function() {
+ element.popover('show');
+ };
+ scope.dismiss = scope.hide;
+
+ });
+
+ }
+ };
+
+}]);
+
+// https://github.com/jdewit/bootstrap-timepicker
+// https://github.com/kla/bootstrap-timepicker
+
+angular.module('$strap.directives')
+
+.directive('bsTimepicker', ['$timeout', function($timeout) {
+ 'use strict';
+
+ var TIME_REGEXP = '((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ element.on('change', function(ev) {
+ scope.$apply(function () {
+ controller.$setViewValue(element.val());
+ });
+ });
+ }
+
+ // Handle input time validity
+ var timeRegExp = new RegExp('^' + TIME_REGEXP + '$', ['i']);
+ controller.$parsers.unshift(function(viewValue) {
+ //console.warn('viewValue', viewValue, timeRegExp, timeRegExp.test(viewValue));
+ if (!viewValue || timeRegExp.test(viewValue)) {
+ controller.$setValidity('time', true);
+ return viewValue;
+ } else {
+ controller.$setValidity('time', false);
+ return undefined;
+ }
+ });
+
+ // Support add-on
+ // var component = element.siblings('[data-toggle="timepicker"]');
+ // if(component.length) {
+ // component.on('click', function() {
+ // var $widget = element.data('timepicker').$widget;
+ // });
+ // }
+
+ // Popover GarbageCollection
+ var $popover = element.closest('.popover');
+ if($popover) {
+ $popover.on('hide', function(e) {
+ var timepicker = element.data('timepicker');
+ if(timepicker) {
+ timepicker.$widget.remove();
+ element.data('timepicker', null);
+ }
+ });
+ }
+
+ // Create datepicker
+ element.attr('data-toggle', 'timepicker');
+ //$timeout(function () {
+ element.timepicker();
+ //});
+
+ }
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsTooltip', ['$parse', '$compile', function($parse, $compile) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attrs, ctrl) {
+
+ var getter = $parse(attrs.bsTooltip),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // Watch bsTooltip for changes
+ scope.$watch(attrs.bsTooltip, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ value = newValue;
+ }
+ });
+
+ if(!!attrs.unique) {
+ element.on('show', function(ev) {
+ // Hide any active popover except self
+ $(".tooltip.in").each(function() {
+ var $this = $(this),
+ tooltip = $this.data('tooltip');
+ if(tooltip && !tooltip.$element.is(element)) {
+ $this.tooltip('hide');
+ }
+ });
+ });
+ }
+
+ // Initialize tooltip
+ element.tooltip({
+ title: function() { return angular.isFunction(value) ? value.apply(null, arguments) : value; },
+ html: true
+ });
+
+ // Bootstrap override to provide events & tip() reference
+ var tooltip = element.data('tooltip');
+ tooltip.show = function() {
+ var e = $.Event('show');
+ this.$element.trigger(e);
+ if (e.isDefaultPrevented()) {
+ return;
+ }
+ var r = $.fn.tooltip.Constructor.prototype.show.apply(this, arguments);
+ // Bind popover to the tip()
+ this.tip().data('tooltip', this);
+ return r;
+ };
+ tooltip.hide = function() {
+ var e = $.Event('hide');
+ this.$element.trigger(e);
+ if (e.isDefaultPrevented()) {
+ return;
+ }
+ return $.fn.tooltip.Constructor.prototype.hide.apply(this, arguments);
+ };
+
+ //Provide scope display functions
+ scope._tooltip = function(event) {
+ element.tooltip(event);
+ };
+ scope.hide = function() {
+ element.tooltip('hide');
+ };
+ scope.show = function() {
+ element.tooltip('show');
+ };
+ scope.dismiss = scope.hide;
+
+ }
+ };
+
+}]);
+
+angular.module('$strap.directives')
+
+.directive('bsTypeahead', ['$parse', function($parse) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ var getter = $parse(attrs.bsTypeahead),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // Watch bsTypeahead for changes
+ scope.$watch(attrs.bsTypeahead, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ value = newValue;
+ }
+ });
+
+ element.attr('data-provide', 'typeahead');
+ element.typeahead({
+ source: function(query) { return angular.isFunction(value) ? value.apply(null, arguments) : value; },
+ minLength: attrs.minLength || 1,
+ items: attrs.items,
+ updater: function(value) {
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ scope.$apply(function () {
+ controller.$setViewValue(value);
+ });
+ }
+ return value;
+ }
+ });
+
+ // Bootstrap override
+ var typeahead = element.data('typeahead');
+ // Fixes #2043: allows minLength of zero to enable show all for typeahead
+ typeahead.lookup = function (ev) {
+ var items;
+ this.query = this.$element.val() || '';
+ if (this.query.length < this.options.minLength) {
+ return this.shown ? this.hide() : this;
+ }
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source;
+ return items ? this.process(items) : this;
+ };
+
+ // Support 0-minLength
+ if(attrs.minLength === "0") {
+ setTimeout(function() { // Push to the event loop to make sure element.typeahead is defined (breaks tests otherwise)
+ element.on('focus', function() {
+ setTimeout(element.typeahead.bind(element, 'lookup'), 200);
+ });
+ });
+ }
+
+ }
+ };
+
+}]);
View
1,106 ajax/libs/angular-strap/0.7.1/angular-strap.js
@@ -0,0 +1,1106 @@
+/**
+ * AngularStrap - Twitter Bootstrap directives for AngularJS
+ * @version v0.7.1 - 2013-03-21
+ * @link http://mgcrea.github.com/angular-strap
+ * @author Olivier Louvignes <olivier@mg-crea.com>
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
+
+angular.module('$strap.config', []).value('$strap.config', {});
+angular.module('$strap.filters', ['$strap.config']);
+angular.module('$strap.directives', ['$strap.config']);
+angular.module('$strap', ['$strap.filters', '$strap.directives', '$strap.config']);
+
+
+angular.module('$strap.directives')
+
+.directive('bsAlert', ['$parse', '$timeout', '$compile', function($parse, $timeout, $compile) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ link: function postLink(scope, element, attrs) {
+
+ var getter = $parse(attrs.bsAlert),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // For static alerts
+ if(!attrs.bsAlert) {
+
+ // Setup close button
+ if(angular.isUndefined(attrs.closeButton) || (attrs.closeButton !== '0' && attrs.closeButton !== 'false')) {
+ element.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>');
+ }
+
+ } else {
+
+ scope.$watch(attrs.bsAlert, function(newValue, oldValue) {
+ value = newValue;
+
+ // Set alert content
+ element.html((newValue.title ? '<strong>' + newValue.title + '</strong>&nbsp;' : '') + newValue.content || '');
+
+ if(!!newValue.closed) {
+ element.hide();
+ }
+
+ // Compile alert content
+ //$timeout(function(){
+ $compile(element.contents())(scope);
+ //});
+
+ // Add proper class
+ if(newValue.type || oldValue.type) {
+ oldValue.type && element.removeClass('alert-' + oldValue.type);
+ newValue.type && element.addClass('alert-' + newValue.type);
+ }
+
+ // Setup close button
+ if(angular.isUndefined(attrs.closeButton) || (attrs.closeButton !== '0' && attrs.closeButton !== 'false')) {
+ element.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>');
+ }
+
+ }, true);
+
+ }
+
+ element.addClass('alert').alert();
+
+ // Support fade-in effect
+ if(element.hasClass('fade')) {
+ element.removeClass('in');
+ setTimeout(function() {
+ element.addClass('in');
+ });
+ }
+
+ var parentArray = attrs.ngRepeat && attrs.ngRepeat.split(' in ').pop();
+
+ element.on('close', function(ev) {
+ var removeElement;
+
+ if(parentArray) { // ngRepeat, remove from parent array
+ ev.preventDefault();
+
+ element.removeClass('in');
+
+ removeElement = function() {
+ element.trigger('closed');
+ if(scope.$parent) {
+ scope.$parent.$apply(function() {
+ var path = parentArray.split('.');
+ var curr = scope.$parent;
+
+ for (var i = 0; i < path.length; ++i) {
+ if (curr) {
+ curr = curr[path[i]];
+ }
+ }
+
+ if (curr) {
+ curr.splice(scope.$index, 1);
+ }
+ });
+ }
+ };
+
+ $.support.transition && element.hasClass('fade') ?
+ element.on($.support.transition.end, removeElement) :
+ removeElement();
+
+ } else if(value) { // object, set closed property to 'true'
+ ev.preventDefault();
+
+ element.removeClass('in');
+
+ removeElement = function() {
+ element.trigger('closed');
+ scope.$apply(function() {
+ value.closed = true;
+ });
+ };
+
+ $.support.transition && element.hasClass('fade') ?
+ element.on($.support.transition.end, removeElement) :
+ removeElement();
+
+ } else { // static, regular behavior
+ }
+
+ });
+
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsButton', ['$parse', '$timeout', function($parse, $timeout) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+
+ // Set as single toggler if not part of a btn-group
+ if(!element.parent('[data-toggle="buttons-checkbox"], [data-toggle="buttons-radio"]').length) {
+ element.attr('data-toggle', 'button');
+ }
+
+ // Handle start state
+ var startValue = !!scope.$eval(attrs.ngModel);
+ if(startValue) {
+ element.addClass('active');
+ }
+
+ // Watch model for changes
+ scope.$watch(attrs.ngModel, function(newValue, oldValue) {
+ var bNew = !!newValue, bOld = !!oldValue;
+ if(bNew !== bOld) {
+ $.fn.button.Constructor.prototype.toggle.call(button);
+ // Handle $q promises
+ } else if(bNew && !startValue) {
+ element.addClass('active');
+ }
+ });
+
+ }
+
+ // Support buttons without .btn class
+ if(!element.hasClass('btn')) {
+ element.on('click.button.data-api', function (e) {
+ element.button('toggle');
+ });
+ }
+
+ // Initialize button
+ element.button();
+
+ // Bootstrap override to handle toggling
+ var button = element.data('button');
+ button.toggle = function() {
+
+ if(!controller) {
+ return $.fn.button.Constructor.prototype.toggle.call(this);
+ }
+
+ var $parent = element.parent('[data-toggle="buttons-radio"]');
+
+ if($parent.length) {
+ element.siblings('[ng-model]').each(function(k, v) {
+ $parse($(v).attr('ng-model')).assign(scope, false);
+ });
+ scope.$digest();
+ if(!controller.$modelValue) {
+ controller.$setViewValue(!controller.$modelValue);
+ scope.$digest();
+ }
+ } else {
+ scope.$apply(function () {
+ controller.$setViewValue(!controller.$modelValue);
+ });
+ }
+
+ };
+
+ /*Provide scope display functions
+ scope._button = function(event) {
+ element.button(event);
+ };
+ scope.loading = function() {
+ element.tooltip('loading');
+ };
+ scope.reset = function() {
+ element.tooltip('reset');
+ };
+
+ if(attrs.loadingText) element.click(function () {
+ //var btn = $(this)
+ element.button('loading')
+ setTimeout(function () {
+ element.button('reset')
+ }, 1000)
+ });*/
+
+ }
+ };
+
+}])
+
+.directive('bsButtonsCheckbox', ['$parse', function($parse) {
+ 'use strict';
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ compile: function compile(tElement, tAttrs, transclude) {
+ tElement.attr('data-toggle', 'buttons-checkbox').find('a, button').each(function(k, v) {
+ $(v).attr('bs-button', '');
+ });
+ }
+ };
+
+}])
+
+.directive('bsButtonsRadio', ['$parse', function($parse) {
+ 'use strict';
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ compile: function compile(tElement, tAttrs, transclude) {
+
+ tElement.attr('data-toggle', 'buttons-radio');
+
+ // Delegate to children ngModel
+ if(!tAttrs.ngModel) {
+ tElement.find('a, button').each(function(k, v) {
+ $(v).attr('bs-button', '');
+ });
+ }
+
+ return function postLink(scope, iElement, iAttrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+
+ iElement
+ .find('[value]').button()
+ .filter('[value="' + scope.$eval(iAttrs.ngModel) + '"]')
+ .addClass('active');
+
+ iElement.on('click.button.data-api', function (ev) {
+ scope.$apply(function () {
+ controller.$setViewValue($(ev.target).closest('button').attr('value'));
+ });
+ });
+
+ // Watch model for changes
+ scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ var $btn = iElement.find('[value="' + scope.$eval(iAttrs.ngModel) + '"]');
+ if($btn.length) {
+ $.fn.button.Constructor.prototype.toggle.call($btn.data('button'));
+ }
+ }
+ });
+
+ }
+
+ };
+ }
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsButtonSelect', ['$parse', '$timeout', function($parse, $timeout) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, ctrl) {
+
+ var getter = $parse(attrs.bsButtonSelect),
+ setter = getter.assign;
+
+ // Bind ngModelController
+ if(ctrl) {
+ element.text(scope.$eval(attrs.ngModel));
+ // Watch model for changes
+ scope.$watch(attrs.ngModel, function(newValue, oldValue) {
+ element.text(newValue);
+ });
+ }
+
+ // Click handling
+ var values, value, index, newValue;
+ element.bind('click', function(ev) {
+ values = getter(scope);
+ value = ctrl ? scope.$eval(attrs.ngModel) : element.text();
+ index = values.indexOf(value);
+ newValue = index > values.length - 2 ? values[0] : values[index + 1];
+ console.warn(values, newValue);
+
+ scope.$apply(function() {
+ element.text(newValue);
+ if(ctrl) {
+ ctrl.$setViewValue(newValue);
+ }
+ });
+ });
+ }
+ };
+
+}]);
+
+// https://github.com/eternicode/bootstrap-datepicker
+
+angular.module('$strap.directives')
+
+.directive('bsDatepicker', ['$timeout', '$strap.config', function($timeout, config) {
+ 'use strict';
+
+ var isTouch = 'ontouchstart' in window && !window.navigator.userAgent.match(/PhantomJS/i);
+
+ var regexpMap = function regexpMap(language) {
+ language = language || 'en';
+ return {
+ '/' : '[\\/]',
+ '-' : '[-]',
+ '.' : '[.]',
+ ' ' : '[\\s]',
+ 'dd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ 'd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ 'mm' : '(?:[0]?[1-9]|[1][012])',
+ 'm' : '(?:[0]?[1-9]|[1][012])',
+ 'DD' : '(?:' + $.fn.datepicker.dates[language].days.join('|') + ')',
+ 'D' : '(?:' + $.fn.datepicker.dates[language].daysShort.join('|') + ')',
+ 'MM' : '(?:' + $.fn.datepicker.dates[language].months.join('|') + ')',
+ 'M' : '(?:' + $.fn.datepicker.dates[language].monthsShort.join('|') + ')',
+ 'yyyy' : '(?:(?:[1]{1}[0-9]{1}[0-9]{1}[0-9]{1})|(?:[2]{1}[0-9]{3}))(?![[0-9]])',
+ 'yy' : '(?:(?:[0-9]{1}[0-9]{1}))(?![[0-9]])'
+ };
+ };
+
+ var regexpForDateFormat = function regexpForDateFormat(format, language) {
+ var re = format, map = regexpMap(language), i;
+ // Abstract replaces to avoid collisions
+ i = 0; angular.forEach(map, function(v, k) {
+ re = re.split(k).join('${' + i + '}'); i++;
+ });
+ // Replace abstracted values
+ i = 0; angular.forEach(map, function(v, k) {
+ re = re.split('${' + i + '}').join(v); i++;
+ });
+ return new RegExp('^' + re + '$', ['i']);
+ };
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ var options = config.datepicker || {},
+ language = attrs.language || options.language || 'en',
+ format = attrs.dateFormat || options.format || ($.fn.datepicker.dates[language] && $.fn.datepicker.dates[language].format) || 'mm/dd/yyyy';
+
+ var dateFormatRegexp = isTouch ? 'yyyy/mm/dd' : regexpForDateFormat(format, language);
+
+ // Handle date validity according to dateFormat
+ if(controller) {
+ controller.$parsers.unshift(function(viewValue) {
+ //console.warn('viewValue', viewValue, dateFormatRegexp, dateFormatRegexp.test(viewValue));
+ if (!viewValue || dateFormatRegexp.test(viewValue)) {
+ controller.$setValidity('date', true);
+ return viewValue;
+ } else {
+ controller.$setValidity('date', false);
+ return undefined;
+ }
+ });
+ }
+
+ // Use native interface for touch devices
+ if(isTouch && element.prop('type') === 'text') {
+
+ element.prop('type', 'date');
+ element.on('change', function(ev) {
+ scope.$apply(function () {
+ controller.$setViewValue(element.val());
+ });
+ });
+
+ } else {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ element.on('changeDate', function(ev) {
+ scope.$apply(function () {
+ controller.$setViewValue(element.val());
+ });
+ });
+ }
+
+ // Popover GarbageCollection
+ var $popover = element.closest('.popover');
+ if($popover) {
+ $popover.on('hide', function(e) {
+ var datepicker = element.data('datepicker');
+ if(datepicker) {
+ datepicker.picker.remove();
+ element.data('datepicker', null);
+ }
+ });
+ }
+
+ // Create datepicker
+ element.attr('data-toggle', 'datepicker');
+ element.datepicker({
+ autoclose: true,
+ format: format,
+ language: language,
+ forceParse: attrs.forceParse || false
+ });
+
+ }
+
+ // Support add-on
+ var component = element.siblings('[data-toggle="datepicker"]');
+ if(component.length) {
+ component.on('click', function() { element.trigger('focus'); });
+ }
+
+ }
+
+ };
+
+}]);
+
+// https://github.com/eternicode/bootstrap-datepicker
+
+angular.module('$strap.directives')
+
+.directive('bsDaterangepicker', ['$timeout', function($timeout) {
+ 'use strict';
+
+ var isTouch = 'ontouchstart' in window && !window.navigator.userAgent.match(/PhantomJS/i);
+
+ // var DATE_REGEXP_MAP = {
+ // '/' : '[\\/]',
+ // '-' : '[-]',
+ // '.' : '[.]',
+ // 'dd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ // 'd' : '(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))',
+ // 'mm' : '(?:[0]?[1-9]|[1][012])',
+ // 'm' : '(?:[0]?[1-9]|[1][012])',
+ // 'yyyy' : '(?:(?:[1]{1}[0-9]{1}[0-9]{1}[0-9]{1})|(?:[2]{1}[0-9]{3}))(?![[0-9]])',
+ // 'yy' : '(?:(?:[0-9]{1}[0-9]{1}))(?![[0-9]])'
+ // };
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+ console.log('postLink', this, arguments); window.element = element;
+
+ // var regexpForDateFormat = function(dateFormat, options) {
+ // options || (options = {});
+ // var re = dateFormat, regexpMap = DATE_REGEXP_MAP;
+ // /*if(options.mask) {
+ // regexpMap['/'] = '';
+ // regexpMap['-'] = '';
+ // }*/
+ // angular.forEach(regexpMap, function(v, k) { re = re.split(k).join(v); });
+ // return new RegExp('^' + re + '$', ['i']);
+ // };
+
+ // var dateFormatRegexp = isTouch ? 'yyyy/mm/dd' : regexpForDateFormat(attrs.dateFormat || 'mm/dd/yyyy'/*, {mask: !!attrs.uiMask}*/);
+
+ // // Handle date validity according to dateFormat
+ // if(controller) {
+ // controller.$parsers.unshift(function(viewValue) {
+ // //console.warn('viewValue', viewValue, dateFormatRegexp, dateFormatRegexp.test(viewValue));
+ // if (!viewValue || dateFormatRegexp.test(viewValue)) {
+ // controller.$setValidity('date', true);
+ // return viewValue;
+ // } else {
+ // controller.$setValidity('date', false);
+ // return undefined;
+ // }
+ // });
+ // }
+
+ // // Support add-on
+ // var component = element.next('[data-toggle="datepicker"]');
+ // if(component.length) {
+ // component.on('click', function() { isTouch ? element.trigger('focus') : element.datepicker('show'); });
+ // }
+
+ // // Use native interface for touch devices
+ // if(isTouch && element.prop('type') === 'text') {
+
+ // element.prop('type', 'date');
+ // element.on('change', function(ev) {
+ // scope.$apply(function () {
+ // controller.$setViewValue(element.val());
+ // });
+ // });
+
+ // } else {
+
+ // // If we have a controller (i.e. ngModelController) then wire it up
+ // if(controller) {
+ // element.on('changeDate', function(ev) {
+ // scope.$apply(function () {
+ // controller.$setViewValue(element.val());
+ // });
+ // });
+ // }
+
+ // // Popover GarbageCollection
+ // var $popover = element.closest('.popover');
+ // if($popover) {
+ // $popover.on('hide', function(e) {
+ // var datepicker = element.data('datepicker');
+ // if(datepicker) {
+ // datepicker.picker.remove();
+ // element.data('datepicker', null);
+ // }
+ // });
+ // }
+
+ // Create daterangepicker
+ element.attr('data-toggle', 'daterangepicker');
+ element.daterangepicker({
+ // autoclose: true,
+ // forceParse: attrs.forceParse || false,
+ // language: attrs.language || 'en'
+ });
+
+ // }
+
+ }
+
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsDropdown', ['$parse', '$compile', '$timeout', function($parse, $compile, $timeout) {
+ 'use strict';
+
+ var buildTemplate = function(items, ul) {
+ if(!ul) ul = ['<ul class="dropdown-menu" role="menu" aria-labelledby="drop1">', '</ul>'];
+ angular.forEach(items, function(item, index) {
+ if(item.divider) return ul.splice(index + 1, 0, '<li class="divider"></li>');
+ var li = '<li' + (item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') + '>' +
+ '<a tabindex="-1" ng-href="' + (item.href || '') + '"' + (item.click ? '" ng-click="' + item.click + '"' : '') + (item.target ? '" target="' + item.target + '"' : '') + '>' +
+ (item.text || '') + '</a>';
+ if(item.submenu && item.submenu.length) li += buildTemplate(item.submenu).join("\n");
+ li += '</li>';
+ ul.splice(index + 1, 0, li);
+ });
+ return ul;
+ };
+
+ return {
+ restrict: 'EA',
+ scope: true,
+ link: function postLink(scope, iElement, iAttrs) {
+
+ var getter = $parse(iAttrs.bsDropdown),
+ items = getter(scope);
+
+ // Defer after any ngRepeat rendering
+ $timeout(function() {
+
+ if(!angular.isArray(items)) {
+ // @todo?
+ }
+
+ var dropdown = angular.element(buildTemplate(items).join(''));
+ dropdown.insertAfter(iElement);
+
+ // Compile dropdown-menu
+ $compile(iElement.next('ul.dropdown-menu'))(scope);
+
+ });
+
+ iElement
+ .addClass('dropdown-toggle')
+ .attr('data-toggle', "dropdown");
+
+ }
+ };
+
+}]);
+
+angular.module('$strap.directives')
+
+.directive('bsModal', ['$parse', '$compile', '$http', '$timeout', '$q', '$templateCache', function($parse, $compile, $http, $timeout, $q, $templateCache) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attr, ctrl) {
+
+ var getter = $parse(attr.bsModal),
+ setter = getter.assign,
+ value = getter(scope);
+
+ $q.when($templateCache.get(value) || $http.get(value, {cache: true})).then(function onSuccess(template) {
+
+ // Handle response from $http promise
+ if(angular.isObject(template)) {
+ template = template.data;
+ }
+
+ // Build modal object
+ var id = getter(scope).replace('.html', '').replace(/[\/|\.|:]/g, "-") + '-' + scope.$id;
+ var $modal = $('<div class="modal hide" tabindex="-1"></div>')
+ .attr('id', id)
+ .attr('data-backdrop', attr.backdrop || true)
+ .attr('data-keyboard', attr.keyboard || true)
+ .addClass(attr.modalClass ? 'fade ' + attr.modalClass : 'fade')
+ .html(template);
+
+ $('body').append($modal);
+
+ // Configure element
+ element.attr('href', '#' + id).attr('data-toggle', 'modal');
+
+ // Compile modal content
+ $timeout(function(){
+ $compile($modal)(scope);
+ });
+
+ // Provide scope display functions
+ scope._modal = function(name) {
+ $modal.modal(name);
+ };
+ scope.hide = function() {
+ $modal.modal('hide');
+ };
+ scope.show = function() {
+ $modal.modal('show');
+ };
+ scope.dismiss = scope.hide;
+
+ $modal.on("show", function(event) {
+ scope.$emit("modal-show", event);
+ });
+
+ $modal.on("shown", function(event) {
+ scope.$emit("modal-shown", event);
+ });
+
+ $modal.on("hide", function(event) {
+ scope.$emit("modal-hide", event);
+ });
+
+ $modal.on("hidden", function(event) {
+ scope.$emit("modal-hidden", event);
+ });
+
+ });
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsNavbar', ['$location', function($location) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ link: function postLink($scope, element, attrs, controller) {
+ // Watch for the $location
+ $scope.$watch(function() {
+ return $location.path();
+ }, function(newValue, oldValue) {
+
+ element.find('li[data-match-route]').each(function(k, li) {
+ var $li = angular.element(li),
+ // data('match-rout') does not work with dynamic attributes
+ pattern = $li.attr('data-match-route'),
+ regexp = new RegExp('^' + pattern + '$', ["i"]);
+
+ if(regexp.test(newValue)) {
+ $li.addClass('active');
+ } else {
+ $li.removeClass('active');
+ }
+
+ });
+ });
+ }
+ };
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsPopover', ['$parse', '$compile', '$http', '$timeout', '$q', '$templateCache', function($parse, $compile, $http, $timeout, $q, $templateCache) {
+ 'use strict';
+
+ // Hide popovers when pressing esc
+ $("body").on("keyup", function(ev) {
+ if(ev.keyCode === 27) {
+ $(".popover.in").each(function() {
+ $(this).popover('hide');
+ });
+ }
+ });
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attr, ctrl) {
+
+ var getter = $parse(attr.bsPopover),
+ setter = getter.assign,
+ value = getter(scope),
+ options = {};
+
+ if(angular.isObject(value)) {
+ options = value;
+ }
+
+ $q.when(options.content || $templateCache.get(value) || $http.get(value, {cache: true})).then(function onSuccess(template) {
+
+ // Handle response from $http promise
+ if(angular.isObject(template)) {
+ template = template.data;
+ }
+
+ // Handle data-unique attribute
+ if(!!attr.unique) {
+ element.on('show', function(ev) { // requires bootstrap 2.3.0+
+ // Hide any active popover except self
+ $(".popover.in").each(function() {
+ var $this = $(this),
+ popover = $this.data('popover');
+ if(popover && !popover.$element.is(element)) {
+ $this.popover('hide');
+ }
+ });
+ });
+ }
+
+ // Handle data-hide attribute to toggle visibility
+ if(!!attr.hide) {
+ scope.$watch(attr.hide, function(newValue, oldValue) {
+ if(!!newValue) {
+ popover.hide();
+ } else if(newValue !== oldValue) {
+ popover.show();
+ }
+ });
+ }
+
+ // Initialize popover
+ element.popover(angular.extend({}, options, {
+ content: template,
+ html: true
+ }));
+
+ // Bootstrap override to provide tip() reference & compilation
+ var popover = element.data('popover');
+ popover.hasContent = function() {
+ return this.getTitle() || template; // fix multiple $compile()
+ };
+ popover.getPosition = function() {
+ var r = $.fn.popover.Constructor.prototype.getPosition.apply(this, arguments);
+
+ // Compile content
+ $compile(this.$tip)(scope);
+ scope.$digest();
+
+ // Bind popover to the tip()
+ this.$tip.data('popover', this);
+
+ return r;
+ };
+
+ // Provide scope display functions
+ scope._popover = function(name) {
+ element.popover(name);
+ };
+ scope.hide = function() {
+ element.popover('hide');
+ };
+ scope.show = function() {
+ element.popover('show');
+ };
+ scope.dismiss = scope.hide;
+
+ });
+
+ }
+ };
+
+}]);
+
+angular.module('$strap.directives')
+
+.directive('bsTabs', ['$parse', '$compile', '$timeout', function($parse, $compile, $timeout) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ scope: true,
+ link: function postLink(scope, iElement, iAttrs, controller) {
+
+ var getter = $parse(iAttrs.bsTabs),
+ setter = getter.assign,
+ value = getter(scope);
+
+ var tabs = ['<ul class="nav nav-tabs">', '</ul>'];
+ var panes = ['<div class="tab-content">', '</div>'];
+
+ iElement.hide();
+ var activeTab = 0;
+
+ // Defer after any ngRepeat rendering
+ $timeout(function() {
+
+ if(!angular.isArray(value)) {
+
+ value = [];
+ // Convert existing dom elements
+ iElement.children('[data-title], [data-tab]').each(function(index) {
+ var $this = angular.element(this);
+ value.push({
+ title: scope.$eval($this.data('title') || $this.data('tab')),
+ content: this.innerHTML,
+ active: $this.hasClass('active'),
+ fade: $this.hasClass('fade')
+ });
+ });
+
+ }
+
+ // Select correct starting activeTab
+ angular.forEach(value, function(tab, index) {
+ if(tab.active) {
+ activeTab = index;
+ }
+ });
+
+ // Build from object
+ angular.forEach(value, function(tab, index) {
+ var id = 'tab-' + scope.$id + '-' + index,
+ active = activeTab === index,
+ fade = iAttrs.fade || tab.fade;
+ tabs.splice(index + 1, 0, '<li' + (active ? ' class="active"' : '') + '><a href="#' + id + '" data-index="' + index + '" data-toggle="tab">' + tab.title + '</a></li>');
+ panes.splice(index + 1, 0, '<div class="tab-pane' + (active ? ' active' : '') + (fade ? ' fade' : '') + (fade && active ? ' in' : '') + '" id="' + id + '">' + tab.content + '</div>');
+ });
+
+ iElement.html(tabs.join('') + panes.join('')).show();
+
+ // Compile tab-content
+ $compile(iElement.children('div.tab-content'))(scope);
+
+ });
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+
+ iElement.on('show', function(ev) {
+ var $target = $(ev.target);
+ scope.$apply(function() {
+ controller.$setViewValue($target.data('index'));
+ });
+ });
+
+ // Watch ngModel for changes
+ scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
+ if(angular.isUndefined(newValue)) { return; }
+ activeTab = newValue; // update starting activeTab before first build
+ setTimeout(function() {
+ var $next = iElement.children('ul.nav-tabs').find('li:eq(' + newValue*1 + ')');
+ if(!$next.hasClass('active')) {
+ $next.children('a').tab('show');
+ }
+ });
+ });
+
+ }
+
+ }
+
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsTimepicker', ['$timeout', function($timeout) {
+ 'use strict';
+
+ var TIME_REGEXP = '((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ element.on('changeTime.timepicker', function(ev) {
+ $timeout(function() {
+ controller.$setViewValue(element.val());
+ });
+ });
+ }
+
+ // Handle input time validity
+ var timeRegExp = new RegExp('^' + TIME_REGEXP + '$', ['i']);
+ controller.$parsers.unshift(function(viewValue) {
+ // console.warn('viewValue', viewValue, timeRegExp, timeRegExp.test(viewValue));
+ if (!viewValue || timeRegExp.test(viewValue)) {
+ controller.$setValidity('time', true);
+ return viewValue;
+ } else {
+ controller.$setValidity('time', false);
+ return;
+ }
+ });
+
+ // Create datepicker
+ element.attr('data-toggle', 'timepicker');
+ element.parent().addClass('bootstrap-timepicker');
+ //$timeout(function () {
+ element.timepicker();
+ //});
+
+ }
+ };
+
+}]);
+
+
+angular.module('$strap.directives')
+
+.directive('bsTooltip', ['$parse', '$compile', function($parse, $compile) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ scope: true,
+ link: function postLink(scope, element, attrs, ctrl) {
+
+ var getter = $parse(attrs.bsTooltip),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // Watch bsTooltip for changes
+ scope.$watch(attrs.bsTooltip, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ value = newValue;
+ }
+ });
+
+ if(!!attrs.unique) {
+ element.on('show', function(ev) {
+ // Hide any active popover except self
+ $(".tooltip.in").each(function() {
+ var $this = $(this),
+ tooltip = $this.data('tooltip');
+ if(tooltip && !tooltip.$element.is(element)) {
+ $this.tooltip('hide');
+ }
+ });
+ });
+ }
+
+ // Initialize tooltip
+ element.tooltip({
+ title: function() { return angular.isFunction(value) ? value.apply(null, arguments) : value; },
+ html: true
+ });
+
+ // Bootstrap override to provide events & tip() reference
+ var tooltip = element.data('tooltip');
+ tooltip.show = function() {
+ var r = $.fn.tooltip.Constructor.prototype.show.apply(this, arguments);
+ // Bind tooltip to the tip()
+ this.tip().data('tooltip', this);
+ return r;
+ };
+
+ //Provide scope display functions
+ scope._tooltip = function(event) {
+ element.tooltip(event);
+ };
+ scope.hide = function() {
+ element.tooltip('hide');
+ };
+ scope.show = function() {
+ element.tooltip('show');
+ };
+ scope.dismiss = scope.hide;
+
+ }
+ };
+
+}]);
+
+angular.module('$strap.directives')
+
+.directive('bsTypeahead', ['$parse', function($parse) {
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function postLink(scope, element, attrs, controller) {
+
+ var getter = $parse(attrs.bsTypeahead),
+ setter = getter.assign,
+ value = getter(scope);
+
+ // Watch bsTypeahead for changes
+ scope.$watch(attrs.bsTypeahead, function(newValue, oldValue) {
+ if(newValue !== oldValue) {
+ value = newValue;
+ }
+ });
+
+ element.attr('data-provide', 'typeahead');
+ element.typeahead({
+ source: function(query) { return angular.isFunction(value) ? value.apply(null, arguments) : value; },
+ minLength: attrs.minLength || 1,
+ items: attrs.items,
+ updater: function(value) {
+ // If we have a controller (i.e. ngModelController) then wire it up
+ if(controller) {
+ scope.$apply(function () {
+ controller.$setViewValue(value);
+ });
+ }
+ return value;
+ }
+ });
+
+ // Bootstrap override
+ var typeahead = element.data('typeahead');
+ // Fixes #2043: allows minLength of zero to enable show all for typeahead
+ typeahead.lookup = function (ev) {
+ var items;
+ this.query = this.$element.val() || '';
+ if (this.query.length < this.options.minLength) {
+ return this.shown ? this.hide() : this;
+ }
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source;
+ return items ? this.process(items) : this;
+ };
+
+ // Support 0-minLength
+ if(attrs.minLength === "0") {
+ setTimeout(function() { // Push to the event loop to make sure element.typeahead is defined (breaks tests otherwise)
+ element.on('focus', function() {
+ element.val().length === 0 && setTimeout(element.typeahead.bind(element, 'lookup'), 200);
+ });
+ });
+ }
+
+ }
+ };
+
+}]);
View
8 ajax/libs/angular-strap/0.7.1/angular-strap.min.js
@@ -0,0 +1,8 @@
+/**
+ * AngularStrap - Twitter Bootstrap directives for AngularJS
+ * @version v0.7.1 - 2013-03-21
+ * @link http://mgcrea.github.com/angular-strap
+ * @author Olivier Louvignes <olivier@mg-crea.com>
+ * @license MIT License, http://www.opensource.org/licenses/MIT
+ */
+angular.module("$strap.config",[]).value("$strap.config",{}),angular.module("$strap.filters",["$strap.config"]),angular.module("$strap.directives",["$strap.config"]),angular.module("$strap",["$strap.filters","$strap.directives","$strap.config"]),angular.module("$strap.directives").directive("bsAlert",["$parse","$timeout","$compile",function(t,e,n){"use strict";return{restrict:"A",link:function(e,a,i){var o=t(i.bsAlert),r=(o.assign,o(e));i.bsAlert?e.$watch(i.bsAlert,function(t,o){r=t,a.html((t.title?"<strong>"+t.title+"</strong>&nbsp;":"")+t.content||""),t.closed&&a.hide(),n(a.contents())(e),(t.type||o.type)&&(o.type&&a.removeClass("alert-"+o.type),t.type&&a.addClass("alert-"+t.type)),(angular.isUndefined(i.closeButton)||"0"!==i.closeButton&&"false"!==i.closeButton)&&a.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>')},!0):(angular.isUndefined(i.closeButton)||"0"!==i.closeButton&&"false"!==i.closeButton)&&a.prepend('<button type="button" class="close" data-dismiss="alert">&times;</button>'),a.addClass("alert").alert(),a.hasClass("fade")&&(a.removeClass("in"),setTimeout(function(){a.addClass("in")}));var s=i.ngRepeat&&i.ngRepeat.split(" in ").pop();a.on("close",function(t){var n;s?(t.preventDefault(),a.removeClass("in"),n=function(){a.trigger("closed"),e.$parent&&e.$parent.$apply(function(){for(var t=s.split("."),n=e.$parent,a=0;t.length>a;++a)n&&(n=n[t[a]]);n&&n.splice(e.$index,1)})},$.support.transition&&a.hasClass("fade")?a.on($.support.transition.end,n):n()):r&&(t.preventDefault(),a.removeClass("in"),n=function(){a.trigger("closed"),e.$apply(function(){r.closed=!0})},$.support.transition&&a.hasClass("fade")?a.on($.support.transition.end,n):n())})}}}]),angular.module("$strap.directives").directive("bsButton",["$parse","$timeout",function(t){"use strict";return{restrict:"A",require:"?ngModel",link:function(e,n,a,i){if(i){n.parent('[data-toggle="buttons-checkbox"], [data-toggle="buttons-radio"]').length||n.attr("data-toggle","button");var o=!!e.$eval(a.ngModel);o&&n.addClass("active"),e.$watch(a.ngModel,function(t,e){var a=!!t,i=!!e;a!==i?$.fn.button.Constructor.prototype.toggle.call(r):a&&!o&&n.addClass("active")})}n.hasClass("btn")||n.on("click.button.data-api",function(){n.button("toggle")}),n.button();var r=n.data("button");r.toggle=function(){if(!i)return $.fn.button.Constructor.prototype.toggle.call(this);var a=n.parent('[data-toggle="buttons-radio"]');a.length?(n.siblings("[ng-model]").each(function(n,a){t($(a).attr("ng-model")).assign(e,!1)}),e.$digest(),i.$modelValue||(i.$setViewValue(!i.$modelValue),e.$digest())):e.$apply(function(){i.$setViewValue(!i.$modelValue)})}}}}]).directive("bsButtonsCheckbox",["$parse",function(){"use strict";return{restrict:"A",require:"?ngModel",compile:function(t){t.attr("data-toggle","buttons-checkbox").find("a, button").each(function(t,e){$(e).attr("bs-button","")})}}}]).directive("bsButtonsRadio",["$parse",function(){"use strict";return{restrict:"A",require:"?ngModel",compile:function(t,e){return t.attr("data-toggle","buttons-radio"),e.ngModel||t.find("a, button").each(function(t,e){$(e).attr("bs-button","")}),function(t,e,n,a){a&&(e.find("[value]").button().filter('[value="'+t.$eval(n.ngModel)+'"]').addClass("active"),e.on("click.button.data-api",function(e){t.$apply(function(){a.$setViewValue($(e.target).closest("button").attr("value"))})}),t.$watch(n.ngModel,function(a,i){if(a!==i){var o=e.find('[value="'+t.$eval(n.ngModel)+'"]');o.length&&$.fn.button.Constructor.prototype.toggle.call(o.data("button"))}}))}}}}]),angular.module("$strap.directives").directive("bsButtonSelect",["$parse","$timeout",function(t){"use strict";return{restrict:"A",require:"?ngModel",link:function(e,n,a,i){var o=t(a.bsButtonSelect);o.assign,i&&(n.text(e.$eval(a.ngModel)),e.$watch(a.ngModel,function(t){n.text(t)}));var r,s,u,c;n.bind("click",function(){r=o(e),s=i?e.$eval(a.ngModel):n.text(),u=r.indexOf(s),c=u>r.length-2?r[0]:r[u+1],console.warn(r,c),e.$apply(function(){n.text(c),i&&i.$setViewValue(c)})})}}}]),angular.module("$strap.directives").directive("bsDatepicker",["$timeout","$strap.config",function(t,e){"use strict";var n="ontouchstart"in window&&!window.navigator.userAgent.match(/PhantomJS/i),a=function a(t){return t=t||"en",{"/":"[\\/]","-":"[-]",".":"[.]"," ":"[\\s]",dd:"(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))",d:"(?:(?:[0-2]?[0-9]{1})|(?:[3][01]{1}))",mm:"(?:[0]?[1-9]|[1][012])",m:"(?:[0]?[1-9]|[1][012])",DD:"(?:"+$.fn.datepicker.dates[t].days.join("|")+")",D:"(?:"+$.fn.datepicker.dates[t].daysShort.join("|")+")",MM:"(?:"+$.fn.datepicker.dates[t].months.join("|")+")",M:"(?:"+$.fn.datepicker.dates[t].monthsShort.join("|")+")",yyyy:"(?:(?:[1]{1}[0-9]{1}[0-9]{1}[0-9]{1})|(?:[2]{1}[0-9]{3}))(?![[0-9]])",yy:"(?:(?:[0-9]{1}[0-9]{1}))(?![[0-9]])"}},i=function i(t,e){var n,i=t,o=a(e);return n=0,angular.forEach(o,function(t,e){i=i.split(e).join("${"+n+"}"),n++}),n=0,angular.forEach(o,function(t){i=i.split("${"+n+"}").join(t),n++}),RegExp("^"+i+"$",["i"])};return{restrict:"A",require:"?ngModel",link:function(t,a,o,r){var s=e.datepicker||{},u=o.language||s.language||"en",c=o.dateFormat||s.format||$.fn.datepicker.dates[u]&&$.fn.datepicker.dates[u].format||"mm/dd/yyyy",l=n?"yyyy/mm/dd":i(c,u);if(r&&r.$parsers.unshift(function(t){return!t||l.test(t)?(r.$setValidity("date",!0),t):(r.$setValidity("date",!1),void 0)}),n&&"text"===a.prop("type"))a.prop("type","date"),a.on("change",function(){t.$apply(function(){r.$setViewValue(a.val())})});else{r&&a.on("changeDate",function(){t.$apply(function(){r.$setViewValue(a.val())})});var d=a.closest(".popover");d&&d.on("hide",function(){var t=a.data("datepicker");t&&(t.picker.remove(),a.data("datepicker",null))}),a.attr("data-toggle","datepicker"),a.datepicker({autoclose:!0,format:c,language:u,forceParse:o.forceParse||!1})}var p=a.siblings('[data-toggle="datepicker"]');p.length&&p.on("click",function(){a.trigger("focus")})}}}]),angular.module("$strap.directives").directive("bsDaterangepicker",["$timeout",function(){"use strict";return"ontouchstart"in window&&!window.navigator.userAgent.match(/PhantomJS/i),{restrict:"A",require:"?ngModel",link:function(t,e){console.log("postLink",this,arguments),window.element=e,e.attr("data-toggle","daterangepicker"),e.daterangepicker({})}}}]),angular.module("$strap.directives").directive("bsDropdown",["$parse","$compile","$timeout",function(t,e,n){"use strict";var a=function(t,e){return e||(e=['<ul class="dropdown-menu" role="menu" aria-labelledby="drop1">',"</ul>"]),angular.forEach(t,function(t,n){if(t.divider)return e.splice(n+1,0,'<li class="divider"></li>');var i="<li"+(t.submenu&&t.submenu.length?' class="dropdown-submenu"':"")+">"+'<a tabindex="-1" ng-href="'+(t.href||"")+'"'+(t.click?'" ng-click="'+t.click+'"':"")+(t.target?'" target="'+t.target+'"':"")+">"+(t.text||"")+"</a>";t.submenu&&t.submenu.length&&(i+=a(t.submenu).join("\n")),i+="</li>",e.splice(n+1,0,i)}),e};return{restrict:"EA",scope:!0,link:function(i,o,r){var s=t(r.bsDropdown),u=s(i);n(function(){!angular.isArray(u);var t=angular.element(a(u).join(""));t.insertAfter(o),e(o.next("ul.dropdown-menu"))(i)}),o.addClass("dropdown-toggle").attr("data-toggle","dropdown")}}}]),angular.module("$strap.directives").directive("bsModal",["$parse","$compile","$http","$timeout","$q","$templateCache",function(t,e,n,a,i,o){"use strict";return{restrict:"A",scope:!0,link:function(r,s,u){var c=t(u.bsModal),l=(c.assign,c(r));i.when(o.get(l)||n.get(l,{cache:!0})).then(function(t){angular.isObject(t)&&(t=t.data);var n=c(r).replace(".html","").replace(/[\/|\.|:]/g,"-")+"-"+r.$id,i=$('<div class="modal hide" tabindex="-1"></div>').attr("id",n).attr("data-backdrop",u.backdrop||!0).attr("data-keyboard",u.keyboard||!0).addClass(u.modalClass?"fade "+u.modalClass:"fade").html(t);$("body").append(i),s.attr("href","#"+n).attr("data-toggle","modal"),a(function(){e(i)(r)}),r._modal=function(t){i.modal(t)},r.hide=function(){i.modal("hide")},r.show=function(){i.modal("show")},r.dismiss=r.hide,i.on("show",function(t){r.$emit("modal-show",t)}),i.on("shown",function(t){r.$emit("modal-shown",t)}),i.on("hide",function(t){r.$emit("modal-hide",t)}),i.on("hidden",function(t){r.$emit("modal-hidden",t)})})}}}]),angular.module("$strap.directives").directive("bsNavbar",["$location",function(t){"use strict";return{restrict:"A",link:function(e,n){e.$watch(function(){return t.path()},function(t){n.find("li[data-match-route]").each(function(e,n){var a=angular.element(n),i=a.attr("data-match-route"),o=RegExp("^"+i+"$",["i"]);o.test(t)?a.addClass("active"):a.removeClass("active")})})}}}]),angular.module("$strap.directives").directive("bsPopover",["$parse","$compile","$http","$timeout","$q","$templateCache",function(t,e,n,a,i,o){"use strict";return $("body").on("keyup",function(t){27===t.keyCode&&$(".popover.in").each(function(){$(this).popover("hide")})}),{restrict:"A",scope:!0,link:function(a,r,s){var u=t(s.bsPopover),c=(u.assign,u(a)),l={};angular.isObject(c)&&(l=c),i.when(l.content||o.get(c)||n.get(c,{cache:!0})).then(function(t){angular.isObject(t)&&(t=t.data),s.unique&&r.on("show",function(){$(".popover.in").each(function(){var t=$(this),e=t.data("popover");e&&!e.$element.is(r)&&t.popover("hide")})}),s.hide&&a.$watch(s.hide,function(t,e){t?n.hide():t!==e&&n.show()}),r.popover(angular.extend({},l,{content:t,html:!0}));var n=r.data("popover");n.hasContent=function(){return this.getTitle()||t},n.getPosition=function(){var t=$.fn.popover.Constructor.prototype.getPosition.apply(this,arguments);return e(this.$tip)(a),a.$digest(),this.$tip.data("popover",this),t},a._popover=function(t){r.popover(t)},a.hide=function(){r.popover("hide")},a.show=function(){r.popover("show")},a.dismiss=a.hide})}}}]),angular.module("$strap.directives").directive("bsTabs",["$parse","$compile","$timeout",function(t,e,n){"use strict";return{restrict:"A",require:"?ngModel",scope:!0,link:function(a,i,o,r){var s=t(o.bsTabs),u=(s.assign,s(a)),c=['<ul class="nav nav-tabs">',"</ul>"],l=['<div class="tab-content">',"</div>"];i.hide();var d=0;n(function(){angular.isArray(u)||(u=[],i.children("[data-title], [data-tab]").each(function(){var t=angular.element(this);u.push({title:a.$eval(t.data("title")||t.data("tab")),content:this.innerHTML,active:t.hasClass("active"),fade:t.hasClass("fade")})})),angular.forEach(u,function(t,e){t.active&&(d=e)}),angular.forEach(u,function(t,e){var n="tab-"+a.$id+"-"+e,i=d===e,r=o.fade||t.fade;c.splice(e+1,0,"<li"+(i?' class="active"':"")+'><a href="#'+n+'" data-index="'+e+'" data-toggle="tab">'+t.title+"</a></li>"),l.splice(e+1,0,'<div class="tab-pane'+(i?" active":"")+(r?" fade":"")+(r&&i?" in":"")+'" id="'+n+'">'+t.content+"</div>")}),i.html(c.join("")+l.join("")).show(),e(i.children("div.tab-content"))(a)}),r&&(i.on("show",function(t){var e=$(t.target);a.$apply(function(){r.$setViewValue(e.data("index"))})}),a.$watch(o.ngModel,function(t){angular.isUndefined(t)||(d=t,setTimeout(function(){var e=i.children("ul.nav-tabs").find("li:eq("+1*t+")");e.hasClass("active")||e.children("a").tab("show")}))}))}}}]),angular.module("$strap.directives").directive("bsTimepicker",["$timeout",function(t){"use strict";var e="((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9])?(?:\\s?(?:am|AM|pm|PM))?)";return{restrict:"A",require:"?ngModel",link:function(n,a,i,o){o&&a.on("changeTime.timepicker",function(){t(function(){o.$setViewValue(a.val())})});var r=RegExp("^"+e+"$",["i"]);o.$parsers.unshift(function(t){return!t||r.test(t)?(o.$setValidity("time",!0),t):(o.$setValidity("time",!1),void 0)}),a.attr("data-toggle","timepicker"),a.parent().addClass("bootstrap-timepicker"),a.timepicker()}}}]),angular.module("$strap.directives").directive("bsTooltip",["$parse","$compile",function(t){"use strict";return{restrict:"A",scope:!0,link:function(e,n,a){var i=t(a.bsTooltip),o=(i.assign,i(e));e.$watch(a.bsTooltip,function(t,e){t!==e&&(o=t)}),a.unique&&n.on("show",function(){$(".tooltip.in").each(function(){var t=$(this),e=t.data("tooltip");e&&!e.$element.is(n)&&t.tooltip("hide")})}),n.tooltip({title:function(){return angular.isFunction(o)?o.apply(null,arguments):o},html:!0});var r=n.data("tooltip");r.show=function(){var t=$.fn.tooltip.Constructor.prototype.show.apply(this,arguments);return this.tip().data("tooltip",this),t},e._tooltip=function(t){n.tooltip(t)},e.hide=function(){n.tooltip("hide")},e.show=function(){n.tooltip("show")},e.dismiss=e.hide}}}]),angular.module("$strap.directives").directive("bsTypeahead",["$parse",function(t){"use strict";return{restrict:"A",require:"?ngModel",link:function(e,n,a,i){var o=t(a.bsTypeahead),r=(o.assign,o(e));e.$watch(a.bsTypeahead,function(t,e){t!==e&&(r=t)}),n.attr("data-provide","typeahead"),n.typeahead({source:function(){return angular.isFunction(r)?r.apply(null,arguments):r},minLength:a.minLength||1,items:a.items,updater:function(t){return i&&e.$apply(function(){i.$setViewValue(t)}),t}});var s=n.data("typeahead");s.lookup=function(){var t;return this.query=this.$element.val()||"",this.query.length<this.options.minLength?this.shown?this.hide():this:(t=$.isFunction(this.source)?this.source(this.query,$.proxy(this.process,this)):this.source,t?this.process(t):this)},"0"===a.minLength&&setTimeout(function(){n.on("focus",function(){0===n.val().length&&setTimeout(n.typeahead.bind(n,"lookup"),200)})})}}}]);
View
2  ajax/libs/angular-strap/package.json
@@ -2,7 +2,7 @@
"name": "angular-strap",
"filename": "angular-strap.min.js",
"description": "AngularStrap - Twitter Bootstrap directives for AngularJS.",
- "version": "0.7.0",
+ "version": "0.7.1",
"homepage": "http://mgcrea.github.com/angular-strap",
"keywords": [
"angular",
Please sign in to comment.
Something went wrong with that request. Please try again.