AC-331 Separated 'expand/collapse' function from 'select' function on Hosts tab tree. It now functions more like the Gmail label tree. Added Wait() utiltiy that can be used to freeze the API during longer than usual API operations. Using it on the 'group move' function.

This commit is contained in:
chouseknecht
2013-08-16 01:15:02 -04:00
parent 9729c6d203
commit 036352f10e
8 changed files with 377 additions and 261 deletions

View File

@@ -216,7 +216,6 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
LoadInventory({ scope: scope, doPostSteps: true }); LoadInventory({ scope: scope, doPostSteps: true });
$('#inventory-tabs a[href="#inventory-hosts"]').on('show.bs.tab', function() { $('#inventory-tabs a[href="#inventory-hosts"]').on('show.bs.tab', function() {
LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] }); LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] });
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });
if (!scope.$$phase) { if (!scope.$$phase) {
scope.$digest(); scope.$digest();
} }
@@ -382,10 +381,10 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.inventoryEditHide = true; scope.inventoryEditHide = true;
scope.groupDeleteHide = false; scope.groupDeleteHide = false;
scope.createButtonShow = true; scope.createButtonShow = true;
scope.group_id = node.attr('group_id'); //scope.group_id = node.attr('group_id');
scope.groupName = n.data; //scope.groupName = n.data;
scope.groupTitle = '<h4>' + n.data + '</h4>'; //scope.groupTitle = '<h4>' + n.data + '</h4>';
scope.groupTitle += (node.attr('description')) ? '<p>' + node.attr('description') + '</p>' : ''; //scope.groupTitle += (node.attr('description')) ? '<p>' + node.attr('description') + '</p>' : '';
} }
else if (type == 'inventory') { else if (type == 'inventory') {
url = node.attr('hosts'); url = node.attr('hosts');
@@ -395,9 +394,9 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
scope.inventoryEditHide=false; scope.inventoryEditHide=false;
scope.groupDeleteHide = true; scope.groupDeleteHide = true;
scope.createButtonShow = false; scope.createButtonShow = false;
scope.groupName = 'All Hosts'; //scope.groupName = 'All Hosts';
scope.groupTitle = '<h4>All Hosts</h4>'; //scope.groupTitle = '<h4>All Hosts</h4>';
scope.group_id = null; //scope.group_id = null;
} }
if (!scope.$$phase) { if (!scope.$$phase) {
@@ -460,11 +459,12 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
}); });
} }
scope.showHosts = function(e) { // Respond to the scope.$emit from awTree directive
console.log('here'); scope.$on('refreshHost', function(e, group, title) {
var elm = angular.elment(e.srcElement); scope.groupTitle = title;
console.log('Need to show hosts: ' + elm.attr('data-hosts')); scope.group_id = group;
} HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: group });
});
} }

View File

@@ -12,7 +12,7 @@
function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, Rest, Alert, LoadBreadCrumbs, Prompt, function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, Rest, Alert, LoadBreadCrumbs, Prompt,
GenerateList, OrganizationList, SearchInit, PaginateInit, ClearScope, ProcessErrors, GenerateList, OrganizationList, SearchInit, PaginateInit, ClearScope, ProcessErrors,
GetBasePath, SelectionInit) GetBasePath, SelectionInit, Wait)
{ {
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope. //scope.
@@ -70,7 +70,7 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, R
OrganizationsList.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', '$log', 'Rest', 'Alert', 'LoadBreadCrumbs', 'Prompt', OrganizationsList.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', '$log', 'Rest', 'Alert', 'LoadBreadCrumbs', 'Prompt',
'GenerateList', 'OrganizationList', 'SearchInit', 'PaginateInit', 'ClearScope', 'ProcessErrors', 'GenerateList', 'OrganizationList', 'SearchInit', 'PaginateInit', 'ClearScope', 'ProcessErrors',
'GetBasePath', 'SelectionInit' ]; 'GetBasePath', 'SelectionInit', 'Wait' ];
function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, OrganizationForm, function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, OrganizationForm,

View File

