angular.module("core-ui", []) .factory('CoreDialog', [function() { var service = {}; service['fatal'] = function(title, message) { bootbox.dialog({ "title": title, "message": "
" + message, "buttons": {}, "className": "co-dialog fatal-error", "closeButton": false }); }; return service; }]) .directive('corLogBox', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-log-box.html', replace: true, transclude: true, restrict: 'C', scope: { 'logs': '=logs' }, controller: function($rootScope, $scope, $element, $timeout) { $scope.hasNewLogs = false; var scrollHandlerBound = false; var isAnimatedScrolling = false; var isScrollBottom = true; var scrollHandler = function() { if (isAnimatedScrolling) { return; } var element = $element.find("#co-log-viewer")[0]; isScrollBottom = element.scrollHeight - element.scrollTop === element.clientHeight; if (isScrollBottom) { $scope.hasNewLogs = false; } }; var animateComplete = function() { isAnimatedScrolling = false; }; $scope.moveToBottom = function() { $scope.hasNewLogs = false; isAnimatedScrolling = true; isScrollBottom = true; $element.find("#co-log-viewer").animate( { scrollTop: $element.find("#co-log-content").height() }, "slow", null, animateComplete); }; $scope.$watch('logs', function(value, oldValue) { if (!value) { return; } $timeout(function() { if (!scrollHandlerBound) { $element.find("#co-log-viewer").on('scroll', scrollHandler); scrollHandlerBound = true; } if (!isScrollBottom) { $scope.hasNewLogs = true; return; } $scope.moveToBottom(); }, 500); }); } }; return directiveDefinitionObject; }) .directive('corOptionsMenu', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-options-menu.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corOption', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-option.html', replace: true, transclude: true, restrict: 'C', scope: { 'optionClick': '&optionClick' }, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTitle', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-title.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTitleAction', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-title-action.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTitleContent', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-title-content.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTitleLink', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-title-link.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corConfirmDialog', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-confirm-dialog.html', replace: false, transclude: true, restrict: 'C', scope: { 'dialogTitle': '@dialogTitle', 'dialogActionTitle': '@dialogActionTitle', 'dialogForm': '=dialogForm', 'dialogContext': '=dialogContext', 'dialogAction': '&dialogAction' }, controller: function($rootScope, $scope, $element) { $scope.working = false; $scope.$watch('dialogContext', function(dc) { if (!dc) { return; } $scope.show(); }); $scope.performAction = function() { $scope.working = true; $scope.dialogAction({ 'info': $scope.dialogContext, 'callback': function(result) { $scope.hide(); } }); }; $scope.show = function() { if ($scope.dialogForm) { $scope.dialogForm.$setPristine(); } $scope.working = false; $element.find('.modal').modal({}); }; $scope.hide = function() { $element.find('.modal').modal('hide'); }; } }; return directiveDefinitionObject; }) .directive('corTabPanel', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-tab-panel.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTabContent', function() { var directiveDefinitionObject = { priority: 2, templateUrl: '/static/directives/cor-tab-content.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTabs', function() { var directiveDefinitionObject = { priority: 3, templateUrl: '/static/directives/cor-tabs.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element, $timeout, $location, UIService) { $scope.isClosed = true; $scope.toggleClosed = function(e) { $scope.isClosed = !$scope.isClosed; e.stopPropagation(); e.preventDefault(); }; UIService.initializeTabs($scope, $element, function() { $scope.isClosed = true; }); } }; return directiveDefinitionObject; }) .directive('corFloatingBottomBar', function() { var directiveDefinitionObject = { priority: 3, templateUrl: '/static/directives/cor-floating-bottom-bar.html', replace: true, transclude: true, restrict: 'C', scope: {}, controller: function($rootScope, $scope, $element, $timeout, $interval) { var handler = function() { $element.removeClass('floating'); $element.css('width', $element[0].parentNode.clientWidth + 'px'); var windowHeight = $(window).height(); var rect = $element[0].getBoundingClientRect(); if (rect.bottom > windowHeight) { $element.addClass('floating'); } }; $(window).on("scroll", handler); $(window).on("resize", handler); var previousHeight = $element[0].parentNode.clientHeight; var stop = $interval(function() { var currentHeight = $element[0].parentNode.clientWidth; if (previousHeight != currentHeight) { currentHeight = previousHeight; handler(); } }, 100); $scope.$on('$destroy', function() { $(window).off("resize", handler); $(window).off("scroll", handler); $interval.cancel(stop); }); } }; return directiveDefinitionObject; }) .directive('corLoaderInline', function() { var directiveDefinitionObject = { templateUrl: '/static/directives/cor-loader-inline.html', replace: true, restrict: 'C', scope: { }, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corLoader', function() { var directiveDefinitionObject = { templateUrl: '/static/directives/cor-loader.html', replace: true, restrict: 'C', scope: { }, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('corTab', function() { var directiveDefinitionObject = { priority: 4, templateUrl: '/static/directives/cor-tab.html', replace: true, transclude: true, restrict: 'C', scope: { 'tabActive': '@tabActive', 'tabTitle': '@tabTitle', 'tabTarget': '@tabTarget', 'tabInit': '&tabInit', 'tabShown': '&tabShown', 'tabHidden': '&tabHidden' }, controller: function($rootScope, $scope, $element) { $element.find('a[data-toggle="tab"]').on('hidden.bs.tab', function (e) { $scope.tabHidden({}); }); $element.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $scope.tabShown({}); }); } }; return directiveDefinitionObject; }) .directive('corStep', function() { var directiveDefinitionObject = { priority: 4, templateUrl: '/static/directives/cor-step.html', replace: true, transclude: false, requires: '^corStepBar', restrict: 'C', scope: { 'icon': '@icon', 'title': '@title', 'text': '@text' }, controller: function($rootScope, $scope, $element) { } }; return directiveDefinitionObject; }) .directive('realtimeAreaChart', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/realtime-area-chart.html', replace: false, transclude: false, restrict: 'C', scope: { 'data': '=data', 'labels': '=labels', 'colors': '=colors', 'counter': '=counter' }, controller: function($scope, $element) { var graph = null; var series = []; var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } ); var colors = $scope.colors || []; var setupGraph = function() { for (var i = 0; i < $scope.labels.length; ++i) { series.push({ name: $scope.labels[i], color: i >= colors.length ? palette.color(): $scope.colors[i], stroke: 'rgba(0,0,0,0.15)', data: [] }); } var options = { element: $element.find('.chart')[0], renderer: 'area', stroke: true, series: series, min: 0, padding: { 'top': 0.3, 'left': 0, 'right': 0, 'bottom': 0.3 } }; if ($scope.minimum != null) { options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1; } else { options['min'] = 0; } if ($scope.maximum != null) { options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1; } graph = new Rickshaw.Graph(options); xaxes = new Rickshaw.Graph.Axis.Time({ graph: graph, timeFixture: new Rickshaw.Fixtures.Time.Local() }); yaxes = new Rickshaw.Graph.Axis.Y({ graph: graph, tickFormat: Rickshaw.Fixtures.Number.formatKMBT }); hoverDetail = new Rickshaw.Graph.HoverDetail({ graph: graph, xFormatter: function(x) { return new Date(x * 1000).toString(); } }); }; var refresh = function(data) { if (!data || $scope.counter < 0) { return; } if (!graph) { setupGraph(); } var timecode = new Date().getTime() / 1000; for (var i = 0; i < $scope.data.length; ++i) { var arr = series[i].data; arr.push( {'x': timecode, 'y': $scope.data[i] } ); if (arr.length > 10) { series[i].data = arr.slice(arr.length - 10, arr.length); } } graph.renderer.unstack = true; graph.update(); }; $scope.$watch('counter', function() { refresh($scope.data_raw); }); $scope.$watch('data', function(data) { $scope.data_raw = data; refresh($scope.data_raw); }); } }; return directiveDefinitionObject; }) .directive('realtimeLineChart', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/realtime-line-chart.html', replace: false, transclude: false, restrict: 'C', scope: { 'data': '=data', 'labels': '=labels', 'counter': '=counter', 'labelTemplate': '@labelTemplate', 'minimum': '@minimum', 'maximum': '@maximum' }, controller: function($scope, $element) { var graph = null; var xaxes = null; var yaxes = null; var hoverDetail = null; var series = []; var counter = 0; var palette = new Rickshaw.Color.Palette( { scheme: 'spectrum14' } ); var setupGraph = function() { var options = { element: $element.find('.chart')[0], renderer: 'line', series: series, padding: { 'top': 0.3, 'left': 0, 'right': 0, 'bottom': 0.3 } }; if ($scope.minimum != null) { options['min'] = $scope.minimum == 'auto' ? 'auto' : $scope.minimum * 1; } else { options['min'] = 0; } if ($scope.maximum != null) { options['max'] = $scope.maximum == 'auto' ? 'auto' : $scope.maximum * 1; } graph = new Rickshaw.Graph(options); xaxes = new Rickshaw.Graph.Axis.Time({ graph: graph, timeFixture: new Rickshaw.Fixtures.Time.Local() }); yaxes = new Rickshaw.Graph.Axis.Y({ graph: graph, tickFormat: Rickshaw.Fixtures.Number.formatKMBT }); hoverDetail = new Rickshaw.Graph.HoverDetail({ graph: graph, xFormatter: function(x) { return new Date(x * 1000).toString(); } }); }; var refresh = function(data) { if (data == null) { return; } if (!graph) { setupGraph(); } if (typeof data == 'number') { data = [data]; } if ($scope.labels) { data = data.slice(0, $scope.labels.length); } if (series.length == 0){ for (var i = 0; i < data.length; ++i) { var title = $scope.labels ? $scope.labels[i] : $scope.labelTemplate.replace('{x}', i + 1); series.push({ 'color': palette.color(), 'data': [], 'name': title }) } } counter++; var timecode = new Date().getTime() / 1000; for (var i = 0; i < data.length; ++i) { var arr = series[i].data; arr.push({ 'x': timecode, 'y': data[i] }) if (arr.length > 10) { series[i].data = arr.slice(arr.length - 10, arr.length); } } graph.update(); }; $scope.$watch('counter', function(counter) { refresh($scope.data_raw); }); $scope.$watch('data', function(data) { $scope.data_raw = data; }); } }; return directiveDefinitionObject; }) .directive('corStepBar', function() { var directiveDefinitionObject = { priority: 4, templateUrl: '/static/directives/cor-step-bar.html', replace: true, transclude: true, restrict: 'C', scope: { 'progress': '=progress' }, controller: function($rootScope, $scope, $element) { $scope.$watch('progress', function(progress) { if (!progress) { return; } var index = 0; for (var i = 0; i < progress.length; ++i) { if (progress[i]) { index = i; } } $element.find('.transclude').children('.co-step-element').each(function(i, elem) { $(elem).removeClass('active'); if (i <= index) { $(elem).addClass('active'); } }); }); } }; return directiveDefinitionObject; }) .directive('corCheckableMenu', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-checkable-menu.html', replace: false, transclude: true, restrict: 'C', scope: { 'controller': '=controller' }, controller: function($rootScope, $scope, $element) { $scope.getClass = function(items, checked) { if (checked.length == 0) { return 'none'; } if (checked.length == items.length) { return 'all'; } return 'some'; }; $scope.toggleItems = function($event) { $event.stopPropagation(); $scope.controller.toggleItems(); }; this.checkByFilter = function(filter) { $scope.controller.checkByFilter(function(item) { return filter({'item': item}); }); }; } }; return directiveDefinitionObject; }) .directive('corCheckableMenuItem', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-checkable-menu-item.html', replace: true, transclude: true, restrict: 'C', require: '^corCheckableMenu', scope: { 'itemFilter': '&itemFilter' }, link: function($scope, $element, $attr, parent) { $scope.parent = parent; }, controller: function($rootScope, $scope, $element) { $scope.selected = function() { $scope.parent.checkByFilter(this.itemFilter); }; } }; return directiveDefinitionObject; }) .directive('corCheckableItem', function() { var directiveDefinitionObject = { priority: 1, templateUrl: '/static/directives/cor-checkable-item.html', replace: false, transclude: false, restrict: 'C', scope: { 'item': '=item', 'controller': '=controller' }, controller: function($rootScope, $scope, $element) { $scope.toggleItem = function($event) { $event.preventDefault(); $event.stopPropagation(); $scope.controller.toggleItem($scope.item, $event.shiftKey); }; } }; return directiveDefinitionObject; }) .directive('corTable', function() { var directiveDefinitionObject = { priority: 1, replace: false, transclude: false, restrict: 'C', scope: {}, compile: function(tElement, tAttrs, transclude) { if (!window.matchMedia('(max-width: 767px)').matches) { return; } var cloneWithAttr = function(e, kind, opt_fullclone) { var clone = $(document.createElement(kind)); var attributes = $(e).prop("attributes"); $.each(attributes, function() { clone.attr(this.name, this.value); }); if (opt_fullclone) { for (var i = 0; i < e.childNodes.length; ++i) { clone.append($(e.childNodes[i]).clone(true)); } } return clone; }; var appendRepeater = function(div, tr, headers, includeRepeat) { // Find all the tds directly under the tr and convert into a header + value span. tr.children('td').each(function(idx, td) { var displayer = cloneWithAttr(tr, 'div'); if (!includeRepeat) { displayer.removeAttr('ng-repeat'); } if (idx < headers.length) { displayer.append(headers[idx].clone(true).addClass('mobile-col-header')); } displayer.append(cloneWithAttr(td, 'div', true).addClass('mobile-col-value')); div.append(displayer); }); }; // Find the thead's tds and turn them into header elements. var headers = []; tElement.find('thead td').each(function(idx, td) { headers.push(cloneWithAttr(td, 'div', true)); }); // Find the element with the 'ng-repeat'. var repeater = tElement.find('[ng-repeat]')[0]; // Convert the repeater into a