mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
398 lines
14 KiB
JavaScript
398 lines
14 KiB
JavaScript
/**
|
|
* 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);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
]);
|