1angular.module("sn.app_common") 2 .service("modelUtil", ['SNAPI', 'TIME', '$rootScope', '$http', '$log', function(SNAPI, TIME, $rootScope, $http, $log) { 3 var modelUtil = this; 4 var DATE_RX = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/; 5 var YMD_RX = /^\d{4}-\d{2}-\d{2}$/; 6 var DEFAULT_GLIDE_LIST_SEPARATOR = ", "; 7 8 // Mapping of legacy ambiguous time zones to equivalent. Taken from Java mappings 9 // See: https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html#SHORT_IDS 10 var SHORT_IDS = { 11 "ACT": "Australia/Darwin", 12 "AET": "Australia/Sydney", 13 "AGT": "America/Argentina/Buenos_Aires", 14 "ART": "Africa/Cairo", 15 "AST": "America/Anchorage", 16 "BET": "America/Sao_Paulo", 17 "BST": "Asia/Dhaka", 18 "CAT": "Africa/Harare", 19 "CNT": "America/St_Johns", 20 "CST": "America/Chicago", 21 "CTT": "Asia/Shanghai", 22 "EAT": "Africa/Addis_Ababa", 23 "ECT": "Europe/Paris", 24 "IET": "America/Indiana/Indianapolis", 25 "IST": "Asia/Kolkata", 26 "JST": "Asia/Tokyo", 27 "MIT": "Pacific/Apia", 28 "NET": "Asia/Yerevan", 29 "NST": "Pacific/Auckland", 30 "PLT": "Asia/Karachi", 31 "PNT": "America/Phoenix", 32 "PRT": "America/Puerto_Rico", 33 "PST": "America/Los_Angeles", 34 "SST": "Pacific/Guadalcanal", 35 "VST": "Asia/Ho_Chi_Minh" 36 }; 37 38 /** 39 * Returns a valid time zone name compensating for ambiguous time zones. 40 * Defaults to UTC if an unsupported value is provided. 41 */ 42 modelUtil.checkTzName = function(tzName) { 43 if (!tzName) 44 return; 45 // Supported values 46 if (moment.tz.zone(tzName) != null) 47 return tzName; 48 // Ambiguous values 49 if (typeof SHORT_IDS[tzName] !== "undefined") 50 return SHORT_IDS[tzName]; 51 // Unknown values 52 return "UTC"; 53 }; 54 55 var dstOffset = {}; 56 /** 57 * Get the DST offset for a timezone for a given timestamp. 58 * Takes into account offsets which are not 1 hour, years/locals without DST etc. 59 * 60 * timestamp: UTC timestamp 61 * tzName: name of the timezone. Defaults to local zone if not present. 62 */ 63 modelUtil.getDSTOffset = function(timestamp, tzName) { 64 var year = new Date(timestamp).getFullYear(); 65 tzName = this.checkTzName(tzName); 66 67 var tzKey = (tzName ? tzName : 'local') + "/" + year; 68 var jan = new Date(year, 0, 1); 69 70 if (dstOffset[tzKey]) 71 return dstOffset[tzKey]; 72 73 if (!tzName) { 74 for (var i = 1; i < 12; i++) { 75 dstOffset[tzKey] = Math.abs(jan.getTimezoneOffset() - (new Date(year,i,1)).getTimezoneOffset()); 76 if (dstOffset[tzKey] != 0) 77 break; 78 } 79 80 return dstOffset[tzKey]; 81 } 82 83 // Same as above but for a defined timezone. 84 var zone = moment.tz.zone(tzName); 85 for (var j = 1; j < 12; j++) { 86 dstOffset[tzKey] = Math.abs(zone.utcOffset(jan.getTime()) - zone.utcOffset((new Date(year, j, 1)).getTime())); 87 if (dstOffset[tzKey] != 0) 88 break; 89 } 90 return dstOffset[tzKey]; 91 }; 92 93 /** 94 * Returns the MS difference between the client local time zone offset and the provided time zone offset. 95 * 96 * timestamp: UTC timestamp 97 * tzName: name of the timezone. Defaults to local offset if not present. 98 */ 99 modelUtil.getTzToLocalMSDiff = function(timestamp, tzName) { 100 if (!tzName) 101 return 0; // No difference if no time zone. 102 103 return (moment.tz.zone(this.checkTzName(tzName)).utcOffset(timestamp) * TIME.MINUTE * -1) - ((new Date(timestamp)).getTimezoneOffset() * TIME.MINUTE * -1); 104 }; 105 106 /** 107 * Patch object with values from record watcher/table API format 108 * Adds in 'value_ms' UTC millisecond value for recognised dates 109 */ 110 modelUtil.patchObject = function(obj, patch) { 111 for (var attr in patch) { 112 var permission; 113 if (obj[attr]) 114 permission = obj[attr]._canWrite; 115 obj[attr] = patch[attr]; 116 if (permission) 117 obj[attr]._canWrite = permission; 118 modelUtil.addValueMS(obj[attr]); 119 } 120 }; 121 122 /** 123 * Adds a value_ms to a date time field. 124 */ 125 modelUtil.addValueMS = function(element) { 126 function strToMS(strDate) { 127 var dtComp = strDate.split(" "); 128 var dComp = dtComp[0].split("-"); //y0, m1, d2 129 var tComp = dtComp[1].split(":"); //h0, mi1, s2 130 return Date.UTC(dComp[0], dComp[1]-1, dComp[2], tComp[0], tComp[1], tComp[2]); 131 } 132 133 function strYMDToMS(strYMD) { 134 var dComp = strYMD.split("-"); 135 return Date.UTC(dComp[0], dComp[1]-1, dComp[2]); 136 } 137 138 // If the value matches a date stamp, add a conversion to MS. 139 if (typeof element.value === "string") { 140 if (element.value.match(DATE_RX)) 141 element.value_ms = strToMS(element.value); 142 else if (element.value.match(YMD_RX)) 143 element.value_ms = strYMDToMS(element.value); 144 else 145 return; //If it's not a date 146 } else 147 return; // If it's not a string 148 149 // Create a forced TZ display_value_ms 150 if (element.tz_name && element.value_ms) { 151 element.display_value_ms = element.value_ms + modelUtil.getTzToLocalMSDiff(element.value_ms, element.tz_name); 152 153 // Adjust display value MS for DST if the value and display value span DST changeover 154 var dispInDST = moment(element.display_value_ms).isDST(); 155 var valInDST = moment(element.value_ms).isDST(); 156 if (dispInDST && !valInDST) 157 element.display_value_ms -= (this.getDSTOffset(element.value_ms) * TIME.MINUTE); 158 else if (!dispInDST && valInDST) 159 element.display_value_ms += (this.getDSTOffset(element.value_ms) * TIME.MINUTE); 160 } 161 162 }; 163 164 /** 165 * Add a value_ms to all date time fields in record 166 */ 167 modelUtil.addValueMSToAll = function(record) { 168 for (var attr in record) 169 modelUtil.addValueMS(record[attr]); 170 }; 171 172 /** 173 * Adds from now/to now display value as display_value_friendly 174 */ 175 modelUtil.addFriendlyDisplayValue = function(element) { 176 if (!element.value_ms) 177 modelUtil.addValueMS(element); 178 179 if (element.value_ms) { // Check if we actually have an ms value 180 if (element.value_ms > Date.now()) 181 element.display_value_friendly = moment(element.value_ms).toNow(); 182 else 183 element.display_value_friendly = moment(element.value_ms).fromNow(); 184 } 185 }; 186 187 /** 188 * Adds a from now/to now display value to all date elements 189 */ 190 modelUtil.addFriendlyDisplayValueToAll = function(record) { 191 for (var attr in record) 192 modelUtil.addFriendlyDisplayValue(record[attr]); 193 }; 194 195 /** 196 * Converts a GlideList representation to JS array. 197 */ 198 modelUtil.glideListToArray = function(element) { 199 if(!angular.isArray(element.display_value)) { 200 if (element.display_value && typeof element.display_value === "string") 201 element.display_value = element.display_value.split(DEFAULT_GLIDE_LIST_SEPARATOR); 202 else 203 element.display_value = []; 204 } 205 206 if(angular.isArray(element.value)) 207 return; 208 209 if (element.value && typeof element.value === "string") 210 element.value = element.value.split(","); 211 else 212 element.value = []; 213 }; 214 215 /** 216 * Simple fail function for REST requests 217 */ 218 modelUtil.failNicely = function(response) { 219 $log.info("REST Failure"); 220 $log.info(response); 221 222 if (!(response.data && response.data.error)) 223 return; 224 225 //If we have any error info try and get any messages 226 $http.get(SNAPI.SERVICE.NOTIFICATION).then(function(response) { 227 if (response.data.result) 228 response.data.result.forEach(function(err){ 229 $rootScope.$broadcast("$$uiNotification", {type: err.type, message: err.text}); 230 }); 231 }, 232 function(response) { 233 $log.info("Notification Failure"); 234 $log.info(response); 235 }); 236 }; 237 238 /** 239 * Simple check if id is 32 bytes of valid hexadecimal 240 */ 241 modelUtil.isValidSysID = function(sysId) { 242 var re = /^[a-f0-9]{32}$/i; 243 return re.test(sysId); 244 }; 245 }]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.