@@ -410,10 +410,12 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
function(RelatedSearchInit, RelatedPaginateInit, InventoryForm, GetBasePath) { function(RelatedSearchInit, RelatedPaginateInit, InventoryForm, GetBasePath) {
return function(params) { return function(params) {
// Rerfresh the Hosts view on right side of page // Rerfresh the Hosts view on right side of page
scope = params.scope;
var group_id = params.group_id;
var scope = params.scope;
scope['hosts'] = null; scope['hosts'] = null;
var url = (scope.group_id !== null && scope.group_id !== undefined) ? GetBasePath('groups') + scope.group_id + '/all_hosts/' : var url = (group_id !== null && group_id !== undefined) ? GetBasePath('groups') + group_id + '/all_hosts/' :
GetBasePath('inventory') + params.inventory_id + '/hosts/'; GetBasePath('inventory') + params.inventory_id + '/hosts/';
var relatedSets = { hosts: { url: url, iterator: 'host' } }; var relatedSets = { hosts: { url: url, iterator: 'host' } };

View File

@@ -100,8 +100,8 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
}]) }])
.factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', 'GetBasePath', 'ProcessErrors', .factory('TreeInit', ['Alert', 'Rest', 'Authorization', '$http', 'LoadTreeData', 'GetBasePath', 'ProcessErrors', 'Wait',
function(Alert, Rest, Authorization, $http, LoadTreeData, GetBasePath, ProcessErrors) { function(Alert, Rest, Authorization, $http, LoadTreeData, GetBasePath, ProcessErrors, Wait) {
return function(params) { return function(params) {
var scope = params.scope; var scope = params.scope;
@@ -200,6 +200,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
$(tree_id).bind('move_node.jstree', function(e, data) { $(tree_id).bind('move_node.jstree', function(e, data) {
// When user drags-n-drops a node, update the API // When user drags-n-drops a node, update the API
Wait('start');
var node, target, url, parent, inv_id, variables; var node, target, url, parent, inv_id, variables;
node = $('#tree-view li[id="' + data.rslt.o[0].id + '"]'); // node being moved node = $('#tree-view li[id="' + data.rslt.o[0].id + '"]'); // node being moved
parent = $('#tree-view li[id="' + data.args[0].op[0].id + '"]'); //node moving from parent = $('#tree-view li[id="' + data.args[0].op[0].id + '"]'); //node moving from
@@ -214,9 +215,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
function showSuccessMsg() { function showSuccessMsg() {
var parent_descr = (parent.attr('type') == 'inventory') ? 'the inventory root' : parent.attr('name'); var parent_descr = (parent.attr('type') == 'inventory') ? 'the inventory root' : parent.attr('name');
var target_descr = (target.attr('type') == 'inventory') ? 'the inventory root' : target.attr('name'); var target_descr = (target.attr('type') == 'inventory') ? 'the inventory root' : target.attr('name');
Alert('Group Moved', 'Group ' + node.attr('name') + ' was successfully moved from ' + parent_descr + Wait('stop');
' to ' + target_descr + '.', 'alert-success');
scope['treeLoading'] = false;
if (!scope.$$phase) { if (!scope.$$phase) {
scope.$digest(); scope.$digest();
} }
@@ -302,7 +301,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
'. GET returned status: ' + status }); '. GET returned status: ' + status });
}); });
scope['treeLoading'] = true; //scope['treeLoading'] = true;
if (!scope.$$phase) { if (!scope.$$phase) {
scope.$digest(); scope.$digest();

View File

@@ -24,6 +24,35 @@ body {
color: @black; color: @black;
} }
.spinny {
display: none;
position: absolute;
z-index: 2000;
width: 75px;
height: 75px;
text-align:center;
color: #eee;
background-color: @black;
border: 1px solid @grey;
border-radius: 6px;
padding-top: 10px;
p {
padding-top: 10px;
font-size: 11px;
}
}
.overlay {
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 1999;
background-color: @black;
opacity: .4;
}
.tooltip { .tooltip {
z-index: 1050; z-index: 1050;
} }
@@ -603,7 +632,7 @@ input[type="text"].job-successful {
.search-tree { .search-tree {
ul { ul {
list-style-type: none; list-style-type: none;
padding-left: 10px; padding-left: 13px;
} }
ul:first-child { ul:first-child {
padding-left: 0; padding-left: 0;
@@ -611,10 +640,21 @@ input[type="text"].job-successful {
} }
.search-tree .active { .search-tree .active {
background-color: #ddd; /*background-color: #ddd;
padding: 1px 1px 1px 0; padding: 1px 1px 1px 0;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;*/
font-weight: bold;
color: #000;
}
.search-tree .expand {
padding: 3px;
}
.search-tree .expand:hover {
background-color: #ddd;
border: 1px solid #ddd;
} }
.parse-selection { .parse-selection {

View File

@@ -317,8 +317,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
} }
}]) }])
.directive('awTree', ['Rest', 'ProcessErrors', 'Authorization', '$compile', '$rootScope', 'HostsReload', .directive('awTree', ['Rest', 'ProcessErrors', 'Authorization', '$compile', '$rootScope',
function(Rest, ProcessErrors, Authorization, $compile, $rootScope, HostsReload) { function(Rest, ProcessErrors, Authorization, $compile, $rootScope) {
return { return {
//require: 'ngModel', //require: 'ngModel',
@@ -335,13 +335,14 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
template: template:
"<div class=\"search-tree well\" id=\"search-tree-container\">\n" + "<div class=\"search-tree well\" id=\"search-tree-container\">\n" +
"<ul>\n" + "<ul>\n" +
"<li><a href=\"\" id=\"search-node-1000\" class=\"active\" data-state=\"closed\" data-hosts=\"{{ treeData[0].hosts}}\" " + "<li id=\"search-node-1000\" data-state=\"closed\" data-hosts=\"{{ treeData[0].hosts}}\" " +
"data-hosts=\"{{ treeData[0].hosts }}\" " + "data-hosts=\"{{ treeData[0].hosts }}\" " +
"data-description=\"{{ treeData[0].description }}\" " + "data-description=\"{{ treeData[0].description }}\" " +
"data-failures=\"{{ treeData[0].failures }}\" " + "data-failures=\"{{ treeData[0].failures }}\" " +
"data-groups=\"{{ treeData[0].groups }}\" " + "data-groups=\"{{ treeData[0].groups }}\" " +
"data-name=\"{{ treeData[0].name }}\" " + "data-name=\"{{ treeData[0].name }}\">" +
"><i class=\"icon-caret-right\"></i> {{ treeData[0].name}}</a></li>\n" + "<a href=\"\" class=\"expand\"><i class=\"icon-caret-right\"></i></a> <a href=\"\" class=\"activate active\">{{ treeData[0].name }}</a></li>\n" +
"</li>\n"+
"</ul>\n" + "</ul>\n" +
"</div>\n", "</div>\n",
@@ -349,90 +350,128 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
var idx=1000; var idx=1000;
function toggle(e) { function refresh(parent) {
var id = (e.target.tagName == 'I') ? e.target.parentNode.attributes.id.value : e.target.attributes.id.value; var group, title;
var elm = angular.element(document.getElementById(id)); if (parent.attr('data-group-id')) {
group = parent.attr('data-group-id');
function activate() { title = '<h4>' + parent.attr('data-name') + '</h4>';
/* Set the clicked node as active */ title += (parent.attr('data-description') !== "") ? '<p>' + parent.attr('data-description') + '</p>' : '';
$('.search-tree .active').removeClass('active');
elm.addClass('active');
var group = (elm.attr('data-group-id')) ? elm.attr('data-group-id') : null;
var parentScope = angular.element(document.getElementById('htmlTemplate')).scope();
console.log('calling for group: ' + group);
HostsReload({ scope: parentScope, inventory_id: parentScope['inventory_id'], group_id: group });
} }
else {
group = null;
title = '<h4>All Hosts</h4>'
}
scope.$emit('refreshHost', group, title);
}
function activate(e) {
/* Set the clicked node as active */
var elm = angular.element(e.target); //<a>
var parent = angular.element(e.target.parentNode); //<li>
$('.search-tree .active').removeClass('active');
elm.addClass('active');
refresh(parent);
}
function toggle(e) {
var id, parent, elm, icon;
if (e.target.tagName == 'I') {
id = e.target.parentNode.parentNode.attributes.id.value;
parent = angular.element(e.target.parentNode.parentNode); //<li>
elm = angular.element(e.target.parentNode); // <a>
}
else {
id = e.target.parentNode.attributes.id.value;
parent = angular.element(e.target.parentNode);
elm = angular.element(e.target);
}
var sibling = angular.element(parent.children()[1]); // <a>
var state = parent.attr('data-state');
var icon = angular.element(elm.children()[0]);
/* Open/close the node and expand */ /* Open/close the node and expand */
if (scope.childrenLoadedRemove) { if (scope.childrenLoadedRemove) {
scope.childrenLoadedRemove(); scope.childrenLoadedRemove();
} }
scope.childrenLoadedRemove = scope.$on('childrenLoaded', function() { scope.childrenLoadedRemove = scope.$on('childrenLoaded', function() {
childlists = elm.parent().find('ul'); //look for children childlists = parent.find('ul'); //look for children
if (childlists && childlists.length > 0) { if (childlists && childlists.length > 0) {
// bind toggle() to click event of each link in the group we clicked on // bind toggle() to click event of each link in the group we clicked on
var parent = angular.element(elm.parent()[0]);
var links = parent.find('a'); var links = parent.find('a');
for (var i=0; i < links.length; i++) { for (var i=0; i < links.length; i++) {
var link = angular.element(links[i]); var link = angular.element(links[i]);
link.unbind('click', toggle); if (link.hasClass('expand')) {
link.bind('click', toggle); link.unbind('click', toggle);
link.bind('click', toggle);
}
if (link.hasClass('activate')) {
link.unbind('click', activate);
link.bind('click', activate);
}
} }
toggle(e); toggle(e);
} }
else { else {
var icon = angular.element(elm.children()[0]); icon.removeClass('icon-caret-right').addClass('icon-caret-down');
icon.removeClass('icon-caret-down').removeClass('icon-caret-right').addClass('icon-ellipsis-horizontal'); //activate(e);
} }
}); });
if (elm.attr('data-state') == 'closed') {
if (state == 'closed') {
// expand the elment // expand the elment
var childlists = elm.parent().find('ul'); var childlists = parent.find('ul');
if (childlists && childlists.length > 0) { if (childlists && childlists.length > 0) {
// already has childen // already has childen
for (var i=0; i < childlists.length; i++) { for (var i=0; i < childlists.length; i++) {
var listChild = angular.element(childlists[i]); var listChild = angular.element(childlists[i]);
var listParent = angular.element(listChild.parent().find('a')[0]); var listParent = angular.element(listChild.parent());
if (listParent.attr('id') == elm.attr('id')) { if (listParent.attr('id') == id) {
angular.element(childlists[i]).removeClass('hidden'); angular.element(childlists[i]).removeClass('hidden');
} }
// all the children should be in a closed state // all the children should be in a closed state
var aList = listChild.find('a'); var liList = listChild.find('li');
for (var j=0; j < aList.length; j++) { for (var j=0; j < liList.length; j++) {
var thisList = angular.element(aList[j]); var thisList = angular.element(liList[j]);
var anchor = angular.element(thisList.find('a')[0]);
var thisIcon = angular.element(anchor.children()[0]);
thisIcon.removeClass('icon-caret-down').addClass('icon-caret-right');
thisList.attr('data-state', 'closed'); thisList.attr('data-state', 'closed');
var icon = angular.element(thisList.children()[0]);
icon.removeClass('icon-caret-down').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-right');
} }
} }
elm.attr('data-state','open'); parent.attr('data-state','open');
var icon = angular.element(elm.children()[0]); icon.removeClass('icon-caret-right').addClass('icon-caret-down');
icon.removeClass('icon-caret-right').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-down');
activate();
} }
else { else {
getChildren(elm); getChildren(elm, parent, sibling);
} }
} }
else { else {
// close the element // close the element
elm.attr('data-state','closed'); parent.attr('data-state','closed');
var icon = angular.element(elm.children()[0]); var icon = angular.element(elm.children()[0]);
icon.removeClass('icon-caret-down').removeClass('icon-ellipsis-horizontal').addClass('icon-caret-right'); icon.removeClass('icon-caret-down').addClass('icon-caret-right');
var childlists = elm.parent().find('ul'); var childlists = parent.find('ul');
if (childlists && childlists.length > 0) { if (childlists && childlists.length > 0) {
// has childen // has childen
for (var i=0; i < childlists.length; i++) { for (var i=0; i < childlists.length; i++) {
angular.element(childlists[i]).addClass('hidden'); angular.element(childlists[i]).addClass('hidden');
} }
} }
activate(); /* When the active node's parent is closed, activate the parent*/
if ($(parent).find('.active').length > 0) {
$(parent).find('.active').removeClass('active');
sibling.addClass('active');
refresh(parent);
}
}
} }
}
function getChildren(elm) { function getChildren(elm, parent, sibling) {
var url = elm.attr('data-groups'); var url = parent.attr('data-groups');
var html = ''; var html = '';
var token = Authorization.getToken(); var token = Authorization.getToken();
/* For reasons unknown calling Rest fails. It just dies with no errors /* For reasons unknown calling Rest fails. It just dies with no errors
@@ -445,23 +484,21 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
// build html and append to parent of clicked link // build html and append to parent of clicked link
for (var i=0; i < data.results.length; i++) { for (var i=0; i < data.results.length; i++) {
idx++; idx++;
html += "<li>\n"; html += "<li ";
html += "<a href=\"\" data-state=\"closed\" ";
html += "id=\"search-tree-" + idx +"\" "; html += "id=\"search-tree-" + idx +"\" ";
html += "date-state=\"closed\" ";
html += "data-hosts=\"" + data.results[i].related.all_hosts + "\" "; html += "data-hosts=\"" + data.results[i].related.all_hosts + "\" ";
html += "data-description=\"" + data.results[i].description + "\" "; html += "data-description=\"" + data.results[i].description + "\" ";
html += "data-failures=\"" +data.results[i].has_active_failures + "\" "; html += "data-failures=\"" +data.results[i].has_active_failures + "\" ";
html += "data-groups=\"" + data.results[i].related.children + "\" "; html += "data-groups=\"" + data.results[i].related.children + "\" ";
html += "data-name=\"" + data.results[i].name + "\" "; html += "data-name=\"" + data.results[i].name + "\" ";
html += "data-group-id=\"" + data.results[i].id + "\" "; html += "data-group-id=\"" + data.results[i].id + "\">";
html += "><i class=\"icon-caret-right\"></i> " + data.results[i].name; html += "<a href=\"\" class=\"expand\"><i class=\"icon-caret-right\"></i></a> ";
html += "</a></li>\n"; html += "<a href=\"\" class=\"activate\">" + data.results[i].name + "</a></li>\n";
} }
html = (html !== '') ? "<ul>" + html + "</ul>\n" : ""; html = (html !== '') ? "<ul>" + html + "</ul>\n" : "";
var parent = angular.element(elm.parent()[0]);
var compiled = $compile(html)(scope); var compiled = $compile(html)(scope);
parent.append(compiled); //append the new list to the parent <li> parent.append(compiled); //append the new list to the parent <li>
console.log('childrenLoaded');
scope.$emit('childrenLoaded'); scope.$emit('childrenLoaded');
}, },
error: function(data, status) { error: function(data, status) {
@@ -474,7 +511,10 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
function initialize() { function initialize() {
var root = angular.element(document.getElementById('search-node-1000')); var root = angular.element(document.getElementById('search-node-1000'));
root.bind('click', toggle); var toggleElm = angular.element(root.find('a')[0]);
var activateElm = angular.element(root.find('a')[1])
toggleElm.bind('click', toggle);
activateElm.bind('click', activate);
} }
if ($rootScope.hostTabInitRemove) { if ($rootScope.hostTabInitRemove) {
@@ -484,18 +524,23 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
var container = angular.element(document.getElementById('search-tree-container')); var container = angular.element(document.getElementById('search-tree-container'));
container.empty(); container.empty();
var html = "<ul>\n" + var html = "<ul>\n" +
"<li><a href=\"\" id=\"search-node-1000\" class=\"active\" data-state=\"closed\" data-hosts=\"{{ treeData[0].hosts}}\" " + "<li id=\"search-node-1000\" data-state=\"closed\" data-hosts=\"{{ treeData[0].hosts}}\" " +
"data-hosts=\"{{ treeData[0].hosts }}\" " + "data-hosts=\"{{ treeData[0].hosts }}\" " +
"data-description=\"{{ treeData[0].description }}\" " + "data-description=\"{{ treeData[0].description }}\" " +
"data-failures=\"{{ treeData[0].failures }}\" " + "data-failures=\"{{ treeData[0].failures }}\" " +
"data-groups=\"{{ treeData[0].groups }}\" " + "data-groups=\"{{ treeData[0].groups }}\" " +
"data-name=\"{{ treeData[0].name }}\" " + "data-name=\"{{ treeData[0].name }}\" " +
"><i class=\"icon-caret-right\"></i> {{ treeData[0].name }}</a></li>\n" + "><a href=\"\" class=\"expand\"><i class=\"icon-caret-right\"></i></a> <a href=\"\" class=\"activate active\">{{ treeData[0].name }}</a>" +
"</li>\n" +
"</ul>\n"; "</ul>\n";
var compiled = $compile(html)(scope); var compiled = $compile(html)(scope);
container.append(compiled); container.append(compiled);
initialize(); initialize();
//setTimeout(function() { $('.search-tree .active').click(); }, 1000); //click the root node, forcing level 1 nodes to appear // Expand the root node and show All Hosts
setTimeout(function() {
$('#search-node-1000 .expand').click();
$('#search-node-1000 .activate').click();
}, 500);
}); });
} }

View File

@@ -8,206 +8,233 @@
angular.module('Utilities',[]) angular.module('Utilities',[])
.factory('ClearScope', function() { .factory('ClearScope', function() {
return function(id) { return function(id) {
var element = document.getElementById(id); var element = document.getElementById(id);
var scope = angular.element(element).scope(); var scope = angular.element(element).scope();
scope.$destroy(); scope.$destroy();
} }
}) })
.factory('ToggleClass', function() { .factory('ToggleClass', function() {
return function(selector, cssClass) { return function(selector, cssClass) {
// Toggles the existance of a css class on a given element // Toggles the existance of a css class on a given element
if ( $(selector) && $(selector).hasClass(cssClass) ) { if ( $(selector) && $(selector).hasClass(cssClass) ) {
$(selector).removeClass(cssClass); $(selector).removeClass(cssClass);
} }
else if ($(selector)) { else if ($(selector)) {
$(selector).addClass(cssClass); $(selector).addClass(cssClass);
} }
} }
}) })
.factory('Alert', ['$rootScope', '$location', function($rootScope, $location) { .factory('Alert', ['$rootScope', '$location', function($rootScope, $location) {
return function(hdr, msg, cls, action, secondAlert, disableButtons) { return function(hdr, msg, cls, action, secondAlert, disableButtons) {
// Pass in the header and message you want displayed on TB modal dialog found in index.html. // Pass in the header and message you want displayed on TB modal dialog found in index.html.
// Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success, // Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success,
// alert-info...). Pass an optional function(){}, if you want a specific action to occur when user // alert-info...). Pass an optional function(){}, if you want a specific action to occur when user
// clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed.
if (secondAlert) { if (secondAlert) {
$rootScope.alertHeader2 = hdr; $rootScope.alertHeader2 = hdr;
$rootScope.alertBody2 = msg; $rootScope.alertBody2 = msg;
$rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger $rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
$('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' });
$rootScope.disableButtons2 = (disableButtons) ? true : false; $rootScope.disableButtons2 = (disableButtons) ? true : false;
if (action) { if (action) {
$('#alert-modal2').on('hidden', function() { $('#alert-modal2').on('hidden', function() {
action(); action();
}); });
} }
$(document).bind('keydown', function(e) { $(document).bind('keydown', function(e) {
if (e.keyCode === 27) { if (e.keyCode === 27) {
$('#alert-modal2').modal('hide'); $('#alert-modal2').modal('hide');
if (action) { if (action) {
action(); action();
} }
} }
}); });
} }
else { else {
$rootScope.alertHeader = hdr; $rootScope.alertHeader = hdr;
$rootScope.alertBody = msg; $rootScope.alertBody = msg;
$rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger $rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
$('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' });
$(document).bind('keydown', function(e) { $(document).bind('keydown', function(e) {
if (e.keyCode === 27) { if (e.keyCode === 27) {
$('#alert-modal').modal('hide'); $('#alert-modal').modal('hide');
if (action) { if (action) {
action(); action();
} }
} }
}); });
$rootScope.disableButtons = (disableButtons) ? true : false; $rootScope.disableButtons = (disableButtons) ? true : false;
if (action) { if (action) {
$('#alert-modal').on('hidden', function() { $('#alert-modal').on('hidden', function() {
action(); action();
}); });
} }
} }
} }
}]) }])
.factory('ProcessErrors', ['$log', 'Alert', function($log, Alert) { .factory('ProcessErrors', ['$log', 'Alert', function($log, Alert) {
return function(scope, data, status, form, defaultMsg) { return function(scope, data, status, form, defaultMsg) {
if (status == 403) { if (status == 403) {
var msg = 'The API responded with a 403 Access Denied error. '; var msg = 'The API responded with a 403 Access Denied error. ';
if (data['detail']) { if (data['detail']) {
msg += 'Detail: ' + data['detail']; msg += 'Detail: ' + data['detail'];
} }
else { else {
msg += 'Please contact your system administrator.'; msg += 'Please contact your system administrator.';
} }
Alert(defaultMsg.hdr, msg); Alert(defaultMsg.hdr, msg);
} }
else if (data.non_field_errors) { else if (data.non_field_errors) {
Alert('Error!', data.non_field_errors); Alert('Error!', data.non_field_errors);
} }
else if (data.detail) { else if (data.detail) {
Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail);
} }
else if (data['__all__']) { else if (data['__all__']) {
Alert('Error!', data['__all__']); Alert('Error!', data['__all__']);
} }
else if (form) { else if (form) {
var fieldErrors = false; var fieldErrors = false;
for (var field in form.fields ) { for (var field in form.fields ) {
if (form.fields[field].realName) { if (form.fields[field].realName) {
if (data[form.fields[field].realName]) { if (data[form.fields[field].realName]) {
scope[field + '_api_error'] = data[form.fields[field]][0]; scope[field + '_api_error'] = data[form.fields[field]][0];
fieldErrors = true; fieldErrors = true;
} }
} }
if (form.fields[field].sourceModel) { if (form.fields[field].sourceModel) {
if (data[field]) { if (data[field]) {
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] =
data[field][0]; data[field][0];
fieldErrors = true; fieldErrors = true;
} }
} }
else { else {
if (data[field]) { if (data[field]) {
scope[field + '_api_error'] = data[field][0]; scope[field + '_api_error'] = data[field][0];
fieldErrors = true; fieldErrors = true;
} }
} }
} }
if ( (!fieldErrors) && defaultMsg) { if ( (!fieldErrors) && defaultMsg) {
Alert(defaultMsg.hdr, defaultMsg.msg); Alert(defaultMsg.hdr, defaultMsg.msg);
} }
} }
else { else {
Alert(defaultMsg.hdr, defaultMsg.msg); Alert(defaultMsg.hdr, defaultMsg.msg);
} }
} }
}]) }])
.factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', function($rootScope, $routeParams, $location, Rest) { .factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', function($rootScope, $routeParams, $location, Rest) {
return function(crumb) { return function(crumb) {
//Keep a list of path/title mappings. When we see /organizations/XX in the path, for example,
//we'll know the actual organization name it maps to.
if (crumb !== null && crumb !== undefined) {
var found = false;
for (var i=0; i < $rootScope.crumbCache.length; i++) {
if ($rootScope.crumbCache[i].path == crumb.path) {
found = true;
$rootScope.crumbCache[i] = crumb;
break;
}
}
if (found == false) {
$rootScope.crumbCache.push(crumb);
}
}
//Keep a list of path/title mappings. When we see /organizations/XX in the path, for example, var paths = $location.path().replace(/^\//,'').split('/');
//we'll know the actual organization name it maps to. var ppath = '';
if (crumb !== null && crumb !== undefined) { $rootScope.breadcrumbs = [];
var found = false; if (paths.length > 1) {
for (var i=0; i < $rootScope.crumbCache.length; i++) { var parent, child;
if ($rootScope.crumbCache[i].path == crumb.path) { for (var i=0; i < paths.length - 1; i++) {
found = true; if (i > 0 && paths[i].match(/\d+/)) {
$rootScope.crumbCache[i] = crumb; parent = paths[i-1];
break; if (parent == 'inventories') {
}
}
if (found == false) {
$rootScope.crumbCache.push(crumb);
}
}
var paths = $location.path().replace(/^\//,'').split('/');
var ppath = '';
$rootScope.breadcrumbs = [];
if (paths.length > 1) {
var parent, child;
for (var i=0; i < paths.length - 1; i++) {
if (i > 0 && paths[i].match(/\d+/)) {
parent = paths[i-1];
if (parent == 'inventories') {
child = 'inventory'; child = 'inventory';
} }
else { else {
child = parent.substring(0,parent.length - 1); //assumes parent ends with 's' child = parent.substring(0,parent.length - 1); //assumes parent ends with 's'
} }
// find the correct title // find the correct title
for (var j=0; j < $rootScope.crumbCache.length; j++) { for (var j=0; j < $rootScope.crumbCache.length; j++) {
if ($rootScope.crumbCache[j].path == '/' + parent + '/' + paths[i]) { if ($rootScope.crumbCache[j].path == '/' + parent + '/' + paths[i]) {
child = $rootScope.crumbCache[j].title; child = $rootScope.crumbCache[j].title;
break; break;
} }
} }
$rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] }); $rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] });
} }
else { else {
$rootScope.breadcrumbs.push({ title: paths[i], path: ppath + '/' + paths[i] }); $rootScope.breadcrumbs.push({ title: paths[i], path: ppath + '/' + paths[i] });
} }
ppath += '/' + paths[i]; ppath += '/' + paths[i];
} }
} }
} }
}]) }])
.factory('ReturnToCaller', ['$location', function($location) { .factory('ReturnToCaller', ['$location', function($location) {
return function(idx) { return function(idx) {
// Split the current path by '/' and use the array elements from 0 up to and // Split the current path by '/' and use the array elements from 0 up to and
// including idx as the new path. If no idx value supplied, use 0 to length - 1. // including idx as the new path. If no idx value supplied, use 0 to length - 1.
var paths = $location.path().replace(/^\//,'').split('/'); var paths = $location.path().replace(/^\//,'').split('/');
var newpath = ''; var newpath = '';
idx = (idx == null || idx == undefined) ? paths.length - 1 : idx + 1; idx = (idx == null || idx == undefined) ? paths.length - 1 : idx + 1;
for (var i=0; i < idx; i++) { for (var i=0; i < idx; i++) {
newpath += '/' + paths[i] newpath += '/' + paths[i]
} }
$location.path(newpath); $location.path(newpath);
} }
}]) }])
.factory('FormatDate', [ function() { .factory('FormatDate', [ function() {
return function(dt) { return function(dt) {
var result = ('0' + (dt.getMonth() + 1)).slice(-2) + '/'; var result = ('0' + (dt.getMonth() + 1)).slice(-2) + '/';
result += ('0' + dt.getDate()).slice(-2) + '/'; result += ('0' + dt.getDate()).slice(-2) + '/';
result += ('0' + (dt.getFullYear() - 2000)).slice(-2) + ' '; result += ('0' + (dt.getFullYear() - 2000)).slice(-2) + ' ';
result += ('0' + dt.getHours()).slice(-2) + ':'; result += ('0' + dt.getHours()).slice(-2) + ':';
result += ('0' + dt.getMinutes()).slice(-2) + ':'; result += ('0' + dt.getMinutes()).slice(-2) + ':';
result += ('0' + dt.getSeconds()).slice(-2); result += ('0' + dt.getSeconds()).slice(-2);
//result += ('000' + dt.getMilliseconds()).slice(-3); //result += ('000' + dt.getMilliseconds()).slice(-3);
return result; return result;
} }
}])
.factory('Wait', [ function() {
return function(directive) {
// Display a spinning icon in the center of the screen to freeze the
// UI while waiting on async things to complete (i.e. API calls).
// Wait('start' | 'stop');
if (directive == 'start') {
var docw = $(document).width();
var doch = $(document).height();
var spinnyw = $('.spinny').width();
var spinnyh = $('.spinny').height();
var x = (docw - spinnyw) / 2;
var y = (doch - spinnyh) / 2;
console.log($(document));
$('.overlay').css({
width: $('html').width(),
height: $(document).height() + 200
}).fadeIn(500);
$('.spinny').css({
top: y,
left: x,
}).fadeIn(500);
}
else {
$('.spinny, .overlay').fadeOut(2000);
}
}
}]); }]);

View File

@@ -321,6 +321,9 @@
</div><!-- container --> </div><!-- container -->
<div class="overlay"></div>
<div class="spinny"><i class="icon-cog icon-spin icon-2x"></i> <p>working...</p></div>
<div class="site-footer"> <div class="site-footer">
<div> <div>
<div class="social pull-left"> <div class="social pull-left">