diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000000..9843934c27 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,21 @@ +{ + // Details: https://github.com/victorporof/Sublime-JSHint#using-your-own-jshintrc-options + // Example: https://github.com/jshint/jshint/blob/master/examples/.jshintrc + // Documentation: http://www.jshint.com/docs/ + + "browser": true, + "jquery": true, + "esnext": true, + "globalstrict": true, + "globals": { "angular":false, "alert":false, "$AnsibleConfig":true, "$basePath":true }, + "strict": false, + "quotmark": false, + "smarttabs": true, + "trailing": true, + "undef": true, + "unused": true, + "eqeqeq": true, + "indent": 4, + "onevar": true, + "newcap": false +} diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index ab367b7fc8..046adb3b73 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -6,40 +6,42 @@ * */ +/* jshint devel:true */ + 'use strict'; angular.module('Utilities',['RestServices', 'Utilities']) - .factory('ClearScope', [ function() { - return function(id) { + .factory('ClearScope', [ function() { + return function(id) { - var element = document.getElementById(id); - if (element) { - var scope = angular.element(element).scope(); - scope.$destroy(); - } + var element = document.getElementById(id), scope; + if (element) { + scope = angular.element(element).scope(); + scope.$destroy(); + } - $('.tooltip').each( function(index) { - // Remove any lingering tooltip and popover
elements - $(this).remove(); - }); - - $('.popover').each(function(index) { - // remove lingering popover
. Seems to be a bug in TB3 RC1 - $(this).remove(); - }); + $('.tooltip').each( function() { + // Remove any lingering tooltip and popover
elements + $(this).remove(); + }); - try { - $('#help-modal').dialog('close'); - } - catch(e) { - // ignore - } + $('.popover').each(function() { + // remove lingering popover
. Seems to be a bug in TB3 RC1 + $(this).remove(); + }); - $(window).unbind('resize'); - - } - }]) + try { + $('#help-modal').dialog('close'); + } + catch(e) { + // ignore + } + + $(window).unbind('resize'); + + }; + }]) /* Empty() @@ -48,548 +50,538 @@ angular.module('Utilities',['RestServices', 'Utilities']) * Only works on non-Ojbect types. * */ - .factory('Empty', [ function() { - return function(val) { - return (val === null || val === undefined || val === '') ? true : false; - } - }]) + .factory('Empty', [ function() { + return function(val) { + return (val === null || val === undefined || val === '') ? true : false; + }; + }]) - .factory('ToggleClass', function() { - return function(selector, cssClass) { - // Toggles the existance of a css class on a given element - if ( $(selector) && $(selector).hasClass(cssClass) ) { - $(selector).removeClass(cssClass); - } - else if ($(selector)) { - $(selector).addClass(cssClass); - } - } - }) + .factory('ToggleClass', function() { + return function(selector, cssClass) { + // Toggles the existance of a css class on a given element + if ( $(selector) && $(selector).hasClass(cssClass) ) { + $(selector).removeClass(cssClass); + } + else if ($(selector)) { + $(selector).addClass(cssClass); + } + }; + }) - - .factory('Alert', ['$rootScope', '$location', function($rootScope, $location) { - 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. - // 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 - // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. - if (secondAlert) { - $rootScope.alertHeader2 = hdr; - $rootScope.alertBody2 = msg; - $rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); - $rootScope.disableButtons2 = (disableButtons) ? true : false; - if (action) { - $('#alert-modal2').on('hidden', function() { - action(); - }); - } - $(document).bind('keydown', function(e) { - if (e.keyCode === 27) { - $('#alert-modal2').modal('hide'); + + .factory('Alert', ['$rootScope', function($rootScope) { + 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. + // 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 + // clicks 'OK' button. Set secondAlert to true, when a second dialog is needed. + if (secondAlert) { + $rootScope.alertHeader2 = hdr; + $rootScope.alertBody2 = msg; + $rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger + $('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' }); + $rootScope.disableButtons2 = (disableButtons) ? true : false; if (action) { - action(); + $('#alert-modal2').on('hidden', function() { + action(); + }); } - } - }); - } - else { - $rootScope.alertHeader = hdr; - $rootScope.alertBody = msg; - $rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger - $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); - - $(document).bind('keydown', function(e) { - if (e.keyCode === 27) { - $('#alert-modal').modal('hide'); - if (action) { - action(); - } - } - }); + $(document).bind('keydown', function(e) { + if (e.keyCode === 27) { + $('#alert-modal2').modal('hide'); + if (action) { + action(); + } + } + }); + } + else { + $rootScope.alertHeader = hdr; + $rootScope.alertBody = msg; + $rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger + $('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' }); + + $(document).bind('keydown', function(e) { + if (e.keyCode === 27) { + $('#alert-modal').modal('hide'); + if (action) { + action(); + } + } + }); - $rootScope.disableButtons = (disableButtons) ? true : false; - if (action) { - $('#alert-modal').on('hidden', function() { - action(); - }); - } - } - } - }]) + $rootScope.disableButtons = (disableButtons) ? true : false; + if (action) { + $('#alert-modal').on('hidden', function() { + action(); + }); + } + } + }; + }]) - - .factory('ProcessErrors', ['$rootScope', '$cookieStore', '$log', '$location', 'Alert', 'Wait', - function($rootScope, $cookieStore, $log, $location, Alert, Wait) { - return function(scope, data, status, form, defaultMsg) { - Wait('stop'); - if ($AnsibleConfig.debug_mode && console) { - console.log('Debug status: ' + status); - console.log('Debug data: '); - console.log(data); - } - if (status == 403) { - var msg = 'The API responded with a 403 Access Denied error. '; - if (data['detail']) { - msg += 'Detail: ' + data['detail']; - } - else { - msg += 'Please contact your system administrator.'; - } - Alert(defaultMsg.hdr, msg); - } - else if ( (status == 401 && data.detail && data.detail == 'Token is expired') || - (status == 401 && data.detail && data.detail == 'Invalid token') ) { - $rootScope.sessionTimer.expireSession(); - $location.url('/login'); - } - else if (data.non_field_errors) { - Alert('Error!', data.non_field_errors); - } - else if (data.detail) { - Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); - } - else if (data['__all__']) { - Alert('Error!', data['__all__']); - } - else if (form) { - var fieldErrors = false; - for (var field in form.fields ) { - if (data[field] && form.fields[field].tab) { - // If the form is part of a tab group, activate the tab - $('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show'); - } - if (form.fields[field].realName) { - if (data[form.fields[field].realName]) { - scope[field + '_api_error'] = data[form.fields[field]][0]; - //scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false); - $('[name="' + form.fields[field].realName + '"]').addClass('ng-invalid'); - fieldErrors = true; - } - } - if (form.fields[field].sourceModel) { - if (data[field]) { - scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = - data[field][0]; - //scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false); - $('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').addClass('ng-invalid'); - fieldErrors = true; - } - } - else { - if (data[field]) { - scope[field + '_api_error'] = data[field][0]; - //scope[form.name + '_form'][field].$setValidity('apiError', false); - $('[name="' + field + '"]').addClass('ng-invalid'); - fieldErrors = true; - } - } - } - if ( (!fieldErrors) && defaultMsg) { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } - else { - Alert(defaultMsg.hdr, defaultMsg.msg); - } - } - }]) - - .factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', 'Empty', - function($rootScope, $routeParams, $location, Empty) { - return function(crumb) { - var title, found, j, i; - - //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 (!Empty(crumb)) { - found = false; - //crumb.title = crumb.title.charAt(0).toUpperCase() + crumb.title.slice(1); - for (i=0; i < $rootScope.crumbCache.length; i++) { - if ($rootScope.crumbCache[i].path == crumb.path) { - found = true; - $rootScope.crumbCache[i] = crumb; - break; - } - } - if (!found) { - $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'; + .factory('ProcessErrors', ['$rootScope', '$cookieStore', '$log', '$location', 'Alert', 'Wait', + function($rootScope, $cookieStore, $log, $location, Alert, Wait) { + return function(scope, data, status, form, defaultMsg) { + var field, fieldErrors, msg; + Wait('stop'); + if ($AnsibleConfig.debug_mode && console) { + console.log('Debug status: ' + status); + console.log('Debug data: '); + console.log(data); + } + if (status === 403) { + msg = 'The API responded with a 403 Access Denied error. '; + if (data.detail) { + msg += 'Detail: ' + data.detail; + } + else { + msg += 'Please contact your system administrator.'; + } + Alert(defaultMsg.hdr, msg); + } + else if ( (status === 401 && data.detail && data.detail === 'Token is expired') || + (status === 401 && data.detail && data.detail === 'Invalid token') ) { + $rootScope.sessionTimer.expireSession(); + $location.url('/login'); + } + else if (data.non_field_errors) { + Alert('Error!', data.non_field_errors); + } + else if (data.detail) { + Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail); + } + else if (data.__all__) { + Alert('Error!', data.__all__); + } + else if (form) { + fieldErrors = false; + for (field in form.fields ) { + if (data[field] && form.fields[field].tab) { + // If the form is part of a tab group, activate the tab + $('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show'); + } + if (form.fields[field].realName) { + if (data[form.fields[field].realName]) { + scope[field + '_api_error'] = data[form.fields[field]][0]; + //scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false); + $('[name="' + form.fields[field].realName + '"]').addClass('ng-invalid'); + fieldErrors = true; + } + } + if (form.fields[field].sourceModel) { + if (data[field]) { + scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] = + data[field][0]; + //scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false); + $('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').addClass('ng-invalid'); + fieldErrors = true; + } + } + else { + if (data[field]) { + scope[field + '_api_error'] = data[field][0]; + //scope[form.name + '_form'][field].$setValidity('apiError', false); + $('[name="' + field + '"]').addClass('ng-invalid'); + fieldErrors = true; + } + } + } + if ((!fieldErrors) && defaultMsg) { + Alert(defaultMsg.hdr, defaultMsg.msg); + } } else { - child = parent.substring(0,parent.length - 1); //assumes parent ends with 's' - child = child.charAt(0).toUpperCase() + child.slice(1); + Alert(defaultMsg.hdr, defaultMsg.msg); } - // find the correct title - found = false; - for (var j=0; j < $rootScope.crumbCache.length; j++) { - if ($rootScope.crumbCache[j].path == '/' + parent + '/' + paths[i]) { - child = $rootScope.crumbCache[j].title; - found = true; - break; + }; + }]) + + + .factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', 'Empty', + function($rootScope, $routeParams, $location, Empty) { + return function(crumb) { + + var title, found, j, i, paths, ppath, parent, child; + + function toUppercase(a) { + return a.toUpperCase(); + } + + function singular(a) { + return (a === 'ies') ? 'y' : ''; + } + + //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 (!Empty(crumb)) { + found = false; + //crumb.title = crumb.title.charAt(0).toUpperCase() + crumb.title.slice(1); + for (i=0; i < $rootScope.crumbCache.length; i++) { + if ($rootScope.crumbCache[i].path === crumb.path) { + found = true; + $rootScope.crumbCache[i] = crumb; + break; + } + } + if (!found) { + $rootScope.crumbCache.push(crumb); } } - if (found && $rootScope.crumbCache[j]['altPath'] !== undefined) { - // Use altPath to override default path construction - $rootScope.breadcrumbs.push({ title: child, path: $rootScope.crumbCache[j].altPath }); - } - else { - $rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] }); - /*if (paths[i - 1] == 'hosts') { - // For hosts, there is no /hosts, so we need to link back to the inventory - // We end up here when user has clicked refresh and the crumbcache is missing - $rootScope.breadcrumbs.push({ title: child, - path: '/inventories/' + $routeParams.inventory + '/hosts' }); + paths = $location.path().replace(/^\//,'').split('/'); + ppath = ''; + $rootScope.breadcrumbs = []; + if (paths.length > 1) { + for (i=0; i < paths.length - 1; i++) { + if (i > 0 && paths[i].match(/\d+/)) { + parent = paths[i-1]; + child = parent.replace(/(ies$|s$)/, singular); + child = child.charAt(0).toUpperCase() + child.slice(1); + // find the correct title + found = false; + for (j=0; j < $rootScope.crumbCache.length; j++) { + if ($rootScope.crumbCache[j].path === '/' + parent + '/' + paths[i]) { + child = $rootScope.crumbCache[j].title; + found = true; + break; + } + } + + if (found && $rootScope.crumbCache[j].altPath !== undefined) { + // Use altPath to override default path construction + $rootScope.breadcrumbs.push({ title: child, path: $rootScope.crumbCache[j].altPath }); + } + else { + $rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] }); + } + } + else { + if (/_/.test(paths[i])) { + // replace '_' with space and uppercase each word + paths[i] = paths[i].replace(/(?:^|_)\S/g, toUppercase) + .replace(/_/g,' '); + } + title = paths[i].charAt(0).toUpperCase() + paths[i].slice(1); + $rootScope.breadcrumbs.push({ title: title, path: ppath + '/' + paths[i] }); + } + ppath += '/' + paths[i]; } - else { */ + } + }; + }]) + + .factory('HelpDialog', ['$rootScope', '$location', 'Store', function($rootScope, $location, Store) { + return function(params) { + // Display a help dialog + // + // HelpDialog({ defn: }) + // + + var defn = params.defn, + current_step = params.step, + autoShow = params.autoShow || false; + + function showHelp(step) { + + var btns, ww, width, height, isOpen=false; + current_step = step; - //} + function buildHtml(step) { + var html = ''; + //html += (step.intro) ? "
" + step.intro + "
" : ""; + html += "

" + step.intro + "

\n"; + html += "
\n"; + html += ""; + html += "
\n"; + html += "
" + step.box + "
"; + html += (autoShow && step.autoOffNotice) ? "
\n" : ""; + return html; } - } - else { - title = paths[i].charAt(0).toUpperCase() + paths[i].slice(1); - $rootScope.breadcrumbs.push({ title: title, path: ppath + '/' + paths[i] }); - /*if (paths[i] == 'hosts') { - $rootScope.breadcrumbs.push({ title: paths[i], path: '/inventories/' + $routeParams.inventory + - '/hosts' }); - } - else {*/ - //} - } - ppath += '/' + paths[i]; - } - } - } - }]) - .factory('HelpDialog', ['$rootScope', '$location', 'Store', function($rootScope, $location, Store) { - return function(params) { - // Display a help dialog - // - // HelpDialog({ defn: }) - // - - var defn = params.defn; - var current_step = params.step; - var autoShow = params.autoShow || false; - - function showHelp(step) { - var width, height, isOpen=false; - current_step = step; - - function buildHtml(step) { - var html = ''; - //html += (step.intro) ? "
" + step.intro + "
" : ""; - html += "

" + step.intro + "

\n"; - html += "
\n"; - html += ""; - html += "
\n"; - html += "
" + step.box + "
"; - html += (autoShow && step.autoOffNotice) ? "
\n" : ""; - return html; - } - - width = (defn.story.width) ? defn.story.width : 510; - height = (defn.story.height) ? defn.story.height : 600; - - // Limit modal width to width of viewport - var ww = $(document).width(); - width = (width > ww) ? ww : width; + width = (defn.story.width) ? defn.story.width : 510; + height = (defn.story.height) ? defn.story.height : 600; - try { - isOpen = $('#help-modal').dialog('isOpen'); - } - catch(e) { - // ignore - } - - if (isOpen) { - $('#help-modal').html(buildHtml(defn.story.steps[current_step])); - } - else { - // Define buttons based on story length - var btns = []; - if (defn.story.steps.length > 1) { - btns.push({ - text: "Prev", - click: function(e, ui) { - if (current_step - 1 == 0) { - $(e.target).button('disable'); - } - if (current_step - 1 < defn.story.steps.length - 1) { - $(e.target).next().button('enable'); - } - showHelp(current_step - 1); - }, - disabled: true - }); - btns.push({ - text: "Next", - click: function(e, ui) { - if (current_step + 1 > 0) { - $(e.target).prev().button('enable'); - } - if (current_step + 1 == defn.story.steps.length - 1) { - $(e.target).button('disable'); - } - showHelp(current_step + 1); - } - }); - } - btns.push({ text: "Close", - click: function() { $('#help-modal').dialog('close'); } - }); - // Show the dialog - $('#help-modal').html(buildHtml(defn.story.steps[current_step])).dialog({ - position: { my: "center top", at: "center top+150", of: 'body' }, - title: defn.story.hdr, - width: width, - height: height, - buttons: btns, - closeOnEscape: true, - show: 500, - hide: 500, - resizable: false, - close: function() { $('#help-modal').empty(); } - }); + // Limit modal width to width of viewport + ww = $(document).width(); + width = (width > ww) ? ww : width; + + try { + isOpen = $('#help-modal').dialog('isOpen'); + } + catch(e) { + // ignore + } + + if (isOpen) { + $('#help-modal').html(buildHtml(defn.story.steps[current_step])); + } + else { + // Define buttons based on story length + btns = []; + if (defn.story.steps.length > 1) { + btns.push({ + text: "Prev", + click: function(e) { + if (current_step - 1 === 0) { + $(e.target).button('disable'); + } + if (current_step - 1 < defn.story.steps.length - 1) { + $(e.target).next().button('enable'); + } + showHelp(current_step - 1); + }, + disabled: true + }); + btns.push({ + text: "Next", + click: function(e) { + if (current_step + 1 > 0) { + $(e.target).prev().button('enable'); + } + if (current_step + 1 === defn.story.steps.length - 1) { + $(e.target).button('disable'); + } + showHelp(current_step + 1); + } + }); + } + btns.push({ text: "Close", + click: function() { $('#help-modal').dialog('close'); } + }); + // Show the dialog + $('#help-modal').html(buildHtml(defn.story.steps[current_step])).dialog({ + position: { my: "center top", at: "center top+150", of: 'body' }, + title: defn.story.hdr, + width: width, + height: height, + buttons: btns, + closeOnEscape: true, + show: 500, + hide: 500, + resizable: false, + close: function() { $('#help-modal').empty(); } + }); - // Make the buttons look like TB and add FA icons - $('.ui-dialog-buttonset button').each( function(idx) { - var c, h, l; - l = $(this).text(); - if (l === 'Close') { - h = "fa-times"; - c = "btn btn-default"; - $(this).attr({ 'class': c }).html(" Close"); - } - else if (l === 'Prev') { - h = "fa-chevron-left"; - c = "btn btn-primary"; - $(this).attr({ 'class': c }).html(" Prev"); - } - else { - h = "fa-chevron-right"; - c = "btn btn-primary"; - $(this).attr({ 'class': c }).html("Next ").css({ 'margin-right': '20px'}); - } - }); + // Make the buttons look like TB and add FA icons + $('.ui-dialog-buttonset button').each( function() { + var c, h, l; + l = $(this).text(); + if (l === 'Close') { + h = "fa-times"; + c = "btn btn-default"; + $(this).attr({ 'class': c }).html(" Close"); + } + else if (l === 'Prev') { + h = "fa-chevron-left"; + c = "btn btn-primary"; + $(this).attr({ 'class': c }).html(" Prev"); + } + else { + h = "fa-chevron-right"; + c = "btn btn-primary"; + $(this).attr({ 'class': c }).html("Next ").css({ 'margin-right': '20px'}); + } + }); - $('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button') - .empty().attr({ 'class': 'close' }).text('x'); + $('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button') + .empty().attr({ 'class': 'close' }).text('x'); - // If user clicks the checkbox, update local storage - $('#auto-off-checkbox').click(function() { - if ($('input[name="auto-off-checkbox"]:checked').length) { - Store('inventoryAutoHelp','off'); - } - else { - Store('inventoryAutoHelp','on'); - } - }); - } - } + // If user clicks the checkbox, update local storage + $('#auto-off-checkbox').click(function() { + if ($('input[name="auto-off-checkbox"]:checked').length) { + Store('inventoryAutoHelp','off'); + } + else { + Store('inventoryAutoHelp','on'); + } + }); + } + } - showHelp(0); + showHelp(0); - } - }]) + }; + }]) - .factory('ReturnToCaller', ['$location', function($location) { - return function(idx) { - // 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. - - var paths = $location.path().replace(/^\//,'').split('/'); - var newpath = ''; - idx = (idx == null || idx == undefined) ? paths.length - 1 : idx + 1; - for (var i=0; i < idx; i++) { - newpath += '/' + paths[i] - } - $location.path(newpath); - } - }]) + .factory('ReturnToCaller', ['$location', 'Empty', function($location, Empty) { + return function(idx) { + // 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. - .factory('FormatDate', [ function() { - return function(dt) { - var result = ('0' + (dt.getMonth() + 1)).slice(-2) + '/'; - result += ('0' + dt.getDate()).slice(-2) + '/'; - result += ('0' + (dt.getFullYear() - 2000)).slice(-2) + ' '; - result += ('0' + dt.getHours()).slice(-2) + ':'; - result += ('0' + dt.getMinutes()).slice(-2) + ':'; - result += ('0' + dt.getSeconds()).slice(-2); - //result += ('000' + dt.getMilliseconds()).slice(-3); - return result; - } - }]) + var paths = $location.path().replace(/^\//,'').split('/'), + newpath = '', i; + idx = (Empty(idx)) ? paths.length - 1 : idx + 1; + for (i=0; i < idx; i++) { + newpath += '/' + paths[i]; + } + $location.path(newpath); + }; + }]) - .factory('Wait', [ '$rootScope', function($rootScope) { - 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' && !$rootScope.waiting) { - $rootScope.waiting = true; - var docw = $(window).width(); - var doch = $(window).height(); - var spinnyw = $('.spinny').width(); - var spinnyh = $('.spinny').height(); - var x = (docw - spinnyw) / 2; - var y = (doch - spinnyh) / 2; - $('.overlay').css({ - width: $(document).width(), - height: $(document).height() - }).fadeIn(); - $('.spinny').css({ top: y, left: x }).fadeIn(400); - } - else if (directive == 'stop' && $rootScope.waiting){ - $('.spinny, .overlay').fadeOut(400, function(){ $rootScope.waiting = false; }); - } - } - }]) + .factory('FormatDate', ['$filter', function($filter) { + return function(dt) { + // Wrapper for data filter- an attempt to insure all dates display in + // the same format. Pass in date object. + return $filter('date')(dt, 'MM/dd/yy HH:mm:ss'); + }; + }]) + + .factory('Wait', [ '$rootScope', function($rootScope) { + 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'); + var docw, doch, spinnyw, spinnyh, x, y; + if (directive === 'start' && !$rootScope.waiting) { + $rootScope.waiting = true; + docw = $(window).width(); + doch = $(window).height(); + spinnyw = $('.spinny').width(); + spinnyh = $('.spinny').height(); + x = (docw - spinnyw) / 2; + y = (doch - spinnyh) / 2; + $('.overlay').css({ + width: $(document).width(), + height: $(document).height() + }).fadeIn(); + $('.spinny').css({ top: y, left: x }).fadeIn(400); + } + else if (directive === 'stop' && $rootScope.waiting){ + $('.spinny, .overlay').fadeOut(400, function(){ $rootScope.waiting = false; }); + } + }; + }]) - .factory('HideElement', [ function() { - return function(selector, action) { - // Fade-in a cloack or vail or a specific element - var target = $(selector); - var width = target.css('width'); - var height = target.css('height'); - var position = target.position(); - var parent = target.parent(); - var borderRadius = target.css('border-radius'); - var backgroundColor = target.css('background-color'); - var margin = target.css('margin'); - var padding = target.css('padding'); - parent.append("
"); - $('#curtain-div').show(0, action); - } - }]) - - .factory('ShowElement', [ function() { - return function() { - // And Fade-out the cloack revealing the element - $('#curtain-div').fadeOut(500, function() { $(this).remove(); }); - } - }]) - - .factory('GetChoices', [ 'Rest', 'ProcessErrors', function(Rest, ProcessErrors) { - return function(params) { - // Get dropdown options - - var scope = params.scope; - var url = params.url; - var field = params.field; - var variable = params.variable; - var callback = params.callback; // Optional. Provide if you want scop.$emit on completion. - var choice_name = params.choice_name; // Optional. Used when data is in something other than 'choices' + .factory('HideElement', [ function() { + return function(selector, action) { + // Fade-in a cloack or vail or a specific element + var target = $(selector), + width = target.css('width'), + height = target.css('height'), + position = target.position(), + parent = target.parent(), + borderRadius = target.css('border-radius'), + backgroundColor = target.css('background-color'), + margin = target.css('margin'), + padding = target.css('padding'); - if (scope[variable]) { - scope[variable].length = 0; - } - else { - scope[variable] = []; - } - - Rest.setUrl(url); - Rest.options() - .success( function(data, status, headers, config) { - var choices = (choice_name) ? data.actions.GET[field][choice_name] : data.actions.GET[field].choices - // including 'name' property so list can be used by search - for (var i=0; i < choices.length; i++) { - scope[variable].push({ label: choices[i][1], value: choices[i][0], name: choices[i][1]}); - } - if (callback) { - scope.$emit(callback); - } - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to get ' + url + '. GET status: ' + status }); - }); - } - }]) + parent.append("
"); + $('#curtain-div').show(0, action); + }; + }]) + + .factory('ShowElement', [ function() { + return function() { + // And Fade-out the cloack revealing the element + $('#curtain-div').fadeOut(500, function() { $(this).remove(); }); + }; + }]) + + .factory('GetChoices', [ 'Rest', 'ProcessErrors', function(Rest, ProcessErrors) { + return function(params) { + // Get dropdown options + + var scope = params.scope, + url = params.url, + field = params.field, + variable = params.variable, + callback = params.callback, // Optional. Provide if you want scop.$emit on completion. + choice_name = params.choice_name; // Optional. Used when data is in something other than 'choices' + + if (scope[variable]) { + scope[variable].length = 0; + } + else { + scope[variable] = []; + } + + Rest.setUrl(url); + Rest.options() + .success( function(data) { + var choices, i; + choices = (choice_name) ? data.actions.GET[field][choice_name] : data.actions.GET[field].choices; + // including 'name' property so list can be used by search + for (i=0; i < choices.length; i++) { + scope[variable].push({ label: choices[i][1], value: choices[i][0], name: choices[i][1]}); + } + if (callback) { + scope.$emit(callback); + } + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get ' + url + '. GET status: ' + status }); + }); + }; + }]) - /* + /* * Search an array of objects, returning the matchting object or null * * Find({ list: [], key: "key", val: }); */ - .factory('Find', [ function(){ - return function(params) { - var list = params.list; - var key = params.key; - var val = params.val; - var found = false; - if (typeof list == 'object' && Array.isArray(list)) { - for (var i=0; i < params.list.length; i++) { - if (list[i][key] == val) { - found = true; - break; - } - } - return (found) ? list[i] : null; - } - else { - // list parameter is not an array - return null; - } - - } - }]) + .factory('Find', [ function(){ + return function(params) { + var list = params.list, + key = params.key, + val = params.val, + found = false, i; + if (typeof list === 'object' && Array.isArray(list)) { + for (i=0; i < params.list.length; i++) { + if (list[i][key] === val) { + found = true; + break; + } + } + return (found) ? list[i] : null; + } + return null; + }; + }]) - /* - * DeugForm({ form:
, scope: }); - * - * Use to log the $pristine and $valid properties of each form element. Helpful when form - * buttons fail to enable/disable properly. - * - */ - .factory('DebugForm', [ function() { - return function(params) { - var form = params.form; - var scope = params.scope; - for (var fld in form.fields) { - if (scope[form.name + '_form'][fld]) { - console.log(fld + ' valid: ' + scope[form.name + '_form'][fld].$valid); - } - if (form.fields[fld].sourceModel) { - if (scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]) { - console.log(form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField + ' valid: ' + - scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField].$valid); - } - } - } - console.log('form pristine: ' + scope[form.name + '_form'].$pristine); - console.log('form valid: ' + scope[form.name + '_form'].$valid); - } - }]) + /* + * DeugForm({ form: , scope: }); + * + * Use to log the $pristine and $valid properties of each form element. Helpful when form + * buttons fail to enable/disable properly. + * + */ + .factory('DebugForm', [ function() { + return function(params) { + var form = params.form, + scope = params.scope, fld; + for (fld in form.fields) { + if (scope[form.name + '_form'][fld]) { + console.log(fld + ' valid: ' + scope[form.name + '_form'][fld].$valid); + } + if (form.fields[fld].sourceModel) { + if (scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]) { + console.log(form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField + ' valid: ' + + scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField].$valid); + } + } + } + console.log('form pristine: ' + scope[form.name + '_form'].$pristine); + console.log('form valid: ' + scope[form.name + '_form'].$valid); + }; + }]) /* Store @@ -604,20 +596,19 @@ angular.module('Utilities',['RestServices', 'Utilities']) * store(key) retrieves the value of the key * */ - .factory('Store', ['Empty', function(Empty) { - return function(key, value) { - if (!Empty(value)) { - // Store the value - localStorage[key] = JSON.stringify(value); - } - else if (!Empty(key)) { - // Return the value - var val = localStorage[key]; - return (!Empty(val)) ? JSON.parse(val) : null; - } - - } - }]) + .factory('Store', ['Empty', function(Empty) { + return function(key, value) { + if (!Empty(value)) { + // Store the value + localStorage[key] = JSON.stringify(value); + } + else if (!Empty(key)) { + // Return the value + var val = localStorage[key]; + return (!Empty(val)) ? JSON.parse(val) : null; + } + }; + }]) /* * @@ -625,48 +616,47 @@ angular.module('Utilities',['RestServices', 'Utilities']) * */ .factory('ApplyEllipsis', [ function() { - return function(selector) { - // Add a hidden element to the DOM. We'll use this to calc the px length of - // our target text. - var tmp = $('#string-test'); - if (!tmp.length) { - $('body').append(''); - tmp = $('#string-test'); - } - // Find and process the text. - $(selector).each(function() { - var setTitle = true; - var txt; - if ($(this).attr('title')) { - txt = $(this).attr('title'); - setTitle = false; + return function(selector) { + // Add a hidden element to the DOM. We'll use this to calc the px length of + // our target text. + var tmp = $('#string-test'); + if (!tmp.length) { + $('body').append(''); + tmp = $('#string-test'); } - else { - txt = $(this).text(); - } - tmp.text(txt); - var w = tmp.width(); //text width - var pw = $(this).parent().width(); //parent width - if (w > pw) { - // text is wider than parent width - if (setTitle) { - // Save the original text in the title - $(this).attr('title',txt); + // Find and process the text. + $(selector).each(function() { + var setTitle = true, txt, w, pw, cw, df; + if ($(this).attr('title')) { + txt = $(this).attr('title'); + setTitle = false; + } + else { + txt = $(this).text(); + } + tmp.text(txt); + w = tmp.width(); //text width + pw = $(this).parent().width(); //parent width + if (w > pw) { + // text is wider than parent width + if (setTitle) { + // Save the original text in the title + $(this).attr('title',txt); + } + cw = w / txt.length; // px width per character + df = w - pw; // difference in px + txt = txt.substr(0, txt.length - (Math.ceil(df / cw) + 3)); + $(this).text(txt + '...'); + } + if (pw > w && !setTitle) { + // the parent has expanded and we previously set the title text + txt = $(this).attr('title'); + $(this).text(txt); } - var cw = w / txt.length; // px width per character - var df = w - pw; // difference in px - txt = txt.substr(0, txt.length - (Math.ceil(df / cw) + 3)); - $(this).text(txt + '...'); - } - if (pw > w && !setTitle) { - // the parent has expanded and we previously set the title text - var txt = $(this).attr('title'); - $(this).text(txt); - } }); - } - }]); + }; + }]);