1'use strict'; 2var __assign = (this && this.__assign) || function () { 3 __assign = Object.assign || function(t) { 4 for (var s, i = 1, n = arguments.length; i < n; i++) { 5 s = arguments[i]; 6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 7 t[p] = s[p]; 8 } 9 return t; 10 }; 11 return __assign.apply(this, arguments); 12}; 13var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 14 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 15 return new (P || (P = Promise))(function (resolve, reject) { 16 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 17 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 18 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 19 step((generator = generator.apply(thisArg, _arguments || [])).next()); 20 }); 21}; 22var __generator = (this && this.__generator) || function (thisArg, body) { 23 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 24 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 25 function verb(n) { return function (v) { return step([n, v]); }; } 26 function step(op) { 27 if (f) throw new TypeError("Generator is already executing."); 28 while (g && (g = 0, op[0] && (_ = 0)), _) try { 29 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 30 if (y = 0, t) op = [op[0] & 2, t.value]; 31 switch (op[0]) { 32 case 0: case 1: t = op; break; 33 case 4: _.label++; return { value: op[1], done: false }; 34 case 5: _.label++; y = op[1]; op = [0]; continue; 35 case 7: op = _.ops.pop(); _.trys.pop(); continue; 36 default: 37 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 38 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 39 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 40 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 41 if (t[2]) _.ops.pop(); 42 _.trys.pop(); continue; 43 } 44 op = body.call(thisArg, _); 45 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 46 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 47 } 48}; 49var __rest = (this && this.__rest) || function (s, e) { 50 var t = {}; 51 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) 52 t[p] = s[p]; 53 if (s != null && typeof Object.getOwnPropertySymbols === "function") 54 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { 55 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) 56 t[p[i]] = s[p[i]]; 57 } 58 return t; 59}; 60var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { 61 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { 62 if (ar || !(i in from)) { 63 if (!ar) ar = Array.prototype.slice.call(from, 0, i); 64 ar[i] = from[i]; 65 } 66 } 67 return to.concat(ar || Array.prototype.slice.call(from)); 68}; 69var authComponents = angular.module('authComponents', []); 70authComponents.component('googleSignIn', { 71 template: '<div id="{{ $ctrl.buttonId }}"></div>', 72 controller: function (CONFIG, $http, $vhttp, $timeout, vSession, Dialogs) { 73 var $ctrl = this; 74 var gAuth; 75 $ctrl.buttonId = 'g-signin'; 76 $ctrl.$onInit = function () { 77 gAuth = gapi.auth2.getAuthInstance(); 78 $timeout(function () { 79 gapi.signin2.render($ctrl.buttonId, { 80 scope: 'profile email', 81 longtitle: true, 82 }); 83 }); 84 if (gAuth.isSignedIn.get()) { 85 $ctrl.signInChange(true); 86 } 87 gAuth.isSignedIn.listen($ctrl.signInChange); 88 }; 89 $ctrl.signInChange = function (signedIn) { 90 if (signedIn) { 91 $vhttp 92 .post('/sso/google', { 93 token: gAuth.currentUser.get().getAuthResponse().id_token, 94 }) 95 .then(function (res) { 96 delete $http.defaults.headers.common.Authorization; 97 vSession.refresh(); 98 }) 99 .catch(function (err) { 100 gAuth.disconnect(); 101 Dialogs.alert('Unauthorized: User account was not found.'); 102 }); 103 } 104 }; 105 }, 106}); 107; 108'use strict';
109var chartModule = angular.module('chartComponents', []); 110chartModule.component('timeSeriesChart', timeSeriesChartComponent()); 111chartModule.service('ChartUtilityService', ChartUtilityService); 112chartModule.directive('kendoChartResizeObserver', kendoChartResizeObserver); 113function kendoChartResizeObserver() { 114 return { 115 require: 'kendoChart', 116 restrict: 'A', 117 link: function (scope, element, attrs) { 118 var resizeObserver = new ResizeObserver(function (entries) { 119 for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) { 120 var entry = entries_1[_i]; 121 if (entry.target === element[0]) { 122 var chart = element.data('kendoChart'); 123 if (chart) { 124 chart.redraw(); 125 } 126 } 127 } 128 }); 129 resizeObserver.observe(element[0]); 130 scope.$on('$destroy', function () { 131 resizeObserver.disconnect(); 132 }); 133 }, 134 }; 135} 136function ChartUtilityService() { 137 var UTIL = {}; 138 UTIL.CHART_THEME = 'metro'; 139 UTIL.GRANULARITY_TYPES = { 140 AUTO: 'Auto', 141 MINUTES: 'Minutes', 142 HOURS: 'Hours', 143 DAYS: 'Days', 144 WEEKS: 'Weeks', 145 MONTHS: 'Months', 146 }; 147 UTIL.CHART_TYPES = { 148 AREA: 'area', 149 BAR: 'bar', 150 COLUMN: 'column', 151 LINE: 'line', 152 WATERFALL: 'waterfall', 153 }; 154 UTIL.TIME_RANGE_TYPES = { 155 SYNC_WITH_REPORT: 'Sync With Report', 156 LAST_7_DAYS: 'Last 7 Days', 157 LAST_WEEK: 'Last Week', 158 LAST_30_DAYS: 'Last 30 Days', 159 }; 160 UTIL.DEFAULT_TIME_RANGE = UTIL.TIME_RANGE_TYPES.SYNC_WITH_REPORT; 161 UTIL.DEFAULT_TIME_RANGE_OPTIONS = _.values(UTIL.TIME_RANGE_TYPES); 162 UTIL.CHART_AGGREGATES = { 163 SUM: 'sum', 164 AVG: 'avg', 165 MIN: 'min', 166 MAX: 'max', 167 COUNT: 'count', 168 }; 169 UTIL.TS_REPORT_AGGREGATES = { 170 FIRST: 'First', 171 LAST: 'Last', 172 MIN: 'Min', 173 MAX: 'Max', 174 SUM: 'Sum', 175 AVG: 'Avg', 176 COUNT: 'Count', 177 }; 178 UTIL.DAY_CATEGORY_FILTER_OPTIONS = __spreadArray([ 179 { name: 'All', value: null }, 180 { name: 'Weekdays', value: '2,3,4,5,6' }, 181 { name: 'Weekends', value: '1,7' } 182 ], _.map(moment.weekdays(), function (day, i) { return ({ name: day, value: "".concat(i + 1) }); }), true); 183 UTIL.CHART_OPTIONS = { 184 DEFAULT_GRANULARITY_OPTIONS: _.values(UTIL.GRANULARITY_TYPES), 185 DEFAULT_CHART_TYPES: _.without(_.values(UTIL.CHART_TYPES), UTIL.CHART_TYPES.WATERFALL), 186 DEFAULT_CATEGORY_OPTIONS: [ 187 UTIL.GRANULARITY_TYPES.DAYS, 188 UTIL.GRANULARITY_TYPES.HOURS, 189 ], 190 }; 191 UTIL.TOOLBAR_DEFAULTS = { 192 showToolbar: true, 193 showVizList: true, 194 showChartTypes: true, 195 showTimeRange: false, 196 showDayCategoryFilter: false, 197 defaultCategoryFilter: null, 198 categoryFilterOptions: UTIL.DAY_CATEGORY_FILTER_OPTIONS, 199 timeRangeOptions: UTIL.DEFAULT_TIME_RANGE_OPTIONS, 200 defaultTimeRange: UTIL.DEFAULT_TIME_RANGE, 201 chartTypes: UTIL.CHART_OPTIONS.DEFAULT_CHART_TYPES, 202 showDateRange: true, 203 showGranularity: true, 204 defaultGranularity: UTIL.GRANULARITY_TYPES.AUTO, 205 granularityOptions: UTIL.CHART_OPTIONS.DEFAULT_GRANULARITY_OPTIONS, 206 defaultCategoryField: 'dateTime', 207 showLineSmoothing: true, 208 exportToPNG: true, 209 exportToPDF: true, 210 exportToSVG: true, 211 }; 212 UTIL.TIME_SERIES_CHART_DEFAULTS = { 213 theme: UTIL.CHART_THEME, 214 legend: { 215 position: 'bottom', 216 }, 217 seriesDefaults: { 218 type: UTIL.CHART_TYPES.AREA, 219 style: 'smooth', 220 aggregate: '', 221 missingValues: 'interpolate', 222 markers: { 223 visible: false, 224 }, 225 }, 226 series: [], 227 valueAxis: { 228 labels: { 229 format: '{0}', 230 }, 231 line: { 232 visible: false, 233 }, 234 }, 235 categoryAxis: { 236 categories: [], 237 majorGridLines: { 238 visible: false, 239 }, 240 type: 'date', 241 baseUnit: 'fit', 242 roundToBaseUnit: true, 243 labels: { 244 rotation: { 245 angle: 'auto', 246 }, 247 }, 248 }, 249 tooltip: { 250 visible: true, 251 format: '{3} {0}%', 252 template: function (e) { 253 var template = "<b>".concat(e.series.name, ": ").concat(e.value, "</b>"); 254 if (!_.isDate(e.category)) 255 return template; 256 var date = moment(e.category).format('MM/DD/YYYY hh:mm A'); 257 return "".concat(template, " <br/> <b>Date: ").concat(date, "</b>"); 258 }, 259 }, 260 }; 261 UTIL.CHART_COLORS = { 262 GREEN: '#8ebc00', 263 DARK_GREEN: '#309b46', 264 BLUE: '#25a0da', 265 ORANGE: '#ff6900', 266 RED: '#e61e26', 267 YELLOW: '#d8e404', 268 TEAL: '#16aba9', 269 PURPLE: '#7e51a1', 270 BLACK: '#313131', 271 PINK: '#ed1691', 272 }; 273 UTIL.SUMMARY_BAR_DEFAULTS = { 274 theme: UTIL.CHART_THEME, 275 title: { 276 visible: false, 277 text: '', 278 position: 'top', 279 font: '16px "Nunito", Arial, sans-serif', 280 color: '#000000', 281 }, 282 plotArea: { 283 padding: 0, 284 margin: 0, 285 }, 286 chartArea: { 287 padding: 0, 288 margin: 0, 289 background: '', 290 }, 291 panes: [{ clip: false, margin: 0 }], 292 seriesDefaults: { 293 visibleInLegend: true, 294 type: UTIL.CHART_TYPES.BAR, 295 stack: { 296 type: '100%', 297 }, 298 labels: { 299 visible: false, 300 position: 'auto', 301 template: '#= dataItem.label #', 302 }, 303 series: [], 304 margin: 0, 305 gap: 0, 306 spacing: 0, 307 visual: function (e) { 308 var visual = e.createVisual(); 309 visual.transform(kendo.geometry 310 .transform() 311 .scale(1, 40 / e.rect.size.height, e.rect.center())); 312 return visual; 313 }, 314 }, 315 legend: { 316 visible: true, 317 position: 'bottom', 318 }, 319 axisDefaults: { 320 labels: { 321 visible: false, 322 }, 323 visibleInLegend: true, 324 }, 325 valueAxis: { 326 min: 0, 327 minorGridLines: { 328 visible: false, 329 }, 330 majorGridLines: { 331 visible: false, 332 }, 333 line: { 334 visible: false, 335 }, 336 }, 337 categoryAxis: { 338 categories: [], 339 minorGridLines: { 340 visible: false, 341 }, 342 majorGridLines: { 343 visible: false, 344 }, 345 line: { 346 visible: false, 347 }, 348 }, 349 tooltip: { 350 visible: true, 351 template: '#= dataItem.tooltip#', 352 }, 353 }; 354 return UTIL; 355} 356function timeSeriesChartComponent() { 357 return { 358 bindings: { 359 timeSeriesChart: '<chart', 360 report: '<', 361 tsOptions: '<', 362 }, 363 template: "<div class=\"d-flex flex-column position-relative\">\n <div class=\"px-15\">\n <div kendo-toolbar=\"$ctrl.chartToolbar\"\n k-rebind=\"$ctrl.kendoToolbarOpts\"\n k-ng-delay=\"$ctrl.kendoToolbarOpts\"\n k-options=\"$ctrl.kendoToolbarOpts\"></div>\n </div>\n <div kendo-chart=\"$ctrl.chart\"\n kendo-chart-resize-observer\n k-on-render=\"$ctrl.onChartRender(kendoEvent)\"\n style=\"width: 100%; height: 550px; padding-top: 15px;\">\n </div>\n <div style=\"z-index: 999\" class=\"chart-loading\"></div>\n</div>", 364 controller: function (kendo, $http, $scope, $element, ChartUtilityService, $timeout) { 365 var $ctrl = this; 366 $ctrl.defaultOptions = { 367 chartTitle: null, 368 visualizations: [], 369 toolbarOptions: ChartUtilityService.TOOLBAR_DEFAULTS, 370 chartOptions: ChartUtilityService.TIME_SERIES_CHART_DEFAULTS, 371 }; 372 $ctrl.options = { 373 chartTitle: null, 374 toolbarOptions: {}, 375 chartOptions: {}, 376 }; 377 $ctrl.vizOptions = { 378 chartTitle: null, 379 toolbarOptions: {}, 380 chartOptions: {}, 381 }; 382 $ctrl.state = { 383 isLoading: true, 384 selectedVizName: null, 385 selectedViz: null, 386 report: { 387 baseUrl: null, 388 queryString: null, 389 }, 390 toolbar: {}, 391 chart: {}, 392 chartData: { 393 rawData: [], 394 series: [], 395 categories: [], 396 }, 397 }; 398 $ctrl.$onChanges = function (changes) { 399 return __awaiter(this, void 0, void 0, function () { 400 var isFirstOptionsChange; 401 return __generator(this, function (_a) { 402 if (changes.report && $ctrl.report) { 403 $ctrl.initReport(); 404 } 405 if (changes.tsOptions && $ctrl.tsOptions) { 406 isFirstOptionsChange = _.result(changes.tsOptions, 'isFirstChange'); 407 if (isFirstOptionsChange) { 408 $ctrl.options = $ctrl.formatOptions($ctrl.tsOptions); 409 $ctrl.updateSelectedViz(); 410 } 411 } 412 return [2]; 413 }); 414 }); 415 }; 416 $ctrl.$postLink = function () {
417 if ($ctrl.state.isLoading) { 418 kendo.ui.progress($('.chart-loading'), true); 419 } 420 }; 421 $ctrl.onChartRender = _.debounce(function (event) { 422 $ctrl.setLoading(false); 423 }, 300); 424 $ctrl.formatOptions = function (tsOptions) { 425 var toolbarOptions = tsOptions.toolbarOptions, visualizations = tsOptions.visualizations, chartOptions = __rest(tsOptions, ["toolbarOptions", "visualizations"]); 426 var defaultToolbarOptions = _.defaultsDeep({}, toolbarOptions, $ctrl.defaultOptions.toolbarOptions); 427 var defaultChartOptions = _.defaultsDeep({}, chartOptions, $ctrl.defaultOptions.chartOptions); 428 var setVisDefaults = function (_a) { 429 var toolbarOptions = _a.toolbarOptions, name = _a.name, chartOptions = __rest(_a, ["toolbarOptions", "name"]); 430 return { 431 toolbarOptions: _.defaults({}, toolbarOptions, defaultToolbarOptions), 432 chartOptions: _.defaults({}, chartOptions, defaultChartOptions), 433 name: name, 434 }; 435 }; 436 var defaultVisualizations = _.map(visualizations, setVisDefaults); 437 return Object.seal({ 438 toolbarOptions: defaultToolbarOptions, 439 chartOptions: defaultChartOptions, 440 visualizations: defaultVisualizations, 441 }); 442 }; 443 $ctrl.setLoading = function (isLoading) { 444 $ctrl.state.isLoading = isLoading; 445 kendo.ui.progress($('.chart-loading'), $ctrl.state.isLoading); 446 }; 447 $ctrl.refreshComponent = function () { 448 return __awaiter(this, void 0, void 0, function () { 449 return __generator(this, function (_a) { 450 switch (_a.label) { 451 case 0: return [4, $ctrl.refreshChartData()]; 452 case 1: 453 _a.sent(); 454 $ctrl.updateToolbar(); 455 $ctrl.updateChart(); 456 return [2]; 457 } 458 }); 459 }); 460 }; 461 $ctrl.refresh = _.debounce($ctrl.refreshComponent, 500); 462 $ctrl.updateSelectedViz = function () { 463 if (!$ctrl.state.selectedVizName) { 464 $ctrl.state.selectedVizName = _.get(_.first($ctrl.options.visualizations), 'name'); 465 } 466 var viz = _.find($ctrl.options.visualizations, { 467 name: $ctrl.state.selectedVizName, 468 }); 469 $ctrl.state.selectedViz = viz; 470 $ctrl.vizOptions.toolbarOptions = 471 $ctrl.state.selectedViz.toolbarOptions; 472 $ctrl.vizOptions.chartOptions = $ctrl.state.selectedViz.chartOptions; 473 Object.seal($ctrl.vizOptions); 474 $ctrl.state.toolbar.chartType = 475 $ctrl.vizOptions.chartOptions.seriesDefaults.type; 476 $ctrl.state.toolbar.style = 477 $ctrl.vizOptions.chartOptions.seriesDefaults.style || 'normal'; 478 $ctrl.state.toolbar.granularity = 479 $ctrl.vizOptions.toolbarOptions.defaultGranularity; 480 $ctrl.state.toolbar.timeRange = 481 $ctrl.vizOptions.toolbarOptions.defaultTimeRange; 482 $ctrl.state.toolbar.categoryDayFilter = 483 $ctrl.vizOptions.toolbarOptions.defaultCategoryFilter; 484 $ctrl.refresh(); 485 }; 486 $ctrl.initReport = function () { 487 if (_.isFunction($ctrl.state.report.watcher)) { 488 $ctrl.state.report.watcher(); 489 } 490 $ctrl.state.report.watcher = $scope.$watch('$ctrl.report.lastDataUrl', function (newvalue, oldvalue) { 491 if (newvalue) { 492 var baseUrl = newvalue.split('?')[0]; 493 var params = newvalue.split('?')[1]; 494 params = params.split('&'); 495 var queryString = '?' + _.filter(params, function (p) { return p.match(/^filter/); }).join('&'); 496 if (queryString == '?') { 497 queryString = ''; 498 } 499 if (queryString !== $ctrl.state.report.queryString) { 500 $ctrl.state.report.queryString = queryString; 501 $ctrl.state.report.baseUrl = baseUrl.replace('data', 'time-series'); 502 $ctrl.refresh(); 503 } 504 } 505 }); 506 }; 507 $ctrl.getDateRange = function (type) { 508 var range = { 509 startDate: null, 510 endDate: null, 511 }; 512 switch (type) { 513 case ChartUtilityService.TIME_RANGE_TYPES.LAST_7_DAYS: { 514 range.startDate = moment() 515 .subtract(7, 'days') 516 .startOf('day') 517 .toISOString(); 518 break; 519 } 520 case ChartUtilityService.TIME_RANGE_TYPES.LAST_30_DAYS: { 521 range.startDate = moment() 522 .subtract(30, 'days') 523 .startOf('day') 524 .toISOString(); 525 break; 526 } 527 case ChartUtilityService.TIME_RANGE_TYPES.LAST_WEEK: { 528 range.startDate = moment() 529 .subtract(1, 'week') 530 .startOf('week') 531 .toISOString(); 532 range.endDate = moment(range.start).endOf('week').toISOString(); 533 } 534 } 535 return range; 536 }; 537 $ctrl.getTSDataUrl = function () { 538 var granularityMapping = { 539 Auto: 'day', 540 Minutes: '5min', 541 Hours: 'hour', 542 Days: 'day', 543 Weeks: 'week', 544 Months: 'month', 545 }; 546 var queryString = $ctrl.state.report.queryString;
547 var baseUrl = "".concat($ctrl.state.report.baseUrl); 548 var chartGranularity = _.get(granularityMapping, $ctrl.state.toolbar.granularity, 'day'); 549 var selectedFields = _.filter(_.map(_.get($ctrl, 'state.selectedViz.chartOptions.series', []), 'field'), _.isString); 550 var fields = _.uniq(_.compact(_.map(selectedFields, function (fieldName) { 551 var match = fieldName.match(/^(.+)(Avg|Sum|Count|Max|Min|First|Last)$/); 552 return match[1]; 553 }))); 554 var queryParams = new URLSearchParams(queryString); 555 if (!baseUrl.match(/\?/)) 556 baseUrl += '?'; 557 queryParams.set('selectedFields', selectedFields.join(',')); 558 queryParams.set('fields', fields.join(',')); 559 queryParams.set('granularity', chartGranularity); 560 function isFilterField(str) { 561 var pattern = /^filter\[filters\]\[\d+\]\[field\]$/; 562 return pattern.test(str); 563 } 564 if ($ctrl.state.selectedViz.chartOptions.categoryAxis.type !== 'date') { 565 queryParams.set('groupCategorically', 'true'); 566 if ($ctrl.state.toolbar.categoryDayFilter) { 567 queryParams.set('categoryDayMatch', $ctrl.state.toolbar.categoryDayFilter); 568 } 569 } 570 if ($ctrl.state.toolbar.timeRange && 571 $ctrl.state.toolbar.timeRange !== 572 ChartUtilityService.TIME_RANGE_TYPES.SYNC_WITH_REPORT) { 573 var filterCount_1 = 0; 574 queryParams.forEach(function (value, key) { 575 if (!isFilterField(key)) 576 return; 577 if (value === 'dateTime') { 578 var path = _.replace(key, '[field]', ''); 579 queryParams.delete(path); 580 } 581 else { 582 filterCount_1++; 583 } 584 }); 585 var _a = $ctrl.getDateRange($ctrl.state.toolbar.timeRange), startDate = _a.startDate, endDate = _a.endDate; 586 var addFilter = function (field, operator, value) { 587 queryParams.set("filter[filters][".concat(filterCount_1, "][field]"), 'dateTime'); 588 queryParams.set("filter[filters][".concat(filterCount_1, "][operator]"), operator); 589 queryParams.set("filter[filters][".concat(filterCount_1, "][value]"), value); 590 filterCount_1++; 591 }; 592 if (startDate) 593 addFilter('dateTime', 'gte', startDate); 594 if (endDate) 595 addFilter('dateTime', 'lte', endDate); 596 } 597 return baseUrl + queryParams.toString(); 598 }; 599 $ctrl.isRawDataCurrent = function () { 600 if (!$ctrl.state.report.dataUrl ||
601 !$ctrl.state.chartData.rawData || 602 !$ctrl.state.chartData.rawData.length) { 603 return false; 604 } 605 return $ctrl.getTSDataUrl() === $ctrl.state.report.dataUrl; 606 }; 607 $ctrl.retrieveUpdatedData = function () { 608 return __awaiter(this, void 0, void 0, function () { 609 var dataUrl, res; 610 return __generator(this, function (_a) { 611 switch (_a.label) { 612 case 0: 613 dataUrl = $ctrl.getTSDataUrl(); 614 return [4, $http.get(dataUrl)]; 615 case 1: 616 res = _a.sent(); 617 $ctrl.state.chartData.rawData = res.data; 618 $ctrl.state.report.dataUrl = dataUrl; 619 return [2]; 620 } 621 }); 622 }); 623 }; 624 $ctrl.refreshChartData = function () { 625 return __awaiter(this, void 0, void 0, function () { 626 var rawData, vizSeries, fnCount, dataSeries; 627 return __generator(this, function (_a) { 628 switch (_a.label) { 629 case 0: 630 $ctrl.setLoading(true); 631 if (!!$ctrl.isRawDataCurrent()) return [3, 2]; 632 return [4, $ctrl.retrieveUpdatedData()]; 633 case 1: 634 _a.sent(); 635 _a.label = 2; 636 case 2: 637 rawData = $ctrl.state.chartData.rawData; 638 vizSeries = $ctrl.state.selectedViz.chartOptions.series; 639 fnCount = 0; 640 dataSeries = _.map(vizSeries, function (def) { 641 var seriesItem = _.clone(def); 642 seriesItem.categoryField = _.get($ctrl.state.selectedViz.chartOptions, 'categoryAxis.categoryField', 'dateTime'); 643 if (_.isFunction(def.field)) { 644 seriesItem.field = 'fn' + fnCount; 645 def.fnName = 'fn' + fnCount; 646 fnCount++; 647 } 648 return seriesItem; 649 }); 650 rawData.forEach(function (d) { 651 if (d.dateTime) 652 d.dateTime = new Date(d.dateTime); 653 _.forEach(vizSeries, function (def) { 654 if (def.fnName) { 655 d[def.fnName] = def.field(d); 656 } 657 }); 658 }); 659 $ctrl.state.chartData.series = dataSeries; 660 return [2]; 661 } 662 }); 663 }); 664 }; 665 $ctrl.updateToolbar = function () { 666 var toolbarOpts = $ctrl.vizOptions.toolbarOptions; 667 var getToolbarBaseOpts = function () { return ({ 668 change: function (e) { 669 e.sender.span[0].style.textTransform = 'uppercase'; 670 }, 671 dataBound: function (e) { 672 e.sender.span[0].style.textTransform = 'uppercase'; 673 }, 674 }); }; 675 $ctrl.kendoToolbarOpts = _.defaultsDeep({ 676 hidden: !toolbarOpts.showToolbar, 677 items: [], 678 }, toolbarOpts); 679 var kendoOpts = $ctrl.kendoToolbarOpts; 680 if (toolbarOpts.showVizList) { 681 $ctrl.vizSelectionKendoOpts = { 682 dataTextField: 'name', 683 dataValueField: 'name', 684 dataSource: $ctrl.options.visualizations, 685 }; 686 kendoOpts.items.push({ 687 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.vizSelectionKendoOpts\"\n ng-model=\"$ctrl.state.selectedVizName\"\n ng-change=\"$ctrl.updateSelectedViz()\"\n style='width: 190px;' />", 688 overflow: 'never', 689 }); 690 } 691 if (toolbarOpts.showChartTypes) { 692 $ctrl.typeSelectionKendoOpts = getToolbarBaseOpts(); 693 kendoOpts.items.push({ type: 'separator' }, { template: '<label>CHART TYPE:</label>' }, {
694 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.typeSelectionKendoOpts\"\n k-data-source=\"$ctrl.vizOptions.toolbarOptions.chartTypes\",\n ng-model=\"$ctrl.state.toolbar.chartType\"\n ng-change=\"$ctrl.updateToolbarState()\"\n style='width: 150px;' />", 695 overflow: 'never', 696 }); 697 } 698 if (toolbarOpts.showLineSmoothing) { 699 kendoOpts.items.push({ 700 type: 'button', 701 id: 'line-smooth', 702 text: 'LINE SMOOTHING', 703 enable: $ctrl.state.toolbar.chartType.match(/area|line/), 704 selected: $ctrl.state.toolbar.chartType.match(/area|line/) && 705 $ctrl.state.toolbar.style === 'smooth', 706 togglable: true, 707 toggle: $ctrl.updateToolbarState, 708 }); 709 } 710 if (toolbarOpts.showGranularity) { 711 $ctrl.granularitySelectKendoOpts = getToolbarBaseOpts(); 712 kendoOpts.items.push({ type: 'separator' }, { template: '<label>SHOW:</label>' }, { 713 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.granularitySelectKendoOpts\"\n k-data-source=\"$ctrl.vizOptions.toolbarOptions.granularityOptions\",\n ng-model=\"$ctrl.state.toolbar.granularity\"\n ng-change=\"$ctrl.updateToolbarState()\"\n style='width: 150px;' />", 714 overflow: 'never', 715 }); 716 } 717 if (toolbarOpts.showDayCategoryFilter) { 718 $ctrl.filterSelectionKendoOpts = __assign(__assign({}, getToolbarBaseOpts()), { dataSource: $ctrl.vizOptions.toolbarOptions.categoryFilterOptions, dataTextField: 'name', dataValueField: 'value' }); 719 kendoOpts.items.push({ type: 'separator' }, { template: '<label>DAYS:</label>' }, { 720 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.filterSelectionKendoOpts\"\n ng-model=\"$ctrl.state.toolbar.categoryDayFilter\"\n ng-change=\"$ctrl.updateToolbarState()\"\n style='width: 190px;' />", 721 overflow: 'never', 722 }); 723 } 724 if (toolbarOpts.showTimeRange) { 725 $ctrl.timeRangeKendoOpts = getToolbarBaseOpts(); 726 kendoOpts.items.push({ type: 'separator' }, { template: '<label>TIME RANGE:</label>' }, { 727 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.timeRangeKendoOpts\"\n k-data-source=\"$ctrl.vizOptions.toolbarOptions.timeRangeOptions\",\n ng-model=\"$ctrl.state.toolbar.timeRange\"\n ng-change=\"$ctrl.updateToolbarState()\"\n style='width: 150px;' />", 728 overflow: 'never', 729 }); 730 } 731 if (toolbarOpts.exportToPDF || toolbarOpts.exportToPNG) { 732 $ctrl.exportSelectionKendoOpts = { 733 optionLabel: 'Export', 734 dataValueField: 'value', 735 dataTextField: 'name', 736 autoWidth: true, 737 select: function (e) { 738 e.preventDefault(); 739 switch (e.dataItem.value) { 740 case 'pdf': 741 $ctrl.chart 742 .exportPDF({ landscape: true }) 743 .done(function (data) { 744 kendo.saveAs({ 745 dataURI: data, 746 fileName: 'chart.pdf', 747 proxyURL: '/api/v1/reporting/download-pdf', 748 }); 749 }); 750 break; 751 case 'png': 752 $ctrl.chart.exportImage().done(function (data) { 753 kendo.saveAs({ 754 dataURI: data, 755 fileName: 'chart.png', 756 }); 757 }); 758 break; 759 case 'svg': 760 $ctrl.chart.exportSVG().done(function (data) { 761 kendo.saveAs({ 762 dataURI: data, 763 fileName: 'chart.svg', 764 }); 765 }); 766 break; 767 } 768 }, 769 dataBound: function (e) { 770 e.sender.span[0].style.textTransform = 'uppercase'; 771 }, 772 dataSource: [], 773 }; 774 if (toolbarOpts.exportToPDF) 775 $ctrl.exportSelectionKendoOpts.dataSource.pu
775sh({ 776 name: 'Export to PDF', 777 value: 'pdf', 778 }); 779 if (toolbarOpts.exportToPNG) 780 $ctrl.exportSelectionKendoOpts.dataSource.push({ 781 name: 'Export to PNG', 782 value: 'png', 783 }); 784 if (toolbarOpts.exportToSVG) 785 $ctrl.exportSelectionKendoOpts.dataSource.push({ 786 name: 'Export to SVG', 787 value: 'svg', 788 }); 789 kendoOpts.items.push({ type: 'separator' }, { 790 template: "<input kendo-drop-down-list\n k-options=\"$ctrl.exportSelectionKendoOpts\"\n />", 791 overflow: 'never', 792 }); 793 } 794 }; 795 $ctrl.updateToolbarState = function (e) { 796 if (e && e.id) { 797 switch (e.id) { 798 case 'line-smooth': 799 $ctrl.state.toolbar.style = e.checked ? 'smooth' : 'normal'; 800 } 801 } 802 $ctrl.updateToolbar(); 803 $ctrl.updateChart(); 804 }; 805 $ctrl.setLine = function (e) { 806 var lineStyle = e.checked ? 'smooth' : null; 807 $ctrl.chart.setOptions({ seriesDefaults: { style: lineStyle } }); 808 }; 809 $ctrl.setChartType = function () { 810 var stackBtnEnabled = true; 811 var options = { seriesDefaults: { type: $ctrl.chartType } }; 812 if ($ctrl.chartType === 'line') { 813 $ctrl.chartToolbar.enable('#line-smooth', true); 814 } 815 else { 816 $ctrl.chartToolbar.enable('#line-smooth', false); 817 } 818 if ($ctrl.chartType === 'waterfall') { 819 stackBtnEnabled = false; 820 $ctrl.chartToolbar.toggle('#count', true); 821 } 822 if (!stackBtnEnabled && $ctrl.stackType === '100%') { 823 _.set(options.seriesDefaults, 'stack.type', 'normal'); 824 } 825 $ctrl.chartToolbar.enable('#stackTypeGroup', stackBtnEnabled); 826 $ctrl.chart.setOptions(options); 827 }; 828 $ctrl.chartOpts = {}; 829 $ctrl.updateChart = function () { 830 return __awaiter(this, void 0, void 0, function () { 831 var chartOpts, kendoOpts, chartType, chartTypes, granularity, dataPoints, chartWidth, maxLabels, step, skip; 832 return __generator(this, function (_a) { 833 switch (_a.label) { 834 case 0: 835 chartOpts = $ctrl.vizOptions.chartOptions; 836 $ctrl.kendoChartOpts = _.cloneDeep(chartOpts); 837 kendoOpts = $ctrl.kendoChartOpts; 838 return [4, $ctrl.refreshChartData()]; 839 case 1: 840 _a.sent(); 841 kendoOpts.series = $ctrl.state.chartData.series; 842 kendoOpts.dataSource = { data: $ctrl.state.chartData.rawData }; 843 chartType = _.get($ctrl.state, 'selectedViz.toolbar.chartType', $ctrl.state.toolbar.chartType); 844 if (chartType) { 845 chartTypes = _.get($ctrl.state.selectedViz, 'toolbarOptions.chartTypes', []); 846 if (chartTypes.length && !_.includes(chartTypes, chartType)) { 847 chartType = chartTypes[0]; 848 } 849 kendoOpts.seriesDefaults.type = chartType; 850 } 851 if ($ctrl.state.toolbar.style) { 852 kendoOpts.seriesDefaults.style = $ctrl.state.toolbar.style; 853 }
854 if ($ctrl.state.toolbar.granularity && 855 chartOpts.categoryAxis.type === 'date') { 856 granularity = $ctrl.state.toolbar.granularity; 857 dataPoints = _.get($ctrl.state.chartData, 'rawData', []).length; 858 chartWidth = kendoOpts.type === 'bar' 859 ? $($element).innerHeight() 860 : $($element).innerWidth(); 861 maxLabels = Math.floor(chartWidth / 20); 862 step = Math.ceil(dataPoints / maxLabels); 863 skip = 0; 864 if (step > 1) { 865 skip = Math.ceil((dataPoints - maxLabels) / (maxLabels - 1)); 866 } 867 kendoOpts.categoryAxis.baseUnit = 'fit'; 868 switch (granularity) { 869 case 'Auto': 870 kendoOpts.categoryAxis.baseUnit = 'fit'; 871 break; 872 case 'Minutes': 873 kendoOpts.categoryAxis.baseUnit = 'minute'; 874 kendoOpts.categoryAxis.baseUnitStep = 5; 875 kendoOpts.categoryAxis.labels.step = step; 876 kendoOpts.categoryAxis.labels.skip = skip; 877 break; 878 case 'Hours': 879 kendoOpts.categoryAxis.baseUnit = 'hour'; 880 kendoOpts.categoryAxis.baseUnitStep = 3; 881 kendoOpts.categoryAxis.labels.step = step; 882 kendoOpts.categoryAxis.labels.skip = skip; 883 break; 884 case 'Days': 885 kendoOpts.categoryAxis.baseUnit = 'day'; 886 kendoOpts.categoryAxis.baseUnitStep = 1; 887 kendoOpts.categoryAxis.labels.step = step; 888 kendoOpts.categoryAxis.labels.skip = skip; 889 break; 890 case 'Weeks': 891 kendoOpts.categoryAxis.baseUnit = 'week'; 892 kendoOpts.categoryAxis.baseUnitStep = 1; 893 kendoOpts.categoryAxis.labels.step = step; 894 kendoOpts.categoryAxis.labels.skip = skip; 895 break; 896 case 'Months': 897 kendoOpts.categoryAxis.baseUnit = 'month'; 898 kendoOpts.categoryAxis.baseUnitStep = 1; 899 kendoOpts.categoryAxis.labels.step = step; 900 kendoOpts.categoryAxis.labels.skip = skip; 901 break; 902 } 903 } 904 $ctrl.chartOpts = kendoOpts; 905 if ($ctrl.chart) { 906 $ctrl.chart.setOptions($ctrl.chartOpts); 907 } 908 return [2]; 909 } 910 }); 911 }); 912 }; 913 }, 914 }; 915} 916; 917'use strict'; 918var appComponents = angular.module('appComponents', [ 919 'inputComponents', 920 'selectionComponents', 921 'stats', 922 'authComponents',
923 'navigationComponents', 924 'formComponents', 925 'layoutComponents', 926 'widgetComponents', 927 'chartComponents', 928]); 929; 930'use strict'; 931var formComponents = angular.module('formComponents', []); 932formComponents.component('adminForm', { 933 templateUrl: '/templates/system/components/forms/admin-form.html', 934 transclude: { 935 formSections: 'adminFormSections', 936 formActions: '?adminFormActions', 937 formNotes: '?adminFormNotes', 938 }, 939 bindings: { 940 form: '=?', 941 onSave: '<?', 942 onUndo: '<?', 943 onDelete: '<?', 944 showActions: '<?', 945 formColWidth: '<?', 946 }, 947 controller: function ($scope, $element, $transclude) { 948 var $ctrl = this; 949 $ctrl.sections = []; 950 $ctrl.showMoreActions = $transclude.isSlotFilled('formActions'); 951 $ctrl.showFormNotes = $transclude.isSlotFilled('formNotes'); 952 $ctrl.$onInit = function () { 953 if (!$ctrl.formColWidth) { 954 $ctrl.formColWidth = 8; 955 } 956 }; 957 $ctrl.$postLink = function () { 958 $ctrl.buildTocSections(); 959 $ctrl.form = $scope.adminForm; 960 }; 961 $ctrl.$doCheck = function () { 962 if ($scope.adminForm) { 963 var sectionCount_1 = 0; 964 _.keys($scope.adminForm).forEach(function (key) { 965 if (key.charAt(0) !== '$') 966 sectionCount_1++; 967 }); 968 if (sectionCount_1 !== $ctrl.sections.length) { 969 $ctrl.buildTocSections(); 970 } 971 } 972 }; 973 $ctrl.buildTocSections = function () { 974 var sections = []; 975 angular.forEach($element.find('admin-form-section'), function (section) { 976 var elm = angular.element(section); 977 sections.push({ id: elm.attr('section-id'), label: elm.attr('label') }); 978 }); 979 $ctrl.sections = sections; 980 }; 981 }, 982}); 983formComponents.component('adminFormSection', { 984 templateUrl: '/templates/system/components/forms/admin-form-section.html', 985 transclude: true, 986 bindings: { 987 label: '@', 988 sectionId: '@', 989 }, 990}); 991formComponents.component('adminFormToc', { 992 templateUrl: '/templates/system/components/forms/admin-form-toc.html', 993 bindings: { 994 sections: '<', 995 adminForm: '<', 996 }, 997 controller: function (elementHelper) { 998 var $ctrl = this; 999 $ctrl.scrollTo = function (elmId) { 1000 var elm = document.getElementById(elmId); 1001 elementHelper.scrollToElement(elm); 1002 }; 1003 $ctrl.getSectionStatus = function (id) { 1004 if ($ctrl.adminForm) { 1005 var formSection = $ctrl.adminForm[id]; 1006 if (!formSection) 1007 return; 1008 if (formSection.$invalid) 1009 return 'fa-exclamation-triangle btn-warning'; 1010 else if (formSection.$dirty) 1011 return 'fa-check btn-success'; 1012 else 1013 return 'fa-edit btn-primary'; 1014 } 1015 }; 1016 }, 1017}); 1018; 1019'use strict'; 1020var inputComponents = angular.module('inputComponents', []); 1021inputComponents.directive('integerCast', [ 1022 function () { 1023 return { 1024 restrict: 'A', 1025 require: 'ngModel', 1026 link: function (scope, element, attrs, ngModel) { 1027 ngModel.$parsers.push(function (value) { return (!!value && 1) || 0; }); 1028 ngModel.$formatters.push(function (value) { return !!value; }); 1029 }, 1030 }; 1031 }, 1032]); 1033inputComponents.component('toggleButton', { 1034 template: '<button type="button" class="btn {{ $ctrl.btnClass }}" ng-click="$ctrl.toggleState()">' + 1035 '<i class="toggle-btn-icon {{ $ctrl.checked ? $ctrl.activeIcon : $ctrl.inactiveIcon }}"></i>' + 1036 '<ng-transclude></ng-transclude>' + 1037 '</button>', 1038 transclude: true, 1039 require: { 1040 ngModel: 'ngModel', 1041 }, 1042 bindings: { 1043 btnClass: '<?', 1044 activeIcon: '<?', 1045 inactiveIcon: '<?', 1046 checked: '=?', 1047 onChange: '&?', 1048 }, 1049 controller: function () { 1050 var $ctrl = this; 1051 $ctrl.$onInit = function () { 1052 $ctrl.btnClass = $ctrl.btnClass || 'btn-primary btn-sm'; 1053 $ctrl.activeIcon = $ctrl.activeIcon || 'far fa-check-circle'; 1054 $ctrl.inactiveIcon = $ctrl.inactiveIcon || 'far fa-circle'; 1055 $ctrl.checked = $ctrl.checked || false; 1056 $ctrl.ngModel.$render = function () { 1057 $ctrl.checked = $ctrl.ngModel.$viewValue; 1058 }; 1059 }; 1060 $ctrl.toggleState = function () { 1061 $ctrl.checked = !$ctrl.checked; 1062 $ctrl.ngModel.$setViewValue($ctrl.checked); 1063 if ($ctrl.onChange) 1064 $ctrl.onChange({ checked: $ctrl.checked }); 1065 }; 1066 }, 1067});
1068inputComponents.component('toggleSwitch', { 1069 bindings: { 1070 checked: '=?', 1071 labelTitle: '@?', 1072 onToggle: '&?', 1073 disabled: '<?', 1074 }, 1075 template: '<div ng-form="toggleSwitch" class="flex-box">' + 1076 '<label class="switch" ng-class="{disabled: $ctrl.disabled}">' + 1077 '<input ng-click="$ctrl.toggleState()" ng-checked="$ctrl.checked" type="checkbox" ng-disabled="$ctrl.disabled">' + 1078 '<span class="slider round"></span>' + 1079 '</label>' + 1080 '<label class="toggle-switch-label" >{{$ctrl.labelTitle}}</label>' + 1081 '</div>', 1082 controller: function ($scope, $timeout) { 1083 var $ctrl = this; 1084 this.toggleState = function () { 1085 this.checked = !this.checked; 1086 $scope.toggleSwitch.$setDirty(); 1087 $timeout(function () { return _.result($ctrl, 'onToggle'); }); 1088 }; 1089 }, 1090}); 1091inputComponents.component('kendoUserAutocomplete', { 1092 template: '<select class="user-select" kendo-multi-select k-options="$ctrl.selectOptions" k-ng-model="$ctrl.value"></select>', 1093 require: { 1094 ngModel: 'ngModel', 1095 }, 1096 bindings: { 1097 placeholder: '@', 1098 fetchUrl: '@?', 1099 onChange: '&', 1100 queryProperty: '@?', 1101 maxSelectedItems: '@?', 1102 serverPaging: '@?', 1103 }, 1104 controller: function (KendoInputService, vhttp, $element) { 1105 var $ctrl = this; 1106 $ctrl.$onInit = function () { 1107 $ctrl.fetchUrl = $ctrl.fetchUrl || '/api/v1/user-autocomplete'; 1108 $ctrl.textField = 'email'; 1109 $ctrl.valueField = '_id'; 1110 $ctrl.queryProperty = $ctrl.queryProperty || 'userQuery'; 1111 $ctrl.itemTemplate = 1112 '<span class="k-state-default" style="font-size:90%">#: data.firstName # #: data.lastName # <small>(#: data.email #)</small></span>'; 1113 $ctrl.autoBind = true; 1114 if (!$ctrl.placeholder) { 1115 $ctrl.placeholder = 'Select Users'; 1116 } 1117 $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl); 1118 var valueMapper = { 1119 virtual: { 1120 mapValueTo: 'dataItem', 1121 valueMapper: function (options) { 1122 var userLookup = _.isArray(options.value) 1123 ? options.value.join() 1124 : options.value; 1125 vhttp 1126 .get('/api/v1/user-autocomplete', { userLookup: userLookup }) 1127 .then(options.success); 1128 }, 1129 }, 1130 }; 1131 $ctrl.selectOptions = _.assign(KendoInputService.getSelectOptions($ctrl), valueMapper); 1132 $ctrl.ngModel.$render = function () { 1133 $ctrl.value = $ctrl.ngModel.$viewValue; 1134 }; 1135 }; 1136 $ctrl.$postLink = function () { 1137 var kendoEl = $element.find('select.user-select'); 1138 $ctrl.multiselect = kendoEl.data('kendoMultiSelect'); 1139 }; 1140 }, 1141}); 1142inputComponents.component('kendoMultiSelectLocal', { 1143 template: '<select class="local-select" ng-readonly="$ctrl.readonly" kendo-multi-select k-options="$ctrl.selectOptions" k-ng-model="$ctrl.value"></select>', 1144 require: { 1145 ngModel: 'ngModel', 1146 }, 1147 bindings: { 1148 placeholder: '@?', 1149 readonly: '=?', 1150 data: '<', 1151 textField: '@', 1152 valueField: '@', 1153 onChange: '&?', 1154 maxSelectedItems: '@?', 1155 }, 1156 controller: function (KendoInputService, $element) { 1157 var $ctrl = this; 1158 $ctrl.$onInit = function () { 1159 $ctrl.dataSource = $ctrl.data; 1160 $ctrl.itemTemplate = "<span class=\"k-state-default\" style=\"font-size:90%\"><b>#: data.".concat($ctrl.textField, " #</b>"); 1161 $ctrl.selectOptions = KendoInputService.getSelectOptions($ctrl); 1162 $ctrl.ngModel.$render = function () { 1163 return ($ctrl.value = $ctrl.ngModel.$viewValue || []); 1164 }; 1165 }; 1166 $ctrl.$onChanges = function (_a) { 1167 var data = _a.data; 1168 if (data.currentValue && $ctrl.multiselect) { 1169 var dataSource = new kendo.data.DataSource({ 1170 data: data.currentValue, 1171 }); 1172 $ctrl.multiselect.setDataSource(dataSource); 1173 $ctrl.multiselect.value($ctrl.value); 1174 } 1175 }; 1176 $ctrl.$postLink = function () { 1177 var kendoEl = $element.find('select.local-select'); 1178 $ctrl.multiselect = kendoEl.data('kendoMultiSelect'); 1179 }; 1180 }, 1181});
1182inputComponents.component('kendoMultiNetworkSelect', { 1183 template: '<select class="network-select" ng-readonly="$ctrl.readonly" kendo-multi-select k-options="$ctrl.selectOptions" ng-model="$ctrl.value"></select>', 1184 require: { 1185 ngModel: 'ngModel', 1186 }, 1187 bindings: { 1188 placeholder: '@?', 1189 multiselect: '=?', 1190 readonly: '=?', 1191 onChange: '&', 1192 maxSelectedItems: '@?', 1193 fetchUrl: '@?', 1194 optionsFilter: '=?', 1195 }, 1196 controller: function (KendoInputService, $element, $timeout) { 1197 var $ctrl = this; 1198 $ctrl.headerTemplate = "\n <div class=\"pt-5 pb-5\" style=\"border-bottom: 1px solid darkgray;\">\n <span class=\"fs-18 text-bold p6\">Search Results</span>\n <span class=\"pull-right btn-link pr-5\" ng-click=\"$ctrl.clearSelection()\">Clear All</span>\n </div>"; 1199 $ctrl.$onInit = function () { 1200 $ctrl.ngModel.$render = function () { 1201 if (_.get($ctrl.ngModel, '$viewValue', []).length) 1202 $ctrl.setUrlOverride($ctrl.ngModel.$viewValue); 1203 $ctrl.value = $ctrl.ngModel.$viewValue; 1204 }; 1205 $timeout(function () { 1206 $ctrl.multiSelect = true; 1207 $ctrl.fetchUrl = $ctrl.fetchUrl || '/api/v1/network-autocomplete'; 1208 $ctrl.itemTemplate = KendoInputService.getNetworkItemTemplate(); 1209 $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl); 1210 $ctrl.selectOptions = KendoInputService.getNetworkRemoteOptions($ctrl); 1211 $ctrl.clearSelection = function () { 1212 $ctrl.value = []; 1213 $ctrl.ngModel.$setViewValue([]); 1214 }; 1215 }, 300); 1216 }; 1217 $ctrl.setUrlOverride = function (networkLookup) { 1218 $ctrl.getUrl = function () { 1219 var url = $ctrl.fetchUrl.split('?')[0]; 1220 url += "?networkLookup=".concat(encodeURI(networkLookup)); 1221 $ctrl.getUrl = null; 1222 return url; 1223 }; 1224 }; 1225 $ctrl.$postLink = function () { 1226 var kendoEl = $element.find('select.network-select'); 1227 $ctrl.multiselect = kendoEl.data('kendoMultiSelect'); 1228 }; 1229 }, 1230}); 1231inputComponents.component('kendoNetworkDropDown', { 1232 template: '<select class="network-dropdown h-50" ng-readonly="$ctrl.readonly" kendo-drop-down-list k-options="$ctrl.selectOptions" ng-model="$ctrl.value" aria-label="network selection dropdown"></select>', 1233 require: { 1234 ngModel: 'ngModel', 1235 }, 1236 bindings: { 1237 optionText: '@?', 1238 readonly: '=?', 1239 onChange: '&', 1240 fetchUrl: '@?', 1241 optionsFilter: '=?', 1242 }, 1243 controller: function ($scope, KendoInputService, $element, $timeout) { 1244 var $ctrl = this; 1245 $ctrl.$onInit = function () { 1246 var name = $ctrl.optionText || 'Default (Recipients Primary Network)'; 1247 $ctrl.ngModel.$render = function () { 1248 if ($ctrl.ngModel.$viewValue) 1249 $ctrl.setUrlOverride($ctrl.ngModel.$viewValue); 1250 $ctrl.value = $ctrl.ngModel.$viewValue; 1251 }; 1252 $timeout(function () { 1253 $ctrl.optionLabel = { name: name, _id: '' }; 1254 $ctrl.itemTemplate = KendoInputService.getNetworkItemTemplate(); 1255 $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl); 1256 $ctrl.selectOptions = KendoInputService.getNetworkRemoteOptions($ctrl); 1257 }, 100); 1258 }; 1259 $ctrl.setUrlOverride = function (networkLookup) { 1260 $ctrl.getUrl = function () { 1261 var url = $ctrl.fetchUrl.split('?')[0]; 1262 url += "?networkLookup=".concat(networkLookup); 1263 $ctrl.getUrl = null; 1264 return url; 1265 }; 1266 }; 1267 $ctrl.$postLink = function () { 1268 var kendoEl = $element.find('select.network-dropdown'); 1269 $ctrl.multiselect = kendoEl.data('kendoDropDownList'); 1270 }; 1271 $scope.$on('scope-value-change', function () { 1272 $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl); 1273 }); 1274 }, 1275}); 1276inputComponents.service('KendoInputService', function ($vhttp, vSession) { 1277 var _this = this; 1278 this.getRemoteDataSource = function ($controller) { 1279 var dataSource = new kendo.data.DataSource({ 1280 transport: { 1281 read: { 1282 url: $controller.fetchUrl, 1283 beforeSend: function (req) { 1284 req.setRequestHeader('Authorization', 'Bearer ' + vSession.token); 1285 if ($controller.getUrl) { 1286 this.url = $controller.getUrl(); 1287 return; 1288 } 1289 var value = _.get(dataSource, '_filter.filters[0].value'); 1290 this.url = this.url.split('&filter')[0]; 1291 if (value) { 1292 var key = $controller.queryProperty || 'name'; 1293 this.url += "&".concat(key, "=").concat(encodeURI(value)); 1294 } 1295 }, 1296 dataFilter: function (options) { 1297 if ($controller.optionsFilter) { 1298 options = JSON.stringify($controller.optionsFilter(JSON.parse(options))); 1299 } 1300 return options; 1301 }, 1302 }, 1303 }, 1304 pageSize: 20, 1305 serverPaging: $controller.serverPaging === 'false' ? false : true, 1306 serverFiltering: true, 1307 serverSorting: true, 1308 }); 1309 return dataSource; 1310 };
1311 this.getSelectOptions = function ($controller) { 1312 return { 1313 placeholder: $controller.placeholder || 'Select', 1314 optionLabel: $controller.optionLabel, 1315 filter: 'contains', 1316 rounded: 'sm', 1317 maxSelectedItems: $controller.maxSelectedItems || null, 1318 dataTextField: $controller.textField || 'name', 1319 dataValueField: $controller.valueField || '_id', 1320 headerTemplate: $controller.headerTemplate, 1321 value: $controller.value || [], 1322 valuePrimitive: true, 1323 autoBind: $controller.autoBind, 1324 delay: 1000, 1325 dataSource: $controller.dataSource, 1326 itemTemplate: $controller.itemTemplate, 1327 change: function (e) { 1328 var value = this.value(); 1329 if (_.isString(value) && !_.size(value)) 1330 value = null; 1331 var dataItem = value && typeof this.dataItem === 'function' ? this.dataItem() : null; 1332 var name = dataItem && dataItem._id && dataItem.name ? dataItem.name : undefined; 1333 if ($controller.onChange) { 1334 $controller.onChange({ value: value, name: name }); 1335 } 1336 if ($controller.ngModel) { 1337 $controller.ngModel.$setViewValue(value); 1338 } 1339 }, 1340 }; 1341 }; 1342 this.getNetworkRemoteOptions = function ($controller) { 1343 var remoteOptions = {}; 1344 if ($controller.multiSelect) { 1345 remoteOptions.deselect = function (e) { 1346 e.preventDefault(); 1347 $controller.value = _.without($controller.value, e.dataItem._id); 1348 $controller.ngModel.$setViewValue($controller.value); 1349 }; 1350 } 1351 return _.assign(remoteOptions, _this.getSelectOptions($controller)); 1352 }; 1353 this.getNetworkItemTemplate = function () { 1354 console.log('getNetworkItemTemplate', CONFIG.hideDetailsFromNetworkItemTemplate); 1355 if (CONFIG.hideDetailsFromNetworkItemTemplate) { 1356 return "<span class=\"k-state-default\" style=\"font-size:90%\">\n <b>#: data.name #</b>\n </span>"; 1357 } 1358 else { 1359 return "<span class=\"k-state-default\" style=\"font-size:90%\">\n <b>#: data.name #</b># if(data.ancestors && data.ancestors[0]) {# <br>\n <span class=\"small\">(Parent Network - #:data.ancestors[0].name#)</span> #} #<p>#: data.description #</p>\n </span>"; 1360 } 1361 }; 1362}); 1363inputComponents.component('kDatePicker', { 1364 template: "\n<input\n kendo-date-picker\n style=\"width: 100%;\"\n k-ng-model=\"$ctrl.date\"\n ng-disabled=\"$ctrl.ngDisabled\"\n k-options=\"$ctrl.kOptions\"\n k-delay=\"$ctrl.kOptions\"\n k-rebind=\"$ctrl.kOptions\">", 1365 require: { 1366 ngModel: 'ngModel', 1367 }, 1368 bindings: { 1369 min: '<', 1370 max: '<', 1371 ngRequired: '<?', 1372 required: '<?', 1373 ngDisabled: '<?', 1374 }, 1375 controller: function ($element) { 1376 var $ctrl = this; 1377 this.$postLink = function () { 1378 var _this = this; 1379 $ctrl.ngModel.$render = function () { return ($ctrl.date = $ctrl.ngModel.$viewValue); }; 1380 this.ngModel.$validators.validDate = function (modelValue, viewValue) { 1381 if (!modelValue && ($ctrl.required || $ctrl.ngRequired)) { 1382 return false; 1383 } 1384 var valid = $ctrl.validateDate(modelValue); 1385 return Boolean(valid); 1386 }; 1387 this.ready = true; 1388 if (this.changesReady) 1389 _.defer(function () { return _this.initializeDatePicker(_this.ngDisabled); }); 1390 }; 1391 this.$onChanges = function (_a) { 1392 var min = _a.min, max = _a.max; 1393 if (this.ready) { 1394 var clear = false; 1395 if ((min && !min.currentValue && min.previousValue) || 1396 (max && !max.currentValue && max.previousValue)) 1397 clear = true; 1398 this.initializeDatePicker(clear); 1399 } 1400 else { 1401 this.changesReady = true; 1402 } 1403 }; 1404 this.initializeDatePicker = function (clear) { 1405 var format = function (val) { return (val ? moment(val).toDate() : undefined); }; 1406 var min = format(this.min); 1407 var max = format(this.max); 1408 var isValid = this.validateDate($ctrl.ngModel.$modelValue); 1409 if ($ctrl.ngDisabled) { 1410 this.ngModel.$setValidity('validDate', isValid); 1411 if (!isValid) { 1412 $($element).find(':input').blur(); 1413 } 1414 return; 1415 } 1416 else if (!clear && isValid) { 1417 this.date = $ctrl.ngModel.$modelValue; 1418 } 1419 else { 1420 this.date = undefined; 1421 this.ngModel.$setViewValue(undefined); 1422 $($element).find(':input').blur(); 1423 } 1424 this.kOptions = { 1425 format: 'yyyy-MM-dd', 1426 showWeeks: false, 1427 min: min, 1428 max: max, 1429 change: function (e) { 1430 var newVal = moment(e.sender.value()); 1431 var val = newVal.isValid() ? newVal.format() : undefined; 1432 $ctrl.ngModel.$setViewValue(val, 'change'); 1433 }, 1434 }; 1435 }; 1436 this.validateDate = function (dateVal) { 1437 if (dateVal && 1438 $ctrl.min && 1439 moment(dateVal).isBefore(moment($ctrl.min, 'YYYY-MM-DD'))) { 1440 return false;
1441 } 1442 return !(dateVal && 1443 $ctrl.max && 1444 moment(dateVal).isAfter(moment($ctrl.max, 'YYYY-MM-DD'))); 1445 }; 1446 }, 1447}); 1448inputComponents.component('sourceOptions', { 1449 bindings: { 1450 ngModel: '=', 1451 selectId: '@', 1452 selectClass: '@?', 1453 }, 1454 template: "\n <select multiple\n notranslate\n ng-model=\"$ctrl.ngModel\"\n ng-init=\"hubConfig = $ctrl.CONFIG.commuteHub.features.tripLogs\"\n id=\"{{$ctrl.selectId}}\"\n name=\"eligibleTripSources\"\n class=\"form-control {{$ctrl.selectClass}}\">\n <optgroup label=\"{{ $ctrl.ngModel && $ctrl.ngModel.length ? 'Restricted to ' + $ctrl.ngModel.length + ' Apps' : 'No Restrictions Enabled' }}\">\n <option value=\"web\">Web Platform</option>\n <option value=\"astro\" ng-show=\"$ctrl.CONFIG.integrations.astro\">Commute Tracker</option>\n <option value=\"strava\" ng-show=\"$ctrl.CONFIG.integrations.strava.enabled\">Strava</option>\n <option value=\"scoop\" ng-show=\"$ctrl.CONFIG.integrations.scoop\">Scoop</option>\n <option value=\"ltr\" ng-show=\"$ctrl.CONFIG.integrations.ltr.enabled\">Love to Ride</option>\n <option value=\"gps-recording\" ng-show=\"$ctrl.CONFIG.commuteHub.features.tripRecording.enabled\">GPS Recording</option>\n <option ng-show=\"hubConfig.webAppSource\" value=\"{{hubConfig.webAppSource}}\" class=\"text-capitalize\">\n {{hubConfig.webAppSource}}\n </option>\n <option ng-show=\"hubConfig.nativeAppSource\" value=\"{{hubConfig.nativeAppSource}}\" class=\"text-capitalize\">\n {{hubConfig.nativeAppSource}}\n </option>\n </optgroup>\n </select>\n ", 1455 controller: function (CONFIG) { 1456 var $ctrl = this; 1457 $ctrl.CONFIG = CONFIG; 1458 }, 1459}); 1460; 1461'use strict'; 1462var layoutComponents = angular.module('layoutComponents', []); 1463layoutComponents.component('dashboardWidget', { 1464 transclude: { 1465 widgetHeader: '?widgetHeader', 1466 widgetContent: 'widgetContent', 1467 widgetFooter: '?widgetFooter', 1468 }, 1469 templateUrl: '/templates/system/components/layout/dashboard-widget.html', 1470 controller: function () { }, 1471}); 1472layoutComponents.component('programCard', { 1473 transclude: { 1474 cardImage: '?cardImage', 1475 cardHeader: 'cardHeader', 1476 cardContent: 'cardContent', 1477 cardFooter: '?cardFooter', 1478 }, 1479 templateUrl: '/templates/system/components/layout/program-card.html', 1480}); 1481; 1482'use strict'; 1483var navigationComponents = angular.module('navigationComponents', []); 1484navigationComponents.component('breadcrumbs', { 1485 transclude: true, 1486 template: '<h3 ng-transclude></h3>', 1487 controller: function () { 1488 var $ctrl = this; 1489 }, 1490}); 1491navigationComponents.component('tabs', { 1492 bindings: { 1493 tabs: '=', 1494 selectedTab: '=', 1495 setTabValue: '<?', 1496 onTabChange: '&?', 1497 disableStateUpdate: '=?', 1498 }, 1499 template: "\n <div class=\"d-flex flex-row py-15\">\n <div ng-repeat=\"tab in ::$ctrl.tabOptions\" class=\"mr-15\">\n <button class=\"tab-button btn btn-normal ls-2 text-uppercase bg-white\" ng-click=\"$ctrl.setTab(tab.value)\" ng-class=\"{'active':$ctrl.
1499selectedTab === tab.value}\">{{::tab.label}}</button>\n </div>\n </div>", 1500 controller: function ($state) { 1501 var $ctrl = this; 1502 this.$onInit = function () { 1503 $ctrl.selectTab = $ctrl.setTab; 1504 $ctrl.tabOptions = _.map($ctrl.tabs, function (tab) { return ({ 1505 label: tab.split('-').join(' '), 1506 value: tab, 1507 }); }); 1508 if (!$ctrl.selectedTab) { 1509 var tab = $state.params.tab || _.first($ctrl.tabs); 1510 $ctrl.setTab(tab, true); 1511 } 1512 }; 1513 this.$onChanges = function (changes) { 1514 if (changes.setTabValue && changes.setTabValue.currentValue) { 1515 $ctrl.selectedTab = changes.setTabValue.currentValue; 1516 } 1517 }; 1518 this.setTab = function (tab, firstChange) { 1519 if (tab !== $ctrl.selectedTab) { 1520 if (!firstChange && _.has($ctrl, 'onTabChange')) { 1521 $ctrl.onTabChange({ tab: tab }); 1522 } 1523 $ctrl.selectedTab = tab; 1524 } 1525 if (!$ctrl.disableStateUpdate && _.has($state.params, 'tab')) { 1526 $ctrl.updateState(tab); 1527 } 1528 }; 1529 this.updateState = function (tab) { 1530 var currentTab = $state.params.tab; 1531 if (currentTab !== tab) { 1532 $state.params.tab = tab; 1533 $state.transitionTo($state.current, $state.params, { notify: false }); 1534 } 1535 }; 1536 }, 1537}); 1538navigationComponents.component('multiStepContainer', { 1539 templateUrl: '/templates/system/components/navigation/multi-step-container.html', 1540 bindings: { 1541 onDone: '&', 1542 modelRef: '=', 1543 kendoWizardOptions: '=?', 1544 kendoWizard: '=?', 1545 currentStep: '=?', 1546 hideStepLabels: '=?', 1547 }, 1548 transclude: { 1549 steps: 'steps', 1550 }, 1551 controller: function ($element, $scope, $timeout) { 1552 var _this = this; 1553 var $ctrl = this; 1554 this.$onInit = function () { 1555 this.wizardElId = "wizard-".concat($scope.$id); 1556 }; 1557 this.getCurrentStepForm = function () { 1558 return _.get($scope.stepContainerForm, $ctrl.currentStep.options.formName, {}); 1559 }; 1560 this.handleStepValidation = function (event, onValid) { 1561 if (onValid === void 0) { onValid = _.noop; } 1562 var stepForm = $ctrl.getCurrentStepForm(); 1563 var isValid = stepForm.$valid; 1564 var skipValidation = event.sender.options.skipValidation; 1565 if (!isValid && !skipValidation) 1566 event.preventDefault(); 1567 event.sender.stepper.selectedStep.setValid(isValid); 1568 if (isValid) 1569 return onValid(); 1570 event.sender.trigger('formValidateFailed', $ctrl.currentStep); 1571 $timeout(stepForm.$setSubmitted); 1572 }; 1573 this.initWizard = function () { 1574 var steps = $ctrl.getSteps(); 1575 var wizardConfig = _.defaults($ctrl.kendoWizardOptions, { 1576 linear: true, 1577 done: function (e) { 1578 $ctrl.handleStepValidation(e, function () { return _.result($ctrl, 'onDone'); }); 1579 }, 1580 pager: steps.length > 1, 1581 messages: { 1582 done: 'SUBMIT', 1583 next: 'NEXT', 1584 previous: 'PREVIOUS', 1585 },
1586 clearButton: false, 1587 select: function (e) { 1588 var isNext = $ctrl.currentStep.options.index < e.step.options.index; 1589 if (isNext) 1590 $ctrl.handleStepValidation(e); 1591 }, 1592 formValidateFailed: function (e) { 1593 e.preventDefault(); 1594 }, 1595 activate: function (e) { 1596 $ctrl.setCurrentStep(e); 1597 }, 1598 steps: steps, 1599 }); 1600 var element = $("#".concat($ctrl.wizardElId)); 1601 element.kendoWizard(wizardConfig); 1602 $ctrl.kendoWizard = element.data('kendoWizard'); 1603 $ctrl.currentStep = $ctrl.kendoWizard.currentStep; 1604 if ($ctrl.hideStepLabels || isPhone) { 1605 $ctrl.kendoWizard.stepper.setOptions({ label: false }); 1606 } 1607 }; 1608 this.$postLink = function () { 1609 $timeout($ctrl.initWizard); 1610 }; 1611 this.getSteps = function () { 1612 var stepEls = $element.find('step'); 1613 var buttons; 1614 if (_.size(stepEls) === 1) 1615 buttons = ['done']; 1616 return _.map(stepEls, function (step, i) { 1617 var stepElm = angular.element(step); 1618 var label = stepElm.attr('label'); 1619 return { 1620 title: label, 1621 label: label, 1622 angularElement: stepElm, 1623 iconTemplate: stepElm.attr('icon-template'), 1624 icon: stepElm.attr('icon'), 1625 formName: "".concat(_.camelCase(label), "Form"), 1626 content: stepElm.contents(), 1627 buttons: buttons, 1628 }; 1629 }); 1630 }; 1631 this.setCurrentStep = function (e) { 1632 _this.currentStep = e.step; 1633 }; 1634 }, 1635}); 1636navigationComponents.component('step', { 1637 template: "\n <div id=\"{{::$ctrl.label}}\">\n <ng-form name=\"{{$ctrl.formName}}\">\n <ng-transclude></ng-transclude>\n </ng-form>\n </div>\n ", 1638 transclude: true, 1639 bindings: { 1640 label: '@', 1641 icon: '@?', 1642 iconTemplate: '@?', 1643 }, 1644 controller: function ($scope) { 1645 var $ctrl = this; 1646 this.$onInit = function () { 1647 $ctrl.formName = "".concat(_.camelCase($ctrl.label), "Form"); 1648 }; 1649 this.getForm = function () { return $scope[$ctrl.formName]; }; 1650 }, 1651}); 1652; 1653'use strict'; 1654var statsRow = angular.module('resource', []); 1655statsRow.component('resourceListNavigation', { 1656 bindings: { 1657 model: '<', 1658 onTabChange: '&', 1659 onSearchChange: '&', 1660 }, 1661 templateUrl: 'templates/system/components/resource-list-navigation.html', 1662 controller: function () { 1663 var $ctrl = this; 1664 $ctrl.$onInit = function () { 1665 $ctrl.states = { 1666 current: false, 1667 past: false, 1668 upcoming: false, 1669 }; 1670 }; 1671 }, 1672}); 1673; 1674'use strict'; 1675var selectionComponents = angular.module('selectionComponents', []); 1676selectionComponents.component('listSelection', { 1677 bindings: { 1678 list: '<', 1679 selected: '=', 1680 titleKey: '@', 1681 valueKey: '@', 1682 canSelectAll: '<', 1683 isDisabled: '<', 1684 noRequire: '<', 1685 }, 1686 templateUrl: 'templates/system/components/list-selection.html', 1687 controller: function ($timeout, $scope) { 1688 var $ctrl = this; 1689 this.selectedIndexes = []; 1690 this.allSelected = false; 1691 this.$onChanges = function (changes) { 1692 if (changes.list && 1693 !changes.list.previousValue && 1694 changes.list.currentValue) 1695 getSelected(); 1696 if (changes.isDisabled) 1697 handleDisabledChange(changes.isDisabled); 1698 }; 1699 function handleDisabledChange(change) {
1700 if (!change.isFirstChange() && change.currentValue) 1701 deselectAll(); 1702 else if (!change.isFirstChange() && 1703 !change.currentValue && 1704 change.previousValue) { 1705 deselectAll(); 1706 updateForm(); 1707 } 1708 } 1709 this.addItem = function (index) { 1710 var itemVal = $ctrl.list[index][$ctrl.valueKey]; 1711 if ($ctrl.selected.indexOf(itemVal) > -1) 1712 return; 1713 this.selected.push(itemVal); 1714 this.selectedIndexes.push(index); 1715 updateForm(); 1716 checkAllSelected(); 1717 }; 1718 this.removeItem = function (index) { 1719 var itemVal = $ctrl.list[index][$ctrl.valueKey]; 1720 this.selected = _.pull(this.selected, itemVal); 1721 this.selectedIndexes = _.pull($ctrl.selectedIndexes, index); 1722 updateForm(); 1723 checkAllSelected(); 1724 }; 1725 this.isChecked = function (index) { 1726 return this.selectedIndexes.length 1727 ? $ctrl.selectedIndexes.indexOf(index) > -1 1728 : false; 1729 }; 1730 this.handleCheck = function () { 1731 if (!$ctrl.allSelected) 1732 selectAll(); 1733 else 1734 deselectAll(); 1735 }; 1736 function checkAllSelected() { 1737 $ctrl.allSelected = 1738 $ctrl.list && $ctrl.selectedIndexes.length === $ctrl.list.length; 1739 } 1740 function getSelected() { 1741 if (!$ctrl.selected) 1742 return ($ctrl.selected = []); 1743 _.forEach($ctrl.list, function (item, index) { 1744 doCheck(item, index); 1745 }); 1746 checkAllSelected(); 1747 updateForm(true); 1748 } 1749 function doCheck(item, index) { 1750 if ($ctrl.selected.indexOf(item[$ctrl.valueKey]) !== -1) { 1751 $ctrl.selectedIndexes.push(index); 1752 } 1753 } 1754 function deselectAll() { 1755 $ctrl.allSelected = false; 1756 $ctrl.selected = []; 1757 $ctrl.selectedIndexes = []; 1758 updateForm(); 1759 } 1760 function selectAll() { 1761 $ctrl.selectedIndexes = _.range(0, $ctrl.list.length); 1762 $ctrl.selected = _.map($ctrl.list, $ctrl.valueKey); 1763 $ctrl.allSelected = true; 1764 updateForm(); 1765 } 1766 function updateForm(keepClean) { 1767 if (!keepClean) 1768 $scope['listSelection' + $scope.$id].$setDirty(); 1769 if (!$ctrl.isDisabled) { 1770 var valid = $ctrl.noRequire ? true : $ctrl.selected.length > 0; 1771 $scope['listSelection' + $scope.$id].$setValidity('required', valid); 1772 } 1773 else if ($ctrl.isDisabled) 1774 $scope['listSelection' + $scope.$id].$setValidity('required', true); 1775 } 1776 }, 1777}); 1778selectionComponents.component('daySelector', { 1779 template: '<label class="day-select-title" title="Eligible Days">{{ :: $ctrl.label }}</label>' + 1780 '<div class="carpool-days-row form-group" title="Weekly commute schedule">' + 1781 '<button ng-repeat="day in $ctrl.days" class="btn btn-default btn-sm text-uppercase" ng-class="{\'active\': $ctrl.isSelected(day)}" ng-click="$ctrl.toggleDaySelection(day)">{{ :: day }}</button>' + 1782 '</div>', 1783 require: { 1784 ngModel: 'ngModel', 1785 }, 1786 bindings: { 1787 label: '<?', 1788 onChange: '&?', 1789 }, 1790 controller: function () { 1791 var $ctrl = this; 1792 $ctrl.days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; 1793 $ctrl.$onInit = function () { 1794 $ctrl.label = $ctrl.label || 'ON THESE DAYS OF THE WEEK'; 1795 $ctrl.selected = $ctrl.selected || []; 1796 $ctrl.ngModel.$render = function () { 1797 $ctrl.selected = $ctrl.ngModel.$viewValue || $ctrl.selected; 1798 }; 1799 }; 1800 $ctrl.isSelected = function (day) { 1801 var index = $ctrl.days.indexOf(day) + 1; 1802 return $ctrl.selected.indexOf(index) !== -1; 1803 }; 1804 $ctrl.toggleDaySelection = function (day) { 1805 var index = $ctrl.days.indexOf(day) + 1; 1806 if ($ctrl.isSelected(day)) { 1807 $ctrl.selected = $ctrl.selected.filter(function (selectedDay) { 1808 return selectedDay !== index; 1809 }); 1810 } 1811 else { 1812 $ctrl.selected = $ctrl.selected.concat([index]); 1813 } 1814 $ctrl.selected.sort();
1815 $ctrl.ngModel.$setViewValue($ctrl.selected); 1816 if ($ctrl.onChange) 1817 $ctrl.onChange({ selected: $ctrl.selected }); 1818 }; 1819 }, 1820}); 1821; 1822'use strict'; 1823var statsRow = angular.module('stats', []); 1824statsRow.component('iconStatList', { 1825 bindings: { 1826 models: '<', 1827 columns: '@', 1828 }, 1829 templateUrl: 'templates/system/components/icon-stat-list.html', 1830 controller: function () { 1831 var $ctrl = this; 1832 $ctrl.displayFieldIcons = { 1833 Trips: 'road', 1834 Distance: 'route', 1835 'CO2 Saved': 'seedling', 1836 'Money Saved': 'piggy-bank', 1837 'Calories Burned': 'heartbeat', 1838 Points: 'map-marker-alt', 1839 }; 1840 $ctrl.dataColumIconMap = { 1841 participants: 'user', 1842 teamCount: 'route', 1843 networkCount: 'networks', 1844 trips: 'trips', 1845 miles: 'distance', 1846 co2Savings: 'plant', 1847 dollarsSavings: 'save', 1848 calories: 'calories', 1849 }; 1850 $ctrl.$onInit = function () { }; 1851 }, 1852}); 1853; 1854'use strict'; 1855var widgetComponents = angular.module('widgetComponents', []); 1856widgetComponents.component('networkJoinWidget', { 1857 template: "\n <div class=\"widget achievement-widget mt-15\" ng-if=\"$ctrl.availableProgramNetworks.length\">\n <div class=\"panel panel-default\">\n <div class=\"panel-heading border-none\">\n <h3 class=\"bold text-center text-uppercase\">{{ ::$ctrl.title }}</h3>\n </div>\n <div class=\"panel-body bg-white\" style=\"border-radius: 4px;\">\n <div class=\"px-15\">\n {{ ::$ctrl.description }}\n </div>\n\n <div ng-repeat=\"network in $ctrl.availableProgramNetworks\" class=\"d-flex justify-content-center p-15\">\n <img src=\"{{network.logoURL}}\" alt=\"network logo\" style=\"max-width: 50%; height: auto;\">\n </div>\n </div>\n <div class=\"panel-footer no-border-top text-center\" style=\"background-color: #ffffff\">\n <a class=\"btn btn-primary text-uppercase pt-6\" href ui-sref=\"account.edit.networks\">LEARN MORE</a>\n </div>\n </div>\n </div>\n ", 1858 controller: function (vSession, CONFIG, $vhttp) { 1859 var $ctrl = this; 1860 this.$onInit = function () { 1861 if (!_.get(CONFIG, 'premiumNetworks.multiPrimaryNetworkEnabled')) { 1862 return; 1863 } 1864 this.bindContent(); 1865 this.bindNetworks(); 1866 }; 1867 this.bindContent = function () { 1868 this.title = _.get(CONFIG, 'regionalNetworkWidgetLanguage.title'); 1869 this.description = _.get(CONFIG, 'regionalNetworkWidgetLanguage.description'); 1870 }; 1871 this.bindNetworks = function () { 1872 $vhttp 1873 .get('/api/v1/users/' + vSession.user._id + '/available-programs') 1874 .then(function (res) { 1875 $ctrl.availableProgramNetworks = res; 1876 }) 1877 .catch(_.noop); 1878 }; 1879 }, 1880}); 1881; 1882'use strict'; 1883var appNavbar = angular.module('appNavbar', []); 1884appNavbar.directive('navbarManageList', function ($state, $rootScope, SessionUserDataService, EnabledTools) { 1885 return { 1886 restrict: 'A', 1887 scope: {}, 1888 templateUrl: '/templates/navbar/navbar-manage-list.html', 1889 link: function ($scope) { 1890 var parentStates = EnabledTools.getParentStates(), rootWatch = null, networkWatch = null, authorization = null; 1891 init(); 1892 function init() { 1893 asyncSetup(); 1894 } 1895 function asyncSetup() { 1896 authorization = $rootScope.$watch('authorizationPending', function (newValue, oldValue) { 1897 if (newValue != oldValue) { 1898 authorization(); 1899 syncSetup(); 1900 } 1901 }); 1902 } 1903 function syncSetup() { 1904 $scope.enabledTools = EnabledTools.getCategories(); 1905 setup(); 1906 } 1907 function setup() { 1908 if (!_.isEmpty($scope.enabledTools)) { 1909 setupNetworkWatcher(); 1910 if (SessionUserDataService.user.isAdmin && 1911 $scope.enabledTools.tool) { 1912 $scope.enabledTools.tool.unshift(getAdminDashboard()); 1913 $scope.tracesEnabled = canDebug(); 1914 } 1915 } 1916 setColSize(); 1917 stateHandler({}, $state.current); 1918 setupRootWatcher(); 1919 } 1920 function setupRootWatcher() { 1921 rootWatch = $rootScope.$on('$stateChangeStart', stateHandler); 1922 } 1923 function canDebug() { 1924 if (window.CONFIG.tracesDebugEnabled) {
1925 var validEmailDomain = window.CONFIG.debugEmailDomain; 1926 var email = SessionUserDataService.user && SessionUserDataService.user.email; 1927 var domain = email.split('@')[1]; 1928 return domain === validEmailDomain; 1929 } 1930 return false; 1931 } 1932 function stateHandler(event, toState, toParams, fromState, fromParams) { 1933 $scope.activeState = toState.name; 1934 $scope.isActiveChildState = 1935 parentStates.indexOf(getParentState($scope.activeState)) > -1; 1936 } 1937 function setupNetworkWatcher() { 1938 if (CONFIG.hideNetworkManageMenu) { 1939 return; 1940 } 1941 networkWatch = $scope.$watch(function () { 1942 return SessionUserDataService.managednetworks; 1943 }, function (newValue, oldValue) { 1944 if (!newValue && !oldValue) 1945 return; 1946 if (newValue.length) { 1947 setNetworkManage(); 1948 setColSize(); 1949 networkWatch(); 1950 } 1951 }); 1952 } 1953 function setNetworkManage() { 1954 $scope.enabledTools.networkmanage = [ 1955 getNetworkManage(), 1956 getNetworkDashboard(), 1957 ]; 1958 } 1959 function getParentState(fullStateName) { 1960 return fullStateName.slice(0, fullStateName.indexOf('.')); 1961 } 1962 function getNetworkManage() { 1963 return { 1964 adminEnabled: true, 1965 name: 'View All', 1966 baseRoute: 'reporting.network.managed-networks', 1967 category: 'networkmanage', 1968 description: 'Dashboard overview of admin features', 1969 entryPointRoute: 'reporting.network.managed-networks', 1970 }; 1971 } 1972 function getNetworkDashboard() { 1973 var defaultItem = { 1974 name: 'Management Dashboard', 1975 description: 'Networks, Reports, and more', 1976 showDescription: true, 1977 baseRoute: 'premium.dashboard', 1978 entryPointRoute: 'premium.dashboard.home', 1979 adminEnabled: false, 1980 networkAdminEnabled: true, 1981 }; 1982 var def = _.find(CONFIG.toolsMenuMega, { name: defaultItem.name }); 1983 return def || defaultItem; 1984 } 1985 function getAdminDashboard() { 1986 return { 1987 adminEnabled: true, 1988 name: 'Admin Dashboard', 1989 baseRoute: 'admin.dashboard', 1990 category: 'tool', 1991 description: 'Dashboard overview of admin features', 1992 entryPointRoute: 'admin.dashboard', 1993 }; 1994 } 1995 function setColSize() { 1996 $scope.colSize = ~~(12 / Object.keys($scope.enabledTools).length); 1997 } 1998 $scope.$on('$destroy', function () { 1999 if (networkWatch) 2000 networkWatch(); 2001 if (rootWatch) 2002 rootWatch(); 2003 rootWatch = networkWatch = null; 2004 }); 2005 }, 2006 }; 2007}); 2008appNavbar.directive('navbarListItem', function (SessionUserDataService) { 2009 return { 2010 restrict: 'A', 2011 scope: { 2012 enabled: '=', 2013 name: '=', 2014 isActiveState: '=', 2015 canDebug: '=', 2016 }, 2017 template: "<ul class=\"list-container-list\">\n <li class=\"list-item dropdown-header\" ng-if=\":: lookup[name]\">{{ :: lookup[name] }}</li>\n <li class=\"list-item\" ng-repeat=\"tool in enabled\">\n <a ng-if=\"!tool.customLink\" class=\"item-link\" href analytics-on ui-sref=\"{{tool.entryPointRoute}}\"\n data-description=\"{{:: tool.description}}\"\n ng-class=\"{ active : isActiveState === tool.entryPointRoute }\">{{:: tool.name}}
2017\n <span ng-if=\"tool.showDescription\" aria-hidden=\"true\"><br><em><small>{{:: tool.description}}</small></em></span>\n </a>\n <a ng-if=\"tool.customLink\" class=\"item-link\" ng-href=\"{{tool.customLink}}\" target=\"{{target = tool.target || '_blank'}}\" analytics-on\n data-description=\"{{:: tool.description}}\">{{:: tool.name}}\n <span ng-if=\"tool.showDescription\"><br><em><small>{{:: tool.description}}</small></em></span>\n </a>\n </li>\n <li class=\"list-item\" ng-if=\"showTraces\">\n <a class=\"item-link\" href=\"/app/traces/dashboard\">Traces Debugger</a>\n </li>\n </ul>\n <navbar-my-networks-item user-networks=\"managednetworks\" ng-if=\"showNetworks\"></navbar-my-networks-item>", 2018 link: function ($scope) { 2019 $scope.lookup = { 2020 program: 'programs', 2021 systemreport: 'System Reports', 2022 networkmanage: 'Network Manage', 2023 tool: 'tools', 2024 mynetworks: 'My Networks', 2025 moretools: ' ', 2026 }; 2027 $scope.managednetworks = SessionUserDataService.managednetworks; 2028 $scope.showNetworks = 2029 $scope.name === 'networkmanage' && $scope.managednetworks.length; 2030 $scope.showTraces = $scope.canDebug && $scope.name === 'tool'; 2031 }, 2032 }; 2033}); 2034appNavbar.directive('navbarMyNetworksItem', function ($state, $filter) { 2035 return { 2036 restrict: 'EA', 2037 scope: { 2038 userNetworks: '=', 2039 }, 2040 template: '<div class="divider"></div>' + 2041 '<ul class="list-container-list" style="max-height: 250px; overflow-y: auto;">' + 2042 '<li class="list-item dropdown-header">My Networks</li>' + 2043 '<li class="list-item" ng-repeat="tool in networkData">' + 2044 '<a class="item-link" href analytics-on ui-sref="networkadmin.overview({network:tool._id})"' + 2045 'data-description="{{tool.description}}"' + 2046 'ng-class="{ active: $state.includes(tool.entryPointRoute) }">{{:: tool.name}}' + 2047 '<small class="text-muted" ng-if="tool.ancestors.length"' + 2048 'ng-repeat="ancestor in tool.ancestors"><br><i>{{:: ancestor.name}}</i>' + 2049 '</small>' + 2050 '</a>' + 2051 '</li>' + 2052 '</ul>', 2053 link: function ($scope) { 2054 $scope.networkData = $filter('orderBy')($scope.userNetworks, 'name'); 2055 }, 2056 }; 2057}); 2058appNavbar.directive('navbarProgramList', function ($state, $rootScope, EnabledPrograms) { 2059 return { 2060 restrict: 'A', 2061 scope: {}, 2062 templateUrl: '/templates/navbar/navbar-program-list.html', 2063 link: function ($scope) { 2064 $scope.programs = new EnabledPrograms(); 2065 $scope.colSize = ~~(12 / $scope.programs.length); 2066 stateHandler({}, $state.current, $state.params); 2067 function stateHandler(event, toState, toParams, fromState, fromParams) { 2068 $scope.activeState = toParams.tab 2069 ? buildQueryStringUrl(toState.name, 'tab', toParams.tab) 2070 : toState.name; 2071 $scope.isActiveChildState = 2072 $scope.activeState === 'challenges.list' || 2073 $scope.activeState === "incentives.list({tab:'available'})" || 2074 $scope.activeState === "incentives.list({tab:'points'})"; 2075 } 2076 function buildQueryStringUrl(name, key, value) { 2077 return name + '({' + key + ':' + "\'" + value + "\'" + '})'; 2078 } 2079 $rootScope.$on('$stateChangeStart', stateHandler); 2080 }, 2081 }; 2082}); 2083appNavbar.directive('programListItem', function () { 2084 return { 2085 restrict: 'A', 2086 scope: { 2087 program: '=', 2088 isActiveState: '=', 2089 }, 2090 template: '<ul class="list-container-list text-center">' + 2091 '<li class="list-item program">' + 2092 '<a class="item-link"' + 2093 'ng-class="{ active : isActiveState === program.entryPoint }"' + 2094 'ng-if="program.link" ng-href="{{:: program.link}}">' + 2095 '<img ng-src="{{:: program.img }}" ng-if="program.img">
2095' + 2096 '<h2 class="dropdown-header">{{:: program.header}}</h2><span ng-bind-html="program.paragraph"></span>' + 2097 '<button class="btn btn-small btn-info" ng-if="program.entryPoint && !program.static">{{:: program.buttonText}}</button>' + 2098 '</a>' + 2099 '<a class="item-link"' + 2100 'ng-class="{ active : isActiveState === program.entryPoint }"' + 2101 'ng-if="!program.link" ui-sref="{{:: program.entryPoint}}">' + 2102 '<img ng-src="{{:: program.img }}" ng-if="program.img">' + 2103 '<h2 class="dropdown-header">{{:: program.header}}</h2><span ng-bind-html="program.paragraph"></span>' + 2104 '<button class="btn btn-small btn-info" ng-if="program.entryPoint && !program.static">{{:: program.buttonText}}</button>' + 2105 '</a>' + 2106 '</li></ul>', 2107 link: function ($scope) { }, 2108 }; 2109}); 2110; 2111'use strict'; 2112var appDirectives = angular.module('appDirectives', ['appNavbar']); 2113appDirectives.directive('debounceClick', function ($timeout) { 2114 return { 2115 restrict: 'A', 2116 link: function ($scope, $element, $attrs) { 2117 var orgContent; 2118 bindEvents(); 2119 function bindEvents() { 2120 $element.bind('click', function () { 2121 if ($attrs.pendingText) { 2122 orgContent = $element.text(); 2123 $element.text($attrs.pendingText); 2124 } 2125 $element.attr('disabled', true); 2126 $timeout(rollbackElement, $attrs.duration || 500); 2127 }); 2128 } 2129 function rollbackElement() { 2130 $element.attr('disabled', false); 2131 if ($attrs.pendingText) { 2132 $element.text(orgContent); 2133 } 2134 } 2135 }, 2136 }; 2137}); 2138appDirectives.directive('toggleContrast', function ($localstorage) { 2139 return { 2140 restrict: 'A', 2141 link: function ($scope, $elem, $attrs) { 2142 $scope.contrastEnabled = getPreference(); 2143 $(document).ready(function () { 2144 if ($scope.contrastEnabled) 2145 turnOn(); 2146 else 2147 turnOff(); 2148 }); 2149 $elem.on('click', toggleContrast); 2150 function toggleContrast() { 2151 if ($scope.contrastEnabled) 2152 turnOff(); 2153 else 2154 turnOn(); 2155 $scope.$apply(function () { 2156 $scope.contrastEnabled = !$scope.contrastEnabled; 2157 }); 2158 storePreference(); 2159 } 2160 function getPreference() { 2161 return ($localstorage.get('highContrastEnabled', 'disabled') === 'enabled'); 2162 } 2163 function storePreference() { 2164 $localstorage.set('highContrastEnabled', $scope.contrastEnabled ? 'enabled' : 'disabled'); 2165 } 2166 function turnOn() { 2167 $('body').addClass('high-contrast'); 2168 } 2169 function turnOff() { 2170 $('body').removeClass('high-contrast'); 2171 } 2172 }, 2173 }; 2174}); 2175appDirectives.directive('roundNumberSmart', function () { 2176 return { 2177 require: 'ngModel', 2178 restrict: 'A', 2179 link: function ($scope, $elem, $attrs, $ctrl) { 2180 var ngModelCtrl = $ctrl, _keyUpHandler = _.debounce(handleUp, 600); 2181 ngModelCtrl.$formatters.push(function (value) { 2182 return value || 1; 2183 }); 2184 ngModelCtrl.$parsers.unshift(function (value) { 2185 if (value && isNumber(value) && isDecimal(value)) { 2186 value = parseFloat(value).toFixed(2); 2187 } 2188 else { 2189 value = ~~value; 2190 } 2191 ngModelCtrl.$setViewValue(value); 2192 return value; 2193 }); 2194 function handleUp() { 2195 var value = parseFloat(ngModelCtrl.$viewValue), domValue = $elem.val(); 2196 if (domValue && parseFloat(domValue) !== value) { 2197 $elem.val(ngModelCtrl.$viewValue); 2198 } 2199 } 2200 function isNumber(value) { 2201 return typeof value === 'number' || !Number.isNaN(parseFloat(value)); 2202 } 2203 function isDecimal(value) { 2204 return value % 1 !== 0; 2205 } 2206 $elem.on('keyup', _keyUpHandler); 2207 $scope.$on('$destroy', function () { 2208 $elem.off('keyup', _keyUpHandler); 2209 }); 2210 }, 2211 }; 2212}); 2213appDirectives.directive('scrollSpy', function ($timeout, elementHelper) { 2214 return { 2215 restrict: 'A', 2216 scope: { 2217 customClass: '@', 2218 triggerOffset: '=?', 2219 }, 2220 link: function ($scope, $element, $attrs) { 2221 var spies = []; 2222 var $window = $(window); 2223 var currentIndex = 0; 2224 var loading = true; 2225 $scope.customClass = $scope.customClass ? $scope.customClass : 'active'; 2226 $(document).ready(function () { 2227 $timeout(init, 300); 2228 });
2229 function init() { 2230 changeDetection(); 2231 $window.on('scroll', handler); 2232 } 2233 function handler() { 2234 if (!elementHelper.isOnSmallScreen()) { 2235 findSpy(); 2236 } 2237 } 2238 function getScrollPos() { 2239 return ($(window).scrollTop() + 2240 elementHelper.getNavHeight() + 2241 ($scope.triggerOffset || 100)); 2242 } 2243 function findSpy() { 2244 if (!loading && spies.length) { 2245 if (!$window) 2246 return; 2247 var scrollPos = getScrollPos(); 2248 if (scrollPos < spies[0].offsetTop && currentIndex !== 0) { 2249 toggleHighlight(0, currentIndex); 2250 } 2251 else if (elementHelper.isScrolledBtm(20)) { 2252 toggleHighlight(spies.length - 1, currentIndex); 2253 } 2254 else if (spies.length > 3 && 2255 getElementHeight(spies.length - 1) + 2256 getElementHeight(spies.length - 2) < 2257 $window.height() && 2258 elementHelper.isScrolledBtm(200)) { 2259 toggleHighlight(spies.length - 2, currentIndex); 2260 } 2261 else { 2262 rotateThrough(scrollPos); 2263 } 2264 } 2265 } 2266 function toggleHighlight(add, remove) { 2267 removeClass(remove); 2268 addClass(add); 2269 } 2270 function getElementHeight(index) { 2271 return spies[index] 2272 ? spies[index].elementBottom - spies[index].elementTop 2273 : 0; 2274 } 2275 function rotateThrough(scrollPos) { 2276 _.forEach(spies, function (spy, index) { 2277 if ((scrollPos >= spy.elementTop && index === spies.length - 1) || 2278 (spies.length > 1 && scrollPos < spies[index + 1].elementTop)) { 2279 toggleHighlight(index, currentIndex); 2280 return false; 2281 } 2282 }); 2283 } 2284 function getSpies() { 2285 spies = _.sortBy(_.map($('div[spy]'), function (spy) { 2286 return { 2287 element: spy, 2288 targetId: spy.getAttribute('spy'), 2289 elementTop: $(spy).offset().top, 2290 elementBottom: $(spy).offset().top + $(spy).outerHeight(), 2291 }; 2292 }), 'elementTop'); 2293 } 2294 function addClass(index) { 2295 var el = spies[index] 2296 ? document.getElementById(spies[index].targetId) 2297 : null; 2298 if (el) { 2299 currentIndex = index; 2300 el.classList.add($scope.customClass); 2301 } 2302 else { 2303 console.warn('spy element not found index:', index); 2304 } 2305 } 2306 function removeClass(index) { 2307 var el = spies[index] 2308 ? document.getElementById(spies[index].targetId) 2309 : null; 2310 if (el) { 2311 el.classList.remove($scope.customClass); 2312 } 2313 else { 2314 console.warn('spy element not found index:', index); 2315 } 2316 } 2317 var debounceChange = _.debounce(changeDetection, 300); 2318 function changeDetection() { 2319 getSpies(); 2320 loading = false; 2321 findSpy(); 2322 } 2323 function handleSpy() { 2324 if (!loading) { 2325 loading = true; 2326 debounceChange(); 2327 } 2328 } 2329 var newSpy = $scope.$on('newSpy', handleSpy); 2330 var downSpy = $scope.$on('spyDown', handleSpy); 2331 $scope.$on('$destroy', function () { 2332 $window.off('scroll', handler); 2333 newSpy(); 2334 downSpy(); 2335 debounceChange = spies = $window = currentIndex = loading = null; 2336 }); 2337 }, 2338 }; 2339}); 2340appDirectives.directive('spy', function ($timeout, $rootScope) { 2341 return { 2342 restrict: 'A', 2343 link: function ($scope, $element, $attrs) { 2344 $rootScope.$broadcast('newSpy'); 2345 $scope.$on('$destroy', function () { 2346 $rootScope.$broadcast('spyDown'); 2347 }); 2348 }, 2349 }; 2350}); 2351appDirectives.directive('stickyOnScroll', function ($timeout) { 2352 return { 2353 restrict: 'A', 2354 link: function ($scope, $element, $attrs) { 2355 var plane = null; 2356 var $window = null; 2357 var db = null; 2358 var resizeFn = null; 2359 var deRegisterFn = null; 2360 var outOfViewFn = null; 2361 var inViewFn = null; 2362 init();
2363 function init() { 2364 $window = $(window); 2365 plane = getPlane($window, $element); 2366 outOfViewFn = $attrs.fromOffScreen ? 'isOffScreen' : 'isAtPlaneEdge'; 2367 inViewFn = $attrs.fromOffScreen 2368 ? 'isOnScreen' 2369 : 'isScrolledToElementCoordinates'; 2370 if (!resizeFn) { 2371 resizeFn = $timeout(function () { 2372 db = _.debounce(resize, 300); 2373 $window.on('resize', db); 2374 }); 2375 } 2376 if (plane.isOnSmallScreen()) { 2377 return; 2378 } 2379 $element.css('transition', 'top .8s linear'); 2380 if (!deRegisterFn) { 2381 deRegisterFn = $timeout(function () { 2382 $window.on('scroll', checkVisibility); 2383 }); 2384 } 2385 } 2386 function destroyEventHandlers() { 2387 $window.off('scroll', checkVisibility); 2388 $window.off('resize', db); 2389 } 2390 function resize() { 2391 if (plane.element.manipulated) { 2392 if (plane.element.hasMoved) { 2393 removeSticky($element); 2394 } 2395 } 2396 resetVars(); 2397 init(); 2398 } 2399 function checkVisibility() { 2400 if (plane.element[outOfViewFn]()) { 2401 plane.element.move(setSticky.bind(this, $element)); 2402 } 2403 else { 2404 if (plane.element.hasMoved) { 2405 if (plane.element[inViewFn]()) { 2406 plane.element.move(removeSticky.bind(this, $element)); 2407 } 2408 } 2409 } 2410 } 2411 function setSticky($el) { 2412 $el 2413 .css('width', plane.element.computed['width']) 2414 .css('right', plane.element.distanceFromRightViewport()) 2415 .css('position', 'fixed') 2416 .css('top', plane.element.toTop() + 5); 2417 } 2418 function removeSticky($el) { 2419 $el 2420 .css('width', '') 2421 .css('right', '') 2422 .css('position', '') 2423 .css('top', ''); 2424 } 2425 function resetVars() { 2426 $window = outOfViewFn = inViewFn = plane = null; 2427 } 2428 function top() { 2429 var nav = $('.navbar'), sub = nav.parent().find('.subsite-navbar'), top = ~~(nav.outerHeight() + sub.outerHeight()); 2430 nav = sub = null; 2431 return top; 2432 } 2433 function getPlane($window, $element) { 2434 return { 2435 element: { 2436 computed: window.getComputedStyle($element[0]), 2437 coordinates: {}, 2438 getCoordinates: function () { 2439 this.coordinates = $element[0].getBoundingClientRect(); 2440 this.coordinates.y = this.coordinates.y || this.coordinates.top; 2441 }, 2442 hasMoved: false, 2443 manipulated: false, 2444 toTop: _.memoize(top), 2445 _private: { 2446 getIntFromStyleProperty: function (str) { 2447 return parseInt(str.slice(0, -2)); 2448 }, 2449 }, 2450 isOffScreen: function () { 2451 this.getCoordinates(); 2452 return (this.coordinates.y + ~~(this.coordinates.height / 2) < 2453 this.toTop()); 2454 }, 2455 isAtPlaneEdge: function () { 2456 this.getCoordinates(); 2457 return ~~this.coordinates.y <= this.toTop(); 2458 }, 2459 isScrolledToElementCoordinates: function () { 2460 this.getCoordinates(); 2461 return $window.scrollTop() < this.coordinates.y; 2462 }, 2463 isOnScreen: function () { 2464 this.getCoordinates(); 2465 return ($window.scrollTop() < 2466 this.coordinates.height + this.coordinates.y); 2467 }, 2468 move: function (cb) { 2469 this.hasMoved = !this.hasMoved; 2470 this.manipulated = true; 2471 cb(); 2472 }, 2473 distanceFromRightViewport: function () { 2474 var right = $window.width() - 2475 ($element.offset().left + $element.outerWidth()); 2476 return (Math.round(right) - 2477 this._private.getIntFromStyleProperty(this.computed['marginRight'])); 2478 }, 2479 }, 2480 isOnSmallScreen: function () { 2481 return $window.innerWidth() < 992; 2482 }, 2483 }; 2484 } 2485 function destroyWatchers() { 2486 deRegisterFn = null; 2487 resizeFn = null; 2488 db = null; 2489 } 2490 $element.on('$destroy', function () { 2491 if (deRegisterFn && _.isFunction(deRegisterFn)) 2492 deRegisterFn(); 2493 if (resizeFn && _.isFunction(resizeFn)) 2494 resizeFn(); 2495 destroyEventHandlers(); 2496 destroyWatchers(); 2497 resetVars(); 2498 }); 2499 }, 2500 }; 2501}); 2502appDirectives.directive('autoViewHeight', function ($window, elementHelper) { 2503 return { 2504 link: function (scope, element, attrs) { 2505 setHeight(); 2506 function setHeight() { 2507 var height = $window.innerHeight - elementHelper.getNavHeight() + 'px'; 2508 element.css('height', height); 2509 } 2510 var handler = _.debounce(setHeight, 300); 2511 _.defer(function () { return angular.element($window).on('resize', handler); }, 300); 2512 var cleanup = function () { return angular.element($window).off('resize', handler); }; 2513 scope.$on('$destroy', cleanup); 2514 }, 2515 }; 2516}); 2517appDirectives.directive('commuteHubEmbeddedView', function ($window, elementHelper, CONFIG) { 2518 return { 2519 restrict: 'A', 2520 link: function (scope, element, attrs) { 2521 var originalInnerBodyMinHeight; 2522 var originalBodyOverflow; 2523 $(element).ready(setLayout); 2524 function setLayout() { 2525 var navHeight = elementHelper.getNavHeight(); 2526 var footerHeight = elementHelper.getFooterHeight(); 2527 var heightAdjustment = CONFIG.commuteHubEmbeddedViewHeightAdjustment || 0; 2528 var height = $window.innerHeight; 2529 var innerBody = $('#innerBody'); 2530 if (!originalInnerBodyMinHeight) { 2531 originalInnerBodyMinHeight = innerBody.css('min-height'); 2532 } 2533 var minHeight = 300; 2534 var availableHeight = height - (navHeight + footerHeight) - heightAdjustment; 2535 var finalHeight = Math.max(minHeight, availableHeight); 2536 innerBody.css('min-height', height - navHeight - heightAdjustment + 'px'); 2537 var body = $('body'); 2538 if (!originalBodyOverflow) { 2539 originalBodyOverflow = body.css('overflow'); 2540 body.css('overflow', 'hidden'); 2541 } 2542 var width = $window.innerWidth + 'px'; 2543 element.css({ 2544 position: 'fixed', 2545 top: navHeight + 'px', 2546 bottom: footerHeight + 'px', 2547 height: finalHeight + 'px', 2548 width: width, 2549 border: 0, 2550 }); 2551 } 2552 var handler = _.debounce(setLayout, 300); 2553 _.defer(function () { return angular.element($window).on('resize', handler); }, 300); 2554 var cleanup = function () { 2555 angular.element($window).off('resize', handler); 2556 var innerBody = $('#innerBody'); 2557 var body = $('body'); 2558 if (originalInnerBodyMinHeight && innerBody) { 2559 innerBody.css('min-height', originalInnerBodyMinHeight); 2560 } 2561 if (originalBodyOverflow && body) { 2562 body.css('overflow', originalBodyOverflow); 2563 } 2564 }; 2565 scope.$on('$destroy', cleanup); 2566 }, 2567 }; 2568}); 2569appDirectives.directive('displayAsDollars', function () { 2570 return { 2571 require: 'ngModel', 2572 restrict: 'A', 2573 link: function ($scope, $elem, $attrs, $ctrl) { 2574 $ctrl.$formatters.unshift(function (val) { 2575 return (parseInt(val) / 100).toFixed(2); 2576 }); 2577 $ctrl.$parsers.unshift(function (val) { 2578 val = parseFloat(val); 2579 return parseInt(val * 100); 2580 }); 2581 }, 2582 }; 2583}); 2584appDirectives.directive('rotateImage', function () { 2585 return { 2586 scope: { 2587 rotateImage: '=', 2588 }, 2589 restrict: 'A', 2590 link: function (scope, $elem, $attr) { 2591 var rotate_factor = 0; 2592 scope.rotateImage = function () { 2593 rotate_factor += 1; 2594 var rotate_angle = (90 * rotate_factor) % 360; 2595 $elem[0].style.transform = "rotate(".concat(rotate_angle, "deg)"); 2596 }; 2597 }, 2598 }; 2599}); 2600appDirectives.directive('pwaModalCloseHandler', function ($rootScope) { 2601 return { 2602 restrict: 'A', 2603 link: function (scope, $elem, $attr) { 2604 var handleEvent = function (e) { 2605 if (window.location.origin !== e.origin) 2606 return false;
2607 if (e.data === 'closeApp') { 2608 removeEventListener(); 2609 $rootScope.globalModalHide(); 2610 } 2611 }; 2612 var removeEventListener = function () { 2613 return window.removeEventListener('message', handleEvent, false); 2614 }; 2615 window.addEventListener('message', handleEvent, false); 2616 $rootScope.$on('modalHidden', function () { 2617 removeEventListener(); 2618 }); 2619 }, 2620 }; 2621}); 2622appDirectives.directive('iframeResizeInjector', function () { 2623 return { 2624 restrict: 'A', 2625 scope: { 2626 onDestroy: '&?', 2627 resizerOptions: '=', 2628 }, 2629 link: function (scope, $elem, $attr) { 2630 var parentScriptEl = createScriptEl('iframeResizer.min.js'); 2631 var childScriptEl = createScriptEl('iframeResizer.contentWindow.min.js'); 2632 function loadResize() { 2633 $elem.append(parentScriptEl); 2634 } 2635 function createScriptEl(file) { 2636 var script = document.createElement('script'); 2637 script.src = "/js/libs/iframe-resizer-4.3.2/".concat(file); 2638 return script; 2639 } 2640 $(document).ready(function () { 2641 if (!window.iFrameResize) 2642 loadResize(); 2643 var iframeEl = $($elem[0].querySelector('iframe')); 2644 iframeEl.on('load', function (event) { 2645 $(this).contents().find('body')[0].append(childScriptEl); 2646 var iframeId = event.target.id ? "#".concat(event.target.id) : null; 2647 var options = _.isObject(scope.resizerOptions) 2648 ? scope.resizerOptions 2649 : { log: false, heightCalculationMethod: 'lowestElement' }; 2650 new iFrameResize(options, iframeId); 2651 if (scope.onDestroy) { 2652 scope.$on('$destroy', function () { return _.result(scope, 'onDestroy'); }); 2653 } 2654 }); 2655 }); 2656 }, 2657 }; 2658}); 2659appDirectives.directive('dynamicContent', function ($compile, $filter, ContentManagementService) { 2660 return { 2661 restrict: 'A', 2662 link: function (scope, element, attrs) { 2663 var contentWatcher = null; 2664 var contentKey; 2665 var observer = attrs.$observe('dynamicContent', function (value) { 2666 if (!value || value === contentKey) 2667 return; 2668 contentKey = value; 2669 if (ContentManagementService.isLoaded()) { 2670 applyContent(); 2671 return; 2672 } 2673 listenForContent(); 2674 }); 2675 function listenForContent() { 2676 if (contentWatcher) 2677 return; 2678 contentWatcher = scope.$watch(function () { 2679 return ContentManagementService.isLoaded(); 2680 }, function (loaded) { 2681 if (loaded) { 2682 applyContent(); 2683 destroyContentWatcher(); 2684 } 2685 }); 2686 } 2687 function destroyContentWatcher() { 2688 observer(); 2689 if (!contentWatcher) 2690 return; 2691 contentWatcher(); 2692 contentWatcher = null; 2693 } 2694 function applyContent() { 2695 var content = ContentManagementService.getContent(contentKey); 2696 if (content) { 2697 var markdown = $filter('markdownToHTML')(content); 2698 element.html(markdown.toString()); 2699 $compile(element.contents())(scope); 2700 } 2701 } 2702 scope.$on('$destroy', destroyContentWatcher); 2703 }, 2704 }; 2705}); 2706appDirectives.directive('kCheckboxGroup', [ 2707 '$timeout', 2708 function ($timeout) { 2709 return { 2710 require: 'ngModel', 2711 scope: { 2712 items: '=', 2713 kOptions: '=', 2714 }, 2715 link: function (scope, element, attrs, ngModelCtrl) { 2716 $timeout(function () { 2717 var kOptions = _.defaults(scope.kOptions, { 2718 layout: 'vertical', 2719 inputName: attrs.inputName, 2720 items: scope.items, 2721 }); 2722 var checkboxGroup = $(element) 2723 .kendoCheckBoxGroup(__assign(__assign({}, kOptions), { change: function (e) { 2724 var checkedItems = this.value(); 2725 $timeout(function () { 2726 ngModelCtrl.$setViewValue(checkedItems); 2727 }); 2728 } })) 2729 .data('kendoCheckBoxGroup'); 2730 ngModelCtrl.$render = function () { 2731 $timeout(function () { 2732 checkboxGroup.value(ngModelCtrl.$viewValue || []); 2733 }, 0); 2734 }; 2735 ngModelCtrl.$render(); 2736 }, 0); 2737 }, 2738 }; 2739 }, 2740]); 2741appDirectives.directive('validateIsNgOption', function ($parse, $timeout) { 2742 return { 2743 require: 'ngModel', 2744 link: function (scope, element, attrs, ngModel) { 2745 var ngOptions = attrs.ngOptions; 2746 var match = ngOptions.match(/^\s*(.+?)\s+as\s+(.+?)\s+for\s+(.+?)\s+in\s+(.+?)(\s+\|\s+.+)?\s*$/); 2747 if (!match) { 2748 throw new Error('Expected ng-options in form of "_select_ as _label_ for _value_ in _collection_ | _filter_" but got "' + 2749 ngOptions + 2750 '".'); 2751 } 2752 var valueFn = $parse(match[1]); 2753 var collectionFn = $parse(match[4]); 2754 var filterExpr = match[5] ? match[5].trim().substring(2) : null; 2755 var filteredCollectionFn = filterExpr 2756 ? $parse("".concat(match[4], " | ").concat(filterExpr)) 2757 : collectionFn; 2758 function getOptions() { 2759 var collection = filteredCollectionFn(scope); 2760 if (!collection) 2761 return []; 2762 return collection.map(function (item) { 2763 var _a; 2764 return valueFn(scope, (_a = {}, _a[match[3]] = item, _a)); 2765 }); 2766 } 2767 function validate(modelValue) { 2768 if (!modelValue) 2769 return true; 2770 var options = getOptions(); 2771 var isValid = options.includes(modelValue); 2772 ngModel.$setValidity('validOption', isValid); 2773 return isValid; 2774 } 2775 ngModel.$validators.validOption = validate; 2776 ngModel.$viewChangeListeners.push(function () { 2777 ngModel.$validate(); 2778 }); 2779 scope.$evalAsync(function () { 2780 if (!ngModel.$validate()) { 2781 ngModel.$setTouched(); 2782 } 2783 }); 2784 scope.$watchCollection(function () { 2785 return filteredCollectionFn(scope); 2786 }, function (newOptions) { 2787 ngModel.$validate(); 2788 }); 2789 }, 2790 }; 2791}); 2792; 2793'use strict';
2794var appFilters = angular.module('currencyFilters', []); 2795appFilters.filter('currencySmart', function (CONFIG) { 2796 var currencyConversionRate = CONFIG.currencyConversionRate 2797 ? CONFIG.currencyConversionRate 2798 : 1; 2799 var currencyFormat = CONFIG.currencyFormat 2800 ? CONFIG.currencyFormat 2801 : '$#VALUE#'; 2802 return function (input) { 2803 if (!angular.isNumber(input) || isNaN(input)) 2804 return null; 2805 var dollars = input.toFixed(2); 2806 var value = dollars * currencyConversionRate; 2807 return currencyFormat.replace('#VALUE#', value 2808 .toFixed(2) 2809 .toString() 2810 .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')); 2811 }; 2812}); 2813; 2814'use strict'; 2815var appFilters = angular.module('dateFilters', []); 2816appFilters.factory('formatIsoDateToShortDate', function () { 2817 return function formatIsoDateToShortDate(isoString) { 2818 var d = new Date(isoString); 2819 if (isNaN(d.getTime())) { 2820 return null; 2821 } 2822 var month = String(d.getUTCMonth() + 1).padStart(2, '0'); 2823 var day = String(d.getUTCDate()).padStart(2, '0'); 2824 var year = String(d.getUTCFullYear()).slice(-2); 2825 return month + '/' + day + '/' + year; 2826 }; 2827}); 2828appFilters.filter('ordinalDate', function ($log) { 2829 $log.getInstance('ordinalDate'); 2830 return function (input) { 2831 var date = new Date(input); 2832 date = moment(date); 2833 if (!date.isValid()) { 2834 return null; 2835 } 2836 return date.format('MMMM Do, YYYY'); 2837 }; 2838}); 2839appFilters.filter('ordinalDateWithTime', function ($log) { 2840 $log.getInstance('ordinalDateWithTime'); 2841 return function (input) { 2842 var date = new Date(input); 2843 date = moment(date); 2844 if (!date.isValid()) { 2845 return null; 2846 } 2847 return date.format('MMMM Do, YYYY (HH:mmA)'); 2848 }; 2849}); 2850; 2851'use strict'; 2852var appFilters = angular.module('distanceFilters', []); 2853appFilters.filter('feet2distanceSmart', function (CONFIG, $log, $filter) { 2854 $log = $log.getInstance('feet2distanceSmart'); 2855 var system = CONFIG.distanceUnitSystem 2856 ? CONFIG.distanceUnitSystem 2857 : 'imperial'; 2858 return function (input, includeUnitLabel) { 2859 if (!angular.isNumber(input) || isNaN(input)) 2860 return null; 2861 var includeUnit = includeUnitLabel === false ? false : true; 2862 var unitA = includeUnit ? ' mi' : ''; 2863 var unitB = includeUnit ? ' ft' : ''; 2864 var result; 2865 if (system === 'imperial') { 2866 var feet = input; 2867 result = 2868 feet > 1000 2869 ? $filter('number')(feet / 5280, 1) + unitA 2870 : $filter('number')(feet, 0) + unitB; 2871 result = includeUnit ? result : parseFloat(result); 2872 } 2873 else if (system === 'metric') { 2874 var meters = input.toFixed(3) * 0.3048; 2875 result = $filter('meters2distanceSmart')(meters, includeUnit); 2876 } 2877 return result; 2878 }; 2879}); 2880appFilters.filter('miles2distanceSmart', function (CONFIG, $log, $filter) { 2881 $log = $log.getInstance('miles2distanceSmart'); 2882 var system = angular.isString(CONFIG.distanceUnitSystem) && 2883 CONFIG.distanceUnitSystem.toLowerCase() === 'metric' 2884 ? 'metric' 2885 : 'imperial'; 2886 return function (inputValue, includeUnitLabel) { 2887 var input = parseFloat(inputValue + ''); 2888 if (!angular.isNumber(input) || isNaN(input)) 2889 return null; 2890 var includeUnit = includeUnitLabel !== false; 2891 var result; 2892 switch (system) { 2893 case 'metric': 2894 var meters = input.toFixed(3) * 1609.34; 2895 result = $filter('meters2distanceSmart')(meters, includeUnit); 2896 break; 2897 case 'imperial': 2898 default: 2899 var feet = input.toFixed(3) * 5280; 2900 result = $filter('feet2distanceSmart')(feet, includeUnit); 2901 break; 2902 } 2903 return result; 2904 }; 2905}); 2906appFilters.filter('meters2distanceSmart', function (CONFIG, $log, $filter) { 2907 $log = $log.getInstance('meters2distanceSmart'); 2908 var system = CONFIG.distanceUnitSystem 2909 ? CONFIG.distanceUnitSystem 2910 : 'imperial'; 2911 return function (input, includeUnitLabel) { 2912 if (!angular.isNumber(input) || isNaN(input)) 2913 return null; 2914 var includeUnit = includeUnitLabel === false ? false : true; 2915 var unitA = includeUnit ? ' km' : ''; 2916 var unitB = includeUnit ? ' m' : ''; 2917 var result; 2918 if (system === 'imperial') { 2919 var feet = input.toFixed(3) / 0.3048; 2920 result = $filter('feet2distanceSmart')(feet, includeUnit); 2921 } 2922 else if (system === 'metric') { 2923 var meters = input; 2924 result = 2925 meters > 249 2926 ? $filter('number')(meters / 1000, 2) + unitA
2927 : $filter('number')(meters, 0) + unitB; 2928 result = includeUnit ? result : parseFloat(result); 2929 } 2930 return result; 2931 }; 2932}); 2933appFilters.filter('distance2milesSmart', function (CONFIG, $log, $filter) { 2934 $log = $log.getInstance('distance2milesSmart'); 2935 var system = CONFIG.distanceUnitSystem 2936 ? CONFIG.distanceUnitSystem 2937 : 'imperial'; 2938 return function (input, includeUnitLabel) { 2939 if (!angular.isNumber(input) || isNaN(input)) 2940 return null; 2941 var includeUnit = includeUnitLabel === false ? false : true; 2942 var unitA = includeUnit ? ' mi' : 0; 2943 var result; 2944 if (system === 'imperial') { 2945 result = input + unitA; 2946 result = includeUnit ? result : parseFloat(result); 2947 } 2948 else if (system === 'metric') { 2949 result = (input * 0.621371).toFixed(2) + unitA; 2950 result = includeUnit ? result : parseFloat(result); 2951 } 2952 return result; 2953 }; 2954}); 2955appFilters.filter('longestStretch', function ($rootScope) { 2956 return function (input) { 2957 var lowest = Number.POSITIVE_INFINITY; 2958 var highest = Number.NEGATIVE_INFINITY; 2959 var tmp, highString, lowString; 2960 angular.forEach(input.result.legs, function (leg) { 2961 for (var i = leg.steps.length - 1; i >= 0; i--) { 2962 tmp = leg.steps[i].distance; 2963 if (tmp < lowest) { 2964 lowest = tmp; 2965 lowString = leg.steps[i].streetName.toString() || null; 2966 } 2967 if (tmp > highest) { 2968 highest = tmp; 2969 highString = leg.steps[i].streetName.toString() || null; 2970 } 2971 } 2972 }); 2973 return highString; 2974 }; 2975}); 2976; 2977'use strict'; 2978var appFilters = angular.module('appFilters', [ 2979 'stringFilters', 2980 'dateFilters', 2981 'timeFilters', 2982 'distanceFilters', 2983 'currencyFilters', 2984 'numberFilters', 2985]); 2986appFilters.filter('conditionalTitleCase', [ 2987 '$filter', 2988 function ($filter) { 2989 return function (input) { 2990 if (!input) { 2991 return input; 2992 } 2993 var words = input.split(' '); 2994 if (words[0].toLowerCase() === 'etc') { 2995 words[0] = words[0].toUpperCase(); 2996 for (var i = 1; i < words.length; i++) { 2997 words[i] = 2998 words[i].charAt(0).toUpperCase() + words[i].substr(1).toLowerCase(); 2999 } 3000 return words.join(' '); 3001 } 3002 else { 3003 return $filter('titleCase')(input); 3004 } 3005 }; 3006 }, 3007]); 3008appFilters.filter('carpoolAddress', function ($rootScope) { 3009 return function (input) { 3010 if (!angular.isString(input)) 3011 return input; 3012 input = input.trim(); 3013 input = input 3014 .replace(/(#|APARTMENT|APT|BASEMENT|BSMT|BUILDING|BLDG|DEPARTMENT|DEPT|FLOOR|FL|FRONT|FRNT|HANGAR|HNGR|LOBBY|LBBY|LOT|LOWER|LOWR|OFFICE|OFC|PENTHOUSE|PH|PIER|REAR|ROOM|RM|SIDE|SLIP|SPACE|SPC|STOP|SUITE|STE|TRAILER|TRLR|UNIT|UPPER|UPPR)\.?\d+(,(?=\s\d))?/gi, '') 3015 .trim(); 3016 input = input 3017 .replace(/^[A-Z]*\d+[A-Z]*\-*\d*\s?[A-Z]{0,2}(?=\s)/i, '') 3018 .trim(); 3019 if ($rootScope.CONFIG && $rootScope.CONFIG.carpoolAddressRegex) 3020 input = input.replace($rootScope.CONFIG.carpoolAddressRegex, '').trim(); 3021 return input; 3022 }; 3023}); 3024appFilters.filter('camelCaseToWords', function () { 3025 return function (input) { 3026 return input.replace(/([A-Z])/g, ' $1').replace(/^./, function (input) { 3027 return input.toUpperCase(); 3028 }); 3029 }; 3030}); 3031appFilters.filter('percentage', function () { 3032 return function (input) { 3033 var rounded = Math.round(input * 10000) / 100; 3034 if (rounded == NaN) { 3035 return ''; 3036 } 3037 var percentage = '' + rounded + '%'; 3038 return percentage; 3039 }; 3040}); 3041appFilters.filter('propertyExists', function () { 3042 return function (items, property) { 3043 var arrayToReturn = []; 3044 for (var i = 0; i < items.length; i++) { 3045 var test = property !== undefined ? items[i][property] : items[i]; 3046 if (test !== undefined && test !== null) { 3047 arrayToReturn.push(items[i]); 3048 } 3049 } 3050 return arrayToReturn; 3051 }; 3052}); 3053appFilters.filter('oldFilter', function () { 3054 return function (array, expression, comparator) { 3055 if (!_.isArray(array)) 3056 return array; 3057 function getter(obj, path, bindFnToScope) { 3058 if (!path) 3059 return obj; 3060 var keys = path.split('.'); 3061 var key; 3062 var lastInstance = obj; 3063 var len = keys.length; 3064 for (var i = 0; i < len; i++) { 3065 key = keys[i]; 3066 if (obj) { 3067 obj = (lastInstance = obj)[key]; 3068 } 3069 } 3070 if (!bindFnToScope && _.isFunction(obj)) { 3071 return _.bind(lastInstance, obj); 3072 } 3073 return obj; 3074 } 3075 var comparatorType = typeof comparator, predicates = []; 3076 predicates.check = function (value) { 3077 for (var j = 0; j < predicates.length; j++) { 3078 if (!predicates[j](value)) { 3079 return false;
3080 } 3081 } 3082 return true; 3083 }; 3084 if (comparatorType !== 'function') { 3085 if (comparatorType === 'boolean' && comparator) { 3086 comparator = function (obj, text) { 3087 return angular.equals(obj, text); 3088 }; 3089 } 3090 else { 3091 comparator = function (obj, text) { 3092 text = ('' + text).toLowerCase(); 3093 return ('' + obj).toLowerCase().indexOf(text) > -1; 3094 }; 3095 } 3096 } 3097 var search = function (obj, text) { 3098 if (typeof text == 'string' && text.charAt(0) === '!') { 3099 return !search(obj, text.substr(1)); 3100 } 3101 switch (typeof obj) { 3102 case 'boolean': 3103 case 'number': 3104 case 'string': 3105 return comparator(obj, text); 3106 case 'object': 3107 switch (typeof text) { 3108 case 'object': 3109 return comparator(obj, text); 3110 default: 3111 for (var objKey in obj) { 3112 if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { 3113 return true; 3114 } 3115 } 3116 break; 3117 } 3118 return false; 3119 case 'array': 3120 for (var i = 0; i < obj.length; i++) { 3121 if (search(obj[i], text)) { 3122 return true; 3123 } 3124 } 3125 return false; 3126 default: 3127 return false; 3128 } 3129 }; 3130 switch (typeof expression) { 3131 case 'boolean': 3132 case 'number': 3133 case 'string': 3134 expression = { 3135 $: expression, 3136 }; 3137 case 'object': 3138 for (var key in expression) { 3139 (function (path) { 3140 if (typeof expression[path] == 'undefined') 3141 return; 3142 predicates.push(function (value) { 3143 return search(path == '$' ? value : getter(value, path), expression[path]); 3144 }); 3145 })(key); 3146 } 3147 break; 3148 case 'function': 3149 predicates.push(expression); 3150 break; 3151 default: 3152 return array; 3153 } 3154 var filtered = []; 3155 for (var j = 0; j < array.length; j++) { 3156 var value = array[j]; 3157 if (predicates.check(value)) { 3158 filtered.push(value); 3159 } 3160 } 3161 return filtered; 3162 }; 3163}); 3164appFilters.filter('offset', function () { 3165 return function (input, start) { 3166 start = parseInt(start, 10); 3167 return input ? input.slice(start) : null; 3168 }; 3169}); 3170appFilters.filter('element', function () { 3171 return function (input, method, argOne) { 3172 var reflect; 3173 if (angular.isDefined(argOne)) { 3174 reflect = angular.element(input)[method](argOne); 3175 } 3176 else { 3177 reflect = angular.element(input)[method](); 3178 } 3179 return reflect; 3180 }; 3181}); 3182appFilters.filter('orderObjectBy', function () { 3183 return function (items, field, reverse) { 3184 var filtered = []; 3185 angular.forEach(items, function (item) { 3186 filtered.push(item); 3187 }); 3188 filtered.sort(function (a, b) { 3189 return a[field] > b[field] ? 1 : -1; 3190 }); 3191 if (reverse) 3192 filtered.reverse(); 3193 return filtered; 3194 }; 3195}); 3196appFilters.filter('typeof', function ($log, $filter) { 3197 $log = $log.getInstance('typeofFilter'); 3198 return function (input, logType) { 3199 if (!_.includes(['log', 'warn', 'info', 'error'], logType)) 3200 logType = 'debug'; 3201 $log[logType]('typeof input', typeof input, input, arguments); 3202 var theReturn = [typeof input, input]; 3203 return theReturn; 3204 }; 3205}); 3206appFilters.filter('log', function ($log, $filter) { 3207 $log = $log.getInstance('typeofFilter'); 3208 return function (input, logType) { 3209 if (!_.includes(['log', 'warn', 'info', 'error'], logType)) 3210 logType = 'debug'; 3211 $log[logType]('$filter:log.' + logType, ' typeof input:', typeof input, input, arguments); 3212 return input; 3213 }; 3214}); 3215appFilters.filter('diffToHTML', function () { 3216 return function (diff) { 3217 return jsondiffpatch.formatters.html.format(diff); 3218 }; 3219}); 3220appFilters.filter('display3Decimals', function () { 3221 return function (input) { 3222 if (angular.isNumber(input)) { 3223 var decimalPart = (input % 1).toFixed(3).substring(2); 3224 if (decimalPart === '000') { 3225 return input.toFixed(0); 3226 } 3227 else if (decimalPart.charAt(2) === '0') { 3228 return input.toFixed(2).replace(/\.?0+$/, ''); 3229 } 3230 else if (decimalPart.charAt(1) === '0') { 3231 return input.toFixed(1).replace(/\.?0+$/, ''); 3232 } 3233 else { 3234 return input.toFixed(3).replace(/\.?0+$/, ''); 3235 } 3236 } 3237 else { 3238 return input; 3239 } 3240 }; 3241}); 3242appFilters.filter('excludeHiddenNetworks', function () { 3243 return function (networks) { 3244 return networks.filter(function (network) { 3245 return !network.hiddenFromUsers; 3246 }); 3247 }; 3248}); 3249; 3250'use strict'; 3251var appFilters = angular.module('numberFilters', []); 3252appFilters.filter('pounds2volumeSmart', function (CONFIG, $log, $filter) { 3253 $log.getInstance('pounds2volumeSmart'); 3254 var system = CONFIG.volumeUnitSystem ? CONFIG.volumeUnitSystem : 'imperial'; 3255 var decimalPosition = function (number) { 3256 return number.toFixed(1) % 1 !== 0 ? 1 : 0; 3257 }; 3258 var formatValue = function (value, string) { 3259 if (value.toFixed(1) / 1 === 1) {
3260 string = string.replace(/s+$/, ''); 3261 } 3262 return $filter('number')(value, decimalPosition(value)) + string; 3263 }; 3264 var doImperialConversion = function (pounds) { 3265 return pounds > 9999 3266 ? formatValue(pounds / 2000, ' tons') 3267 : formatValue(pounds, ' lbs'); 3268 }; 3269 var doMetricConversion = function (pounds) { 3270 var kg = (pounds * 0.453592).toFixed(2) + 0.0; 3271 var metricTons = kg / 1000; 3272 return kg > 250 3273 ? formatValue(metricTons, ' tons') 3274 : formatValue(Number(kg), ' kg'); 3275 }; 3276 return function (input) { 3277 if (!angular.isNumber(input) || isNaN(input)) { 3278 return null; 3279 } 3280 input = input.toFixed(2) * 1; 3281 return system === 'imperial' 3282 ? doImperialConversion(input) 3283 : doMetricConversion(input); 3284 }; 3285}); 3286appFilters.filter('shortNumber', function ($log) { 3287 $log.getInstance('shortNumber'); 3288 return function (input) { 3289 if (!angular.isNumber(input)) { 3290 return null; 3291 } 3292 var value = Math.round(input); 3293 var newValue = value; 3294 if (value >= 1000) { 3295 var suffixes = [ 3296 '', 3297 'k', 3298 ' Million', 3299 ' Billion', 3300 ' Trillion', 3301 ' Quadrillion', 3302 ' Quintillion', 3303 ]; 3304 var suffixNum = Math.floor(('' + value).length / 3); 3305 var shortValue = ''; 3306 for (var precision = 2; precision >= 1; precision--) { 3307 shortValue = parseFloat((suffixNum !== 0 3308 ? value / Math.pow(1000, suffixNum) 3309 : value).toPrecision(precision)); 3310 var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g, ''); 3311 if (dotLessShortValue.length <= 2) { 3312 break; 3313 } 3314 } 3315 newValue = shortValue + suffixes[suffixNum]; 3316 } 3317 return newValue ? newValue : value; 3318 }; 3319}); 3320appFilters.filter('round2NearestQuarterDecimal', function () { 3321 return function (input) { 3322 var float = parseFloat(input), isWholeNum = float % 1 === 0, decimal; 3323 if (!input || isNaN(float)) { 3324 return input; 3325 } 3326 if (isWholeNum) { 3327 return float; 3328 } 3329 decimal = (input % 1).toFixed(2).substring(2); 3330 if (decimal < 25) 3331 float = Math.floor(float); 3332 else if (decimal >= 25 && decimal < 50) 3333 float = parseFloat(Math.floor(float) + '.25'); 3334 else if (decimal >= 50 && decimal < 75) 3335 float = parseFloat(Math.floor(float) + '.50'); 3336 else if (decimal > 75) 3337 float = Math.round(float); 3338 return float; 3339 }; 3340}); 3341appFilters.filter('percentDiff', function () { 3342 return function (a, b) { 3343 if (!a || !b || a === 0) { 3344 return '0 %'; 3345 } 3346 var percent = Math.floor((b / a) * 100 - 100); 3347 return percent === 0 ? '0 %' : percent + ' %'; 3348 }; 3349}); 3350appFilters.filter('numberSmart', function ($filter) { 3351 return function (inputNumber, decimalLimit) { 3352 if (isNaN(inputNumber)) { 3353 return ''; 3354 } 3355 if (decimalLimit === undefined) { 3356 decimalLimit = 2; 3357 } 3358 var formattedNumber = $filter('number')(inputNumber, decimalLimit); 3359 return _.replace(formattedNumber, /\.?0*$/, ''); 3360 }; 3361}); 3362; 3363'use strict'; 3364var appFilters = angular.module('stringFilters', []); 3365appFilters.filter('capitalizeFirstLetter', function () { 3366 return function (text) { 3367 if (!angular.isString(text)) { 3368 return text; 3369 } 3370 return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase(); 3371 }; 3372}); 3373appFilters.filter('titleCase', function () { 3374 return function (input) { 3375 if (angular.isNumber(input)) 3376 input = input.toString(); 3377 if (!angular.isString(input) && !angular.isArray(input)) 3378 return input; 3379 function upperFirstLetter(str) { 3380 return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase(); 3381 } 3382 var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i; 3383 var words = !angular.isArray(input) ? input.split(' ') : input; 3384 angular.forEach(words, function (w, i) { 3385 words[i] = 3386 i === 0 || words[i].search(smallWords) === -1 3387 ? upperFirstLetter(words[i]) 3388 : words[i].toLowerCase(); 3389 }); 3390 return words.join(' '); 3391 }; 3392}); 3393appFilters.filter('classname', function ($log, $filter) { 3394 $log = $log.getInstance("filter:'classname'"); 3395 return function (input) { 3396 if (typeof input !== 'string') 3397 return input; 3398 var firstChar = isNaN(input.charAt(0)) ? '' : '_'; 3399 var joinedString = firstChar + input.toLowerCase().replace(/[\.\s]/g, '-'); 3400 return joinedString; 3401 }; 3402}); 3403appFilters.filter('safeString', function ($log) { 3404 $log = $log.getInstance("filter:'safeString'"); 3405 return function (inputString, joinString) { 3406 if (typeof inputString !== 'string') 3407 return inputString;
3408 var validCharacters = new RegExp(/-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g); 3409 var joinCharacters = typeof joinString !== 'string' ? '_' : joinString; 3410 var firstCharacter = isNaN(inputString.charAt(0)) ? '' : '_'; 3411 var stringArray = (firstCharacter + inputString).match(validCharacters); 3412 var joined = stringArray ? stringArray.join(joinCharacters) : ''; 3413 return joined; 3414 }; 3415}); 3416appFilters.filter('toLowerCase', function ($log) { 3417 $log = $log.getInstance("filter:'toLowerCase'"); 3418 return function (input) { 3419 return !angular.isString(input) ? input : input.toLowerCase(); 3420 }; 3421}); 3422appFilters.filter('toUpperCase', function ($log) { 3423 $log = $log.getInstance("filter:'toUpperCase'"); 3424 return function (input) { 3425 return !angular.isString(input) ? input : input.toUpperCase(); 3426 }; 3427}); 3428appFilters.filter('htmlToText', function () { 3429 return function (input) { 3430 return String(input).replace(/<[^>]+>/gm, ''); 3431 }; 3432}); 3433appFilters.filter('stringReplace', function ($log) { 3434 $log = $log.getInstance("filter:'stringReplace'"); 3435 return function (input, oldString, newString) { 3436 if (typeof input !== 'string') 3437 return null; 3438 var result = input.replace(oldString, newString); 3439 return result; 3440 }; 3441}); 3442appFilters.filter('limitText', function ($log) { 3443 $log = $log.getInstance('filter:limitText'); 3444 return function (_value, _arg1_wordwise, _arg2_max, _arg3_tail) { 3445 if (!_value) 3446 return ''; 3447 var defaults = { 3448 wordwise: true, 3449 max: 35, 3450 tail: '…', 3451 }; 3452 var tail = _arg3_tail || _arg2_max || _arg1_wordwise || defaults.tail; 3453 if (!_.isString(tail)) 3454 tail = defaults.tail; 3455 var max = parseInt(_arg2_max); 3456 if (_.isNaN(max)) 3457 max = parseInt(_arg1_wordwise); 3458 if (_.isNaN(max)) 3459 max = parseInt(defaults.max); 3460 var wordwise = _arg1_wordwise === false ? false : defaults.wordwise; 3461 var value = _value; 3462 if (value.length <= max) 3463 return value; 3464 value = value.substr(0, max); 3465 if (wordwise) { 3466 var lastspace = value.lastIndexOf(' '); 3467 if (lastspace !== -1) { 3468 value = value.substr(0, lastspace); 3469 } 3470 } 3471 return value + tail; 3472 }; 3473}); 3474appFilters.filter('modesToLabels', function () { 3475 function translateMode(mode) { 3476 var translation = _.find(CONFIG.modes, function (m) { 3477 return m.value === mode; 3478 }); 3479 return translation && translation.label ? translation.label : mode; 3480 } 3481 return function (modes) { 3482 if (modes && angular.isArray(modes)) { 3483 return _.map(modes, function (mode) { 3484 return translateMode(mode); 3485 }).join(', '); 3486 } 3487 else if (modes && angular.isString(modes)) { 3488 return translateMode(modes); 3489 } 3490 else { 3491 return ''; 3492 } 3493 }; 3494}); 3495appFilters.filter('joinByKey', function () { 3496 return function (array, key) { 3497 if (array === void 0) { array = []; } 3498 return _.map(array, key).join(', '); 3499 }; 3500}); 3501appFilters.filter('locationToString', function (LocationService) { 3502 return function (location) { 3503 var label = _.get(location, 'properties.label'); 3504 var coords = _.get(location, 'geometry.coordinates', []); 3505 if (!label || !coords.length) 3506 return; 3507 return LocationService.locationToString({ 3508 label: label, 3509 lng: coords[0], 3510 lat: coords[1], 3511 }); 3512 }; 3513}); 3514; 3515'use strict'; 3516var appFilters = angular.module('timeFilters', []); 3517appFilters.filter('min2hoursSmart', function () { 3518 return function (input) { 3519 if (!angular.isNumber(input) || isNaN(input)) 3520 return null; 3521 input = Math.round(input); 3522 if (input < 1) 3523 return '< 1 min'; 3524 return input < 60 3525 ? input.toFixed() + ' min' 3526 : Math.floor(input / 60) + ' hr ' + (input % 60).toFixed() + ' min'; 3527 }; 3528}); 3529appFilters.filter('trimLeftZeros', function ($rootScope) { 3530 return function (input) { 3531 if (!angular.isString(input)) 3532 return input; 3533 var formattedText = input ? input.replace(/^0/, '') : ''; 3534 return formattedText; 3535 }; 3536}); 3537appFilters.filter('normalizeDateString', function ($filter) { 3538 return function (input) { 3539 var momentDate = moment(input).utc(); 3540 var day = '<span isolate>' + momentDate.format('dddd') + '</span>';
3541 var month = '<span isolate>' + momentDate.format('MMMM') + '</span>'; 3542 var date = '<var>' + momentDate.format('D') + '</var>'; 3543 return day + ', ' + month + ' ' + date; 3544 }; 3545}); 3546appFilters.filter('tzDate', function ($filter, CONFIG) { 3547 return function (input, format, tz) { 3548 format = format || 'medium'; 3549 tz = tz || -moment().utcOffset(); 3550 var result = $filter('date')(input, format, tz); 3551 return result; 3552 }; 3553}); 3554appFilters.filter('momentRoundForward', function ($log) { 3555 $log = $log.getInstance("filter:'momentRoundForward'"); 3556 return function momentRoundForward(inputStringOrMoment, precision, key, momentFormat) { 3557 if (window.moment && 3558 (!moment().round || !moment().ceil || !moment().floor)) { 3559 (function () { 3560 moment.fn.round = function (precision, key, direction) { 3561 if (typeof direction === 'undefined') { 3562 direction = 'round'; 3563 } 3564 var keys = ['Hours', 'Minutes', 'Seconds', 'Milliseconds']; 3565 var maxValues = [24, 60, 60, 1000]; 3566 key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase(); 3567 if (key.indexOf('s', key.length - 1) === -1) { 3568 key += 's'; 3569 } 3570 var value = 0; 3571 var rounded = false; 3572 var subRatio = 1; 3573 var maxValue; 3574 for (var i in keys) { 3575 var k = keys[i]; 3576 if (k === key && typeof this._d['get' + key] === 'function') { 3577 value = this._d['get' + key](); 3578 maxValue = maxValues[i]; 3579 rounded = true; 3580 } 3581 else if (rounded && typeof this._d['get' + k] === 'function') { 3582 subRatio *= maxValues[i]; 3583 value += this._d['get' + k]() / subRatio; 3584 this._d['set' + k](0); 3585 } 3586 } 3587 value = Math[direction](value / precision) * precision; 3588 value = Math.min(value, maxValue); 3589 this._d['set' + key](value); 3590 return this; 3591 }; 3592 moment.fn.ceil = function (precision, key) { 3593 return this.round(precision, key, 'ceil'); 3594 }; 3595 moment.fn.floor = function (precision, key) { 3596 return this.round(precision, key, 'floor'); 3597 }; 3598 })(); 3599 } 3600 if (!window.moment || !window.moment().round) { 3601 return inputStringOrMoment; 3602 } 3603 var result = inputStringOrMoment; 3604 var inputWasaString = _.isString(inputStringOrMoment); 3605 var precision = precision || 15; 3606 var key = key || 'minutes'; 3607 var momentFormat = momentFormat || 'hh:mm A'; 3608 if (inputWasaString) 3609 result = moment(result, momentFormat); 3610 if (!moment.isMoment(result) || !result.isValid()) { 3611 return inputStringOrMoment; 3612 } 3613 result = result.round(precision, key, 'ceil'); 3614 if (inputWasaString) 3615 result = result.format(momentFormat); 3616 return result; 3617 }; 3618}); 3619; 3620'use strict'; 3621angular 3622 .module('contentManagement', []) 3623 .run(function ($rootScope, ContentManagementService) { 3624 var tokenWatcher = $rootScope.$watch('session', function (session) { 3625 if (session && session.token) { 3626 ContentManagementService.loadContent(); 3627 tokenWatcher(); 3628 } 3629 }); 3630}) 3631 .factory('ContentManagementService', function ($vhttp, $rootScope) { 3632 var contentMap = new Map(); 3633 var loaded = false; 3634 var hasError = false; 3635 function getContent(key) { 3636 return contentMap.get(key); 3637 } 3638 function loadContent() { 3639 if (loaded) 3640 loaded = false; 3641 return $vhttp 3642 .get('/api/v1/cms/content-collection/preloaded') 3643 .then(function (content) { 3644 contentMap = new Map(); 3645 for (var key in content) { 3646 contentMap.set(key, content[key]); 3647 } 3648 loaded = true; 3649 }) 3650 .catch(function (err) { 3651 console.error('Error loading content', err); 3652 hasError = true; 3653 }); 3654 } 3655 function pullForContentKey(key) { 3656 return new Promise(function (resolve, reject) { 3657 if (loaded) { 3658 return resolve(getContent(key)); 3659 } 3660 if (hasError) { 3661 return reject('Content keys unavailable.'); 3662 } 3663 return registerContentKeyListener(key, resolve, reject); 3664 }); 3665 } 3666 var timer = null; 3667 var contentWatcher = null; 3668 function registerContentKeyListener(key, resolve, reject) { 3669 if (contentWatcher) 3670 return; 3671 timer = setTimeout(function () { 3672 destroyContentWatcher();
3673 reject('Content has timed out'); 3674 }, 10000); 3675 contentWatcher = $rootScope.$watch(function () { return ContentManagementService.isLoaded(); }, function (loaded) { 3676 if (loaded) { 3677 destroyTimer(); 3678 destroyContentWatcher(); 3679 resolve(getContent(key)); 3680 } 3681 }); 3682 } 3683 function destroyContentWatcher() { 3684 if (contentWatcher) 3685 contentWatcher(); 3686 contentWatcher = null; 3687 } 3688 function destroyTimer() { 3689 if (timer) 3690 clearTimeout(timer); 3691 timer = null; 3692 } 3693 return { 3694 getContent: getContent, 3695 loadContent: loadContent, 3696 fetchContentKey: pullForContentKey, 3697 isLoaded: function () { 3698 return loaded; 3699 }, 3700 }; 3701}); 3702; 3703'use strict'; 3704var appServices = angular.module('elementServices', []); 3705appServices.service('elementHelper', function () { 3706 var service = this; 3707 this.getNavHeight = function () { 3708 var nav = $('.navbar'), sub = nav.parent().find('.subsite-navbar'), top = ~~(nav.outerHeight() + sub.outerHeight()); 3709 nav = sub = null; 3710 return top; 3711 }; 3712 this.getFooterHeight = function () { 3713 var footer = $('.layout-footer'); 3714 if (footer.is(':visible')) { 3715 return footer.outerHeight() || 0; 3716 } 3717 else { 3718 return 0; 3719 } 3720 }; 3721 this.scrollToElement = function (element, offset, speed) { 3722 offset = offset || this.getNavHeight(); 3723 speed = speed || 500; 3724 $('html, body').animate({ 3725 scrollTop: $(element).offset().top - offset, 3726 }, speed); 3727 }; 3728 this.isScrolledBtm = function (offset) { 3729 offset = offset || 10; 3730 return ($(document).height() - $(window).height() <= 3731 $(window).scrollTop() + offset); 3732 }; 3733 this.isOnSmallScreen = function () { 3734 return $(window).innerWidth() < 992; 3735 }; 3736 return this; 3737}); 3738; 3739'use strict'; 3740var appServices = angular.module('ErrorResolvingServices', []); 3741appServices.service('AccountResolvingService', function (Dialogs) { 3742 function handleError(error, callback) { 3743 var _a; 3744 var message; 3745 var errorData = !!error.data; 3746 var emailError = errorData && error.data.errors && error.data.errors.email; 3747 var uniqueError = emailError 3748 ? error.data.errors.email.kind === 'unique' 3749 : false; 3750 var restrictedDomain = emailError 3751 ? error.data.errors.email.message === 'restrictedDomains' 3752 : false; 3753 var genericLoginErrorMessage = 'Please check your email and password and try again'; 3754 var genericErrorMessage = 'There was a problem completing your request'; 3755 var incorrectDomainMessage = emailError 3756 ? error.data.errors.email.value.replace(/.*@/, '') + 3757 ' is not an authorized email domain' 3758 : ''; 3759 var emailTakenMessage = emailError 3760 ? 'The email ' + error.data.errors.email.value + ' is already in use. ' 3761 : ''; 3762 var emailTakenPasswordMessage = emailTakenMessage + 'Please try resetting your password'; 3763 var emailTakenPasswordResendMessage = emailTakenPasswordMessage + ' or resending your confirmation email'; 3764 var accountNotActivatedMessage = 'The account provided has not been activated yet, you can activate it by resending your confirmation email.'; 3765 if (errorData) { 3766 if (uniqueError) { 3767 if (uniqueError && CONFIG.requireEmailConfirmation) { 3768 message = emailTakenPasswordResendMessage; 3769 } 3770 else { 3771 message = emailTakenMessage; 3772 } 3773 } 3774 else if (restrictedDomain) { 3775 message = incorrectDomainMessage; 3776 } 3777 } 3778 else { 3779 var errorName = (_a = error.error) !== null && _a !== void 0 ? _a : error.name; 3780 if (errorName === 'InvalidCredentials') { 3781 message = genericLoginErrorMessage; 3782 } 3783 else if (errorName === 'AccountLocked') { 3784 message = error.message; 3785 } 3786 else if (errorName === 'AccountNotActivated') { 3787 message = accountNotActivatedMessage; 3788 } 3789 } 3790 if (callback) { 3791 callback(message !== null && message !== void 0 ? message : genericErrorMessage); 3792 } 3793 else { 3794 Dialogs.alert(message !== null && message !== void 0 ? message : genericErrorMessage); 3795 } 3796 } 3797 return { 3798 handleError: handleError, 3799 }; 3800}); 3801; 3802'use strict'; 3803var appTools = angular.module('AppTools', []); 3804appTools.factory('EnabledPrograms', function () { 3805 var blueprints = [ 3806 { 3807 name: 'LeftColumn', 3808 img: CONFIG.navbarLanguage.programsLeftColumnImg || 3809 'img/parkside/bicycle.png', 3810 entryPoint: CONFIG.navbarLanguage.programsLeftColumnEntryPoint || '#', 3811 link: CONFIG.navbarLanguage.programsLeftColumnLink, 3812 buttonText: CONFIG.navbarLanguage.programsLeftColumnButtonText || 'Go!', 3813 static: CONFIG.navbarLanguage.programsLeftColumnStatic, 3814 isVisible: function () { 3815 return !CONFIG.hideDidYouKnowNavTab; 3816 }, 3817 }, 3818 { 3819 name: 'Events', 3820 img: 'img/parkside/bicycle.png', 3821 entryPoint: 'events.list', 3822 buttonText: 'Go!', 3823 isVisible: function () { 3824 return CONFIG.showEventsProgramsNavTab; 3825 }, 3826 }, 3827 { 3828 name: 'PointPrograms', 3829 entryPoint: "incentives.list({tab:'points'})", 3830 buttonText: 'Go!', 3831 isVisible: function () { 3832 return !CONFIG.rewardsEnabled && !CONFIG.hidePointsProgramsNavTab; 3833 }, 3834 }, 3835 { 3836 name: 'Challenges', 3837 img: 'img/parkside-images/car-leaf-trunk.png', 3838 entryPoint: 'challenges.list', 3839 buttonText: 'Go!', 3840 isVisible: function () { 3841 return CONFIG.challengesV2Enabled && !CONFIG.hideChallengesNavTab; 3842 }, 3843 }, 3844 { 3845 name: 'Incentives', 3846 entryPoint: "incentives.list({tab:'available'})", 3847 buttonText: 'Go!', 3848 isVisible: function () { 3849 return (!CONFIG.rewardsEnabled && 3850 CONFIG.incentivesEnabled && 3851 !CONFIG.hideIncentivesNavTab); 3852 }, 3853 }, 3854 { 3855 name: 'Rewards', 3856 img: 'img/parkside-images/giftbox.svg', 3857 entryPoint: 'rewards', 3858 buttonText: 'Go!', 3859 isVisible: function () { 3860 return CONFIG.rewardsEnabled && !CONFIG.navarProgramsHideRewards; 3861 }, 3862 }, 3863 { 3864 name: 'ERH', 3865 img: 'img/parkside-images/pointprogram.svg', 3866 entryPoint: CONFIG.navbarProgramsERHEntryPoint, 3867 buttonText: CONFIG.navbarLanguage.programsERHButtonText, 3868 isVisible: function () { 3869 return CONFIG.navbarProgramsERH; 3870 }, 3871 }, 3872 ]; 3873 function getComplexConfigValue(name, type) { 3874 var description = CONFIG.navbarLanguage['programs' + name + 'Paragraph']; 3875 return _.isArray(description) ? _.sample(description) : description; 3876 } 3877 function make(program) { 3878 return _.merge(program, { 3879 header: CONFIG.navbarLanguage['programs' + program.name + 'Header'], 3880 paragraph: getComplexConfigValue(program.name, 'Paragraph'), 3881 }); 3882 } 3883 function blueprintFactory() { 3884 return blueprints 3885 .filter(function (blueprint) { 3886 return blueprint.isVisible(); 3887 }) 3888 .map(function (program) { 3889 return make(program); 3890 }); 3891 } 3892 return blueprintFactory; 3893}); 3894appTools.service('EnabledTools', function ($rootScope) { 3895 var $instance = this; 3896 $instance.getCategories = function () { 3897 return _.groupBy($rootScope.enabledTools, function (tool) { 3898 return tool.category; 3899 }); 3900 }; 3901 $instance.getParentStates = function () { 3902 var uniqueParentNames = ['admin'];
3903 $rootScope.enabledTools.forEach(function (tool) { 3904 var parent = tool.baseRoute.split('.')[0]; 3905 if (uniqueParentNames.indexOf(parent) < 0) { 3906 uniqueParentNames.push(parent); 3907 } 3908 }); 3909 return uniqueParentNames; 3910 }; 3911 return $instance; 3912}); 3913; 3914'use strict'; 3915var appServices = angular.module('appServices', [ 3916 'ErrorResolvingServices', 3917 'elementServices', 3918 'AppTools', 3919 'contentManagement', 3920]); 3921appServices.service('SessionUserDataService', function ($rootScope, $log, $http, LocationService, $timeout) { 3922 $log = $log.getInstance('SessionUserDataService'); 3923 $rootScope.$watch('session.user', function (user) { 3924 if (user) { 3925 sessionUserData.setUser(user); 3926 } 3927 else { 3928 sessionUserData.reset(); 3929 } 3930 }); 3931 var SessionUser = function () { 3932 this.reset(); 3933 $rootScope.$emit('resetUserData', this); 3934 }; 3935 SessionUser.prototype.setUser = function (user) { 3936 if (user !== this.user) { 3937 this.user = user; 3938 this.updateUserData(); 3939 } 3940 }; 3941 SessionUser.prototype.reset = function () { 3942 this.user = undefined; 3943 this.tripplans = []; 3944 this.updateTripplans = SessionUser.getUpdateFn(this, 'tripplans'); 3945 this.tripsearches = []; 3946 this.updateTripsearches = SessionUser.getUpdateFn(this, 'tripsearches'); 3947 this.carpoolmessages = []; 3948 this.updateCarpoolmessages = SessionUser.getUpdateFn(this, 'carpoolmessages'); 3949 this.managednetworks = []; 3950 this.updateManagednetworks = SessionUser.getUpdateFn(this, 'managednetworks'); 3951 this.vanpools = []; 3952 this.updateVanpools = SessionUser.getUpdateFn(this, 'vanpools'); 3953 this.triplogReport = {}; 3954 this.badges = null; 3955 this.updateBadges = SessionUser.getUpdateFn(this, 'badges'); 3956 }; 3957 SessionUser.prototype.updateTriplogReport = function () { 3958 var self = this; 3959 $http({ 3960 url: '/api/v1/triplogreports/user/' + this.user._id, 3961 method: 'GET', 3962 params: { xcache: new Date() }, 3963 }).then(function (data) { 3964 if (data.data) 3965 self.triplogReport = data.data; 3966 }); 3967 }; 3968 SessionUser.prototype.updateAdvancedManager = function () { 3969 return __awaiter(this, void 0, void 0, function () { 3970 var self, data; 3971 return __generator(this, function (_a) { 3972 switch (_a.label) { 3973 case 0: 3974 self = this; 3975 if (!(CONFIG.premiumNetworks.advancedManagementEnabled && 3976 self.user.managedNetworks.length)) return [3, 2]; 3977 return [4, $http.get('/api/v1/ra-connected/is-advanced-manager')]; 3978 case 1: 3979 data = (_a.sent()).data; 3980 self.user.isAdvancedManager = data; 3981 return [3, 3]; 3982 case 2: 3983 self.user.isAdvancedManager = false; 3984 _a.label = 3; 3985 case 3: return [2]; 3986 } 3987 }); 3988 }); 3989 }; 3990 SessionUser.prototype.updateAbilities = function (cb) { 3991 if (cb === void 0) { cb = _.noop; } 3992 var onEnd = function () { return $timeout(cb); }; 3993 Promise.all([this.updateSchoolpoolAdmin(), this.updateAdvancedManager()]) 3994 .then(onEnd) 3995 .catch(onEnd); 3996 }; 3997 SessionUser.prototype.updateSchoolpoolAdmin = function () { 3998 return __awaiter(this, void 0, void 0, function () { 3999 var self, data; 4000 return __generator(this, function (_a) { 4001 switch (_a.label) { 4002 case 0: 4003 self = this; 4004 if (!(CONFIG.premiumNetworks.schoolpoolAdminEnabled && 4005 self.user.managedNetworks.length)) return [3, 2]; 4006 return [4, $http.get('/api/v1/ra-connected/is-schoolpool-admin')]; 4007 case 1: 4008 data = (_a.sent()).data; 4009 self.user.isSchoolpoolAdmin = data; 4010 return [3, 3]; 4011 case 2: 4012 self.user.isSchoolpoolAdmin = false;
4013 _a.label = 3; 4014 case 3: return [2]; 4015 } 4016 }); 4017 }); 4018 }; 4019 SessionUser.prototype.updateUserData = function () { 4020 var self = this; 4021 if (!this.user) { 4022 return; 4023 } 4024 var broadcastUserUpdate = $rootScope.$broadcast.bind($rootScope, 'updateUserData', self); 4025 this.updateManagednetworks(); 4026 this.updateVanpools(); 4027 this.updateTripplans(); 4028 this.updateTripsearches(); 4029 this.updateCarpoolmessages(); 4030 this.updateTriplogReport(); 4031 this.updateBadges(); 4032 this.updateAbilities(broadcastUserUpdate); 4033 }; 4034 SessionUser.getUpdateFn = function (instance, name) { 4035 return function () { 4036 if (!instance.user) 4037 return; 4038 return instance.user.getList(name, { xcache: new Date() }).then(function (val) { 4039 instance[name] = val; 4040 }, function () { 4041 instance[name] = []; 4042 }); 4043 }; 4044 }; 4045 SessionUser.prototype.getTripplanMatchingTripsearch = function (search) { 4046 var self = this; 4047 $log.debug('getTripplanMatchingTripsearch(search)', search, self.tripplans); 4048 var doesMatch = LocationService.doLocationsMatch; 4049 var matchingPlan = null; 4050 _.forEach(self.tripplans, function (plan) { 4051 if (search.event || plan.relatedEvent) { 4052 if (plan.relatedEvent && 4053 search.event && 4054 _.isObject(plan.relatedEvent) && 4055 plan.relatedEvent._id == search.event) 4056 matchingPlan = plan; 4057 if (plan.relatedEvent && 4058 search.event && 4059 _.isString(plan.relatedEvent) && 4060 plan.relatedEvent == search.event) 4061 matchingPlan = plan; 4062 return; 4063 } 4064 if ((doesMatch(plan.from, search.from) && 4065 doesMatch(plan.to, search.to)) || 4066 (doesMatch(plan.from, search.to) && doesMatch(plan.to, search.from))) { 4067 matchingPlan = plan; 4068 } 4069 }); 4070 $log.debug('getTripplanMatchingTripsearch(search)', 'RESULT', matchingPlan); 4071 return matchingPlan; 4072 }; 4073 SessionUser.prototype.getCarpoolmessages = function (tripplan) { 4074 $log.debug('getCarpoolmessages(tripplan)', tripplan._id); 4075 var self = this; 4076 var lastContacted = undefined; 4077 var matchingMessages = []; 4078 _.forEach(self.carpoolmessages, function (message) { 4079 $log.debug('checking carpool', message.trip, tripplan._id, message.trip == tripplan._id); 4080 if (message.trip === tripplan._id) 4081 matchingMessages.push(message); 4082 }); 4083 $log.debug('getCarpoolmessages() matchingMessages', lastContacted); 4084 return _.sortBy(matchingMessages, 'created').reverse(); 4085 }; 4086 SessionUser.prototype.getReduced = function (type, callback) { 4087 if (!this[type] || !this[type].length) { 4088 return []; 4089 } 4090 return _.filter(this[type], callback); 4091 }; 4092 var sessionUserData = new SessionUser(); 4093 window.SessionUserData = sessionUserData; 4094 return sessionUserData; 4095}); 4096appServices.service('Clipboard', function () { 4097 return function (selector, options) { 4098 return new Clipboard(selector || '.btn', options || {}); 4099 }; 4100}); 4101appServices.service('CarpoolContactService', function (SessionUserDataService, $q, $log, Dialogs) { 4102 $log = $log.getInstance('CarpoolContactService'); 4103 function getLastContacted(tripplan) { 4104 $log.debug('getLastContacted()', tripplan._id); 4105 var carpoolMessages = SessionUserDataService.getCarpoolmessages(tripplan); 4106 if (carpoolMessages.length) 4107 return carpoolMessages[0].created; 4108 return undefined; 4109 } 4110 function getCarpoolMessages(tripplan) { 4111 $log.debug('getCarpoolMessages()', tripplan._id); 4112 return SessionUserDataService.getCarpoolmessages(tripplan); 4113 } 4114 function sendCarpoolMessage(tripplan, message, type) { 4115 type = type || 'Carpool'; 4116 var deferred = $q.defer(); 4117 $log.debug('sendCarpoolMessage(tripplan,message)', tripplan, message); 4118 if (message == null) { 4119 Dialog.alert('Please provide a message to send!'); 4120 deferred.reject(); 4121 return; 4122 } 4123 var success = function (message) { 4124 $log.debug('sendCarpoolMessage() SUCCESS', message); 4125 Dialogs.alert('Your message was sent!'); 4126 deferred.resolve(SessionUserDataService.updateCarpoolmessages()); 4127 }; 4128 var error = function (error) { 4129 $log.debug('sendCarpoolMessage() ERROR', error); 4130 SessionUserDataService.updateCarpoolmessages(); 4131 deferred.reject(error); 4132 }; 4133 SessionUserDataService.user 4134 .post('carpoolmessages', { 4135 trip: tripplan._id, 4136 message: message, 4137 type: type, 4138 }) 4139 .then(success, error); 4140 return deferred.promise; 4141 } 4142 return { 4143 getLastContacted: getLastContacted, 4144 getCarpoolMessages: getCarpoolMessages, 4145 sendCarpoolMessage: sendCarpoolMessage, 4146 }; 4147}); 4148appServices.service('VanpoolContactService', function (SessionUserDataService, $log, Dialogs) { 4149 $log = $log.getInstance('VanpoolContactService'); 4150 function sendVanpoolMessage(vanpool, message) { 4151 $log.debug('sendVanpoolMessage(vanpool,message)', vanpool, message); 4152 if (message == null) { 4153 Dialog.alert('Please provide a message to send!'); 4154 return; 4155 } 4156 var success = function (message) { 4157 $log.debug('sendVanpoolMessage() SUCCESS', message); 4158 Dialogs.alert('Your message was sent!'); 4159 }; 4160 var error = function (error) { 4161 $log.debug('sendVanpoolMessage() ERROR', error); 4162 Dialogs.alert('Oops! There was a problem sending your message. You may try again or c
4162ontact us if the problem persists.'); 4163 }; 4164 SessionUserDataService.user 4165 .post('vanpoolmessages', { 4166 vanpool: vanpool._id, 4167 message: message, 4168 }) 4169 .then(success, error); 4170 } 4171 return { 4172 sendVanpoolMessage: sendVanpoolMessage, 4173 }; 4174}); 4175appServices.factory('$localstorage', [ 4176 '$window', 4177 function ($window) { 4178 return { 4179 set: function (key, value) { 4180 $window.localStorage[key] = value; 4181 }, 4182 get: function (key, defaultValue) { 4183 return $window.localStorage[key] || defaultValue; 4184 }, 4185 setObject: function (key, value) { 4186 $window.localStorage[key] = JSON.stringify(value); 4187 }, 4188 getObject: function (key) { 4189 return JSON.parse($window.localStorage[key] || '{}'); 4190 }, 4191 }; 4192 }, 4193]); 4194appServices.factory('$tempStorage', [ 4195 '$log', 4196 '$rootScope', 4197 function ($log, $rootScope) { 4198 $log = $log.getInstance('$tempStorage'); 4199 $log.debug('Initialized $rootScope.tempStorage = ', $rootScope.tempStorage); 4200 $rootScope.tempStorage = {}; 4201 return { 4202 set: function (key, val) { 4203 $log.debug('set', key, val, $rootScope.tempStorage[key]); 4204 return ($rootScope.tempStorage[key] = val); 4205 }, 4206 get: function (key, defaultVal) { 4207 $log.debug('get', key, defaultVal, $rootScope.tempStorage[key]); 4208 return $rootScope.tempStorage[key] || defaultVal; 4209 }, 4210 check: function (key, val) { 4211 $log.debug('check', key, val, $rootScope.tempStorage[key] === val); 4212 return $rootScope.tempStorage[key] === val; 4213 }, 4214 }; 4215 }, 4216]); 4217appServices.factory('$vhttp', function ($http, vSession) { 4218 var service = {}; 4219 service.get = get; 4220 service.post = post; 4221 service.put = put; 4222 service.remove = remove; 4223 return service; 4224 function get(url, queryParams) { 4225 return $http 4226 .get(url, { 4227 params: queryParams, 4228 headers: { 4229 Authorization: 'Bearer ' + vSession.token, 4230 Accept: 'application/json, text/plain, */*', 4231 }, 4232 }) 4233 .then(function (result) { 4234 return result.data; 4235 }); 4236 } 4237 function post(url, data) { 4238 return $http 4239 .post(url, data, { 4240 headers: { 4241 Authorization: 'Bearer ' + vSession.token, 4242 Accept: 'application/json, text/plain, */*', 4243 }, 4244 }) 4245 .then(function (result) { 4246 return result.data; 4247 }); 4248 } 4249 function put(url, data) { 4250 return $http 4251 .put(url, data, { 4252 headers: { 4253 Authorization: 'Bearer ' + vSession.token, 4254 Accept: 'application/json, text/plain, */*', 4255 }, 4256 }) 4257 .then(function (result) { 4258 return result.data; 4259 }); 4260 } 4261 function remove(url, data) { 4262 var options = { 4263 headers: { 4264 Authorization: 'Bearer ' + vSession.token, 4265 Accept: 'application/json, text/plain, */*', 4266 }, 4267 }; 4268 if (data) { 4269 options.data = data; 4270 options.headers['Content-Type'] = 'application/json'; 4271 } 4272 return $http.delete(url, options).then(function (result) { 4273 return result.data; 4274 }); 4275 } 4276}); 4277appServices.service('mergeModalQue', function ($rootScope, vSession, CarpoolPromptService, $state, CONFIG) { 4278 var self = this; 4279 this.queue = []; 4280 this.startCaptureQue = function () { 4281 if (this.queue.length || !vSession.user) 4282 return; 4283 var promises = []; 4284 if (CONFIG.premiumNetworks.multiPrimaryNetworkEnabled) { 4285 promises.push(self.getIncompleteProfileDef, self.getPrimaryMergeDef, self.getCarpoolOptInDef); 4286 } 4287 promises.push(self.getPostRegistrationDef, self.getCarpoolPromptDef); 4288 self.queue = _.map(promises, function (p) { return p.bind(self); }); 4289 _.delay(function () { return self.nextQueue(); }, 500); 4290 }; 4291 this.getIncompleteProfileDef = function () { 4292 return __awaiter(this, void 0, void 0, function () { 4293 var modalDef, incompleteProfiles, userProfile, name_1, networkProfileId, netId; 4294 return __generator(this, function (_a) { 4295 switch (_a.label) { 4296 case 0: 4297 modalDef = { 4298 template: 'network-profile-completion-modal.html', 4299 show: false, 4300 extraScope: { 4301 disableModalAutoClose: true,
4302 disableModalBackgroundClick: true, 4303 }, 4304 }; 4305 return [4, vSession.user 4306 .getList('incomplete-profiles') 4307 .catch(function () { return []; })]; 4308 case 1: 4309 incompleteProfiles = _a.sent(); 4310 if (incompleteProfiles.length) { 4311 userProfile = _.first(incompleteProfiles); 4312 name_1 = _.get(userProfile, 'networkProfile.organizationName'); 4313 networkProfileId = _.get(userProfile, 'networkProfile._id'); 4314 netId = _.get(userProfile, 'networkProfile.network'); 4315 modalDef.extraScope.appUrl = "".concat(location.origin, "/app/my-networks/join-network?name=").concat(name_1, "&id=").concat(netId, "&profile=").concat(networkProfileId); 4316 modalDef.show = Boolean(netId && name_1); 4317 } 4318 return [2, modalDef]; 4319 } 4320 }); 4321 }); 4322 }; 4323 this.checkModalPromptField = function (field) { 4324 var path = "customProfileFields.".concat(field); 4325 return _.has(vSession.user, path) && !_.get(vSession.user, path, false); 4326 }; 4327 this.getCarpoolOptInDef = function () { 4328 return __awaiter(this, void 0, void 0, function () { 4329 var modalDef, isSharedCommute_1, trips; 4330 return __generator(this, function (_a) { 4331 switch (_a.label) { 4332 case 0: 4333 if (!CONFIG.showCarpoolOptInModal) { 4334 return [2, { show: false }]; 4335 } 4336 modalDef = { 4337 template: 'carpool-opt-in-modal', 4338 show: this.checkModalPromptField('carpoolOptIn'), 4339 extraScope: {}, 4340 }; 4341 if (!modalDef.show) return [3, 3]; 4342 isSharedCommute_1 = function (trip) { 4343 var isShared = trip.shared.public || 4344 (!trip.shared.public && trip.shared.networks.length); 4345 var isCommute = !trip.schedule.oneTimeTrip && 4346 (trip.tripPreferences.carpool || trip.tripPreferences.bikepool); 4347 return isShared && isCommute; 4348 }; 4349 return [4, vSession.user 4350 .getList('tripplans') 4351 .then(function (trips) { return _.filter(trips, isSharedCommute_1); })]; 4352 case 1: 4353 trips = _a.sent(); 4354 modalDef.show = Boolean(trips.length); 4355 modalDef.extraScope.trips = trips; 4356 if (!!modalDef.show) return [3, 3]; 4357 return [4, this.updateUserProfileField('carpoolOptIn', true)]; 4358 case 2: 4359 _a.sent(); 4360 _a.label = 3; 4361 case 3: return [2, modalDef]; 4362 } 4363 }); 4364 }); 4365 }; 4366 this.getPrimaryMergeDef = function () { 4367 return __awaiter(this, void 0, void 0, function () { 4368 var modalDef, showPrimaryMergeNotice, userNets, primaryNets; 4369 return __generator(this, function (_a) { 4370 switch (_a.label) { 4371 case 0: 4372 modalDef = { 4373 template: 'account-merge-modal', 4374 show: false, 4375 extraScope: {}, 4376 }; 4377 showPrimaryMergeNotice = this.checkModalPromptField('primaryMergeNotice'); 4378 if (!showPrimaryMergeNotice) return [3, 3]; 4379 return [4, vSession.user.getList('networks')]; 4380 case 1: 4381 userNets = _a.sent(); 4382 primaryNets = _.filter(userNets, 'capabilities.primaryNetwork'); 4383 modalDef.show = _.size(primaryNets) > 1; 4384 modalDef.extraScope.userNetworks = primaryNets; 4385 if (!!modalDef.show) return [3, 3]; 4386 return [4, this.updateUserProfileField('primaryMergeNotice', true)]; 4387 case 2: 4388 _a.sent(); 4389 _a.label = 3; 4390 case 3: return [2, modalDef]; 4391 } 4392 }); 4393 }); 4394 }; 4395 this.getPostRegistrationDef = function () { 4396 return __awaiter(this, void 0, void 0, function () { 4397 var modalDef, modalShow; 4398 return __generator(this, function (_a) { 4399 modalDef = {
4400 template: CONFIG.postRegistrationCaptureModal, 4401 show: false, 4402 extraScope: { 4403 disableModalAutoClose: true, 4404 disableModalBackgroundClick: true, 4405 }, 4406 }; 4407 modalDef.onClose = _.bind(function () { 4408 var _this = this; 4409 if (!this.user.postRegistrationCapture) { 4410 this.user.get(vSession.user._id).then(function (user) { 4411 user.postRegistrationCapture = 'Did Not Respond'; 4412 user.save().then(_this.refresh, _.noop); 4413 }, _.noop); 4414 } 4415 }, vSession); 4416 modalShow = CONFIG.postRegistrationCaptureModal && 4417 vSession.user && 4418 !vSession.user.postRegistrationCapture; 4419 if (modalShow && CONFIG.postRegistrationCaptureModalNetwork) 4420 modalShow = vSession.user.networks.includes(CONFIG.postRegistrationCaptureModalNetwork); 4421 modalDef.show = modalShow; 4422 if (CONFIG.postRegistrationEligibleNetworks) { 4423 modalDef.show = !!_.intersection(vSession.UserData.user.networks, CONFIG.postRegistrationEligibleNetworks).length; 4424 } 4425 return [2, modalDef]; 4426 }); 4427 }); 4428 }; 4429 this.getCarpoolPromptDef = function () { 4430 return __awaiter(this, void 0, void 0, function () { 4431 var modalDef, _a; 4432 return __generator(this, function (_b) { 4433 switch (_b.label) { 4434 case 0: 4435 modalDef = { 4436 template: CONFIG.postRegistrationCarpoolModal, 4437 show: false, 4438 extraScope: { 4439 disableModalAutoClose: true, 4440 disableModalBackgroundClick: true, 4441 }, 4442 }; 4443 if (!(CONFIG.postRegistrationCarpoolModal && 4444 vSession.user && 4445 !$state.current.name.match(/gotober/))) return [3, 2]; 4446 _a = modalDef; 4447 return [4, CarpoolPromptService.userNeedsCarpoolPrompt(vSession.user)]; 4448 case 1: 4449 _a.show = _b.sent(); 4450 _b.label = 2; 4451 case 2: return [2, modalDef]; 4452 } 4453 }); 4454 }); 4455 }; 4456 this.updateUserProfileField = function (field, value) { 4457 return __awaiter(this, void 0, void 0, function () { 4458 return __generator(this, function (_a) { 4459 switch (_a.label) { 4460 case 0: 4461 _.set(vSession.user, "customProfileFields.".concat(field), value); 4462 return [4, vSession.user.put().then(_.noop, _.noop)]; 4463 case 1: 4464 _a.sent(); 4465 return [2]; 4466 } 4467 }); 4468 }); 4469 }; 4470 this.initModalCloseListener = function () { 4471 if (this.modalCloseListener) 4472 return; 4473 this.modalCloseListener = $rootScope.$on('modalHidden', function () { 4474 self.nextQueue(); 4475 }); 4476 }; 4477 this.nextQueue = function () { 4478 return __awaiter(this, void 0, void 0, function () { 4479 var self, nextInQueue, modalDef; 4480 return __generator(this, function (_a) { 4481 switch (_a.label) { 4482 case 0: 4483 self = this; 4484 nextInQueue = _.head(this.queue); 4485 if (nextInQueue && $rootScope.globalModalVisible) 4486 return [2]; 4487 if (!nextInQueue) return [3, 2]; 4488 return [4, nextInQueue()]; 4489 case 1: 4490 modalDef = _a.sent(); 4491 self.queue.shift(); 4492 if (modalDef.show) { 4493 self.initModalCloseListener(); 4494 $rootScope.globalModalShow(modalDef.template, modalDef.extraScope, modalDef.onClose); 4495 } 4496 else { 4497 self.nextQueue(); 4498 } 4499 return [3, 3]; 4500 case 2: 4501 this.endQueue(); 4502 _a.label = 3; 4503 case 3: return [2]; 4504 } 4505 }); 4506 }); 4507 }; 4508 this.endQueue = function () { 4509 this.queue = []; 4510 _.result(this, 'modalCloseListener'); 4511 }; 4512 return this; 4513});
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.