This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/core-ui.js
Joseph Schorr 32635cc641 - Make robots manager fully responsive
- Add a cor-table which automatically stacks and collapses on mobile views
2015-04-17 16:43:53 -04:00

799 lines
22 KiB
JavaScript

angular.module("core-ui", [])
.factory('CoreDialog', [function() {
var service = {};
service['fatal'] = function(title, message) {
bootbox.dialog({
"title": title,
"message": "<div class='alert-icon-container-container'><div class='alert-icon-container'><div class='alert-icon'></div></div></div>" + 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',
'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() {
$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) {
$scope.isClosed = true;
$scope.toggleClosed = function(e) {
$scope.isClosed = !$scope.isClosed;
e.stopPropagation();
e.preventDefault();
};
}
};
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(tag) {
return filter({'tag': tag});
});
};
}
};
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() {
$scope.controller.toggleItem($scope.item);
};
}
};
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) {
// 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');
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 <div> repeater.
var divRepeater = cloneWithAttr(repeater, 'div').addClass('mobile-row');
// If the repeater is a tbody, then we append each child tr. Otherwise, the repeater
// itself should be a tr.
if (repeater.nodeName.toLowerCase() == 'tbody') {
$(repeater).children().each(function(idx, tr) {
appendRepeater(divRepeater, $(tr), headers);
});
} else {
appendRepeater(divRepeater, $(repeater), headers);
}
var repeaterBody = $(document.createElement('tbody'));
var repeaterTr = $(document.createElement('tr'))
var repeaterTd = $(document.createElement('td'))
repeaterTd.append(divRepeater);
repeaterTr.append(repeaterTd);
repeaterBody.append(repeaterTr);
// Remove the tbody and thead.
tElement.find('thead').remove();
tElement.find('tbody').remove();
tElement.append(repeaterBody);
},
controller: function($rootScope, $scope, $element) {
$element.addClass('co-table');
}
};
return directiveDefinitionObject;
});