{"version":3,"file":"app-agweb.js","names":["app","_bypassInjectorHeader","_tiosUtil","_globalUtil","enums","vars","angular","module","directive","restrict","scope","value","model","link","e","t","n","on","$apply","checked","$watch","factory","$q","$injector","tiosUtil","request","config","data","dataContainsAsLocals","dataCopy","copy","convertDatesFlaggedAsLocal","headers","response","Error","xhrStatus","global","showError","responseError","rejection","deferred","defer","status","reject","promise","$httpProvider","$anchorScrollProvider","$locationProvider","interceptors","push","defaults","transformResponse","responseData","convertDateStringsToDates","useApplyAsync","disableAutoScrolling","html5Mode","enabled","rewriteLinks","run","$rootScope","$document","$http","globalUtil","util","urls","filter","input","disabled","newlineToBr","plainToHtml","text","stripHTML","groups","require","requireAll","elem","attrs","modelCtrl","requiredAny","groupName","isRequired","group","$on","$id","Object","keys","length","$formatters","validate","$parsers","unshift","$setValidity","pattern","RegExp","test","every","key","determineIfRequired","$timeout","onFocus","$","target","label","min","max","onBlur","msg","match","showConfirm","title","message","callback","select","$setViewValue","parseInt","off","wholenumbers","wholeMin","wholeMax","element","ngModel"],"sources":["angular/app-agweb.js"],"mappings":"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","sourcesContent":["//#region Angular app\r\nvar app;\r\nif (typeof (angular) !== 'undefined') {\r\n (function appAGWeb() {\r\n var _u = 'undefined';\r\n var _f = 'function';\r\n var _o = 'object';\r\n var _$destroy = '$destroy';\r\n var _$interval = '$interval';\r\n var _$http = '$http';\r\n var _$rootScope = '$rootScope';\r\n var _$document = '$document';\r\n var _$timeout = '$timeout';\r\n var _$http = '$http';\r\n var _$filter = '$filter';\r\n var _$sce = '$sce';\r\n var _signalFactory = 'signalFactory';\r\n var _invalid_grant = 'invalid_grant';\r\n var _$q = '$q';\r\n var _post = 'POST';\r\n var _bypassInjectorHeader = 'bypass';\r\n var _tiosUtil = 'tiosUtil';\r\n var _tiosVars = 'tiosVars';\r\n var _tiosCookiecutter = 'tiosCookiecutter';\r\n var _tiosCookies = 'tiosCookies';\r\n var _globalUtil = 'globalUtil';\r\n var _enums = enums;\r\n var _vars = vars;\r\n\r\n //From: https://github.com/jvdvleuten/angular-enum-flag-directive\r\n 'use strict'; angular.module('enumFlag', []).directive('ngEnumFlag', function enumflag() { return { restrict: 'A', scope: { value: '=ngEnumFlag', model: '=ngEnumModel' }, link: function (e, t) { var n = t[0]; t.on('change', function change() { e.$apply(function () { if (n.checked) { e.model += e.value } else { e.model -= e.value } }) }); e.$watch('model', function () { n.checked = (e.model & e.value) == e.value }) } } })\r\n\r\n app = angular.module('agweb', ['tios','globalModule', 'enumFlag', 'ngSanitize']);//includes the above module and sanitize //, 'ngTable', 'angular.filter', 'SignalR'\r\n\r\n app.factory('authInterceptorService', ['$q', '$injector', _tiosUtil, function ($q, $injector, tiosUtil) { //mirror this functionality in global.js $.ajaxSetup for non-angular calls\r\n var $http;\r\n //console.log('creating authinterceptorservice');\r\n\r\n /*\r\n var _saveTokens = function (resp) {\r\n //console.log('_saveTokens');\r\n var _authData = tios.util.getFromStorage(vars.AuthStorageName) || {};\r\n var updated = false;\r\n var expires_in = null;\r\n\r\n if (resp.data) {\r\n var data = resp.data;\r\n if (data.access_token) {\r\n //console.log('updating access token');\r\n //If an access_token is present in a response, save it to storage and memory\r\n _authData.access_token = data.access_token;\r\n\r\n\r\n //Use this if we can need signalR to respond to this cookie instead of the generic auth cookie\r\n //tios.cookiecutter.createCookie(vars.BearerCookieName);\r\n //tios.cookies[vars.BearerCookieName].value = _authData.access_token;\r\n //tios.cookies[vars.BearerCookieName].saveCookie(1);//one day expiration (although it will be updated/expire before that)\r\n\r\n updated = true;\r\n }\r\n\r\n if (data.refresh_token) { //We expect expires_in whenever we get a refresh token\r\n //console.log('updating refresh token');\r\n _authData.refresh_token = data.refresh_token;//Automatically update the auth token in the event that it has change and been returned\r\n updated = true;\r\n }\r\n\r\n if (data.refresh_token_expires_in) {\r\n expires_in = data.refresh_token_expires_in;\r\n }\r\n\r\n if (data.Redirect_page) { // If the api is telling us to redirect immediately, do so (must be after setting access tokens in case of forcing identity update)\r\n global.navApp(urls[data.Redirect_page], true);\r\n }\r\n }\r\n\r\n //Update from header if that value exists (it usually will when coming back from the refresh token service rather than the custom auth override)\r\n if (typeof (resp.headers) === _f) {\r\n var headers = resp.headers();\r\n if (headers['refresh_token_expires_in']) {\r\n expires_in = parseFloat(headers['refresh_token_expires_in']);\r\n }\r\n }\r\n\r\n if (expires_in) {\r\n //console.log('updating refresh token expiry');\r\n _authData.refresh_token_expires_at = tios.util.addSeconds(new Date(), expires_in);\r\n updated = true;\r\n }\r\n\r\n if (updated) tios.util.saveToStorage(vars.AuthStorageName, _authData);\r\n };\r\n\r\n \r\n //Function to retrieve new refresh token when old one has expired\r\n var _getRefreshToken = function () {\r\n var deferred = $q.defer();\r\n\r\n var _authData = tios.util.getFromStorage(vars.AuthStorageName) || {};\r\n //console.log('_getRefreshToken, auth data is:');\r\n //console.log(JSON.stringify(_authData));\r\n\r\n if (_authData && _authData.refresh_token && _authData.refresh_token.length) {\r\n\r\n //_authData.access_token = null;\r\n //tios.util.saveToStorage(authStorageName, _authData);//Delete the auth data, because if it comes back as an error, this is probably invalid now anyway\r\n\r\n $http = $http || $injector.get(_$http);\r\n $http({ url: urls.Api + 'Auth/renew', method: _post, data: { RefreshToken: _authData.refresh_token } })\r\n .then(function success(response) {\r\n //console.log('got refresh token and saved');\r\n //console.log('response in _getRefreshToken', response);\r\n _saveTokens(response);\r\n deferred.resolve(response);\r\n }, function error(err, status) {\r\n //console.log('error getting refresh token');\r\n //console.log(err);\r\n tios.util.removeFromStorage(vars.AuthStorageName);//Removed stored auth due to error\r\n\r\n //Use this if we need signalR to respond to this cookie instead of the generic auth cookie\r\n //tios.cookiecutter.createCookie(vars.BearerCookieName);\r\n //tios.cookies[vars.BearerCookieName].saveCookie(-1);//expire now\r\n\r\n deferred.reject(err);//Auth failed, return an error\r\n });\r\n } else {\r\n deferred.reject();\r\n }\r\n\r\n return deferred.promise;\r\n };\r\n\r\n var _retryHttpRequest = function (config, deferred) { //Try a request again on failure (so that we can re-attempt once authorised)\r\n //console.log('_retryHttpRequest');\r\n $http = $http || $injector.get(_$http);\r\n $http(config).then(function (response) {\r\n deferred.resolve(response);\r\n }, function (response) {\r\n deferred.reject(response);\r\n });\r\n }*/\r\n\r\n var _handleRequest = function handleRequest(config) {\r\n\r\n // Here we check whether the request data has dates tagged with _AsLocal and transform them appropriately.\r\n // If none of the data contains an AsLocal property, don't bother copying (we could end up with munged data\r\n // when using angular copy, as it will attempt to flatten any other kind of request).\r\n if (typeof config.data == _o && tiosUtil.dataContainsAsLocals(config.data)) {\r\n // Copy the data from the request (so we don't modify the data in the caller, which could shunt\r\n // dates there, causing creep when next posting.\r\n var dataCopy = angular.copy(config.data);\r\n tiosUtil.convertDatesFlaggedAsLocal(dataCopy);\r\n config.data = dataCopy;\r\n //tiosUtil.debug('transformed data is', config.data, JSON.stringify(config.data));\r\n }\r\n\r\n // If a specific request has asked to bypass the injector for requests, don't do any of the below code.\r\n // Continue if the bypassInjector header is not present\r\n if (!config.headers[_bypassInjectorHeader]) {\r\n /*\r\n //console.log('_handleRequest');\r\n //add clientTime headers to all requests\r\n var timeInfo = tios.util.clientTimeInfo(vars.OverrideDate);\r\n config.headers['ClientTimeOffset'] = timeInfo.offset;\r\n config.headers['ClientTimeUTC'] = timeInfo.UTCString;\r\n\r\n // Also add the clientToken from the cookie if it's provided (if we added it anyway, 'null' would be set as a string)\r\n var ct = tios.cookiecutter.getValue(vars.ClientCookieName);\r\n if (ct != null) {\r\n config.headers[vars.ClientCookieName] = ct;\r\n }\r\n\r\n\r\n\r\n var _authData = tios.util.getFromStorage(vars.AuthStorageName) || {};//Retrieve auth token from storage and append to the transmission as a header.\r\n if (_authData) {\r\n if (_authData.access_token && _authData.access_token.length) {\r\n config.headers['Authorization'] = 'Bearer ' + _authData.access_token;\r\n }\r\n //Also including the refreshtoken so that the user activity method knows which row to update\r\n if (_authData.refresh_token && _authData.refresh_token.length) {\r\n config.headers['RefreshToken'] = _authData.refresh_token;\r\n }\r\n }*/\r\n } else {\r\n // Remove the header so it isn't passed to an external service\r\n delete (config.headers[_bypassInjectorHeader]);\r\n }\r\n return config;\r\n };\r\n\r\n var _handleResponse = function (response) { // Handles a successful 200 (non-error) response\r\n //console.log('_handleResponse');\r\n //console.log(response);\r\n\r\n if (response) {\r\n /*\r\n //The response contains the login page information, redirect to logout after showing a message\r\n if (typeof response.data === 'string' && response.data.indexOf('id=\"pgLogin\"') > -1) {\r\n //console.log('Redirected to login');\r\n global.sessionEndWarningGlobal();\r\n return $q.reject(response);\r\n } else {\r\n _saveTokens(response); // If the response contains tokens, we'll update them now\r\n }*/\r\n\r\n // Handle the error (exception) condition and hand over, otherwise just return the response to the controller.\r\n // You'd only use this here if not throwing an exception but wanting to prompt with some other info.\r\n // The $http then reject part will still fire in addition to this\r\n if (response && response.data && response.data.Error) {//&& response.data.Exception\r\n //console.log('response handler error');\r\n //console.log(response);\r\n // If the response is anything other than abort (cancelled loading on nav), \r\n // throw an error\r\n if (!response.xhrStatus || response.xhrStatus != 'abort') {\r\n global.showError(response);\r\n }\r\n } else return response;\r\n }\r\n };\r\n\r\n var _getErrorMessage = function (response) {\r\n return (!!response && !!response.data && response.data.error_description ? response.data.error_description : null);\r\n };\r\n\r\n var _handleResponseError = function (rejection) {\r\n //console.log('_handleResponseError', rejection);\r\n\r\n var deferred = $q.defer();\r\n // 401 is unauthorized (as in, for the user authentication, not whether they can act, which would be 403 forbidden)\r\n // it is returned by the auth token having expired - if this is the case, we retry once\r\n if (rejection.status === 401) {\r\n /*\r\n // If this rejection was due to expired token, boot out the user now.\r\n if (rejection.data && rejection.data.refresh_token_expired) {\r\n //console.log('token expired, boot out!');\r\n global.sessionEndWarningGlobal();\r\n }\r\n else if (rejection.data && rejection.data.invalid_grant) {\r\n global.sessionEndWarningGlobal(rejection.data.invalid_grant);\r\n\r\n } else {\r\n //On auth failure, try to get the refresh token then re-send the original request\r\n _getRefreshToken().then(function (response) {\r\n //Try the original request again\r\n //console.log('got refresh token, attempting original call again');\r\n _retryHttpRequest(rejection.config, deferred);\r\n }, function (err) {\r\n //Getting the refresh/auth token failed a second time, log the user out\r\n //console.log('getting refresh token returned failure', err);\r\n\r\n // If there's a special error message, show that\r\n //global.sessionEndWarningGlobal(_getErrorMessage(err));\r\n\r\n // Allow the enclosing method to handle the rejection - the outer clause will catch this again as appropriate\r\n deferred.reject(rejection);\r\n });\r\n }*/\r\n // Not using authentication - added\r\n deferred.reject(rejection);\r\n } else if (rejection.status == 503) {\r\n // on a server unavailable, do not show the error, just reject\r\n deferred.reject(rejection);\r\n } else {\r\n\r\n //console.log('showing error in _handleResponseError');\r\n // Show a warning on all other errors except aborts\r\n\r\n if (!rejection.xhrStatus || rejection.xhrStatus != 'abort') {\r\n global.showError(rejection, 'app-agweb.js _handleResponseError');\r\n }\r\n\r\n // On an error that we haven't caught, pass the rejection message on so that the caller can also handle it.\r\n deferred.reject(rejection);\r\n\r\n }\r\n\r\n return deferred.promise;\r\n };\r\n\r\n return {\r\n request: _handleRequest,\r\n response: _handleResponse,\r\n responseError: _handleResponseError,\r\n };\r\n }]);\r\n\r\n //From: http://aboutcode.net/2013/07/27/json-date-parsing-angularjs.html\r\n app.config(['$httpProvider', _tiosUtil, '$anchorScrollProvider', '$locationProvider', function httprovider($httpProvider, tiosUtil, $anchorScrollProvider, $locationProvider) {\r\n\r\n $httpProvider.interceptors.push('authInterceptorService');\r\n\r\n //transform date strings into actual date object properties (because they come from the server as strings and need to be re-serialized on sending)\r\n // Also converts those returned with AsLocal from UTC times to the same hours local\r\n $httpProvider.defaults.transformResponse.push(function (responseData) {\r\n tiosUtil.convertDateStringsToDates(responseData);\r\n return responseData;\r\n });\r\n\r\n $httpProvider.useApplyAsync(true);//make data that returns at roughly the same time cause only one digest\r\n\r\n // Do not allow angular to handle automatic hash scrolling\r\n $anchorScrollProvider.disableAutoScrolling();\r\n\r\n $locationProvider.html5Mode({\r\n enabled: true, // Makes angular not rewrite # to #!#\r\n rewriteLinks: false // Don't assume SPA mode (allow links to actually navigate)\r\n });\r\n }]);\r\n\r\n app.run([_$rootScope, _$document, _$http, _globalUtil, _tiosUtil, function ($rootScope, $document, $http, globalUtil, tiosUtil) { //adding global utility functions and variables to root scope for app-wide access.\r\n //var _documentClickEvent = 'documentClicked';\r\n\r\n //$http.defaults.useXDomain = true; // Set up for cors (doesn't appear to be necessary)\r\n\r\n $rootScope.util = tiosUtil;\r\n $rootScope.enums = enums;\r\n $rootScope.vars = vars;\r\n $rootScope.urls = urls;\r\n $rootScope.global = globalUtil;\r\n\r\n //add a global document click event (for things that react to being clicked off)\r\n //$document.on('click', function (e) {\r\n // $rootScope.$emit(_documentClickEvent, { element: angular.element(e.target) });\r\n //});\r\n\r\n }]);\r\n\r\n app.filter('newlines', [_tiosUtil, function newlines(tiosUtil) {\r\n return function (input, disabled) {\r\n if (input) {\r\n if (disabled) {//If disabled, just return it as-is\r\n return input;\r\n } else { //Otherwise swap out the newlines with br tags\r\n return tiosUtil.newlineToBr(input);\r\n }\r\n } else {\r\n return '';\r\n }\r\n }\r\n }]);//convert newlines (do before unsafe, eg newlines | unsafe)\r\n\r\n // Convert plaintext to renderable html (so < does not break etc.) but\r\n // cannot take multiple spaces into account.\r\n app.filter('plaintohtml', [_tiosUtil, function plainToHtml(tiosUtil) {\r\n return tiosUtil.plainToHtml\r\n }]);\r\n\r\n app.filter('htmltoplain', [_tiosUtil, function htmltoplain(tiosUtil) {\r\n return function (text) {\r\n return tiosUtil.stripHTML(text);\r\n };\r\n }]);//convert htmltoplain before running newlines if presenting in html output\r\n\r\n app.directive('requiredAny', function requiredAny() {\r\n //Based on: http://stackoverflow.com/questions/24227903/form-validation-required-one-of-many-in-a-group\r\n //expanded to include requiring everything in a group if at least one is filled in - use require-all=\"true\" in that case.\r\n //Hash for holding the state of each group. Expanded to include field pattern validity\r\n var groups = {};\r\n\r\n // Helper function: Determines if at least one control\r\n // in the group is non-empty\r\n function determineIfRequired(groupName, requireAll) {\r\n var group = groups[groupName];\r\n if (!group) return false;\r\n //Is the group flagged as isRequired, or are any of the fields empty/invalid\r\n return Object.keys(group).every(key => requireAll || (key === 'isRequired') || !group[key]);\r\n }\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n scope: {\r\n requireAll: '=?'\r\n }, // an isolate scope is used for easier/cleaner\r\n // $watching and cleanup (on destruction)\r\n link: function postLink(scope, elem, attrs, modelCtrl) {\r\n // If no groupName has been specified, there is nothing we can do\r\n if (!attrs.requiredAny) return;\r\n\r\n // Get a hold on the group's state object\r\n // (if it doesn't exist, initialize it first)\r\n var groupName = attrs.requiredAny;\r\n\r\n if (typeof groups[groupName] === _u) {\r\n groups[groupName] = { isRequired: true };\r\n }\r\n var group = scope.group = groups[groupName];\r\n\r\n // Clean up when the element is removed\r\n scope.$on(_$destroy, function () {\r\n delete (group[scope.$id]);\r\n if (Object.keys(group).length <= 1) {\r\n delete (groups[groupName]);\r\n }\r\n });\r\n\r\n // Updates the group's state and this control's validity\r\n function validate(value) {\r\n group[scope.$id] = !!value &&\r\n (!attrs.pattern || new RegExp(attrs.pattern).test(value));\r\n group.isRequired = determineIfRequired(groupName, scope.requireAll);\r\n return group.isRequired ? '' : value;//Return empty string rather then undefined which causes parse errors.\r\n };\r\n\r\n // Make sure re-validation takes place whenever:\r\n // either the control's value changes\r\n // or the group's `isRequired` property changes\r\n modelCtrl.$formatters.push(validate);\r\n modelCtrl.$parsers.unshift(validate);\r\n scope.$watch('group.isRequired', function () {\r\n modelCtrl.$setValidity(\"required\", !scope.group.isRequired);\r\n });\r\n }\r\n };\r\n });\r\n\r\n\r\n\r\n // Regex check to make sure only whole numbers are passed into a field.\r\n app.directive('wholenumbers', [_globalUtil, '$timeout', function (globalUtil, $timeout) {\r\n function onFocus(e) {\r\n $(e.target).on('blur', {\r\n model: e.data.model,\r\n label: e.data.label,\r\n min: e.data.min,\r\n max: e.data.max\r\n }, onBlur);\r\n }\r\n\r\n function onBlur(e) {\r\n var msg = '';\r\n if (!e.target.value.match(/^\\-?[0-9]*$/gm)) {// Match any non-digit character.\r\n msg = `Please set the value of ${e.data.label} to a whole number`;\r\n } else if (e.target.value < e.data.min) {\r\n msg = `Please set the value of ${e.data.label} to a whole number higher than ${e.data.min}`;\r\n } else if (e.target.value > e.data.max) {\r\n msg = `Please set the value of ${e.data.label} to a whole number lower than ${e.data.max}`;\r\n }\r\n\r\n if (!!msg.length) {\r\n globalUtil.showConfirm({\r\n title: 'Input error',\r\n message: msg,\r\n callback: () => e.target.select()\r\n });\r\n } else {\r\n e.data.model.$setViewValue(!!e.target.value ? parseInt(e.target.value) : null);\r\n }\r\n\r\n $(e.target).off('blur');\r\n }\r\n\r\n return {\r\n restrict: 'A',\r\n require: 'ngModel',\r\n scope: {\r\n wholenumbers: '@',\r\n wholeMin: '