| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- /**
- * AngularStrap - Twitter Bootstrap directives for AngularJS
- * @version v0.7.5 - 2013-07-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('$strapConfig', {});
- angular.module('$strap.filters', ['$strap.config']);
- angular.module('$strap.directives', ['$strap.config']);
- angular.module('$strap', [
- '$strap.filters',
- '$strap.directives',
- '$strap.config'
- ]);
- 'use strict';
- angular.module('$strap.directives').directive('bsDatepicker', [
- '$timeout',
- '$strapConfig',
- function ($timeout, $strapConfig) {
- var isAppleTouch = /(iP(a|o)d|iPhone)/g.test(navigator.userAgent);
- 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;
- i = 0;
- angular.forEach(map, function (v, k) {
- re = re.split(k).join('${' + i + '}');
- i++;
- });
- 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 = angular.extend({ autoclose: true }, $strapConfig.datepicker || {}), type = attrs.dateType || options.type || 'date';
- angular.forEach([
- 'format',
- 'weekStart',
- 'calendarWeeks',
- 'startDate',
- 'endDate',
- 'daysOfWeekDisabled',
- 'autoclose',
- 'startView',
- 'minViewMode',
- 'todayBtn',
- 'todayHighlight',
- 'keyboardNavigation',
- 'language',
- 'forceParse'
- ], function (key) {
- if (angular.isDefined(attrs[key]))
- options[key] = attrs[key];
- });
- var language = options.language || 'en', readFormat = attrs.dateFormat || options.format || $.fn.datepicker.dates[language] && $.fn.datepicker.dates[language].format || 'mm/dd/yyyy', format = isAppleTouch ? 'yyyy-mm-dd' : readFormat, dateFormatRegexp = regexpForDateFormat(format, language);
- if (controller) {
- controller.$formatters.unshift(function (modelValue) {
- return type === 'date' && angular.isString(modelValue) && modelValue ? $.fn.datepicker.DPGlobal.parseDate(new Date(modelValue), $.fn.datepicker.DPGlobal.parseFormat(readFormat), language) : modelValue;
- });
- controller.$parsers.unshift(function (viewValue) {
- if (!viewValue) {
- controller.$setValidity('date', true);
- return null;
- } else if (type === 'date' && angular.isDate(viewValue)) {
- controller.$setValidity('date', true);
- return viewValue;
- } else if (angular.isString(viewValue) && dateFormatRegexp.test(viewValue)) {
- controller.$setValidity('date', true);
- if (isAppleTouch)
- return new Date(viewValue);
- return type === 'string' ? viewValue : $.fn.datepicker.DPGlobal.parseDate(viewValue, $.fn.datepicker.DPGlobal.parseFormat(format), language);
- } else {
- controller.$setValidity('date', false);
- return undefined;
- }
- });
- controller.$render = function ngModelRender() {
- if (isAppleTouch) {
- var date = controller.$viewValue ? $.fn.datepicker.DPGlobal.formatDate(controller.$viewValue, $.fn.datepicker.DPGlobal.parseFormat(format), language) : '';
- element.val(date);
- return date;
- }
- if (!controller.$viewValue)
- element.val('');
- return element.datepicker('update', controller.$viewValue);
- };
- }
- if (isAppleTouch) {
- element.prop('type', 'date').css('-webkit-appearance', 'textfield');
- } else {
- if (controller) {
- element.on('changeDate', function (ev) {
- scope.$apply(function () {
- controller.$setViewValue(type === 'string' ? element.val() : ev.date);
- });
- });
- }
- element.datepicker(angular.extend(options, {
- format: format,
- language: language
- }));
- scope.$on('$destroy', function () {
- var datepicker = element.data('datepicker');
- if (datepicker) {
- datepicker.picker.remove();
- element.data('datepicker', null);
- }
- });
- attrs.$observe('startDate', function (value) {
- element.datepicker('setStartDate', value);
- });
- attrs.$observe('endDate', function (value) {
- element.datepicker('setEndDate', value);
- });
- }
- var component = element.siblings('[data-toggle="datepicker"]');
- if (component.length) {
- component.on('click', function () {
- if (!element.prop('disabled')) {
- element.trigger('focus');
- }
- });
- }
- }
- };
- }
- ]);
- 'use strict';
- angular.module('$strap.directives').factory('$modal', [
- '$rootScope',
- '$compile',
- '$http',
- '$timeout',
- '$q',
- '$templateCache',
- '$strapConfig',
- function ($rootScope, $compile, $http, $timeout, $q, $templateCache, $strapConfig) {
- var ModalFactory = function ModalFactory(config) {
- function Modal(config) {
- var options = angular.extend({ show: true }, $strapConfig.modal, config), scope = options.scope ? options.scope : $rootScope.$new(), templateUrl = options.template;
- return $q.when($templateCache.get(templateUrl) || $http.get(templateUrl, { cache: true }).then(function (res) {
- return res.data;
- })).then(function onSuccess(template) {
- var id = templateUrl.replace('.html', '').replace(/[\/|\.|:]/g, '-') + '-' + scope.$id;
- // grafana change, removed fade
- var $modal = $('<div class="modal hide" tabindex="-1"></div>').attr('id', id).html(template);
- if (options.modalClass)
- $modal.addClass(options.modalClass);
- $('body').append($modal);
- $timeout(function () {
- $compile($modal)(scope);
- });
- scope.$modal = function (name) {
- $modal.modal(name);
- };
- angular.forEach([
- 'show',
- 'hide'
- ], function (name) {
- scope[name] = function () {
- $modal.modal(name);
- };
- });
- scope.dismiss = scope.hide;
- angular.forEach([
- 'show',
- 'shown',
- 'hide',
- 'hidden'
- ], function (name) {
- $modal.on(name, function (ev) {
- scope.$emit('modal-' + name, ev);
- });
- });
- $modal.on('shown', function (ev) {
- $('input[autofocus], textarea[autofocus]', $modal).first().trigger('focus');
- });
- $modal.on('hidden', function (ev) {
- if (!options.persist)
- scope.$destroy();
- });
- scope.$on('$destroy', function () {
- $modal.remove();
- });
- $modal.modal(options);
- return $modal;
- });
- }
- return new Modal(config);
- };
- return ModalFactory;
- }
- ])
- 'use strict';
- angular.module('$strap.directives').directive('bsTabs', [
- '$parse',
- '$compile',
- '$timeout',
- function ($parse, $compile, $timeout) {
- var template = '<div class="tabs">' + '<ul class="nav nav-tabs">' + '<li ng-repeat="pane in panes" ng-class="{active:pane.active}">' + '<a data-target="#{{pane.id}}" data-index="{{$index}}" data-toggle="tab">{{pane.title}}</a>' + '</li>' + '</ul>' + '<div class="tab-content" ng-transclude>' + '</div>';
- return {
- restrict: 'A',
- require: '?ngModel',
- priority: 0,
- scope: true,
- template: template,
- replace: true,
- transclude: true,
- compile: function compile(tElement, tAttrs, transclude) {
- return function postLink(scope, iElement, iAttrs, controller) {
- var getter = $parse(iAttrs.bsTabs), setter = getter.assign, value = getter(scope);
- scope.panes = [];
- var $tabs = iElement.find('ul.nav-tabs');
- var $panes = iElement.find('div.tab-content');
- var activeTab = 0, id, title, active;
- $timeout(function () {
- $panes.find('[data-title], [data-tab]').each(function (index) {
- var $this = angular.element(this);
- id = 'tab-' + scope.$id + '-' + index;
- title = $this.data('title') || $this.data('tab');
- active = !active && $this.hasClass('active');
- $this.attr('id', id).addClass('tab-pane');
- if (iAttrs.fade)
- $this.addClass('fade');
- scope.panes.push({
- id: id,
- title: title,
- content: this.innerHTML,
- active: active
- });
- });
- if (scope.panes.length && !active) {
- $panes.find('.tab-pane:first-child').addClass('active' + (iAttrs.fade ? ' in' : ''));
- scope.panes[0].active = true;
- }
- });
- if (controller) {
- iElement.on('show', function (ev) {
- var $target = $(ev.target);
- scope.$apply(function () {
- controller.$setViewValue($target.data('index'));
- });
- });
- scope.$watch(iAttrs.ngModel, function (newValue, oldValue) {
- if (angular.isUndefined(newValue))
- return;
- activeTab = newValue;
- setTimeout(function () {
- // Check if we're still on the same tab before making the switch
- if(activeTab === newValue) {
- var $next = $($tabs[0].querySelectorAll('li')[newValue * 1]);
- if (!$next.hasClass('active')) {
- $next.children('a').tab('show');
- }
- }
- });
- });
- }
- };
- }
- };
- }
- ]);
- 'use strict';
- angular.module('$strap.directives').directive('bsTooltip', [
- '$parse',
- '$compile',
- function ($parse, $compile) {
- return {
- restrict: 'A',
- scope: true,
- link: function postLink(scope, element, attrs, ctrl) {
- var getter = $parse(attrs.bsTooltip), setter = getter.assign, value = getter(scope);
- scope.$watch(attrs.bsTooltip, function (newValue, oldValue) {
- if (newValue !== oldValue) {
- value = newValue;
- }
- });
- // Grafana change, always hide other tooltips
- if (true) {
- element.on('show', function (ev) {
- $('.tooltip.in').each(function () {
- var $this = $(this), tooltip = $this.data('tooltip');
- if (tooltip && !tooltip.$element.is(element)) {
- $this.tooltip('hide');
- }
- });
- });
- }
- element.tooltip({
- title: function () {
- return angular.isFunction(value) ? value.apply(null, arguments) : value;
- },
- html: true,
- container: 'body', // Grafana change
- });
- var tooltip = element.data('tooltip');
- tooltip.show = function () {
- var r = $.fn.tooltip.Constructor.prototype.show.apply(this, arguments);
- this.tip().data('tooltip', this);
- return r;
- };
- scope._tooltip = function (event) {
- element.tooltip(event);
- };
- scope.hide = function () {
- element.tooltip('hide');
- };
- scope.show = function () {
- element.tooltip('show');
- };
- scope.dismiss = scope.hide;
- }
- };
- }
- ]);
- 'use strict';
- angular.module('$strap.directives').directive('bsTypeahead', [
- '$parse',
- function ($parse) {
- return {
- restrict: 'A',
- require: '?ngModel',
- link: function postLink(scope, element, attrs, controller) {
- var getter = $parse(attrs.bsTypeahead), setter = getter.assign, value = getter(scope);
- 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 (controller) {
- scope.$apply(function () {
- controller.$setViewValue(value);
- });
- }
- scope.$emit('typeahead-updated', value);
- return value;
- }
- });
- var typeahead = element.data('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;
- };
- if (!!attrs.matchAll) {
- typeahead.matcher = function (item) {
- return true;
- };
- }
- if (attrs.minLength === '0') {
- setTimeout(function () {
- element.on('focus', function () {
- element.val().length === 0 && setTimeout(element.typeahead.bind(element, 'lookup'), 200);
- });
- });
- }
- }
- };
- }
- ]);
|